1

一、Docker Compose 介绍

1.1、Docker Compose 简介

        Compose 是用于配置和运行多个 Docker 容器的工具。通过Compose,你可以使用 YAML 文件来配置应用程序,然后使用 docker-compose 命令,就可以从配置文件中创建并启动所有服务。

        说通俗点,Docker Compose 就是一个容器编排工具(当然了,容器编排工具不知这一种,过后我们要学习的 Kubernetes 就是一种使用很广泛的容器编排工具)。比如你现在要使用 Docker 部署一套 lnmp 环境,之前的方案是分别拉取 NginxMySQLPHP 三个镜像,然后基于这三个镜像分别启动三个容器,这期间你还得考虑数据持久化、网络互通等问题,这个过程是有点麻烦的;那么有没有什么办法可以简化这些步骤? Docker Compose 的出现解决了这个问题,通过 YAML 格式的配置文件,你可以一步到位的部署好你的 lnmp 环境,后面我们将手动操作,以便加深理解。

        通过 Dockerfile 可以管理一个单独的容器,而通过 Docker Compose 你可以更方便的管理一组相关联的容器。

        使用Compose基本上是一个三步的过程:

  1. 使用 Dockerfile 定义应用程序的环境;
  2. docker-compose.yml 中定义组成您的应用程序的服务,以便不同的容器可以相互通信;
  3. 通过执行 docker-compose up 启动并运行您的整个应用程序。

        Docker Compose 的核心就是这个 YAML 文件,当你创建好这个 YAML 文件后,你可以通过 docker-compose 命令来同时管理(创建、启动、停止、删除等)一组相关联的容器。

1.2、Docker Compose YAML 文件

        随着 Docker 的发展,Docker 迭代了很多个版本,那么对应的 Docker Compose 的 YAML 文件的书写格式也进行了几次升级,目前最新版为 3.7,支持 Docker 18.06.0 以上的版本,也是我们用的比较多的格式版本。

        YAML 文件书写格式可以参考此链接

       Docker Compose 的  YAML 文件通常由三大部分组成的(当然还有其他模块),分别是:

  • Services:一个 Server 代表一个/组 Container(可以来自 DockerHub 的 image 来创建,也可以来自本地的 Dockerfile Build 来创建),Service 模块中可以引用以下的 Networks 模块和 Volumes 模块 定义的 network 和 volume;
  • Networks:要加入的网络;
  • Volumes:volume 挂载路径设置,可以设置宿主机路径 (HOST:CONTAINER) 或加上访问模式 (HOST:CONTAINER:ro)。
        docker run -v HOST:CONTAINER 如果未指定 “rw” 或 “ro”,则默认为 ”rw“,即 ”read-write“ 模式——”docker run -v HOST:CONTAINER:rw“,如果你希望挂载文件为只读,则可以使用 ”ro“ 选项,即 ”docker run -v HOST:CONTAINER:ro“        

        Services 很像 docker container create ;同样地,NetworksVolumes 类似于docker network createdocker volume create

二、安装 Docker Compose

        不同平台安装方法不同,如果你是 Mac 平台,那么你安装 Docker 时,就已经安装好了 docker-compose 工具;下面以常用的 CentOS 为例,介绍安装 docker-compose 的过程,其他平台安装方法参考 https://docs.docker.com/compose/install/

2.1、pip 方式安装 docker-compose

        Docker Compose 是使用 python 编写的,你可以使用 pip 的方式安装;这种安装方式相比于下面另一种安装方式要快一点,国内服务器可以使用这种方式安装。

# 安装epel和pip以及python-devel
$ sudo yum -y install epel-release
$ sudo yum -y install python-pip python-devel

# 通过pip安装 docker-compose
$ sudo pip install docker-compose --ignore-installed requests

2.2、curl 方式安装docker-compose

        国内用户访问 github.com 巨慢,可以用pip的方式安装

# 下载 docker-compose 工具,并指定下载路径
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 赋予可执行权限
$ sudo chmod +x /usr/local/bin/docker-compose

2.3、使用帮助

        安装完成后你可以使用 docker-compose --help 命令来查看 docker-compose 命令的使用帮助,看不懂没关系,后期使用此命令时自然会理解这些参数的意义。

$ sudo docker-compose --help
Define and run multi-container applications with Docker.

Usage:
  docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]
  docker-compose -h|--help

Options:
  -f, --file FILE             Specify an alternate compose file
                              (default: docker-compose.yml)
  -p, --project-name NAME     Specify an alternate project name
                              (default: directory name)
  --verbose                   Show more output
  --log-level LEVEL           Set log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
  --no-ansi                   Do not print ANSI control characters
  -v, --version               Print version and exit
  -H, --host HOST             Daemon socket to connect to

  --tls                       Use TLS; implied by --tlsverify
  --tlscacert CA_PATH         Trust certs signed only by this CA
  --tlscert CLIENT_CERT_PATH  Path to TLS certificate file
  --tlskey TLS_KEY_PATH       Path to TLS key file
  --tlsverify                 Use TLS and verify the remote
  --skip-hostname-check       Don't check the daemon's hostname against the
                              name specified in the client certificate
  --project-directory PATH    Specify an alternate working directory
                              (default: the path of the Compose file)
  --compatibility             If set, Compose will attempt to convert keys
                              in v3 files to their non-Swarm equivalent
  --env-file PATH             Specify an alternate environment file

Commands:
  build              Build or rebuild services
  bundle             Generate a Docker bundle from the Compose file
  config             Validate and view the Compose file
  create             Create services
  down               Stop and remove containers, networks, images, and volumes
  events             Receive real time events from containers
  exec               Execute a command in a running container
  help               Get help on a command
  images             List images
  kill               Kill containers
  logs               View output from containers
  pause              Pause services
  port               Print the public port for a port binding
  ps                 List containers
  pull               Pull service images
  push               Push service images
  restart            Restart services
  rm                 Remove stopped containers
  run                Run a one-off command
  scale              Set number of containers for a service
  start              Start services
  stop               Stop services
  top                Display the running processes
  unpause            Unpause services
  up                 Create and start containers
  version            Show the Docker-Compose version information

三、使用 Docker Compose

3.1、一个简单的 docker-compose.yml 文件示例

        在存在 docker-compose.yml 的目录下使用 docker-compose up 命令,可以直接创建并启动配置文件中的容器;一般情况下,docker-compose.ylm 文件与项目文件放在同一个目录,此目录名称为默认的项目名称,当然你也可以在 docker-compose up 的时候加上 -p 参数来自定义项目名称。

        以下示例来自 Wordpress,YAML 格式不了解的,建议花二分钟看一下 此链接。以下示例中你可以看到一些 ”key“ ,比如 versionserviceswordpressimagerestart 等,你可以在 这里 找到这些 ”key“ 的具体意义,如果你对 docker 有一定的了解的话,下面这个示例文件内的 ”key“ 你应该是可以看得明白的。

version: "3.7"
services:

 wordpress:
   image: wordpress:latest
   restart: always
   ports:
     - 8080:80
   environment:
     WORDPRESS_DB_HOST: db
     WORDPRESS_DB_USER: userwp
     WORDPRESS_DB_PASSWORD: pwdwp
     WORDPRESS_DB_NAME: wordpress
   volumes:
     - wordpress:/var/www/html
   networks:
     - db-net
     - web-net

 db:
   image: mysql:8.0.18
   command: --default-authentication-plugin=mysql_native_password
   restart: always
   environment:
     MYSQL_ROOT_PASSWORD: password
     MYSQL_DATABASE: wordpress
     MYSQL_USER: userwp
     MYSQL_PASSWORD: pwdwp

   volumes:
     - mysql8_db:/var/lib/mysql
   networks:
     - db-net

volumes:
  mysql8_db:
  wordpress:
networks:
  web-net:
  db-net:

        解释一下上面这个配置文件,docker-compose.yml 配置文件内部结构由三部分组成:

  • Services:此例中包含 wordpress 和 db 两个 service
  • Volumes:此例中包含 wordpress 和 mysql8_db 两个 volume
  • Networks:此例中包含 web-net 和db-net 两个 network

        你可以这样理解,Volumes 和 Networks 都属于容器(Services)的一部分,或者说容器(Services)调用 Volumes 和 Networks 标签声明的 volumes 和 networks,所以,调用的 volumes 和 networks 的名称需要与声明的名称相同,画了个简单的图,你可以对照代码看一下。

3.2、使用 docker-compose 工具

        以上配置文件创建好以后,我们便可以通过 docker-compose 命令来进行一番体验了。

$ sudo pwd
/docker/myblog

# Create and start containers, -d 后台运行
$ sudo docker-compose up -d
Creating network "myblog_web-net" with the default driver
Creating network "myblog_db-net" with the default driver
Creating volume "myblog_mysql8_db" with default driver
Creating volume "myblog_wordpress" with default driver
Creating myblog_db_1        ... done
Creating myblog_wordpress_1 ... done
        实际上 docker-compose create 已经不建议使用,如果你只想创建容器而不启动,官方建议使用 docker-compose up --no-start ,然后再通过 docker-compose start 来启动这些容器。

        另外注意,docker-compose scale 这个命令已经废弃,不建议使用

        执行 docker-compose --help 后可以看到 docker-compose 工具的详细用发,都是些基础的 IT 英文,我就不翻译了,请务必自行练习以下命令:

  • docker-compose up
  • docker-compose stop
  • docker-compose start
  • docker-compose down
  • docker-compose images
  • docker-compose log
  • docker-compose ps
  • docker-compose top

四、docker-compose.yml 文件

4.1、官方示例文件

        以下为官方 docker-compose.yml 示例文件

version: "3.7"
services:

  redis:
    image: redis:alpine
    ports:
      - "6379"
    networks:
      - frontend
    deploy:
      replicas: 2
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: on-failure

  db:
    image: postgres:9.4
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - backend
    deploy:
      placement:
        constraints: [node.role == manager]

  vote:
    image: dockersamples/examplevotingapp_vote:before
    ports:
      - "5000:80"
    networks:
      - frontend
    depends_on:
      - redis
    deploy:
      replicas: 2
      update_config:
        parallelism: 2
      restart_policy:
        condition: on-failure

  result:
    image: dockersamples/examplevotingapp_result:before
    ports:
      - "5001:80"
    networks:
      - backend
    depends_on:
      - db
    deploy:
      replicas: 1
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: on-failure

  worker:
    image: dockersamples/examplevotingapp_worker
    networks:
      - frontend
      - backend
    deploy:
      mode: replicated
      replicas: 1
      labels: [APP=VOTING]
      restart_policy:
        condition: on-failure
        delay: 10s
        max_attempts: 3
        window: 120s
      placement:
        constraints: [node.role == manager]

  visualizer:
    image: dockersamples/visualizer:stable
    ports:
      - "8080:8080"
    stop_grace_period: 1m30s
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      placement:
        constraints: [node.role == manager]

networks:
  frontend:
  backend:

volumes:
  db-data:

4.2、Services 配置参数

        这部分相当于 Google 翻译官方文档了,稍微整理了一下,感觉不常用的参数我就没列出来,所以不是很全面,觉得看着别扭的话你可以直接看官方文档。

4.2.1、build - 构建

4.2.1.1、build - 构建

        容器的创建可以来自 Docker Hub 的镜像,也可以来自本地使用 Dockerfile 构建的镜像,build 便是指定容器为本地构建的 Dockerfile 文件的路径;

        指定构建镜像的上下文路径:

        例如 webapp 服务,指定为从上下文路径 ./dir/dockerfile 所构建的镜像:

version: "3.7"
services:
  webapp:
    build: ./dir

        或者,指定具体的 Dockerfile 文件:

version: "3.7"
services:
  webapp:
    build:
      context: ./dir
      dockerfile: Dockerfile-alternate
4.2.1.2、context - 上下文

        构建镜像的上下文(Dockerfile 的目录),可以是相对路径(相对于 docker-compose.yml 文件的相对路径)和绝对路径。

build:
  context: ./dir
4.2.1.3、dockerfile - dockerfile 文件
build:
  context: .
  dockerfile: Dockerfile-alternate
4.2.1.4、args - 构建参数

        添加构建参数,这是只能在构建过程中访问的环境变量。

        前提是你需要在 Dockerfile 中指定参数,

ARG buildno
ARG gitcommithash

RUN echo "Build number: $buildno"
RUN echo "Based on commit: $gitcommithash"

        然后在 docker-compose 的 build 下指定参数,您可以传递映射或列表:

build:
  context: .
  args:
    buildno: 1
    gitcommithash: cdc3b19
build:
  context: .
  args:
    - buildno=1
    - gitcommithash=cdc3b19
    注意:在Dockerfile中,如果在FROM指令之前指定ARG,则在FROM下的构建指令中ARG不可用。如果您需要一个参数在两个地方都可用,请在FROM指令下指定该参数。有关用法的详细信息,请参阅了解ARGS和FROM的交互方式
4.2.1.5、cache_from - 缓存images

        默认情况下,在构建 Docker 镜像时,Docker 使用它的构建缓存来检查它是否可以跳过Dockerfile 中的任何步骤,该 cache_from 参数告诉 docker,可用缓存的镜像是什么;如果提供的镜像和当前版本具有相同的层(之前提过层的概念),则可以获得与在同一台计算机上构建镜像时以相同层构建出更快的速度。

build:
  context: .
  cache_from:
    - alpine:latest
    - corp/web_app:3.14
4.2.1.6、labels - Docker 标签

        格式有下面两种:

build:
  context: .
  labels:
    com.example.description: "Accounting webapp"
    com.example.department: "Finance"
    com.example.label-with-empty-value: ""
build:
  context: .
  labels:
    - "com.example.description=Accounting webapp"
    - "com.example.department=Finance"
    - "com.example.label-with-empty-value"
4.2.1.7、target - 构建阶段

        根据Dockerfile中的定义构建指定的阶段。 有关详细信息,请参见之前提过的多阶段构建。

build:
  context: .
  target: prod

4.2.2、command - 覆盖命令

        覆盖容器启动时的默认命令

command: bundle exec thin -p 3000
command: ["bundle", "exec", "thin", "-p", "3000"]

4.2.3、container_name - 指定容器名称

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

container_name: my-web-container
        由于Docker容器名称必须唯一,因此如果您指定了自定义名称,则不能将服务扩展到1个以上的容器。

4.2.4、deploy - 集群部署

4.2.4.1、deploy - 集群部署

        指定与服务的部署和运行有关的配置,只在 swarm 模式下才会有用,会被 docker-compose updocker-compose run 忽略.

version: "3.7"
services:
  redis:
    image: redis:alpine
    deploy:
      replicas: 6
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: on-failure
4.2.4.2、endpoint_mode - 访问集群服务的方式

        两种模式:

  • endpoint_mode: vip - Docker为服务分配了一个虚拟IP(VIP),该虚拟IP充当客户端访问网络上服务的前端。 Docker在客户端和服务的可用工作节点之间路由请求,而无需客户端知道有多少节点正在参与服务或其IP地址或端口。 (这是默认设置。)
  • endpoint_mode: dnsrr- DNS轮询(DNSRR)服务发现不使用单个虚拟IP。 Docker设置服务的DNS条目,以便对服务名称的DNS查询返回IP地址列表,并且客户端直接连接到其中之一。在想要使用自己的负载平衡器或混合Windows和Linux应用程序的情况下,DNS轮询很有用。
version: "3.7"

services:
  wordpress:
    image: wordpress
    ports:
      - "8080:80"
    networks:
      - overlay
    deploy:
      mode: replicated
      replicas: 2
      endpoint_mode: vip

  mysql:
    image: mysql
    volumes:
       - db-data:/var/lib/mysql/data
    networks:
       - overlay
    deploy:
      mode: replicated
      replicas: 2
      endpoint_mode: dnsrr

volumes:
  db-data:

networks:
  overlay:
4.2.4.3、labels - 指定标签

        指定服务标签。这些标签仅在服务上设置,而不在服务的任何容器上设置。

version: "3.7"
services:
  web:
    image: web
    deploy:
      labels:
        com.example.description: "This label will appear on the web service"
4.2.4.4、mode - 集群模式

       global(每个群集节点一个容器) orreplicated(指定数量的容器). 默认为 replicated.

version: "3.7"
services:
  worker:
    image: dockersamples/examplevotingapp_worker
    deploy:
      mode: global
4.2.4.5、replicas - replicated 模式的容器数量

        如果选择了 replicated 模式,replicas 用来指定运行的容器数量

version: "3.7"
services:
  worker:
    image: dockersamples/examplevotingapp_worker
    networks:
      - frontend
      - backend
    deploy:
      mode: replicated
      replicas: 6
4.2.4.6、resources - 资源限制

        以下示例中,redis服务被限制为使用不超过50M的内存和0.50(单核的50%)的可用处理(CPU),并有最低20M的内存和0.25的CPU资源使用。

version: "3.7"
services:
  redis:
    image: redis:alpine
    deploy:
      resources:
        limits:
          cpus: '0.50'
          memory: 50M
        reservations:
          cpus: '0.25'
          memory: 20M
4.2.4.7、restart_policy - 重启规则

        配置如何在退出容器时重新启动容器。

  • condition:可选 none,on-failure 或者 any(默认值:any)。
  • delay:设置多久之后重启(默认值:0)。
  • max_attempts:尝试重新启动容器的次数,超出次数,则不再尝试(默认值:一直重试)。
  • window:设置容器重启超时时间(默认值:0)。
version: "3.7"
services:
  redis:
    image: redis:alpine
    deploy:
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 120s
4.2.4.8、rollback_config - 回滚规则

        配置在更新失败的情况下应如何回滚服务。

  • parallelism:一次要回滚的容器数。如果设置为0,则所有容器将同时回滚。
  • delay:每个容器组回滚之间等待的时间(默认为0s)。
  • failure_action:如果回滚失败,该怎么办。其中一个 continue 或者 pause(默认pause)。
  • monitor:每个容器更新后,持续观察是否失败了的时间 (ns|us|ms|s|m|h)(默认为0s)。
  • max_failure_ratio:在回滚期间可以容忍的故障率(默认为0)。
  • order:回滚期间的操作顺序。其中一个 stop-first(串行回滚),或者 start-first(并行回滚)(默认 stop-first )。
4.2.4.9、update_config - 更新规则

        配置应如何更新服务,对于配置滚动更新很有用。

  • parallelism:一次更新的容器数。
  • delay:在更新一组容器之间等待的时间。
  • failure_action:如果更新失败,该怎么办。其中一个 continue,rollback 或者pause (默认:pause)。
  • monitor:每个容器更新后,持续观察是否失败了的时间 (ns|us|ms|s|m|h)(默认为0s)。
  • max_failure_ratio:在更新过程中可以容忍的故障率。
  • order:回滚期间的操作顺序。其中一个 stop-first(串行回滚),或者 start-first(并行回滚)(默认stop-first)。
version: "3.7"
services:
  vote:
    image: dockersamples/examplevotingapp_vote:before
    depends_on:
      - redis
    deploy:
      replicas: 2
      update_config:
        parallelism: 2
        delay: 10s
        order: stop-first

4.2.5、devices - 设备映射

        指定设备映射列表。

devices:
  - "/dev/ttyUSB0:/dev/ttyUSB0"

4.2.6、dns - 定义DNS

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

dns: 8.8.8.8
dns:
  - 8.8.8.8
  - 9.9.9.9

4.2.7、dns_search - 定义DNS搜索域

        自定义DNS搜索域,可以是单个值或列表。

dns_search: example.com
dns_search:
  - dc1.example.com
  - dc2.example.com

4.2.8、entrypoint - 入口点

        覆盖容器默认入口点。

entrypoint: /code/entrypoint.sh
entrypoint:
    - php
    - -d
    - zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20100525/xdebug.so
    - -d
    - memory_limit=-1
    - vendor/bin/phpunit
        注意:设置入口点会覆盖所有使用 Dockerfile ENTRYPOINT 指令在服务镜像上设置的默认入口点,并清除镜像上的任何默认 CMD ,这意味着如果Dockerfile中有CMD指令,则会将其忽略。

4.2.9、env_file - 环境变量文件

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

env_file: .env
env_file:
  - ./common.env
  - ./apps/web.env
  - /opt/secrets.env

        .env 文件格式为 VAR=VAL

# Set Rails/Rack environment
RACK_ENV=development

4.2.10、environment - 添加环境变量

        添加环境变量。您可以使用数组或字典、任何布尔值,布尔值需要用引号引起来,以确保 YML 解析器不会将其转换为 True 或 False。

environment:
  RACK_ENV: development
  SHOW: 'true'
  SESSION_SECRET:
environment:
  - RACK_ENV=development
  - SHOW=true
  - SESSION_SECRET
       如果你使用了 build 选项,则在构建过程中不会自动显示 environment 中定义的变量,可以使用 buildargs 子选项来定义构建时环境变量。

4.2.11、expose - 声明端口

        暴露端口,但不映射到宿主机,只被连接的服务访问,仅可以指定内部端口为参数:

expose:
 - "3000"
 - "8000"

4.2.12、external_links - 链接容器

        链接到在docker-compose.yml之外甚至在Compose之外启动的容器,特别是对于提供共享或公共服务的容器。

external_links:
 - redis_1
 - project_db_1:mysql
 - project_db_1:postgresql

4.2.13、external_host - 添加主机映射

        添加主机名映射,类似 docker client --add-host

extra_hosts:
 - "somehost:162.242.195.82"
 - "otherhost:50.31.209.229"

        实现在容器内修改host /etc/hosts 文件的效果

162.242.195.82  somehost
50.31.209.229   otherhost

4.2.14、healthcheck - 健康检查

        配置运行检查,以确定此服务的容器是否“健康”。

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost"] # 设置检测程序
  interval: 1m30s # 设置检测间隔
  timeout: 10s # 设置检测超时时间
  retries: 3 # 设置重试次数
  start_period: 40s # 启动后,多少秒开始启动检测程序

4.2.15、image - 指定镜像

        指定要从中启动容器的镜像

image: redis
image: ubuntu:14.04
image: tutum/influxdb
image: example-registry.com:4000/postgresql
image: a4bc65fd

4.2.16、labels - 标签

        Services 容器标签

labels:
  com.example.description: "Accounting webapp"
  com.example.department: "Finance"
  com.example.label-with-empty-value: ""
labels:
  - "com.example.description=Accounting webapp"
  - "com.example.department=Finance"
  - "com.example.label-with-empty-value"

4.2.17、logging - 日志配置

        服务的日志记录配置。

logging:
  driver: syslog
  options:
    syslog-address: "tcp://192.168.0.42:123"

        这个 driver 名称为服务的容器指定了日志记录驱动程序,与docker run --log-driver 选项相同,默认值为 json-file,有以下三个选项:

driver: "json-file"
driver: "syslog"
driver: "none"

        仅在 json-file 驱动程序下,可以使用以下参数,限制日志得数量和大小;当达到文件限制上限,会自动删除旧得文件。

logging:
  driver: json-file
  options:
    max-size: "200k" # 单个文件大小为200k
    max-file: "10" # 最多10个文件

        syslog 驱动程序下,可以使用 syslog-address 指定日志接收地址。

logging:
  driver: syslog
  options:
    syslog-address: "tcp://192.168.0.42:123"

4.2.18、network_mode - 网络模式

4.2.18.1、network_mode - 网络模式

        设置网络模式

network_mode: "bridge"
network_mode: "host"
network_mode: "none"
network_mode: "service:[service name]"
network_mode: "container:[container name/id]"

        配置容器连接的网络,引用一级 networks 下的条目 。

services:
  some-service:
    networks:
     - some-network
     - other-network
4.2.18.2、aliases - 别名

        网络别名,可以指定多个别名。

version: "3.7"

services:
  web:
    image: "nginx:alpine"
    networks:
      - new

  worker:
    image: "my-worker-image:latest"
    networks:
      - legacy

  db:
    image: mysql
    networks:
      new:
        aliases:
          - database
          - dbnet
      legacy:
        aliases:
          - mysql

networks:
  new:
  legacy:
4.2.18.3、ipv4_address、ipv6_address - 静态网络

        加入网络后,为此服务的容器指定一个静态IP地址。

        一级 networks 部分中的相应网络配置必须具有ipam块,其子网配置覆盖每个静态地址。

version: "3.7"

services:
  app:
    image: nginx:alpine
    networks:
      app_net:
        ipv4_address: 172.16.238.10
        ipv6_address: 2001:3984:3989::10

networks:
  app_net:
    ipam:
      driver: default
      config:
        - subnet: "172.16.238.0/24"
        - subnet: "2001:3984:3989::/64"

4.2.19、ports - 暴露端口

        使用宿主port:容器port(HOST:CONTAINER)格式或者仅仅指定容器的端口(宿主将会随机选择端口)都可以。

ports:
 - "3000"
 - "3000-3005"
 - "8000:8000"
 - "9090-9091:8080-8081"
 - "49100:22"
 - "127.0.0.1:8001:8001"
 - "127.0.0.1:5000-5010:5000-5010"
 - "6060:6060/udp"

        长语法:长语法允许配置其他不能以短格式表示的字段。

  • target: 容器内的端口
  • published: 公开暴露的端口
  • protocol: 端口协议 (tcporudp)
  • mode:host用于在每个节点上发布主机端口, 或ingress 用于群模式端口以实现负载平衡
ports:
  - target: 80
    published: 8080
    protocol: tcp
    mode: host

4.2.20、restart - 重启规则

        容器重启规则

  • no:是默认的重启策略,在任何情况下都不会重启容器。
  • always:容器总是重新启动。
  • on-failure:在容器非正常退出时(退出状态非0),才会重启容器。
  • unless-stopped:在容器退出时总是重启容器,但是不考虑在Docker守护进程启动时就已经停止了的容器
restart: "no"
restart: always
restart: on-failure
restart: unless-stopped

4.2.21、secrets - 存储敏感数据

        用来存储敏感文件,如密码等。

        短语法:以下示例使用短语法向redis服务授予对my_secretmy_other_secret机密的访问权限。 将my_secret的值设置为文件./my_secret.txt的内容,并将my_other_secret定义为外部资源,这意味着它已经在Docker中定义,可以通过运行docker secret create命令或其他堆栈进行定义 部署。 如果外部secrets不存在,则堆栈部署将失败,并显示“未找到secrets”错误。

version: "3.7"
services:
  redis:
    image: redis:latest
    deploy:
      replicas: 1
    secrets:
      - my_secret
      - my_other_secret
secrets:
  my_secret:
    file: ./my_secret.txt
  my_other_secret:
    external: true

4.2.22、security_opt - 修改概要标签

        修改容器的概要标签

security-opt:
  - label:user:USER   # 设置容器的用户标签
  - label:role:ROLE   # 设置容器的角色标签
  - label:type:TYPE   # 设置容器的安全策略标签
  - label:level:LEVEL  # 设置容器的安全等级标签

4.2.23、stop_grace_period

        在发送 SIGKILL 之前指定stop_signal,如果试图停止容器(如果它没有处理 SIGTERM(或指定的任何停止信号)),则需要等待的时间,默认情况下,stop 在发送SIGKILL之前等待10秒钟容器退出

stop_grace_period: 1s # 等待 1 秒
stop_grace_period: 1m30s # 等待 1 分 30 秒 

4.2.24、stop_signal - 容器停止信号

        设置停止容器的替代信号,默认情况下使用 SIGTERM ;以下示例,使用 SIGUSR1 替代信号 SIGTERM 来停止容器。

stop_signal: SIGUSR1

4.2.25、sysctls - 内核参数

        要在容器中设置的内核参数

sysctls:
  net.core.somaxconn: 1024
  net.ipv4.tcp_syncookies: 0
sysctls:
  - net.core.somaxconn=1024
  - net.ipv4.tcp_syncookies=0

4.2.26、tmpfs - 临时文件系统

        挂载临时文件目录到容器内部

tmpfs: /run
tmpfs:
  - /run
  - /tmp

4.2.27、ulimit - 覆盖容器默认ulimit

        覆盖容器默认的 ulimit

ulimits:
  nproc: 65535
  nofile:
    soft: 20000
    hard: 40000

4.2.28、volumes - 挂载volume

        将主机的数据卷或着文件挂载到容器里。

        挂载一个目录或者一个已存在的数据卷容器,可以直接使用HOST:CONTAINER这样的格式,或者使用HOST:CONTAINER:ro这样的格式,后者对于容器来说,数据卷是只读的,这样可以有效保护宿主机的文件系统

version: "3.7"
services:
  web:
    image: nginx:alpine
    volumes:
      - type: volume
        source: mydata
        target: /data
        volume:
          nocopy: true
      - type: bind
        source: ./static
        target: /opt/app/static

  db:
    image: postgres:latest
    volumes:
      - "/var/run/postgres/postgres.sock:/var/run/postgres/postgres.sock"
      - "dbdata:/var/lib/postgresql/data"

volumes:
  mydata:
  dbdata:

        数据卷的格式如下多种形式:

volumes:
  # 仅指定一个路径时,Docker 会自动创建一个数据卷(此路径是容器内部路径)
  - /var/lib/mysql

  # 使用绝对路径挂载数据卷
  - /opt/data:/var/lib/mysql

  # 以 Compose 配置文件为中心的相对路径作为数据卷挂载到容器
  - ./cache:/tmp/cache

  # 使用用户的相对路径(~/ 表示的目录是 /home/<用户目录>/ 或者 /root/)
  - ~/configs:/etc/configs/:ro

  # 挂载数据卷。
  - datavolume:/var/lib/mysql

4.2.29、domainname, hostname, ipc, privileged, read_only, shm_size, stdin_open, tty, user, working_dir

        每个值都只对应一个值,类似于其docker run的参数选项

user: postgresql
working_dir: /code

domainname: foo.com
hostname: foo
ipc: host

privileged: true

read_only: true
shm_size: 64M
stdin_open: true
tty: true

4.3、Volumes 配置参数

        允许您创建命名卷(不依赖volumes_from),这些卷可以在多个服务中重用,并且可以使用docker命令行或API。

        以下是两种服务设置的示例,其中 db 的数据目录作为卷与另一服务共享,以便可以定期备份它:

version: "3.7"

services:
  db:
    image: db
    volumes:
      - data-volume:/var/lib/db
  backup:
    image: backup-service
    volumes:
      - data-volume:/var/lib/backup/data

volumes:
  data-volume:

        一级volumes下的条目可以为空,在这种情况下,它使用引擎配置的默认驱动程序(在大多数情况下,这是 local驱动程序)。

4.3.1、labels - 标签

        volume 的标签

labels:
  com.example.description: "Database volume"
  com.example.department: "IT/Ops"
  com.example.label-with-empty-value: ""
labels:
  - "com.example.description=Database volume"
  - "com.example.department=IT/Ops"
  - "com.example.label-with-empty-value"

4.4、Networks 配置参数

        一级networks,允许您指定要创建的网络。

4.4.1、driver - 网络接入方式

    指定该网络应使用哪个驱动程序。

    默认驱动程序取决于您使用的Docker引擎的配置方式,但是在大多数情况下,它bridge位于单个主机和overlaySwarm上。

4.4.1.1、bridge - 网桥

        Docker 默认的网络接入方式

4.4.1.2、overlay - 覆盖

        该overlay驱动程序创建一个跨多个节点命名的网络

4.4.1.3、host 和 none

        使用主机的网络,或者不使用网络。等同于 docker run --network=hostdocker run --network=none,仅在使用docker stack命令时使用,如果使用docker-compose命令,请改用network_mode

4.4.2、IPAM - IP地址管理

        IP地址管理,有几个属性,每一个属性都是可选的:

  • driver:自定义IPAM驱动程序,而不使用默认的
  • config:有零个或多个配置块的列表,每个包含任何以下项:

    • subnet:子网CIDR格式表示一个网段

一个完整的例子:

ipam:
  driver: default
  config:
    - subnet: 172.28.0.0/16

4.4.3、labels - 网络标签

        网络标签

labels:
  com.example.description: "Financial transaction network"
  com.example.department: "Finance"
  com.example.label-with-empty-value: ""
labels:
  - "com.example.description=Financial transaction network"
  - "com.example.department=Finance"
  - "com.example.label-with-empty-value"

4.4.4、name - 网络名称

        自定义网络名称

version: "3.7"
networks:
  network1:
    name: my-app-net

        它也可以与external配合使用:

version: "3.7"
networks:
  network1:
    external: true
    name: my-app-net

4.5、configs 配置文件

        一级configs声明定义或引用可以授予此项目中的服务的配置。配置的来源是fileexternal

  • file:使用指定路径中的文件内容创建配置
  • external:如果设置为true,则表示此配置已创建,Docker不会尝试创建它;如果它不存在,则会发生 config not found错误
  • name:Docker中配置对象的名称,此字段可引用包含特殊字符的配置。

        在以下示例中,部署项目时创建了 my_first_config(as<stack_name> _my_first_config),并且Docker中已经存在my_second_config

configs:
  my_first_config:
    file: ./config_data
  my_second_config:
    external: true

        外部配置的另一个方式是Docker中的config名称与服务中存在的名称不同时,以下示例修改了前一个示例,以使用名为 redis_config 的外部配置。

configs:
  my_first_config:
    file: ./config_data
  my_second_config:
    external:
      name: redis_config

        配置好一级 configs 后仍然需要 将配置访问权限授予 项目中的每个服务。

4.6、secrets configuration reference

        顶级secrets声明定义或引用的secrets,可在这个项目被授予服务。secrets 来源于fileexternal

  • file:使用指定路径中的文件内容
  • external:如果设置为true,则表示这个 secret 已经创建指定,Docker 不会尝试创建它;如果它不存在,将报错secret not found
  • name:Docker中 secret 的名称

        在下面例子中,my_first_secret被创建为<stack_name>_my_first_secret当堆栈被部署,并my_second_secret在多克尔已经存在。

        在此示例中部署项目时,将my_first_secret创建为<stack_name> _my_first_secret,并且Docker中已经存在my_second_secret

secrets:
  my_first_secret:
    file: ./secret_data
  my_second_secret:
    external: true

        外部机密的另一个方式是Docker中的secret名称与服务中存在的名称不同时,以下示例修改了前一个示例,以使用名为redis_secret的外部secret。

# V3.5及以上
secrets:
  my_first_secret:
    file: ./secret_data
  my_second_secret:
    external: true
    name: redis_secret

五、Docker Compose 入门

        接下来我们将使用 Docker Compose 构建一个简单Python Web应用程序,该应用程序使用Flask框架,并在Redis中维护一个计数器程序(每访问一次web应该,就给输出的访问次数+1)。尽管该示例使用Python,但并不是说就需要你掌握 Python。

5.1、准备工作

        首先需要创建项目目录,以及准备 Python 程序代码,操作如下:

$ mkdir composetest
$ cd composetest

程序 app.py 的代码如下:

import time

import redis
from flask import Flask

app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)


def get_hit_count():
    retries = 5
    while True:
        try:
            return cache.incr('hits')
        except redis.exceptions.ConnectionError as exc:
            if retries == 0:
                raise exc
            retries -= 1
            time.sleep(0.5)


@app.route('/')
def hello():
    count = get_hit_count()
    return 'Hello World! I have been seen {} times.\n'.format(count)

        在 app.py 目录下创建名为 requirements.txt 的文件,文件内容如下

flask
redis

5.2、创建Dockerfile文件

        需要编写一个构建 Docker镜像 的 Dockerfile,该镜像包含 Python 应用程序以及此演示项目所需的所有依赖关系;具体的 Dockerfile 文件内容如下:

FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP app.py
ENV FLASK_RUN_HOST 0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . .
CMD ["flask", "run"]

        以上操作内容说明:

  • 以 Python 3.7 镜像作为基础镜像来构建新镜像。
  • 将工作目录设置为/code
  • 设置flask命令使用的环境变量。
  • 安装gcc,以便诸如MarkupSafe和SQLAlchemy之类的Python包可以编译加速。
  • 复制requirements.txt并安装Python依赖项。
  • 将项目中的当前目录复制到镜像中的工作目录。
  • 将容器的默认命令设置为flask run

5.3、创建 docker-compose.yml 文件

version: '3'
services:
  web:
    build: .
    ports:
      - "5000:5000"
  redis:
    image: "redis:alpine"

5.4、使用 docker-compose 构建启动项目

        使用命令 docker-compose up 启动这个项目,你将在执行命令后的输出内容的最后一行看到如下信息:

web_1    |  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

        接下来,通过curl命令来测试项目部署效果,此操作需要重新打开一个 shell 窗口,通过执行如下命令,来检查部署结果(你将在执行 docker-compose up 命令的窗口看到一些访问日志):

$ curl http://0.0.0.0:5000
Hello World! I have been seen 1 times.
$ curl http://0.0.0.0:5000
Hello World! I have been seen 2 times.
$ curl http://0.0.0.0:5000
Hello World! I have been seen 3 times.

5.4、查看镜像、容器详情

        你可以分别执行如下命令来查看此项目部署后产生了哪些镜像,启动了哪些容器,以及网络、数据卷的情况

$ docker image ls
$ docker ps
$ docker network ls
$ docker volume ls

5.5、补充

docker-compose.yaml 文件的编写需要多练习才能熟悉,熟悉不了也没关系,但最起码得了解个大概,知道都能定义哪些标签就行,遇到问题可以快速查阅官方文档或者个人笔记。

如果需要进一步了解 Docker Compose 的更多内容,建议去官方看文档;说白了,它就是个用于配置和运行多个 Docker 容器的工具,但是如果后期业务拆分模块较多,或者说微服务拆分较多的模块,就需要部署更多的容器,而且还得考虑负载均衡、故障自愈、网络通信、数据存储、容器管理等等问题,这时候 Docker Compose 就显得有点力不从心了;

所以,接下来的几个章节我们要学习更专业的容器编排管理工具,如 Mesos(Apache下的,诞生于2013年)、kubernetes(Google家的,诞生于2014年6月)、Swarm(Docker自家的,2016年的面世),后面我们会介绍Swarmkubernetes 这两个工具,另外一个自己去学习了解即可。

---

参考链接:

https://docs.docker.com/compose/

https://docs.docker.com/compose/compose-file/

https://docs.docker.com/compose/gettingstarted/


Liu_wt
35 声望3 粉丝

业余选手,多多指教!