前言
在 Docker 常用详解指令 一文中粗粗提了一下, Docker 是分为客户端和服务端两部分的, 本文将介绍客户端是如何连接服务端的。
连接方式
1. UNIX域套接字
默认就是这种方式, 会生成一个 /var/run/docker.sock 文件, UNIX 域套接字用于本地进程之间的通讯, 这种方式相比于网络套接字效率更高, 但局限性就是只能被本地的客户端访问。
2. TCP 端口监听
服务端开启端口监听:dockerd -H IP:PORT
客户端通过指定的 IP 和 端口 访问服务端:docker -H IP:PORT
通过这种方式, 任何人只要知道了你暴露的 IP 和 端口 就能随意访问你的 Docker 服务了, 这是一件很危险的事, 因为 docker 的权限很高, 不法分子可以从这突破取得服务端 宿主机 的最高权限。
相关:一个回车键黑掉一台服务器
3. 可以同时监听多个 socket
ubuntu@VM-84-201-ubuntu:/usr/anyesu/docker$ sudo dockerd -H unix:///var/run/docker.sock -H tcp://127.0.0.1:2376 -H tcp://127.0.0.1:2377
...
INFO[0004] API listen on 127.0.0.1:2377
INFO[0004] API listen on /var/run/docker.sock
INFO[0004] API listen on 127.0.0.1:2376
启用 TLS 安全连接
上面介绍了普通的 HTTP 方式远程连接很不安全, 解决的办法很简单, 就是启用 TLS 证书实现客户端和服务端的双向认证, 以此来保证安全性。
创建 TLS 证书 ( 根证书、服务端证书、客户端证书 )
cd /usr/anyesu/docker
# 内容比较多, 就写成一个shell脚本, 将需要绑定的服务端ip或域名做参数传入即可
vi tlscert.sh
脚本内容如下:
#!/bin/bash
# @author: anyesu
if [ $# != 1 ] ; then
echo "USAGE: $0 [HOST_IP]"
exit 1;
fi
#============================================#
# 下面为证书密钥及相关信息配置,注意修改 #
#============================================#
PASSWORD="8#QBD2$!EmED&QxK"
COUNTRY=CN
PROVINCE=yourprovince
CITY=yourcity
ORGANIZATION=yourorganization
GROUP=yourgroup
NAME=yourname
HOST=$1
SUBJ="/C=$COUNTRY/ST=$PROVINCE/L=$CITY/O=$ORGANIZATION/OU=$GROUP/CN=$HOST"
echo "your host is: $1"
# 1.生成根证书RSA私钥,PASSWORD作为私钥文件的密码
openssl genrsa -passout pass:$PASSWORD -aes256 -out ca-key.pem 4096
# 2.用根证书RSA私钥生成自签名的根证书
openssl req -passin pass:$PASSWORD -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem -subj $SUBJ
#============================================#
# 用根证书签发server端证书 #
#============================================#
# 3.生成服务端私钥
openssl genrsa -out server-key.pem 4096
# 4.生成服务端证书请求文件
openssl req -new -sha256 -key server-key.pem -out server.csr -subj "/CN=$HOST"
# 5.使tls连接能通过ip地址方式,绑定IP
echo subjectAltName = IP:127.0.0.1,IP:$HOST > extfile.cnf
# 6.使用根证书签发服务端证书
openssl x509 -passin pass:$PASSWORD -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf
#============================================#
# 用根证书签发client端证书 #
#============================================#
# 7.生成客户端私钥
openssl genrsa -out key.pem 4096
# 8.生成客户端证书请求文件
openssl req -subj '/CN=client' -new -key key.pem -out client.csr
# 9.客户端证书配置文件
echo extendedKeyUsage = clientAuth > extfile.cnf
# 10.使用根证书签发客户端证书
openssl x509 -passin pass:$PASSWORD -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile.cnf
#============================================#
# 清理 #
#============================================#
# 删除中间文件
rm -f client.csr server.csr ca.srl extfile.cnf
# 转移目录
mkdir client server
cp {ca,cert,key}.pem client
cp {ca,server-cert,server-key}.pem server
rm {cert,key,server-cert,server-key}.pem
# 设置私钥权限为只读
chmod -f 0400 ca-key.pem server/server-key.pem client/key.pem
执行服务端配置
# 给脚本添加运行权限
chmod +x tlscert.sh
HOST_IP=127.0.0.1
./tlscert.sh $HOST_IP
# 客户端需要的证书保存在client目录下, 服务端需要的证书保存在server目录下
sudo cp server/* /etc/docker
# 修改配置
sudo vi /etc/default/docker
# 改为 DOCKER_OPTS="--selinux-enabled --tlsverify --tlscacert=/etc/docker/ca.pem --tlscert=/etc/docker/server-cert.pem --tlskey=/etc/docker/server-key.pem -H=unix:///var/run/docker.sock -H=0.0.0.0:2375"
# 重启docker
sudo service docker restart
关于 Ubuntu 16.04.2 LTS 下DOCKER_OPTS 不生效的问题解决
接着按之前的方式连接服务端就出错了,说明 TLS 已经生效了。
ubuntu@VM-84-201-ubuntu:/usr/anyesu/docker$ docker -H tcp://127.0.0.1:2375 version
Get http://127.0.0.1:2375/v1.29/version: malformed HTTP response "\x15\x03\x01\x00\x02\x02".
* Are you trying to connect to a TLS-enabled daemon without TLS?
正确的访问方式:
# 客户端加tls参数访问
docker --tlsverify --tlscacert=client/ca.pem --tlscert=client/cert.pem --tlskey=client/key.pem -H tcp://127.0.0.1:2375 version
# Docker API方式访问
curl https://127.0.0.1:2375/images/json --cert client/cert.pem --key client/key.pem --cacert client/ca.pem
# 简化客户端调用参数配置
sudo cp client/* ~/.docker
# 追加环境变量
echo -e "export DOCKER_HOST=tcp://$HOST_IP:2375 DOCKER_TLS_VERIFY=1" >> ~/.bashrc
sudo docker version
切记, 要保护好客户端证书, 这是连接服务端的凭证。另外根证书私钥也要保存好, 泄漏之后就能签发客户端证书了。
认证模式
1. 服务端认证模式
选项 | 说明 |
---|---|
tlsverify, tlscacert, tlscert, tlskey | 向客户端发送服务端证书, 校验客户端证书是否由指定的 CA ( 自签名根证书 ) 签发 |
tls, tlscert, tlskey | 向客户端发送服务端证书, 不校验客户端证书是否由指定的 CA ( 自签名根证书 ) 签发 |
2. 客户端认证模式
选项 | 说明 |
---|---|
tls | 校验服务端证书是否由 公共的 CA 机构签发 |
tlsverify, tlscacert | 校验服务端证书是否由指定的 CA ( 自签名根证书 ) 签发 |
tls, tlscert, tlskey | 使用客户端证书进行身份验证, 但不校验服务端证书是否由指定的 CA ( 自签名根证书 ) 签发 |
tlsverify, tlscacert, tlscert, tlskey | 使用客户端证书进行身份验证且校验服务端证书是否由指定的 CA ( 自签名根证书 ) 签发 |
关于远程构建命令
在之前的文章中介绍了 使用 Docker Compose 构建容器 , 学了今天的内容之后可以连接远程 Docker Daemon 进行构建, 不过需要注意的一点是, 构建需要的配置文件、依赖文件等都需要在客户端准备好, 然后会把这些内容传输到服务端执行构建或运行容器。
另外, win10 下的 WSL 也可以安装 Docker ( 不过可能是因为早期版本子系统的缘故, Docker 服务端跑不起来, 只能运行 Docker 客户端, 前段时间的 创意者更新 中可能有所改进, 不过还未尝试 ), 通过 Docker 客户端连接远程 Docker 服务 假装 体验下 Docker 也是不错的。