负责实现对 Docker 容器集群的快速编排,允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project),从而实现一键启动/关闭容器
例如在使用 docker 部署微服务项目A时,项目A需要按顺序依次启动 Nginx > Nacos > RabbtiMQ > Redis > MySQL … 等中间件,根据以往的 docker run 方式启动是非常繁琐的,还有可能误操作导致容器顺序启动不对,此时使用 Docker-compose 就能很好解决这一痛点
Docker-compose 适用于几十个内的项目模块,如果项目模块数量过多,docker-compose.yml 将不好维护,且只能用于单机环境,因此实际开发中如果是集群中间件,容器编排会使用 k8s

核心概念:

文件:docker-compose.yml
服务:docker 内的容器应用实例
工程:由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。

使用步骤:

  1. 编写 Dockerfile 定义各个微服务应用并构建出对应的镜像文件
  2. 使用 docker-compose.yml 定义一个完整业务单元,安排好整体应用中的各个容器服务
  3. 执行 docker-compose up (V1版本)命令来启动并运行整个应用程序,完成一键部署上线

项目创建:

创建一个需要使用 Redis + MySQL 的 SpringBoot 项目来演示 Docker-compose 的使用案例
项目地址:Gitee


非 docker-compose 发布项目:

演示一个不使用 docker-compose 发布项目的步骤

编写 Dockerfile 生成项目镜像:

  1. # 基础镜像使用java
  2. FROM java:8
  3. # 作者
  4. MAINTAINER dmbjz
  5. # VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
  6. VOLUME /tmp
  7. # 将jar包添加到容器中并更名为dmbjz_docker.jar
  8. ADD dmbjz-0.0.1-SNAPSHOT.jar dmbjz_docker.jar
  9. # 运行jar包
  10. RUN bash -c 'touch /dmbjz_docker.jar'
  11. ENTRYPOINT ["java","-jar","/dmbjz_docker.jar"]
  12. #暴露8181端口作为微服务
  13. EXPOSE 8181
  1. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/21405095/1660379161302-fee436ca-a372-4775-99fa-1b23c23c2e6c.png#clientId=ubb681977-4f38-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=501&id=u7a3c7263&margin=%5Bobject%20Object%5D&name=image.png&originHeight=903&originWidth=917&originalType=binary&ratio=1&rotation=0&showTitle=true&size=78600&status=done&style=stroke&taskId=ue220920c-6a07-44d7-9c1a-098ccf13d76&title=%E9%A1%B9%E7%9B%AE%E9%95%9C%E5%83%8F%E7%94%9F%E6%88%90%E6%88%90%E5%8A%9F&width=508.3333740234375 "项目镜像生成成功")

创建 MySQL 容器:

  1. docker run -p 3306:3306 --name mysql57 --privileged=true -v /dmbjz/mysql/conf:/etc/mysql/conf.d -v /dmbjz/mysql/logs:/logs -v /dmbjz/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7

image.png

创建数据库:

使用 Navicat 等工具远程连接上 MySQL 容器,创建 docker 数据库 和 t_user

  1. CREATE TABLE `t_user` (
  2. `id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  3. `username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '用户名',
  4. `password` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '密码',
  5. `sex` int NOT NULL DEFAULT 0 COMMENT '性别 0=女 1=男 ',
  6. `deleted` int UNSIGNED NOT NULL DEFAULT 0 COMMENT '删除标志,默认0不删除,1删除',
  7. `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  8. `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  9. PRIMARY KEY (`id`) USING BTREE
  10. ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
  1. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/21405095/1660379668184-03a8de21-bd89-494b-87cd-c813b83226d8.png#clientId=u3349d78a-0a79-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=223&id=u2501eebc&margin=%5Bobject%20Object%5D&name=image.png&originHeight=236&originWidth=202&originalType=binary&ratio=1&rotation=0&showTitle=true&size=10362&status=done&style=stroke&taskId=u4bf71e43-4248-4d9f-b85e-fb2f70e26b1&title=%E5%88%9B%E5%BB%BA%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%8E%E5%AF%B9%E5%BA%94%E8%A1%A8&width=190.6666717529297 "创建数据库与对应表")

创建 Redis 容器:

  1. docker run -p 6379:6379 --name redis608 --privileged=true -v /app/redis/redis.conf:/etc/redis/redis.conf -v /app/redis/data:/data -d redis:6.0.8 redis-server /etc/redis/redis.conf

启动项目:

  1. docker run -d -p 8181:8181 dmbjz:1.0

image.png

测试API:

image.png


Docker-Compose 操作:

执行命令时需要在 docker-compose.yml 文件所在路径下,否则可能提示 docker-compose.yml 找不到

下载安装:

使用 GitHub 下载 1.29.2 版本,然后改名 docker-compose 并放到 /usr/local/bin/ 路径下

  1. curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

授予读写权限

  1. chmod +x /usr/local/bin/docker-compose

查看安装情况

  1. docker-compose --version

image.png

卸载:

直接删除 docker-compose 文件即可

  1. rm /usr/local/bin/docker-compose

常用命令:

docker-compose.yml 文件所在路径进行操作,如果文件名不为 docker-compose.yml,需要使用 -f 参数进行指定
docker-compose.yml 中使用了 build 指定 Dockerfile 文件时,如果后期 Dockerfile 文件有修改,需要使用 docker-compose build 或者 docker-compose up -d —build 进行更新镜像(原因:在首次 up 后 docker-compose 不会再关注 Dockerfile 文件是否被修改)
docker-compose.yml 中删除了不需要的服务,可以通过 docker-compose up -d —remove-orphans 在下次启动容器编排时移除被删除服务对应的容器

  1. docker-compose -h # 查看帮助
  2. docker-compose up # 启动所有docker-compose服务
  3. docker-compose up -d # 启动所有docker-compose服务并后台运行
  4. docker-compose down # 停止并删除容器、网络、卷、镜像。
  5. docker-compose exec yml里面的服务id # 进入容器实例内部 docker-compose exec docker-compose.yml文件中写的服务id /bin/bash
  6. docker-compose ps # 展示当前docker-compose编排过的运行的所有容器
  7. docker-compose top # 展示当前docker-compose编排过的容器进程
  8. docker-compose rm # 删除由docker-compose创建且已经停止的容器
  9. docker-compose build # 重新构建镜像(例如修改docker-compose.yml文件中dockerFile的参数)
  10. docker-compose logs yml里面的服务id # 查看容器输出日志
  11. docker-compose config # 检查配置
  12. docker-compose config -q # 检查配置,有问题才有输出
  13. docker-compose restart # 重启 docker-compose 服务
  14. docker-compose start # 启动 docker-compose 服务
  15. docker-compose stop # 停止 docker-compose 服务

使用 Docker-compose 发布:

对之前演示的案例使用 Docker-compose 进行发布

docker-compose.yml 语法模板:

docker-compose 与 docker 引擎之间的版本兼容关系参考官方文档,这里以 V3 版为例:

  1. version: "3.8"
  2. services: # 容器
  3. servicename: # 服务名字,不同的服务之间可以通过该名称进行ping通
  4. image: # 镜像的名字与版本
  5. build: #相当于 docker build。如果有build,image相当于指定生成后的镜像的 镜像名:版本号
  6. context: #dockerfile 文件路径
  7. dockerfile: #dockerfile 文件
  8. command: # 可选,如果设置,则会覆盖默认镜像里的 CMD命令
  9. environment: # 可选,相当于 docker run里的 --env,可以从文件中读取值
  10. volumes: # 可选,相当于docker run里的 -v
  11. networks: # 可选,相当于 docker run里的 --network
  12. ports: # 可选,相当于 docker run里的 -p
  13. servicename2:
  14. servicename3:
  15. volumes: # 可选,相当于 docker volume create
  16. networks: # 可选,相当于 docker network create,如果没有该参数 docker-compose 会自动创建一个叫 compose_defaulf 的自定义网络
  17. name1: #自定义网络1
  18. name2: #自定义网络1

编写 docker-compose.yml:

使用 docker-compose.yml 创建 docker 网络会自动在名称之前加上当前 docker-compose.yml 所在文件夹的前缀,虽然当前案例中创建的网络名为: dmbjz_net,然而实际网络名称为:当前docker-compose.yml所在文件夹名_dmbjz_net
如果依赖使用的镜像没有指定容器名(containername),其创建出的容器名称的命名规则与网络名类似,为:**当前docker-compose.yml所在文件夹名镜像名_数字(从1开始逐渐递增)**

容器名问题:

在实际项目部署时,如果不指定 depends_on 中镜像生成后的容器名( container_name ),项目容器会优先使用通过 docker-compose.yml 中创建的镜像容器,因此当多个服务使用同一个文件夹进行容器编排,可能会导致调用错误,所以实际编写 docker-compose.yml 需要指定容器名

  1. version: "3" #docker-compose文件编写版本
  2. services: #使用的服务,固定
  3. microService: #具体的service名称,类似 spring.application.name
  4. image: dmbjz:2.0 #需要使用的项目镜像:版本号
  5. container_name: springboot_docker #生成的容器名称
  6. ports:
  7. - "8181:8181" #对外暴露端口(与项目server.port一致)
  8. volumes:
  9. - /app/microService:/data #数据卷挂载,可用于查看日志
  10. networks:
  11. - dmbjz_net #指定网络,必须为自定义网络
  12. depends_on: #定义容器启动顺序,按照数组顺序依次启动,有该参数的服务最后启动
  13. - redis
  14. - mysql
  15. redis:
  16. image: redis:6.0.8
  17. container_name: dmbjz_redis #生成的容器名称
  18. ports:
  19. - "6379:6379"
  20. volumes:
  21. - /app/redis/redis.conf:/etc/redis/redis.conf
  22. - /app/redis/data:/data
  23. networks:
  24. - dmbjz_net
  25. command: redis-server /etc/redis/redis.conf
  26. mysql:
  27. image: mysql:5.7
  28. container_name: dmbjz_mysql #生成的容器名称
  29. environment:
  30. MYSQL_ROOT_PASSWORD: 'root'
  31. MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
  32. MYSQL_DATABASE: 'docker'
  33. MYSQL_USER: 'dmbjz'
  34. MYSQL_PASSWORD: 'dmbjz'
  35. ports:
  36. - "3306:3306"
  37. volumes:
  38. - /app/mysql/db:/var/lib/mysql
  39. - /app/mysql/conf/my.cnf:/etc/my.cnf
  40. - /app/mysql/init:/docker-entrypoint-initdb.d
  41. networks:
  42. - dmbjz_net
  43. command: --default-authentication-plugin=mysql_native_password #解决外部无法访问
  44. networks:
  45. dmbjz_net:

修改项目:

将项目中的 MySQL 与 Redis 地址换成容器名称后重新生成 jar 文件并生成镜像

  1. spring.datasource.url=jdbc:mysql://dmbjz_mysql:3306/docker?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=GMT%2B8
  2. spring.redis.host=dmbjz_redis

image.png

校验 docker-compose.yml 文件,查看其格式是否编写错误

  1. docker-compose config -q

image.png

启动项目:

使用 docker-compose 的启动命令,根据 docker-compose.yml 进行一键启动

  1. docker-compose up -d

image.png

创建数据表:

使用 Navicat 等工具远程连接上 MySQL 容器,创建 t_user
image.png

API测试:

使用 Controller 内的 API 方法
image.png

一键关停:

一键关闭 docker-compose.yml 内所有镜像容器

  1. docker-compose stop

image.png


水平拓展:

动态增加或减少某个服务的数量并自动创建负载均衡

  1. docker-compose up -d --scale 需要拓展的servicename名称=数量

从文件读取环境变量:

如果希望 docker-compose.yml 文件中的变量可以其他文件中读取,可以通过同级的 .env 文件进行指定
image.png

如果文件不为 .env,可以通过 —env-file 文件名 进行指定,具体命令如下:

  1. docker-compose --env-file 文件名 config

案例演示:

docker-compose.yml 文件:
默认会自动寻找 .env 文件来查询变量值

  1. version: "3.8"
  2. services:
  3. redis-server:
  4. image: redis:latest
  5. command: redis-server --requirepass ${REDIS_PASSWORD}

.env文件:

  1. REDIS_PASSWORD=ABC123
  1. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/21405095/1661600581920-46734ce6-0133-475f-a402-bf80b068652f.png#clientId=u9be4a23e-93ca-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=281&id=u7794d2e2&margin=%5Bobject%20Object%5D&name=image.png&originHeight=461&originWidth=788&originalType=binary&ratio=1&rotation=0&showTitle=true&size=61447&status=done&style=stroke&taskId=u1cf7d3f5-db93-4869-b2ec-d322d5057c3&title=%E4%BB%8E%20.env%20%E6%96%87%E4%BB%B6%E8%8E%B7%E5%8F%96%E5%88%B0%E5%8F%98%E9%87%8F&width=480 "从 .env 文件获取到变量")<br /> ![image.png](https://cdn.nlark.com/yuque/0/2022/png/21405095/1661600521424-6e5b0330-f46d-456d-b344-0ad55ce3b214.png#clientId=u9be4a23e-93ca-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=259&id=u8fa7fafe&margin=%5Bobject%20Object%5D&name=image.png&originHeight=434&originWidth=804&originalType=binary&ratio=1&rotation=0&showTitle=true&size=62270&status=done&style=stroke&taskId=uf1032d33-2cdc-42e5-95c6-fab395c2167&title=%E6%96%87%E4%BB%B6%E4%B8%8D%E4%B8%BA%20.env%20%E7%9A%84%E6%8C%87%E5%AE%9A%E6%96%B9%E5%BC%8F&width=480 "文件不为 .env 的指定方式")