關於Docker的 DinD VS. DooD
背景:最近在使用Jenkins搭建CICD的環境時,考慮使用Docker官網提供的image (jenkins/jenkins:lts)來直接搭建。要想讓Jenkins的job中直接build出一個映象,免不了需要在Jenkins容器使用Docker命令,於是就引出了今天的話題,在Docker中使用Docker的兩種方式:DinD和DooD
什麼是Docker in Docker(DinD)
在容器中安裝一個全新的完整的隔離的Docker版本,該容器和外部的Docker系統完全隔離,
在Docker官方有映象直接就能用 ofollow,noindex" target="_blank">官方DinD映象
你可以直接使用下面的命令啟動一個Docker容器:
docker run --privileged --name some-docker -d docker:stable-dind
注意:這裡有一個前提條件就是,你的Docker版本必須支援 –privileged 引數.Docker的官方文件同時也提醒你,使用了該引數之後,該容器就有了最高許可權,在容器中你幾乎可以做跟宿主機上同樣的任何事情,所以要小心使用。
這時當你進入這個新的容器後執行:
docker images REPOSITORY TAG IMAGE ID CREATED SIZE / #
你會看到沒有任何映象顯示出來,因為這是一個全新的容器,並且和你宿主機上的Docker系統隔離,所以還沒有任何一個映象。
DinD可能遇到的問題:
1. 關於Linux安全模組(AppArmor and SELinux)。 “內部Docker”使用的安全策略很可能與“外部Docker”的安全策略有衝突。比如我在Debian系統的機器上跑了一個Ubuntu的VM來測試我的Docker image,測試都通過了。但是我的同事用了一個Fedora的VM測試image就失敗了。
2. 關於儲存的驅動問題。外部Docker可能跑在下面這些正常的檔案系統之上(EXT4,BTRFS,等等),但是“內部Docker”可能是跑在一個copy-on-write系統之上(AUFS,BTRFS,Device Mapper等等),那麼內部和外部所使用的儲存驅動的組合有很多是不能同時工作的。比如你不能內外部同時都用AUFS。
3. 關於build cache的問題。(此處還需要繼續研究才能展開討論)
因此,你用來學習的時候,是可以用DinD的,但是在世界生產環境中一般用不到。就是因為DinD可能會出現很多意想不到的問題,比如上面我們談到的那些。
什麼是Docker-outside-of-Docker(DooD)
是指通過載入宿主Docker socket和程式的方式達成重用宿主映象的目的。
通常情況下,大多數人並不是真正想使用Docker-in-Docker, 而只是想在類似Jenkins的CI系統裡執行Docker命令。如何做呢, 最簡單的方式是在啟動容器的時候以-v的方式掛載宿主機的Docker的socket給你的新的容器使用。類似這樣使用(僅列出最相關的-v引數,其他忽略):
docker run -v /var/run/docker.sock:/var/run/docker.sock ...
這樣的話,這個新的容器就可以訪問到宿主機的Docker socket並且使用它,因此這個容器就有能力啟動容器,這樣他啟動和操作的容器和它本身是平級的兄弟關係。
DooD可能遇到的問題就是jenkins使用者 (這裡以jenkins CI為例) 沒有許可權執行docker命令。
解決辦法1:
需要賦予jenkins使用者sudo許可權以便能在容器內執行Docker命令。
所以在我們的Dockerfile中可以要這樣寫(這裡僅擷取Dockerfile中最相關的那一小段程式碼,全部程式碼請參見另外一篇如何使用Docker版的Jenkins做CICD的文章):
RUN apt-get update \ && apt-get install -y sudo \ && rm -rf /var/lib/apt/lists/* RUN echo "jenkins ALL=NOPASSWD: ALL" >> /etc/sudoers
解決辦法2:
或者我們也可以將jenkins使用者加入到Docker組中來解決(不過這樣可能有一個潛在的小問題就是,這個組gid的不同會造成不可移植)
Dockerfile中可以這樣寫:
ARG dockerGid=999 RUN echo "docker:x:${dockerGid}:jenkins" >> /etc/group
然後我們就可以執行下面命令去build一個自己的Jenkins image:
Docker build –rm –t myjenkins .
最後用下面命令完成DooD的啟動:
docker run -p 9090:8080 -p 50000:50000 --name my_jenkins \ --restart=always \ -v $(which docker):/usr/bin/docker \ -v /var/run/docker.sock:/var/run/docker.sock \ -d myjenkins:latest
結論:最後總結一下,當你需要在自己建立的容器中使用docker命令的時候,
DinD一般只是在學習的時候使用,但是如果你想實現映象對宿主的隱藏和隔離,則可以用DinD。
DooD能重用並且快取宿主機上的映象,通常情況下這才是我們真正想在容器中執行docker命令時應該使用的方法。