Docker安裝Jenkins並支持Maven,Docker,Helm

Docker 安裝 Jenkins 很簡單, 可是安裝完的 Jenkins 並不直接支持 maven, docker 等 CI 經常使用工具. 特別是 docker 涉及到 docker中運行docker, 也就是 docker in docker 的問題. 本文將示例如何解決.html

本示例所用主機 ttg12 的環境爲:git

  • IP: 192.168.31.12,
  • OS: ubuntu server 18.04,
  • Docker 版本: 19.03.6.

一. Docker 安裝 Jenkins

Jenkins如今也分長期支持版(LTS)和普通支持版, 對於須要線上長期穩定支持的, 最好下載 LTS 版. 當前 (2020.7) jenkins 最新 LTS 版本爲 2.235.1-lts.github

# 下載鏡像
sudo docker pull jenkins/jenkins:2.235.1-lts
# 新建容器並啓動
sudo docker run -d -p 8081:8080 -p 50001:50000 \
    -v /data2/jenkins/jenkins_home:/var/jenkins_home \
    -v /etc/localtime:/etc/localtime:ro \
    --restart=always \
    --name dao_jenkins_1 \
    jenkins/jenkins:2.235.1-lts

其中 2 個 Volumn Mapping 說明以下.spring

  • -v /data2/jenkins/jenkins_home:/var/jenkins_home, docker 中 /var/jenkins_home 是 jenkins 的 $HOME 以及全部配置, 數據存儲的地方, 因此必須持久化到本地.
  • -v /etc/localtime:/etc/localtime:ro, 保持 docker 中的時區跟 host 保持一致, 不然日誌等時間都使用 UTC+0 時區, 跟中國時間差 8 個小時.

查看容器日誌:docker

sudo docker logs dao_jenkins_1

顯示權限錯誤:apache

touch: cannot touch '/var/jenkins_home/copy_reference_file.log': Permission denied
Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?

這是由於 jenkins 在 host 上用戶爲當前用戶 faceless, 而 host 本地目錄 /data2/jenkins/jenkins_home 屬於 root. json

簡單的解決方案, 就是將 /data2/jenkins/jenkins_home 的全部者 (owner) 修改成 host 上運行 docker 用戶 faceless (uid=1000)ubuntu

# 修改 faceless 爲 host 上 運行 docker 的用戶
sudo chown -R faceless /data/jenkins/jenkins_home 
# sudo chown -R faceless /var/run/docker.sock
sudo docker start dao_jenkins_1

而後再重啓 jenkins 容器 dao_jenkins_1安全

sudo docker restart dao_jenkins_1

二. 支持 Docker

咱們將 Jenkins 運行在容器中, 而 Jenkins CI 也須要運行 docker 的話, 就會遇到 docker in docker 的問題. 具體請參考: ~jpetazzo/Using Docker-in-Docker for your CI or testing environment? Think twice.. bash

而咱們知道, Docker 其實分爲兩部分: 服務端和客戶端. 服務端經過 socket 套接字 或者監聽端口接受客戶端的命令. 具體可參考官方文檔 Configure where the Docker daemon listens for connections.

也就是說若是咱們在宿主機上運行了 docker 服務端的話, 咱們在容器內能夠只安裝 docker 客戶端, 而後經過 socket套接字 或者 ip+端口 的方式來直接使用宿主的docker 服務. 這樣在容器內新建容器, 實際上是在宿主機上新建容器.

由於 Docker 服務端和客戶端默認使用 socket 套接字進行交互, 因此咱們這裏也使用 socket套接字 的方案, 即將宿主機的 /var/run/docker.sock 經過映射給 Jenkins 容器.

2.1 讓容器使用宿主的docker

按照上面的思路, 咱們在建立容器的 docker run 命令中增長以下 3 個參數:

-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/bin/docker:/usr/bin/docker 
-v /etc/docker:/etc/docker \

有關三者的說明

  • -v /var/run/docker.sock:/var/run/docker.sock, 經過映射主機的套接字文件到容器, 讓容器內啓動 docker 的時候並非啓動容器內的容器(子容器), 而是啓動主機上的容器(兄弟容器).
  • -v /usr/bin/docker:/usr/bin/docker, 讓容器中直接使用宿主機的 docker 客戶端.
  • -v /etc/docker:/etc/docker, 讓容器中的 docker 客戶端使用宿主機的 docker 配置文件, 包括國內鏡像 (mirrors) 和 非ssl安全訪問白名單 等配置.

2.2 解決訪問宿主 socket 的權限問題

重啓容器後, 咱們經過 docker exec -it dao_jenkins_1 /bin/bash 命令進入容器, 執行 docker ps 驗證 docker 命令是否可正常使用, 結果發現會遇到以下權限問題:

jenkins@f9fd87225ddb:/$ docker ps
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.40/containers/json: dial unix /var/run/docker.sock: connect: permission denied

咱們先看下 host 上 /var/run/docker.sock 的權限:

faceless@ttg12:~$ ll /var/run/docker.sock
srw-rw---- 1 root docker 0 Jul 16 10:17 /var/run/docker.sock=

能夠看到 docker.sock 屬於 root 用戶 和 docker 組. 映射到容器內的權限爲:

jenkins@5affdae1637b:/$ ls -al /var/run/docker.sock
srw-rw---- 1 root 128 0 Jul 16 10:17 /var/run/docker.sock

咱們再在容器查看下 jenkins 用戶的 user id 和 groupd id:

jenkins@5affdae1637b:/$ id
uid=1000(jenkins) gid=1000(jenkins) groups=1000(jenkins)

咱們能夠看到 jenkins 的用戶id 爲 1000, group id 也爲 1000. 所以咱們的解決方案也有 2 個:

  • 在宿主機將 socket 文件的全部者改成 user id = 1000 的用戶;
  • 在給容器內的用戶增長 group id = 128 的權限.

下面分別講解.

2.2.1 修改宿主機 socket 文件權限設置

將 host 上 docker socket 的擁有者修改成運行 uid=1000 的用戶, 或者直接將權限修改成其餘人可讀寫666:

# 修改宿主機上 socket 的 owner 爲 id=1000 的用戶
sudo chown 1000 /var/run/docker.sock
# 或修改 sock 的權限爲 666
sudo chmod 666 /var/run/docker.sock

這個方案無需重啓容器, 直接在容器內運行 docker ps 能夠看到能輸出正常結果.

這個方案是網上大多數文章給出的方案. 可是該方案有一個比較的缺陷, 那就是若是宿主機或者 docker 重啓, 會從新建立 docker.sock 文件, 其全部者會被重置爲 root 用戶, 因此咱們又須要再執行上面的命令修改權限.

2.2.2 給予容器 docker 組權限

第二個方案是, 咱們給容器內的 jenkins 用戶增長 id=128 的組權限. 而正好 docker run 很友好地提供 groupd-add 參數支持該操做.

官方文檔 Additional groups🔗

--group-add: Add additional groups to run as
By default, the docker container process runs with the supplementary groups looked up for the specified user. If one wants to add more to that list of groups, then one can use this flag:

$ docker run --rm --group-add audio --group-add nogroup --group-add 777 busybox id

uid=0(root) gid=0(root) groups=10(wheel),29(audio),99(nogroup),777

也就是說咱們可一個經過 group-add 參數給容器中的用戶經過 group name 或者 group id 添加多個額外的用戶組權限, 可是注意: 這個用戶組是指容器內的用戶組, 其 id 可能跟宿主機上的 id 不一致. 而咱們要讓容器內的用戶擁有 host 的某個 group 權限, 須要經過 id 來賦權.

所以這裏咱們先看 host 上 docker 組的 id.

faceless@ttg12:~$ cat /etc/group | grep docker
[sudo] password for weiping:
docker:x:128:weiping

能夠看到 docker 用戶組的 id 爲 128. 所以咱們在建立容器的時候加上 --group-add=128 便可讓容器內的 jenkins 用戶擁有 /var/run/docker.sock 文件的讀寫權限:

# 先移除舊容器
sudo docker rm -f dao_jenkins_1
# 從新建立容器
sudo docker run -d -p 8081:8080 -p 50001:50000 \
    -v /data2/jenkins/jenkins_home:/var/jenkins_home \
    -v /etc/localtime:/etc/localtime:ro \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v /etc/docker:/etc/docker \
    -v /usr/bin/docker:/usr/bin/docker \
    --restart=always  \
    --group-add=128 \
    --name dao_jenkins_1 \
    jenkins/jenkins:2.235.1-lts

2.2.3 自定義 Dockerfile

其餘可能的解決方案 (還未驗證), 自定義 Dockerfile (參考自 Use docker inside docker with jenkins user:

FROM jenkins:2.32.3

USER root
RUN apt-get -qq update \
   && apt-get -qq -y install \
   curl

RUN curl -sSL https://get.docker.com/ | sh

RUN usermod -a -G staff jenkins

USER jenkins

三. 安裝其餘 CI 工具

3.1 安裝和配置 Maven

首先安裝 maven:

mkdir -p /opt/ && \
cd /opt/ && \
curl -fsSL https://mirror.bit.edu.cn/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz > /tmp/apache-maven-3.6.3-bin.tar.gz && \
tar xzf /tmp/apache-maven-3.6.3-bin.tar.gz -C /opt/ && \
rm /tmp/apache-maven-3.6.3-bin.tar.gz && \
ln -s /opt/apache-maven-3.6.3/bin/mvn /bin/mvn && \
ln -s /opt/apache-maven-3.6.3/bin/mvnyjp /bin/mvnyjp && \
export PATH=/opt/apache-maven-3.6.3/bin:$PATH

而後配置和加速 maven:
1) 在 host 目錄 /data2/jenkins/jenkins_home/ (對應 docker 的 /var/jenkins_home/) 中打開或新建 .m2/settings.xml 文件, 添加阿里雲鏡像:

<mirrors>
    <mirror>
      <id>ali-public</id>
      <mirrorOf>public</mirrorOf>
      <name>aliyun maven public</name>
      <url>https://maven.aliyun.com/repository/public</url>
    </mirror>
    <mirror>
      <id>ali-central</id>
      <mirrorOf>central</mirrorOf>
      <name>aliyun maven central</name>
      <url>https://maven.aliyun.com/repository/central</url>
    </mirror>
        <mirror>
      <id>aligoogle</id>
      <mirrorOf>google</mirrorOf>
      <name>aliyun google</name>
      <url>https://maven.aliyun.com/repository/google</url>
    </mirror>
        <mirror>
      <id>alisping</id>
      <mirrorOf>spring</mirrorOf>
      <name>aliyun spring</name>
      <url>https://maven.aliyun.com/repository/spring</url>
    </mirror>
        <mirror>
      <id>alispringplugin</id>
      <mirrorOf>spring-plugin</mirrorOf>
      <name>aliyun spring-plugin</name>
      <url>https://maven.aliyun.com/repository/spring-plugin</url>
    </mirror>
  </mirrors>

2) 甚至能夠把本地 repository 裏面已經下載好的三方庫都 copy 到 .m2/repository, 節約下載時間.

3.2 支持 Kubernetes Helm

對 Kubernetes Helm3 的支持比較簡單, 直接將宿主機上的 helm 映射到容器中便可. 注意這裏針對 helm3, 由於 helm3 中已經移除 tiller, 只須要客戶端便可.

先將 k8s master 上的 .kube/config 文件複製到 docker 宿主機 (這裏是ttg12) 的 /data2/jenkins/jenkins_home/.kube/ 目錄下.

而後在 docker run 命令中增長以下映射, 並重建容器.

-v /usr/local/bin/helm:/bin/helm

3.3 提交修改到新鏡像 Image

待 docker-ce 安裝完成後, 提交本次更新爲新的 image, 後面從這個 image 啓動容器:

# 提交修改
sudo docker commit -a "thefacelessman@126.com" -m "jenkins v2.235.1-lts with support for maven, docker & k8s" dao_jenkins_1 jenkins_with_dockercli:2.235.1-lts

# 中止並移除舊容器
sudo docker rm -f dao_jenkins_1

# 以新image啓動新容器
sudo docker run -d -p 8081:8080 -p 50001:50000 \
    -v /data2/jenkins/jenkins_home:/var/jenkins_home \
    -v /etc/localtime:/etc/localtime:ro \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v /etc/docker:/etc/docker \
    -v /usr/bin/docker:/usr/bin/docker \
    -v /usr/local/bin/helm:/bin/helm \
    --restart=always  \
    --name dao_jenkins_1 \
    jenkins_with_dockercli:2.235.1-lts

若是須要, 能夠將 image push 到私有的 docker registry:

docker login --username=<your-useranme> registry.cn-hangzhou.aliyuncs.com
docker tag jenkins_with_dockercli:2.235.1-lts registry.cn-hangzhou.aliyuncs.com/faceless/jenkins_with_dockercli:2.235.1-lts
docker push registry.cn-hangzhou.aliyuncs.com/faceless/jenkins_with_dockercli:2.235.1-lts

四. 附錄

參考資料:

相關文章
相關標籤/搜索