使用 Jenkins + Ansible 實現(xiàn) Springboot 自動化部署101

首發(fā)于 Jenkins 中文社區(qū)

image.png

本文要點:

  1. 設(shè)計一條 Spring Boot 最基本的流水線:包括構(gòu)建狞谱、制品上傳壳炎、部署哲虾。
  2. 使用 Docker 容器運(yùn)行構(gòu)建邏輯锦亦。
  3. 自動化整個實驗環(huán)境:包括 Jenkins 的配置,Jenkins agent 的配置等嫂拴。

1. 代碼倉庫安排

本次實驗涉及以下多個代碼倉庫:

% tree -L 1
├── 1-cd-platform # 實驗環(huán)境相關(guān)代碼
├── 1-env-conf # 環(huán)境配置代碼-實現(xiàn)配置獨立
└── 1-springboot # Spring Boot 應(yīng)用的代碼及其部署代碼

1-springboot 的目錄結(jié)構(gòu)如下:

% cd 1-springboot
% tree -L 1 
├── Jenkinsfile # 流水線代碼
├── README.md
├── deploy # 部署代碼
├── pom.xml 
└── src # 業(yè)務(wù)代碼

所有代碼播揪,均放在 GitHub:https://github.com/cd-in-practice

2. 實驗環(huán)境準(zhǔn)備

筆者使用 Docker Compose + Vagrant 進(jìn)行實驗。環(huán)境包括以下幾個系統(tǒng):

  • Jenkins * 1
    Jenkins master筒狠,全自動安裝插件猪狈、默認(rèn)用戶名密碼:admin/admin。
  • Jenkins agent * 2
    Jenkins agent 運(yùn)行在 Docker 容器中辩恼,共啟動兩個雇庙。
  • Artifactory * 1
    一個商業(yè)版的制品庫谓形。筆者申請了一個 30 天的商業(yè)版。

使用 Vagrant 是為了啟動虛擬機(jī)疆前,用于部署 Spring Boot 應(yīng)用寒跳。如果你的開發(fā)機(jī)器無法使用 Vagrant,使用 VirtualBox 也可以達(dá)到同樣的效果竹椒。但是有一點需要注意童太,那就是網(wǎng)絡(luò)。如果在虛擬機(jī)中要訪問 Docker 容器內(nèi)提供的服務(wù)胸完,需要在 DNS 上或者 hosts 上做相應(yīng)的調(diào)整书释。所有的虛擬機(jī)的鏡像使用 Centos7。

另舶吗,接下來筆者的所有教程都將使用 Artifactory 作為制品庫征冷。在此申明,筆者沒有收 JFrog——研發(fā) Artifactory 產(chǎn)品的公司——任何廣告費(fèi)誓琼。 筆者只是想試用商業(yè)產(chǎn)品,以便了解商業(yè)產(chǎn)品是如何應(yīng)對制品管理問題的肴捉。

啟動 Artifactory 后腹侣,需要添加 “Virtual Repository” 及 “Local Repository”。具體請查看 Artifactory 的官方文檔齿穗。如果你當(dāng)前使用的是 Nexus傲隶,參考本教程,做一些調(diào)整窃页,問題也不大跺株。

如果想使用已有制品庫,可以修改 1-cd-platform 倉庫中的 settings-docker.xml 文件脖卖,指向自己的制品庫乒省。

實驗環(huán)境近期的總體結(jié)構(gòu)圖如下:

image.png

之所以說是“近期的”,是因為上圖與本篇介紹的結(jié)構(gòu)有小差異畦木。本篇文章還沒有介紹 Nginx 與 Springboot 配置共用袖扛,但是總體不影響讀者理解。

3. Springboot 應(yīng)用流水線介紹

Springboot 流水線有兩個階段:

  1. 構(gòu)建并上傳制品
  2. 部署應(yīng)用

流水線的所有邏輯都寫在 Jenkinsfile 文件十籍。接下來蛆封,分別介紹這兩個階段。

3.1 構(gòu)建并上傳制品

此階段核心代碼:

docker.image('jenkins-docker-maven:3.6.1-jdk8')
.inside("--network 1-cd-platform_cd-in-practice -v $HOME/.m2:/root/.m2") {
    sh """
      mvn versions:set -DnewVersion=${APP_VERSION}
      mvn clean test package
      mvn deploy
    """
}

它首先啟動一個裝有 Maven 的容器勾栗,然后在容器內(nèi)執(zhí)行編譯惨篱、單元測試、發(fā)布制品的操作围俘。

mvn versions:set -DnewVersion=${APP_VERSION} 的作用是更改 pom.xml 文件中的版本砸讳。這樣就可以實現(xiàn)每次提交對應(yīng)一個版本的效果机断。

3.2 部署應(yīng)用

注意: 這部分需要一些 Ansible 的知識。

首先看部署腳本的入口 1-springboot/deploy/playbook.yaml

---
- hosts: "springboot"
  become: yes
  roles:
    - {"role": "ansible-role-java", "java_home": "{{JAVA_HOME}}"}
    - springboot

先安裝 JDK绣夺,再安裝 Spring Boot吏奸。JDK 的安裝,使用了現(xiàn)成 Ansible role: https://github.com/geerlingguy/ansible-role-java陶耍。

重點在 Spring Boot 部署的核心邏輯奋蔚。它主要包含以下幾部分:

  1. 創(chuàng)建應(yīng)用目錄。
  2. 從制品庫下載指定版本的制品烈钞。
  3. 生成 Systemd service 文件(實現(xiàn)服務(wù)化)泊碑。
  4. 啟動服務(wù)。

以上步驟實現(xiàn)在 1-springboot/deploy/roles/springboot 中毯欣。

流水線的部署階段的核心代碼如下:

docker.image('williamyeh/ansible:centos7').inside("--network 1-cd-platform_cd-in-practice") {

  checkout([$class: 'GitSCM', branches: [[name: "master"]], doGenerateSubmoduleConfigurations: false,
            extensions: [[$class: 'RelativeTargetDirectory', relativeTargetDir: "env-conf"]], submoduleCfg: [],
            userRemoteConfigs: [[url: "https://github.com/cd-in-practice/1-env-conf.git"]]])

  sh "ls -al"

  sh """
    ansible-playbook --syntax-check deploy/playbook.yaml -i env-conf/dev
    ansible-playbook deploy/playbook.yaml -i env-conf/dev --extra-vars '{"app_version": "${APP_VERSION}"}'
  """
}

它首先將配置變量倉庫的代碼 clone 下來馒过,然后對 playbook 進(jìn)行語法上的檢查,最后執(zhí)行 ansible-playbook 命令進(jìn)行部署酗钞。--extra-vars 參數(shù)的 app_version 用于指定將要部署的應(yīng)用的版本腹忽。

3.3 實現(xiàn)簡易指定版本部署

1-springboot/Jenkinsfile 中實現(xiàn)了簡易的指定版本部署。核心代碼如下:

  1. 流水線接受參數(shù)
parameters { string(name: 'SPECIFIC_APP_VERSION', 
defaultValue: '', description: '') }
  1. 如果指定了版本砚作,則跳過構(gòu)建階段窘奏,直接執(zhí)行部署階段
stage("build and upload"){
      // 如果不指定部署版本,則執(zhí)行構(gòu)建
      when {
        expression{ return params.SPECIFIC_APP_VERSION == "" }
      }
      // 構(gòu)建并上傳制品的邏輯
      steps{...}
}

之所以說是“簡易”葫录,是因為部署時只指定了制品的版本着裹,并沒有指定的部署邏輯和配置的版本。這三者的版本要同步米同,部署才真正做到準(zhǔn)確骇扇。

4. 配置管理

所有的配置項都放在 1-env-conf 倉庫中。Ansible 執(zhí)行部署時會讀取此倉庫的配置面粮。

將配置放在 Git 倉庫中有兩個好處:

  1. 配置版本化少孝。
  2. 任何配置的更改都可以被審查。

有好處并不代表沒有成本但金。那就是開發(fā)人員必須開始關(guān)心軟件的配置(筆者發(fā)現(xiàn)不少開發(fā)者忽視配置項管理的重要性韭山。)。

本文重點不在配置管理冷溃,后面會有文章重點介紹钱磅。

5. 實驗環(huán)境詳細(xì)介紹

事實上,整個實驗似枕,工作量大的地方有兩處:一是 Spring Boot 流水線本身的設(shè)計盖淡;二是整個實驗環(huán)境的自動化。讀者朋友之所以能一兩條簡單的命令就能啟動整個實驗環(huán)境凿歼,是因為筆者做了很多自動化的工作褪迟。筆者認(rèn)為有必要在本篇介紹這些工作冗恨。接下來的文章將不再詳細(xì)介紹。

5.1 解決流水線中啟動的 Docker 容器無法訪問 http://artifactory

流水線中味赃,我們需要將制品上傳到 artifactory(settings.xml 配置的倉庫地址是 http://artifactory:8081)掀抹,但是發(fā)現(xiàn)無法解析 host。這是因為流水線中的 Docker 容器所在網(wǎng)絡(luò)與 Docker compose 創(chuàng)建的網(wǎng)絡(luò)不同心俗。所以傲武,解決辦法就是讓流水線中的 Docker 容器加入到 Docker compose 的網(wǎng)絡(luò)。

具體解決辦法就是在啟動容器時城榛,加入?yún)?shù):--network 1-cd-platform_cd-in-practice

5.2 Jenkins 初次啟動初始化

在沒有做任何設(shè)置的情況啟動 Jenkins揪利,會出現(xiàn)一個配置向?qū)А_@個過程必須是手工的狠持。筆者希望這一步也是自動化的疟位。Jenkins 啟動時會執(zhí)行 init.groovy.d/目錄下的 Groovy 腳本。

5.3 虛擬機(jī)中如何能訪問到 http://artifactory 喘垂?

http://artifactory 部署在 Docker 容器中甜刻。Spring Boot 應(yīng)用的制品要部署到虛擬機(jī)中,需要從 http://artifactory 中拉取制品王污,也就是要在虛擬機(jī)里訪問容器里提供的服務(wù)罢吃。虛擬機(jī)與容器之間的網(wǎng)絡(luò)是不通的。那怎么辦呢昭齐?筆者的解決方案是使用宿主機(jī)的 IP 做中轉(zhuǎn)。具體做法就是在虛擬機(jī)中加一條 host 記錄:

machine.vm.provision "shell" do |s|
    s.inline = "echo '192.168.52.1 artifactory' >> /etc/hosts"
end

以上是使用了 Vagrant 的 provision 技術(shù)矾柜,在執(zhí)行命令 vagrant up 啟動虛擬機(jī)時阱驾,就自動執(zhí)行那段內(nèi)聯(lián) shell。192.168.52.1 是虛擬宿主機(jī)的 IP怪蔑。所以里覆,虛擬機(jī)里訪問 http://artifactory:8081 時,實際上訪問的是 http://192.168.52.1:8081缆瓣。

網(wǎng)絡(luò)結(jié)構(gòu)可以總結(jié)為下圖:

image.png

后記

目前遺留問題:

  1. 部署時制品版本喧枷、配置版本、部署代碼版本沒有同步弓坞。
  2. Springboot 的配置是寫死在制品中的隧甚,沒有實現(xiàn)制品與配置項的分離。

這些遺留問題在后期會逐個解決渡冻。就像現(xiàn)實一樣戚扳,經(jīng)常需要面對各種遺留項目的遺留問題。

附錄

  1. 使用 Jenkins + Ansible 實現(xiàn)自動化部署 Nginx:https://jenkins-zh.cn/wechat/articles/2019/04/2019-04-25-jenkins-ansible-nginx/
  2. 簡單易懂 Ansible 系列 —— 解決了什么:https://showme.codes/2017-06-12/ansible-introduce/

本文作者:翟志軍

image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末族吻,一起剝皮案震驚了整個濱河市帽借,隨后出現(xiàn)的幾起案子珠增,更是在濱河造成了極大的恐慌,老刑警劉巖砍艾,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蒂教,死亡現(xiàn)場離奇詭異,居然都是意外死亡脆荷,警方通過查閱死者的電腦和手機(jī)凝垛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來简烘,“玉大人苔严,你說我怎么就攤上這事」屡欤” “怎么了届氢?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長覆旭。 經(jīng)常有香客問我退子,道長,這世上最難降的妖魔是什么型将? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任寂祥,我火速辦了婚禮,結(jié)果婚禮上七兜,老公的妹妹穿的比我還像新娘丸凭。我一直安慰自己,他們只是感情好腕铸,可當(dāng)我...
    茶點故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布惜犀。 她就那樣靜靜地躺著,像睡著了一般狠裹。 火紅的嫁衣襯著肌膚如雪虽界。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天涛菠,我揣著相機(jī)與錄音莉御,去河邊找鬼。 笑死俗冻,一個胖子當(dāng)著我的面吹牛礁叔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播言疗,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼晴圾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了噪奄?” 一聲冷哼從身側(cè)響起死姚,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤人乓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后都毒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體色罚,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年账劲,在試婚紗的時候發(fā)現(xiàn)自己被綠了戳护。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡瀑焦,死狀恐怖腌且,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情榛瓮,我是刑警寧澤铺董,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站禀晓,受9級特大地震影響精续,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜粹懒,卻給世界環(huán)境...
    茶點故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一重付、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧凫乖,春花似錦确垫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嚣镜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間橘蜜,已是汗流浹背菊匿。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留计福,地道東北人跌捆。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像象颖,于是被迫代替她去往敵國和親佩厚。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,666評論 2 350

推薦閱讀更多精彩內(nèi)容