Dokcer 的远程连接和部署
让远程部署和本地一样简单!
TL;DR
- Docker 是 C/S 架构的,服务端和客户端可以在不同主机运行
- 无加密的 TCP 连接配置简单,但不安全
- TLS 加密的连接需要创建和配置证书,最常用
- SSH 连接使用方便,但是 IDE 不大兼容,比较局限
- 命令行、IDEA、VS Code 怎么连接 Docker daemon
- 一个小 demo,用 Dokcer client 部署 Spring Boot 项目
20220913 更新:现在 SSH 连接的方式已经被大部分软件支持了,别的方式的可以不用看了。
Docker 的架构
最近在学习用 Docker 来部署项目。我按照这个教程来把 Java 项目部署到了服务器的 Docker 上面。IDEA 的 Dokcer 插件真的是特别方便,配置好之后一键就能部署上去,而且 Windows 本机上也不需要安装几百兆的 Docker Desktop,不用开启 Hyper-V。这是怎么实现的呢?
从 Docker 的官方文档里面可以看到,Docker 使用的是 C/S 架构的系统,分为客户端和服务端。客户端(Docker client)使用命令和服务端(Dokcer daemon,守护进程)进行交互。守护进程负责干重活,比如构建、运行和分发你的容器。客户端和守护进程可以运行在同一台主机,也就是我们常规的安装;也可以让客户端连接到一台远程的守护进程。客户端和守护进程使用 REST API 进行交互,通过 UNIX sockets 或者网络接口进行传输。
所以我们如果只需要连接远程服务器的 Docker 的话,就没有必要在本地安装完整的 Docker,不需要安装 Docker daemon,只需要有能与 Docker daemon 进行交互的客户端,比如 Docker client,就可以了。
连接 Docker daemon
在默认的设置下,Docker daemon 只监听来自本地的 UNIX socket 连接。
在 /lib/systemd/system/docker.service
下面可以看到
dockerd
,即 Docker daemon 的启动参数:
1 | ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock |
我们需要修改这个 systemd
的启动参数来开启外部访问。
使用无加密 TCP 连接
使用
sudo systemctl edit docker.service
来编辑docker.service
,这会在它的基础上重写配置。写上下面的内容,保存文件。
1
2
3[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375上面这个
ExecStart=
的作用是清空原来项目的值,然后用新的值替代。官方文档这么写的,我之前还以为是笔误……更新 systemctl 配置和重启 Docker。
1
2sudo systemctl daemon-reload
sudo systemctl restart docker.service检查 dockerd 是否运行起来
1
sudo netstat -lntp | grep dockerd
现在我们已经开放了 TCP 的 2375 端口,只要在执行命令的时候加上参数就可以了:
1 | docker -H tcp://docker.beanbang.cn:2375 version |
也可以设置环境变量
DOCKER_HOST
,这样就不用每次都带参数:
1 | export DOCKER_HOST=tcp://docker.beanbang.cn:2375 |
注意:使用这种连接方式是不安全的,端口并没有加密,这意味者任何人都可以连接你的 Docker daemon,往里面运行容器。虚拟机用还好,云服务器上要是被别有用心的人发现了不是纯白给了。所以加密你的 Docker 端口还是很有必要的。
使用 TLS 加密的 TCP 连接
需要使用 OpenSSL 生成密钥,证书。客户端和守护进程使用这些证书和密钥来进行认证。只要照着官方文档的这篇文章,一步一步做下来就可以了:
生成证书的大致过程是,生成 CA 的密钥和 CA 证书,生成客户端和服务端的密钥;生成客户端和服务端的签名请求,然后 CA 分别对客户端和服务端的签名请求生成证书。
跟着教程一顿操作之后,可以得到下面的几个文件。
文件 | 描述 |
---|---|
ca-key.pem | CA 密钥 |
ca.pem | CA 证书 |
server-key.pem | 服务端密钥 |
server-cert.pem | 服务端证书 |
key.pem | 客户端密钥 |
cert.pem | 客户端证书 |
然后我们接着修改 docker.service。虽然可以这么写:
1 | sudo systemctl edit docker.service |
1 | [Service] |
不过,这样大长串的参数很不直观。下面我们换成使用 Docker
提供的另一种配置 dockerd 的方式,就是 daemon.json
文件。
1 | sudo vim /etc/docker/daemon.json |
1 | { |
原本的 docker.service 只保留一点东西:
1 | sudo vim /etc/docker/daemon.json |
1 | [Service] |
然后重启 Docker 就可以了。
注意:Docker 在启动的时候会同时使用
systemd
和 daemon.json
文件。如果两个文件的配置项冲突了,会造成无法启动。所以配置要么写
docker.service 里面,要么写 daemon.json
里面,不要两个都写,防止出现问题。
注意2:按照惯例,不加密的 TCP 连接使用 2375 端口,TLS 加密的 TCP 连接使用 2376 端口。
运行起来后,客户端连接需要 ca.pem,cert.pem,key.pem
三个文件。我们可以把它们从主机上拷贝下来,放在自己用户目录的
.docker
目录下,这是证书文件的默认查找目录。
纯命令:
1 | docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem \ |
使用环境变量:
1 | export DOCKER_HOST=tcp://docker.beanbang.cn:2376 DOCKER_TLS_VERIFY=1 |
使用 SSH 连接
从 Docker 的 18.09 版本开始,Docker client 支持通过 SSH 来连接远程 daemon 了。但是到了今天(2020年8月),我能直接下载到的最新 Dokcer client for Windows 版本是 17.09。IDEA 和 VS Code 这些 IDE 我也试过,同样不能使用 SSH 协议来连接。所以这种方法虽然特别方便,但是目前还是比较有局限性的。
要使用 SSH 协议来连接 Docker daemon,你可以使用 Linux 或者 WSL 安装新版的 docker-cli。
服务端不需要任何配置,只需要在客户端执行命令:
1 | docker -H ssh://ubuntu@192.168.43.220 version |
注意,这边主机名只能使用 IP 地址,不能使用域名。
这种方式是使用 SSH 密钥登录和认证的,如果你没有使用密钥来登录主机,可以现配置一个:
检查一下你的用户目录下的
.ssh
文件夹下面有没有id_rsa
和id_rsa.pub
文件。如果你在用 Git,可能已经创建过密钥了。没有的话就创建:
1
ssh-keygen -t rsa -C "youremail@example.com"
把你的公钥添加到远程主机:
1
ssh-copy-id ubuntu@192.168.43.220
Windows 没有这个命令的话就手动把
id_rsa.pub
里面的内容添加到远程主机用户的~/.ssh/authorized_keys
里面。
这就行了。同样可以把这个连接串设置到环境变量中,方便使用:
1 | export DOCKER_HOST=ssh://ubuntu@192.168.43.220 |
客户端配置
命令行
Windows
直接安装 Docker desktop 是可以的,安装完成之后就可以使用 docker 命令了。但是假如我们本地只想用客户端的功能,不想安装它那厚重的 Docker Engine,可以只下载几个二进制可执行文件。下面是下载地址:
Docker CLI Windows:https://download.docker.com/win/static/stable/x86_64/
Docker compose:https://github.com/docker/compose/releases
下载完成后,重命名成 docker.exe
和
docker-compose.exe
,丢进设置过 Path
环境变量的文件夹里就可以了。
Linux
Linux 客户端只需要安装 docker-ce-cli
。这里推荐一下清华 tuna
镜像源,提供了 docker-ce 的镜像和安装教程。
IntelliJ IDEA
IDEA 里面图形化的设置很方便。如果使用了加密的
TCP,要选定证书的文件夹,并且 URL 要写成
https://docker.beanbang.cn:2376
这样的以 https
开头的形式。
VS Code
首先安装 Docker 插件,然后修改配置文件。
1 | // settings.json |
试试看!
连接上远程 Docker 之后,我们就可以尝试远程部署了。这是一个例子,在 Windows 10 上用 Dokcer CLI 部署一个 Spring Boot 项目到远程服务器上。我使用的是 TLS 加密的 TCP,就是上面的提到的配置。
环境变量:
1 | $ set | findstr DOCKER |
在 Spring initializr 上面创建项目并下载到本地。
添加一个控制器:
1 | package cn.beanbang.demo.controller; |
执行 mvnw package
命令打包。会在 target
目录下生成 rest-test-0.0.1-SNAPSHOT.jar
文件。
在项目的目录下创建 Dockerfile
文件:
1 | FROM openjdk:8-jre |
然后可以开始部署了。
创建容器:
1 | $ docker build -t rest-test . |
运行容器:
1 | $ docker run --name rest-demo -p 8081:8080 -d rest-test |
这样,一个简单的 Java Web 服务就搭建起来了。在执行
docker build
命令的时候,Docker
会把构建所需要的文件上传到服务端的 daemon,然后 daemon
负责创建镜像和后续的容器运行等流程。
参见: