使用 GitLab + Jenkins 實現自動化構建

背景


在測試環境部署這塊,經歷過以下幾個階段:

  • 階段一

    有一臺測試服務器把項目放上面測試,當初也沒有什么相關的經驗,每次改完代碼本地打包上傳到服務器上,然后一頓命令啟動項目,完成了最原始的部署。

    這種方式構建和部署全靠人肉,項目簡單的時候還好說,項目一多配置一多( 比如微服務 )中間哪個環節粗心出點錯那簡直就是災難。

    同時還要專門有人對運維相關的技術比較了解,不然我不在的時候測試工作就完全停滯了。

  • 階段二

    既然都是重復工作,那就整理下步驟寫個腳本:

    1. SVN/Git 拉代碼

    2. Maven 構建打包

    3. 重啟 Tomcat

    每次執行下腳本就搞定了。看著挺不錯的,不過實際執行時的情況總會復雜許多( 服務器賬號權限、測試人員對 Linux 的熟悉程度、項目啟動依賴復雜等等問題 )。

  • 階段三

    了解到 Jenkins 是個不錯的工具,那就把腳本的內容遷移到 Jenkins 上,不管是開發還是測試只要在 web 界面上點擊一下按鈕即可完成構建部署,很 easy 。

  • 階段四

    容器化:使用 Docker 來部署項目,這樣就可以干掉原來服務器上散落各地參差不齊的 Tomcat ( 不同項目依賴不同 ),利用 Docker Compose 對項目進行編排,提供一種規范的構建配置( 同時也是一份文檔 ),大大減小了后期維護和交接的成本。

  • 階段五

    上面的階段已經能解決日常需求了,但是還有一點問題就是每次提交完代碼還要手動去 Jenkins 上發布,能更自動點就更好了( 嗯,就是懶 )。

    于是就引出了本文的目標 —— 自動持續構建,不需要人工操作 ( 留人工操作用于處理特殊情況 )。

方案流程


cover
  1. 開發提交代碼。

  2. 開發對需要發布的版本打上 Tag

  3. 觸發 GitLabtag push 事件,調用 Webhook

  4. Webhook 觸發 Jenkins 的構建任務。

  5. Jenkins 構建完項目可以按版本號上傳到倉庫、部署、通知相關人員等等。

安裝 GitLab


GitLab 官方文檔 已經介紹的比較詳細了,這里不再贅述,下面給出最終調整過的 Docker Compose 配置( 參考 ):

gitlab:
  image: "twang2218/gitlab-ce-zh:11.0.2"
  restart: always
  hostname: 'gitlab'
  ports:
    - "10022:10022"
    - "10086:10086"
    # postgresql 端口
    - "5432:5432"
  volumes:
    - ./gitlab/data:/var/opt/gitlab
    - ./gitlab/log:/var/log/gitlab
    - ./gitlab/config:/etc/gitlab
  environment:
    GITLAB_OMNIBUS_CONFIG: |
      # 倉庫路徑,填寫宿主機的域名或 IP
      external_url 'http://192.168.xxx.xxx:10086'
      # ssh 連接端口
      gitlab_rails['gitlab_shell_ssh_port'] = 10022

      # 調整工作進程數減小內存占用,最小為 2
      unicorn['worker_processes'] = 2
      # 設置時區
      gitlab_rails['time_zone'] = 'Asia/Shanghai'

      # 郵箱配置
      gitlab_rails['gitlab_email_from'] = '<your_email>'
      gitlab_rails['gitlab_email_display_name'] = '<your_email_name>'
      gitlab_rails['smtp_enable'] = true
      gitlab_rails['smtp_address'] = 'smtp.163.com'
      gitlab_rails['smtp_port'] = 25
      gitlab_rails['smtp_user_name'] = "<your_email_account>"
      gitlab_rails['smtp_password'] = "<your_email_password>"
      gitlab_rails['smtp_domain'] = 'smtp.163.com'
      gitlab_rails['smtp_tls'] = false
      gitlab_rails['smtp_openssl_verify_mode'] = 'none'
      gitlab_rails['smtp_enable_starttls_auto'] = false
      gitlab_rails['smtp_ssl'] = false
      gitlab_rails['smtp_force_ssl'] = false

      # 數據庫配置
      gitlab_rails['db_host'] = '127.0.0.1'
      gitlab_rails['db_port'] = 5432
      gitlab_rails['db_username'] = "gitlab"
      gitlab_rails['db_password'] = "gitlab"

      postgresql['listen_address'] = '0.0.0.0'
      postgresql['port'] = 5432
      postgresql['md5_auth_cidr_addresses'] = %w()
      postgresql['trust_auth_cidr_addresses'] = %w(0.0.0.0/0)
      postgresql['sql_user'] = "gitlab"
      postgresql['sql_user_password'] = Digest::MD5.hexdigest "gitlab" << postgresql['sql_user']

      # 備份設置-保留7天
      gitlab_rails['backup_keep_time'] = 604800
    GITLAB_BACKUPS: "daily"
    GITLAB_SIGNUP: "true"
    GITLAB_ROOT_PASSWORD: "lb80h&85"
    GITLAB_GRAVATAR_ENABLED: "true"

說明:

  • 這里使用 漢化版 鏡像,如果不適應可以換回 官方原版 鏡像 gitlab/gitlab-ce:11.0.2-ce.0

  • 項目初始配置 + 啟動很慢,需要一段時間,日志中出現 Reconfigured 時表示啟動成功。

  • 192.168.xxx.xxx 替換為宿主機的 IP 地址。

  • 初始管理員賬號密碼: root / lb80h&85自行修改配置文件中的密碼 )。

  • 該配置為 乞丐版 ,內存占用 2G+worker_processes 越多內存占用越大,默認為 8G )。

  • postgresql 為容器中內置的數據庫( 賬號密碼: gitlab / gitlab ),非必要情況就不要暴露端口了。

  • 郵箱填寫用于 發送找回密碼和通知 的發件人賬號( 收不到郵件? ),不想配郵箱可以刪掉相關配置,不影響正常使用( 注冊賬號時郵箱可以隨便填 )。

  • 如果指定了 external_url ,那么其中的端口號就是用于 NGINX 監聽的端口號( 如果 nginx['listen_port'] 沒有顯式配置 ),所以上面配置中的端口映射是 10086:10086 而非 10086:80 。( 參考

    Expose GitLab on different ports

  • 由于安全問題,新版本瀏覽器禁用了 10080 端口的訪問,可以換成其他端口。( 參考

安裝 Jenkins


為了測試方便,本文中使用 Docker 化的 Jenkins ,如果需要調用一些特殊的命令或腳本就不是很方便,實際使用過程中可以換成普通版的。

Docker Compose 配置如下:

version: '3'
services:
  jenkins:
    image: jenkins/jenkins:2.456
    container_name: jenkins
    networks:
    - net
    user: "root"
    restart: always
    ports:
    - 9000:8080
    environment:
    - JAVA_OPTS="-Duser.timezone=Asia/Shanghai"
    volumes:
    - /etc/localtime:/etc/localtime:ro
    - ./data:/var/jenkins_home:rw
    - ./backup:/var/jenkins_backup:rw
# 網絡配置
networks:
  net:
    driver: bridge
    ipam:
      driver: default
      config:
      - subnet: 172.23.0.0/16

說明:

  • 初次啟動請打印日志,日志中有管理員賬號的初始密碼,第一次登錄的時候需要用到。

    Jenkins initial setup is required. An admin user has been created and a password generated.
    Please use the following password to proceed to installation:
    
    db7bb60324dc4331bc0dd3e79cc499a5
    
    This may also be found at: /var/jenkins_home/secrets/initialAdminPassword
    
  • 為了方便,使用了 root 賬號啟動 Docker 容器,如果使用默認賬號啟動還需要修改本地目錄( data、backup )的讀寫權限。

  • 初始化過程中有些插件可能搜不到,可以在賬號初始化結束后再進入設置頁面安裝插件。

配置 GitLab


注冊賬號什么的就不贅述了,建一個測試項目 test ,隨便 commit 幾條內容。

GitLab - 新建測試項目

按下圖步驟創建賬號的 access token ,用于 Jenkins 調用 GitLabAPI

GitLab - 創建 access token

GitLab - 獲取 access token

記下這里生成的 access tokengRCtwVWU8cxwHdxxVZJD ),后面要用到。

配置 Jenkins


  • 安裝插件

    安裝過程可能會失敗,多試幾次就好了,可以嘗試更新 Jenkins

    插件 說明
    Git Parameter 用于參數化構建中動態獲取項目分支。
    Generic Webhook Trigger 用于解析 Webhook 傳過來的參數。
    GitLab 用于推送構建結果給 GitLab
  • 添加 GitLab 憑據

    憑據 -> 系統 -> 全局憑據 -> 添加憑據,把上面 GitLab 中生成的 access token 填進去。

    Jenkins - 添加憑據
  • 配置 GitLab 連接

    系統管理 -> 系統設置 -> GitLab 配置項,填入 GitLab 相關的配置,后面配置項目時用到。

    Jenkins - 配置 GitLab 連接
  • 新建項目 test

    Jenkins - 項目完整配置

    新建一個 Job ( 構建一個多配置項目 ),大部分配置可以按上圖照抄:

    • 勾選 參數化構建過程,添加 Git Parameter 類型的參數 ref ,這樣手動點擊構建按鈕( Build with Parameters )的時候就可以指定分支進行構建。

    • Source Code Management 選擇 Git ,添加項目地址和授權方式( 賬號密碼 或者 ssh key ,不能選 GitLab API token ),分支填寫構建參數 $ref

    • Build Triggers 選擇 Generic Webhook Trigger 方式用于解析 GitLab 推過來的詳細參數,其中 TokenGUID / UUID 生成一個。

      用法說明:GitLabWebhook 編輯頁面中點擊 View details 查看調用詳情,其中 Request body 就是傳遞給 Jenkins 的參數,利用 JSONPath 語法( 在線測試 )將這個大的 JSON 解析為一個個小的自定義參數用于后面的構建流程。

      其他觸發方式中: Trigger builds remotelyJenkins 自帶的, Build when a change is pushed to GitLabGitLab 插件 提供的,都屬于簡單的觸發構建,無法做復雜的處理。

    • 雖然 Generic Webhook Trigger 提供了 Token 參數進行鑒權,但為了避免不同項目進行混調( 比如 A 項目提交代碼卻觸發了 B 項目的構建 ),還要對請求做下過濾。 Optional filterText 填寫需要校驗的內容( 可使用變量 ), Expression 使用正則表達式對 Text 進行匹配,匹配成功才允許觸發構建。

    • Build 內容按自己實際的項目類型進行調整,使用 Maven 插件腳本 等等。

    • GitLab Connection 選擇上面添加的 GitLab 連接( JenkinsPost-build Actions 添加 Publish build status to GitLab 動作,實現構建結束后反饋構建結果給 GitLab

  • 回到 GitLab 的項目頁面中,添加一個 Webhook

    http://JENKINS_URL/generic-webhook-trigger/invoke?token=<上面 Jenkins 項目配置中的 token>
    

    觸發器選擇 標簽推送事件 。因為日常開發中 push 操作比較頻繁而且不是每個版本都需要構建,所以只針對需要構建的版本打上 Tag 就好了。

    GitLab - 添加 Webhook

    創建完使用 test 按鈕 先測試下,可能會出現下面的錯誤:

    Hook execution failed: URL 'http://192.168.xxx.xxx:9000/generic-webhook-trigger/invoke?token=d63ad84eb18cb04d4459ec347a196dce' is blocked: Requests to the local network are not allowed

    解決辦法: 允許 GitLab 本地網絡發送 Webhook 請求

測試效果


可以在 GitLab 上直接添加 Tag ,不過我覺得用 IDEA 操作更方便點,就把代碼拉下來在本地操作。

IDEA - 針對每個 commit 添加 Tag

使用快捷鍵 Ctrl + Shift + K 調出 Push 窗口 ,把 Tag 推送到 GitLab 中。

IDEA - Push Tag

回到 GitLab 頁面可以看到觸發了 WebhookView details 查看請求詳情, Response bodytriggered 字段值為 true 則表示成功觸發了 Jenkins 的構建。

如果 triggered 字段值為 false 很可能是 Optional filter 中實際的 Text 值和正則表達式 Expression 不匹配( 見 Response bodyregexpFilterTextregexpFilterExpression 的具體值 ),比如刪除 Tag 的時候沒有 commitsId 就不會匹配上。

GitLab - Webhook 觸發歷史

再看下構建結果:

見上面的 Publish build status to GitLab

GitLab - 查看構建結果 — 流水線

GitLab - 查看構建結果 — commits

注意: 每添加一個 Tag 就會觸發一次事件,不管是不是一起 push 的。所以一次 push 多個 Tag 會觸發 Jenkins 進行多次構建。不過 Jenkins 已經做了處理,默認串行執行任務( 一個任務結束后再執行下一個 ),而且在構建前有一個 pending 狀態,此時被多次觸發會進行合并,并取首次觸發的參數,如下圖所示:

Jenkins - 同時觸發多次事件

測試發現新版 Jenkins 似乎不再合并構建了。

關于 Tag 的幾點說明


  • 推送 Tag 到遠端的時候,遠端已存在( 同名 )的 Tag 不會被添加到遠端。

  • 拉取遠端的 Tag 時,本地已存在( 同名 )的 Tag 不會添加到本地。

  • 拉取遠端的 Tag 時,本地不會刪除遠端已刪除的 Tag ,需要同步遠端的 Tag 可以先刪除本地所有 Tag 再進行 pull

  • 刪除 Tag 也會推送事件,要做好過濾( 上面配置中已使用 commitsId 字段進行過濾 )。

后續


通過上面的步驟已經初步實現了想要的效果,還有幾個點后續可以再考慮下:

  • 上文只包含自動構建的內容,對于項目的部署可以考慮幾種方式:手動選擇指定的版本進行發布、構建任務結束后直接觸發部署任務、定時部署最新版本( 根據實際需求調整 )。

  • 測試發版的頻率會比較高,會生成大量的 Tag ,可以約定 Tag 的格式,比如用 test 0.0.1 表示觸發測試環境的項目構建,用 online 1.0.0 表示觸發正式版本構建,隔離之后可以方便后續的維護和清理。

  • 構建部分可以整合 Docker ,把構建結果打包到 Docker 鏡像中( 代碼版本庫的 Tag 正好可以作為鏡像的 Tag ),再上傳到 Docker 鏡像倉庫( 私服 或者第三方倉庫 )中,后續部署就可以直接從鏡像倉庫拉取鏡像直接運行了。

  • 集成自動化測試 ,比如 這個

  • 嘗試配置 GitLab 自帶的 CI / CD

相關


總結


以上就是對曾經踩過的一些坑進行的整合,也沒什么好總結的。總之,合理地利用現有工具來解放雙手,就能有更多時間做其他想做的事!

時間有限一些基礎的步驟就不細講直接一筆帶過了,方案上可能有些細節方面也沒考慮全,歡迎評論留言。


轉載請注明出處: http://www.lxweimin.com/p/7e8037c63d63

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,763評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,238評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,823評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,604評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,339評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,713評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,712評論 3 445
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,893評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,448評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,201評論 3 357
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,397評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,944評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,631評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,033評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,321評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,128評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,347評論 2 377

推薦閱讀更多精彩內容