Jenkins 安裝
Jenkins 支持主流的 Linux 發行版系統,同時還支持 macOS、Windows、和 Docker 運行。 具體系統的 Jenkins 安裝包可以去官網下載 https://www.jenkins.io/download。
作為運行在生產環境,推薦在 CentOS 中安裝,目前容器技術也非常流行,在 Docker 中運行 Jenkins 也是不錯的選擇。接下來將會演示在 CentOS 和 Docker 中運行 Jenkins 服務。
Jenkins 的版本迭代非常快,插件也是每天都有更新。目前 Jenkins 界面也有非常大的改版,我測試對比了一下,只有 2.222.4 及以下的版本界面還是熟悉的樣子,2.222.4 之后的版本在 UI 界面上變化非常大,特別是配置管理的功能菜單要花點時間熟悉下。所以我后面的演示操作全是基於 Jenkins 2.222.4 版本,如果各位有興趣可以嘗試用一用最新版的 Jenkins。
Linux 下安裝 Jenkins
直接在 Linux 中安裝 Jenkins 需要做以下的幾件事,參見詳細步驟:
1、Jenkins 運行時需要安裝 Git 和 JDK
# 安裝最新版的 git 和 JDK 1.8
$ sudo yum install git java-1.8.0-openjdk
2、設置 Jenkins 源並安裝 Jenkins
# 安裝指定版本的 Jenkins
$ wget https://pkg.jenkins.io/redhat-stable/jenkins-2.222.4-1.1.noarch.rpm
$ sudo rpm -ivh jenkins-2.222.4-1.1.noarch.rpm
# 安裝最新版本的 Jenkins
$ sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
$ sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
$ sudo yum install jenkins -y
# 將 Jenkins 加入開機啟動項
$ sudo systemctl start jenkins
$ sudo systemctl enable jenkins
$ sudo systemctl daemon-reload
3、允許 Jenkins 通過 Linux 防火牆
# Jenkins 默認運行在 8080 端口,允許8080端口通過防火牆
$ sudo firewall-cmd --zone=public --add-port=8080/tcp --permanent
$ sudo firewall-cmd --zone=public --add-service=http --permanent
$ sudo firewall-cmd --reload
# 或者直接關閉防火牆
$ sudo firewall-cmd --state # 查看防火牆狀態
$ sudo systemctl stop firewalld.service # 停止防火牆
$ sudo systemctl disable firewalld.service # 禁用防火牆開機啟動
$ sudo systemctl enable firewalld.service # 起用防火牆開機啟動
$ sudo systemctl start firewalld.service # 禁用防火牆開機啟動
Docker 容器部署 Jenkins
采用容器來跑服務有個很大的好處,那就是搞壞了可以快速重新開始,這是我喜歡 Docker 的原因之一。采用 Docker 容器來跑 Jenkins 服務有兩種方式:其一是直接使用 docker run 命令;其二就是使用 docker-compose 命令。推薦使用 docker-compose ,因為后期如果要升級 Jenkins 比較方便,更換下 Jenkins 鏡像就可以了。下面還是將兩種方式都做個記錄,各自選擇自己喜歡的方式進行實操。
為了讓運行在 Docker 容器中的 Jenkins 也能執行 docker 相關命令,我們這里要把宿主機的 docker 和 docker.sock 掛載到容器中。當然你也可以在 Jenkins 容器中再安裝 Docker 服務,這就是 docker-in-docker 的模式了,docker-in-docker 的坑比較多,留給各位自己去探索吧,我這里就把宿主機的 docker 客戶端和 docker daemon 掛載到 Jenkins 容器中。
注意點:
- 要想能執行 docker 命令,就需要將系統用戶加到 docker 組,安裝完 docker 服務這個組就會自動創建。
- docker 容器中運行 jenkins,容器里面是默認使用的 uid=1000 的 jenkins 用戶啟動的 jenkins 服務。
- 確保宿主機中存在一個系統賬號,可以執行 docker 命令,並且和容器中的 jenkins 用戶的 uid、gid和組的屬性相同。
所以這里會涉及到調整系統用戶的 id 和組的 id,相關操作和說明,參見后續的操作過程,當然你可以簡單粗暴地將 docker 和 docker.sock 的權限設置為任何賬號都可執行,但是不推薦這樣,可能存在安全風險。
采用 docker run 的方式運行 Jenkins 容器
# 拉取指定版本 Jenkins 容器
$ docker pull jenkins/jenkins:2.222.4-lts-centos7
# 創建一個屬於 Jenkins 容器的 docker 網絡(可選,如果沒創建,后面就不要指定網絡)
$ docker network create jenkins_network
# 運行 jenkins 容器
$ docker run --name jenkins-in-docker \
--network jenkins_network \
--publish 8080:8080 --publish 50000:50000 \
--volume jenkins_home:/var/jenkins_home \
--volume /usr/bin/docker:/usr/bin/docker \
--volume /var/run/docker.sock:/var/run/docker.sock \
jenkins/jenkins:2.222.4-lts-centos7
docker run 中的命令參數設置不做過多解釋,不明白的可以自己去先熟悉下 docker 常用命令。這里單獨說明下 --volume 數據卷的設置,該參數可以掛載宿主機的文件到容器,也可以創建新的數據卷,新的數據卷由 docker 容器管理,如果你是將 jenkins_home 目錄掛載到宿主機,可能還會遇到 Jenkins 容器啟動失敗的問題。
# 看看容器日志 docker logs -f <container_id_or_name>
$ docker logs -f jenkins-in-docker --tail=50
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_home 目錄的所有權調整下
$ sudo chown -R 1000:1000 volume_dir
容器里面一般都是筆記精簡的,能不要的東西就不要,這樣可以保證容器鏡像盡量安全且體積小,但有時我們確實需要在容器中安裝些工具,但是又發現進入容器后默認的用戶又沒有管理權限,這是就需要用如下命令以管理員身份進入容器,然后在容器中安裝工具,進行特殊操作都是可以的。
# 以root身份進入容器,有的容器沒有 bash,將 bash 換成 sh 即可
$ docker exec -u 0 -it <container_id_or_name> bash
采用 docker-compose 方式運行 Jenkins 容器
采用 docker-compose 方式運行 Jenkins 容器,首先請確保自己系統可以執行 docker-compose 命令,如果還沒安裝 docker-compose 可翻看前面安裝 docker 的章節。
新建一個目錄,在下面創建 infrastructure-docker-compose.yml、startup-infrastructure-docker-compose.sh 兩個文件。
docker-compose 配置文件如下 infrastructure-docker-compose.yml :
version: '3.7'
services:
jenkins-in-docker:
image: jenkins/jenkins:2.222.4-lts-centos7
container_name: jenkins-in-docker
privileged: true
restart: unless-stopped
ports:
- 8080:8080
- 50000:50000
environment:
JAVA_OPTS: "-Xmx2048m -Xms1024m -Djava.security.egd=file:/dev/./urandom -Duser.timezone=Asia/Shanghai -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8"
volumes:
- /usr/bin/docker:/usr/bin/docker
- /var/run/docker.sock:/var/run/docker.sock
- ./docker_data/jenkins/2.222.4/jenkins_home:/var/jenkins_home
- ./docker_data/jenkins/2.222.4/jenkins_home_bak:/var/jenkins_home_bak
networks:
- infrastructure_network
deploy:
resources:
limits:
memory: 4096M
cpus: '2'
networks:
infrastructure_network:
external: true
下面就是啟動 docker-compose 運行 jenkisn 服務,我這里專門寫了個 shell 腳本,在演示的過程中有時需要重復的敲命令,寫在 shell 腳本中直接運行就行,省去重復敲命令的繁瑣。
shell 腳本 startup-infrastructure-docker-compose.sh :
#!/usr/bin/env bash
# 設置docker網絡名稱和docker-compose文件
docker_network=infrastructure_network
docker_compose_file=infrastructure-docker-compose.yml
# 輸出下docker-compose文件內容
echo "The compose file as below: "
docker-compose -f ${docker_compose_file} config
nw=$(docker network ls | grep ${docker_network} | awk '{print $1}')
if [[ ${nw} ]]; then
docker-compose -f ${docker_compose_file} --compatibility up --remove-orphans -d
else
docker network create ${docker_network} && docker-compose -f ${docker_compose_file} --compatibility up --remove-orphans -d
fi
運行 shell 腳本,啟動 Jenkins 服務:
# 設置shell腳本可執行
$ chmod +x startup-infrastructure-docker-compose.sh
# 運行shell腳本
$ ./startup-infrastructure-docker-compose.sh
同樣你可能還是會遇到 jenkins_home 目錄權限問題,解決方式還是如下,調整目前所有權:
$ chown -R 1000:1000 docker_data/jenkins
$ ./startup-infrastructure-docker-compose.sh
沒什么意外的話等個1分鍾,就可以訪問 Jenkins 服務了,或者看到 jenkins 日志 Jenkins is fully up and running 也說明 jenkins 已經啟動好了。瀏覽器訪問 http://host_ip:8080,如果訪問不了,確保自己防火牆開放了 8080 端口。
Jenkins 日志和默認密碼

輸入 jenkins 默認密碼,【繼續】到下一步。

安裝 Jenkins 插件,暫時不知道安裝哪些插件的話可以選擇默認【安裝推進的插件】。

當然你也可以【選擇插件來安裝】,在里面選擇自己想要的插件,每個插件的功能都有介紹。

選好后就點擊【安裝】,進入插件安裝界面,這個界面要等幾分鍾,如果網絡不好的話,有些插件還可能會安裝失敗,不過失敗了也沒關系,可以點擊界面下的【重試】按鈕,重新安裝失敗的插件。

插件安裝好后就開始設置第一個管理員賬號。

Jenkins URL 的設置,這里先默認即可,如果后面我們要為 Jenkins 服務設置域名可以重新在 Jenkins 的配置里面重新設置。

這就是 Jenkins 默認的界面了,目前還沒有任何任務 Job。

這是管理 Jenkins 的界面,還是熟悉的界面。

如果你安裝的 Jenkins 版本是 2.222.4 以上版本,就需要先熟悉下 Jenkins 的管理面板了。
這個版本是 2.263.1,我當時的最新版 Jenkins,下圖是進入 Jenkins 的默認界面。

這是 Jenkins 的管理配置界面,對管理配置進行了分類,已經大變樣了。

到這里你以為完了,並沒有!還有個問題要解決,Jenkins 運行在容器中,並且希望可以正常執行 docker 命令。前面我們將宿主機的 docker 客戶端和 docker.sock 掛載到了容器里面,現在在 Jenkins 容器里面執行 docker 命令你可能會遇到如下提示:
$ 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.24/containers/json: dial unix /var/run/docker.sock: connect: permission denied
這就很納悶兒了,我宿主機上有個 jenkins 用戶,並且 uid 也是 1000,為什么在 jenkins 容器中還是不能執行 docker 相關命令呢?我的排查過程如下:
先看看我在宿主機上的用戶信息:
$ id jenkins
uid=1000(jenkins) gid=1000(jenkins) 組=1000(jenkins),10(wheel),994(docker) 環境=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
可以看到 jenkins 這個用戶的 uid、gid和所屬組的信息,我們再看看容器中 jenkins 的 uid、gid 信息:
$ docker exec -it jenkins-in-docker bash
bash-4.2$ id jenkins
uid=1000(jenkins) gid=1000(jenkins) groups=1000(jenkins)
發現 Jenkins 容器默認的 jenkins 用戶沒有在 docker 組中,處理方式如下:
# 以 root 身份進入容器
$ docker exec -it -u root jenkins-in-docker bash
# 看看用戶和組信息
[root@e77ed7439afd ~]$ cat /etc/group
⋮
jenkins:x:1000:
docker:x:997:
⋮
# 發現docker組存在,但是宿主機docker組的id=994,容器中docker組的id=997
# 我們先將jenkins用戶加入到docker組中試試
[root@e77ed7439afd ~]$ usermod -aG docker jenkins
[root@e77ed7439afd ~]$ id jenkins
uid=1000(jenkins) gid=1000(jenkins) groups=1000(jenkins),997(docker)
# 退出容器,將jenkins容器重啟下
$ docker restart jenkins-in-docker
# 以默認身份進入容器
$ docker exec -it jenkins-in-docker bash
bash-4.2$ 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.24/containers/json: dial unix /var/run/docker.sock: connect: permission denied
# 發現還是不能執行docker命令,我們把docker組的id也調整成和宿主機一樣試試
$ docker exec -it -u root jenkins-in-docker bash
[root@e77ed7439afd ~]$ groupmod -g 994 docker
[root@e77ed7439afd ~]$ id jenkins
uid=1000(jenkins) gid=1000(jenkins) groups=1000(jenkins),994(docker)
# 再重啟下jenkins容器,以默認用戶進入容器看能否執行docker命令
$ docker exec -it jenkins-in-docker bash
bash-4.2$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e77ed7439afd jenkins/jenkins:2.222.4-lts-centos7 "/sbin/tini -- /usr/…" 2 weeks ago Up 4 seconds 0.0.0.0:8080->8080/tcp, 0.0.0.0:50000->50000/tcp jenkins-in-docker
5f89b1a44f39 mysql:8.0.17 "docker-entrypoint.s…" 4 weeks ago Up 2 weeks 0.0.0.0:3306->3306/tcp, 33060/tcp mysql-in-docker
87c2dcc88c71 nginx:1.18.0 "/docker-entrypoint.…" 4 weeks ago Up 2 weeks 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp nginx-in-docker
bash-4.2$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker 20.10.1-dind 8d54f09a2b77 5 weeks ago 256MB
nginx 1.18.0 05f64a802c26 6 weeks ago 133MB
jenkins/jenkins 2.222.4-lts-centos7 32078832282a 7 months ago 637MB
mysql 8.0.17 b8fd9553f1f0 16 months ago 445MB
# 如果容器中沒有docker用戶組,直接創建一個docker並設置docker組ID與宿主機docker組ID相同,然后將jenkins用戶加入docker組
$ groupadd -g 994 docker && usermod -aG docker jenkins
現在發現在容器中可以正常執行 docker 命令了,其實總結起來就兩點:
- 容器中默認的 jenkins 用戶要在 docker 組中。
- 容器中 docker 組的 id 要保持和宿主機的 docker 組的 id 相同。
OK,到此才算是真正地做完了 jenkins 服務的准備工作,我們將宿主機的 docker 掛載到容器中,並且在盡量不調整宿主機的設置,做到了在容器中可以完美執行 docker 命令。
插件下載加速
Jenkins 插件的官方源在國外,下載速度非常慢,國內也有一些鏡像源,但是卻做得不徹底,實際上還是會從國外下載。經過我自己測試驗證,以及在網上尋找到的資料,有以下的幾種方式來加速 Jenkins 插件的下載,但是具體哪種方式有效,各位也可以自己試試看。
- 修改默認的配置文件,使其從國內鏡像源下載
在 Jenkins 的安裝目錄下有個updates目錄,該目錄下有個default.json文件,該文件就是插件鏡像源的JSON內容。修改這個文件,將里面的 mirrors.jenkins-ci.org 批量替換成 mirrors.tuna.tsinghua.edu.cn/jenkins 或者你自己知道並且想使用的鏡像源,將 www.google.com 替換成 www.baidu.com 即可。
- 設置反向代理,將下載源從官方源代理到國內鏡像源
主要是將 Jenkins 插件下載地址代理到清華等國內的 Jenkins 插件下載地址。在 Jenkins 機器上安裝 Nginx 服務,然后添加一條hosts記錄:127.0.0.1 updates.jenkins-ci.org 然后修改 Nginx 的配置文件:
rewrite ^/download/plugins/(.*)$ https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins/$1? last;
# 或者添加一條 location 配置
location /download/plugins {
proxy_next_upstream http_502 http_504 error timeout invalid_header;
proxy_set_header Host mirrors.tuna.tsinghua.edu.cn;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
rewrite /download/plugins(.*) /jenkins/plugins/$1 break;
proxy_pass https://mirrors.tuna.tsinghua.edu.cn;
}
- 設置 Jenkins 插件的升級站點
Jenkins 系統管理 → 插件管理 → 高級 → 升級站點,設置國內的鏡像源。
- 使用 Localization: Chinese (Simplified) 插件
安裝 Localization: Chinese (Simplified) 插件后,在 Jenkins 界面的右下角會多出一個【Jenkins 中文社區】按鈕。點擊進去你會看到 Jenkins 中文社區的介紹和二維碼,下邊還有個【更新中心鏡像設置】,點擊下【使用】按鈕,然后將 Jenkins 的默認的升級站點 https://updates.jenkins.io/update-center.json 修改為 https://updates.jenkins-zh.cn/update-center.json ,【提交】修改后【立即獲取】試試看,沒什么問題就可以去【可選插件】里面找幾個插件安裝看看速度是不是快多了。
經過我自己的測試和驗證,目前第4種方式是最有效且沒有什么問題的。其他方式都是治標不治本,並且還可能會遇到如下簽名校驗不過的問題。

關於 Jenkins 鏡像源加速站點在使用過程中如果有什么問題,可以參考 Jenkins 中文社區的一些解答 https://community.jenkins-zh.cn/t/jenkins/26
