Jenkins借助Docker API自签证书实现远程部署
生成自签TLS证书
首先创建证书存放目录:
mkdir -p /etc/docker/certs
cd /etc/docker/certs
执行以下命令序列生成CA证书、服务端证书和客户端证书:
# 生成CA私钥和证书
openssl genrsa -aes256 -out ca-key.pem 4096
openssl req -new -x509 -days 3650 -key ca-key.pem -sha256 -out ca.pem
# 生成服务端证书
openssl genrsa -out server-key.pem 4096
openssl req -subj "/CN=server" -sha256 -new -key server-key.pem -out server.csr
# 创建扩展配置文件并签署服务端证书
echo subjectAltName = DNS:223.5.5.5,IP:106.14.114.xx,IP:172.22.xx.xx,IP:127.0.0.1 > extfile.cnf
echo extendedKeyUsage = serverAuth >> extfile.cnf
openssl x509 -req -days 3650 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf
# 生成客户端证书
openssl genrsa -out key.pem 4096
openssl req -subj '/CN=client' -new -key key.pem -out client.csr
echo extendedKeyUsage = clientAuth > extfile-client.cnf
openssl x509 -req -days 3650 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile-client.cnf
# 清理临时文件并设置权限
rm -f client.csr server.csr extfile.cnf extfile-client.cnf
chmod 0400 ca-key.pem key.pem server-key.pem
chmod 0444 ca.pem server-cert.pem cert.pem
注意替换extfile.cnf中的IP为实际内外网地址。
配置Docker守护进程
编辑Docker systemd服务单元文件:
vim /lib/systemd/system/docker.service
在[Service]段修改为:
ExecStart=
ExecStart=/usr/bin/dockerd --tlsverify \
--tlscacert=/etc/docker/certs/ca.pem \
--tlscert=/etc/docker/certs/server-cert.pem \
--tlskey=/etc/docker/certs/server-key.pem \
-H fd:// -H tcp://0.0.0.0:2376
重新加载并启动Docker服务:
systemctl enable docker.service
systemctl daemon-reload
systemctl start docker.service
systemctl status docker.service
验证API端口监听状态:
netstat -lntp | grep dockerd
Jenkins证书配置
- 在Jenkins凭据管理中,添加类型为Certificate的凭据,分别上传
ca.pem、cert.pem和key.pem三个文件,并命名如docker-cert。 - 在系统设置中配置Docker Cloud,启用TLS验证,选择刚创建的证书凭据,设置Docker主机URL为
tcp://你的服务器IP:2376。

创建Pipeline任务
- 新建任务,选择"流水线"类型。
- 在"流水线"定义中选择"Pipeline script from SCM"。
- SCM选择Git,填写仓库地址和凭据,指定Jenkinsfile路径,并取消"轻量级检出"选项。
Jenkinsfile示例
stage('Deploy to Docker') {
environment {
// 引用客户端证书凭据,对应Jenkins中创建的凭据ID
DOCKER_CERT_PATH = credentials('docker-cert')
}
steps {
script {
def containerPort = params.container_port ?: 80
def portMapping = containerPort ? " -p ${containerPort}:80 " : ""
def dockerRemotes = params.docker_remotes?.split(',') ?: []
dockerRemotes.each { remote ->
sh """
export DOCKER_TLS_VERIFY=1
export DOCKER_HOST=tcp://${remote}:2377
docker rm -f ${DOMAIN_NAME} || true
docker run -d --name ${DOMAIN_NAME} --restart=always \
-e TZ='Asia/Shanghai' \
-e CONTAINER_PORT=${containerPort} \
-m ${params.LIMIT_MEMORY}M \
${portMapping} \
-v /etc/localtime:/etc/localtime:ro \
${DOCKER_IMAGE}
echo "清理旧镜像"
docker images ${IMAGE_NAME} -q --filter before=${DOCKER_IMAGE} | xargs --no-run-if-empty docker rmi
"""
}
}
}
}
部署说明
- 任务参数
container_port指定容器内部端口(默认80),docker_remotes为逗号分隔的远程Docker主机IP列表。 - 环境变量
DOCKER_CERT_PATH由Jenkins自动注入,指向包含三个证书文件的临时目录。 - 若不需要TLS验证,可移除
DOCKER_TLS_VERIFY=1及相关证书配置,但不建议在生产环境这样做。