☰
Docker Classic Swarm 的 TLS 安全配置:从证书体系到全集群实战
2026/10/12 1:24:53 网站建设 项目流程
  • 云原生
  • 后端
  • 微服务

【免费下载链接】classicswarm

Swarm Classic: a container clustering system. Not to be confused with Docker Swarm which is at https://github.com/docker/swarmkit

项目地址:https://gitcode.com/gh_mirrors/cl/classicswarm
点击查看免费下载

Docker Swarm(Classic Swarm)集群中的所有节点都必须在网络上绑定 Docker daemon 端口,这带来显而易见的安全风险——当网络不可信(如公网)时风险成倍放大。本文以docs/secure-swarm-tls.md与docs/configure-tls.md为主线,系统讲解 TLS 与 PKI 的基础概念、三种证书签发模式,并给出从零搭建「CA 服务器 + swarm manager + 双节点 + 远程客户端」五机 TLS 环境的完整九步实操,同时结合本仓库源码(cli/manage.go、api/server.go、cluster/httpclient.go 等)说明 TLS 在 Swarm 内部的真实作用路径。读完本文,你将能够独立为 Docker Classic Swarm 集群配置双向 TLS 认证,并理解其底层实现原理。

为什么 Swarm 集群需要 TLS

Docker Classic Swarm 是一个容器集群系统,它把多台 Docker 主机的计算资源聚合成一个虚拟的、巨大的 Docker Engine。为此,集群中的每一台节点(包括 swarm manager 与 swarm 节点)都必须把 Docker daemon 绑定到网络端口上,接受来自网络的命令。一旦端口暴露到不受信任的网络(例如互联网),攻击者就可能:

  • 直接向 daemon 发送恶意命令(创建容器、拉取镜像、读写数据卷);
  • 实施中间人攻击(man-in-the-middle),篡改客户端与 daemon 之间的通信内容。

为了缓解这些风险,Docker Swarm 与 Docker Engine daemon 支持传输层安全协议(Transport Layer Security,TLS)。TLS 是 SSL(Secure Sockets Layer)的继任者,两者经常被混用;Docker 使用的是 TLS,本文统一使用 TLS 一词。生产规划文档 docs/plan-for-production.md 也明确指出:所有节点都必须绑定网络端口,Swarm 与 Engine 通过 TLS 认证来缓解中间人攻击等风险,并给出了 TLS 模式下的默认端口约定:

组件默认 TLS 端口
Engine daemon2376/tcp
Swarm manager3376/tcp

(非 TLS 模式下,Engine 与 Swarm 的默认端口分别为2375/tcp与3375/tcp。)

先理解 TLS 与 PKI 的基本概念

在动手配置之前,先弄清 TLS 与公钥基础设施(Public Key Infrastructure,PKI)的核心概念。PKI 是一套用于创建和管理数字证书的安全技术、策略与流程的组合,这些证书与基础设施通过认证(authentication)与加密(encryption)等机制保护数字通信。

护照类比:护照用于验证一个人的身份,包含持有人照片与生物特征信息,还列出了签发国家以及valid from(生效日)与valid to(失效日)日期。数字证书与此非常相似。下面是从一张数字证书中摘录的内容:

Certificate: Data: Version: 3 (0x2) Serial Number: 9590646456311914051 (0x8518d2237ad49e43) Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=CA, L=Sanfrancisco, O=Docker Inc Validity Not Before: Jan 18 09:42:16 2016 GMT Not After : Jan 15 09:42:16 2026 GMT Subject: CN=swarm

这张证书标识的是一台名为swarm的计算机,有效期从 2016 年 1 月到 2026 年 1 月,由位于美国加州旧金山的 Docker Inc. 签发。正如护照在登机、过海关时认证个人身份,数字证书在网络上认证计算机的身份。

PKI 则是在幕后支撑数字证书的技术、策略与流程组合,主要包括:

  • 安全地请求证书的服务;
  • 认证证书请求实体身份的程序;
  • 判断实体是否有资格获得证书的程序;
  • 签发证书的技术与流程;
  • 吊销证书的技术与流程。

Docker Engine 如何利用 TLS 进行认证

你可以同时配置 Docker Engine CLI 与 Docker Engine daemon 要求使用 TLS 进行认证。配置 TLS 意味着:CLI 与 daemon 之间的所有通信都必须附带并经由受信任的数字证书签名。Docker Engine CLI 必须先出示自己的数字证书,daemon 才会接受它发来的命令。

与此同时,daemon 也必须信任 CLI 所使用的证书。这种信任通常经由可信第三方建立——即图中的 Certificate Authority(CA,证书颁发机构)服务器。

图中的可信第三方就是 CA 服务器。如同护照示例中的国家,CA 负责创建、签名、签发和吊销证书。信任的建立方式是:在运行 Docker Engine daemon 的主机上安装 CA 的根证书,然后 Docker Engine CLI 向 CA 服务器请求自己的证书,由 CA 签名后签发给它。

工作流程如下:

  1. Docker Engine CLI 在发出命令前,先把证书发送给 Docker Engine daemon;
  2. daemon 检查证书——由于 daemon 信任该 CA,它会自动信任任何由该 CA 签名的证书;
  3. 假设证书有效(未过期、未被吊销等),daemon 就接受来自这个可信 CLI 的命令。

需要强调:Docker Engine CLI 本质上只是使用 Docker Engine API 与 daemon 通信的一个客户端。任何使用 Docker Engine API 的客户端都可以使用 TLS。例如 Docker Universal Control Plane(UCP)内置了 TLS 支持,其他基于 Docker Engine API 的第三方产品也可以这样配置。

Docker 与 Swarm 的三种 TLS 配置模式

根据承担 CA 角色的实体类型不同,Docker Engine daemon 及其客户端存在三种可能的 TLS 配置:

  • 外部第三方 CA(External 3rd party CA)
  • 内部企业 CA(Internal corporate CA)
  • 自签名证书(Self-signed certificates)

外部第三方 CA

外部 CA 是受信任的第三方公司,提供创建、签发、吊销和管理证书的服务。说它们「受信任」,是因为它们必须满足特定条件、保持高水准的安全与商业实践才能赢得你的业务;同时你也需要安装外部 CA 的根证书,才能让计算机和服务信任它们。

使用外部第三方 CA 时,证书的创建、签名、签发、吊销与管理全部由它负责。这类服务通常收费,但被公认为企业级、可扩展的解决方案,能提供较高程度的信任。

内部企业 CA

许多组织选择搭建自己的 CA 与 PKI,常见实现包括 OpenSSL 和 Microsoft Active Directory。这种情况下,你的公司自己就是 CA,需要承担 CA 的全部工作。好处是:作为自己的 CA,你对 PKI 拥有更强的控制力。

自建 CA 与 PKI 需要你自行提供外部第三方 CA 提供的全部服务,包括创建、签发、吊销和管理证书。自己做这些事有相应的成本与开销,但对大型企业而言,与使用外部第三方服务相比仍可能降低成本。假设你的内部 CA 与 PKI 运营管理得当,内部企业 CA 可以是一种高度可扩展、高度安全的选择。

自签名证书

顾名思义,自签名证书是用自己的私钥签名的证书,而不是由受信任的 CA 签名。这是低成本、易用的选择。如果正确实现和管理自签名证书,它们比完全没有证书要好。

但由于自签名证书缺少完整的 PKI,扩展性差,也缺少其他两种方案提供的许多优势。一个明显的缺点是:自签名证书无法吊销。由于这一点及其他限制,自签名证书被认为是三种方案中最不安全的,不建议在暴露于不受信任网络的公网生产负载中使用。

实战:为 Docker Swarm 集群配置 TLS(九步全流程)

下面的流程将创建一个两节点的 swarm 集群,外加一个 Docker Engine CLI、一个 swarm manager 和一个 CA 服务器,如图所示。所有 Docker Engine 主机(client、swarm、node1、node2)都拥有 CA 证书副本以及由 CA 签发的各自密钥对。

流程包含以下步骤:

  1. Step 1: 准备前置条件
  2. Step 2: 创建 CA 服务器
  3. Step 3: 创建并签发密钥
  4. Step 4: 安装密钥
  5. Step 5: 为 Engine daemon 配置 TLS
  6. Step 6: 创建 swarm 集群
  7. Step 7: 使用 TLS 启动 swarm manager
  8. Step 8: 测试 swarm manager 配置
  9. Step 9: 配置 Engine CLI 使用 TLS

开始之前的重要提示:下文包含使用 OpenSSL 自建 CA 的步骤,这与运营内部企业 CA 和 PKI 类似。但绝不能把这里的步骤当作搭建生产级内部 CA 与 PKI 的指南。这些步骤仅用于演示目的——让没有现成 CA 和证书的读者也能跟着操作,完成 Swarm 的 TLS 配置。

Step 1: 准备前置条件

完成本流程需要准备 5 台 Linux 服务器,可以是物理机与虚拟机的任意组合,可位于本地或公有云。各服务器的名称与用途如下:

服务器名说明
ca充当 Certificate Authority(CA)服务器
swarm充当 swarm manager
node1充当 swarm 节点
node2充当 swarm 节点
client充当远程 Docker Engine 客户端

确保你能通过 SSH 访问全部 5 台服务器,且它们能通过 DNS 名称解析相互通信。特别要注意:

  • 在 swarm manager 与 swarm 节点之间开放 TCP 端口2376;
  • 在 Docker Engine client 与 swarm manager 之间开放 TCP 端口3376。

如果这些端口已被占用,可以选择其他端口,但本示例假设使用这些端口。每台服务器必须运行与 Docker Engine 兼容的操作系统;为简便起见,后续步骤假设所有服务器都运行 Ubuntu 14.04 LTS。

Step 2: 创建 CA 服务器

注意:如果你已经拥有 CA 和证书且熟悉其使用,可以跳过本步直接进入下一步。

本步把一台 Linux 服务器配置为 CA,用它来创建和签发密钥。再次强调:这只是为了让没有现成 CA 的读者可以跟随完成后续步骤,不是生产级 CA 的部署范本。

  1. 登录 CA 服务器的终端并提升为 root:

    $ sudo su
  2. 为 CA 创建私钥ca-priv-key.pem:

    # openssl genrsa -out ca-priv-key.pem 2048 Generating RSA private key, 2048 bit long modulus ...........................................................+++ .....+++ e is 65537 (0x10001)
  3. 为 CA 创建公钥ca.pem。公钥基于上一步创建的私钥:

    # openssl req -config /usr/lib/ssl/openssl.cnf -new -key ca-priv-key.pem -x509 -days 1825 -out ca.pem You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:US <output truncated>

    这里的-days 1825意味着 CA 证书有效期约为 5 年(1825 天)。

至此你已配置好一个拥有公私钥对的 CA 服务器。可以检查每个密钥的内容:用openssl rsa -in ca-priv-key.pem -noout -text检查私钥,用openssl x509 -in ca.pem -noout -text检查公钥(证书)。下面是 CA 公钥的部分内容:

# openssl x509 -in ca.pem -noout -text Certificate: Data: Version: 3 (0x2) Serial Number: 17432010264024107661 (0xf1eaf0f9f41eca8d) Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=CA, L=Sanfrancisco, O=Docker Inc Validity Not Before: Jan 16 18:28:12 2016 GMT Not After : Jan 13 18:28:12 2026 GMT Subject: C=US, ST=CA, L=San Francisco, O=Docker Inc Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:d1:fe:6e:55:d4:93:fc:c9:8a:04:07:2d:ba:f0: 55:97:c5:2c:f5:d7:1d:6a:9b:f0:f0:55:6c:5d:90: <output truncated>

稍后,你将用这张证书为基础设施中的其他服务器签发密钥。

Step 3: 创建并签发密钥

现在 CA 已就绪,你需要为 swarm manager、swarm 节点和远程 Docker Engine client 创建密钥对。所有服务器的密钥对创建命令与流程完全相同。涉及的关键文件如下:

文件说明
ca-priv-key.pemCA 的私钥,必须妥善保管。稍后用它为环境中其他节点签发新密钥。与ca.pem一起构成 CA 的密钥对。
ca.pemCA 的公钥(即证书)。安装到环境中所有节点上,使所有节点信任由该 CA 签名的证书。与ca-priv-key.pem一起构成 CA 的密钥对。
NODE_NAME.csr证书签名请求(CSR)。CSR 本质上是向 CA 申请为某个节点创建新密钥对的申请单。CA 根据 CSR 提供的信息生成该节点的公私钥对。
NODE_NAME-priv-key.pem由 CA 签名的私钥。节点用它向远程 Docker Engine 认证自己的身份。与NODE_NAME-cert.pem一起构成节点的密钥对。
NODE_NAME-cert.pem由 CA 签名的证书。与NODE_NAME-priv-key.pem一起构成节点的密钥对。

下面的命令演示如何为所有节点创建密钥,请在 CA 服务器上的一个工作目录中执行。

  1. 登录 CA 服务器终端并提升为 root:

    $ sudo su
  2. 为 swarm manager 创建私钥swarm-priv-key.pem:

    # openssl genrsa -out swarm-priv-key.pem 2048 Generating RSA private key, 2048 bit long modulus ............................................................+++ ........+++ e is 65537 (0x10001)
  3. 用上一步创建的私钥生成证书签名请求(CSR)swarm.csr:

    # openssl req -subj "/CN=swarm" -new -key swarm-priv-key.pem -out swarm.csr

    注意:这仅用于演示目的。真实生产环境中创建 CSR 的流程略有不同。这里-subj "/CN=swarm"直接指定了证书的主体名(Common Name)为swarm,即前面证书示例中Subject: CN=swarm所对应的身份。

  4. 基于上一步创建的 CSR 生成证书swarm-cert.pem:

    # openssl x509 -req -days 1825 -in swarm.csr -CA ca.pem -CAkey ca-priv-key.pem -CAcreateserial -out swarm-cert.pem -extensions v3_req -extfile /usr/lib/ssl/openssl.cnf <snip> # openssl rsa -in swarm-priv-key.pem -out swarm-priv-key.pem

    至此你拥有了 swarm manager 的密钥对。

  5. 对其余节点(node1、node2、client)重复上述步骤。注意把swarm相关的取值替换为正在创建密钥对的节点对应的值:

    服务器名私钥CSR证书
    node1node1-priv-key.pemnode1.csrnode1-cert.pem
    node2node2-priv-key.pemnode2.csrnode2-cert.pem
    clientclient-priv-key.pemclient.csrclient-cert.pem
  6. 验证工作目录包含以下文件:

    # ls -l total 64 -rw-r--r-- 1 root root 1679 Jan 16 18:27 ca-priv-key.pem -rw-r--r-- 1 root root 1229 Jan 16 18:28 ca.pem -rw-r--r-- 1 root root 17 Jan 18 09:56 ca.srl -rw-r--r-- 1 root root 1086 Jan 18 09:56 client-cert.pem -rw-r--r-- 1 root root 887 Jan 18 09:55 client.csr -rw-r--r-- 1 root root 1679 Jan 18 09:56 client-priv-key.pem -rw-r--r-- 1 root root 1082 Jan 18 09:44 node1-cert.pem -rw-r--r-- 1 root root 887 Jan 18 09:43 node1.csr -rw-r--r-- 1 root root 1675 Jan 18 09:44 node1-priv-key.pem -rw-r--r-- 1 root root 1082 Jan 18 09:49 node2-cert.pem -rw-r--r-- 1 root root 887 Jan 18 09:49 node2.csr -rw-r--r-- 1 root root 1675 Jan 18 09:49 node2-priv-key.pem -rw-r--r-- 1 root root 1082 Jan 18 09:42 swarm-cert.pem -rw-r--r-- 1 root root 887 Jan 18 09:41 swarm.csr -rw-r--r-- 1 root root 1679 Jan 18 09:42 swarm-priv-key.pem

    ca.srl是 CA 自动生成的序列号文件(由-CAcreateserial参数产生),CA 用它记录已签发证书的序列号。

你可以用openssl rsa -in <key-name> -noout -text检查私钥,用openssl x509 -in <key-name> -noout -text检查公钥。下面是 swarm manager 公钥swarm-cert.pem的部分内容:

# openssl x509 -in ca.pem -noout -text Certificate: Data: Version: 3 (0x2) Serial Number: 9590646456311914051 (0x8518d2237ad49e43) Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=CA, L=Sanfrancisco, O=Docker Inc Validity Not Before: Jan 18 09:42:16 2016 GMT Not After : Jan 15 09:42:16 2026 GMT Subject: CN=swarm <output truncated>

可以看到,Subject: CN=swarm对应前面openssl req -subj "/CN=swarm"设定的主体名。

Step 4: 安装密钥

本步把密钥安装到基础设施中对应的服务器上。每台服务器需要三个文件:

  • CA 公钥的副本(ca.pem)
  • 自己的私钥
  • 自己的公钥(证书)

下面的步骤演示如何用scp把这些文件从 CA 服务器复制到各服务器。复制时按如下规则重命名文件:

原文件名复制后文件名
ca.pemca.pem
<server>-cert.pemcert.pem
<server>-priv-key.pemkey.pem
  1. 登录 CA 服务器终端并提升为 root:

    $ sudo su
  2. 在 swarm manager 上创建~/.certs目录。这里假设用户账户是 ubuntu:

    $ ssh ubuntu@swarm 'mkdir -p /home/ubuntu/.certs'
  3. 把密钥从 CA 复制到 swarm manager 服务器:

    $ scp ./ca.pem ubuntu@swarm:/home/ubuntu/.certs/ca.pem $ scp ./swarm-cert.pem ubuntu@swarm:/home/ubuntu/.certs/cert.pem $ scp ./swarm-priv-key.pem ubuntu@swarm:/home/ubuntu/.certs/key.pem

    注意:scp命令可能需要提供认证。例如 AWS EC2 实例使用基于证书的认证。要把文件复制到与公钥nigel.pem关联的 EC2 实例,scp命令需修改为:scp -i /path/to/nigel.pem ./ca.pem ubuntu@swarm:/home/ubuntu/.certs/ca.pem。

  4. 对其余每台服务器重复步骤 2 与 3:

    • node1
    • node2
    • client
  5. 验证你的工作。复制完成后,每台机器都应拥有以下密钥:

    基础设施中的每个节点都应在/home/ubuntu/.certs/目录下拥有以下文件:

    # ls -l /home/ubuntu/.certs/ total 16 -rw-r--r-- 1 ubuntu ubuntu 1229 Jan 18 10:03 ca.pem -rw-r--r-- 1 ubuntu ubuntu 1082 Jan 18 10:06 cert.pem -rw-r--r-- 1 ubuntu ubuntu 1679 Jan 18 10:06 key.pem

Step 5: 为 Engine daemon 配置 TLS

上一步你已在每个 swarm 节点上创建并安装了必要密钥。本步把它们配置为监听网络且只接受 TLS 连接。完成后,swarm 节点将监听 TCP 端口2376,并且只接受使用 TLS 的连接。

在node1和node2(你的 swarm 节点)上执行以下操作:

  1. 打开node1的终端并提升为 root:

    $ sudo su
  2. 向/etc/docker/daemon.json添加以下配置键。如果文件不存在,则创建它:

    { "hosts": ["tcp://0.0.0.0:2376"], "tlsverify": "true", "tlscacert": "/home/ubuntu/.certs/ca.pem", "tlscert": "/home/ubuntu/.certs/cert.pem", "tlskey": "/home/ubuntu/.certs/key.pem" }

    重启 Docker 使配置生效。如果文件不是合法 JSON,Docker 将启动失败并输出错误。

    各配置键含义如下:

    配置键含义
    hostsdaemon 监听的地址与端口,tcp://0.0.0.0:2376表示在所有网卡上以 TLS 端口 2376 提供服务
    tlsverify置为"true"启用 TLS 并强制验证客户端证书(双向认证)
    tlscacertCA 根证书路径,daemon 用它验证客户端证书链
    tlscertdaemon 自己的证书路径
    tlskeydaemon 自己的私钥路径
  3. 在node2上重复上述过程。

从这里可以看出 TLS 的「双向」特征:daemon 不仅要向客户端证明自己(出示cert.pem/key.pem),还要通过tlsverify与ca.pem反过来校验客户端身份。这正是 cli/manage.go 中loadTLSConfig所体现的行为——verify为真时加载 CA 证书池并设置ClientAuth = tls.RequireAndVerifyClientCert,强制要求客户端提供由该 CA 签发的证书。

Step 6: 创建 swarm 集群

接下来创建 swarm 集群。本流程使用默认的hosted discovery(托管发现)后端创建一个两节点 swarm 集群。默认的 hosted discovery 后端使用 Docker Hub,不建议用于生产环境。

  1. 登录 swarm manager 节点的终端。

  2. 创建集群并把它的唯一 ID 导出到TOKEN环境变量:

    $ sudo export TOKEN=$(docker run --rm swarm create) Unable to find image 'swarm:latest' locally latest: Pulling from library/swarm d681c900c6e3: Pulling fs layer <snip> 986340ab62f0: Pull complete a9975e2cc0a3: Pull complete Digest: sha256:c21fd414b0488637b1f05f13a59b032a3f9da5d818d31da1a4ca98a84c0c781b Status: Downloaded newer image for swarm:latest

    swarm create子命令会生成一个集群 token,所有节点通过token://$TOKEN接入同一个集群。

  3. 把node1加入集群。务必指定 TCP 端口2376而不是2375:

    $ sudo docker run -d swarm join --addr=node1:2376 token://$TOKEN 7bacc98536ed6b4200825ff6f4004940eb2cec891e1df71c6bbf20157c5f9761
  4. 把node2加入集群:

    $ sudo docker run -d swarm join --addr=node2:2376 token://$TOKEN db3f49d397bad957202e91f0679ff84f526e74d6c5bf1b6734d834f5edcbca6c

Step 7: 使用 TLS 启动 swarm manager

  1. 启动一个启用 TLS 的新容器:

    $ docker run -d -p 3376:3376 -v /home/ubuntu/.certs:/certs:ro swarm manage --tlsverify --tlscacert=/certs/ca.pem --tlscert=/certs/cert.pem --tlskey=/certs/key.pem --host=0.0.0.0:3376 token://$TOKEN

    这条命令基于swarm镜像启动一个新容器,并把服务器上的端口3376映射到容器内的端口3376。这个映射确保发送到主机端口3376的 Docker Engine 命令会被转发到容器内的端口3376。容器以--tlsverify、--tlscacert、--tlscert和--tlskey选项运行swarm manage进程——这些选项强制进行 TLS 验证并指定 swarm manager TLS 密钥的位置。证书目录/home/ubuntu/.certs以只读方式挂载为容器内/certs,/certs/*.pem路径即对应上述三个--tls*参数。

  2. 运行docker ps验证 swarm manager 容器已启动并运行:

    $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 035dbf57b26e swarm "/swarm manage --tlsv" 7 seconds ago Up 7 seconds 2375/tcp, 0.0.0.0:3376->3376/tcp compassionate_lovelace

    源码印证:manage命令在 cli/manage.go 中先检查--tls/--tlsverify标志:若指定了它们而未提供--tlscert/--tlskey则直接报错退出;指定--tlsverify而未提供--tlscacert同样报错;反之,若只提供了--tlscert/--tlskey/--tlscacert而没开--tls/--tlsverify也会被拒绝(因为这些参数将被忽略)。随后 loadTLSConfig 会调用tls.LoadX509KeyPair加载证书私钥,并把 TLS 最低版本设为 TLS 1.2(MinVersion: tls.VersionTLS12)。校验启用时还会把 CA 证书读入证书池,同时设置ClientAuth = tls.RequireAndVerifyClientCert与ClientCAs,实现双向认证。生成的tlsConfig最终被传给 api.NewServer(见 cli/manage.go)与 swarm.NewCluster。api.Server在 newListener 中检测到tlsConfig != nil时,会设置NextProtos = []string{"http/1.1"}并用tls.NewListener包装监听器——也就是说,Swarm 对外暴露的 HTTPS 端口正是由这份 TLS 配置支撑的。

你的 swarm 集群现在已配置为使用 TLS。

Step 8: 测试 swarm manager 配置

集群已构建并配置 TLS,现在用 Docker Engine CLI 验证它是否工作。

  1. 打开client服务器的终端。

  2. 执行docker version命令。执行时,必须传入客户端证书的位置:

    $ sudo docker --tlsverify --tlscacert=/home/ubuntu/.certs/ca.pem --tlscert=/home/ubuntu/.certs/cert.pem --tlskey=/home/ubuntu/.certs/key.pem -H swarm:3376 version Client: Version: 1.9.1 API version: 1.21 Go version: go1.4.2 Git commit: a34a1d5 Built: Fri Nov 20 13:12:04 UTC 2015 OS/Arch: linux/amd64 Server: Version: swarm/1.0.1 API version: 1.21 Go version: go1.5.2 Git commit: 744e3a3 Built: OS/Arch: linux/amd64

    输出中Server的版本显示为 "swarm/1.0.1",说明命令已成功发往 swarm manager。

  3. 验证同一命令在不带 TLS 时无法工作。这次不向 swarm manager 传证书:

    $ sudo docker -H swarm:3376 version : Version: 1.9.1 API version: 1.21 Go version: go1.4.2 Git commit: a34a1d5 Built: Fri Nov 20 13:12:04 UTC 2015 OS/Arch: linux/amd64 Get http://swarm:3376/v1.21/version: malformed HTTP response "\x15\x03\x01\x00\x02\x02". * Are you trying to connect to a TLS-enabled daemon without TLS?

    输出显示命令被服务器拒绝。这是因为服务器(swarm manager)配置为只接受使用 TLS 的已认证客户端的连接。malformed HTTP response正是 TLS 握手失败的典型特征:客户端用明文 HTTP 请求打到了一个只讲 TLS 的端口上。

    源码印证:manager 通过 api.Server 对外服务,而 swarm manager 把来自客户端的请求转发给后端节点时,同样使用 TLS。在 cluster/engine.go 的Connect中,NewHTTPClientTimeout("tcp://"+e.Addr, config, ...)会在配置了 TLS 时把 URL scheme 从http自动切换为https(见 cluster/httpclient.go),并把tlsConfig装进http.Transport;此后 api/utils.go 的proxyAsync通过engine.HTTPClientAndScheme()取回这个带 TLS 的客户端,完成对节点的反向代理。也就是说,无论manage是代理普通 API 调用(如proxyContainer)还是代理attach类长连接(hijack,见 api/handlers.go 中hijack(c.tlsConfig, ...)的调用),TLS 配置都会贯穿 client → manager → node 的完整链路。

Step 9: 配置 Engine CLI 使用 TLS

你可以配置 Engine,使每次执行命令时无需再传 TLS 参数。方法是在 Docker Engine 客户端上把Docker Engine host与TLS设置配置为默认值。

具体做法:把客户端的密钥放入~/.docker配置目录。如果系统上有其他用户使用 Engine 命令行,也要配置他们的~/.docker。下面以 Docker Engine 客户端上的ubuntu用户为例。

  1. 打开client服务器的终端。

  2. 如果不存在,在ubuntu用户主目录创建.docker目录:

    $ mkdir /home/ubuntu/.docker
  3. 把 Docker Engine 客户端的密钥从/home/ubuntu/.certs复制到/home/ubuntu/.docker:

    $ cp /home/ubuntu/.certs/{ca,cert,key}.pem /home/ubuntu/.docker
  4. 编辑该账户的~/.bash_profile。

  5. 设置以下变量:

    变量说明
    DOCKER_HOST设置所有 Engine 命令要发送到的 Docker 主机与 TCP 端口。
    DOCKER_TLS_VERIFY告诉 Engine 使用 TLS。
    DOCKER_CERT_PATH指定 TLS 密钥的位置。

    例如:

    export DOCKER_HOST=tcp://swarm:3376 export DOCKER_TLS_VERIFY=1 export DOCKER_CERT_PATH=/home/ubuntu/.docker/
  6. 保存并关闭文件。

  7. 用source加载文件以拾取新变量:

    $ source ~/.bash_profile
  8. 执行docker version验证配置生效:

    $ docker version Client: Version: 1.9.1 API version: 1.21 Go version: go1.4.2 Git commit: a34a1d5 Built: Fri Nov 20 13:12:04 UTC 2015 OS/Arch: linux/amd64 Server: Version: swarm/1.0.1 API version: 1.21 Go version: go1.5.2 Git commit: 744e3a3 Built: OS/Arch: linux/amd64

    输出中的服务器部分说明你的 Docker 客户端正在向 swarm manager 发送命令并使用 TLS。至此,你已经成功配置了一个使用 TLS 的 Docker swarm 集群。

深入理解:TLS 配置在 Swarm 源码中的完整路径

结合前文九步实操,从源码结构可以梳理出 TLS 在 Docker Classic Swarm 中的完整作用链路:

  1. 参数解析与校验:swarm manage的 TLS 相关命令行参数在 cli/flags.go 中定义为--tls、--tlscacert、--tlscert、--tlskey、--tlsverify五个 flag。其中--tls的用法说明是「use TLS; implied by --tlsverify=true」,--tlscacert被描述为「仅信任由此处给定 CA 签名的证书的远端」。

  2. TLS 配置对象构建:manage函数在 cli/manage.go 完成上述校验后调用loadTLSConfig(cli/manage.go)构建*tls.Config:加载cert/key密钥对,设置最低 TLS 版本为 TLS 1.2;--tlsverify开启时加载 CA 证书池并要求客户端证书(RequireAndVerifyClientCert);未开启校验时则InsecureSkipVerify = true。

  3. 对外服务端(manager 自身):tlsConfig传入 api.NewServer,ListenAndServe在 newListener 中用tls.NewListener包装 TCP 监听器,使 manager 对外只接受 TLS 连接(如0.0.0.0:3376)。

  4. 对内连接端(manager → 节点):同一份tlsConfig传入 swarm.NewCluster,存入Cluster.TLSConfig;节点经发现服务注册后,validatePendingEngine调用engine.Connect(c.TLSConfig)(cluster/swarm/cluster.go)。Connect中NewHTTPClientTimeout会根据tlsConfig是否存在把节点 URL 切换为https(cluster/httpclient.go),随后的所有 API 代理(api/utils.go)与 attach/hijack 长连接(api/handlers.go、api/utils.go)都复用这份 TLS 配置。

由此可见:一份tlsConfig同时支撑了「客户端 → swarm manager」与「swarm manager → 节点 daemon」两段加密链路,这也是文档要求同时在 manager 与节点上安装ca.pem、cert.pem、key.pem三件套的根本原因。

相关文档

  • Secure Docker Swarm with TLS(本文理论基础篇)
  • Configure Docker Swarm for TLS(九步实操完整版)
  • Plan for Swarm in production(生产环境端口规划与网络访问控制)
  • 云原生
  • 后端
  • 微服务

【免费下载链接】classicswarm

Swarm Classic: a container clustering system. Not to be confused with Docker Swarm which is at https://github.com/docker/swarmkit

项目地址:https://gitcode.com/gh_mirrors/cl/classicswarm
点击查看免费下载
上一篇:jina-embedding-s-en-v1在聚类任务中的应用:Arxiv论文主题自动分组实践
下一篇:Foundation for Emails中的ZURB Stack技术栈解析

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询