Docker 实战:使用 Docker Compose 实现高效的多容器部署

在这里插入图片描述

1. 简介

Docker Compose 是一个工具,允许用户通过一个 YAML 文件定义和运行多容器 Docker 应用程序。使用 Compose,你可以在一个文件中配置你的应用服务、网络和数据卷,然后通过一个简单的命令docker-compose up创建和启动你的所有服务。这极大地简化了 Docker 容器的管理过程,特别是对于涉及多个相互依赖容器的复杂应用。具有如下核心特性:

  • 服务定义:在docker-compose.yml文件中,每个服务都可以指定使用的 Docker 镜像、构建路径(如果你是从Dockerfile构建镜像的话)、端口映射、容器之间的依赖关系、环境变量、数据卷挂载等。

  • 网络配置:Compose 允许你定义一个或多个隔离的网络,并将服务关联到这些网络,容器间能够在这些网络内部相互发现和通信。

  • 数据卷管理:你可以在 Compose 文件中定义和管理数据卷,这样可以持久化和共享容器间的数据。

  • 一键部署:通过一个命令docker-compose up,可以自动执行拉取镜像、构建镜像、创建网络和启动所有容器等一系列操作。

2. 发展历程

Docker项目启动时,容器的概念开始流行。最初,Docker被设计为一个简单的工具,用于管理单个容器。但随着用户开始将容器用于更复杂的应用程序,需要一种更好的方式来编排和管理多个相关的容器。Docker Compose 最初是作为一个名为 Fig 的开源项目启动。在当时是进行多容器管理的最佳方案。Fig 是一个基于 Docker 的 Python 工具,允许用户基于一个YAML文件定义多容器应用,从而可以使用 fig 命令行工具进行应用的部署。Fig 还可以对应用的全生命周期进行管理。

2015年 Docker Inc. 收购了 Fig,并将其重新命名为 Docker Compose。随着第一个公开版本 1.0 的发布,Docker Compose 宣布正式加入 Docker 生态系统。虽然它从未完全集成到Docker引擎中,但是仍然受到广泛关注并得到普遍使用。

2020年 Docker 宣布 Compose规范(Compose Specification)开放和标准化进程,旨在使 Compose 文件格式成为开放标准,支持其他开发者和公司更容易地集成和扩展 Compose。Docker 开始转向开发 Compose V2,这是对工具的重大更新。Compose V2 重写了 Python实现为 Go,与 Docker CLI 集成得更紧密,使得命令行使用更加一致,性能也有所提升。2021年 Docker Compose V2 开始作为 Docker CLI 的插件发布,实现了与 Docker CLI 的更好整合,并与 Docker Desktop 一同发布。

3. 安装

Docker Compose 作为 Docker Desktop 的一部分进行安装,所以一旦安装了 Docker Desktop ,也就安装了 Docker Compose。 Docker Desktop 如何安装具体请查阅:Docker 实战:使用 Docker Desktop 在 MacOS 上安装 Docker。在终端中运行如下命令检查 Docker Compose 是否安装:

smartsi@localhost docker % docker-compose --version
Docker Compose version v2.26.1-desktop.1

证明 Docker Compose 已经安装成功。

4. 核心概念

4.1 服务(Services)

服务就是应用的不同组成部分。在微服务架构中,每个服务通常运行一个独立的功能,比如Web服务器、数据库、应用接口(API)等。在docker-compose.yml文件中,你可以定义需要运行的服务,每个服务可以使用不同的 Docker 镜像。Compose 会在启动服务时创建需要的 Docker 容器。

4.2 容器(Containers)

容器是服务运行的实例。当你在 Docker Compose 中定义了服务之后,Compose 会利用Docker 来运行这些服务,每个服务都在其各自的容器内运行。这些容器是轻量级的,包含了运行服务所需要的所有依赖,独立于宿主机和其他容器运行。

4.3 镜像(Images)

镜像是一个轻量级、可执行的独立软件包,包含运行应用所需的一切:代码、运行时、库、环境变量和配置文件。在 Docker Compose 文件中,你可以指定使用现有的 Docker 镜像或者通过指向 Dockerfile 来构建新的镜像。

4.4 网络(Networks)

网络允许容器之间互相通信,Compose 会自动设置应用中服务之间能够进行发现和通信的网络。这对于应用中各服务的互连是必要的。例如,一个 Web 应用需要访问后端数据库,Compose 可以在同一个网络内部署这两个服务,以便它们可以互相发现并通信。

4.5 数据卷(Volumes)

数据卷用于数据持久化和数据共享。在无状态容器中管理状态和数据时非常重要。通过在Docker Compose 文件中定义数据卷,可以保留数据即使容器被销毁,同时在不同容器之间共享数据。

4.6 Docker-compose.yml文件

这是 Docker Compose 的核心,一个 YAML 格式的文件,在其中定义了你的多容器 Docker 应用。它包含服务、网络和数据卷的定义。该文件描述了组成你的应用的各个部分以及它们如何相互关联。

5. Compose 文件详解

Docker Compose 使用 YAML 文件来定义多服务的应用。YAML 是 JSON 的一个子集,因此也可以使用 JSON。不过本章中的例子将全部采用 YAML。 Docker Compose 默认使用文件名 docker-compose.yml。当然,用户也可以使用 -f 参数指定具体文件。

如下是一个简单的 Compose 文件的示例,它定义了一个包含两个服务(web 和 redis)的小型 Flask 应用。这是一个能够对访问者进行计数并将其保存到 Redis 的简单的 Web 服务:

version: "3.5"  
services:  
    web:  
        build: .  
        command: python app.py  
        ports:
            - target: 5000  
              published: 5000  
        networks:
            - counter-net  
        volumes:
            - type: volume  
              source: counter-vol  
              target: /code  
    redis:  
        image: "redis:alpine"  
        networks:  
            counter-net:

networks:  
    counter-net:

volumes:  
    counter-vol:

在深入研究之前粗略观察文件的基本结构,首先可以注意到,它包含4个一级key:version、services、networks、volumes。下面详细介绍一下。

5.1 version

version 是必须指定的,而且总是位于文件的第一行。它定义了 Compose 文件格式的版本。建议使用最新版本。 需要注意的是,version 并非定义 Docker Compose 或 Docker 引擎的版本号。上面示例中 Compose 文件使用的是 v3.5 版本。

5.2 services

services 用于定义不同的应用服务。上边的例子定义了两个服务:一个名为 web 的 Web 前端服务以及一个名为 redis 的内存数据库服务。Docker Compose 会将每个服务部署在各自的容器中,并且会使用 key 作为容器名字的一部分。本例中定义了两个key:webredis。因此 Docker Compose 会部署两个容器,一个容器的名字中会包含 web,而另一个会包含 redis

5.2.1 web

web 的服务定义中,包含如下指令:

  • build:. 指定 Docker 基于当前目录 . 下 Dockerfile 来构建一个新镜像。该镜像会被用于启动该服务的容器。

  • command:python app.py 指定 Docker 在容器中执行名为 app.py 的 Python 脚本作为主程序。因此镜像中必须包含 app.py 文件以及 Python,这一点在 Dockerfile 中可以得到满足。

  • ports:指定 Docker 将容器内(-target)的5000端口映射到宿主机(published)的5000 端口。这意味着发送到宿主机 5000 端口的流量会被转发到容器的 5000 端口。容器中的应用监听端口 5000。

  • networks:使得 Docker 可以将服务连接到指定的网络上。这个网络应该是已经存在的,或者是在 networks 一级key中定义的网络。对于 Overlay 网络来说,它还需要定义一个 attachable 标志,这样独立的容器才可以连接上它。

  • volumes:指定 Docker 将 counter-vol 数据卷(source:)挂载到容器内的 /code(target:)。counter-vol 数据卷应该是已存在的,或者是在文件下方的 volumes 一级key中定义的。

综上,Docker Compose 会调用 Docker 来为 web-fe 服务部署一个独立的容器。该容器基于与 Compose 文件位于同一目录下的 Dockerfile 构建的镜像。基于该镜像启动的容器会运行 app.py 作为其主程序,将 5000 端口暴露给宿主机,连接到 counter-net 网络上,并挂载一个卷到 /code

5.2.2 redis

redis 服务的定义相对比较简单:

  • image: redis:alpine 使得Docker可以基于 redis:alpine 镜像启动一个独立的名为redis 的容器。这个镜像会被从 Docker Hub 上拉取下来。

  • networks:配置 redis 容器连接到 counter-net 网络。

由于两个服务都连接到 counter-net 网络,因此它们可以通过名称解析到对方的地址。了解这一点很重要,本例中上层应用被配置为通过名称与 Redis 服务通信。

5.3 networks

networks 用于指引 Docker 创建新的网络。默认情况下,Docker Compose 会创建 bridge 网络。这是一种单主机网络,只能够实现同一主机上容器的连接。当然,也可以使用 driver 属性来指定不同的网络类型。

下面的代码可以用来创建一个名为over-net的Overlay网络,允许独立的容器(standalone container)连接(attachable)到该网络上:

networks:  
    over-net:  
    driver: overlay  
    attachable: true

5.4 volumes

volumes 用于指引 Docker 来创建新的数据卷。

6. 命令

6.1 创建并启动服务

可以使用 docker-compose up 命令来创建并启动服务:用于创建、启动以及重新启动docker-compose.yml文件中定义的服务。命令格式如下所示:

docker compose up [OPTIONS] [SERVICE...]

默认情况下当命令退出时,所有容器都会停止:

smartsi@localhost counter-app % docker compose up
[+] Running 1/0
 ✔ Network counter-app_default    Created                                                                                                             0.0s
 ⠋ Container counter-app-web-1    Created                                                                                                             0.0s
 ⠋ Container counter-app-redis-1  Created                                                                                                             0.0s
Attaching to redis-1, web-1
redis-1  | 1:C 03 May 2024 03:33:39.706 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis-1  | 1:C 03 May 2024 03:33:39.706 # Redis version=6.2.6, bits=64, commit=00000000, modified=0, pid=1, just started
redis-1  | 1:C 03 May 2024 03:33:39.706 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
redis-1  | 1:M 03 May 2024 03:33:39.707 * monotonic clock: POSIX clock_gettime
redis-1  | 1:M 03 May 2024 03:33:39.707 * Running mode=standalone, port=6379.
redis-1  | 1:M 03 May 2024 03:33:39.707 # Server initialized
redis-1  | 1:M 03 May 2024 03:33:39.709 * Ready to accept connections
web-1    |  * Serving Flask app 'app.py'
web-1    |  * Debug mode: on
web-1    | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
web-1    |  * Running on all addresses (0.0.0.0)
web-1    |  * Running on http://127.0.0.1:5000
web-1    |  * Running on http://172.22.0.3:5000
web-1    | Press CTRL+C to quit
web-1    |  * Restarting with stat
web-1    |  * Debugger is active!
web-1    |  * Debugger PIN: 679-338-443
  Gracefully stopping... (press Ctrl+C again to force)
[+] Stopping 2/2
 ✔ Container counter-app-web-1    Stopped                                                                                                             0.1s
 ✔ Container counter-app-redis-1  Stopped                                                                                                             0.2s
canceled

可以使用 -d--detach 选项以后台模式启动应用程序,使得应用程序在后台运行,不会阻塞命令行:

smartsi@localhost counter-app % docker compose up -d
[+] Running 3/3
 ✔ Network counter-app_default    Created                                                                                                             0.0s
 ✔ Container counter-app-redis-1  Started                                                                                                             0.0s
 ✔ Container counter-app-web-1    Started

默认情况下会创建并启动docker-compose.yml中定义的所有服务。也可以通过指定一个或多个服务名称来仅创建并启动docker-compose.yml定义中的部分服务及它们依赖的服务:

smartsi@localhost counter-app % docker compose up web redis -d
[+] Running 3/3
 ✔ Network counter-app_default    Created                                                                                                             0.0s
 ✔ Container counter-app-web-1    Started                                                                                                             0.0s
 ✔ Container counter-app-redis-1  Started

默认情况下读取的是 docker-compose.yml 文件,你也可以使用 -f 选项可以指定要使用的其他 Compose 文件:

docker compose up -f docker-compose-prod.yml

如果所有服务的日志太多,只想关注特定服务,可以使用 --attach 选项帮助用户关注特定的服务。假设你的docker-compose.yml包含三个服务:webredis,如果你只对redis服务的输出感兴趣,可以这样使用:

smartsi@localhost counter-app % docker compose up --attach redis
[+] Running 1/0
 ✔ Network counter-app_default    Created                                                                                                             0.0s
 ⠋ Container counter-app-redis-1  Created                                                                                                             0.0s
 ⠋ Container counter-app-web-1    Created                                                                                                             0.0s
Attaching to redis-1
redis-1  | 1:C 03 May 2024 03:38:49.249 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis-1  | 1:C 03 May 2024 03:38:49.250 # Redis version=6.2.6, bits=64, commit=00000000, modified=0, pid=1, just started
redis-1  | 1:C 03 May 2024 03:38:49.250 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
redis-1  | 1:M 03 May 2024 03:38:49.250 * monotonic clock: POSIX clock_gettime
redis-1  | 1:M 03 May 2024 03:38:49.250 * Running mode=standalone, port=6379.
redis-1  | 1:M 03 May 2024 03:38:49.250 # Server initialized
redis-1  | 1:M 03 May 2024 03:38:49.251 * Ready to accept connections

这个命令将会启动所有服务,但只将redis服务的日志输出到控制台。这对于调试redis服务非常有用,而不被其他服务可能产生的日志所干扰。需要注意的不能与--detach选项结合使用。

除此之外,还支持一些其他的可选选项:

选项用途
--force-recreate通过重新创建容器来强制重新启动服务,即使它们已经存在(配置和镜像没有变化)。该选项不会影响已持久化的数据卷。
--no-recreate如果服务容器已经存在,则不重新创建。使用这个选项可以避免通过重新创建容器来应用配置的更新。
--build在启动服务之前,强制构建服务镜像,即使镜像已存在。
--no-build启动服务时跳过构建步骤,即使docker-compose.yml文件指定了构建指令。
--abort-on-container-exit默认情况下,即使一个服务容器停止,其他服务容器仍会继续运行。使用该选项时,如果任何一个容器退出,所有其他容器将会停止。与 -d 选项不兼容
--abort-on-container-failure默认情况下,即使一个服务容器失败(退出状态非零),其他服务容器仍会继续运行。使用该选项时,如果任何一个容器失败,所有其他容器将会被停止。与 -d 选项不兼容
--remove-orphans移除由 docker-compose.yml 文件定义以外的容器。这些容器可能是旧的或由以前的配置文件创建的。
--quiet-pull拉取镜像时不显示进度信息。
--no-deps不启动服务的依赖容器。这在某些情况下很有用,比如当你想单独启动一个服务进行调试时。
--attach-dependencies当你主要关注某个特定服务,但同时也需要了解它所依赖的服务的状态或输出信息。例如,如果你有一个web应用服务依赖于数据库和缓存服务,而你想启动web服务并同时跟踪数据库和缓存服务的日志,该选项就会非常有用

6.2 停止并删除服务

可以使用 docker-compose down 命令来停止并移除由 docker-compose up 创建并启动的所有服务。这个命令不仅处理容器,而且默认情况下也会移除由 docker-compose.yml 文件定义的网络(不包括外部网络)。如果使用相应的选项,它还可以移除数据卷和镜像。指令格式如下所示:

docker compose down [OPTIONS] [SERVICES]

默认情况下会停止并删除docker-compose.yml中定义的所有服务:

smartsi@localhost counter-app % docker compose down
[+] Running 3/3
 ✔ Container counter-app-redis-1  Removed                                                                                         0.2s
 ✔ Container counter-app-web-1    Removed                                                                                         0.1s
 ✔ Network counter-app_default    Removed

可以通过指定一个或多个服务名称来仅停止删除docker-compose.yml定义中的部分服务:

smartsi@localhost counter-app % docker compose down web redis
[+] Running 3/3
 ✔ Container counter-app-redis-1  Removed                                                                                         0.2s
 ✔ Container counter-app-web-1    Removed                                                                                         0.1s
 ✔ Network counter-app_default    Removed

默认情况下不会删除数据卷,可以使用 --volumes-v 选项来删除所有由服务定义的数据卷(包括匿名卷),但不包括通过 external 标记的外部数据卷:

docker-compose down --volumes

可以使用 --rmi type 来移除由 docker-compose.yml 文件定义的镜像。type 可以是 all(移除所有镜像),或者local(仅移除未在 Docker Hub 上标记的镜像):

docker-compose down --rmi all

可以使用 --remove-orphans 来移除由 docker-compose.yml 文件定义以外的容器。如果你之前更改了文件内容,新增或删除了服务,这个选项能帮助清理那些不再属于 Compose 配置文件的 “孤立” 容器:

docker-compose down --remove-orphans

6.3 构建服务镜像

可以使用 docker-compose build 命令构建服务镜像。命令格式如下所示:

docker compose build [OPTIONS] [SERVICE...]

该命令基于docker-compose.yml文件中的服务定义构建或重新构建服务的镜像。这个命令非常实用,尤其是在开发流程中,当你需要更新或者创建新的服务镜像时。它会根据服务配置中指定的Dockerfile和上下文来构建镜像。

默认情况下会构建 docker-compose.yml 文件中定义的所有服务的镜像。可以通过指定一个或多个服务名称来构建docker-compose.yml定义中的部分服务:

smartsi@localhost counter-app % docker compose build web redis
[+] Building 16.1s (13/13) FINISHED                                                                                                   docker:desktop-linux
 => [web internal] load build definition from Dockerfile                                                                                              0.0s
 => => transferring dockerfile: 332B                                                                                                                  0.0s
 => [web] resolve image config for docker-image://docker.io/docker/dockerfile:1                                                                      15.6s
 => CACHED [web] docker-image://docker.io/docker/dockerfile:1@sha256:42399d4635eddd7a9b8a24be879d2f9a930d0ed040a61324cfdf59ef1357b3b2                 0.0s
 => [web internal] load .dockerignore                                                                                                                 0.0s
 => => transferring context: 2B                                                                                                                       0.0s
 => [web internal] load metadata for docker.io/library/python:3.10-alpine                                                                             0.4s
 => [web 1/6] FROM docker.io/library/python:3.10-alpine@sha256:dce56d40d885d2c8847aa2a278a29d50450c8e3d10f9d7ffeb2f38dcc1eb0ea4                       0.0s
 => [web internal] load build context                                                                                                                 0.0s
 => => transferring context: 4.44kB                                                                                                                   0.0s
 => CACHED [web 2/6] WORKDIR /code                                                                                                                    0.0s
 => CACHED [web 3/6] RUN apk add --no-cache gcc musl-dev linux-headers                                                                                0.0s
 => CACHED [web 4/6] COPY requirements.txt requirements.txt                                                                                           0.0s
 => CACHED [web 5/6] RUN pip install -r requirements.txt                                                                                              0.0s
 => CACHED [web 6/6] COPY . .                                                                                                                         0.0s
 => [web] exporting to image                                                                                                                          0.0s
 => => exporting layers                                                                                                                               0.0s
 => => writing image sha256:5f239ff94979c90a9288c2ed66d63cb1b00ffd85bd8aaecec86af58c470630cd                                                          0.0s
 => => naming to docker.io/library/counter-app-web

除此之外,还支持一些其他的可选选项:

选项用途
--no-cache构建镜像时不使用缓存。这确保了所有的步骤都会重新执行,用于解决某些缓存相关的问题,或确保获取最新的基础镜像。
--build-arg ARG=value设置构建时的变量,这些变量在构建过程中是可用的,经常用来传递版本号、构建时间等信息。
-m, --memory设置构建过程中容器的内存限制。
--pull总是尝试通过拉取新的版本来更新更新的基础镜像。

6.4 查看 Compose 项目

可以使用 docker compose ls 命令列出与 Compose 项目关联的容器的状态。命令格式如下所示:

docker compose ls [OPTIONS]

如下所示列出所有活跃服务项目:

smartsi@localhost counter-app % docker compose ls
NAME                STATUS              CONFIG FILES
counter-app         running(2)          /opt/workspace/counter-app/compose.yaml

可以使用 --format 选项来指定输出的格式。常见的值包括prettyjson,其中pretty提供了易于阅读的格式,而json则提供了方便程序处理的JSON格式。默认提供 pretty 格式:

docker compose ls --format pretty
docker compose ls --format json

默认只展示活跃的项目,可以使用--all-a 选项显示所有的 Compose 项目,包括那些当前没有运行任何容器的项目:

docker compose ls --all

6.5 服务容器中执行命令

可以使用 docker compose exec 命令在运行的服务容器中执行命令。命令格式如下所示:

docker compose exec [OPTIONS] SERVICE COMMAND [ARGS...]

这在许多情形下非常有用,比如当你需要进入容器内部进行调试、查看容器内的文件结构、手动启动某些进程或执行数据库迁移等操作时。

假设你有一个名为redis的服务,你想进入这个服务的容器内部的 Redis 命令行终端:

smartsi@localhost counter-app % docker compose exec redis redis-cli
127.0.0.1:6379> get hits
"4"
127.0.0.1:6379>

假设你有一个名为web的服务,查看服务容器的 /code 目录下的文件和文件夹:

smartsi@localhost counter-app % docker compose exec web ls /code -al
total 28
drwxr-xr-x    1 root     root          4096 May  3 05:29 .
drwxr-xr-x    1 root     root          4096 May  3 05:29 ..
-rw-r--r--    1 root     root           293 May  2 14:16 Dockerfile
drwxr-xr-x    2 root     root          4096 May  3 05:29 __pycache__
-rw-r--r--    1 root     root           514 May  2 14:00 app.py
-rw-r--r--    1 root     root            96 May  2 14:20 compose.yaml
-rw-r--r--    1 root     root            12 May  2 23:57 requirements.txt

除此之外,还支持一些其他的可选选项:

选项用途
-d, --detach在分离模式下运行,即在后台运行命令
-e, --env设置环境变量(例:-e KEY=VALUE
-T禁用伪终端分配。这在你不需要交互式命令时很有用,比如自动化脚本的执行
-u, --user以指定用户身份执行命令,而不是默认的root用户
--index当服务扩展为多个实例时,指定要执行命令的实例索引

6.6 查看服务日志

可以使用 docker compose logs查看服务的输出日志。命令格式如下所示:

docker compose logs [OPTIONS] [SERVICE...]

允许开发人员和运维人员查看和跟踪服务容器的日志。这对于调试容器应用、监视容器行为以及理解容器运行时发生了什么特别有用。如果你希望查看所有服务的日志,简单地运行:

smartsi@localhost counter-app % docker compose logs
web-1  |  * Serving Flask app 'app.py'
web-1  |  * Debug mode: on
web-1  | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
web-1  |  * Running on all addresses (0.0.0.0)
web-1  |  * Running on http://127.0.0.1:5000
web-1  |  * Running on http://172.27.0.3:5000
web-1  | Press CTRL+C to quit
web-1  |  * Restarting with stat
web-1  |  * Debugger is active!
web-1  |  * Debugger PIN: 583-098-631
redis-1  | 1:C 03 May 2024 04:15:54.805 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis-1  | 1:C 03 May 2024 04:15:54.805 # Redis version=6.2.6, bits=64, commit=00000000, modified=0, pid=1, just started
redis-1  | 1:C 03 May 2024 04:15:54.805 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
redis-1  | 1:M 03 May 2024 04:15:54.805 * monotonic clock: POSIX clock_gettime
redis-1  | 1:M 03 May 2024 04:15:54.805 * Running mode=standalone, port=6379.
redis-1  | 1:M 03 May 2024 04:15:54.805 # Server initialized
redis-1  | 1:M 03 May 2024 04:15:54.806 * Ready to accept connections

如果想要实时查看一个或几个指定服务的日志,可以结合使用-f(或--follow)选项和服务名称,如下所示实时查看 web 服务的实时日志:

smartsi@localhost counter-app % docker compose logs -f web
web-1  |  * Serving Flask app 'app.py'
web-1  |  * Debug mode: on
web-1  | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
web-1  |  * Running on all addresses (0.0.0.0)
web-1  |  * Running on http://127.0.0.1:5000
web-1  |  * Running on http://172.27.0.3:5000
web-1  | Press CTRL+C to quit
web-1  |  * Restarting with stat
web-1  |  * Debugger is active!
web-1  |  * Debugger PIN: 583-098-631
web-1  | 192.168.65.1 - - [03/May/2024 05:05:13] "GET / HTTP/1.1" 200 -
web-1  | 192.168.65.1 - - [03/May/2024 05:05:13] "GET / HTTP/1.1" 200 -

如果你只对查看最近的日志感兴趣,可以使用-n 或者 --tail选项:

smartsi@localhost counter-app % docker compose logs --tail=4
web-1    | 192.168.65.1 - - [03/May/2024 05:05:14] "GET / HTTP/1.1" 200 -
web-1    | 192.168.65.1 - - [03/May/2024 05:05:21] "GET / HTTP/1.1" 200 -
redis-1  | 1:M 03 May 2024 04:15:54.805 * monotonic clock: POSIX clock_gettime
redis-1  | 1:M 03 May 2024 04:15:54.805 * Running mode=standalone, port=6379.
redis-1  | 1:M 03 May 2024 04:15:54.805 # Server initialized
web-1    | 192.168.65.1 - - [03/May/2024 05:05:33] "GET / HTTP/1.1" 200 -
web-1    | 192.168.65.1 - - [03/May/2024 05:06:01] "GET / HTTP/1.1" 200 -
redis-1  | 1:M 03 May 2024 04:15:54.806 * Ready to accept connections

6.7 启动服务

可以使用 docker compose start 命令用于启动一个或多个已经停止的服务。命令格式如下所示:

docker compose start [SERVICE...]

值得注意的是,在使用docker compose start之前,服务应已通过docker compose up命令创建,只是处于停止状态。这一命令的主要用途是重新启动那些之前被停止的服务,而不是重新创建或重建服务的容器。

默认情况下命令尝试启动所有由当前目录下的docker-compose.yml文件定义的服务。可以指定你希望启动的一个或多个服务的名称来启动指定服务:

smartsi@localhost counter-app % docker compose start redis web
[+] Running 2/2
 ✔ Container counter-app-redis-1  Started                                                                                                             0.1s
 ✔ Container counter-app-web-1    Started
  • docker compose start命令不会构建或重建服务的镜像。如果需要更新或构建服务的镜像,请使用docker compose up命令并配合--build选项。
  • docker compose start操作仅限于启动服务容器,不会重新应用配置变化。如果你修改了docker-compose.yml文件,想要这些修改生效,通常需要使用docker compose up命令。

6.8 停止服务

可以使用 docker-compose stop 命令用来停止一个或多个正在运行的服务。命令格式如下所示:

docker compose stop [OPTIONS] [SERVICE...]

这个命令非常有用,因为它允许你在不删除服务容器的情况下停止服务,这意味着你可以在之后随时使用docker compose start命令重新启动它们。

默认情况下命令会停止所有由当前目录下的docker-compose.yml文件定义的服务。可以指定你希望停止的一个或多个服务的名称来停止指定服务:

smartsi@localhost counter-app % docker compose stop redis web
[+] Stopping 2/2
 ✔ Container counter-app-web-1    Stopped                                                                                                             0.2s
 ✔ Container counter-app-redis-1  Stopped

6.9 重启服务

可以使用 docker-compose restart 命令来重启一个或多个正在运行的服务容器。命令格式如下所示:

docker compose restart [OPTIONS] [SERVICE...]

这对于开发阶段特别有用,当你对应用或环境进行了更新并希望快速重新加载服务时,可以使用此命令。它比分别执行停止(stop)和启动(start)操作要简单得多,简化了重新启动服务的流程。自动执行了停止和启动操作,无需单独执行这两个步骤。可以理解为这是docker-compose stopdocker-compose start的一个便捷组合。

默认情况下命令会重启所有由当前目录下的docker-compose.yml文件定义的服务。可以指定你希望重启的一个或多个服务的名称来重启指定服务:

smartsi@localhost counter-app % docker compose restart redis web
[+] Restarting 2/2
 ✔ Container counter-app-redis-1  Started                                                                                                             0.3s
 ✔ Container counter-app-web-1    Started

对于那些想要更新服务镜像的场景,你需要先构建新的镜像,然后重新启动服务。

6.10 移除停止状态的服务

可以使用 docker-compose rm 命令移除停止状态的服务。命令格式如下所示:

docker compose rm [OPTIONS] [SERVICE...]

在不再需要某些服务或想要重置服务状态时,可以通过移除容器来实现。这对于开发环境的清理或者测试新配置时非常有用,因为你可以快速地移除旧容器,然后用docker compose up命令重新创建并启动新容器。

这个命令常常与docker-compose stop配合使用,以清除不再需要的容器:

smartsi@localhost counter-app % docker compose stop
[+] Stopping 2/2
 ✔ Container counter-app-redis-1  Stopped                                                                                         0.1s
 ✔ Container counter-app-web-1    Stopped                                                                                         0.2s
smartsi@localhost counter-app %
smartsi@localhost counter-app % docker compose rm
? Going to remove counter-app-web-1, counter-app-redis-1 Yes
[+] Removing 2/0
 ✔ Container counter-app-redis-1  Removed                                                                                         0.0s
 ✔ Container counter-app-web-1    Removed

默认情况下命令会移除所有由当前目录下的docker-compose.yml文件定义的停止状态的服务。可以指定你希望移除的一个或多个服务的名称来移除指定服务:

smartsi@localhost counter-app % docker compose stop
[+] Stopping 2/2
 ✔ Container counter-app-web-1    Stopped                                                                                                             0.2s
 ✔ Container counter-app-redis-1  Stopped                                                                                                             0.2s
smartsi@localhost counter-app %
smartsi@localhost counter-app % docker compose rm redis web
? Going to remove counter-app-redis-1, counter-app-web-1 Yes
[+] Removing 2/0
 ✔ Container counter-app-web-1    Removed                                                                                                             0.0s
 ✔ Container counter-app-redis-1  Removed                                                                                                             0.0s
smartsi@localhost counter-app %

7. 实践

7.1 环境准备

首先为项目创建一个目录,在我们的工作目录 /opt/workspace下创建一个名为 counter-app 的目录 :

smartsi@localhost workspace % mkdir counter-app
smartsi@localhost workspace % cd counter-app

在项目目录中创建一个名为 app.py 的应用程序文件(一个 Python Flask 应用):

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 exc:
            if retries == 0:
                raise exc
            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)

在这个例子中,redis 是应用程序网络上的 redis 容器的主机名,使用默认端口 6379。

在项目目录中继续创建另一个名为 requirements.txt 的文件,该文件列出了 Python 应用所依赖的 Python 包:

flask
redis

在项目目录中继续创建一个 Dockerfile,定义了如何构建 web 服务所使用的镜像:

# syntax=docker/dockerfile:1
FROM python:3.10-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run", "--debug"]

简单介绍一些 Dockerfile 中的指令:

  • FROM 指令表示使用 python:3.10-alpine 镜像作为基础镜像来构建一个镜像

  • WORKDIR 指令表将工作目录设置为 /code

  • ENV 指令表示设置 flask 命令使用的环境变量 FLASK_APPFLASK_RUN_HOST

  • 第一个 RUN 指令表示需要安装 gcc 以及其他依赖项

  • 第一个 COPY 指令表示复制 requirements.txt 到容器中

  • 第二个 RUN 指令表示安装 requirements.txt 文件中的 Python 依赖项

  • EXPOSE 指令表示向镜像添加元数据,以描述容器正在侦听端口 5000

  • 第二个 COPY 指令复制当前目录 . 到镜像中工作目录.

  • CMD 指令表示将容器的默认命令设置为 flask run --debug

Dockerfile 指令详细介绍请查阅 Docker 实战:通过 Dockerfile 构建镜像

7.2 创建 Compose 文件

Compose 简化了对整个应用程序堆栈的控制,使得在一个易于理解的 YAML 配置文件中轻松管理服务、网络和数据卷。如下创建一个名为 compose.yaml 的简单文件,定义 Docker 如何部署应用:

services:
  web:
    build: .
    ports:
      - "8000:5000"
  redis:
    image: "redis:alpine"

这个 Compose 文件定义了两个服务: web 和 redis。web 服务使用根据当前目录中Dockerfile 构建的映像。然后,指定 Docker 将容器内的 5000 端口映射到宿主机的 8000 端口。redis 服务使用从 Docker Hub 拉取的官方 redis 镜像。

7.3 使用Compose构建并运行应用程序

通过一个命令就可以从配置文件创建并启动所有服务。在项目目录中,通过运行 docker compose up 启动应用程序:

smartsi@localhost counter-app % docker compose up -d
[+] Running 3/3
 ✔ Network counter-app_default    Created                                                                                                             0.0s
 ✔ Container counter-app-redis-1  Started                                                                                                             0.0s
 ✔ Container counter-app-web-1    Started

Compose 拉取一个 Redis 镜像,为你的代码构建一个镜像,并启动你定义的服务。在这种情况下,代码在构建时被静态地复制到镜像中。在浏览器中输入 http://localhost:8000/ 查看应用程序的运行情况。如果这不能解决,您也可以尝试 http://127.0.0.1:8000。您应该在浏览器中看到一条消息:

Hello World! I have been seen 1 times.

然后刷新页面,数字会增加:

Hello World! I have been seen 2 times.

切换到另一个终端窗口,输入 docker image ls 列出本地镜像。此时列出的镜像应该包含 redis 和 web:

smartsi@localhost counter-app % docker image ls
REPOSITORY        TAG       IMAGE ID       CREATED        SIZE
counter-app-web   latest    5f239ff94979   6 hours ago    177MB
redis             alpine    5d44f444e409   2 years ago    32.4MB

你可以使用 docker inspect <tag or id> 来详细查看镜像。最后停止应用程序,可以在第二个终端的项目目录下运行 docker compose,或者在启动应用程序的原始终端中按 CTRL+C

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@SmartSi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值