本文从本人博客搬运,原文格式更加美观,可以移步原文阅读:docker-compose容器编排

基本介绍

docker-compose是docker官方的开源项目,负责实现对docker容器集群的快速编排。它的作用是定义和运行多个docker容器的应用

之前我们如果要启动多个容器,只能手动执行多个docker run命令。然而在日常工作中,一个项目往往要同时启动非常多的容器,并且容器的启动顺序也有要求,例如要运行一个web项目,除了启动web服务容器之外,还需要启动它依赖的mysql、redis等等,这时候手动一个个启动非常麻烦

docker-compose允许用户通过一个单独的docker-compose.yml模板文件来定义一组相关联的应用容器为一个项目,它有2个重要的概念:

  • 服务(service):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。在docker-compose.yml中定义
  • 项目(project):由一组关联的应用容器组成的一个完整业务单元,一个docker-compose.yml文件就代表一个项目

docker-compose的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。比如我们要开发一个Web项目,除了运行后端应用接口的容器,还需要依赖MySQL、Redis、RabbitMQ、Nginx等容器,那么就可以通过一个docker-compose.yml来统一编排管理这一组容器

安装

1.linux

从官方下载编译好的docker-compose二进制可执行文件,下载地址为:https://github.com/docker/compose/releases

下载完成后手动上传到linux指定目录/usr/local/bin,将其文件名修改成docker-compose。然后给其加上可执行权限

# 因为下载后的docker-compose文件是一个可执行脚本,所以要开放其权限
chmod +x /usr/local/bin/docker-compose

安装完成后可以用docker-compose -v检查安装是否成功

2.win/mac

win/mac平台安装docker后就自带docker-compose,可以直接使用

具体使用

1.入门

使用docker-compose的基本步骤如下:

  1. 编写docker-compose.yml模板文件,指定要编排运行的一组容器
  2. 利用docker-compose指令启动模板文件中的所有容器

我们来尝试启动2个tomcat,编写如下的docker-compose.yml

version: "3.2"  # 指定compose的版本

services:
  tomcat1: # 代表一个容器的服务名称,在文件中必须唯一
    image: tomcat:8.0-jre8  # 指定用哪个镜像来创建这个容器
    ports:
      - "8080:8080"  # 指定容器与宿主机的端口映射
  tomcat2: 
    image: tomcat:8.0-jre8 
    ports:
      - "8081:8080"

把上述模板文件在独立的一个目录中创建,这里是/docker/compose。然后在该目录下启动模板文件中定义的容器

docker-compose up

可以发现启动时,由于镜像不存在,compose先帮我们自动下载了镜像,然后启动2个tomcat容器,并且2个容器的日志颜色会进行区分

2.模板文件指令详解

模板文件指令指的是docker-compose.yml中可以写的指令。每个指令都可以类比为docker run中的某个参数

2.1 version

指的是docker compose的版本号,与docker的版本有对应关系:

Compose file formatDocker Engine release
Compose specification19.03.0+
3.819.03.0+
3.718.06.0+
3.618.02.0+
3.517.12.0+
3.417.09.0+
3.317.06.0+
3.217.04.0+
3.11.13.1+
3.01.13.0+
2.417.12.0+
2.317.06.0+
2.21.13.0+
2.11.12.0+
2.01.10.0+
1.01.9.1.+

2.2 image

指定运行容器的镜像名称或id,如果本地镜像不存在,compose将会尝试拉取这个镜像

2.3 ports

容器与宿主机的端口映射信息,格式为宿主机端口:容器端口,可以不指定宿主机端口,此时宿主机将会随机选择端口

version: "3.2"  

services:
  mytomcat: 
    image: tomcat:8.0-jre8  
    ports:
      - "8081:8080"
      - "8082:8082"

建议端口映射信息加上双引号,否则可能会出现一些意外错误

2.4 volumes

容器与宿主机的数据卷映射。可以采用如下格式:

  • 宿主机绝对路径:容器绝对路径
  • 数据卷名称:容器绝对路径,如果采用这种方式,还必须在后面声明所使用的数据卷
version: "3.2"  

services:
  mytomcat: 
    image: tomcat:8.0-jre8  
    ports:
      - "8080:8080"
    volumes:
      - tomcatwebapp:/usr/local/tomcat/webapps  # 数据卷映射,如果采用数据卷名称方式,必须在下面定义数据卷名称

volumes:
  tomcatwebapp:  # 声明上面所使用的数据卷

如果使用数据卷名称方式进行映射,那么在启动容器时,compose会自动帮我们创建一个数据卷,名称为项目名_自定义数据卷名,其中项目名为docker-compose.yml模板文件所在的目录名

如果不想使用compose帮我们自动创建的这个带项目名前缀的数据卷名称,可以指定使用外部已存在的数据卷名称,但此时必须先用docker volume create创建出指定的数据卷,否则会报错

version: "3.2"  

services:
  mytomcat: 
    image: tomcat:8.0-jre8  
    ports:
      - "8080:8080"
    volumes:
      - tomcatwebapp:/usr/local/tomcat/webapps  # 数据卷映射,如果采用数据卷名称方式,必须在下面定义数据卷名称

volumes:
  tomcatwebapp:  # 声明上面所使用的数据卷
    external: 
      true  # 使用外部已存在的数据卷tomcatwebapp,该数据卷必须存在,不存在的话必须先手动创建,否则报错

一般情况下使用compose默认帮我们创建的带项目名称前缀的数据卷即可,因为compose管理容器的单位是项目,这样能区分不同的项目

2.5 networks

配置容器使用哪个网络(桥)

version: "3.2"  

services:
  mytomcat: 
    image: tomcat:8.0-jre8  
    ports:
      - "8080:8080"
    networks: 
      - mynetwork  # 指定容器连接哪个网络。指定的自定义网络名称必须在下面定义

networks:
  mynetwork:  # 定义网络。定义后才能在上面使用,否则报错

启动容器后,compose会自动帮我们创建mynetwork网络

可以看出:

  • 如果我们在模板文件中没有指定容器用的网络,那么compose会自动创建一个名称为项目名_default的网络,其中项目名为docker-compose.yml模板文件所在的目录名
  • 如果我们在模板文件中指定了容器的网络,那么compose会自动创建一个名称为项目名_自定义网络名的网络,其中项目名为docker-compose.yml模板文件所在的目录名

如果我们不想让compose创建网络时名称前面带项目名的前缀,那么可以指定使用外部已存在的网络,但此时必须现用docker network create创建出指定的网络,否则会报错

version: "3.2"  

services:
  mytomcat: 
    image: tomcat:8.0-jre8  
    ports:
      - "8080:8080"
    networks: 
      - mynetwork  # 指定容器连接哪个网络。指定的自定义网络名称必须在下面定义

networks:
  mynetwork:  # 定义网络。定义后才能在上面使用,否则报错
    external: 
      true  # 使用外部已存在的网络mynetwork,该网络必须存在,不存在的话必须先手动创建,否则报错

一般情况下使用compose默认帮我们创建的带项目名称前缀的网络即可,因为compose管理容器的单位是项目,这样能区分不同的项目

2.6 container_name

指定容器的名称。不指定时默认由compose生成带项目名称前缀的容器名

version: "3.2"  

services:
  mytomcat: 
    container_name: tomcat01  # 指定容器的名称
    image: tomcat:8.0-jre8  
    ports:
      - "8080:8080"

2.7 environment

设置环境变量,可以使用数组或字典两种格式。如果只给定变量名称,不指定值的话会自动获取运行compose宿主机上对应的环境变量的值,可以用来防止泄露不必要的数据

version: "3.2"  

services:
  mysql5: 
    container_name: mysql01  # 指定容器的名称
    image: mysql:5.7
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ROOT_PASSWORD=root  # 等价写法MYSQL_ROOT_PASSWORD: root

如果环境变量的名称或值中用到true|false或者yes|no这样的布尔表达式,建议放到引号里,避免解析错误

2.8 env_file

从文件中获取环境变量,可以为单独的文件路径或列表

如果通过docker-compose -f FILE方式来指定compose.yml模板文件,则env_file中变量的路径会基于模板文件路径

如果有变量名称与environment指令冲突,则以后者为准

# 指定单个环境变量文件
env_file: .env

# 指定多个环境变量文件
env_file: 
  - ./common.env
  - /opt/secrets.env

环境变量文件中每一行必须符合格式,支持#开头的注释行

# mysql密码
MYSQL_ROOT_PASSWORD=root

一般我们会把一些敏感信息环境变量放到文件中,比如mysql密码。这样compose模板文件中不会暴露密码

2.9 command

用于run镜像之后覆盖容器启动时的默认命令,比如启动redis时docker run -p 6379:6379 -d --name redis5 -v redis.data:/data -v redis.conf:/etc/redis/redis.conf redis:5 redis-server /etc/redis/redis.conf,需要如下配置

version: "3.2"  

services:
  redis5: 
    container_name: redis5  # 指定容器的名称
    image: redis:5
    ports:
      - "6379:6379"
    volumes:
      - redis.data:/data
      - redis.conf:/etc/redis
    command: "redis-server /etc/redis/redis.conf"  # 指定容器启动时要运行的命令

2.10 depends_on

解决容器之间的依赖、启动先后问题。比如我们自己的web应用会连接mysql、redis,那么就要求mysql、redis先启动,web应用后启动

version: "3.2"  

services:
  web:
    image: mywebapp:latest
    ports:
      - "8080:8080"
    depends_on:  # 依赖于redis5和mysql5.7,会先启动redis5和mysql5.7
      - redis5   # 注意一定要写services下面配置的服务id,而不是容器名称
      - mysql5.7
    
  redis5: 
    container_name: redis01
    image: redis:5
    ports:
      - "6379:6379"
    volumes:
      - redis.data:/data
      - /dockermapping/redis/conf/redis.conf:/etc/redis/redis.conf
    command: "redis-server /etc/redis/redis.conf"  # 指定容器启动时要运行的命令
  
  mysql5.7: 
    container_name: mysql01
    image: mysql:5.7
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ROOT_PASSWORD=root

2.11 build

如果要将我们自己的应用放到compose模板文件中进行编排,首先要用dockerfile生成镜像,然后在compose模板中编排,这样做稍显麻烦。build指令可以一步到位,在compose模板中将指定的dockerfile打包成镜像后再运行

version: "3.2"  

services:
  web:
    build:  # 启动服务时先将build命令中指定的dockerfile打包成镜像,再运行该镜像
      context: myweb  # 指定上下文目录,即dockerfile所在目录
      dockerfile: Dockerfile  # 指定dockerfile的文件名
    ports:
      - "8080:8080"
    depends_on:  # 依赖于redis5和mysql5.7,会先启动redis5和mysql5.7
      - redis5   # 注意一定要写services下面配置的服务id,而不是容器名称
      - mysql5.7
    
  redis5: 
    container_name: redis01
    image: redis:5
    ports:
      - "6379:6379"
    volumes:
      - redis.data:/data
      - redis.conf:/etc/redis
    command: "redis-server /etc/redis/redis.conf"  # 指定容器启动时要运行的命令
  
  mysql5.7: 
    container_name: mysql01
    image: mysql:5.7
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ROOT_PASSWORD=root

2.12 限制容器可用内存

version: "3.2"
services:
  redis:
    image: redis:alpine
    container_name: testredis
    deploy:
      resources:
        limits:
          memory: 2G  # 限制容器可用最大内存为2G

3.docker-compose常用命令

对于docker-compose来说,大部分命令的对象既可以是项目本身,也可以指定为项目中的服务或者容器。如果没有特别的说明,命令的对象将是项目,这意味着项目中所有的服务都会收到命令影响

执行docker-compose [具体命令] --help或者docker-compose help [具体命令]可以查看某个具体命令的格式。docker-compose的基本格式如下:

docker-compose [-f=<arg>...] [options] [COMMAND] [ARGS...]

命令的选项如下:

  • -f,--file FILE:指定使用的compose模板配置文件,默认为docker-compose.yml,可以多次指定
  • -p,--project-name NAME:指定项目名称,默认将使用模板文件所在目录名称作为项目名称
  • --x-networking:使用docker的可拔插网络后端特性
  • --x-network-driver DRIVER:指定网络后端的驱动,默认为bridge
  • --verbose:输出更多调试信息
  • -v,--version:打印版本并退出

3.1 up

格式为docker-compose up [options] [SERVICE...]

  • 该命令十分强大,它将尝试自动完成包括构建镜像,(重新)创建服务,启动服务,并关联服务相关容器的一系列操作。可以说大部分的时候都可以直接通过该命令来启动一个项目
  • 连接的服务将会被自动启动,除非已经处于运行状态
  • 默认情况下,docker-compose up启动的容器都在前台,控制台将会同时打印所有容器的输出信息,方便进行调试。当通过Ctrl-C停止命令时,所有容器将会停止。如果想要在后台启动所有容器,可以使用docker-compose up -d推荐生产环境使用该选项
  • 默认情况下,如果服务容器已经存在,docker-compose up将会尝试停止容器,然后重新创建(保持使用volumes挂载的数据卷),以保证新启动的服务匹配docker-compose.yml文件的最新内容

我们编写如下模板文件来测试,模板文件放在mytomcatapp目录下

version: "3.2"  # 指定compose的版本

services:
  tomcat1: # 代表一个容器的服务名称,在文件中必须唯一
    image: tomcat:8.0-jre8  # 指定用哪个镜像来创建这个容器
    ports:
      - "8080:8080"  # 指定容器与宿主机的端口映射
    volumes:
      - webapp1:/usr/local/tomcat/webapps
  tomcat2:
    image: tomcat:8.0-jre8 
    ports:
      - "8081:8080"
    volumes:
      - webapp2:/usr/local/tomcat/webapps

volumes:
  webapp1:
  webapp2:

启动时指定后台运行与项目名称

docker-compose up -d

运行后可以发现,compose帮我们自动创建了项目的网络、数据卷、容器

此时我们尝试修改模板文件中容器的端口映射

然后再次运行compose up指令,会发现docker-compose能判断出tomcat1没有被修改,无需重新构建启动。tomcat2重新映射新的端口启动。并且原来的网络、数据卷都还在

如果不修改任何模板文件内容,在服务容器已经启动的情况下再次运行docker-compose up -d,将不会有任何效果

3.2 down

停止并删除up命令所启动的容器,并移除网络

我们在up命令执行后执行down命令,会发现up启动的容器将被停止并删除,同时容器网络也会被删除,但是数据卷会被保留

3.3 ps

列出项目中目前的所有容器,格式为docker-compose ps [options] [SERVICE...]

选项:

  • -q:只打印容器的id信息

3.4 restart

重启项目中的服务,格式为docker-compose restart [options] [SERVICE...]

选项:

  • -t,--timeout TIMEOUT:指定重启前停止容器的超时,默认为10秒

3.5 rm

删除所有停止状态的服务容器,格式为docker-compose rm [options] [SERVICE...]

在执行该命令前推荐先执行docker-compose stop命令来停止容器

选项:

  • -f,--force:强制直接删除,包括非停止状态的容器。尽量不要用该选项
  • -v:删除容器所挂载的数据卷

3.6 start

启动已经存在的服务容器。格式为docker-compose start [SERVICE...]

3.7 stop

停止已经处于运行状态的容器,但不删除它。通过docker-compose start可以再次启动这些容器

选项:

  • -t,--timeout TIMEOUT:停止容器时候的超时,默认为10秒

3.8 top

查看各个服务容器内运行的进程

3.9 pause/unpause

暂停/恢复服务容器,格式为docker-compose pause/unpause [SERVICE...]

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐