这学期的Object Oriented Design课程的项目我使用Docker来做打包和部署,过去我都是手动ssh到服务器上执行Docker命令来部署新版本。但是这种方式对CI系统则不太友好,我们的确可以让CI系统使用ssh登录到目标主机并执行Docker命令,但是这样就涉及到密码,密钥及sudo的安全性问题,(主要是不够优雅。
这一次我使用了Docker Remote Host来解决这个问题。Remote Host可以使我们无需ssh登录服务器,仅通过网络即可控制目标主机上的docker daemon。
首先我们需要了解Docker的命令是如何执行的
Docker主要分为两部分,daemon和client。

Docker daemon (dockerd) 监听Docker API的请求,并管理镜像,容器,网络,卷等Docker对象。daemon 也可以和其他Docker daemon通信来管理Docker服务。
Docker client (docker) 是与Docker引擎交互的主要方式。当使用类似于docker run的命令时,client将命令通过Docker API发送到dockerd。
一个Docker client可以控制多个Docker daemon,显然我们也可以使用本地的Docker的Docker client控制远程的Docker daemon。
Docker client与Docker daemon的交互可以通过unix socket或TCP socket。通常情况下使用的是unix socket(/var/run/docker.sock
),如果要使用TCP socket则需要另外做一些配置。
开启Remote Host有三种方式:HTTP,HTTPS和SSH。其中最简单的办法是HTTP Socket。
HTTP
编辑/etc/docker/daemon.json
,如果没有则新建一个。
{"hosts": ["tcp://0.0.0.0:2375", "unix:///var/run/docker.sock"]}
编辑/etc/systemd/system/docker.service.d/override.conf
,如果没有则新建一个。
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd
reload并重启服务
systemctl daemon-reload
systemctl restart docker.service
这时执行netstat -a
应该可以看到Docker daemon在监听0.0.0.0:2375。
确保目标主机防火墙放行了TCP 2375端口,就可以尝试连接远程主机上的Docker daemon了。
docker -H=your.address:2375 version
docker-compose -H=your.address:2375 version
如果能正确打印出目标主机的Docker daemon信息,说明成功。
TLS
由于HTTP是明文协议,并且直接暴露到公网,没有任何的保护,这会带来一些安全问题。所以这里我们使用TLS来保护HTTP。
通常情况下我们需要手动使用OpenSSL来签发证书,但是GitHub上有位朋友提供了一个Docker镜像,我们可以使用这个镜像来自动配置Docker的HTTP Socket及签发证书。
具体请参考这个页面 kekru/docker-remote-api-tls – Docker Hub 的Remote Api with auto generating CA, certificates and keys章节。
当签发了证书并启动这个Docker容器之后,容器会启动一个被TLS保护的socket来接受来自Docker client的请求,并将请求通过Unix socker传给宿主机上的Docker daemon。
因为这堆参数太长了,我们使用alias来配置Docker客户端
alias dockerx="docker \
--tlsverify \
-H=your-remote-server.org:2376 \
--tlscacert=/home/me/docker-tls/ca.pem \
--tlscert=/home/me/docker-tls/cert.pem \
--tlskey=/home/me/docker-tls/key.pem"
dockerx version
SSH
平时使用docker时,需要使用sudo才有权限访问docker daemon,而在通过ssh访问docker daemon时显然是不能使用sudo的,所以我们需要新建一个用户,并将其加入docker
组。
新建一个用户,这里给新用户命名为dockerdaemon
useradd dockerdaemon
将新用户加入docker组
usermod -aG docker dockerdaemon
然后使用su切换至新建的用户,生成密钥对并将SSH配置为密钥登录,具体步骤参考文中的Step1: How to Set Up SSH Keys on Ubuntu 18.04 | DigitalOcean 。
这会在~/.ssh
中生成两个文件:id_rsa
和id_rsa.pub
,其中前者是私钥,后者是公钥。
如果有兴趣了解ssh密钥对认证的原理,请参考: Understanding the SSH Encryption and Connection Process | DigitalOcean
我们需要将生成的公钥添加到authorized_keys
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
然后把私钥下载到本地。
使用ssh-agent将私钥安装至本机。
eval $(ssh-agent -s)
echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
测试Docker连接
docker -H=ssh://[email protected] version
如果有显示出目标主机的Docker信息则成功。
如果要在GitLab CI中使用,请参考: Using SSH keys with GitLab CI/CD | GitLab
References
https://docs.docker.com/get-started/overview/
https://docs.docker.com/config/daemon/systemd/
https://gist.github.com/kekru/4e6d49b4290a4eebc7b597c07eaf61f2
发表回复/Leave a Reply