Docker桌面版安裝包括了Docker Client和Docker Engine。但Docker Engine不但污染了我純潔的小本本還占據(jù)了幾十個(gè)G的硬盤空間,真是萬(wàn)惡。所以我刪除了桌面版的Docker,僅在筆記本上安裝客戶端,通過(guò)客戶端連接云主機(jī)的Docker Engine。下面我來(lái)整理一下過(guò)程。
安裝Docker客戶端
在安裝Docker的時(shí)候,我們并不需要安裝官網(wǎng)提供的標(biāo)準(zhǔn)安裝包,因?yàn)槟前?code>Docker Engine和Docker Client。
所以我們需要安裝的是docker-toolbox。MacOS可以通過(guò)brew search docker-toolbox找到,其他系統(tǒng)可以通過(guò)github下載https://github.com/docker/toolbox/releases
開(kāi)始安裝 Docker 客戶端。
$ brew cask install docker-toolbox
docker-toolbox包含以下幾部分內(nèi)容
- docker-cli : 客戶端命令行,目前的版本是19.03.1
- docker-machine : 可以在本機(jī)啟動(dòng)用于Docker Engine虛擬機(jī)并管理他們
- docker-compose : docker提供的編排工具,支持compose文件,這個(gè)并不常用。
- Kitematic : Docker的客戶端GUI,官方已經(jīng)廢棄了。
- Boot2Docker ISO : 用于創(chuàng)建Docker Engine虛擬機(jī)的鏡像。由于包中的這個(gè)版本并不是最新的,所以創(chuàng)建虛擬機(jī)的時(shí)候可能會(huì)需要重新下載。
- VirtualBox : 虛擬機(jī)
連接遠(yuǎn)程 Docker Engine
本文先不介紹Docker服務(wù)器如何部署。我們假定服務(wù)器已經(jīng)部署完畢,從開(kāi)啟遠(yuǎn)程連接端口開(kāi)始介紹。
服務(wù)器環(huán)境
- Ubuntu 18.04.3 LTS bionic (AWS免費(fèi)EC2服務(wù)器)
- Docker Version
Server: Docker Engine - Community
??Engine:
????Version: 19.03.5
開(kāi)啟遠(yuǎn)程連接端口
Docker的Client和Engine之間的通訊有一下幾種方式
Unix Socket
這是類unix系統(tǒng)進(jìn)程間通訊的一種方式,當(dāng)Client操作本機(jī)的Engine是就是使用這種方式。缺省的socket文件是unix:///var/run/docker.sockSystemd socket activation :
這是systemd提供的一種為了服務(wù)并行啟動(dòng)設(shè)計(jì)的socket,缺省值為fd://
對(duì)這個(gè)技術(shù)感興趣的小伙伴可以進(jìn)一步了解一下。
http://0pointer.de/blog/projects/socket-activation.html
這還有一篇中文的文章講解的不錯(cuò)
https://segmentfault.com/a/1190000017132823?utm_source=tag-newestTCP :
上面兩種都是只能連接本地Engine,需要連接遠(yuǎn)程Engine,必須在服務(wù)端開(kāi)始TCP連接。此連接為不安全連接,數(shù)據(jù)通過(guò)明文進(jìn)行傳輸。缺省端口2375。TCP_TLS :
在TCP的基礎(chǔ)之上加上了SSL的安全證書(shū),以保證連接安全。缺省端口2376。
不加密的TCP連接
我們先開(kāi)啟一個(gè)簡(jiǎn)單的TCP連接測(cè)試一下Docker Engine
登錄遠(yuǎn)程服務(wù)器
$ ssh <server-name-in-ssh-config>
我們的操作涉及兩個(gè)配置文件
-
<?>/systemd/system/docker.service
docker的系統(tǒng)服務(wù)腳本文件。此文件是通過(guò)systemctl命令啟動(dòng)或停止服務(wù)時(shí)執(zhí)行的腳本。
在不同系統(tǒng)中,此文件的路徑不同。我們可以通過(guò)命令來(lái)查看$ sudo systemctl status docker|grep Loaded|grep -Po '(?<=Loaded: loaded \()[^;]*' /lib/systemd/system/docker.service /etc/docker/daemon.json
dockerd命令對(duì)應(yīng)的配置文件。dockerd命令是Docker Engine的啟動(dòng)命令。啟動(dòng)時(shí)的參數(shù)可以通過(guò)命令行參數(shù)提供,也可以通過(guò)此配置文件提供。具體信息可以參考官方文檔
https://docs.docker.com/engine/reference/commandline/dockerd/
先打開(kāi)docker.service,并找到Engine的啟動(dòng)命令
$ sudo cat $(systemctl status docker|grep Loaded|grep -Po '(?<=Loaded: loaded \()[^;]*')|grep dockerd
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
可以看到這個(gè)參數(shù)-H fd://,意思是啟用socket activation作為客戶端接口。
我們要把它刪掉。因?yàn)楣俜降奈臋n中介紹說(shuō):
Note: You cannot set options in daemon.json that have already been set on daemon startup as a flag. On systems that use systemd to start the Docker daemon, -H is already set, so you cannot use the hosts key in daemon.json to add listening addresses. See https://docs.docker.com/engine/admin/systemd/#custom-docker-daemon-options for how to accomplish this task with a systemd drop-in file.
靈魂翻譯:在命令行設(shè)置的參數(shù),不能在daemon.json中進(jìn)行設(shè)置。嗯,就是這樣。
$ # 先備份docker.service
$ SERVICE_FILE=$(systemctl status docker|grep Loaded|grep -Po '(?<=Loaded: loaded \()[^;]*') \
&& sudo cp ${SERVICE_FILE} ${SERVICE_FILE}.bak
$
$ # 刪除dockerd的 -H參數(shù)
$ SERVICE_FILE=$(systemctl status docker|grep Loaded|grep -Po '(?<=Loaded: loaded \()[^;]*') \
&& sudo sed -i -e 's/ -H fd:\/\/ / /g' ${SERVICE_FILE}
$
$ # 再次查看驗(yàn)證
$ sudo cat $(systemctl status docker|grep Loaded|grep -Po '(?<=Loaded: loaded \()[^;]*')|grep dockerd
ExecStart=/usr/bin/dockerd --containerd=/run/containerd/containerd.sock
$ # OK
添加或修改daemon.json
如果沒(méi)有這個(gè)文件可以直接建立
$ sudo ls /etc/docker/daemon.json
ls: cannot access '/etc/docker/daemon.json': No such file or directory
$
$ sudo sh -c 'echo "{
\"hosts\":[
\"fd://\",
\"tcp://0.0.0.0:2375\"
]
}">/etc/docker/daemon.json'
如果文件已經(jīng)存在
則需添加如下內(nèi)容
"hosts":[
"fd://",
"tcp://0.0.0.0:2375"
]
現(xiàn)在重啟 docker服務(wù)
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker
$ sudo systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2019-11-27 07:48:40 UTC; 31s ago
Docs: https://docs.docker.com
Main PID: 19750 (dockerd)
Tasks: 8
CGroup: /system.slice/docker.service
└─19750 /usr/bin/dockerd --containerd=/run/containerd/containerd.sock
重啟成功,查看端口2375是否開(kāi)放。
$ ss -l |grep -Po '\s[^\s]*2375\s'
*:2375
$ # OK
客戶端連接
$ docker -H tcp://<服務(wù)器IP>:2375 version
Client: Docker Engine - Community
Version: 19.03.1
API version: 1.40
Go version: go1.12.5
Git commit: 74b1e89
Built: Thu Jul 25 21:18:17 2019
OS/Arch: darwin/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 19.03.5
API version: 1.40 (minimum version 1.12)
Go version: go1.12.12
Git commit: 633a0ea838
Built: Wed Nov 13 07:28:22 2019
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.2.10
GitCommit: b34a5c8af56e510852c35414db4c1f4fa6172339
runc:
Version: 1.0.0-rc8+dev
GitCommit: 3e425f80a8c931f88e6d94a8c831b9d5aa481657
docker-init:
Version: 0.18.0
GitCommit: fec3683
可以看到客戶端版本19.03.01,服務(wù)器端版本19.03.5。連接OK。
如果連接不上,經(jīng)常是防火墻的問(wèn)題
由于Docker Engine使用iptables來(lái)作為容器網(wǎng)絡(luò)的轉(zhuǎn)發(fā)。所以不能直接禁止iptables,需要添加相關(guān)的INPUT策略。
例如:
iptables -A INPUT -p tcp --dport 2375 -j ACCEPT
具體如何添加能夠生效,則需要根據(jù)服務(wù)器iptables的具體情況進(jìn)行調(diào)整。
例如:我在vultr.com的服務(wù)器所有的INPUT chain都轉(zhuǎn)向了IN_public_allow chain,上面那個(gè)命令添加后不會(huì)生效。需要在修改命令為iptables -A IN_public_allow -p tcp --dport 2375 -j ACCEPT
安全TCP連接(TCP+TLS)
上一節(jié)我們已經(jīng)連接了遠(yuǎn)程的Docker服務(wù)。但由于傳輸沒(méi)有加密,同時(shí)也沒(méi)有身份認(rèn)證,任何人都可以連接到服務(wù)器。那么我們需要在此基礎(chǔ)上進(jìn)行安全證書(shū)的生成和配置。
創(chuàng)建CA和證書(shū)
過(guò)程具體參見(jiàn)Docker官網(wǎng)教程Protect the Docker daemon socket
我對(duì)這個(gè)過(guò)程編寫(xiě)了兩個(gè)shell腳本可以簡(jiǎn)化這個(gè)過(guò)程
gen-server.sh : 生成服務(wù)器端的CA和證書(shū)
gen-user.sh : 生成客戶端使用的證書(shū)
$ # ------服務(wù)端操作------
$ # 創(chuàng)建臨時(shí)目錄
$ mkdir -p ~/.ssh/tls
$ cd ~/.ssh/tls
$
$ # 下載腳本
$ curl https://raw.githubusercontent.com/Si-He-Xiang/Docker-Tech/master/Docker%E7%A7%91%E6%99%AE/scripts/%E7%94%9F%E6%88%90%E8%BF%9E%E6%8E%A5%E8%AF%81%E4%B9%A6/gen-server.sh > gen-server.sh
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 2032 100 2032 0 0 5822 0 --:--:-- --:--:-- --:--:-- 5805
$ curl https://raw.githubusercontent.com/Si-He-Xiang/Docker-Tech/master/Docker%E7%A7%91%E6%99%AE/scripts/%E7%94%9F%E6%88%90%E8%BF%9E%E6%8E%A5%E8%AF%81%E4%B9%A6/gen-user.sh > gen-user.sh
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 2160 100 2160 0 0 539 0 0:00:04 0:00:04 --:--:-- 539
$
$ chmod +x gen-server.sh gen-user.sh
$
$ # 生成服務(wù)器端證書(shū)
$ # gen-server.sh至少需要三個(gè)參數(shù)
$ # --pass 表示更證書(shū)Key的密鑰
$ # --email 郵箱地址
$ # --domain 服務(wù)器的域名 或 使用 --ip 制定服務(wù)器IP
$ ./gen-server.sh --pass 111111 --altauto --domain <服務(wù)器域名> --email <郵件地址>
Generating RSA private key, 4096 bit long modulus
...................................................................++
.............++
e is 65537 (0x10001)
Generating RSA private key, 4096 bit long modulus
.............................++
............................................................++
e is 65537 (0x10001)
Signature ok
subject=/CN=si_he_xiang.github.com
Getting CA Private Key
mode of "./server/ca-key.pem" changed from 0664 (rw-rw-r--) to 0400 (r--------)
mode of "./server/server-key.pem" changed from 0664 (rw-rw-r--) to 0400 (r--------)
mode of "./server/ca.pem" changed from 0664 (rw-rw-r--) to 0444 (r--r--r--)
mode of "./server/server-cert.pem" changed from 0664 (rw-rw-r--) to 0444 (r--r--r--)
$
$ # 此命令在當(dāng)前目錄下創(chuàng)建了子目錄"server"
$ ls -l ./server
總用量 16
-r-------- 1 op op 3326 11月 28 16:20 ca-key.pem
-r--r--r-- 1 op op 2143 11月 28 16:20 ca.pem
-r--r--r-- 1 op op 2074 11月 28 16:20 server-cert.pem
-r-------- 1 op op 3243 11月 28 16:20 server-key.pem
$
$ # 將這4個(gè)文件復(fù)制到docker配置目錄
$ sudo mkdir -p /etc/docker/tls
$ sudo cp ./server/* /etc/docker/tls/
$
$ # 生成客戶端證書(shū)
$ # 密碼需要和上面的CAKey密碼一致
$ # -t 參數(shù)可以將生成的客戶端證書(shū)打包,以方面下載。(可以通過(guò)"--tar filename"指定打包文件名)
$ ./gen-user.sh --pass 111111 --user tester -t
$ ls -l tester*
-rw-rw-r-- 1 op op 4932 11月 28 16:27 tester-cert.tar.gz
$
$ # 證書(shū)生成完畢
現(xiàn)在證書(shū)已經(jīng)生成完了。我們需要讓Docker Engine使用服務(wù)器端證書(shū)來(lái)驗(yàn)證鏈接。
打開(kāi)配置文件vi /etc/docker/daemon.json, 根據(jù)之前的操作其內(nèi)容應(yīng)該是這樣的:
{
"hosts":[
"fd://",
"tcp://0.0.0.0:2375"
]
}
我們把它改成這個(gè)樣子:
{
"hosts":[
"fd://",
"tcp://0.0.0.0:2376"
],
"tlsverify":true,
"tlscacert":"/etc/docker/tls/ca.pem",
"tlscert":"/etc/docker/tls/server-cert.pem",
"tlskey":"/etc/docker/tls/server-key.pem"
}
端口由
2375改為2376,2376是Docker Engine默認(rèn)的TLS端口。
重啟服務(wù)
$ sudo systemctl restart docker
現(xiàn)在服務(wù)器端配置完成。別忘了在防火墻打開(kāi)2376端口。
配置客戶端
下面我們進(jìn)入客戶端操作。上一步我們?cè)诜?wù)器上生成了客戶端需要使用的證書(shū),我們下載到客戶端。
$ # 下載證書(shū)
$ mkdir -p ~/.ssh/tls
$ scp <server-name-in-ssh-config>:~/.ssh/tls/tester-cert.tar.gz ~/.ssh/tls
$ mkdir -p ~/.ssh/tls/docker
$ cd ~/.ssh/tls/docker
$ tar -xzvf ~/.ssh/tls/tester-cert.tar.gz
$ cd tester
$ ls -l
total 24
-r--r--r-- 1 shixiao staff 2143 11 28 16:27 ca.pem
-r--r--r-- 1 shixiao staff 1883 11 28 16:27 cert.pem
-r-------- 1 shixiao staff 3247 11 28 16:27 key.pem
$ pwd
<HOME>/.ssh/tls/docker/tester
下面我們通過(guò)命令連接服務(wù)器
$ docker -H tcp://<服務(wù)器域名>:2376 \
--tlsverify=1 \
--tlscacert=${HOME}/.ssh/tls/docker/tester/ca.pem \
--tlscert=${HOME}/.ssh/tls/docker/tester/cert.pem \
--tlskey=${HOME}/.ssh/tls/docker/tester/key.pem \
version
Client: Docker Engine - Community
Version: 19.03.1
API version: 1.40
Go version: go1.12.5
Git commit: 74b1e89
Built: Thu Jul 25 21:18:17 2019
OS/Arch: darwin/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 19.03.5
API version: 1.40 (minimum version 1.12)
Go version: go1.12.12
Git commit: 633a0ea838
Built: Wed Nov 13 07:28:22 2019
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.2.10
GitCommit: b34a5c8af56e510852c35414db4c1f4fa6172339
runc:
Version: 1.0.0-rc8+dev
GitCommit: 3e425f80a8c931f88e6d94a8c831b9d5aa481657
docker-init:
Version: 0.18.0
GitCommit: fec3683
$
$ # OK!連接成功
擴(kuò)展一下客戶端功能
到上一節(jié)為止我們已經(jīng)成功完成了所有連接必須的內(nèi)容。
有時(shí)候我們的客戶端會(huì)需要在幾個(gè)不同的環(huán)境中進(jìn)行切換,為了操作方便,我建立了幾個(gè)命令行的alias。
首先,我們有幾個(gè)約定:
- 所有服務(wù)器的配置和證書(shū)都放到
~/.ssh/tls/docker目錄下的獨(dú)立子目錄中。 -
~/.ssh/tls/docker目錄下的子目錄名即服務(wù)器配置名稱 - 服務(wù)器配置子目錄中必須包含4個(gè)文件
- ca.pem : CA證書(shū)
- cert.pem : 客戶端證書(shū)
- key.pem : 客戶端證書(shū)Key
- host : 服務(wù)點(diǎn)連接地址及端口配置
那么,現(xiàn)在我們要為之前創(chuàng)建的目錄~/.ssh/tls/docker/tester添加host文件
$ echo "tcp://<服務(wù)器域名>:2376" > ~/.ssh/tls/docker/tester/host
現(xiàn)在一個(gè)遵循約定的docker服務(wù)器配置目錄已經(jīng)有了,下面我們創(chuàng)建alias。
$ # 下載.alias_docker.sh
$ curl https://raw.githubusercontent.com/Si-He-Xiang/Docker-Tech/master/Docker%E7%A7%91%E6%99%AE/scripts/.alias_docker.sh >.alias_docker.sh
.alias_docker.sh文件中包含4個(gè)擴(kuò)展命令。
- docker-show : 查看當(dāng)前激活的docker連接
- docker-clear : 清除docker連接
- docker-switch : 激活或切換到指定的docker連接
- docker-list :查看可用的docker連接(即符合上述約定的目錄名稱)
下載.alias_docker.sh文件并將其加入啟動(dòng)腳本,然后嘗試一下這幾個(gè)命令。
$ docker-list
tester
$
$ docker-show
DOCKER_HOST=
DOCKER_TLS_VERIFY=
DOCKER_CERT_PATH=
$
$ docker-switch tester
DOCKER_HOST=tcp://<服務(wù)器域名>:2376
DOCKER_TLS_VERIFY=1
DOCKER_CERT_PATH=<HOME>/.ssh/tls/docker/tester
$
$ docker version
.......
.......
$ # OK! 完結(jié)撒花