Docker Daemon连接方式详解

96
anyesu
0.1 2017.06.30 02:47* 字数 773

前言


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不生效的问题解决

接着按之前的方式连接服务端就出错了

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也是不错的。

参考文章


系列文章


Docker 学习总结

Docker 常用指令详解

使用Dockerfile构建镜像

使用Docker-compose构建容器

Docker下的网络模式


转载请注明出处:http://www.jianshu.com/p/7ba1a93e6de4

Docker
Web note ad 1