docker in docker(docker裏邊跑docker)

docker run in docker

原文地址

一、背景

Docker技術目前在DevOps中被廣泛使用,我們需要將測試或者構建的代碼和自動化腳本打包成Docker鏡像,然後部署在各運行環境中。比如:在 jenkins 容器內運行 docker 命令執行構建鏡像

而在CI/CD中,我們常用一些CI/CD服務器,比如Jenkins和GoCD來構建與部署我們的應用,從而實現CI/CD的自動化。現在一些CI/CD服務器也被Docker化運行在真實的物理機上。於是我們需要在CI/CD服務器的Docker container裏面來構建(build)與運行(run)我們的Docker鏡像,這就涉及到"Docker run Docker"的問題。

一個很自然的想法是,我們是不是需要在CI/CD服務器鏡像中安裝一個Docker Daemon和Docker命令呢?但是Docker裏面跑Docker總感覺有些蹩腳,額外安裝與運行Docker無疑增加了CI/CD服務器鏡像的大小,同時還增加Docker的深度。

實際上,我們並不需要在CI/CD服務器上安裝Docker。通過如下的命令在CI/CD服務器上運行我們的鏡像:

二、原理:移花接木

  • Docker採取的是C/S架構,Docker的成功運行需要Docker Daemon和Docker Client(客戶端)的支持,當我們運行一些docker build等命令時,實際是需要Docker Client連接Docker Daemon發送命令,Docker Daemon會在宿主機操作系統分配文件、網絡等資源。

  • 默認情況下,Docker守護進程會生成一個socket(/var/run/docker.sock)文件來進行本地進程通信,而不會監聽任何端口,因此只能在本地使用docker客戶端或者使用Docker API進行操作。

  • 我們訪問本機的服務往往通過127.0.0.1:8080這種IP:端口的網絡地址方式進行通信,而sock文件是UNIX 域套接字(UNIX domain socket),它可以通過文件系統(而非網絡地址)進行尋址和訪問的套接字。

具體操作

  • 從表象上看,上面的命令似乎依然是在“Docker裏面run docker”,其實這是個誤區。docker run提供了-v參數讓我們將宿主的文件映射到docker裏面。比如通過-v /var/run/docker.sock:/var/run/docker.sock,我們將宿主的Docker Daemonsocket映射到Docker Container裏面;當Container裏面的docker 客戶端通過 /var/run/docker.sock 去操作Docker Daemon時,這些操作已移花接木地轉移到宿主的Docker Daemon上。(實際上是操作的宿主機的docker)
  • 歸根結底:
    • 容器內僅部署 docker 命令行工具(作爲客戶端),實際執行交由宿主機內的 docker-engine(服務器)
  • 如果還是不行,可能是沒有安裝執行docker的庫文件
    • 編輯Dockerfile文件
    RUN apt-get update && apt-get install -y libltdl7
    
    • 再執行啓動(啓動的時候記得掛載docker.socket)

三、延伸:操作遠程主機

既然docker client通過socket方式與本地的Docker Daemon進行通信,那麼我們可以很自然地想到,如果想在其他主機上通過socket連接到遠程DockerDaemon,是不是可以遠程操作Docker主機進行鏡像的構建與運行呢?

答案是可以的,就需要讓Docker守護進程監聽一個端口,這樣才能實現遠程通信,同時需要修改docker客戶端連接的主機是遠程地址而並非本地sock文件。由於Docker C/S 之間採取Rest API作爲通信協議,這爲我們使用第三方客戶端(如postman)操作docker乃至自己開發client提供了擴展.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章