Docker Compose容器编排

一、Docker Compose概念

Docker Compose (可简称Compose)是一个定义与运行复杂应用程序的 Docker 工具,是 Docker 官方编排(Orchestration)项目之一,负责快速在集群中部署分布式应用。

其代码目前在 https://github.com/docker/compose 上开源。

1、为什么要使用 Docker Compose部署容器

仅使用docker命令部署和管理多容器:应用程序时往往需要编写若干脚本文件,使用的命令可能会变得冗长,包括大量的选项和参数,配置过程比较复杂,而且容易发生差错。

Docker Compose实质:不是通过脚本和各种docker命令将多个容器组织起来,而是通过一个声明式的配置文件描述整个应用程序,从而让用户使用一条命令即可完成整个应用程序的部署。

Docker Compose功能:将逻辑关联的多个容器编排为一个整体进行统一管理,提高了应用程序部署效率。

2、Docker Compose项目概念

Docker Compose 以项目为单位管理应用程序的部署。按从上到下依次分为以下三个层次。

项目(project):一组关联的容器组成一个完整的业务单位,实现一个应用程序,涵盖应用程序所需的所有资源。在 docker-compose.yml 文件中定义。

服务(service):具体定义容器运行的镜像.可以包括若干运行相同镜像的容器实例。

容器(container):指的是服务的副本。每个服务可以以多个容器实例的形式运行。

3、使用Docker Compose的基本步骤

  1. 使用 Dockerfile 定义应用程序的环境,以便可以在任何地方分发。Compose编排主要是用于多容器的复杂应用程序,但是镜像还是要基于Dockerfile构建。
  2. 使用Compose文件 docker-compose.yml 定义组成应用程序的服务。文件声明的配置,可以定义包含多个相关互联的容器的程序(服务)。
  3. 执行 docker-compose up 命令启动整个应用程序。

二、Docker Compose基本操作

1、安装 Compose

Compose 有两种常用的安装方式:

  1. 使用pip安装Docker Compose(Compose是用python写的)
# 注意:Docker Compose需要Python 3.6或更高版本。
$ pip install docker-compose
# 安装后判断是否安装成功
$ docker-compose -h
  1. 从GITHUB上的Docker Compose 仓库下载docker-compose二进制文件进行安装。
# 1.curl命令从GitHub上的Docker Compose仓库下载二进制文件
# 语法:curl -L "<GitHub上的Docker Compose仓库网址>" -o /usr/local/bin/docker-compose
# 下载实例:
[root@hecs-hqs-01 ~]# curl -L "https://github.com/docker/compose/releases/download/v2.6.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100 24.7M  100 24.7M    0     0  39116      0  0:11:03  0:11:03 --:--:-- 55673

# 2.为该二进制文件添加可执行权限
[root@hecs-hqs-01 ~]# chmod +x /usr/local/bin/docker-compose 
[root@hecs-hqs-01 ~]# ll /usr/local/bin/docker-compose 
-rwxr-xr-x 1 root root 25968640 Jun  7 14:39 /usr/local/bin/docker-compose

# 3.进行命令测试
[root@hecs-hqs-01 ~]# docker-compose --version
Docker Compose version v2.6.0

2、卸载Compose

两种不同的安装方式,使用不同的卸载方法如下:

# 如通过 pip 安装,则可以以如下方式删除
$ pip uninstall docker-compose

# 二进制包安装,则删除二级制文件即可
[root@hecs-hqs-01 ~]# rm /usr/local/bin/docker-compose

3、使用Docker Compose 部署 WordPress

WordPress是个人博客系统,逐步演化成一款内容管理系统软件。使用PHP和mysql开发。
以部署 WordPress 为例示范使用 Compose进行容器编排的完整过程。

每个服务容器就是服务的一个副本,其名称格式:“项目名_服务名_序号”,序号编排从1开始,不同的序号表示依次分配的副本。

# 1.定义项目,切换到该项目目录
# Compose项目目录:可根据需要命名,是应用程序镜像的上下文环境,仅包含用于构建镜像的资源。
[root@hecs-hqs-01 ~]# mkdir my_wordpress && cd my_wordpress
[root@hecs-hqs-01 my_wordpress]# 

# 2.创建并编辑docker-compose.yml 的compose文件来定义项目
# db定义的是mysql服务器,wordpress定义了wordpress博客项目,db_data卷用于保存提交到数据库的数据
[root@hecs-hqs-01 my_wordpress]# vi docker-compose.yml 
version: '3.3'
services:
  db:
    image: mysql:5.7
    volumes:
      - db_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: somewordpress
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
  wordpress:
    depends_on:
      - db
    image: wordpress:latest
    ports:
      - "8000:80"
    restart: always
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
volumes:
  db_data: {}

# 3.项目目录中执行docker-compose命令构建项目
[root@hecs-hqs-01 my_wordpress]# docker-compose up -d
[+] Running 34/34
 ⠿ wordpress Pulled                                                                                  48.6s
   ⠿ 42c077c10790 Pull complete                                                                      24.3s
    ...略                                                                      45.0s
   ⠿ 39f9aa71aa04 Pull complete                                                                      45.1s
 ⠿ db Pulled                                                                                         94.3s
   ⠿ c1ad9731b2c7 Pull complete                                                                      46.0s
    ...略                                                                      90.7s
   ⠿ 1b606c4f93df Pull complete                                                                      90.7s
[+] Running 4/4
 ⠿ Network my_wordpress_default        Created                                                        0.1s
 ⠿ Volume "my_wordpress_db_data"       Created                                                        0.0s
 ⠿ Container my_wordpress-db-1         Started                                                        1.2s
 ⠿ Container my_wordpress-wordpress-1  Started

# 4.执行命令查看运行中的容器
[root@hecs-hqs-01 my_wordpress]# docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                  NAMES
49b78626c20c        wordpress:latest    "docker-entrypoint.s…"   About a minute ago   Up About a minute   0.0.0.0:8000->80/tcp   my_wordpress-wordpress-1
fecf57f4dfd8        mysql:5.7           "docker-entrypoint.s…"   About a minute ago   Up About a minute   3306/tcp, 33060/tcp    my_wordpress-db-1


# 5.在浏览器访问Wordpress
在浏览器访问:http://192.168.200.103:8000/
注册账号,完成登录后,可以进入wordpress首页。

# 6.关闭和清理
# 执行如下命令删除容器、默认网络、卷
[root@localhost my_wordpress]# docker-compose down --volumes
[+] Running 4/4
 ⠿ Container my_wordpress-wordpress-1  Removed                                1.4s
 ⠿ Container my_wordpress-db-1         Remov...                               1.7s
 ⠿ Volume my_wordpress_db_data         Remov...                               0.0s
 ⠿ Network my_wordpress_default        Remo...                                0.0s

三、YAML介绍

YAML 是一种可读性很强的数据序列化格式,简洁、易于阅读,特别适合用来表示数据。

YAML 语法特点:

  • 可读性强: YAML 使用缩进和空格来结构化数据,方便轻松阅读和编写,避免了复杂符合或标记。
  • 结构: 通过层级结构组织数据,通过缩进来定义结构。
    • 缩进时不允许使用 Tab 键,只允许使用空格。
    • 缩进的空格数不重要,但同级元素必须左侧对齐。
  • 注释:YAML 允许使用注释在数据中提供额外的信息和解释。注释以 # 字符开头,直到行尾结束。
  • 每个冒号与后面所跟的参数之间都需要有一个空格。
  • 大小写敏感。

1、基本结构

YAML 用缩进来表示层级关系,通常使用 两个 空格进行缩进。

# 键值对
key: value

# 序列
list:
  - item1
  - item2

# 字典(映射)
dict:
  key1: value1
  key2:
    subkey: subvalue

2、YAML数据类型

(1)标量

标量:相当于常量,是YAML最小的单位,支持4种数据类型:字符串、数字、布尔值、null、日期、时间等。

字符串:
  - 单引号: 'abc'
  - 双引号: "abc"
  - 纯文本: abc     # 字符串可以不用引号标注
数字:
  - 整数: 123
  - 浮点数: 123.456
  - 十进制: 58
布尔值:
  - is_active: true
  - is_empty: false
null值:
  - empty: null
日期和时间:
  - date: 2023-01-01
  - time: 12:00:00
  - datetime: 2023-01-01T12:00:00
  - timestamp: 1672531200

1)字符串
YAML语法中,字符串可以不用引号标注。

无引号:自动判断字符串类型,如果字符串包含空格,需要使用引号。
单引号:保留字符串的原样,包括转义字符。
双引号:允许使用转义字符,可以解析特殊字符,如\n 换行。

class_name: 2022yun3
single_quoted: 'single quoted, can include "quotes" and \n escape.'
double_quoted: "double quoted, can handle \"quotes\" and special char like \n."

多行字符串格式:可以使用三个引号(""" ''' ```)包围多方文本,保持原有格式和换行。

muti_line: """
  这个是一个多行的字符串文本,
  可以包含  "引号",换行,
  还可以包含其他特殊字符。
"""

折叠块字符串:同样使用三引号,在三引号后紧跟一个减号和一个空格,则所有空白都会压缩为一个空格。

fold_bloack: """- 
  这是一个折叠块字符串,
  制表符和空格会被压缩
  为一个空格。
"""

2)数字和布尔值
YAML支持整数、浮点数、指数和布尔值。

  • 整数:可以是正数和负数,有符号 - 表示是负数。
  • 浮点数:小数点分隔整数和小数部分,可以有正负。
  • 指数:使用字母e 或 E 跟一个可选的正负号和指数,1e10表示1乘以10的10次方。
  • 布尔值:只有两个有效值,truefalse。大小写敏感,必须小写。(YAML1.2后如此规定)
# 整数
positive_int: 42
negative_int: -52

# 浮点数
float_num: 3.14
negative_float: -5.87

# 指数
expon_num: 6.022e23
expon_num2: 1e10

# 布尔值
is_active: true
is_empty: false

(2)列表(数组)

序列:就是列表,相当于数组,使用一个短横线加上一个空格表示一个序列项。
在YAML中,使用列表存储一系列有序的值。
列表中每个成员,可以是任何有效的YAML数据类型,如:其他列表或映射。
列表使用短横线-开始,每个项目缩进表示属于同一个列表。

fruits:
  - Apple
  - Banana
  - Mango

学生名册:
  - name: 张三
    age: 18
    sex: male
    car: lixiang
  - name: Alice
    age: 20
    sex: female
    car: benz

nums:
  - 1
  - 2.5
  - 3.14E2

mixed_list:
  - name: Alice
    age: 18
    sex: female
  - name: Bob
    age: 20
    sex: male

YAML中可以表示空列表,可以使用空的方括号或破折号加换行

empty_list: []
empty_li: -

(3)映射(字典)

映射:相当于json中的对象,也使用键值对表示,只是冒号后一定要加一个空格,同一缩进层次的所有键值对属于一个映射。
映射由键值对组成,键后面跟一个冒号 :,后面是值,多个键值对通过缩进对齐来区分。

  • 键:通常是字符串,且在同一个映射中唯一
  • 值:可以是任意YAML数据类型,包括列表、映射、字符串等。
mysql:
  host: 192.168.80.101
  port: 3306
  image: mysql:5.7
  name: mysql

james:
  address_detail:
    city: 北京
    street: 朝阳
    house_number: 100
    country: 中华人民共和国
  name: lebron  james
  age: 36
  height: 2.07
  cars:
    - benz S450
    - byd HAN
    - lixiang l8

# 空映射
empty_map: {}

映射可以通过 YAML 的 锚点(&)别名(*) 功能来复用,可以有效避免重复和管理复杂数据。
锚点:允许给一个数据结构分配一个名称,这个名称可以在其他地方被引用。
别名:对已经定义锚点的引用,可使用 * 符号后接之前定义的锚点标识符。

address_detail: &default_address
  street: 123 Example St
  city: Exampleville
  country: Exampleland

alice:
  name: Alice
  address: *default_address

bob:
  name: Bob
  address: *default_address

(5)注释

在 YAML 中,以井号 # 开始,到行尾的所有内容都被视为注释。

1、单行注释:可以直接在任何非字符串值之后或者独立成行

# 这是一个整行的单行注释

database: example8    # 数据库名称
username: root        # 用户名
password: hunter2     # 密码

2、多行注释:YAML 本身不支持多行注释,可以在每行开头使用井号 # 来实现多行注释

# 这是一个
# 多行注释
# 的示例

三、编写Compose文件

模板文件是使用 Compose 的核心,大部分指令和 docker run 相关参数含义类似。

默认的模板文件名称为 docker-compose.yml,格式为YAML格式。

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

1、Compose文件结构

默认的模板文件名称为 docker-compose.yml,格式为YAML格式。

版本2相比版本1,添加了版本信息,所有的服务放在 services 根下。案例如下:

version: "2"
services:
  webapp:
    image: examples/web
	ports:
    - "80:80"
	volumes:
	  - "/data"

注意:

  • 每个服务都必须通过 image 指令指定镜像,或用 build 指令指定Dockerfile 所在文件夹路径自动构建生成镜像。
  • version 节必须指定,且总是位于文件第一行,没有任何下级节点。
  • 版本2和版本3的 Compose 文件结构基本相同。
  • services 节中定义服务,每个服务实际上就是一个容器,需要基于镜像运行。

2、image

在 Compose 文件中,必须通过 imagebuild 键提供镜像。
image 键用于指定启动容器的镜像,可以是镜像名称或镜像ID。

services:
  foo:
    image: busybox
    environment:
      - COMPOSE_PROJECT_NAME
    command: echo "I'm running ${COMPOSE_PROJECT_NAME}"

若镜像本地不存在,Docker Compose 会尝试从镜像注册中心拉取镜像。

3、build

https://docs.docker.com/compose/compose-file/build/
build 键用于定义构建镜像时的配置,可以定义包括构建上下文环境的字符串也可以定义一个对象。

build 键可以使用的选项:

  • context:定义构建上下文路径,可以是包括 Dockerfile 的目录,也可以是访问GIT仓库的URL。
  • dockerfile:指定 Dockerfile。
  • args:指定构建参数,仅在构建阶段访问的环境变量,允许是空值。

(1)上下文环境的字符串(相对路径)

准备文件和目录:

[root@yun nginx]# tree
.
├── dir
│   └── Dockerfile
└── docker-compose.yml

编写docker-compose.yml文件

version: '3.7'
services:
  webapp:
    build: ./dir
    stdin_open: true    # 开启标准输入保持打开
    tty: true           # 分配伪终端

编写./dir/Dockerfile文件

FROM centos:7.9.2009
RUN rm -rf /etc/yum.repos.d/*.repo 
ADD http://mirrors.aliyun.com/repo/Centos-7.repo /etc/yum.repos.d/
CMD ["/bin/bash"]

启动服务,验证服务

[root@yun nginx]# docker-compose up -d
[+] Running 2/2
 ✔ Network nginx_default     Created                                                  0.0s 
 ✔ Container nginx-webapp-1  Started                                                  0.2s
[root@yun nginx]# docker-compose ps
NAME             IMAGE          COMMAND       SERVICE   CREATED          STATUS          PORTS
nginx-webapp-1   nginx-webapp   "/bin/bash"   webapp    19 seconds ago   Up 18 seconds   
[root@yun nginx]# docker exec -ti nginx-webapp-1 ls -lrt /etc/yum.repos.d/
total 4
-rw------- 1 root root 2523 Aug  4  2022 Centos-7.repo

(2)上下文环境(git 仓库URL)

注意要准备一个案例:github?gitee?本地git?

services:
  webapp:
    build: https://github.com/mycompany/example.git#branch_or_tag:subdirectory

(3)上下文环境指定路径的对象

build:
  context: .
  dockerfile: webapp.Dockerfile

真实案例(详情看后面的django实验):

version: '3.7'
services:
  db:
    image: postgres
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    volumes:
      - db_data:/var/lib/postgresql
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db
volumes:
    db_data: {}

(4)同时指定 imagebuild

将构建镜像并将镜像命名为image键定义的名称。

services:
  frontend:
    image: awesome/webapp
    build: ./webapp

  backend:
    image: awesome/database
    build:
      context: backend
      dockerfile: ../backend.Dockerfile

3、depends_on

该键定义服务之间的依赖,解决容器依赖、启动先后的问题。

version: "3.7"
services:
  web:
    build:
	depends_on:
	  - db
	  - redis
  redis:
    image: redis
  db:
    image: postgre

上例中服务依赖效果:

  • 按依赖顺序启动服务:db和redis先于web启动。
  • 若执行 docker-compose up web(服务名) 会自动创建并启动db和redis。
  • 停止服务时,按依赖顺序停止服务,web先于db和redis停止。

4、networks

默认情况,Docker Compose 会为应用程序自动创建名为 [项目名]_default 的默认网络,服务的每个容器都加入默认网络。

  • 该网络上容器间可以互访
  • 可以通过主机名(与容器名称相同)互访

每个服务,也可以使用 networks 键指定要连接的网络,需要使用 networks 节中定义的网络名。

services:
  frontend:
    image: awesome/webapp
    networks:
      - front-tier
      - back-tier

networks:
  front-tier:
  back-tier:

(1)自定义网络案例

创建自定义网络,将服务连接到自定义网络,案例如下:

version: '3.7'
services:
  web:
    image: nginx
    networks:
      - mynetwork
    depends_on:
      - db
      - redis
  redis:
    image: redis
    networks:
      - mynetwork
  db:
    image: mysql:5.7
    ports: 
      - 3306:3306
    environment:
      - MYSQL_ROOT_PASSWORD=root
networks:
  mynetwork:
    driver: bridge

运行上面的案例如下所示:

[root@yun test_network]# docker-compose up -d

[root@yun test_network]# docker-compose ps 
NAME                   IMAGE       COMMAND                  SERVICE   CREATED          STATUS          PORTS
test_network-db-1      mysql:5.7   "docker-entrypoint.s…"   db        17 seconds ago   Up 16 seconds   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp
test_network-redis-1   redis       "docker-entrypoint.s…"   redis     17 seconds ago   Up 16 seconds   6379/tcp
test_network-web-1     nginx       "/docker-entrypoint.…"   web       17 seconds ago   Up 16 seconds   80/tcp
# 查看新创建的网络
[root@yun test_network]# docker network ls
NETWORK ID     NAME                     DRIVER    SCOPE
dd9e48b49023   test_network_default     bridge    local
be8e866e3292   test_network_mynetwork   bridge    local

# 查看网络中的容器
# db连接的是default网络
[root@yun test_network]# docker inspect test_network_default --format="{{json .Containers}}"
{"e207084c39f51adec296e58204ef6d2b638c753e1b9ef09d38665f5ae625043f":{"Name":"test_network-db-1","EndpointID":"a2fb2c33edf7ef4ed306d72d09e6b2b1f185010ad303c255e78529c6f14f66f1","MacAddress":"02:42:ac:15:00:02","IPv4Address":"172.21.0.2/16","IPv6Address":""}}

# redis和web连接的是mynetwork网络
[root@yun test_network]# docker inspect test_network_mynetwork --format="{{json .Containers}}"
{"08c1d752bde081313ebb6ea49623809ef9d2a2ca3db8928b9c9f8c802b3496ad":{"Name":"test_network-web-1","EndpointID":"0f999944fc0388b71b93780c7440fa28d944d7ed281413a2614867aac9443712","MacAddress":"02:42:ac:14:00:03","IPv4Address":"172.20.0.3/16","IPv6Address":""},
"54a0c503b42e9ba0b613a472f0b20aefb37cc62d74948e09f522d8ab7a31b79a":{"Name":"test_network-redis-1","EndpointID":"17e660328101dfc33446494c4c6bbdf24af06c00c410788b25198e53079f392d","MacAddress":"02:42:ac:14:00:02","IPv4Address":"172.20.0.2/16","IPv6Address":""}}

(2)aliases选项案例

aliases 选项比较特别,用来设置服务在该网络上的别名。

  • 同网络的其他容器可通过服务名称或别名连接该服务的容器
  • 同一服务可在不同网络上有不同别名
version: "3.7"
services:
  worker1:
    image: "centos"
    stdin_open: true    # 开启标准输入保持打开
    tty: true           # 分配伪终端
    networks:
      - new
  worker2:
    image: "centos"
    stdin_open: true    # 开启标准输入保持打开
    tty: true           # 分配伪终端
    networks:
      - legacy
  db:
    image: mysql:5.7
    environment:
      - MYSQL_ROOT_PASSWORD=root
    ports:
      - 3306:3306
    networks:
      new:
        aliases:
          - database
      legacy:
        aliases:
          - mysql
networks:
  new:
  legacy:

上例中:

  • db服务在new网络中的别名是database,在legacy网络中的别名是mysql。
  • web服务可通过db和database访问服务db,worker服务可通过db和mysql访问服务db.

上例运行效果如下:

[root@yun test_aliases]# docker-compose up -d

[root@yun test_aliases]# docker-compose ps
NAME                    IMAGE       COMMAND                  SERVICE   CREATED         STATUS         PORTS
test_aliases-db-1        mysql:5.7   "docker-entrypoint.s…"   db        4 seconds ago   Up 3 seconds   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp
test_aliases-worker1-1   centos      "/bin/bash"              worker1   4 seconds ago   Up 3 seconds   
test_aliases-worker2-1   centos      "/bin/bash"              worker2   4 seconds ago   Up 3 seconds
# 互ping 测试别名
[root@yun test_aliases]# docker exec -i test_aliases-worker1-1 ping database
PING database (172.27.0.2) 56(84) bytes of data.
64 bytes from test_aliases-db-1.test_aliases_new (172.27.0.2): icmp_seq=1 ttl=64 time=0.050 ms
64 bytes from test_aliases-db-1.test_aliases_new (172.27.0.2): icmp_seq=2 ttl=64 time=0.040 ms
[root@yun test_aliases]# docker exec -i test_aliases-worker1-1 ping mysql
ping: mysql: Name or service not known

[root@yun test_aliases]# docker exec -i test_aliases-worker2-1 ping database
ping: database: Name or service not known
[root@yun test_aliases]# docker exec -i test_aliases-worker2-1 ping mysql
PING mysql (172.26.0.3) 56(84) bytes of data.
64 bytes from test_aliases-db-1.test_aliases_legacy (172.26.0.3): icmp_seq=1 ttl=64 time=0.044 ms
64 bytes from test_aliases-db-1.test_aliases_legacy (172.26.0.3): icmp_seq=2 ttl=64 time=0.042 ms

(3)external选项案例

如果要让服务加入现有的网络,要使用 external 选项.

version: "3.7"
services:
  worker:
    image: "centos"
    stdin_open: true    # 开启标准输入保持打开
    tty: true           # 分配伪终端
    networks:
      - yun1-test
networks:
  yun1-test:
    external: true

测试操作如下:

# 创建网络并查看
[root@yun test_external]# docker network create --driver bridge  yun1-test
a22a2c5f57f20cada338be94b81232c881d4aa7d3b518a41aacc617278ca37d6
[root@yun test_external]# docker network ls
NETWORK ID     NAME                  DRIVER    SCOPE
a22a2c5f57f2   yun1-test             bridge    local

[root@yun test_external]# docker-compose up -d
[root@yun test_external]# docker-compose ps 
NAME                     IMAGE     COMMAND       SERVICE   CREATED         STATUS         PORTS
test_external-worker-1   centos    "/bin/bash"   worker    6 seconds ago   Up 5 seconds 
[root@yun test_external]# docker inspect test_external-worker-1 --format="{{json .NetworkSettings.Networks}}"
{"yun1-test":{"IPAMConfig":null,"Links":null,"Aliases":["test_external-worker-1","worker"],"MacAddress":"02:42:ac:1c:00:02","NetworkID":"a22a2c5f57f20cada338be94b81232c881d4aa7d3b518a41aacc617278ca37d6","EndpointID":"1881a855e69da99e0b54b3f8b6e3b7c97baa5ef3f1fc86dd53a3f9ebcb28d970","Gateway":"172.28.0.1","IPAddress":"172.28.0.2","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"DriverOpts":null,"DNSNames":["test_external-worker-1","worker","dac4a0181129"]}}

5、volumes

此处 volumes 是服务的下级键,用于定义要挂载的主机路径或命名卷。

  • 挂载主机路径作为单个服务定义一部分,不用在 volumes 节中定义卷
  • 多个服务用一个卷,要在 volumes 节中定义卷,另外在服务中用 volumes 键引用。

volumes 键的定义有两种格式:

  • 长格式:使用多个选项定义
  • 短格式:直接使用 主机:容器 格式指定主机上的路径,或者使用 主机:容器:ro 格式定义访问模式

(1)长格式语法

  • type:挂载类型 volumebindtmpfsnpipe
  • source:挂载的源(主机路径或卷),不适用于 tmpfs 挂载
  • target:挂载目标(容器中挂载路径)
  • read_only:将卷设置为只读模式
  • bind:配置绑定挂载选项
    • propagation:传播模式
    • create_host_path:若主机无内容,在源路径创建目录;若有内容,则不做任务事
    • selinux:SElinux 重新标识 选项 z(共享)、Z(私有)
  • volume:配置卷选项
    • nocopy:创建卷时禁止从容器复制数据
  • tmpfs:配置tmpfs选项
    • size:tmpfs挂载的大小,单位为字节
    • mode:tmpfs挂载文件模式以八进制数作为UNIX权限位
  • consistency:挂载的一致性要求

长格式示例:

# 案例:backend服务中分别进行了卷挂载和绑定挂载,db-data卷在volume节中定义
services:
  backend:
    image: awesome/backend
    volumes:
      - type: volume
        source: db-data
        target: /data
        volume:
          nocopy: true
      - type: bind
        source: /var/run/postgres/postgres.sock
        target: /var/run/postgres/postgres.sock

volumes:
  db-data:

(2)短格式语法

使用单个字符串,值以冒号分割,指定卷或绑定挂载或访问模式

  • volume:主机路径或卷名
  • container_path:容器挂载卷的路径
  • access_mode:访问模式,rw读写模式、ro只读模式、z(selinux配置挂载主机内容在容器间共享)、Z(selinux配置挂载主机内容私有)

短格式案例:

volumes:
  # 仅定义一个路径,让docker引擎自动创建一个匿名卷
  - /var/lib/mysql
  # 定义一个绑定挂载
  - /opt/data:/var/lib/mysql
  # 定义主机上相当于compose文件路径
  - ./cache:/tmp/cache
  # 定义相对于用户的路径
  - ~/configs:/etc/configs/:ro
  # 命名卷
  - datavolume:/var/lib/mysql

6、mysql8单服务案例

准备上下文环境和相关文件:

[root@master ~] mkdir mysql8 && cd mysql8

# 编辑docker-compose.yml文件
version: '3.7'
services:
  mysql:
    image: mysql:8.0
    container_name: mysql
    ports:
      - 3306:3306
    command:
      --default-authentication-plugin=mysql_native_password
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_general_ci
      --explicit-defaults-for-timestamp=true
      --lower_case_table_names=1
    environment:
      - MYSQL_ROOT_PASSWORD=root
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - volumes.mysql8-data:/var/lib/mysql
volumes:
  volumes.mysql8-data: null

# 验证和查看
[root@master mysql8]# docker-compose config
# 验证结果正常,且以更规范的形式显示整个文件

# 启动服务
[root@master mysql8]# docker-compose up -d

# 查看正在运行的服务
[root@master mysql8]# docker-compose ps
NAME                COMMAND                  SERVICE             STATUS              PORTS
mysql               "docker-entrypoint.s…"   mysql               running             0.0.0.0:3306->3306/tcp, :::3306->3306/tcp

# 查看日志
[root@master mysql8]# docker-compose logs
mysql  | 2025-05-14T10:28:11.608941Z 8 [Warning] [MY-013360] [Server] Plugin mysql_native_password reported: ''mysql_native_password' is deprecated and will be removed in a future release. Please use caching_sha2_password instead'

# 访问数据库
[root@master mysql8]# docker exec -it mysql mysql -uroot -proot
Your MySQL connection id is 11
Server version: 8.0.42 MySQL Community Server - GPL
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> 

# 停止服务
[root@master mysql8]# docker-compose down --volumes

7、Django/PostgreSQL程序案例

准备上下文环境和相关文件:

[root@master ~]# mkdir django && cd django

# 编辑Dockerfile
[root@master django]# vi Dockerfile 
FROM python:3.6
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
COPY requirements.txt /code/
RUN pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple &&  pip install --upgrade pip && pip install -r requirements.txt
COPY . /code/

# 编辑requirements.txt文件
[root@master django]# vi requirements.txt 
Django>=2.0,<3.0
psycopg2>=2.7,<3.0

# 编辑docker-compose.yml文件
[root@master django]# cat docker-compose.yml 
version: '3.7'
services:
  db:
    image: postgres
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    volumes:
      - db_data:/var/lib/postgresql
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db
volumes:
    db_data: {}

创建项目和修改配置

# 创建Django项目
[root@master django]# docker-compose run web django-admin startproject myexample .

# 查看所创建的项目内容
[root@master django]# ls
docker-compose.yml  Dockerfile  manage.py  myexample  requirements.txt

# 修改settings.py
[root@master django]# vi myexample/settings.py
ALLOWED_HOSTS = ['*']
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'postgres',
        'USER': 'postgres',
        'PASSWORD': 'postgres',
        'HOST': 'db',
        'PORT': 5432
    }
}

# 启动程序
[root@master myexample]# docker-compose up

# 访问http://192.168.200.103:8000/  可查看Django首页信息。

五、docker-compose命令详解

docker-compose 是一个用于定义和运行多容器docker应用的工具,使用 yaml文件来配置服务、网络、卷等。

可以轻松启动、停止、重建、关闭多个容器。

Usage:  docker-compose [OPTIONS] COMMAND\
Options:
      --ansi string                Control when to print ANSI control characters ("never"|"always"|"auto") (default "auto")
      --compatibility              Run compose in backward compatibility mode
      --env-file string            Specify an alternate environment file.     # 指定包含环境变量的文件,在服务中可用
  -f, --file stringArray           Compose configuration files                # 指定一个或多个compose文件的名称和路径
      --profile stringArray        Specify a profile to enable               # 指定配置文件中的profiles启动服务
      --project-directory string   Specify an alternate working directory     # 指定项目路径,默认为compose文件所在路径
                                   (default: the path of the, first specified, Compose file)      
  -p, --project-name string        Project name              # 指定项目名称,默认使用当前目录作为项目名称

Commands:
  build       Build or rebuild services        # 构建服务容器镜像
  convert     Converts the compose file to platforms canonical format    
  cp          Copy files/folders between a service container and the local filesystem   # 在容器和本地文件系统间复制文件和文件夹
  create      Creates containers for a service.        # 给服务创建容器
  down        Stop and remove containers, networks     # 停止并删除容器、网络
  events      Receive real time events from containers.    # 显示容器事件
  exec        Execute a command in a running container.    # 连接容器
  images      List images used by the created containers   # 列出创建的容器使用的镜像
  kill        Force stop service containers.         # 强停服务容器
  logs        View output from containers            # 查看容器日志
  ls          List running compose projects          # 列出运行中项目
  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 containers                # 重启容器
  rm          Removes stopped service containers           # 删除停止的服务容器
  run         Run a one-off command on 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      # 显示版本信息
  wait        Block until the first service container stops
  watch       Watch build context for service and rebuild/refresh containers when files are updated

1、docker-compose build

该命令根据compose文件中定义的服务配置及关联Dockerfile文件构建服务镜像。

允许我们一次性构建或更新整个项目多个服务的镜像。

Usage:  docker compose build [OPTIONS] [SERVICE...]
Build or rebuild services
Options:  
      --build-arg stringArray   Set build-time variables for services         # 为服务设置构建时的变量
      --builder string          Set builder to use
      --dry-run                 Execute command in dry run mode
  -m, --memory bytes            Set memory limit for the build container. Not supported by BuildKit.
      --no-cache                Do not use cache when building the image      # 强制docker忽略缓存,从头开始构建镜像,常用于确保使用最新依赖或清理潜在构建问题
      --pull                    Always attempt to pull a newer version of the image    # 总是尝试拉取最新版本的镜像
      --push                    Push service images
  -q, --quiet                   Dont print anything to STDOUT    # 不打印到标准输出
      --ssh string              Set SSH authentications used when building service images. (use 'default'    # 设置ssh认证
                                for using your default SSH Agent)
      --with-dependencies       Also build dependencies (transitively)


# 案例:
# docker-compose.yml文件内容如下:
services:
  yun3_service:
    build:
      context: .
      args:
        VERSION: 1.0
    stdin_open: true    # 开启标准输入保持打开
    tty: true           # 分配伪终端

# 在当前目录下准备Dockerfile文件
FROM centos:7.9.2009
RUN rm -rf /etc/yum.repos.d/*.repo 
ADD http://mirrors.aliyun.com/repo/Centos-7.repo /etc/yum.repos.d/
CMD ["/bin/bash"]


# 然后构建服务如下:
[root@yun test_build]# docker-compose build yun3_service

2、docker-compose up

该命令用于构建镜像,创建、启动和连接指定的服务容器。

使用该命令后,所有连接的服务都会启动,除非它们已经运行。

docker-compose up该命令会默认将所有输出重定向到控制台。这样并不方便排查问题,最好是使用-d选项,采用分离模式在后台启动容器并保持运行。

Usage:  docker compose up [SERVICE...]
Create and start containers
Options:
      --abort-on-container-exit   Stops all containers if any container was stopped. Incompatible with -d       # 只要有容器停止就停止所有容器,与-d选项不兼容
      --always-recreate-deps      Recreate dependent containers. Incompatible with --no-recreate.       # 总是重新创建所依赖的容器,与--no-recreate选项不兼容
      --attach stringArray        Attach to service output.
      --attach-dependencies       Attach to dependent containers.
      --build                     Build images before starting containers.      # 在启动容器之前构建镜像
  -d, --detach                    Detached mode: Run containers in the background          # 后台运行服务容器,输出新容器名称
      --exit-code-from string     Return the exit code of the selected service container. Implies --abort-on-container-exit   # 为指定服务的容器返回退出码
      --force-recreate            Recreate containers even if their configuration and image havent changed.      # 强制重新创建容器,即使配置和镜像没有变化
      --no-build                  Dont build an image, even if its missing.     # 不构建缺失的镜像
      --no-color                  Produce monochrome output.
      --no-deps                   Dont start linked services.                   # 不启动所连接的服务
      --no-log-prefix             Dont print prefix in logs.
      --no-recreate               If containers already exist, dont recreate them. Incompatible with --force-recreate.
      --no-start                  Dont start the services after creating them.
      --quiet-pull                Pull without printing progress information.              # 拉取镜像时不会输出进程信息
      --remove-orphans            Remove containers for services not defined in the Compose file.     # 移除compose文件中未定义的服务容器
  -V, --renew-anon-volumes        Recreate anonymous volumes instead of retrieving data from the previous containers.
      --scale scale               Scale SERVICE to NUM instances. Overrides the scale setting in the Compose file if present.   # 服务=数值,来设置服务的实例数量
  -t, --timeout int               Use this timeout in seconds for container shutdown when attached or when containers are already running. (default 10)   # 设置停止连接的容器或已运行容器所等待的超时时间
      --wait                      Wait for services to be running|healthy. Implies detached mode.

3、docker-compose down

该命令用于停止容器并删除由 docker-compose up 命令启动的容器、网络、卷、镜像。

默认情况会删除,compose文件中定义的服务的容器、compose文件中networks定义的网络、所使用的默认网络。

默认情况不会删除,外部定义的网络、卷。

Usage:  docker compose down
Stop and remove containers, networks
Options:
      --remove-orphans    Remove containers for services not defined in the Compose file.    # 删除不在compose文件中定义的服务容器
      --rmi string        Remove images used by services. "local" remove only images that dont have a custom tag ("local"|"all")    # 删除服务使用的镜像
  -t, --timeout int       Specify a shutdown timeout in seconds (default 10)    # 设置停止容器的超时时间(默认10秒)
  -v, --volumes volumes    Remove named volumes declared in the volumes section of the Compose file and anonymous volumes attached to containers.     # 删除由服务定义创建的数据卷


# 常规清理(清理容器和网络)
docker-compose down

# 带数据卷清理
docker-compose down -v
[root@hqs-docker my_wordpress]# docker-compose down -v
[+] Running 4/2
 ⠿ Container my_wordpress-wordpress-1  Removed                 1.2s
 ⠿ Container my_wordpress-db-1         Removed                 1.7s
 ⠿ Volume my_wordpress_db_data         Removed                 0.0s
 ⠿ Network my_wordpress_default        Removed                 0.0s


# 删除镜像
docker-compse down --rmi all
[root@hqs-docker my_wordpress]# docker-compose down --rmi all
[+] Running 3/3
 ⠿ Image mysql:5.7               Removed                         0.0s    #从注册中心下载的进行
 ⠿ Network my_wordpress_default  Removed                         0.0s
 ⠿ Image wordpress:latest        Removed                         0.2s    # 在本地构建的镜像

# 超时设置(设置容器停止超时时间为30秒)
docker-compose down --timeout 30

4、 docker-compose run

该命令用于运行一次性或临时任务,需要制定运行的服务名称,并仅启动正在运行的服务所依赖的服务容器。

该命令适合运行测试或执行管理任务。

Usage:  docker compose run [options] [-v VOLUME...] [-p PORT...] [-e KEY=VAL...] [-l KEY=VALUE...] SERVICE [COMMAND] [ARGS...]
Run a one-off command on a service.
Options:
  -d, --detach                Run container in background and print container ID      # 后台运行仅打印容器ID
      --entrypoint string     Override the entrypoint of the image                    # 覆盖entrypoint指令
  -e, --env stringArray       Set environment variables       # 设置环境变量
  -i, --interactive           Keep STDIN open even if not attached. (default true)   # 保持开启标准输入
  -l, --label stringArray     Add or override a label         # 添加或覆盖标签
      --name string            Assign a name to the container    # 声明容器名
  -T, --no-TTY                Disable pseudo-TTY allocation (default: auto-detected).   # 禁止分配伪终端,通常不需要交互式终端时使用
      --no-deps               Dont start linked services.       # 不启动服务所依赖的服务容器
  -p, --publish stringArray   Publish a containers port(s) to the host.     # 发布容器端口
      --quiet-pull            Pull without printing progress information.      # 拉取不打印过程信息
      --rm                    Automatically remove the container when it exits     # 容器退出自动删除
      --service-ports         Run command with the services ports enabled and mapped to the host.    # 重用服务配置中的端口映射
      --use-aliases           Use the service‘s network useAliases in the network(s) the container connects to.     # 使用服务网络别名
  -u, --user string           Run as specified username or uid          # 指定容器运行命令的用户名或用户ID
  -v, --volume stringArray    Bind mount a volume.              # 绑定宿主机目录或已存在的数据卷到容器
  -w, --workdir string        Working directory inside the container    # 指定容器内部的工作目录


# django实验案例
[root@host1 django-pg]# docker-compose run web django-admin startproject myexample .

5、docker-compose ps

该命令查看服务中当前运行的容器。

[root@hqs-docker ~]# docker-compose ps --help
Usage:  docker compose ps [SERVICE...]
List containers

Options:
  -a, --all                  Show all stopped containers (including those created by the run command)    # 显示所有已经停止的容器
      --filter string        Filter services by a property (supported filters: status).         # 根据属性过滤服务
      --format string        Format the output. Values: [pretty | json] (default "pretty")      # 格式化输出
  -q, --quiet                Only display IDs       # 只显示ID
      --services             Display services       # 显示服务
      --status stringArray   Filter services by status. Values: [paused | restarting | removing | running | dead | created | exited]     # 过滤服务状态

[root@hqs-docker my_wordpress]# docker-compose ps
容器名(项目名_服务名_序号)  启动容器执行的命令        服务名              容器当前状态         映射的端口信息
NAME                       COMMAND                  SERVICE             STATUS              PORTS
my_wordpress-db-1          "docker-entrypoint.s…"   db                  running             33060/tcp
my_wordpress-wordpress-1   "docker-entrypoint.s…"   wordpress           running             0.0.0.0:8000->80/tcp, :::8000->80/tcp

6、docker-compose rm

该命令用于删除所有处于停止状态的服务容器。

Usage:  docker compose rm [SERVICE...]
Removes stopped service containers
By default, anonymous volumes attached to containers will not be removed. You
can override this with -v. To list all volumes, use "docker volume ls".
Any data which is not in a volume will be lost.

Options:
  -f, --force     Dont ask to confirm removal    # 删除不问询确认
  -s, --stop      Stop the containers, if required, before removing   # 删除前先停止容器
  -v, --volumes   Remove any anonymous volumes attached to containers  # 删除容器附加的卷

7、docker-compose start/stop/kill/pause/uppause

# 启动运行指定服务已经存在但停止的容器
Usage:  docker compose start [SERVICE...]  
Start services

# 停止运行指定服务的所有容器
Usage:  docker compose stop [SERVICE...]
Stop services
Options:
  -t, --timeout int   Specify a shutdown timeout in seconds (default 10)     # 指定关闭超时时间(默认10秒)

# 发送SIGKILL信号强制终止正在运行的容器
Usage:  docker compose kill [options] [SERVICE...]
Force stop service containers.
Options:
  -s, --signal string   SIGNAL to send to the container. (default "SIGKILL")

# 暂停指定服务的容器
Usage:  docker compose pause [SERVICE...]
Pause services

# 恢复指定服务的容器
Usage:  docker compose unpause [SERVICE...]
Unpause services

六、从源代码构建、部署和管理应用程序

项目的程序采用python编写,使用了flask框架。

通过redis服务维护一个计数器。

# 1、创建flask项目目录
[root@hqs-docker ~]# mkdir flask-web && cd flask-web
[root@hqs-docker flask-web]# pwd
/root/flask-web

# 2、编写python程序
[root@hqs-docker flask-web]# vi 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 e:
            if retries == 0:   # retries值为0,则抛出异常
                raise e
            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.run(debug=True, host='0.0.0.0', port=5000)

# 3、编写requirement.txt文件
[root@hqs-docker flask-web]# vi requirements.txt
flask
redis

# 4、编写Dockerfile文件
[root@hqs-docker flask-web]# vi Dockerfile
FROM python:3.4-alpine
ADD . /code
WORKDIR /code
RUN pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple &&  pip install --upgrade pip && pip install -r requirements.txt
CMD ["python", "app.py"]

# 5、编写Compose文件
[root@hqs-docker flask-web]# vi docker-compose.yml
version: '3'
services:
  web:
    build: .
    ports:
      - "5000:5000"
  redis:
    image: "redis:alpine"


# 6、构建并运行服务
[root@hqs-docker flask-web]# docker-compose up 
[+] Running 3/1                                                                                                          
 ⠿ Network flask-web_default    Created                                                                             0.0s 
 ⠿ Container flask-web-redis-1  Created                                                                             0.0s
 ⠿ Container flask-web-web-1    Created                                                                             0.0s
Attaching to flask-web-redis-1, flask-web-web-1
flask-web-redis-1  | 1:C 05 Jun 2024 14:52:32.570 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
flask-web-redis-1  | 1:C 05 Jun 2024 14:52:32.570 # Redis version=6.2.6, bits=64, commit=00000000, modified=0, pid=1, just started
...
flask-web-web-1    |  * Serving Flask app "app" (lazy loading)
flask-web-web-1    |  * Environment: production
flask-web-web-1    |    WARNING: This is a development server. Do not use it in a production deployment.
flask-web-web-1    |    Use a production WSGI server instead.
flask-web-web-1    |  * Debug mode: on
flask-web-web-1    |  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

# 访问网页 http://192.168.130.101:5000/  测试,多次访问,次数不断增加
Hello World! I have been seen 2 times.
Hello World! I have been seen 3 times.
posted @ 2022-06-07 14:45  休耕  阅读(1372)  评论(0)    收藏  举报