【问题标题】:How to deploy a docker app to production without using Docker compose?如何在不使用 Docker compose 的情况下将 docker 应用程序部署到生产环境?
【发布时间】:2020-11-01 07:22:38
【问题描述】:

听说过

Docker compose 是为开发而非生产而设计的。

但我看到人们在生产环境中使用 Docker compose 和绑定挂载。然后从 github 中提取最新的更改,它会在生产中实时显示,无需重建。但是其他人说你需要COPY . .进行生产和重建。

  1. 但是这是如何工作的呢?因为在docker-compose.yaml 中,您可以指定depends-on,它在另一个容器运行之前不会启动一个容器。如果我在生产中不使用docker-compose,那么这个呢?我将如何将我的 docker-compose 推送到生产环境(我有 4 个服务 / 4 个需要运行的图像)。有了docker-compose up -d,就这么简单。

  2. 如何单独构建每个图像?

  3. 如何将这些图像复制到我的生产服务器以运行它们(以正确的顺序)?我什至无法在我的机器上的任何地方找到构建映像。

这是我的 docker-compose.yaml 文件,非常适合开发

version: '3'
services:

  # Nginx client server
  nginx-client:
    container_name: nginx-client
    build:
        context: .                  
    restart: always
    stdin_open: true  
    environment:
      - CHOKIDAR_USEPOLLING=true  
    ports:
      - 28874:3000
    volumes:
      - ./client:/var/www
      - /var/www/node_modules
    networks:
      - app-network


  # MySQL server for the server side app
  mysql-server:
    image: mysql:5.7.22
    container_name: mysql-server
    restart: always
    tty: true
    ports:
      - "16427:3306"
    environment:
      MYSQL_USER: root
      MYSQL_ROOT_PASSWORD: BcGH2Gj41J5VF1
      MYSQL_DATABASE: todo
    volumes:
      - ./docker/mysql-server/my.cnf:/etc/mysql/my.cnf
    networks:
      - app-network


  # Nginx server for the server side app
  nginx-server:
    container_name: nginx-server
    image: nginx:1.17-alpine
    restart: always
    ports:
      - 49691:80
    volumes:
      - ./server:/var/www
      - ./docker/nginx-server/etc/nginx/conf.d:/etc/nginx/conf.d
    depends_on:
    - php-server
    - mysql-server
    networks:
      - app-network


  # PHP server for the server side app
  php-server:
    build:
      context: .        
      dockerfile: ./docker/php-server/Dockerfile
    container_name: php-server
    restart: always
    tty: true
    environment:
      SERVICE_NAME: php
      SERVICE_TAGS: dev
    working_dir: /var/www
    volumes:
      - ./server:/var/www
      - ./docker/php-server/local.ini:/usr/local/etc/php/conf.d/local.ini
      - /var/www/vendor
    networks:
      - app-network
    depends_on:
      - mysql-server


# Networks
networks:
  app-network:
    driver: bridge

【问题讨论】:

    标签: docker docker-compose containers


    【解决方案1】:

    如何构建 docker 镜像?我假设您不打算使用注册表,因此您必须:

    • 为所有服务命名
    • 在某处构建 docker 映像(CI/CD 服务器,本地,这并不重要)
    • 将图像保存在文件中
    • 压缩文件
    • 远程导出压缩文件
    • 在服务器上,解压并加载

    我会为此创建一个脚本。像这样的:

    #!/bin/bash
    set -e
    
    docker-compose build
    
    docker save -o images.tar "$( grep  "image: .*" docker-compose.yml | awk '{ print $2 }' )"
    gzip images.tar
    
    scp images.tar.gz myserver:~
    
    ssh myserver ./load_images.sh
    -----
    
    on myserver, the load_images.sh would look like this:
    
    ```bash
    #!/bin/bash
    
    if [ ! -f images.tar.gz ] ; then
        echo "no file"
        exit 1
    fi
    
    gunzip images.tar.gz
    docker load -i images.tar
    

    然后你必须创建 docker 命令来模拟 docker-compose 配置(我不会去那里,因为它没什么困难但很无聊,而且我不想写那个)。你如何模拟depends_on?好吧,您必须单独启动每个容器,这样您要么准备另一个脚本,要么手动执行。


    关于在生产环境中使用 docker-compose:

    只要正确使用 docker-compose,在生产环境中使用它并没有什么大问题。例如我的一些生产设置往往如下所示:

    • docker-compose.yml
    • docker-compose.dev.yml
    • docker-compose.prd.yml

    开发人员将使用docker-compose -f docker-compose.yml -f docker-compose.dev.yml $cmd,而在生产中您将使用docker-compose -f docker-compose.yml -f docker-compose.prd.yml $cmd

    以你的文件为例,我会将所有volumesportsttystdin_open 小节从 docker-compose.yml 移动到 docker-compose.dev.yml。例如 docker-compose.dev.yml 看起来像这样:

    version: '3'
    services:
      nginx-client:
        stdin_open: true
        ports:
          - 28874:3000
        volumes:
          - ./client:/var/www
          - /var/www/node_modules
    
      mysql-server:
        tty: true
        ports:
          - "16427:3306"
        volumes:
          - ./docker/mysql-server/my.cnf:/etc/mysql/my.cnf
    
      nginx-server:
        ports:
          - 49691:80
        volumes:
          - ./server:/var/www
          - ./docker/nginx-server/etc/nginx/conf.d:/etc/nginx/conf.d
    
      php-server:
        restart: always
        tty: true
        volumes:
          - ./server:/var/www
          - ./docker/php-server/local.ini:/usr/local/etc/php/conf.d/local.ini
          - /var/www/vendor
    

    在生产中,docker-compose 您将拥有严格要求的port 小节,定义存储所需密码的生产环境文件(该文件将仅在生产服务器上,不在 git 中)等等等

    实际上,您可以采取许多不同的方法。

    【讨论】:

      【解决方案2】:

      通常,docker-compose 在开发中用作容器编排工具。在大多数流行的托管服务(如 GCP 和 AWS)上,还有其他几种生产级容器编排工具可用。 Kubernetes 是迄今为止最受欢迎和最常用的。

      根据 docker-compose 中使用的服务,建议不要直接在生产环境中使用它。运行 mysql 容器可能会导致数据丢失问题,因为容器是临时的。最好选择像 RDS 这样的托管 MySQL 服务。同样,nginx 也可以更好地设置您的托管服务提供的任何反向代理/负载平衡器服务。

      在构建镜像时,您可以利用 CI/CD 管道从它们各自的 Dockerfile 构建这些镜像,然后推送到您选择的镜像注册表,让您的托管服务获取镜像并使用您的托管服务提供的容器编排工具。

      【讨论】:

        【解决方案3】:

        如果您需要一个轻量级的生产环境,使用 Compose 可能没问题。此处的其他答案暗示了更多涉及的工具,这些工具具有支持多主机集群和零停机部署等优势,但涉及更多。

        您的描述中缺少一个核心部分是图像注册表。 Docker Hub 适合这个角色,如果你想使用它;主要的云提供商都有一个;甚至 GitHub 现在也有一个容器注册表(用于公共存储库);或者你可以自己运行。这解决了您的几个问题:(2)您在本地(或在专用的连续集成系统上)docker build 图像并将它们docker push 到注册表,然后(3)您在生产中使用docker pull 图像系统,或者让 Docker 自己做。

        一个很好的做法是给每个构建一个唯一的标签,可能是一个日期戳或提交 ID。这使得通过更改标签并重新运行docker-compose up 来升级(或降级)变得非常容易。

        为此,您需要更改您的 docker-compose.yml,例如:

        services:
          nginx-client:
            # No `build:`
            image: registry.example.com/nginx:${NGINX_TAG:latest}
          php-server:
            # No `build:`
            image: registry.example.com/php:${PHP_TAG:latest}
        

        然后您可以更新以下内容:

        docker build -t registry.example.com/nginx:20201101 ./nginx
        docker build -t registry.example.com/php:20201101 ./php
        docker push registry.example.com/nginx:20201101 registry.example.com/php:20201101
        
        ssh production-system.example.com \
          NGINX_TAG=20201101 PHP_TAG=20201101 docker-compose up -d
        

        您可以使用多个docker-compose.yml 文件,也可以将docker-compose builddocker-compose push 用于您的自定义图像,以及仅用于开发的覆盖文件。有an example in the Docker documentation

        不要单独复制您的代码;它包含在图像中。不要在镜像代码上绑定本地代码。特别是不要使用匿名卷来保存库,因为这将完全忽略底层映像中的任何更新。这些也是开发中的良好做法,因为如果您将映像中有趣的所有内容替换为卷安装,那么它与您在生产中运行的内容没有任何关系。

        您需要将您引用的配置文件和docker-compose.yml本身分别复制到目标系统,并负责备份数据库数据。

        最后,我建议从 docker-compose.yml 文件中删除不必要的选项(不要手动指定 container_name:,使用 Compose 提供的 default 网络,更喜欢在图像中指定 command:,等等在)。这不是必需的,但它可以帮助减少 YAML 文件的大小。

        【讨论】:

          猜你喜欢
          • 2021-01-01
          • 2020-04-10
          • 1970-01-01
          • 1970-01-01
          • 2013-10-15
          • 1970-01-01
          • 1970-01-01
          • 2023-04-01
          • 1970-01-01
          相关资源
          最近更新 更多