一、前言

docker-compose 依赖于yml文件,默认为docker-compose.yml文件,通过yml文件,可以完成一系列的服务编排,指定服务间的依赖,网络,挂载卷等,因此有必要掌握compose配置文件

二、compose 配置文件介绍

YML文件是一种非标记语言,以数据为中心,使用空白,缩进,分行组织数据

基本原则

  • 大小写敏感
  • 使用缩进表示层级关系
  • 禁止使用tab键,只能使用空格
  • 缩进长度没有限制,只要元素对齐就表示同一层级
  • 使用#表示注释
  • 字符串可以不用引号标注

数据结构

  1. 对象
  2. 数组
  3. 值类型和字符串

三、compose 配置文件详解

1.version

指定compose文件的版本号, 有1,2,3个版本,目前最新的是3版本,1版本已经在慢慢弃用,建议使用最新版本,如下命令,指定3版本

version: "3"

2.services

根节点,编排的服务需要写在services下面,如下配置,在services下编排了web服务和nginx服务,web,nginx服务名称可自己定义

version: '3'
services:
    web:
      image: dev_tools_web
    nginx:
       image: my_nginx:v1

注意名称不能使用大写,如下配置有myWeb有大写

version: '3'
services:
    myWeb:
      image: dev_tools_web
    nginx:
       image: my_nginx:v1

运行时报如下错误

docker compose 配置redis dockercompose配置文件_Dockerfile

3.image

指定镜像的名称或镜像ID,先从本地镜像仓库中找,如果找到,使用本地镜像,如果找不到,则从中央仓库下载,如下配置均可以

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

4.build

除了使用image指定镜像外,还可以通过Dockerfile文件,在up命令启动时执行构建,使用的构建标签就是build,它可以指定Dockerfile文件所在目录,compose可以通过Dockerfile文件生成镜像,然后通过该镜像启动容器服务

Dockerfile文件放在/home/ubuntu/dev_tools目录下,因此可以使用绝对路径

version: '3'
services:
    web:
       build: /home/ubuntu/dev_tools

也可以使用相对路径,只要能读到Dockerfile文件

build: ../dev_tools

5.context

除了在build中直接指定Dockerfile所在目录的路径外,还可以通过contest上下文,指定上下文后,可以基于指定的上下文找Dockerfile文件

version: '3'
services:
    web:
       build:
         context: /home/ubuntu
         dockerfile: ./dev_tools/Dockerfile

6.container_name

容器的默认名称是<项目名><服务名><序号>,如果需要指定容器名称,可以使用container_name,在如下配置中,指定容器的名称为my_web

version: '3'
services:
    web:
      image: dev_tools_web
      container_name: my_web

通过docker-compose up -d创建并启动容器后,再使用docker-compose ps -a使用查看,发现容器名称已变成my_web

docker compose 配置redis dockercompose配置文件_数据_02


但是这样会有一个问题,由于容器名称是唯一的,指定容器名称后,就无法进行扩容,比如要把web服务扩容到5个节点,执行扩容命令 docker-compse scale web=5,则出现如下错误

docker compose 配置redis dockercompose配置文件_数据_03

7.ports

指定容器的端口映射,是一个数组,使用HOST:CONTAINER格式,或者只是指定容器的端口,宿主机会随机映射端口,如下配置,指定了缩主机(8090)和容器(8081)的端口映射

version: '3'
services:
    web:
      image: dev_tools_web
      ports:
        - 8090:8081

还可以同时指定多个端口,如下配置均有效

ports:
 - "3000"
 - "8090:8081"
 - "49100:22"
 - "127.0.0.1:8001:8001"

注意:当使用HOST:CONTAINER格式来映射端口时,如果你使用的容器端口小于60你可能会得到错误得结果,因为YAML将会解析xx:yy这种数字格式为60进制。所以建议采用字符串格式

8.depends_on

如果服务需要依赖于其他服务,可以使用depends_on指定依赖关系,depends_on是一个数组,compose创建并启动一个服务时,会优先启动依赖的服务,如下配置,web服务依赖于redis和db,先启动redis和db后,才会启动web服务

version: '3'
services:
    web:
      image: dev_tools_web
      ports:
         - 8081:8081
      depends_on:
       - redis
       - db
    redis:
       image: wodby/redis
       ports:
          - 6379:6379
    db:
       image: mysql
       ports:
          - 3306:3306

9.volumes

挂载一个目录或已存在的数据卷容器,可以使用[HOST:CONTAINER]或[HOST:CONTAINER:ro]这样的格式,对于后者来说,数据卷只读,这样可以保证宿主机的文件不被修改
compose的数据卷可以是相对路径,也可以是绝对路径,还可以是已存在的数据卷(但是容器挂载路径只能是绝对路径)

version: '3'
services:
    web:
      image: dev_tools_web
      volumes:
       # 只指定容器挂载目录,Docker会制动创建一个数据卷
       - /app/logs
       # 使用绝对路径挂载数据卷
       - /app/data:/tmp/data:ro
       # 以 Compose 配置文件为中心的相对路径作为数据卷挂载到容器
       - ./cache:/tmp/cache
       # 已经存在的数据卷
       - file_data:/tmp/file_data
volumes:
    file_data:

以上配置,使用docker-compose config检查配置,结果如下

docker compose 配置redis dockercompose配置文件_Dockerfile_04


以上结果可看出,挂载目录./cache:/tmp/cache和数据卷file_data未指定操作权限,默认权限为rw–可读可写;如果数据卷需要给其他服务共享,则需要定义在volumes标签下,服务启动时,如果数据卷不存在,则先创建数据卷,如下启动结果

docker compose 配置redis dockercompose配置文件_数据_05


配置 - /app/logs未指定数据卷,启动服务时,docker会自动创建一个数据卷,如下结果

docker compose 配置redis dockercompose配置文件_数据_06


配置 - /app/data:/tmp/data:ro- ./cache:/tmp/cache指定的是宿主机和容器的挂载目录,这种挂载目录只能容器内部使用

compose创建并启动容器时

  1. 在宿主机中:在根路径下会自动中创建app和data目录,在yml文件所在路径下创建cache目录
  2. 在容器中:自动在根路径下创建tmp目录及其data,cache,file_data子目录,使用命令
    docker exec -it app_web_1 /bin/bash进入到容器内部,发现根路径下多出tmp目录,并在tmp目录中有data,cache,file_data子目录

    删除容器时,在容器启动时创建的数据卷并不会自动删除,需要使用docker volume rm [volume_name]手动删除

10.networks

Docker提供的network功能能够对容器进行网络上的隔离,如下配置,我们创建了三个服务和两个网络,其中proxy和web共用frantnet网络,web和db共用endnet网络

version: '3'
services:
    proxy:
      image: nginx
      networks:
        - frantnet
    web:
      image: dev_tools_web
      networks:
        - frantnet
        - endnet
    db:
      image: mysql
      networks:
        - endnet
networks:
   frantnet:
   endnet:

使用命令 docker-compose up -d启动服务,从执行结果可看出,创建了两个网络和三个容器

docker compose 配置redis dockercompose配置文件_数据_07


使用docker network ls可以查看到创建的网络

docker compose 配置redis dockercompose配置文件_docker_08


使用命令 docker exec -it app_web_1 /bin/bash进入到容器app_web_1中检查容器的网络连接状态,

docker compose 配置redis dockercompose配置文件_Dockerfile_09


因为 we 服务同时连接到了 frantnet 和 endnet 两个网络中,所以它可以同时连接这两个网络中的其它容器(proxy 和 db),(注意,ping命令前需要在容器中通过 apt-get update && apt-get install iputils-ping命令安装 ping 命令):

然后连接到app_proxy_1容器中,访问db服务,发现proxy中也可以访问到db,不是说存在网络隔离吗,怎么还能访问到呢,这是因为frantnet和endnet都是brigde,想要实现网络隔离,需要指定为overlay

networks:
  endnet:
    driver: overlay
  frantnet:
    driver: overlay

PS:要指定overlay,要求节点在swarm中