Docker Compose学习

Docker Compose是什么

Docker Compose是一个用于定义和管理多个Docker容器的工具,Docker Compose项目由Python编写,调用Docker服务提供的API来对容器进行管理。

docker-compose.yml是Docker Compose工具使用的配置文件,它是一个YML/YAML格式的文件,用于描述应用程序的组件和它们之间的关系。在这个文件中,你可以定义多个服务,每个服务对应一个容器,并指定容器的镜像、端口映射、环境变量等配置。

为什么要使用Docker Compose

  1. 简化多容器应用部署:Docker Compose 允许你使用一个文件来定义和管理多个容器,而不需要手动编写大量的 Docker 命令。这样可以大大简化多容器应用的部署过程,减少人工错误。
  2. 统一的环境描述:使用 Docker Compose,你可以将应用程序的各个组件的配置集中在一个文件中,包括容器镜像、端口映射、环境变量等。这样可以确保在不同环境(开发、测试、生产)之间具有一致的配置,避免了手动配置的差异性。
  3. 快速启动和停止应用:通过运行 docker-compose up 命令,Docker Compose 可以自动创建、启动和连接多个容器。这使得应用的启动过程变得非常简单和快速。而使用 docker-compose down 命令可以快速停止并清理所有相关的容器和资源。
  4. 容器间的依赖管理:Docker Compose 允许你在配置文件中指定容器之间的依赖关系。这意味着你可以确保在启动应用程序时,所有依赖的容器都会正确启动,并按照指定的顺序进行启动。
  5. 可扩展性和复用性:Docker Compose 允许你定义多个服务,并将它们组合成一个应用程序。这样,你可以轻松地扩展应用程序,添加新的服务或复制现有的服务。此外,你还可以将已定义的服务组合成一个模板,并在不同的项目中重复使用。

假设有这么一个场景,你开发了一个web服务,这个web服务涉及到了前端,后端,Nginx,数据库,缓存,消息队列,搜索引擎等,现在需要将这些服务部署到Docker上,如果一个一个部署的话,以现在的体量,可能还好,当服服务达到几十上百个的时候,你要对这些服务进行部署,启动,停止,容器间连接,效率就会非常慢;你可能会说,我可以把这些都部署到一个容器中啊!

你说的不错,的确都可以都部署到一个容器中;但是当服务需要做分布式的时候,显然是不能将所以服务都部署到一个服务中的,像数据库集群,缓存集群做起来就会非常麻烦;还有就是将所有服务都部署到一个容器中,这不变成直接再服务器上部署,失去了Docker的便利性了。

总的来说,使用 Docker Compose 可以简化多容器应用的部署和管理过程,提高开发效率,确保环境的一致性,并提供了容器间依赖管理和可扩展性的优势。它是一个强大的工具,特别适用于构建和管理复杂的应用程序架构。

以下就针对docker-compose的编写规范,指令详解,以及针对一个应用示例进行说明。

docker-compose.yml的文件指令详解

按照YML文件的格式,docker-compose.yml文件包含四个常见的一级key:version、services、networks、volumes,以及还有几个不常见的,configs、secrets

version: 必须指定的,而且总是位于文件的第一行。它定义了 compose 文件格式(主要是 API)的版本。注意,version 并非定义 Docker Compose 或 Docker 引擎的版本号。基本上就是定义你这一系列服务的版本。

services: 用于定义不同的容器服务,每个服务都是一个容器。比如数据库服务、后端服务、网关服务等,每个服务占用一个二级标签。

networks: 用于自定义docker虚拟网桥,将指定容器链接在这个网络下,这个容器间就可以通过网桥名称:端口访问对于的容器了。

volumes: 用于指引 Docker 来创建新的卷,卷的作用就是容器间共享数据,然后将卷映射到外部宿主机。

configs:定义要创建的配置及其配置,配置用于将文件或配置数据传递给服务容器。

secrets:定义要创建的密钥及其配置。密钥用于安全地传递敏感信息给服务容器。

version

# 版本1.2.3,只当前docker-compose的版本
version: '1.2.3'

services

  • services也是docker-compose最主要的部分,也是重点要关注的部分,services下每一个二级标签都是一个服务(容器)
services: 
# web服务
web:
# web服务的镜像
image: nginx:latest
# 容器名称
container_name: nginx-client
# 暴露的端口
ports:
- "80:80"
# 挂载的卷,映射的目录,容器内/usr/share/nginx/html映射到当前目录html下
volumes:
- ./html:/usr/share/nginx/html
# 网络,处于docker自定义的frontend网卡下
networks:
- frontend
# api服务
api:
# 这里没有使用image,则是使用当前目录的api目录下的Dockerfile来构建镜像
# 容器名称
container_name: back-api
build:
context: ./api
dockerfile: Dockerfile
# 暴露端口
ports:
- "8080:8080"
# 依赖于下面的的db服务,这样只有在db服务启动后,这个服务才会启动
# 注意:这个在之db后只是说db服务已经启动,不一定是可用的,如果db服务启动了,但是不可以,api服务还是会启动的
depends_on:
- db
# 网络,连接到多个网络,或者说连接到多个docker虚拟网桥
networks:
- frontend
- backend
# db服务
db:
# 启动镜像
image: mysql:latest
# 容器名称
container_name: m
# 环境变量
environment:
- MYSQL_ROOT_PASSWORD=secret
# 挂载的卷,这个dbdata不是一个路径,注意了,是一个卷
volumes:
- dbdata:/var/lib/mysql
# 连接到的网络
networks:
- backend

# 这个下面就是指定卷,dbdata这个卷没有指定路径,就是一个匿名卷,匿名卷的路径一般在宿主机该目录下:/var/lib/docker/volumes
volumes:
dbdata:
# 这下面就是定义自定义网桥
networks:
frontend:
backend:

networks

  • 自定义docker-compose网桥
networks:
# 自定义名为mynetwork的网桥
mynetwork:
# 网络模式为bridge
driver: bridge
# 定 IP 地址管理驱动程序为 default,default 是 Docker 默认的 IP 地址管理驱动程序,它负责为容器分配 IP 地址
ipam:
driver: default
# 指定 IP 地址配置的详细信息。
config:
# 子网掩码
- subnet: 172.20.0.0/16
# 网关地址
gateway: 172.20.0.1
  • dirver为定义网络的类型,以下是几种不同的网络类型

    • bridge:这是 Docker 默认的网络驱动程序。它使用 Docker 守护进程的网络桥接功能,允许容器通过宿主机的网络进行通信。bridge 驱动程序适用于大多数常见的应用场景,基本上自定义网桥都是使用bridge类型。

    • host:使用 host 驱动程序时,容器将与宿主机共享网络命名空间。这意味着容器将直接使用宿主机的网络接口,而不会创建自己的网络栈。使用 host 驱动程序可以实现与宿主机相同的网络性能,但容器之间的网络隔离性较差。相当于容器就是宿主机上的一个应用,使用宿主机的网络。

    • overlayoverlay 驱动程序允许在多个 Docker 主机之间创建跨主机的网络。它适用于构建分布式应用程序和容器集群,允许容器在不同的主机上进行通信。

    • macvlanmacvlan 驱动程序允许为容器分配与宿主机相同的 MAC 地址,使容器能够直接与物理网络进行通信。这对于需要与物理网络进行直接交互的应用程序非常有用。

    • ipvlanipvlan 驱动程序类似于 macvlan,但它允许为容器分配不同的 IP 地址。这使得容器可以直接与物理网络进行通信,并具有与宿主机不同的 IP 地址。这相当于是另一台与宿主机在同一网络下的机器。

volumes

  • 创建卷,也就是在宿主机上创建一个多容器共享的文件夹
volumes:
# 卷一,没有指定卷在宿主机的路径,默认在/var/lib/docker/volumes下
myvolume1:
# 卷二,使用local驱动(默认),
myvolume2:
driver: local
driver_opts:
# 不适用特定驱动类型
type: none
# 改卷在/app/volumes/目录下
device: /app/volumes/

configs

version: '3'
services:
service1:
image: image1
configs:
# 将这个配置设置到这个容器的/app/config/目录
- myconfig:/app/config/
# 创建一个配置
configs:
# 配置地址
myconfig:
# 配置文件名称
file: ./config.txt

secrets(具体还不知道有啥用,以后再研究,不过者指令也基本上用的非常少)

version: '3.1'
services:
service1:
image: image1
secrets:
- mysecret
# 创建一个密钥
secrets:
mysecret:
file: ./mysecret.txt

根据上文创建的Dockerfile,创建一个docker-compose.yml整合整个系统(实战)

  • 在linux上拉取,项目地址

  • 进入docker文件夹,里面有个docker-compose.yml文件,该docker-compose.yml整合了一个后端,两个前端,数据库,缓存。

# 版本
version: '1.0.0'

# 服务列表
services:
# 后端
after-end:
# 根据该目录下的Dockerfile构建
build:
context: ../after-end
dockerfile: Dockerfile
# 指定构建生成的镜像的名称,与build指令一起存在的话,这个image就是指定构建好镜像的名称以及标签
image: after-end:v1.0
# 指定容器名称为after-end
container_name: after-end
ports:
- 8080:8888
# 关联的网络
networks:
- frontend
- backend
# 依赖于db与cache服务
depends_on:
- db
- cache

# 前端用户端
front-client:
build: ../client
image: front-client:v1.0
container_name: front-client
ports:
- 81:80
volumes:
- ./nginx/client/nginx.conf:/etc/nginx/nginx.conf
networks:
- frontend
# 依赖于after-end服务
depends_on:
- after-end

# 前端管理端
front-manage:
build: ../manage
image: front-manage:v1.0
container_name: front-manage
ports:
- 82:80
volumes:
- ./nginx/manage/nginx.conf:/etc/nginx/nginx.conf
networks:
- frontend
# 依赖于after-end服务
depends_on:
- after-end

# 数据库
db:
# 依赖镜像创建容器,当镜像不存在时,便从远程下载
image: mysql:8.0.22
container_name: mysql8
ports:
- 3306:3306
volumes:
- ./mysql/log:/var/log/mysql
- ./mysql/data:/var/lib/mysql
- ./mysql/conf:/etc/mysql/conf.d
environment:
- MYSQL_ROOT_PASSWORD=123456
networks:
- backend

# redis缓存
cache:
image: redis:6.2.12
container_name: redis6
# 运行时指令,指定配置文件
command: redis-server /etc/redis/redis.conf
volumes:
- ./redis/data:/data
- ./redis/conf/redis.conf:/etc/redis/redis.conf
ports:
- 6379:6379
networks:
- backend

# 自定义docker网络
networks:
frontend:
backend:
  • 在docker目录下执行docker-compose up -d执行docker-compose.yml脚本,因为docker-compose正好在该目录下,所有不需要加上便可执行。

补充

关于docker-compose.yml中的指令,以上已经涉及到了大部分常用的,如果还有一些细节部分可以上Docker Compose官方文档上查看