循序渐进Docker Compose

1.概述

1.1 Docker Compose 定义

Docker Compose是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器

1.2 Docker Compose背景

我们使用 Docker 的时候,定义 Dockerfile 文件,然后使用 docker build、docker run 等命令操作容器。然而微服务架构的应用系统一般包含若干个微服务,每个微服务一般都会部署多个实例,如果每个微服务都要手动启停,那么效率之低,维护量之大可想而知。
Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。.Docker Compose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器,Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。
注意,为变量输入数据时,必须遵循标准 YAML 规则。 对于包含特殊字符的密码,需要正确转义它们($ 是转义字符)或正确引用变量。 如果不知道如何执行此操作或不愿意研究,最好的做法是仅使用字母数字字符。

1.3 Docker Compose核心概念

Docker Compose将所管理的容器分为三层,分别是:

  • 项目(project)
  • 服务(service)
  • 容器(containner)
    我们将通过后续的章节理解这三层的意思或用途

2.安装

2.1 Official Repos

从版本 2 开始,Docker 开始将 docker compose 发布为基于 Go 的 Docker 插件(而不是基于 Python 的独立二进制文件)。并且为多个架构发布了这个插件,而 v1.x 版本的二进制文件仅适用于 x86_64 架构。
按照此处描述从官方仓库安装 Docker,确保在此过程中安装 docker-compose-plugin 软件包。

2.2 Manual Installation

通过以下命令手动安装 docker compose:

mkdir -p "$HOME/.docker/cli-plugins" 
curl -sL "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o "$HOME/.docker/cli-plugins/docker-compose" 
chmod +x $HOME/.docker/cli-plugins/docker-compose

在系统范围内安装,可以使用 /usr/local/lib/docker/cli-plugins 而不是 $HOME/.docker/cli-plugins
如果已经安装了 docker(或至少安装了 docker-cli),最好是从官仓 安装compose,运行 docker compose version 将显示 compose 版本。

./docker-compose version
Docker Compose version v2.27.0

2.3 v1.x 兼容性

由于 v2 作为插件运行而不是独立的二进制文件,它通过 docker compose args 而不是 docker-compose args调用。
Docker 在推出 v2 作为插件运行后,为了帮助用户更顺利地从 v1 迁移到 v2,提供了一个新的适用于 x86_64 和 aarch64 平台的docker-compose 二进制文件以兼容原有的命令调用方式。例如:

  • 以插件方式运行comose:
docker compose version
Docker Compose version v2.27.0
  • 兼容命令方式:
/home/docker/.docker/cli-plugins/docker-compose version
Docker Compose version v2.27.0

3. YAML 配置说明

简而言之,Docker Compose 通过应用在单个 docker-compose.yml 配置文件中声明的许多规则来工作。
几乎每个规则都替换了特定的 Docker 命令,因此最终只需要运行:

docker-compose up

使用 Docker Compose 可以应用大量的配置,而这些配置是由 Compose 在后台处理的, 这省去用 Bash 或其他东西编写脚本的麻烦。

在此文件中,我们需要指定至少一项服务以及可选的卷和网络:

version: "3.7"
services:
  ...
volumes:
  ...
networks:
  ...

3.1 Services

首先,服务指的是容器的配置.
例如,以一个由前端、后端和数据库组成的 Docker 化 Web 应用程序为例。 可能会将这些组件拆分为三个映像,并在配置中将它们定义为三个不同的服务:

services:
  frontend:
    image: my-vue-app
    ...
  backend:
    image: my-springboot-app
    ...
  db:
    image: postgres
    ...

3.2 Volumes & Networks

卷是主机和容器之间甚至容器之间共享的磁盘空间的物理区域。 换句话说,卷是主机中的共享目录,对某些或所有容器可见。
同样,网络定义了容器之间以及容器与主机之间的通信规则。 Common network zones(公共网络区域)将使容器的服务可以相互发现,而private zones(私有区域)将它们隔离在虚拟沙箱中。

4. 解析 Service

现在让我们开始检查服务的主要设置。

4.1 Pulling一个Image

有时,Service所需的镜像已经(由我们或其他人)发布在 Docker Hub 或另一个 Docker Registry中。
可以通过来使用 image 属性引用它,在属性中指定镜像名称和标签

services: 
  my-service:
    image: ubuntu:latest
    ...

4.2 Building一个Image

或者使用dockerfile建置,需要通过读取 Dockerfile构建镜像。
这里使用 build 关键字,将 Dockerfile 的路径作为值传递:

services: 
  my-custom-app:
    build: /path/to/dockerfile/
    ...

使用 URL 代替路径:

services: 
  my-custom-app:
    build: https://github.com/my-company/my-project.git

还可以与 build 属性一起指定image名称,该属性将在创建后命名image,后续可供其他服务使用:

services: 
  my-custom-app:
    build: https://github.com/my-company/my-project.git
    image: my-project-image
    ...

4.3 Configuring the Networking

Docker 容器之间,通过 Docker Compose 隐式创建或通过配置创建的网络进行通信。一个服务可以通过容器名称和端口(例如 network-example-service:80)直接引用同一网络上的另一个服务进行通信,前提是已经通过expose关键字公开端口:

services:
  network-example-service:
    image: karthequian/helloworld:latest
    expose:
      - "80"

但是,要从主机访问容器,端口必须通过ports关键字进行映射,映射的format如下:
host_port:container_port

services:
  network-example-service:
    image: karthequian/helloworld:latest
    ports:
      - "80:80"
    ...
  my-custom-app:
    image: myapp:latest
    ports:
      - "8080:3000"
    ...
  my-custom-app-replica:
    image: myapp:latest
    ports:
      - "8081:3000"
    ...

端口 80 现在将在主机上可见,而其他两个容器的 3000 端口将分别在主机的 8080 和 8081 端口上可用

进一步定义额外的虚拟网络来隔离容器:

services:
  network-example-service:
    image: karthequian/helloworld:latest
    networks: 
      - my-shared-network
    ...
  another-service-in-the-same-network:
    image: alpine:latest
    networks: 
      - my-shared-network
    ...
  another-service-in-its-own-network:
    image: alpine:latest
    networks: 
      - my-private-network
    ...
networks:
  my-shared-network: {}
  my-private-network: {}

“another-service-in-the-same-network“将能够ping并访问“network-example-service”的端口80,而“another-service-in-its-own-network”则不行。

4.4 设置卷

卷分为三种类型:

  • anonymous(匿名卷)
  • named(命名卷)
  • host(主机卷)
    Docker 管理着匿名卷和命名卷,并自动将它们挂载到主机上自行生成的目录中。虽然在旧版本的 Docker(1.9 之前)中,匿名卷很有用,但现在推荐使用命名卷。主机卷还允许我们指定主机上的一个现有文件夹。。
    我们可以在service级别配置主机卷,并在配置的外层级别配置命名卷,以便后者对其他容器可见,而不仅仅是它们所属的容器可见:
services:
  volumes-example-service:
    image: alpine:latest
    volumes: 
      - my-named-global-volume:/my-volumes/named-global-volume                     --引用命名卷
      - /tmp:/my-volumes/host-volume                                               --主机卷
      - /home:/my-volumes/readonly-host-volume:ro                                  --主机卷
    ...
  another-volumes-example-service:
    image: alpine:latest                        
    volumes:
      - my-named-global-volume:/another-path/the-same-named-global-volume           --引用命名卷
    ...
volumes:
  my-named-global-volume:  --定义命名卷

这里,两个容器都将对 my-named-global-volume 共享文件夹具有读/写访问权限,无论它们将其映射到哪个路径。 相反,这两个主机卷将仅可用于volumes-example-service。

主机文件系统的 /tmp 文件夹映射到容器的 /my-volumes/host-volume 文件夹。 文件系统的这一部分是可写的,这意味着容器可以读取也可以写入(和删除)主机中的文件。
通过在规则中附加 :ro 以只读模式挂载卷,就像 /home 文件夹(因为有时候不希望 Docker 容器错误地删除用戶的home目录)。

4.5 声明依赖关系

通常,如果需要在服务之间创建依赖链,以便某些服务在其他服务之前加载(并在之后卸载)。 则通过depends_on关键字来实现这个结果:

services:
  kafka:
    image: wurstmeister/kafka:2.11-0.11.0.3
    depends_on:
      - zookeeper
    ...
  zookeeper:
    image: wurstmeister/zookeeper

不过要注意,Compose 不会等待 Zookeeper 服务加载完成才启动 kafka 服务; 它只是简单的等待它start。 如果我们需要在启动另一个服务之前完全加载一个服务,需要在 Compose 中更深入地控制启动和关闭顺序

5. 管理环境变量

在 Compose 中使用环境变量非常简单。我们可以定义静态环境变量,也可以使用 ${} 标记来定义动态变量。

services:
  database: 
    image: "postgres:${POSTGRES_VERSION}"
    environment:
      DB: mydb
      USER: "${USER}"

有不同的方法可以向 Compose 提供这些值:
例如,一种方法是将它们设置在同一目录中的 .env 文件中,其结构类似于 .properties 文件,key=value:

POSTGRES_VERSION=alpine
USER=foo

否则,在调用命令之前在操作系统中设置变量:

export POSTGRES_VERSION=alpine
export USER=foo
docker-compose up

也可以在 shell 中使用简单的一行代码:

POSTGRES_VERSION=alpine USER=foo docker-compose up

可以混合使用这些方法,但请记住,Compose 使用以下优先级顺序,用较高优先级覆盖不太重要的内容:

  • 1.Compose file
  • 2.Shell environment variables
  • 3.Environment file
  • 4.Dockerfile
  • 5.Variable not defined

6. Scaling & Replicas

在较旧的 Compose 版本中,可以通过 docker-compose scale 命令来扩展容器实例。较新的版本废弃了这个命令,并用 --scale 选项取而代之。
利用 Docker Swarm(一个 Docker 引擎的集群),并通过 deploy 部分的 replicas 属性声明性地自动扩展容器。

services:
  worker:
    image: dockersamples/examplevotingapp_worker
    networks:
      - frontend
      - backend
    deploy:
      mode: replicated
      replicas: 6
      resources:
        limits:
          cpus: '0.50'
          memory: 50M
        reservations:
          cpus: '0.25'
          memory: 20M

在 deploy 部分,还可以指定许多其他选项,例如资源阈值。然而,Compose 仅在部署到 Swarm 时才考虑整个 deploy 部分,否则会忽略它。

7. 生命周期管理

Docker Compose 的语法:

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

有许多可用的选项和命令,但至少需要知道正确active和deactive整个系统的选项和命令。

7.1. Startup

可以使用 up 命令来创建和启动配置中定义的容器、网络和卷。

docker-compose up

在第一次之后,可以简单地使用 start 命令来启动服务

docker-compose start

如果文件的名称与默认文件名 (docker-compose.yml) 不同,可以利用 -f 和 ––file 标志来指定备用文件名:

docker-compose -f custom-compose-file.yml start

使用 -d 选项启动时,Compose 还可以作为守护进程在后台运行:

docker-compose up -d

7.2. Shutdown

为了安全地停止活动服务,可以使用 stop,它将保留容器、卷和网络,以及对它们所做的每项修改:

docker-compose stop

要重置项目的状态,可以运行 down 命令。运行 down 命令会删除由 docker-compose.yml 文件定义的所有服务、网络和容器,但会保留外部卷(如果有的话)

docker-compose down

8. Docker compose示例

8.1 Single service

以下是使用 docker compose 部署 single service的基本示例:

services:
  heimdall:
    image: linuxserver/heimdall
    container_name: heimdall
    volumes:
      - /home/user/appdata/heimdall:/config
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/London
    ports:
      - 10080:80
      - 10443:443
    restart: unless-stopped

如果将上述代码片段保存在名为 compose.yml 的文件中,则只需从同一文件夹中运行 docker compose up -d 即可自动拉取 heimdall 映像,并创建并启动一个容器。 up 表示创建并启动服务,-d 表示在后台执行。
如果从不同的文件夹执行操作,或者 yaml 文件命名为其他名字,例如 heimdall.yml,那么需要在命令中使用 -f 选项:

docker compose -f /path/to/single_service.yml up -d。

docker compose ls将列出running状态的服务,如果要列出包含“非running状态”,需要搭配-a 选项

docker compose ls
NAME                STATUS              CONFIG FILES
docker              running(1)          /home/docker/single_service.yaml

8.2 Multiple Service

以下是使用 docker compose 部署 multiple service的基本示例:
可以通过一个单一的 compose yaml 文件来管理多个服务。将以下内容复制.yml 文件中,然后使用 docker-compose up/down 命令就可以同时对所有服务进行操作。

services:
  heimdall:
    image: linuxserver/heimdall
    container_name: heimdall
    volumes:
      - /home/user/appdata/heimdall:/config
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/London
    ports:
      - 80:80
      - 443:443
    restart: unless-stopped

  nginx:
    image: linuxserver/nginx
    container_name: nginx
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/London
    volumes:
      - /home/user/appdata/nginx:/config
    ports:
      - 81:80
      - 444:443
    restart: unless-stopped

  mariadb:
    image: linuxserver/mariadb
    container_name: mariadb
    environment:
      - PUID=1000
      - PGID=1000
      - MYSQL_ROOT_PASSWORD=ROOT_ACCESS_PASSWORD
      - TZ=Europe/London
    volumes:
      - /home/user/appdata/mariadb:/config
    ports:
      - 3306:3306
    restart: unless-stopped

启动yaml档:

docker compose -f /home/docker/multi_service.yaml up -d
[+] Running 3/3
 ✔ Container nginx     Running                                                                                                                                                                                 0.0s
 ✔ Container heimdall  Running                                                                                                                                                                                 0.0s
 ✔ Container mariadb   Started 

查看compose项目运行状况

docker@anzfam:~$ docker compose ls -a
NAME                STATUS              CONFIG FILES
docker              running(3)          /home/docker/multi_service.yaml

查看compose包含的服务

docker@anzfam:~$ docker compose config --services
heimdall
mariadb
nginx

查看compose所拥有的容器

docker container ls -a
CONTAINER ID   IMAGE                  COMMAND   CREATED          STATUS              PORTS                                                                                NAMES
dcbf3af2c44e   linuxserver/heimdall   "/init"   19 minutes ago   Up 19 minutes       0.0.0.0:10080->80/tcp, :::10080->80/tcp, 0.0.0.0:10443->443/tcp, :::10443->443/tcp   heimdall
a3939bcca133   linuxserver/nginx      "/init"   19 minutes ago   Up 19 minutes       0.0.0.0:10081->80/tcp, :::10081->80/tcp, 0.0.0.0:10444->443/tcp, :::10444->443/tcp   nginx
59b322021f3a   linuxserver/mariadb    "/init"   19 minutes ago   Up About a minute   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp                                            mariadb

从上述输出结果来看,已经定义了 3 个服务:heimdall、nginx 和 mariadb,并与之对应有三个container运行,当执行 docker compose up -d 时,它将首先下载所有三个容器的映像(如果它们不存在)(如果存在,则不会更新),然后它将创建所有三个容器并启动它们。 docker compose down 将关闭所有三个服务并销毁容器(持久数据将保留)。

8.3 启动多个compose project

前面讲到docker compose将整个结构分为project、service以及container三层,如果想要在同一台主机上启动多个yaml档项目,需要指定-p选项来指定project name,否则docker将默认project name为docker,如此当分别启动上述两个示例时,可能会产生冲突

启动single_service.yaml,并命名为single-service-example

 docker compose -f ./single_service.yaml -p single-service-example up -d
[+] Running 2/2
 ✔ Network single-service-example_default  Created                                                                                                                                                                                      0.1s
 ✔ Container heimdall01                    Started 

启动multi_service.yaml,并命名为multi-service-example

docker compose -f ./multi_service.yaml -p multi-service-example up -d
[+] Running 4/4
 ✔ Network multi-service-example_default  Created                                                                                                                                                                                       0.1s
 ✔ Container nginx                        Started                                                                                                                                                                                       1.9s
 ✔ Container mariadb                      Started                                                                                                                                                                                       1.5s
 ✔ Container heimdall02                   Started 

查看结果显示这里已经有两个不同yaml档建立的project

docker@anzfam:~$ docker compose ls -a
NAME                     STATUS              CONFIG FILES
multi-service-example    running(3)          /home/docker/multi_service.yaml
single-service-example   running(1)          /home/docker/single_service.yaml

相关推荐

  1. DockerCompose

    2024-05-26 02:20:42       41 阅读
  2. 循序渐进Docker Compose

    2024-05-26 02:20:42       14 阅读
  3. 循序渐进理解数据库基本概念

    2024-05-26 02:20:42       25 阅读
  4. DockerCompose安装mysql及配置

    2024-05-26 02:20:42       41 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-05-26 02:20:42       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-26 02:20:42       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-26 02:20:42       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-26 02:20:42       20 阅读

热门阅读

  1. 反编译 Trino Dockerfile

    2024-05-26 02:20:42       15 阅读
  2. Python pdf2imges -- pdf文件转图片

    2024-05-26 02:20:42       9 阅读
  3. ModuleNotFoundError: No module named ‘import_export‘

    2024-05-26 02:20:42       7 阅读
  4. 网页解析之lxml与xpath

    2024-05-26 02:20:42       11 阅读
  5. Django搭建和数据迁移

    2024-05-26 02:20:42       10 阅读
  6. 【Redis精通之路】数据类型(2)

    2024-05-26 02:20:42       10 阅读
  7. 删除有序数组中的重复项-力扣

    2024-05-26 02:20:42       10 阅读