docker run
/docker build
?Docker 容器技術目前是微服務/持續集成/持續交付領域的第一選擇。而在 DevOps 中,咱們須要將各類後端/前端的測試/構建環境打包成 Docker 鏡像,而後在須要的時候,Jenkins 會使用這些鏡像啓動容器以執行 Jenkins 任務。html
爲了方便維護,咱們的 CI 系統如 Jenkins,也會使用 Docker 方式部署。
Jenkins 任務中有些任務須要將微服務構建成 Docker 鏡像,而後推送到 Harbor 私有倉庫中。
或者咱們全部的 Jenkins Master 鏡像和 Jenkins Slave 鏡像自己都不包含任何額外的構建環境,執行任務時都須要啓動包含對應環境的鏡像來執行任務。前端
咱們的 Jenkins Master、Jenkins Slaves 都是跑在容器裏面的,該如何在它們裏面調用 docker run
命令啓動包含 CI 環境的鏡像呢?
在這些 CI 鏡像裏面,咱們從源碼編譯完成後,又如何經過 docker build
將編譯結果打包成 Docker 鏡像,而後推送到內網倉庫呢?python
答案下面揭曉。docker
/var/run/docker.sock
Docker 採起的是 Client/Server 架構,咱們經常使用的 docker xxx
命令工具,只是 docker 的 client,咱們經過該命令行執行命令時,其實是在經過 client 與 docker engine 通訊。後端
咱們經過 apt/yum 安裝 docker-ce 時,會自動生成一個 systemd 的 service,因此安裝完成後,須要經過 sudo systemctl enable docker.service
來啓用該服務。
這個 Docker 服務啓動的,就是 docker engine,查看 /usr/lib/systemd/system/docker.service
,能看到有這樣一條語句:網絡
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
默認狀況下,Docker守護進程會生成一個 socket(/var/run/docker.sock
)文件來進行本地進程通訊,所以只能在本地使用 docker 客戶端或者使用 Docker API 進行操做。
sock 文件是 UNIX 域套接字,它能夠經過文件系統(而非網絡地址)進行尋址和訪問。架構
若是咱們在容器內部安裝 docker client,而且經過添加參數 -v /var/run/docker.sock:/var/run/docker.sock
將宿主機的 /var/run/docker.sock
文件以 volume 方式掛載到容器內部,這樣就能實現 "Docker in Docker",在容器內使用 docker 命令了。socket
要記住的是,真正執行咱們的 docker 命令的是 docker engine,而這個 engine 跑在宿主機上。因此這並非真正的 "Docker in Docker".微服務
version: '3.3' services: jenkins-master: image: jenkinsci/blueocean:latest container_name: jenkins-master environment: - TZ=Asia/Shanghai ports: - "8080:8080" - "50000:50000" volumes: - ./jenkins_home:/var/jenkins_home - /usr/bin/docker:/usr/bin/docker # 爲容器內部提供 docker 命令行工具(這個隨意) - /var/run/docker.sock:/var/run/docker.sock # 容器內部經過 unix socket 使用宿主機 docker engine user: root restart: always
或者若是你想使用 python 客戶端鏈接,在鏡像構建時,用 pip install docker
將客戶端放到鏡像裏就行了。工具
須要的時候,也能夠將 /etc/docker
映射到容器內,這樣容器內的 docker
命令行工具也會使用與宿主機一樣的配置。
經過上面的操做,咱們在容器內執行 docker ps
時,仍是極可能會遇到一個問題:權限問題。
若是你容器的默認用戶是 root,那麼你不會遇到這個問題,由於 /var/run/docker.sock
的 onwer 就是 root.
可是通常來講,爲了限制用戶的權限,容器的默認用戶通常都是 uid 和 gid 都是 1000 的普通用戶。這樣咱們就沒有權限訪問 /var/run/docker.sock
了。
解決辦法:
方法一(不必定有效):在構建鏡像時,最後一層添加以下內容:
# docker 用戶組的 id,一般都是 999 RUN groupadd -g 999 docker \ && usermod -aG docker <your_user_name>
這樣咱們的默認用戶,就能使用 docker 命令了。
P.S.
999
不必定是 docker 用戶組,因此上述方法某些狀況下可能失效。這時仍是老老實實經過docker run -u root
啓動容器吧。(或者在docker-compose.yml
中添加user: root
屬性)