如何安全便捷地管理Docker船隊
Docker
Docker是什麼?如果說你的伺服器是一條船,你只是一個小船主,你的船上散裝著各種貨物(也就是服務,比如http服務,資料庫服務,快取服務,訊息服務等等),那麼Docker
就相當於把你的伺服器改裝成了一條集裝箱貨船,把你原先凌亂堆放的貨物放置在一個一個容器裡,互相隔離,有序堆放。我們來看看Docker
的商標,是不是很形象呢?
但是你的業務越做越大,很明顯一條船是裝不下了,你需要一支船隊:
這時候,如何管理船隊就變成了一個難題,沒有工具的幫忙,你甚至都不知道你有幾條船,每條船上裝的都是些什麼貨物,這些貨物現在的狀態如何。
Portainer
Portainer這個工具就是管理你船隊的一個好幫手。並且它本身也是安裝在一條船上,這條船就是你的指揮艇吧(說實話這個圖示有點醜,一點都沒有船隊老大的氣質)。
怎麼安裝Portainer
呢?這個別人早都已經介紹過了,包括官網上也有說明。但是我要介紹一下我的經驗,我安裝Portainer
的方式和官網的也不同,和別人講的也不同:
docker run -d --network=host --name portainer --restart always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
在這裡我們沒有暴露9000
埠,而是使用了一個特殊的設定:--network=host
,就是這一點點小小的不同,會對你後面的操作影響巨大。
Docker API
光裝上Portainer
是沒有用的,它充其量也只能管理它所在的這條船。
它怎麼管理整個船隊呢?首先你得建立Portainer
和船隊裡其它船隻之間的聯絡。這個聯絡就是讓被管理的船隻暴露出Docker API
介面來。但是如果你檢視Docker
官方的說明文件,把整個過程弄得極其複雜無比,又要建立什麼安全證書中心,又要頒發證書,沒有初中以上文化是搞不定的。
Docker
本來是有一套簡便的暴露埠的方法的,為什麼官網要搞這麼複雜呢?因為原先的方法比較簡單,會直接把整個管理介面全部暴露給公網,有極大的安全風險,所以Docker
官網搞了一套複雜的認證流程。
我們的解決思路比較簡單:你不要把埠暴露給公網不就行了嗎?加一個防火牆,只讓我們允許的地址來訪問就可以了,何必搞什麼CA
回到我們的被管理的船上,把API
埠先暴露出來:
# systemctl edit docker
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375
好吧,這只是CentOS 7
下的一種作法,還有一種作法是修改/etc/sysconfig/docker
檔案:
OPTIONS='--selinux-enabled --log-driver=journald --signature-verification=false -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375'
具體應該用哪種作法,要取決於你的docker
服務是怎麼設定的:
systemctl show docker | grep EnvironmentFile
你如果有EnvironmentFile
設定,那麼你就需要用上面第二種辦法,如果沒有,就用第一種辦法。
iptables
好了,現在埠是暴露出來了,但是全公網任何人都能訪問,安全性怎麼辦?這時候我們發現一個嚴重的問題:Docker
在亂搞我們的iptables
表!
iptables
是很重要的防火牆的設定,docker
為了暴露它的服務,它會忽視你設定在iptables
表裡的一切規則,強行讓它的規則生效。這還了得?我們必須禁止Docker
這麼胡搞,在上面的options
裡再加上一個選項--iptables=false
:
OPTIONS='--selinux-enabled --log-driver=journald --signature-verification=false -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375' --iptables=false
重啟Docker
服務後,它終於不再亂動我們的iptables
表了。實際上為了安全起見,我們應該在所有docker
伺服器上都加上--iptables=false
的選項。但是這樣又產生了另外一個問題:外部訪問固然是阻止了,但我們的Docker
容器想訪問外部也訪問不了了,比如我們一開始安裝的Portainer
也是執行在容器裡的,不能訪問網際網路,它就沒有辦法管理其它Docker
伺服器了。為了解決這個問題,需要我們在建立Docker
容器的時候指定--network=host
,這也就是本文一開始安裝Portainer
時候那樣設定的原因。
好,現在各個被管理端的2375
埠是開開了,但是除了localhost
誰也訪問不了它,怎麼辦?我們可以在iptables
裡增加一條規則:
-A INPUT -s ###.###.###.### -m state --state NEW -m tcp -p tcp --dport 2375 -j ACCEPT
上面那個###.###.###.###
就是你的Portainer
指揮艇伺服器的IP
地址。這樣一來,除了這臺指揮艇伺服器可以訪問被管理船隻的Docker API
介面以外,別的任何人都不能訪問。這樣就既達到了我們管理的目的,又保證了安全,同時還免出去了設定證書的繁瑣。
啟航吧,船隊!