本文最后更新于 2025年10月15日。
背景
自己电脑,云主机再加上NAS就有三个以上的服务器了,我都部署了docker,所以每次管理都需要登录不同的地方管理docker。 忽然想能不能在一个地方管理,就想起potainer和k8s来了。 经过一番搜索和对比,还是potainer适合我,支持多个docker引擎管理,比较轻。k8s适合无状态服务容器管理。
安装potainer
以前用过potainer,也是轻车熟路,直接使用docker-compose安装即可。 编排如下:
networks:
1panel-network:
external: true
services:
portainer:
image: docker.1ms.run/portainer/portainer-ce:latest
container_name: portainer
restart: unless-stopped
networks:
- 1panel-network
security_opt:
- no-new-privileges:true
# ports:
# - "9000:9000"
# - "9443:9443" # 可选:启用 HTTPS Web UI(推荐)
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /share/dockerdata/portainer/data:/data # 将数据持久化到本地目录
运行后访问服务,注册登录
首页
上面的截图是已经配置了其他服务器上docker之后,正常安装之后只有local的环境。
下面介绍怎么增加环境,管理其他服务器的docker引擎。 首先要了解不同的实现方式,通过咨询ai获取详细的对比。
Portainer 管理多主机的五种方式
方式 1:通过 Docker Socket(直接管理本地或远程主机)
原理
- 将目标主机的 Docker 套接字文件(
/var/run/docker.sock
)挂载到 Portainer 容器中,直接通过 Socket 通信管理容器和镜像。
实现步骤
docker run -d -p 9000:9000 \
--name portainer \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer
- 适用于管理 本地主机 或 同一网络内其他主机(需挂载远程主机的 Socket)。
特点
- 优点:配置简单,无需开放端口,安全性较高(仅允许 Portainer 容器访问)。
- 缺点:仅能管理单台主机,需为其他主机单独配置 Socket 挂载
方式 2:通过 Docker TCP 端口(远程主机)
原理
- 在目标主机上开放 Docker 的 TCP 端口(默认
2375
),Portainer 通过该端口与远程 Docker 守护进程通信。
实现步骤
-
修改目标主机的 Docker 配置(
/usr/lib/systemd/system/docker.service
):ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock
-
重启 Docker 并验证:
sudo systemctl daemon-reload && sudo systemctl restart docker docker -H tcp://目标IP:2375 ps # 测试连接
-
在 Portainer UI 中添加 Endpoint:
- 填写目标主机的
IP:2375
,选择Remote
类型,支持 TLS 加密(推荐)。
- 填写目标主机的
特点
- 优点:支持跨网络管理多台主机,无需逐个部署 Portainer。
- 缺点:需开放端口,若未配置 TLS 存在安全风险(如未授权访问)^3。
方式 3:通过 Swarm Manager(集群模式)
原理
- Portainer 连接 Swarm 集群的 Manager 节点,通过 Swarm API 管理所有节点(Worker/Manager)。
实现步骤
-
部署 Portainer 时指定连接 Manager 节点:
docker run -d -p 9000:9000 \ --name portainer \ -v /var/run/docker.sock:/var/run/docker.sock \ portainer/portainer -H tcp://<manager-ip>:2376
-
在 Portainer UI 中添加 Swarm 集群的 Endpoint,选择
Swarm
类型。
特点
- 优点:集中管理所有集群节点,支持服务编排(如扩展服务副本数)。
- 缺点:需提前部署 Swarm 集群,Manager 节点需开放端口(默认
2377
)^4。
方式 4:通过 Kubernetes(混合云环境)
原理
- Portainer 连接 Kubernetes API Server,统一管理 Kubernetes 和 Docker Swarm 混合环境。
实现步骤
- 在 Portainer UI 中添加
Kubernetes
类型 Endpoint,输入 API Server 地址和证书信息。
特点
- 优点:支持多云/混合环境(如同时管理本地 Swarm 和云上的 K8s)。
- 缺点:配置复杂,需处理认证和权限问题。
方式 5:通过 Agent 模式(跨网络/防火墙)
原理
- 在每台目标主机上部署 Portainer Agent(轻量级代理),Portainer Server 通过 Agent 与主机通信。
实现步骤
-
在目标主机运行 Agent:
docker run -d -v /var/run/docker.sock:/var/run/docker.sock \ portainer/agent
-
在 Portainer UI 中添加 Endpoint,选择
Agent
类型,输入 Agent 地址。
特点
- 优点:穿透防火墙,无需直接暴露 Docker 端口,安全性更高。
- 缺点:需为每个主机部署 Agent,增加维护成本^1。
选择建议
- 简单环境:优先选择 Docker Socket(本地管理)或 TCP 端口(远程单主机)。
- 生产集群:使用 Swarm Manager 或 Agent 模式,避免直接暴露 TCP 端口。
- 混合云:通过 Kubernetes 模式统一管理。
- 安全性:始终启用 TLS 加密(如方式 2/3/5)或限制 IP 访问(如方式 1/5)
很明显,方式一不适合一次部署同时管理多个服务器,个人使用不必要上集群这种复杂的方式,所以我选择通过 Docker TCP 端口(远程主机)。
要远程控制必须让远程docker开放tcp端口才行。
配置docker开放tcp端口服务
有两种方式,一个是非加密,一个加密,非加密简单,适合局域网测试用。为了安全可以使用加密通信模式。
非加密模式(简单)
修改配置
直接修改docker配置文件docker.service 路径
usr\lib\systemd\system\docker.service
将ExecStart指令内容由
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
改为
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://172.29.206.19:2375 -H unix:///var/run/docker.sock --containerd=/run/containerd/containerd.sock
其中
tcp://172.29.206.19:2375
改为你自己的ip地址。 然后
重新载入配置,重启docker
重新载入配置(一定要进行,我因为没重新载入,虽然重启docker服务也没有生效,浪费了很多时间排查问题),重启docker
sudo systemctl daemon-reload #必须执行,否则重启docker也无法生效
sudo systemctl restart docker
可以查看docker配置(可选)
sudo systemctl show docker --no-pager
使用systemd-analyze verify验证文件正确性(可选)
$ sudo systemd-analyze verify /usr/lib/systemd/system/docker.service
加密模式(复杂)
与非加密模式的差别在于需要配置证书
修改配置
直接修改docker配置文件docker.service 路径
usr\lib\systemd\system\docker.service
将ExecStart指令内容由
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
改为
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://172.29.206.19:2375 --tlsverify --tlscacert=/etc/docker/docker-tls-server/ca.pem --tlscert=/etc/docker/docker-tls-server/server-cert.pem --tlskey=/etc/docker/docker-tls-server/server-key.pem --containerd=/run/containerd/containerd.sock
其中
tcp://172.29.206.19:2375
改为你自己的ip地址。 里面增加了证书配置。证书需要生成。我写了脚本可以一次性生成服务器和客户端的证书以及根证书。
生成证书脚本(我对sh也不熟,调试很久)
sh脚本保存为generate-docker-tls.sh
#!/bin/bash
export RANDFILE="/tmp/.rnd" # ← 修复 .rnd 路径问题set -euo pipefail
# ========= 配置区 =========
PASSWORD="yourpasswoord" # 改密码!
WORK_DIR="./docker-tls"
CA_DAYS=36500
CERT_DAYS=3650
EXT_FILE="/tmp/extfile.cnf" # ← 修复配置文件路径
# =========================
# 初始化随机种子
mkdir -p /tmp/.rnd
cd "$(dirname "$0")"
mkdir -p "$WORK_DIR"
cd "$WORK_DIR"
rm -f *.pem *.csr *.cnf
echo " 生成 Docker TLS 证书 (Linux版)"
# 1. 生成 CA
openssl genrsa -aes256 -passout "pass:$PASSWORD" -out ca-key.pem 4096
openssl req -new -x509 -days "$CA_DAYS" -passin "pass:$PASSWORD" \
-key ca-key.pem -sha256 -out ca.pem -subj "/CN=MyDockerCA"
# 2. 服务端证书
openssl genrsa -out server-key.pem 4096
openssl req -new -key server-key.pem -out server.csr -subj "/CN=localhost"
# 安全生成配置文件(避免路径问题)
cat > "$EXT_FILE" << 'EOF'
# ← 单引号禁止变量展开
subjectAltName = DNS:localhost,DNS:*,IP:172.29.206.19,IP:127.0.0.1,IP:10.10.10.1,IP:10.10.10.2,IP:10.10.10.10
extendedKeyUsage = serverAuth
EOF
openssl x509 -req -in server.csr -CA ca.pem -CAkey ca-key.pem -passin "pass:$PASSWORD" \
-days "$CERT_DAYS" -sha256 -extfile "$EXT_FILE" -out server-cert.pem
# 3. 客户端证书
openssl genrsa -out key.pem 4096
openssl req -new -key key.pem -out client.csr -subj "/CN=admin"
openssl x509 -req -in client.csr -CA ca.pem -CAkey ca-key.pem -passin "pass:$PASSWORD" \
-days "$CERT_DAYS" -sha256 -out cert.pem
# 清理
rm -f *.csr "$EXT_FILE" # ← 清理绝对路径文件
echo " 成功! 文件列表:"
ls -la
其中
DNS:localhost,DNS:*,IP:172.29.206.19,IP:127.0.0.1,IP:10.10.10.1,IP:10.10.10.2,IP:10.10.10.10
改成你自己的DNS和IP
在linux命令行执行
如果在windows环境下编辑的sh脚本需要进行空白符号转换
dos2unix generate-docker-tls.sh
执行生成脚本
sh generate-docker-tls.sh
生成的证书在docker-tls文件夹下
把server证书上传到上面配置中写的路径下。
不带server标记的证书是客户端证书,一会用于potainer连结用。
potainer添加环境连结已经配置好的tcp
在管理界面点击添加环境
选择standalone并开始
选择api模式,
填写名称和api地址,也就是上面修改docker配置中的地址,之后点击连接即可(非加密模式)。
加密模式需要打开tls开关,并上传刚才生成的客户端证书
正常会提示连接成功,并且环境中会出现刚才添加的远程服务器。
如果连接失败,需要排查你的ip是否正确,远程docker服务端口是否成功开启,本地机器是否能连通远程ip,证书位置类型是不是正确。
然后就可以在这里管理远程的docker了,而不用在登录远程的服务器。可以开始体验docker管理all in one的感觉了。
一些建议
为了安全,建议使用加密模式。 另外我咨询ai说加密模式对性能影响也不大。
将 Docker 的 TCP 接口(-H tcp://...
)启用 TLS 加密,确实会对性能产生一定影响,但具体程度取决于多种因素。以下是针对内网暴露场景的详细分析,帮助你权衡安全与性能的取舍:
启用 TLS 加密的影响
1. 性能影响的核心来源
TLS 加密的开销主要来自以下环节:
环节 | 描述 | 性能损耗 | 可优化性 |
---|---|---|---|
握手阶段(Handshake) | 首次建立连接时的密钥协商、身份验证 | 较高(延迟增加 1-3ms) | 高(会话复用、短连接优化) |
数据传输(Encryption) | 每个数据包应用层的加密/解密 | 低(现代 CPU 支持 AES-NI 加速) | 中(选择轻量级密码套件) |
系统调用(Syscall) | TLS 库的上下文切换和内存拷贝 | 可忽略 | 低 |
📌 关键结论:
- 一次性握手成本是主要开销,但后续数据传输的损耗极低。
- 对于短连接(如 CI/CD 频繁请求),握手占比高;长连接(如 Docker Compose 持续监控)则几乎无感。
2. 内网场景下的实际影响测试数据
以下是基于真实服务器的测试对比(内网 1Gbps 环境,ECDHE-RSA-AES256-GCM-SHA384 套件):
指标 | 无 TLS | 有 TLS | 差异 |
---|---|---|---|
单次 docker ps (本地命令) |
2ms | 4ms | +2ms |
批量创建 100 个容器(短连接) | 12s | 15s | +25% |
批量创建 100 个容器(长连接) | 8s | 9s | +12.5% |
大镜像下载(5GB 镜像) | 120s | 122s | +1.6% |
带宽占用(netstat 统计) |
100Mbps | 100Mbps | 无变化 |
🔍 观察结果:
- 简单操作(如
docker ps
)延迟增加明显(+2ms),但人类无感知。- 批量短连接任务的延迟波动较大(+25%),因频繁握手。
- 长连接或大数据传输(如下载镜像)几乎无影响(+1~2%)。
- 带宽无损耗,TLS 仅增加头部负载(通常 < 1%)。
3. 内网是否真的“安全”?
即使在内网,仍需考虑以下威胁:
风险类型 | 描述 | 防御建议 |
---|---|---|
横向移动攻击 | 内网某台机器被入侵(如漏洞、弱密码)后,攻击者快速控制所有 Docker 主机 | TLS 双向认证 + 防火墙规则 |
员工误操作/内部威胁 | 员工随意运行特权容器、删除服务 | 基于 TLS 的访问控制(证书白名单) |
供应链攻击 | 第三方工具被植入恶意代码,调用 Docker API 提权 | 限制访问源 IP(如 172.29.0.0/24 ) |
嗅探流量 | 内网抓包窃取敏感信息(如 docker exec 执行的密码) |
TLS 加密传输 |
🛡️ TLS 的价值:
- 即使在内网,双向 TLS 认证(
--tlsverify
)可确保:> – 客户端必须提供证书(防止未授权访问)。
- 流量加密(防止抓包窃取)。
- 配置得当后,安全性远超裸奔 TCP 接口。
4. 内网性能优化建议
若追求极致性能,可采取以下优化措施:
(1) 优化 TLS 握手
-
启用会话复用(Session Resumption)
添加--tlscacert
并确保客户端保存会话票据(Ticket):docker --tlsverify \ --tlscacert=ca.pem \ --host=tcp://172.29.0.14:2375 \ ps
效果:第二次连接时,握手时间从 3ms 降至 0.5ms。
-
使用更快的加密套件
在dockerd
启动参数中指定:
--tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
原因:AES-128-GCM 比 AES-256-GCM 快约 20%,且硬件加速更成熟。
(2) 减少短连接
- 改用长连接:
在脚本中使用docker compose
而非频繁的docker run
。
或设置客户端超时(减少重建连接):export DOCKER_CLIENT_TIMEOUT=300
(3) 硬件加速
- 启用 AES-NI(默认开启):
确保 CPU 支持 AES-NI(grep aes /proc/cpuinfo
): “`bash docker info | grep “AES-NI”**效果**:加密吞吐量提升 3-5 倍。
(4) 替代方案
- SSH 隧道(更低开销)
对于远程管理,可通过 SSH 端口转发:
然后本地使用:ssh -L 2375:localhost:2375 user@172.29.0.14
优势:使用成熟的 SSH 加密(OpenSSH 优化极好),性能损耗 < 1%。docker -H tcp://localhost:2375 ps
5. 最终建议
场景 | 推荐方案 | 性能损耗 | 安全性 |
---|---|---|---|
对延迟极度敏感(<1ms) | 裸 TCP + 严格防火墙 | 无 | 中等(依赖网络隔离) |
一般内网(企业/团队环境) | TLS + 会话复用 + AES-128 | +2~5% | 高(防内部威胁) |
生产级内网(多租户/CI-CD) | TLS 双向认证 + 证书轮换 | +5~10% | 极高 |
开发环境(单机测试) | Unix Socket(关闭 TCP) | 无 | 完全安全 |
💡 决策建议:
- 如果内网是可信的封闭环境(如单个服务器+无外部工具),可用裸 TCP + 防火墙(仅限
172.29.0.0/24
)。- 如果有多主机、多用户、第三方工具接入,必须启用 TLS(性能损耗可接受,安全收益显著)。
- 优先尝试 SSH 隧道,它是内网场景下的最佳平衡点。
如有更多性能优化需求(如 Kubernetes 集成、大规模并发),可进一步调整内核参数或升级硬件(如 10Gbps 网卡)。