Docker是目前很流行的一个平台工具。虽然我比较喜欢用命令行使用docker,但是用类似Portainer的可视化面板管理docker也是个不错的选择,检查docker的配置和状态都非常便捷。

Portainer不止能管理本机的docker,通过docker api ,进行一定的配置,可以通过网络远程连接和管理其它机器上的docker容器。具体教程可以参见以下两个链接:

Docker开启TLS和CA认证 配置Docker 远程访问TLS 认证 - 乌帮图

但是每次新建一台VPS后,按照这些命令输入来开启docker的远程访问实在是太繁琐了,于是我整理了一下相关命令,编制了一个脚本,一键执行来完成相关配置。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
#!/bin/bash

root_need(){
    if [[ $EUID -ne 0 ]]; then
        echo "Error:这个脚本必须以root身份运行!"
        exit 1
    fi
}

# 检查docker是否已经安装
if ! command -v docker &> /dev/null
then
    echo "Docker未安装,开始安装Docker..."
    # 安装Docker
    wget -qO- get.docker.com | bash

    systemctl enable docker
    # 输出安装结果
    docker --version
else
    echo "Docker已经安装"
    # 输出Docker版本
    docker --version
fi

# 获取主机的 IP 地址
IP=$(curl -s http://ipv4.icanhazip.com)

# 设置证书目录
CERT_DIR="/root/docker_data/ca"
mkdir -p "$CERT_DIR"

# 生成 CA 证书
openssl genrsa -aes256 -passout pass:changepasswd -out "$CERT_DIR/ca-key.pem" 4096
openssl req -new -x509 -days 365 -key "$CERT_DIR/ca-key.pem" -passin pass:changepasswd -sha256 -out "$CERT_DIR/ca.pem" \
-subj "/C=US/ST=New York/L=New York/O=Example Company/OU=IT Department/CN=example.com/[email protected]"

# 生成服务器证书
openssl genrsa -out "$CERT_DIR/server-key.pem" 4096
openssl req -subj "/CN=$(hostname)" -sha256 -new -key "$CERT_DIR/server-key.pem" -out "$CERT_DIR/server.csr"
echo "subjectAltName = DNS:$(hostname),IP:$IP" > "$CERT_DIR/extfile.cnf"

read -p "你想添加一个受信任的域名吗? (y/n): " add_domain
if [ "$add_domain" == "y" ]; then
    read -p "输入域名: " domain_name
    echo "subjectAltName = DNS:$domain_name" >> "$CERT_DIR/extfile.cnf"
    echo "将$domain_name添加到受信任域列表中"
else
    echo "跳过将域添加到受信任域列表的步骤"
fi

echo "extendedKeyUsage = serverAuth" >> "$CERT_DIR/extfile.cnf"
openssl x509 -req -days 365 -sha256 -in "$CERT_DIR/server.csr" -CA "$CERT_DIR/ca.pem" -CAkey "$CERT_DIR/ca-key.pem" -CAcreateserial -out "$CERT_DIR/server-cert.pem" -extfile "$CERT_DIR/extfile.cnf" -passin pass:changepasswd

# 生成客户端证书
openssl genrsa -out "$CERT_DIR/client-key.pem" 4096
openssl req -subj '/CN=client' -new -key "$CERT_DIR/client-key.pem" -out "$CERT_DIR/client.csr"
echo "extendedKeyUsage = clientAuth" > "$CERT_DIR/client-extfile.cnf"
openssl x509 -req -days 365 -sha256 -in "$CERT_DIR/client.csr" -CA "$CERT_DIR/ca.pem" -CAkey "$CERT_DIR/ca-key.pem" -CAcreateserial -out "$CERT_DIR/client-cert.pem" -extfile "$CERT_DIR/client-extfile.cnf" -passin pass:changepasswd

# 生成 Docker 配置文件
cp /usr/lib/systemd/system/docker.service /usr/lib/systemd/system/docker.service.bak
sed -i "s|^ExecStart=.*$|ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2376 -H fd:// --containerd=/run/containerd/containerd.sock --tlsverify --tlscacert=${CERT_DIR}/ca.pem --tlscert=${CERT_DIR}/server-cert.pem --tlskey=${CERT_DIR}/server-key.pem|" /usr/lib/systemd/system/docker.service

# 重新加载 Docker 服务
systemctl daemon-reload
systemctl restart docker

# 检查 Docker 服务是否正常启动
if systemctl is-active --quiet docker; then
   echo -e "Docker TLS配置已经成功完成。"
else
# Docker 服务启动失败, 恢复原配置并报错
   echo "Error: docker服务启动失败。恢复到原来的配置..."
   cp /usr/lib/systemd/system/docker.service.bak /usr/lib/systemd/system/docker.service
   systemctl daemon-reload
   systemctl restart docker
   echo "docker服务已被恢复到原始配置。"
   exit 1
fi

# 配置证书自动更新脚本
cat > $CERT_DIR/renewcert.sh <<'EOF'
#!/bin/bash
CURRENT_TIME=$(date +"%F %T")

# check if CA certificate is expired
if openssl x509 -checkend 1728000 -noout -in $(dirname "$0")/ca.pem; then
  echo "[$CURRENT_TIME] CA certificate is still valid" >> $(dirname "$0")/crontab_log.txt
else
  echo "[$CURRENT_TIME] CA certificate has expired. Renewing all certificates..." >> $(dirname "$0")/crontab_log.txt

  # regenerate server and client certificates using existing CA

  openssl req -new -x509 -days 365 -key "$(dirname "$0")/ca-key.pem" -passin pass:changepasswd -sha256 -out "$(dirname "$0")/ca.pem" \
-subj "/C=US/ST=New York/L=New York/O=Example Company/OU=IT Department/CN=example.com/[email protected]"

  openssl x509 -req -days 365 -sha256 -in "$(dirname "$0")/server.csr" -CA "$(dirname "$0")/ca.pem" -CAkey "$(dirname "$0")/ca-key.pem" -CAcreateserial -out "$(dirname "$0")/server-cert.pem" -extfile "$(dirname "$0")/extfile.cnf" -passin pass:changepasswd

  openssl x509 -req -days 365 -sha256 -in "$(dirname "$0")/client.csr" -CA "$(dirname "$0")/ca.pem" -CAkey "$(dirname "$0")/ca-key.pem" -CAcreateserial -out "$(dirname "$0")/client-cert.pem" -extfile "$(dirname "$0")/client-extfile.cnf" -passin pass:changepasswd

   systemctl daemon-reload
   systemctl restart docker

  echo "[$CURRENT_TIME] All certificates have been renewed" >> $(dirname "$0")/crontab_log.txt
fi
EOF

# 配置脚本定时任务
chmod +x $CERT_DIR/renewcert.sh
crontab -l | { cat; echo "0 0 */15 * * bash $CERT_DIR/renewcert.sh"; } | crontab -

执行成功后应该如下图所示:

shell

注意: 1、添加受信任域名适用于仅IPV6地址的VPS,如果VPS有ipv4公网地址可以不添加。 2、脚本适用于debian系统,其它系统请自行修改。 3、docker如果更新,/usr/lib/systemd/system/docker.service这个文件会重置,导致远程访问服务被关闭,有时间我再优化一下脚本吧,偷懒~

脚本执行完成后,docker api 运行于2376端口,如果有防火墙的话记得放行此端口。

把/root/docker_data/ca目录下的ca.pem, client-cert.pem, client-key.pem共三个文件下载下来。

打开portainer页面,进入Environment选项卡。

portainer page

把上图进行配置即可连接docker环境了。