编程语言研究书库

第 9 章拆解(下)— 编排:Docker Swarm 与 Kubernetes

编排:Docker Swarm 与 Kubernetes

上篇把应用装进了集装箱;这一篇把集装箱装上船。 先讲 Docker Swarm ——配置格式和你刚学过的 Compose 是同一份规格,新增的概念一只手数得过来; 再讲 Kubernetes——Google Borg 的公开后裔,概念多一个量级,但核心思想没变: 描述期望状态,让系统持续对账。 主线例子:同一份工单系统,先在 三管理两工作的 Swarm 上跑起来,再被 Kompose 翻译成 20 个 K8s 配置文件。

1. 顶层全景

  Docker Swarm(K8s 的小弟弟)
    起集群:Multipass 开 VM → swarm init → join-token 逐台加入
      四个新概念:manager/worker、overlay 网络、secrets、deploy 块
        stack 文件 ≈ compose 文件 + deploy/secrets/网络加密
  Kubernetes(Borg 血统的船长)
    三级架构:Cluster(控制平面) → Nodes → Pods
      两类工作负载:Deployment(无状态) / StatefulSet(有状态,数据库)
        Kompose 转换 → Kind 建集群 → kubectl 四板斧
  不变的主线:期望状态 + 持续对账(reconcile)

  图说:台阶从小弟弟到大船,工具复杂度翻倍,思想一行没换。

2. Docker Swarm:小弟弟上场

定位一句话: 「Kubernetes 的小弟弟——提供类似服务,规模更小」; 配置格式与 Compose 遵循同一份规范,用法有些差异1。

先把集群立起来(Multipass 路线): Swarm 模式内置于 Docker Engine, 但威力要多引擎组网才释放,所以需要多台 VM 当节点。Ubuntu 的 Multipass 一条命令开 VM:multipass launch docker --name mgr1——docker 是预置模板, VM 里 Docker 已装好;每台至少 4 GB 内存。开三台 manager(mgr1/2/3)+ 两台 worker,然后:

docker swarm init                          # 在 mgr1 里初始化
docker swarm join-token manager            # 打印加入命令(带 SWMTKN 令牌)
docker swarm join --token SWMTKN-1-… 172.24.19.65:2377   # 在别的 VM 里逐台执行

2

红字级别的差异:Swarm 不构建镜像。 Compose 能顺手 build,Swarm 只从 registry 拉预构建的镜像——「所以务必先把镜像构建发布好」3。

2.1 四个新概念

① 集群、管理者与工人(clusters, managers, workers): Swarm = 可组网实现编排的 Docker Engine 集群;节点分两种角色—— manager 负责监督与期望状态对账,worker 负责扛容器。 两条最佳实践:manager 上不部署容器(职责分离); manager 数量取奇数、至少 3——分区容错时永远有一边节点多, 多数派显而易见,该谁接管 supervisor 职责没有争议4。

② 网络(networks): 真实环境里不能假设大家在一个网——为了安全, 默认互相隔离,谁能访问谁要显式声明;配置里不写网络,组件之间就默认不通。 Swarm 用 overlay 驱动(跨主机虚拟网络),还能开加密:

networks:
  ticketing-net:
    driver: overlay
    driver_opts:
      encrypted: 'yes'

5

③ Secrets(机密): compose 时代密码走 env_file;Swarm 给了正经机制—— docker secret create 创建后,配置文件里 secrets: [mariadb_password] 引用, 容器内以文件形式出现在 /run/secrets/<名字>, 环境变量写成 MARIADB_PASSWORD_FILE: /run/secrets/mariadb_password。 密码不再以环境变量的形态躺在进程表里6。

④ deploy 块(每个服务的调度策略):

deploy:
  replicas: 1                     # 期望实例数
  placement:
    constraints: ['node.role == worker']   # 只落在工人节点
  update_config:
    parallelism: 1                # 一次更新几个实例
    delay: 10s
    failure_action: rollback      # 更新失败自动回滚
  restart_policy:
    condition: on-failure
    max_attempts: 3
    delay: 5s
    window: 120s

7

2.2 七服务的 Swarm 版与 compose 版的差异

同一份全家桶,Swarm 版相对 compose 版只改了四类地方:8

差异compose 版Swarm 版
密码env_file 整文件注入secrets 文件挂载
调度restart: always 一个键完整 deploy 块(placement/update/restart)
网络隐式默认网络显式 overlay 加密网络,每服务 networks: [ticketing-net]
卷直接引用顶层 volumes: 先声明命名卷再引用

后端的 environment 在 Swarm 版里最壮观:十几行环境变量把前面八章的配置 全部显式化(SQLX_OFFLINE=1、MAX_BODY_LIMIT=5、BUCKET_NAME=…), secrets 四个(JWT/mariadb/postgres/smtp)9。这个文件是「架构即配置」的 最佳标本:读它等于重读全书。

3. Kubernetes:大船船长

来历: Google 的私有集群管理器 Borg 练出的经验,开源后用 Go 重写, 名字是希腊语「舵手」——像巨型货轮的船长,指挥成百上千的容器10。

它能干什么(书里列的七项): 服务发现(内建 DNS,按名字找、不管 IP)、 负载均衡、存储编排(对接云存储、按期望状态自动供给)、 自动发布与回滚、自愈(检出故障组件、杀掉、按策略重启)、 secret 与配置管理(声明式配置、secret 可安全轮换不停机)、水平伸缩 (一条命令、预定义逻辑或 UI)11。

3.1 三级架构与四种工作负载

架构骨架: Cluster(被管理的隔离环境,期望状态被持续观察、对账)→ Control Plane(控制集群组件、暴露 API)→ Nodes(跑 Pod 的物理机/VM, 生命周期被托管、可互相分担)→ Pod(容器的包装,最小部署单元; 一 Pod 可含多容器,惯例是一 Pod 一容器)12。

工作负载(「一个运行中的应用」的四种种法):

工作负载适用
Deployment(+ReplicaSet)无状态、可替换的应用——我们的前后端
StatefulSet有状态、换实例后仍要在同一端点——数据库(MariaDB/Postgres/Redis 在 K8s 里都该是 StatefulSet)
DaemonSet节点本地的常驻驱动型程序(日志收集之类)
Job跑完就停的一次性任务

配套设施: Service(把 Pod 暴露给集群外)、StorageClass + PV + PVC (动态供给存储的三件套)、Secrets、Ingress/负载均衡13。

3.2 从 Swarm 到 K8s:Kompose 一键翻译

手写 20 个 YAML 太劝退——官方工具 Kompose 干这个: kompose convert -f stack.yml 一把生成全套文件。 概念全都认识:每个组件拆成 deployment + service,密码进 secret 文件, 存储进 PVC 文件。书里给了完整的 20 个文件清单,并点出两个例外:14

  • 存储要手工补:并非所有 Compose 特性都能自动翻译;
  • secret 文件里的 base64 不是加密——「这些文件依旧不许进版本库; 更好是动态生成,或最后一刻注入;仓库里只放可注入的样例文件」。 (这句和第 7 章「base64 是编码不是加密」遥相呼应。)

3.3 Kind 建集群、Kubectl 四板斧

本地跑 K8s 三选一:Docker Desktop 勾个框、Kind(为测试 K8s 而生, 节点跑成 Docker 容器)、Minikube(最接近真集群的体验)。 书里选 Kind,集群定义文件长这样:一个 control-plane + 两个 worker, extraPortMappings 把宿主端口透进来,extraMounts 把宿主目录挂给 worker(建卷和读初始化脚本用)15:

kind create cluster --config=kind-cluster-config.yml --name wslkind
kubectl cluster-info --context kind-wslkind    # 验活:控制平面与 CoreDNS 的地址
kubectl apply -f mariadb-password-secret.yaml  # 逐个应用配置(顺序:基建先行)
kubectl get all        # 全览:pods/services/deployments/replicasets/statefulsets

get all 的输出值得读一次:READY 列是「实际/期望」实例数, STATUS 里 CrashLoopBackOff = 持续失败的雅称; service 列表里能看到 ClusterIP(集群内)与 NodePort(对外)两种类型16。

排障三板斧(比 get 多两板): kubectl describe <资源>(详情与事件)、 kubectl logs <资源>(日志;容器被杀过加 --previous 看上一轮)。 顺手的贴士:给 kubectl 起别名 k17。

收尾的实话: 后端通过 kubectl proxy 能访问到(那条长长的 /api/v1/namespaces/default/services/backend:8000/proxy/login); 但前端对路径敏感,受不了这种长 URL——「要配 Ingress controller 或 负载均衡,超出本章范围」18。

4. 主线例子走一遍:一套系统,两种船

  路线 A(Swarm):
  multipass 开 5 台 VM → mgr1 上 swarm init → join-token 拉进其余 4 台
      → docker secret create × 4 → docker stack deploy -c stack.yml
      → 七服务落在 worker 节点,manager 只管对账
  路线 B(Kubernetes):
  kompose convert 把同一份 stack.yml 翻成 20 个 YAML
      → kind create cluster(1 控制面 + 2 工人)
      → kubectl apply 逐个文件(先基建后应用)
      → kubectl get all:5 个 Pod 全 Running,mariadb/postgres/redis 是 StatefulSet
      → kubectl proxy 打开登录页
  ——两条路线,同一个思想:把期望状态写下来,让系统去对账。

  图说:工具从 stack.yml 换到 20 个 YAML,复杂度涨了,但「读配置即读架构」不变。
  (节点数量、文件数量出自原书示例。)

5. 作者的判断与证据(分开标)

有出处的: Swarm 只拉不构建、奇数 manager 的多数派理由、overlay 默认隔离、 K8s 七特性清单、Kompose 的两处例外、base64≠加密,均为原书原文3451114。

作者自己的评估:

  • 「Swarm 是 K8s 的小弟弟」「K8s 超出本章范围只讲基础」是篇幅取舍;
  • 部署顺序「基建先行、后端其次、前端最后」是对依赖拓扑的经验判断19;
  • 12 篇那个 YAGNI 判断块在这里依然生效:多数团队到 Compose/Swarm 就该停。

6. 边界与局限

  • 点到为止: Swarm 的滚动更新零停机、K8s 的 Ingress/Helm/Operator,全是 「知道名字、会查文档」的粒度;
  • 本地集群的坑: Kind 的端口映射和挂载要手工声明;前端在 proxy 长 URL 下 不能工作,书里如实承认18;
  • 数据库上 K8s: 书里把 MariaDB/Postgres/Redis 都写成 StatefulSet 是对的, 但生产要不要在 K8s 里养数据库,业界至今争论——托管数据库服务往往是更省心的答案。

7. 可带走的

  1. Swarm = Compose 同规格 + 四个新词:角色(manger/worker)、网络(overlay+加密)、 secrets(文件挂载)、deploy(调度策略)。
  2. manager 取奇数至少 3: 分区时多数派即正统;manager 上不跑容器。
  3. Swarm 不构建镜像——先 build、push,再 deploy。
  4. K8s 三级架构:Cluster → Node → Pod; Pod 是最小部署单位,惯例一 Pod 一容器。
  5. 无状态用 Deployment,有状态用 StatefulSet; 数据库属于后者。
  6. Kompose 能翻译 Swarm 配置到 K8s, 但存储要手补、secret 文件不进版本库。
  7. kubectl 四板斧: get all 看全景、describe 看事件、logs 看日志 (--previous 看上一轮)、apply 发配置。
  8. 期望状态 + 持续对账,是两个编排器共同的心跳; 学会了读配置,就学会了读架构。

8. 原文地图

主题原书章原文位置
Swarm 定位与同规格Containerization and Orchestrationtext/75-fm-docker-swarm.txt:4(搜「little brother」)、:7(搜「same specification」)
Multipass 起 VM 与 join同上text/75-fm-docker-swarm.txt:19(搜「multipass launch」)、:34(搜「swarm init」)、:46(搜「join --token」)
「只拉不构建」同上text/75-fm-docker-swarm.txt:77(搜「will not build images」)
manager/worker 与奇数原则同上text/75-fm-docker-swarm.txt:88(搜「supervise」)、:98(搜「odd number」)
overlay 网络默认隔离同上text/75-fm-docker-swarm.txt:109(搜「no access by default」)、:128(搜「encrypted」)
secrets 与 _FILE 变量同上text/75-fm-docker-swarm.txt:167(搜「PASSWORD_FILE」)、:182(搜「secrets」)
deploy 块四键同上text/75-fm-docker-swarm.txt:191(搜「replicas」)、:203(搜「update_config」)、:215(搜「restart_policy」)
K8s 的来历与七特性同上(Kubernetes)text/76-fm-kubernetes.txt:4(搜「Borg」)、:11(搜「Service discovery」)、:29(搜「Self-healing」)、:34(搜「rotate secrets」)
本地三选项同上text/76-fm-kubernetes.txt:54(搜「Docker Desktop」)、:59(搜「Kind」)、:62(搜「Minikube」)
Cluster/Control Plane/Node/Pod同上text/76-fm-kubernetes.txt:86(搜「Cluster」)、:91(搜「Control Plane」)、:97(搜「Pods」)
四种工作负载同上text/76-fm-kubernetes.txt:108(搜「Deployment」)、:112(搜「StatefulSet」)、:119(搜「Jobs」)
PV/PVC/StorageClass 三件套同上text/76-fm-kubernetes.txt:132(搜「PersistentVolumeClaim」)
Kompose 转换与两处例外同上text/76-fm-kubernetes.txt:153(搜「kompose convert」)、:243(搜「manual definition」)、:259(搜「not encryption」)
Kind 集群配置同上text/76-fm-kubernetes.txt:291(搜「extraPortMappings」)、:330(搜「expose」)、:339(搜「create cluster」)
kubectl 三板斧与输出判读同上text/76-fm-kubernetes.txt:376(搜「apply -f」)、:382(搜「get all」)、:460(搜「CrashLoopBackOff」)、:506(搜「describe」)、:512(搜「logs」)
前端与 proxy 长 URL同上text/76-fm-kubernetes.txt:489(搜「more sensitive to paths」)
启动顺序经验同上text/76-fm-kubernetes.txt:246(搜「requires them to be up」)

3.4 Swarm stack 文件的逐服务账(与 Compose 版的 diff 全录)

把第 2.2 节的「四类差异」落到每一行(依据原书 Code listing 9.6):20

MariaDB 服务: environment 里出现 MARIADB_ROOT_PASSWORD_FILE: /run/secrets/mariadb_root_password——密码不再以环境变量明文存在, 而是 _FILE 后缀指向 secret 挂载的文件;secrets: [mariadb_root_password, mariadb_password] 声明两个挂载;deploy 四件套齐活(replicas: 1、 placement 约束到 worker、update_config parallelism 1 / delay 10s / failure_action rollback、restart_policy on-failure / max_attempts 3 / delay 5s / window 120s);网络显式 ticketing-net;端口改写成 published: 3306 / target: 3306 的长格式21。

PostgreSQL 服务: 同款四件套 + healthcheck(pg_isready 每秒一探、 超时 5 秒、重试 10 次);初始化脚本 bind 到 /docker-entrypoint-initdb.d (官方镜像首次启动自动执行);POSTGRES_DB: fang——调度库与主库分离的 配置证据22。

Redis / MailHog 服务: 最简形态——placement 约束 + 网络 + 端口 + Redis 的命名卷(ticketing-redis:/data,RDB 快照落这里); MailHog 两个端口都 published(1025 SMTP + 8025 网页)23。

backend 服务: 全家桶里配置最壮观的一个——environment 十几行: SERVER_PORT、CLIENT_URL、REDIS_URL: redis://redis/(服务名即主机名)、 MARIADB_(HOST/DATABASE/USER/PASSWORD_FILE)、POSTGRES_、 JWT_SECRET_FILE、SQLX_OFFLINE: 1、MAX_BODY_LIMIT: 5、 BUCKET_NAME: dv-rust-ticketing-s3-bucket、SMTP_*;secrets 四个 (jwt/mariadb/postgres/smtp);deploy 里 parallelism: 2(前后端滚动 更新允许两个实例并行)24。

frontend 服务: 两行 environment(BACKEND_HOST: ticketing-backend、 BACKEND_PORT: 8000)——反代方案的运行期半;依赖后端(deploy 顺序)。 「服务名即 DNS」是 overlay 网络的隐形福利: 容器之间按服务名互找, IP 漂移无所谓25。

3.5 起栈与运维的两条命令(原书流程补全)

  # 在 manager 节点上(node1 装过多台 VM 后任选一):
  docker stack deploy -c stack.yml ticketing     # 应用整个栈
  docker service ls                               # 看服务分布与副本状态

  图说:stack = Swarm 世界的「compose up」;-c 指定文件,ticketing 是栈名。

「先构建发布,再部署」的红字再放一次: Swarm 不构建镜像,只从 registry 拉——所以 CI(第 12 篇的 docker.yml)必须先于 stack deploy 跑完; viktordaroczi/ticketing:latest 这类 tag 就是部署的寻址坐标26。

4.4 K8s 对象文件的完整清单(20 个文件的逻辑分组)

把 Kompose 产物按对象类型归档(原书逐文件列过,此处收拢):27

对象文件(按服务)干什么
Secretmariadb-root-password / mariadb-password / postgres-password / smtp-password / jwt-secret密码注入(值是 base64,不是加密)
PVC(+StorageClass/PV)mariadb-data / mariadb-init / postgres-data / postgres-init / redis-data存储的动态供给与初始化脚本的挂载
Deploymentmariadb-deployment / postgres-deployment / redis-deployment / mailhog-deployment / backend-deployment / frontend-deployment无状态负载的期望实例管理
StatefulSet(数据库三件套在 get all 输出里显示为 StatefulSet)有状态负载:稳定端点 + 稳定存储
Service每服务一个 *-service.yaml集群内 DNS 名 + 对外暴露(NodePort/ClusterIP)

「生成后要人工过」的两处(原书明写):存储需要手工定义 (「并非所有 Compose 特性都能自动翻译」);secret 文件不入库 (「仓库里只放可注入的样例」)。Kompose 是 kickstart 不是成品—— 「我们仍需 review 生成的文件」28。

4.5 kubectl 排障场景的完整剧本

  症状:某个 Pod 一直 CrashLoopBackOff
      kubectl get all                     # 定位哪个 Pod(READY 列实际/期望)
      kubectl describe pod/<名>            # 事件流:调度失败?探针失败?镜像拉不到?
      kubectl logs <pod>                   # 应用日志(若容器活着)
      kubectl logs <pod> --previous        # 上一轮日志(容器已重启过时必须)
      kubectl get all / describe / logs 三板斧循环,直到定位

  图说:get 定位对象,describe 看事件,logs 看输出;--previous 专查「死过一次」的。

alias 贴士原样收: 「在 .rc 文件里加 alias k="kubectl";PowerShell 用 Set-Alias -Name k -Value kubectl」——排障时省下的每次 7 个字母, 累积起来很可观29。

4.6 K8s 概念与 Swarm 概念的对照表(一鱼两吃)

Swarm 的词K8s 对应差别
manager / workercontrol plane / node同思路;K8s 的控制面组件更多更细
service + deploy 块Deployment(+ReplicaSet)/ StatefulSetK8s 把「无状态/有状态」拆成两类负载
overlay 网络Service + 内建 DNS同:按名寻址;K8s 另加 Ingress 统一入口
secrets(文件挂载)Secrets(注入方式更多)K8s 的 secret 管理更可编程(轮换不停机)
stack 文件(一份)20 个对象 YAMLK8s 的粒度细到每个对象可单独 apply
healthcheckliveness/readiness 探针K8s 分两探针:活=重启,就绪=摘流量30

「编排的谱系」一句话: Docker Compose(单机)→ Swarm(同规格多机、 配置同源)→ Kubernetes(集群的一切皆对象)——复杂度递增,期望状态的 思想一行未改;这正是第 12 篇那句「编排 = 自动化生命周期 + 健康 + 伸缩」的三级注脚31。

8. 原文地图补充

主题原书章原文位置
manager 取奇数的多数派理由Containerization and Orchestrationtext/75-fm-docker-swarm.txt:98(搜「odd number」)
overlay 默认隔离同上text/75-fm-docker-swarm.txt:109(搜「no access by default」)
Swarm 只拉不构建同上text/75-fm-docker-swarm.txt:77(搜「will not build images」)
K8s secret 的 base64 非加密同上(Kubernetes)text/76-fm-kubernetes.txt:259(搜「not encryption」)
CrashLoopBackOff 判读同上text/76-fm-kubernetes.txt:460(搜「CrashLoopBackOff」)

9. 可带走的(补两条)

  1. Compose 到 Swarm 的四类 diff:密码变 secrets、restart 变 deploy 四件套、 隐式网络变显式 overlay、卷先声明——配置同源,语义升格。
  2. kubectl 四板斧: get all 定位、describe 看事件、logs 看输出 (--previous 查死过一次的)、apply 发配置;先基建后应用。

Footnotes

  1. 出处:「Docker Swarm」(text/75-fm-docker-swarm.txt:4,搜「little brother」)、:7(搜「same specification」)。 ↩

  2. 出处:「Swarming with Multipass」(text/75-fm-docker-swarm.txt:19,搜「multipass launch」)、:34(搜「swarm init」)、:46(搜「join --token」)。 ↩

  3. 出处:「Swarming with Multipass」(text/75-fm-docker-swarm.txt:77,搜「will not build images」)。 ↩ ↩2

  4. 出处:「Clusters, managers, and workers」(text/75-fm-docker-swarm.txt:88,搜「supervise」)、:98(搜「odd number of managers」)。 ↩ ↩2

  5. 出处:「Networks」(text/75-fm-docker-swarm.txt:109,搜「no access by default and by design」)、:128(搜「encrypted」)。 ↩ ↩2

  6. 出处:stack 配置(text/75-fm-docker-swarm.txt:167,搜「MARIADB_ROOT_PASSWORD_FILE」)、:182(搜「secrets」)。 ↩

  7. 出处:stack 配置(text/75-fm-docker-swarm.txt:191,搜「replicas: 1」)、:203(搜「update_config」)、:215(搜「restart_policy」)。 ↩

  8. 出处:stack 配置(text/75-fm-docker-swarm.txt:122,搜「networks」)、:137(搜「volumes」)、:152(搜「mariadb」)。 ↩

  9. 出处:stack 配置(text/75-fm-docker-swarm.txt:520,搜「SERVER_PORT」)、:553(搜「JWT_SECRET_FILE」)、:556(搜「SQLX_OFFLINE」)。 ↩

  10. 出处:「Kubernetes」(text/76-fm-kubernetes.txt:4,搜「Borg」与「navigator」)。 ↩

  11. 出处:「Kubernetes」(text/76-fm-kubernetes.txt:11,搜「Service discovery」)、:24(搜「rollouts and rollbacks」)、:29(搜「Self-healing」)、:34(搜「rotate secrets」)、:37(搜「Horizontal scaling」)。 ↩ ↩2

  12. 出处:「Architecture of Kubernetes」(text/76-fm-kubernetes.txt:86,搜「Cluster」)、:91(搜「Control Plane」)、:94(搜「Nodes」)、:97(搜「smallest deployable unit」)。 ↩

  13. 出处:「Further concepts」(text/76-fm-kubernetes.txt:108,搜「Deployment」)、:112(搜「StatefulSet」)、:119(搜「Jobs」)、:132(搜「StorageClass」)、:137(搜「Secrets」)、:140(搜「Ingress」)。 ↩

  14. 出处:「Converting stack specification to Kubernetes」(text/76-fm-kubernetes.txt:153,搜「kompose convert」)、:243(搜「manual definition」)、:259(搜「not encryption」)。 ↩ ↩2

  15. 出处:「Creating a Kubernetes cluster with Kind」(text/76-fm-kubernetes.txt:291,搜「extraPortMappings」)、:306(搜「extraMounts」)、:339(搜「create cluster」)。 ↩

  16. 出处:「Managing the cluster with Kubectl」(text/76-fm-kubernetes.txt:376,搜「apply -f」)、:382(搜「get all」)、:460(搜「CrashLoopBackOff」)。 ↩

  17. 出处:「Troubleshooting with Kubectl」(text/76-fm-kubernetes.txt:506,搜「describe」)、:512(搜「logs」)、:517(搜「alias」)。 ↩

  18. 出处:「Managing the cluster with Kubectl」(text/76-fm-kubernetes.txt:489,搜「more sensitive to paths」)。 ↩ ↩2

  19. 出处:「Converting stack specification to Kubernetes」(text/76-fm-kubernetes.txt:246,搜「requires them to be up and running」)。 ↩

  20. 对照依据:原书 docker-compose.yml(text/74-fm-containerization-with-docker.txt:703)与 stack 文件(text/75-fm-docker-swarm.txt:122 起)。 ↩

  21. 出处:「Docker Swarm」(text/75-fm-docker-swarm.txt:167,搜「PASSWORD_FILE」)、:191(搜「replicas: 1」)、:215(搜「restart_policy」)。 ↩

  22. 出处:「Docker Swarm」(text/75-fm-docker-swarm.txt:370,搜「healthcheck」)、:280(搜「POSTGRES_DB: fang」)。 ↩

  23. 出处:「Docker Swarm」(text/75-fm-docker-swarm.txt:390,搜「redis」)、:446(搜「mailhog」)、:432(搜「ticketing-redis」)。 ↩

  24. 出处:「Docker Swarm」(text/75-fm-docker-swarm.txt:493,搜「backend」)、:520(搜「SERVER_PORT」)、:553(搜「JWT_SECRET_FILE」)、:613(搜「parallelism: 2」)。 ↩

  25. 出处:「Docker Swarm」(text/75-fm-docker-swarm.txt:660,搜「frontend」)、:672(搜「BACKEND_HOST」)。 ↩

  26. 出处:「Swarming with Multipass」(text/75-fm-docker-swarm.txt:77,搜「will not build images」)。 ↩

  27. 文件清单见「Converting stack specification to Kubernetes」(text/76-fm-kubernetes.txt:162,搜「mariadb-data-persistentvolumeclaim」)。 ↩

  28. 出处:「Converting stack specification to Kubernetes」(text/76-fm-kubernetes.txt:243,搜「manual definition」)、:259(搜「not encryption」)。 ↩

  29. 出处:「Troubleshooting with Kubectl」(text/76-fm-kubernetes.txt:506,搜「describe」)、:512(搜「logs」)、:517(搜「alias」)。 ↩

  30. 探针两分为 K8s 通用知识(补充,不在书里);Swarm/K8s 对照表为我们整理,两侧定义见原书两节。 ↩

  31. 谱系为我们的归纳;编排定义见 text/74-fm-containerization-with-docker.txt:1049。 ↩

On this page