Docker部署WordPress LNMP(Nginx PHP MySQL)环境实践

Docker基于LXC实现了把软件封装到一个完整的文件系统,可以在docker容器中运行所需的一切代码,运行环境,系统工具和系统库。由于docker使用独立于主机的文件系统,可以确保软件在不同的主机环境中仍然保持运行环境不变。docker与主机共用一个操作系统内核,使用docker容器具有轻量级的特点,能占用更少的内存快速启动容器。

下面我们学习使用docker来部署目前非常流行的博客系统wordpress的运行环境nginx php mysql(作者wordpress博客devops.webres.wang正是运行在docker容器中)。那么docker部署wordpress的运行环境与我们传统上直接在主机配置环境有什么区别?我们从开发和运维人员角度来说明。运维使用docker制作好wordpress容器,分发给开发人员,开发人员随即只需一个命令就可以部署好完全一样的运行环境,从此只需要关注代码本身,而不再需要把时间浪费在配置环境上。而同时,docker容器确保了开发环境与生产环境的一致性,极大减少由于开发环境与生产环境不一致出现的各种问题。而由于docker容器可以快速部署的特点,运维人员可以很轻松的对服务进行伸缩和扩展。

那么如何使用docker部署wordpress的运行环境?大概步骤是分别编写nginx php mysql的Dockerfile文件,从这些Dockerfile文件中生成各自的镜像,然后使用docker-compose工具来统一管理nginx php mysql。为了能只使用docker-compose.yml一个文件就能快速部署wordpress环境,我们把Dockerfile及环境的相关配置保存到阿里云的Kelude(git代码托管code.aliyun.com),然后使用阿里云的Docker镜像仓库(cr.console.aliyun.com)从Kelude拉取Dockerfile自动构建镜像。国外此类服务有hub.docker.com和github.com,使用阿里云的是因为可以免费设置私有git仓库和私有镜像,因为我们可能需要保存一些不便公开的私密信息(如网站证书,密码)。当然你也可以不使用这类服务,直接把镜像保存到本地环境中。下面开始一步步介绍。

准备工作

使用阿里云Kelude

到https://code.aliyun.com/创建一个项目,如Dockerfile。之后我们把wordpress环境的所有相关Dockerfile及配置文件放置到centosbz目录。

使用阿里云镜像仓库

阿里云docker镜像仓库地址为https://cr.console.aliyun.com,用来存放docker镜像,可以在本地push镜像上去,也可以从Kelude拉取Dockerfile自动构建镜像。我们先登录,然后新建一个namespace,如centos-bz,之后所有的nginx,php,mysql镜像将存放在这个namespace下。

安装docker-compose

需要在运行docker容器的主机上安装docker-compose,可以参照官方文档手动安装,也可以使用ezhttp的一键安装工具(推荐)安装。如:

wget webres.wang/ezhttp.zip
unzip ezhttp.zip
cd ezhttp-master
./start.sh

之后会弹出一个菜单,输入2选择Some Useful Tools,然后输入18选择安装docker和compose。

编写Dockerfile

clone以上在阿里云Kelude创建的Dockerfile镜像到本地,在此项目中创建webres.wang,然后在webres.wang目录分别创建mysql,nginx,php目录,用于存放它们各自Dockerfile及配置文件。
这里我们还约定以下目录:

  • /home/docker/nginx/logs/webres.wang:存放devops.webres.wang网站的日志
  • /home/docker/nginx/www/webres.wang: 存放devops.webres.wang网站的文件
  • /home/docker/php: 存放php-fpm的日志
  • /home/docker/mysql:mysql data目录
  • nginx Dockerfile

    在nginx目录创建Dockerfile文件,写入如下内容:

    # 从debian:jessie镜像基础上安装nginx
    FROM debian:jessie
    
    # 声明此Dockerfile维护者的邮箱,有什么问题可以发到此邮件寻问
    LABEL maintainer "[email protected]"
    
    # 定义软件版本及编译工具变量
    ENV NGINX_VERSION 1.10.3
    ENV OPENSSL_VERSION 1.0.2h
    ENV ZLIB_VERSION 1.2.11
    ENV PCRE_VERSION 8.40
    ENV CONCAT_VERSION 1.2.2
    ENV BUILD_TOOLS wget gcc make g++
    ENV SRC_DIR /opt/nginx
    
    # 切换到工作目录
    WORKDIR ${SRC_DIR}
    
    # 开始编译nginx,我们这里使用编译安装nginx而不是使用官方提供的nginx镜像是因为这里使用到了第三方的concat模块,只能编译了。
    # 把所有的安装命令都写在一个RUN指令中是因为这样可以减小镜像层数,缩减镜像大小。推荐使用反斜杠和&&把所有的安装命令放置到一行中。
    RUN apt-get update 
        && apt-get -y --no-install-recommends install ca-certificates ${BUILD_TOOLS} 
        && wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz  
        && wget https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz  
        && wget http://www.zlib.net/zlib-${ZLIB_VERSION}.tar.gz  
        && wget https://ftp.pcre.org/pub/pcre/pcre-${PCRE_VERSION}.tar.gz  
        && wget https://github.com/alibaba/nginx-http-concat/archive/${CONCAT_VERSION}.tar.gz -O nginx-http-concat-${CONCAT_VERSION}.tar.gz  
        && tar xf nginx-${NGINX_VERSION}.tar.gz  
        && tar xf openssl-${OPENSSL_VERSION}.tar.gz  
        && tar xf zlib-${ZLIB_VERSION}.tar.gz  
        && tar xf pcre-${PCRE_VERSION}.tar.gz  
        && tar xf nginx-http-concat-${CONCAT_VERSION}.tar.gz  
        && cd nginx-${NGINX_VERSION}  
        && ./configure --prefix=/usr/local/nginx --with-pcre=../pcre-${PCRE_VERSION} 
                    --with-zlib=../zlib-${ZLIB_VERSION} 
                    --with-http_ssl_module 
                    --with-openssl=../openssl-${OPENSSL_VERSION} 
                    --add-module=../nginx-http-concat-${CONCAT_VERSION}  
        && make -j$(nproc) 
        && make install 
        && rm -rf ${SRC_DIR} 
        && apt-get purge -y --auto-remove ${BUILD_TOOLS} 
        && rm -rf /var/lib/apt/lists/* 
    
    # 把构建上下文目录conf,即Dockerfile/webres.wang/nginx/conf目录下的文件复制到容器的/usr/local/nginx/conf目录。
    COPY conf/ /usr/local/nginx/conf/
    
    # 定义启动容器时运行的命令
    ENTRYPOINT ["/usr/local/nginx/sbin/nginx"]
    
    EXPOSE 80 443
    

    对于conf目录下的nginx配置文件,需要把日志,网站目录更改为以下约定的目录位置。

    php-fpm Dockerfile

    创建Dockerfile/webres.wang/php-fpm目录,在此目录下创建Dockerfile文件,内容如下:

    FROM debian:jessie
    LABEL maintainer "[email protected]"
    
    # 定义软件版本,编译工具,依赖等变量
    ENV PHP_VERSION 5.6.30
    ENV BUILD_TOOLS m4 
                   autoconf 
                   autoconf2.13 
                   openssl 
                   wget 
                   gcc 
                   make
    
    ENV BUILD_DEPS libcurl4-gnutls-dev 
                   libxml2-dev 
                   zlib1g-dev 
                   libpcre3-dev 
                   libjpeg-dev 
                   libpng12-dev 
                   libfreetype6-dev 
                   libmhash-dev 
                   libmcrypt-dev 
                   libssl-dev 
                   libtool
    
    ENV PHP_LOCATION /usr/local/php
    ENV BUILD_ARG   --prefix=${PHP_LOCATION} 
                    --with-config-file-path=${PHP_LOCATION}/etc 
                    --enable-fpm 
                    --enable-bcmath 
                    --with-pdo_sqlite 
                    --with-gettext 
                    --with-iconv 
                    --enable-ftp 
                    --with-sqlite3 
                    --enable-mbstring 
                    --enable-sockets 
                    --enable-zip 
                    --enable-soap 
                    --with-openssl 
                    --with-zlib 
                    --with-curl 
                    --with-gd 
                    --with-jpeg-dir 
                    --with-png-dir 
                    --with-freetype-dir 
                    --with-mcrypt 
                    --with-mhash 
                    --with-mysql=mysqlnd 
                    --with-mysqli=mysqlnd 
                    --with-pdo-mysql=mysqlnd 
                    --without-pear 
                    --with-libdir=lib64 
                    --enable-opcache 
                    --disable-cgi
    
    ENV SRC_DIR /opt/php
    
    WORKDIR ${SRC_DIR}
    
    # 开始编译安装php
    RUN apt-get update 
        && apt-get -y --no-install-recommends install ${BUILD_DEPS} ${BUILD_TOOLS} 
        && wget http://php.net/distributions/php-${PHP_VERSION}.tar.gz 
        && tar xf php-${PHP_VERSION}.tar.gz 
        && cd php-${PHP_VERSION} 
        && ln -s /usr/lib/x86_64-linux-gnu/libssl.so /usr/lib/libssl.so 
        && ln -s /usr/lib /usr/lib64 
        && ./configure ${BUILD_ARG} 
        && make -j$(nproc) 
        && make install 
        && cp php.ini-production ${PHP_LOCATION}/etc/php.ini 
        && cp ${PHP_LOCATION}/etc/php-fpm.conf.default ${PHP_LOCATION}/etc/php-fpm.conf 
        && rm -rf ${SRC_DIR} 
        && apt-get purge -y --auto-remove ${BUILD_TOOLS} 
        && rm -rf /var/lib/apt/lists/* 
    
    
    WORKDIR ${PHP_LOCATION}/etc/
    
    # 配置php-fpm,即使用sed工具编辑php-fpm.conf和php.ini文件,这里的php-fpm相关配置命令不与上面的编译命令合在一起来减小层数是因为
    # 配置文件可能会改动比较多,这样分开当配置文件更改时可以直接使用缓存跳过编译步骤,加快构建速度。
    RUN set_php_variable(){ 
            local key=$1; 
            local value=$2; 
            if grep -q -E "^$keys*=" php.ini;then 
                sed -i -r "s#^$keys*=.*#$key=$value#" php.ini; 
            else 
                sed -i -r "s#;s*$keys*=.*#$key=$value#" php.ini; 
            fi; 
            if ! grep -q -E "^$keys*=" php.ini;then 
                echo "$key=$value" >> php.ini; 
            fi; 
        } 
        && BASE_DIR=/home/docker/php 
        && set_php_variable disable_functions "dl,eval,assert,exec,popen,system,passthru,shell_exec,escapeshellarg,escapeshellcmd,proc_close,proc_open" 
        && set_php_variable expose_php Off 
        && set_php_variable error_log ${BASE_DIR}/php_errors.log 
        && set_php_variable request_order  "CGP" 
        && set_php_variable cgi.fix_pathinfo 0 
        && set_php_variable short_open_tag on 
        && set_php_variable date.timezone Asia/Chongqing 
        && sed -i 's/^user =.*/user = www-data/' php-fpm.conf 
        && sed -i 's/^group =.*/group = www-data/' php-fpm.conf 
        && sed -i "s#;slowlog = log/$pool.log.slow#slowlog = ${BASE_DIR}/$pool.log.slow#" php-fpm.conf 
        && sed -i 's/;request_slowlog_timeout = 0/request_slowlog_timeout = 5/' php-fpm.conf 
        && sed -i 's/^pm.max_children.*/pm.max_children =20/' php-fpm.conf 
        && sed -i 's/^pm.start_servers.*/pm.start_servers =5/' php-fpm.conf 
        && sed -i 's/^pm.min_spare_servers.*/pm.min_spare_servers =3/' php-fpm.conf 
        && sed -i 's/^pm.max_spare_servers.*/pm.max_spare_servers =8/' php-fpm.conf 
        && sed -i '/[global]/adaemonize =no' php-fpm.conf 
        && sed -i 's/^listen.*/listen =0.0.0.0:9000/' php-fpm.conf 
        && echo "[opcache]n 
                zend_extension=opcache.son 
                opcache.memory_consumption=128n 
                opcache.interned_strings_buffer=8n 
                opcache.max_accelerated_files=4000n 
                opcache.revalidate_freq=60n 
                opcache.fast_shutdown=1 n" >> php.ini
    
    ENTRYPOINT ["/usr/local/php/sbin/php-fpm"]
    
    EXPOSE 9000    
    

    mysql Dockerfile

    创建Dockerfile/webres.wang/mysql/Dockerfile文件,内容如下:

    FROM mysql:5.6
    LABEL maintainer "[email protected]"
    COPY my.cnf /etc/mysql/my.cnf
    

    这个Dockerfile非常简单,直接使用了官方的mysql镜像,唯一区别是我们使用自己定义的my.cnf配置文件。
    对于my.cnf配置文件,需要把日志,data目录指向/home/docker/mysql,一个my.cnf示例文件如下:

    # Generated by EZHTTP at 2016-02-03 01:05:29
    
    [mysql]
    
    # CLIENT #
    port                           = 3306
    socket                         = /home/docker/mysql/mysql.sock
    
    [mysqld]
    
    # GENERAL #
    port                           = 3306
    user                           = mysql
    default-storage-engine         = InnoDB
    socket                         = /home/docker/mysql/mysql.sock
    pid-file                       = /home/docker/mysql/mysql.pid
    skip-name-resolve
    
    # MyISAM #
    key-buffer-size                = 32M
    
    # INNODB #
    #innodb-flush-method            = O_DIRECT
    innodb-log-files-in-group      = 2
    innodb-log-file-size           = 64M
    innodb-flush-log-at-trx-commit = 2
    innodb-file-per-table          = 1
    innodb-buffer-pool-size        = 1G
    
    # CACHES AND LIMITS #
    tmp-table-size                 = 32M
    max-heap-table-size            = 32M
    query-cache-type               = 0
    query-cache-size               = 0
    max-connections                = 300
    thread-cache-size              = 50
    open-files-limit               = 1024
    table-definition-cache         = 100
    table-open-cache               = 400
    
    
    # SAFETY #
    max-allowed-packet             = 16M
    max-connect-errors             = 1000000
    
    # DATA STORAGE #
    datadir                        = /home/docker/mysql
    
    # LOGGING #
    log-error                      = /home/docker/mysql/mysql-error.log
    log-queries-not-using-indexes  = 1
    slow-query-log                 = 1
    slow-query-log-file            = /home/docker/mysql/mysql-slow.log
    
    # BINARY LOGGING #
    log-bin = /home/docker/mysql/mysql-bin
    server-id = 1
    expire-logs-days = 14
    sync-binlog = 1
    

    构建镜像

    把上一步创建的文件推送到阿里云的Kelude。然后我们登录阿里云的docker镜像仓库cr.console.aliyun.com。这里以设置自动构建nginx镜像为例,php和mysql镜像构建设置类似。
    1.点击左侧“镜像列表”,在右侧点击仓库镜像,如图:
    虚拟化技术
    2.在仓库镜像创建对话框中,说明如下:
    地域:选择离部署docker主机最近的位置,国内的话选择华东1或华东2。
    Namespace和仓库名称:这里选择centos-bz,nginx。
    设置代码源:我们这里选择阿里云code。
    构建设置:勾选代码变更时自动构建镜像,海外机器构建(因为国内主机apt-get安装软件时较慢),Dockerfile路径填/webres.wang/nginx
    完成后点击创建仓库按钮。
    如图:
    虚拟化技术
    3.回到镜像列表,找到nginx镜像,点击管理。
    4.左侧点击“构建”,右侧点击“立即构建”开始首次构建,之后我们更改Dockerfile及配置文件到Kelude之后就会自动构建了。
    5.查看日志,查看构建进程。
    然后继续完成php,mysql的镜像构建设置。

    启动环境

    为了方便统一管理nginx,php,mysql的启动,我们使用docker-compose工具。我们只需要编写一个docker-compose.yml文件,然后使用docker-compose工具就可以快速启动docker容器了。之后把docker-compose.yml传输到任意一台支持docker环境的主机中就可以快速配置wordpress的运行环境。

    docker-compose.yml

    把docker-compose.yml文件放置在/home/docker目录下。

    version: '3'
    # 定义三个服务nginx,php,mysql
    services:
        nginx:
            # 依赖php服务,意味着在启动nginx之前先启动php
            depends_on:
                - php
            # nginx镜像的路径
            image: registry.cn-hangzhou.aliyuncs.com/centos-bz/nginx
            # 容器的/home/docker/nginx目录挂载主机中的/home/docker/nginx目录,
            # 这样使nginx容器把网站文件和目录存放到主机目录中,持久化和方便管理
            volumes:
                - /home/docker/nginx:/home/docker/nginx
            # nginx意外退出时自动重启
            restart: always
    
            # 映射80和443端口
            ports:
                - "80:80"
                - "443:443"
    
            # 容器名称
            container_name: nginx    
        php:
            depends_on:
                - mysql
            image: registry.cn-hangzhou.aliyuncs.com/centos-bz/php-fpm
            restart: always
            volumes:
                - /home/docker/nginx/www:/home/docker/nginx/www
                - /home/docker/php:/home/docker/php
            container_name: php   
    
        mysql:
            image: registry.cn-hangzhou.aliyuncs.com/centos-bz/mysql
            volumes:
                - /home/docker/mysql:/home/docker/mysql
            restart: always
            # 设置MYSQL_ROOT_PASSWORD环境变量,这里是设置mysql的root密码。这里为root。
            environment:
                MYSQL_ROOT_PASSWORD: root
            container_name: mysql
    

    启动环境

    在/home/docker目录执行:

    docker-compose up
    

    查看nginx,php,mysql是否正常启动,如果正常,ctrl-c停止,再执行:

    docker-compose up -d
    

    这里compose命令就在后台启动了。
    执行docker ps查看容器运行状态。

    连接问题

    容器之间可以通过容器名称来连接,如nginx配置文件中连接php的代码fastcgi_pass php:9000,网站数据库配置文件使用mysql:3306。

    日常运维

    迁移

    比如A主机迁移到B主机。只需要三步。

  • 1.打包A主机的/home/docker目录,传输到B主机相同位置
  • 2.配置B主机docker环境
  • 3.在B主机的/home/docker目录下执行docker-compose up -d
  • 导出导入数据库

    把centos.sql.gz数据库文件导入到centos数据库:

    gunzip < centos.sql.gz | docker exec -i mysql mysql -uroot -proot centos
    

    把centos数据库导出到centos.sql.gz

    docker exec -i mysql mysqldump -uroot -proot centos | gzip > centos.sql.gz
    

    备份

    推荐使用ezhttp一键备份设置:

    wget webres.wang/ezhttp.zip
    unzip ezhttp.zip
    cd ezhttp-master
    ./start.sh
    

    之后会弹出一个菜单,输入2选择Some Useful Tools,然后输入14选择备份设置。需要注意的是在设置mysql使用mysqldump备份时,在提示输入mysql bin directory时,输入docker exec /usr/bin/。

    docker和compose一键快速安装脚本

    本文介绍快速安装docker和compose的方法。与手动安装相比,一键安装省去了手工输入命令的繁琐步骤且不容易出错。由于国内网络环境原因,连接docker官方服务器异常的慢,这体现为在国内安装docker-engine和拉取镜像非常慢,甚至无法安装和拉取。此脚本通过更换repository和registry mirror解决了此问题。

    脚本特性

    对于docker-engine的安装,脚本特性如下:

  • 支持centos7,ubuntu,debian系统的安装
  • 支持安装特定版本的docker
  • 根据网络环境测试结果自动选取较快的repository,如国内使用mirrors.ustc.edu.cn,国外使用dockerproject.org
  • 通过测试网络自动为国内设置hub-mirror.c.163.com registry mirror
  • 对于compose的安装,脚本特性如下:

  • 支持所有Linux系统的安装
  • 支持安装特定版本的compose
  • 由于compose托管在amazonaws,国内几乎无法访问,自动设置一个代理下载
  • 使用方法

    1. wget webres.wang/ezhttp.zip
    2. unzip ezhttp.zip
    3. cd ezhttp-master
    4. ./start.sh

    之后会弹出一个菜单,输入2选择Some Useful Tools.
    然后输入17选择安装docker,输入18选择安装compose。

    docker compose文件参考(4) – 变量替换

    配置项可以包含环境变量。compose使用docker-compose运行所在的shell环境的变量值。例如,假设shell包含环境变量EXTERNAL_PORT=8000且配置中引用了此变量:

    1. web:
    2.   build: .
    3.   ports:
    4.     – "${EXTERNAL_PORT}:5000"

    当使用此配置插docker-compose run命令时,compose在shell中查找EXTERNAL_PORT环境变量并使用其值替换此配置文件中对应的占位符。在这个示例中,在创建web容器之前,compose解析端口映射为8000:5000。

    如果环境变量没有设置,compose使用空字符替换。在上面的示例中,如果EXTERNAL_PORT没有设置,端口映射的值为:5000(是一个无效的端口映射,创建容器时会导致错误)。

    可以使用.env文件为环境变量设置默认的值。在shell环境中设置的值会覆盖在.env文件设置的值。

    1. $ unset EXTERNAL_PORT
    2. $ echo "EXTERNAL_PORT=6000" > .env
    3. $ docker-compose up          # EXTERNAL_PORT will be 6000
    4. $ export EXTERNAL_PORT=7000
    5. $ docker-compose up          # EXTERNAL_PORT will be 7000

    $VARIABLE和${VARIABLE}两种写法都支持。如果使用的是2.1文件格式,还可以在一行中设置默认的值:

  • ${VARIABLE:-default}:当VARIABLE没有设置或为空值时使用default值。
  • ${VARIABLE-default} :仅当VARIABLE没有设置时使用default值。
  • 其它的shell风格的扩展功能,如${VARIABLE/foo/bar}不支持。

    可以使用双美元符号来转义美元符号,即阻止compose解析为值。

    1. web:
    2.   build: .
    3.   command: "$$VAR_NOT_INTERPOLATED_BY_COMPOSE"

    docker compose文件参考(3) – 网络配置

    driver

    指定用于这个网络的驱动。

    默认使用的驱动取决于docker engine的配置,但大多数情况中,单台主机中使用的是bridge,在集群中使用的是overlay。

    1. driver: overlay

    driver_opts

    指定一列键值对选项传递给这个数据卷的驱动。这些选项依赖于驱动。此参数可选。

    1. driver_opts:
    2.     foo: "bar"
    3.     baz: 1

    enable_ipv6

    在这个网络启用IPv6网络支持。从version 2.1文件格式可用。

    ipam

    指定自定义IPAM配置。这个是带几个属性的对象,每个属性都是可选的:

  • driver: 自定义IPAM驱动,而不是default。
  • config: 0个或多个配置块,可以是以下键:
    subnet:表示一个网段的CIDR格式的子网
    ip_range:从指定范围分配容器IP
    gateway:主子网的IPv4或IPv6网关
    aux_addresses:网络驱动程序使用的辅助IPv4或IPv6地址,作为从主机名到IP的映射
  • 一个完整的示例:

    1. ipam:
    2.   driver: default
    3.   config:
    4.     – subnet: 172.28.0.0/16
    5.       ip_range: 172.28.5.0/24
    6.       gateway: 172.28.5.254
    7.       aux_addresses:
    8.         host1: 172.28.1.5
    9.         host2: 172.28.1.6
    10.         host3: 172.28.1.7

    docker compose文件参考(2) – 数据卷配置

    driver

    指定这个数据卷使用的数据卷驱动。默认为local。如果驱动不可用,docker engine将会返回一个错误。

    1. driver: foobar

    driver_opts

    指定一列键值对选项传递给这个数据卷的驱动。这些选项依赖于驱动。此参数可选。

    1. driver_opts:
    2.    foo: "bar"
    3.    baz: 1

    external

    如果设置为true,表示这个数据卷已经在compose外部创建好了。docker-compose up将不会尝试创建它。

    external不能与其它的数据卷配置关键词(driver, driver_opts)一起使用。

    在下面的示例中,compose不会尝试创建名为[projectname]_data的数据卷,而是仅仅查找一个称为data存在的数据卷并挂载它到db服务的容器。

    1. version: ‘2’
    2.  
    3. services:
    4.   db:
    5.     image: postgres
    6.     volumes:
    7.       – data:/var/lib/postgresql/data
    8.  
    9. volumes:
    10.   data:
    11.     external: true

    也可以指定在compose文件内引用的数据卷名称:

    1. volumes:
    2.   data:
    3.     external:
    4.       name: actual-name-of-volume

    docker compose文件参考(1) – 服务配置

    build

    这个配置选项应用在构建镜像时。

    build可以指定包含构建上下文路径的字符串,或者是context指定一个路径和可选的dockerfile和args。

    1. build: ./dir
    2.  
    3. build:
    4.   context: ./dir
    5.   dockerfile: Dockerfile-alternate
    6.   args:
    7.     buildno: 1

    如果指定了image和build,那么compose以image中指定的名称命名构建的镜像,如:

    1. build: ./dir
    2. image: webapp:tag

    compose将由./dir构建的镜像命名为webapp,tag为tag。

    注意:在version 1文件格式中,build有两点不同的地方:
    1.只允许build: .一种格式,不允许对象格式。
    2.不允许build与image一起使用。

    context

    context可用于verion 2文件格式或以上版本,version 1中只用build。

    指定一个包含Dockerfile的目录路径,或git存储库url。

    当指定了一个相对路径,就解析为相对compose文件所在的目录。这个目录也是发送到docker daemon的构建上下文。

    1. build:
    2.   context: ./dir

    dockerfile

    替代的Dockerfile

    compose使用另一个dockerfile文件构建镜像。必须指定一个context构建路径。

    注意:在verions 1文件格式中,dockerfile有两点不同:
    1.它出现在build的同级,而不是作为它的子选项:

    1. build: .
    2. dockerfile: Dockerfile-alternate

    2.不允许dockerfile与image一起使用。

    args

    此选项只支持version 2文件格式和之上版本。

    增加build参数,这些参数是只在构建期间访问的环境变量。

    首先,在Dockerfile中指定参数:

    1. ARG buildno
    2. ARG password
    3.  
    4. RUN echo "Build number: $buildno"
    5. RUN script-requiring-password.sh "$password"

    然后在build下面指定参数。可以传递映射或列表:

    1. build:
    2.   context: .
    3.   args:
    4.     buildno: 1
    5.     password: secret
    6.  
    7. build:
    8.   context: .
    9.   args:
    10.     – buildno=1
    11.     – password=secret

    compose文件中可以只指定参数名不设置值,在这种情况下参数的值就是compose运行所在shell的环境变量值。

    1. args:
    2.   – buildno
    3.   – password

    注意:YAML布尔值(true,false,yes,no,on,off)必须用引号引起来,以便解析器将其解释为字符串。

    command

    覆盖默认的命令。

    1. command: bundle exec thin -p 3000

    命令也可以是一个列表,与dockerfile中的列表类似:

    1. command: [bundle, exec, thin, -p, 3000]

    container_name

    指定一个自定义的容器名称,而不是一个生成的默认名称。

    1. container_name: my-web-container

    因为docker容器名称必须是唯一的,所以如果指定了一个自定义的名称,不能扩展一个服务超过1个容器。

    depends_on

    指定服务之间的依赖关系,有两种效果:

  • docker-compose up将以依赖顺序启动服务。在下面的示例中,db和redis在web之前启动。
  • docker-compose up SERVICE将自动包括SERVICE的依赖。在下面的示例中,docker-compose up web也会创建和启动db和redis。
  • 简单的示例:

    1. version: ‘2’
    2. services:
    3.   web:
    4.     build: .
    5.     depends_on:
    6.       – db
    7.       – redis
    8.   redis:
    9.     image: redis
    10.   db:
    11.     image: postgres

    注意:depends_on不会等到db和redis状态为“ready”才启动web – 它只等到它们已经开始启动。如果需要等到一个服务变为ready,查看Controlling startup order

    dns

    自定义DNS服务器。可以是单个值或列表。

    1. dns: 8.8.8.8
    2. dns:
    3.   – 8.8.8.8
    4.   – 9.9.9.9

    dns_search

    自定义search域名。可以是单个值或列表。

    1. dns_search: example.com
    2. dns_search:
    3.   – dc1.example.com
    4.   – dc2.example.com

    tmpfs

    需要version 2文件格式或以上版本。

    在容器内部挂载一个临时文件系统。可以是单个值或列表。

    tmpfs: /run
    tmpfs:
    – /run
    – /tmp

    entrypoint

    覆盖默认的entrypoint。

    1. entrypoint: /code/entrypoint.sh

    entrypoint也可以是一个列表:

    1. entrypoint:
    2.     – php
    3.     – -d
    4.     – zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20100525/xdebug.so
    5.     – -d
    6.     – memory_limit=-1
    7.     – vendor/bin/phpunit

    注意:设置entrypoint将会覆盖默认使用ENTRYPOINT Dockerfile指令设置服务镜像的entrypoint,也会清除这个镜像的任何默认命令 – 意味着如果Dockerfile中指定的任何CMD指定将会忽略。

    env_file

    从一个文件添加环境变量。可以是单个值或列表。

    如果使用docker-compose -f FILE指定了一个compose文件,那么在env_file的路径就是相对于那个文件所在的目录。

    在environment关键词指定的环境变量将会覆盖env_file设置的值。

    1. env_file: .env
    2.  
    3. env_file:
    4.   – ./common.env
    5.   – ./apps/web.env
    6.   – /opt/secrets.env

    env文件中每行的格式为VAR=VAL。以#开头的行将忽略,也包括空行。

    1. # Set Rails/Rack environment
    2. RACK_ENV=development

    注意:如果服务指定了一个build选项,定义在env文件中的变量在构建期间不可用。使用build的子选项来定义在构建期间使用的环境变量。

    VAL的值按原样使用,不再不修改。 例如,如果值由引号括起来(通常是shell变量的情况),引号将包含在传递给Compose的值中。

    environment

    添加环境变量。可以使用数组或字典。任何的布尔值,true,false,yes,no需要用引号括起来,以确保YML解析器把它们转换为True或False。

    1. environment:
    2.   RACK_ENV: development
    3.   SHOW: ‘true’
    4.   SESSION_SECRET:
    5.  
    6. environment:
    7.   – RACK_ENV=development
    8.   – SHOW=true
    9.   – SESSION_SECRET

    expose

    暴露只在链接服务之间可用的端口。只能指定内部使用的端口。

    1. expose:
    2.  – "3000"
    3.  – "8000"

    extends

    在当前文件或另一个文件扩展另一个服务,可选地覆盖配置。

    extends可以与service相关的配置项一起使用。extends的值必须是一个字典,其中service是必须的以及一个可选的file选项。

    1. extends:
    2.   file: common.yml
    3.   service: webapp

    service指定的是扩展服务到当前服务的名称。例如web或databases。file指定的是定义有那个service的compose文件。

    如果不指定file选项,compose则在当前文件查找service的配置。file值可以是一个绝对的或相对的路径。如果指定一个相对的路径,这个路径就是相对于当前文件所在目录的路径。

    可以扩展一个本身扩展有另一个的服务。

    external_links

    链接那些在docker-compose.yml外部启动的容器或甚至是在compose外部的,特别是那么提供共享或通用服务的容器。

    external_links在指定容器名称和链接别名(CONTAINER:ALIAS)时遵循类似于链接的语义。

    1. external_links:
    2.  – redis_1
    3.  – project_db_1:mysql
    4.  – project_db_1:postgresql

    注意:如果使用的是version 2文件格式的compose文件,外部创建的容器必须是连接到与链接到它们的服务同处至少一个相同的网络。

    extra_hosts

    添加主机名映射。与docker客户端的–add-host参数作用一样。

    1. extra_hosts:
    2.  – "somehost:162.242.195.82"
    3.  – "otherhost:50.31.209.229"

    这些定义的ip地址和主机条目将在容器内部的/etc/hosts文件里,如:

    1. 162.242.195.82  somehost
    2. 50.31.209.229   otherhost

    image

    指定从其启动容器的镜像。可以是repository/tag或部分镜像ID。

    1. image: redis
    2. image: ubuntu:14.04
    3. image: tutum/influxdb
    4. image: example-registry.com:4000/postgresql
    5. image: a4bc65fd

    如果镜像不存在,compose尝试拉取它,除非也指定了build,在这种情况下它使用指定的选项来构建镜像并使用指定的tag来作标记。

    注意:在version 1文件格式中,不允许build和image一起使用。

    links

    链接到另一个服务的容器。可以指定服务名称和链接别名(SERVICE:ALIAS),或只是服务名称。

    1. web:
    2.   links:
    3.    – db
    4.    – db:database
    5.    – redis

    可以使用与别名一样的主机名访问链接服务的容器,或者如果没有指定别名就使用服务名称。

    链接也以与depends_on相同的方式表示服务之间的依赖关系,因此它们可以决定服务启动的顺序。

    注意:如果定义了links和网络,为了能够通信,链接的服务之间必须至少在一个相同的网络。

    logging

    version 2文件格式或更高版本。在version 1中,使用是的log_driver和log_opt。

    服务的日志配置。

    logging:
    driver: syslog
    options:
    syslog-address: “tcp://192.168.0.42:123”

    driver名称指定一个服务容器的日志驱动,相当于docker run的–log-driver。
    默认的值是json-file。

    1. driver: "json-file"
    2. driver: "syslog"
    3. driver: "none"

    使用options关键词指定日志驱动的日志选项,就像docker run的log-opt选项。

    日志选项是键值对。一个syslog选项的示例:

    1. driver: "syslog"
    2. options:
    3.   syslog-address: "tcp://192.168.0.42:123"

    network_mode

    要求version 2文件格式和之后版本。version 1使用net。

    网络模式。与docker客户端的–net参数一样,加上一个特别的格式service:[service name]。

    1. network_mode: "bridge"
    2. network_mode: "host"
    3. network_mode: "none"
    4. network_mode: "service:[service name]"
    5. network_mode: "container:[container name/id]"

    networks

    要求version 2文件格式和之后版本。version 1使用net。

    要加入的网络,在顶层networks关键词之下引用网络。

    1. services:
    2.   some-service:
    3.     networks:
    4.      – some-network
    5.      – other-network

    aliases

    在网络中服务的别名(替代主机名)。在同一网络的其它容器可以使用服务名称或这个别名来连接服务容器的其中一个。

    因为别名作用域是网络内,所以同一服务在不同的网络可以有不同的别名。

    注意:网络范围的别名可以由多个容器共享,甚至是由多个服务。如果是这样,那么该名称解析到哪个容器将不能保证。

    一般的格式如下:

    1. services:
    2.   some-service:
    3.     networks:
    4.       some-network:
    5.         aliases:
    6.          – alias1
    7.          – alias3
    8.       other-network:
    9.         aliases:
    10.          – alias2

    在下面的示例中,配置了三个服务(web,worker和db)和两个网络(new和legay)。在net网络上可以使用db主机名或database访问db服务,在legacy网络上可以使用db或mysql访问db服务。

    1. version: ‘2’
    2.  
    3. services:
    4.   web:
    5.     build: ./web
    6.     networks:
    7.       – new
    8.  
    9.   worker:
    10.     build: ./worker
    11.     networks:
    12.     – legacy
    13.  
    14.   db:
    15.     image: mysql
    16.     networks:
    17.       new:
    18.         aliases:
    19.           – database
    20.       legacy:
    21.         aliases:
    22.           – mysql
    23.  
    24. networks:
    25.   new:
    26.   legacy:

    ipv4_address, ipv6_address

    加入网络时可以为服务的容器指定静态的IP地址。

    顶层networks区域的相关网络配置必须有一个指定有子网和网关覆盖每个静态地址的配置的ipadm块。如果要使用IPv6地址,必须设置com.docker.network.enable_ipv6驱动选项为true。
    示例:

    1. version: ‘2’
    2.  
    3. services:
    4.   app:
    5.     image: busybox
    6.     command: ifconfig
    7.     networks:
    8.       app_net:
    9.         ipv4_address: 172.16.238.10
    10.         ipv6_address: 2001:3984:3989::10
    11.  
    12. networks:
    13.   app_net:
    14.     driver: bridge
    15.     driver_opts:
    16.       com.docker.network.enable_ipv6: "true"
    17.     ipam:
    18.       driver: default
    19.       config:
    20.       – subnet: 172.16.238.0/24
    21.         gateway: 172.16.238.1
    22.       – subnet: 2001:3984:3989::/64
    23.         gateway: 2001:3984:3989::1

    ports

    暴露端口。可以指定两个端口(HOST:CONTAINER),或只指定一个容器端口(将选择一个随机的主机端口)。

    1. ports:
    2.  – "3000"
    3.  – "3000-3005"
    4.  – "8000:8000"
    5.  – "9090-9091:8080-8081"
    6.  – "49100:22"
    7.  – "127.0.0.1:8001:8001"
    8.  – "127.0.0.1:5000-5010:5000-5010"

    ulimits

    覆盖容器默认的ulimits。可以指定单个限制或soft/hard限制。

    1. ulimits:
    2.   nproc: 65535
    3.   nofile:
    4.     soft: 20000
    5.     hard: 40000

    volumes, volume_driver

    挂载路径或命名数据卷,可选地指定主机的路径(HOST:CONTAINER),或权限模式(HOST:CONTAINER:ro)。对于version 2文件,命名数据卷必须在顶层volumes关键词中指定。当使用version 1时,当命名数据卷不存在时docker engine将会自动创建。

    可以挂载主机的一个相对路径,此路径相对于正在使用的compose文件所在的目录。相对的路径以.或..开头。

    1. volumes:
    2.   # Just specify a path and let the Engine create a volume
    3.   – /var/lib/mysql
    4.  
    5.   # Specify an absolute path mapping
    6.   – /opt/data:/var/lib/mysql
    7.  
    8.   # Path on the host, relative to the Compose file
    9.   – ./cache:/tmp/cache
    10.  
    11.   # User-relative path
    12.   – ~/configs:/etc/configs/:ro
    13.  
    14.   # Named volume
    15.   – datavolume:/var/lib/mysql

    如果不使用主机路径,可能要指定一个volume_driver。

    1. volume_driver: mydriver

    注意,对于version 2文件,这个驱动不会应用到命名数据卷(当声明数据卷时应该使用driver选项)。对于version 1,命名数据卷和容器数据卷使用这个指定的驱动。

    volumes_from

    挂载从另一个服务或容器的所有数据卷,可选地指定只读权限(ro)或读写(rw)。如果没有指定权限级别,将使用读写(rw)权限。

    1. volumes_from:
    2.  – service_name
    3.  – service_name:ro
    4.  – container:container_name
    5.  – container:container_name:rw

    cpu_shares, cpu_quota, cpuset, domainname, hostname, ipc, mac_address, mem_limit, memswap_limit, oom_score_adj, privileged, read_only, restart, shm_size, stdin_open, tty, user, working_dir

    1. cpu_shares: 73
    2. cpu_quota: 50000
    3. cpuset: 0,1
    4.  
    5. user: postgresql
    6. working_dir: /code
    7.  
    8. domainname: foo.com
    9. hostname: foo
    10. ipc: host
    11. mac_address: 02:42:ac:11:65:43
    12.  
    13. mem_limit: 1000000000
    14. memswap_limit: 2000000000
    15. privileged: true
    16.  
    17. oom_score_adj: 500
    18.  
    19. restart: always
    20.  
    21. read_only: true
    22. shm_size: 64M
    23. stdin_open: true
    24. tty: true

    在生产环境使用docker compose

    当在compose定义你的app用于开发环境时,也可以使用这个配置来在不同的环境,如CI,临时和生产环境运行应用程序。

    更改compose文件适用于生产环境

    在把compose部署到生产环境之前,虽然更改你的app配置,这些更改包括:

  • 删除应用程序代码的挂载,以使代码留在容器内,保证无法从外部更改。
  • 绑定不同的主机端口
  • 设置不同的环境变量(如降低日志的详细程序或启用邮件发送)
  • 指定一个重启策略(如restart: always)来避免宕机时间
  • 增加额外的服务(如,日志聚合器)
  • 以上这么多的更改,可以定义一个额外的compose文件,称为production.yml,定义了适合生产环境的配置。这个文件只需要包含你想要对原始文件的更改部分。可以通过原始docker-compose.yml应用额外的Compose文件来创建新配置。

    一旦完成了第二个配置文件的编写,使用-f选项告诉compose使用它:

    1. docker-compose -f docker-compose.yml -f production.yml up -d

    部署更改

    当对你的app代码更改后,需要重建镜像和容器。要重新部署web服务,使用:

    1. $ docker-compose build web
    2. $ docker-compose up –no-deps -d web

    第一个命令重建web的镜像然后停止,销毁和重建web服务。–no-deps选项阻止compose重新创建web信赖的服务。

    Docker Compose网络配置

    注意:本文涉及的compose只适用于compose文件格式为version 2的版本。verion 1(旧的)不支持网络功能。

    默认下compose为你的app配置一个单独的网络。服务中的每个容器都加入到这个默认的网络且在这个网络的容器都能互相通信,它们也能通过与容器名称相同的主机名发现对方。

    注意:app的网络基于“项目名称”设置网络名称,这个项目名称基于项目所处的目录名称。可以使用–project-name选项或COMPOSE_PROJECT_NAME环境变量来覆盖它。

    例如,假设app在一个名为myapp的目录,docker-compose.yml类似如下:

    1. version: ‘2’
    2.  
    3. services:
    4.   web:
    5.     build: .
    6.     ports:
    7.       – "8000:8000"
    8.   db:
    9.     image: postgres

    当执行docker-compose up时,网络部分设置如下:
    1.创建了称为myapp_default的网络。
    2.使用web的配置创建了容器,然后这个容器加入到myapp_default网络。
    3.使用db的配置创建容器,这个容器加入到myapp_default网络。

    每个容器现在能查找web或db来得到容器的IP地址。例如,web应用程序的代码可以连接URL postgres://db:5432并开始使用postgres数据库。

    由于web明确地映射了一个端口,外部网络也就能通过在docker主机的网络接口的8000端口连接容器。

    更新容器

    如果更改了服务的配置并执行docker-compose up来更新它,将删除旧的容器并且新的容器加入到相同的网络,分配到了不同的IP地址不过主机名不变。运行中的容器应该能够查找主机名并连接到新的地址,不过旧的地址将失效。

    如果任何一个容器与旧的容器有连接,它们会被关闭掉。容器有责任检测这种情况然后重新查找旧容器的主机来重新连接。

    链接

    链接可以为一个容器定义额外的别名。它们不需要启用服务进行通信 – 默认情况下,任何服务都可以通过该服务的名称访问任何其他服务。在下面的示例中,在web容器中可以通过db和database访问db容器。

    1. version: ‘2’
    2. services:
    3.   web:
    4.     build: .
    5.     links:
    6.       – "db:database"
    7.   db:
    8.     image: postgres

    指定自定义网络

    除了使用默认的app网络之外,还可以使用最顶层networks关键词指定自己定义的网络。这让你可以创建更复制的网络拓扑并指定自定义网络驱动及其选项。也可以使用它来连接服务到不由compose管理的外部创建的网络。

    每个服务都能指定连接由networks关键词配置的网络。

    下面的示例compose文件定义了两个自定义网络。proxy服务与db服务隔离,因为它们没有指定相同的网络。

    1. version: ‘2’
    2.  
    3. services:
    4.   proxy:
    5.     build: ./proxy
    6.     networks:
    7.       – front
    8.   app:
    9.     build: ./app
    10.     networks:
    11.       – front
    12.       – back
    13.   db:
    14.     image: postgres
    15.     networks:
    16.       – back
    17.  
    18. networks:
    19.   front:
    20.     # Use a custom driver
    21.     driver: custom-driver-1
    22.   back:
    23.     # Use a custom driver which takes special options
    24.     driver: custom-driver-2
    25.     driver_opts:
    26.       foo: "1"
    27.       bar: "2"

    也可以通过设置ipv4_address和/或ipv6_address为每个附着的网络配置静态的IP地址。

    Docker Compose: 在文件和项目间共享compose配置

    compose支持两种共享通用配置的方法:
    1.通过使用多个compose文件扩展整个compose文件
    2.使用extends字段扩展单个服务

    多个compose文件

    使用多个compose文件可以为不同的环境或不同的工作流自定义compose应用程序。

    理解多compose文件

    默认下,compose读取两个文件,一个docker-compose.yml和一个可选的docker-compose.override.yml文件。通常来说,docker-compose.yml包含基本的配置。而override文件包含覆盖已存在服务或整个新服务的配置。

    如果一个服务在两个文件中都有定义,那么compose就使用在”添加和覆盖配置”中描述的规则合并配置。

    要使用多个override文件或不同名称的override文件,可以使用-f选项指定文件列表。compose根据在命令行指定的顺序来合并它们。

    当使用多个配置文件时,必须确保文件中所有的路径是相对于base compose文件的(-f指定的第一个compose文件)。这样要求是因此override文件不需要是一个有效的compose文件。override文件可以只包含配置中的小片段。跟踪一个服务的片段是相对于哪个路径的是很困难的且令人困惑的,所以要保持路径容易理解,所以的路径必须定义为相对于base文件的路径。

    示例

    在本段介绍两个常见的多compose文件用例:为不同的环境更改compose app和针对compose app运行管理任务。

    不同的环境

    使用多文件的一个常见用例是更改用于类生产环境(可能是生产环境,临时环境或配置项)的开发compose app。要支持这样的更改,可以把一个compose配置文件分割为多个不同的文件:

    从定义服务的规范配置的基本文件开始。

    docker-compose.yml

    1. web:
    2.   image: example/my_web_app:latest
    3.   links:
    4.     – db
    5.     – cache
    6.  
    7. db:
    8.   image: postgres:latest
    9.  
    10. cache:
    11.   image: redis:latest

    在下面这个示例中开发配置暴露了一些端口到主机上,挂载代码目录到容器然后构建web镜像。

    docker-compose.override.yml

    1. web:
    2.   build: .
    3.   volumes:
    4.     – ‘.:/code’
    5.   ports:
    6.     – 8883:80
    7.   environment:
    8.     DEBUG: ‘true’
    9.  
    10. db:
    11.   command: ‘-d’
    12.   ports:
    13.     – 5432:5432
    14.  
    15. cache:
    16.   ports:
    17.     – 6379:6379

    当执行docker-compose up命令时它会自动读取这个override文件。

    现在我们创建另一个用于生产环境的override文件。

    docker-compose.prod.yml

    1. web:
    2.   ports:
    3.     – 80:80
    4.   environment:
    5.     PRODUCTION: ‘true’
    6.  
    7. cache:
    8.   environment:
    9.     TTL: ‘500’

    要使用这个生产compose文件部署,运行如下命令:

    1. docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

    这个将会使用docker-compose.yml和docker-compose.prod.yml(没有用到docker-compose.override.yml)来部署这三个服务。

    管理任务

    另一个常见的用例是针对在compose app中的一个或多个服务运行adhoc或管理任务。这个示例演示备份运行中的数据库。

    docker-compose.yml

    1. web:
    2.   image: example/my_web_app:latest
    3.   links:
    4.     – db
    5.  
    6. db:
    7.   image: postgres:latest

    在docker-compose.admin.yml中添加一个新服务用到导出数据库或备份。

    1. dbadmin:
    2.   build: database_admin/
    3.   links:
    4.     – db

    要启动一个正常的环境运行docker-compose up -d。要备份数据库,运行:

    1. docker-compose -f docker-compose.yml -f docker-compose.admin.yml
    2.     run dbadmin db-backup

    扩展服务

    docker compose的extends关键词能够在不同的文件或甚至完全不同的项目之间共享通用的配置。如果有几个重用通用配置项集的服务,则扩展服务非常有用。使用extends你可以在一个地方定义一个通用的服务选项集然后在任何地方引用它。

    注意:不能使用extends来共享links, volumes_from和depends_on配置。这是为了避免隐式依赖 – 始终在本地定义links和volumes_fromm。这确保了当读取当前文件时服务之间的依赖是清晰可见的。在本地定义这些还确保对引用文件的更改不会导致破坏。

    理解extends配置

    当在docker-compose.yml定义任何服务时,可以像这样声明扩展另一个服务:

    1. web:
    2.   extends:
    3.     file: common-services.yml
    4.     service: webapp

    这告诉compose重用定义在comm-services.yml文件的webapp服务配置。假设common-services.yml看起来像这样的:

    1. webapp:
    2.   build: .
    3.   ports:
    4.     – "8000:8000"
    5.   volumes:
    6.     – "/data"

    在这种情况下,docker-compose.yml中定义的web服务将与webapp配置一样。

    我们可以进一步在本地定义(或重新定义)docker-compose.yml:

    1. web:
    2.   extends:
    3.     file: common-services.yml
    4.     service: webapp
    5.   environment:
    6.     – DEBUG=1
    7.   cpu_shares: 5
    8.  
    9. important_web:
    10.   extends: web
    11.   cpu_shares: 10

    也可以定义其它服务并在web服务链接它们:

    1. web:
    2.   extends:
    3.     file: common-services.yml
    4.     service: webapp
    5.   environment:
    6.     – DEBUG=1
    7.   cpu_shares: 5
    8.   links:
    9.     – db
    10. db:
    11.   image: postgres

    示例用例

    当多个服务有一个通用的配置时,扩展单个服务非常有用。下面示例是有两个服务的compose app:一个web应用程序和一个queue worker。两个服务使用相同的代码和共享许多配置项。

    在common.yml我们定义通用的配置:

    1. app:
    2.   build: .
    3.   environment:
    4.     CONFIG_FILE_PATH: /code/config
    5.     API_KEY: xxxyyy
    6.   cpu_shares: 5

    在docker-compose.yml文件我们定义使用通用配置的具体服务:

    1. webapp:
    2.   extends:
    3.     file: common.yml
    4.     service: app
    5.   command: /code/run_web_app
    6.   ports:
    7.     – 8080:8080
    8.   links:
    9.     – queue
    10.     – db
    11.  
    12. queue_worker:
    13.   extends:
    14.     file: common.yml
    15.     service: app
    16.   command: /code/run_worker
    17.   links:
    18.     – queue

    添加和覆盖配置

    compose从original服务复制配置到local服务。如果配置项定义在original服务和local服务中,local服务的值替换或扩展original服务的值。

    对于单值选项如image,command或mem_limit,新值替换旧值。

    1. # original service
    2. command: python app.py
    3.  
    4. # local service
    5. command: python otherapp.py
    6.  
    7. # result
    8. command: python otherapp.py

    注意:当使用的是version 1的compose文件格式时,build和image两个选项,在local服务使用一个选项会导致compose忽略另一个如果定义在original服务的选项。

    例如,如果orginal服务定义了image: webapp且local服务定义了build: . 那么结果是服务有build: .选项没有image选项。

    这是因为在verion 1文件中build和image不能一起使用。

    对于多值选项ports,expose,external_link,dns,dns_search物tmpfs,compose连接两组值:

    1. # original service
    2. expose:
    3.   – "3000"
    4.  
    5. # local service
    6. expose:
    7.   – "4000"
    8.   – "5000"
    9.  
    10. # result
    11. expose:
    12.   – "3000"
    13.   – "4000"
    14.   – "5000"

    对于environment, labels, volumes和devices,compose以本地定义的值优先原则来合并它们:

    1. # original service
    2. environment:
    3.   – FOO=original
    4.   – BAR=original
    5.  
    6. # local service
    7. environment:
    8.   – BAR=local
    9.   – BAZ=local
    10.  
    11. # result
    12. environment:
    13.   – FOO=original
    14.   – BAR=local
    15.   – BAZ=local

    关于Docker Compose的环境变量

    在compose文件中引用环境变量

    可以在compose文件中引用运行docker-compose所在的shell中的环境变量,如:

    1. web:
    2.   image: "webapp:${TAG}"

    在容器中设置环境变量

    可以在compose文件中的environment关键词下设置容器的环境变量,就像docker run -e VARIABLE=VALUE …:

    1. web:
    2.   environment:
    3.     – DEBUG=1

    将环境变量传递到容器

    可以在compose文件中的environment关键词下定义一个环境变量而不赋值,就像docker run -e VARIABLE …:

    1. web:
    2.   environment:
    3.     – DEBUG

    容器中环境变量DEBUG的值是从执行compose文件所在的shell的同一个环境变量取得。

    env_file配置选项

    可以使用compose文件中的env_file选项从一个外部的文件传递多个环境变量到容器中,就像docker run –env-file=FILE …:

    1. web:
    2.   env_file:
    3.     – web-variables.env

    使用docker-compose run设置环境变量

    就像docker run -e,可以使用docker-compose run -e为一次性容器设置环境变量:

    1. docker-compose run -e DEBUG=1 web python console.py

    也可以不赋值从shell变量中取值:

    1. docker-compose run -e DEBUG web python console.py

    DEBUG的值是从执行compose文件所在的shell的同一个环境变量取得。

    .env文件

    可以在环境文件.env设置默认的环境变量,这些环境变量可以在compose文件引用:

    1. $ cat .env
    2. TAG=v1.5
    3.  
    4. $ cat docker-compose.yml
    5. version: ‘2.0’
    6. services:
    7.   web:
    8.     image: "webapp:${TAG}"

    当执行docker-compose up命令,上面定义的web服务将使用webapp:v1.5镜像。可以使用config命令来打印出来:

    1. $ docker-compose config
    2. version: ‘2.0’
    3. services:
    4.   web:
    5.     image: ‘webapp:v1.5’

    在shell中的环境变量将比定义在.env文件中的环境变量优先。如果在shell中设置了一个不同的TAG,镜像将使用shell中定义的而不是.env文件中的:

    1. $ export TAG=v2.0
    2. $ docker-compose config
    3. version: ‘2.0’
    4. services:
    5.   web:
    6.     image: ‘webapp:v2.0’