萬字乾貨! 使用docker部署jenkins和gitlab

2023-01-12 06:02:27

閱讀本文, 需要有基礎的Git, Linux, Docker, Java, Maven, shell知識, 並最少有一臺記憶體16G以上並已經安裝好了Docker的機器.

1. 概述

Jenkins是是一個CI/CD工具, GitLab是一個類似與GitHub程式碼託管平臺, 本文將實現通過docker部署Jenkins與GitLab, 並自動化釋出應用: 本地機器將程式碼推播到GitLab, GitLab通過web hook觸發Jenkins流水線, Jenkins獲取GitLab的程式碼並生成jar包, 將jar包推播到應用伺服器, 並執行jar包. 只需一個push操作, 即可自動釋出應用.

綜上, 我們需要三個容器, 一個Jenkins容器, 一個GitLab容器, 一個執行jar包的容器(本文稱其為應用容器, 即執行java應用的容器), 以及還要有一臺寫Java程式碼的個人電腦. 部署容器的電腦(本文稱其為伺服器)可以是同一個個人電腦, 也可以是其他電腦或伺服器, 部署容器的電腦的記憶體推薦16G以上, 因為GitLab比較吃記憶體, 設定不夠可能帶不動. 本文是一臺個人電腦寫程式碼, 一臺伺服器部署三個容器.

為了方便大家理解與閱讀, 在個人電腦執行的命令, 其命令提示字元為$$; 伺服器的命令提示字元為$; 容器內的命令提示字元為>.

2. 容器互聯

因為Jenkins需要從GitLab中拉取程式碼, Jenkins也需要嚮應用伺服器上傳jar包, 即容器間需要通訊, 所以我們需要建立一個橋接網路, 將容器都部署在橋接網路上, 容器間就可以互聯互通了.

通過下面的命令, 建立一個名為my-bridge的橋接網路:

$ docker network create --driver bridge --subnet 172.12.0.0/16 --gateway 172.12.0.1 my-bridge

3. 應用容器

3.1 部署應用容器

執行下面的命令執行應用容器, 這裡我們選擇Ubuntu 20.04作為基礎映象, 使用其他的發行版也可以, 這裡使用Ubuntu只是因為我對Ubuntu最瞭解.

$ docker run --interactive --tty --detach \
    --name app \
    --hostname app \
    --restart on-failure \
    --network my-bridge \
    --publish 31022:22 \
    --publish 31808:8080 \
    --volume $PWD/app:/root/app \
    ubuntu:20.04

3.2 設定SSH

Jenkins向伺服器傳輸jar包一般是通過SSH, 所以我們還需要在應用容器中安裝SSH. 執行應用也需要java, 沒裝java也需要安裝java.

# 進入應用容器
$ docker exec -it app bash

# 修改apt源之前, 備份apt源
> cp /etc/apt/sources.list /etc/apt/sources.list.org

# 更換apt源(預設的apt源非常慢)
> echo "
deb http://archive.canonical.com/ubuntu focal partner
deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal main restricted
deb http://mirrors.aliyun.com/ubuntu/ focal multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted
deb http://mirrors.aliyun.com/ubuntu/ focal-security multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-security universe
deb http://mirrors.aliyun.com/ubuntu/ focal universe
deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted
deb http://mirrors.aliyun.com/ubuntu/ focal-updates multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-updates universe
" > /etc/apt/source.list

# 安裝SSH和java
> apt update && apt install -y openssh-server openjdk-8-jdk-headless

平時我們用的伺服器, SSH一般都是開機自啟動, 所以我們幾乎不會去啟動SSH, 但是容器中都沒有SSH, 更別說開機自啟了, 所以安裝好之後還要啟動SSH.

注意: 容器內一般直接使用root使用者, 預設情況下SSH不允許root使用者使用密碼登入, 我們需要將PermitRootLogin yes加入到SSH組態檔中, 使root使用者可以通過密碼登入.

# 備份ssh設定
> cp /etc/ssh/sshd_config /etc/ssh/sshd_config.org

# 使root可以用密碼登入
> echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config

# 啟動ssh
> /sbin/sshd

# 第一次啟動可能會報錯, 顯示/run/sshd不存在, 不存在手動新建就好了
> mkdir /run/sshd

# 再次啟動ssh
> /sbin/sshd

# 修改root密碼
> passwd

4. Jenkins

4.1 部署Jenkins

使用docker部署Jenkins, 我們當然需要Jenkins的容器, 但是請注意, jenkins有兩個官方容器: jenkinsjenkins/jenkins. jenkins在2018年就已經棄用, 不再更新, 現在應該使用jenkins/jenkins, 現在大部分映象的命名都採用組織名稱/映象名稱的格式了.

使用如下命令來啟動Jenkins:

$ docker run --detach \
    --user root \
    --name jenkins \
    --hostname jenkins \
    --restart on-failure \
    --network my-bridge \
    --publish 37808:8080 \
    --publish 37500:50000 \
    --volume $PWD/jenkins:/var/jenkins_home \
    jenkins/jenkins:2.385

4.2 安裝外掛

啟動Jenkins後, 使用瀏覽器輸入伺服器地址:37808進入Jenkins介面, 預設的使用者為admin, 密碼的話我們有兩種方式知道密碼

  • 網頁會提示我們密碼儲存在/var/jenkins_home/secrets/initialAdminPassword, 所以我們檢視這個檔案就行了, 使用docker exec -t jenkins cat /var/jenkins_home/secrets/initialAdminPassword即不進入容器檢視檔案
  • Jenkins的啟動紀錄檔中也有密碼所在檔案的路徑以及密碼, 使用docker logs jenkins檢視Jenkins的紀錄檔, 也能找到密碼

接下來選擇安裝推薦的外掛就好了

然後點選右下角的使用admin賬戶繼續

接下來我們還要做一些準備工作, 比如安裝外掛, 設定mavan, 設定ssh...... 設定好之後我們才會正式的構建專案.

進入主頁後, 點選 Manage Jenkins -> Manage Plugins -> Available plugins, 安裝以下三個外掛:

  • Publish Over SSH
  • Maven Integration
  • Build Authorization Token Root


4.3 安裝maven

Jenkins預設是沒有maven的, 所以我們還需要安裝maven, 使用docker exec -it jenkins bash進入到容器, 再檢視下系統

> cat /etc/*release
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

這裡使用的是Debian, 先換下apt源, 不然會很慢

# 備份apt源
> cp /etc/apt/sources.list /etc/apt/sources.list.org

# 更換apt源
> echo "
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-updates main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-backports main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian-security bullseye-security main contrib non-free
" > /etc/apt/sources.list

然後執行apt update && apt install maven安裝maven, 安裝好後執行mvn -v檢視maven版本, 有對應的輸出說明已經安裝好了

# 注意, 此處顯示了 Maven home
> mvn -v
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 11.0.17, vendor: Eclipse Adoptium, runtime: /opt/java/openjdk
Default locale: en, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-1160.80.1.el7.x86_64", arch: "amd64", family: "unix"

4.4 設定maven

安裝好之後, 還要告訴Jenkins安裝好了Maven, 點選主頁的 Manage Jenkins -> Global Tool Configuration -> Maven -> 新增Maven 新增一個maven

  • Name 只是一個標識, 可以隨便取. 假如安裝了多個版本的maven的話, 在Name上有所區分就好了
  • Maven home 填寫mvn -v的輸出
  • 取消勾選自動安裝

4.5 設定遠端伺服器

遠端伺服器指的是, Jenkins構建好jar包之後, 上傳jar到的伺服器, 同樣也需要設定, 在主頁點選Manage Jenkins -> Configure System

找到 Publish over SSH, 點選新增

  • Name 隨便取, 只是一個標識
  • Hostname 為應用伺服器地址, 因為我們用的是docker橋接網路, 所以不需要輸入IP, 直接填應用容器的名字即可
  • Username 為應用伺服器使用者名稱
  • Remote Directory 表示遠端目錄(應用伺服器), 預設為/root,
  • 勾選上 Use password authentication, or use a different key, 不然沒地方輸密碼
  • Passphrase/Password 表示應用伺服器密碼

右下角有個Test Connecttion, 可以測試連線, 能看到Success就說明設定沒問題了

5. GitLab

5.1 部署GitLab

執行下面的命令執行GitLab容器. 請注意, 如果不使用預設的埠, 除了使用--publish對映埠外, 還需要在環境變數GITLAB_OMNIBUS_CONFIG中註明埠.

$ docker run --detach \
    --env GITLAB_OMNIBUS_CONFIG="external_url='http://127.0.0.1:35080'; gitlab_rails['gitlab_ssh_host'] = '127.0.0.1'; gitlab_rails['gitlab_shell_ssh_port'] = 35022" \
    --memory 12GB \
    --memory-swap 16GB \
    --name gitlab \
    --hostname gitlab \
    --restart on-failure \
    --network my-bridge \
    --publish 35080:80 \
    --publish 35022:22 \
    --volume $PWD/gitlab/config:/etc/gitlab \
    --volume $PWD/gitlab/logs:/var/log/gitlab \
    --volume $PWD/gitlab/data:/var/opt/gitlab \
    gitlab/gitlab-ce:15.6.3-ce.0

5.2 設定GitLab

Gitlab啟動需要幾分鐘, 啟動好之後瀏覽器輸入 http://伺服器地址:35080 進入Gitlab的登入頁面, 預設使用者名稱為root, 密碼通過docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password檢視.

在主頁點選 頭像 -> Preferences -> SSH Keys 可以設定SSH金鑰.

在主頁點選 頭像 -> Preferences -> Password 可以修改密碼.

5.3 上傳專案

GitLab設定好之後就可以推播程式碼了, 在推播程式碼前, 需要GitLab有對應的專案, 我們先來新建一個專案,
點選主頁右上角加號 -> New project -> Create blank project新建一個專案.

接下來推播程式碼. 大家可以推播自己的專案; 我也準備了一個簡單的Spring Boot專案, 地址為 https://github.com/yuanpeilin/spring-boot-demo, 專案比較簡單, 就一個類, 存取URL:8080/hello就能返回當前時間.

這裡比較簡單不做過多描述, 唯一需要注意的是, 我給了一個GitHub地址, 如果用的是我的GitHub專案, 不注意的話推播到GitLab會失敗, 因為從GitHub clone已經用了origin這個名字了, 推播到GitLab要換個名字, 下述三條命令中的origin隨便改個名字, 把三條命令的origin改成一樣的就行.

$$ git remote add origin ssh://[email protected]:35022/root/gitlab-test.git

$$ git remote set-url origin ssh://[email protected]:35022/root/gitlab-test.git

$$ git push -u origin HEAD

6. 聯動

6.1 手動觸發Jenkins

在Jenkins主頁點選 新建專案 -> 構建一個maven專案

接下來就到了設定介面模組

  • 原始碼管理要選擇Git
  • Repository URL要填從GitLab複製來的HTTP形式URL, 例如http://gitlab/root/spring-boot-demo.git, 填完之後點選下空白的地方, 可能會有報錯, 這是因為git倉庫可能被設定為私有的, 要有許可權才能存取
  • 點選下方的Credentials模組的新增GitLab的使用者名稱和密碼, 再次點選空白處, 紅色的報錯已經消失了


下一步設定post step模組, 這是在Jenkins構建好jar包後執行的操作, 點選Add post-build step選擇Send build artifacts over SSH

  • SSH Server選擇設定遠端伺服器設定的應用伺服器, jar包會傳到這個伺服器上
  • Source files選擇jar包相對路徑, 用我的專案的話是target/spring-boot-demo-1.0.jar
  • Remove prefix填入target, 就會自動移除target目錄, 之上傳jar包, 不然傳到應用伺服器會將target目錄也一起上傳, 且jar包也在target目錄下
  • Remote directory填入/app, 會在設定遠端伺服器設定的Remote Directory的基礎上追加, 本文中最終的路徑為/root/app/, jar包在應用伺服器的路徑為/root/app/spring-boot-demo-1.0.jar
  • Exec command填入 bash /root/app/start.sh, 這是在執行了上面的步驟後會執行的命令

在到應用容器中寫入以下內容到 /root/app/start.sh

#!/bin/bash

BASE_HOME=/root/app
JAR_NAME=spring-boot-demo-1.0.jar
LOG_NAME=app.log
# 停止應用
ps -ef | grep $JAR_NAME | grep -v grep | awk '{print $2}' | xargs -i kill {}
# 備份紀錄檔
if [ -f $BASE_HOME/$LOG_NAME ]; then
    mv $BASE_HOME/$LOG_NAME $BASE_HOME/$LOG_NAME.`date +%Y%m%d%H%M%S`
fi
# 備份jar包
if [ -f $BASE_HOME/$JAR_NAME ]; then
    cp $BASE_HOME/$JAR_NAME $BASE_HOME/$JAR_NAME.`date +%Y%m%d%H%M%S`
fi
# 啟動應用
nohup java -jar $BASE_HOME/$JAR_NAME &>$BASE_HOME/$LOG_NAME &

點選儲存後, 點選左邊的立即構建, 再到瀏覽器裡面輸入 http://伺服器地址/hello , 能看到返回了, 就說明應用已經啟動好了.

6.2 通過GitLab自動出發Jenkins構建

點選Jenkins主頁的 Item -> 設定 -> 構建觸發器, 勾選上觸發遠端構建, 填入token, 隨便填入一個值就可以, 這裡設定為aabbcc

設定Token的下方提示了我們可以用JENKINS_URL/job/spring-boot-demo/build?token=TOKEN_NAME觸發, 現在我們再開啟一個無痕視窗, 輸入伺服器地址:37808/job/spring-boot-demo/build?token=aabbcc, 發現要登入?!

之前我們安裝了一個Build Authorization Token Root外掛, 這是因為預設情況下遠端出發jenkins需要登入, 有了這個外掛不需要登入也可以出發Jenkins構建. 再到瀏覽器開個無痕視窗, 根據這個外掛的檔案, 我們存取的地址與上面有所區別, 存取 http://伺服器地址:37808/buildByToken/build?job=spring-boot-demo&token=aabbcc , 然後我們回到Jenkins會發現已經在構建專案了.

現在就簡單了, 回到Gitlab, 在主頁點選頭像 -> Settings -> Web Hooks, 在URL中填入http://伺服器地址:37808/buildByToken/build?job=spring-boot-demo&token=aabbcc, 並取消勾選 Enable SSL verification, 點選儲存就可以了.

現在再隨便改點程式碼, 執行git push 遠端倉庫名, 將程式碼推播到GitLab後, GitLab會自動往設定的地址發生請求, Jenkins就會出發構建, 構建好了後就會自動換包並重啟應用, 至此, 大功告成!!!

7. 參考

  1. 【尚矽谷】Jenkins教學(從設定到實戰) https://www.bilibili.com/video/BV1bS4y1471A/?p=16&share_source=copy_web&vd_source=1df973656734dfeb952c3969e308a1d1
  2. Build Authorization Token Root外掛檔案 https://plugins.jenkins.io/build-token-root/
  3. GitLab官方檔案 https://docs.gitlab.com/ee/install/docker.html