potainer管理多服务器容器教程

本文最后更新于 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 守护进程通信。

实现步骤

  1. 修改目标主机的 Docker 配置/usr/lib/systemd/system/docker.service):

    ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock
    
  2. 重启 Docker 并验证

    sudo systemctl daemon-reload && sudo systemctl restart docker
    docker -H tcp://目标IP:2375 ps  # 测试连接
    
  3. 在 Portainer UI 中添加 Endpoint

    • 填写目标主机的 IP:2375,选择 Remote 类型,支持 TLS 加密(推荐)。

特点

  • 优点:支持跨网络管理多台主机,无需逐个部署 Portainer。
  • 缺点:需开放端口,若未配置 TLS 存在安全风险(如未授权访问)^3

方式 3:通过 Swarm Manager(集群模式)

原理

  • Portainer 连接 Swarm 集群的 Manager 节点,通过 Swarm API 管理所有节点(Worker/Manager)。

实现步骤

  1. 部署 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
    
  2. 在 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 与主机通信。

实现步骤

  1. 在目标主机运行 Agent:

    docker run -d -v /var/run/docker.sock:/var/run/docker.sock \
      portainer/agent
    
  2. 在 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
    
    然后本地使用:
    docker -H tcp://localhost:2375 ps
    
    优势:使用成熟的 SSH 加密(OpenSSH 优化极好),性能损耗 < 1%。

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 网卡)。