【Copy攻城獅日志】docker搭建jenkins拉取svn代碼打包vue項(xiàng)目部署到nginx【轉(zhuǎn)】

原文地址:https://segmentfault.com/a/1190000022079215

前言

打開搜索引擎輸入『Copy攻城獅』,發(fā)現(xiàn)最新的一條記錄已經(jīng)是去年的4月,意味著我又有一年時(shí)間沒有再總結(jié)成長(zhǎng)了。習(xí)慣了“溫水煮青蛙”的日子,無(wú)論是經(jīng)驗(yàn)水平還是薪資收入,已經(jīng)被同期的小伙伴遠(yuǎn)遠(yuǎn)地甩在了后頭。開年至今,一直在家“云辦公”的我,被各種打包發(fā)布需求困擾。由于種種原因,小作坊模式的開發(fā)團(tuán)隊(duì)代碼托管依舊用的svn,無(wú)力改變也無(wú)力吐槽,我們項(xiàng)目是完完全全的前后分離,前端用的人人都會(huì)的Vue,之前都是美麗善良的測(cè)試妹妹用公司測(cè)試打包專用電腦自己純手工打包、純手工發(fā)布到服務(wù)器靜態(tài)目錄,然后純手工測(cè)試。后來(lái),打包這項(xiàng)艱巨的任務(wù)就落到前端這邊了,重復(fù)的步驟讓人感覺疲倦:本地電腦新建目錄拉取svn代碼-->安裝npm依賴-->打包不同環(huán)境-->上傳服務(wù)器靜態(tài)目錄,簡(jiǎn)單又繁瑣的工作,加之通過(guò)EasyConnect連接公司內(nèi)網(wǎng)的網(wǎng)速慢到我能絕望。終于,后端看不下去了,提出了要給我上docker的想法,可惜我前端這邊根本就沒用docker去部署,僅僅一個(gè)文件夾丟到nginx靜態(tài)文件服務(wù)器下就行;后端又問(wèn)了我打包命令之類的,后來(lái)就不了了之了。鑒于后端部署用的docker以及jenkins一鍵發(fā)布,我琢磨了一下,前端也能jenkins一鍵發(fā)布啊!不就是把我本地手工輸入的npm命令丟給jenkins去做嗎?說(shuō)干就干,just do it!沒有運(yùn)維的我們擼起袖子就是干!有寫得不當(dāng)?shù)牡胤桨萃懈魑欢喽嘀刚?/p>

docker安裝jenkins

盡管公司機(jī)器已經(jīng)用docker部署了jenkins,秉著學(xué)習(xí)的態(tài)度,我用自己的乞丐版阿里云ECS再操作一遍,雖然不懂原來(lái),人稱『Copy攻城獅』可不是蓋的,一頓copy操作,妥妥的8080端口就起了一個(gè)jenkins服務(wù)。關(guān)于docker的內(nèi)容,我這里就不展開說(shuō),因?yàn)槲乙膊粫?huì),具體可以關(guān)注下圖雀社區(qū)熱乎乎的docker教程,一杯茶的時(shí)間,上手 Docker,真的只用一杯茶的時(shí)間。那我這里就直接安裝jenkins,更詳細(xì)的安裝文檔請(qǐng)移步安裝Jenkins。那我這邊就簡(jiǎn)單三步走啦,三行命令分分鐘起一個(gè)jenkins服務(wù)。

  • 拉取jenkins鏡像

    docker pull jenkins/jenkins
    

    [圖片上傳失敗...(image-5b1db1-1600846533352)]

  • 新建文件夾,用于磁盤掛載

    mkdir /home/jenkins
    
  • 啟動(dòng)服務(wù)

    docker run -itd --name jenkins -p 8080:8080 -p 50000:50000 --privileged=true -v /home/jenkins:/var/jenkins jenkins/jenkins
    

    [圖片上傳失敗...(image-783eb1-1600846533352)]

    難得一把過(guò),沒有翻車沒有bug。我這邊首次打開會(huì)提示密碼放在/var/jenkins_home/secrets/initialAdminPassword,當(dāng)然服務(wù)器上是沒有這個(gè)文件的,需要進(jìn)到docker容器中。當(dāng)然也可以直接通過(guò)安裝日志查看:docker logs jenkins。

    docker ps -a
    docker exec -it jenkins /bin/bash 
    cat /var/jenkins_home/secrets/initialAdminPassword
    

    [圖片上傳失敗...(image-94f8ad-1600846533352)]

    恩恩,拿到密碼了,趕緊Copy過(guò)去試一試!O98K,等待一口茶的時(shí)間,密碼確認(rèn)完畢,我們來(lái)到了初始化頁(yè)面

    [圖片上傳失敗...(image-16928c-1600846533352)]

jenkins初始化翻車

當(dāng)我點(diǎn)擊install選項(xiàng)卡滿懷期待的等待初始化完成的時(shí)候,時(shí)間一點(diǎn)一點(diǎn)的流逝,看著滿屏的紅叉和一動(dòng)不動(dòng)、動(dòng)也不動(dòng)的進(jìn)度條,我開始焦慮,一種不祥的預(yù)感涌上心頭。十分鐘過(guò)去了,二十分鐘過(guò)去了,三十分鐘過(guò)去了......jenkins卡在Getting Started 哼,一定是撞墻了!
[圖片上傳失敗...(image-c4cafd-1600846533354)]

一看到安裝出的問(wèn)題,第一感覺就是撞墻了,改配置文件吧!那就先進(jìn)入jenkins容器唄。最開始以為在jenkins容器root目錄下結(jié)果Permission denied,想到上一步密碼存放在/var/jenkins_home/secrets/initialAdminPassword,那就進(jìn)入/var/jenkins_home/目錄看看,順利地找到了/var/jenkins_home/updates/default.json ,滿懷信心的想打開它看看究竟是怎樣的配置導(dǎo)致jenkins插件安裝這么慢。結(jié)果忘了docker容器默認(rèn)沒有vivim
[圖片上傳失敗...(image-91ba51-1600846533354)]

先通過(guò)docker cp把文件復(fù)制到剛剛新建的/home/jenkins目錄下,查看下default.json究竟有些啥神配置?果然,“一枝紅杏出墻來(lái)”,接下來(lái)的目標(biāo)是將connectionCheckUrl字段改為墻內(nèi)地址。

docker cp jenkins:/var/jenkins_home/updates/default.json /home/jenkins/
vi /home/jenkins/default.json

[圖片上傳失敗...(image-ce4681-1600846533354)]
考慮到我安裝vivim還在坑里沒爬出來(lái),這里就通過(guò)在主環(huán)境上修改完再copy到容器中去,不過(guò)也掉坑里了,坑在直接復(fù)制不生效,我這里先進(jìn)入jenkins容器備份一下default.json,將主環(huán)境修改好的配置文件復(fù)制到jenkins容器/tmp目錄下,再移動(dòng)到/var/jenkins_home/updates/目錄下。再將配置文件復(fù)制到主環(huán)境驗(yàn)證一下是否替換成功。

docker cp /home/jenkins/default.json jenkins:/tmp/
docker exec -u root -it jenkins /bin/bash
mv /var/jenkins_home/updates/default.json /var/jenkins_home/updates/default.json.bak 
mv /tmp/default.json /var/jenkins_home/updates/default.json
exit
docker cp jenkins:/var/jenkins_home/updates/default.json  /home/jenkins/default.json.bak
vi /home/jenkins/default.json.bak

完成修改配置后重啟一下,正常的話能進(jìn)到賬號(hào)注冊(cè)的頁(yè)面。如果還是顯示很多紅叉,右下角重試左邊應(yīng)該會(huì)有個(gè)跳過(guò)的選項(xiàng)。歷經(jīng)了幾個(gè)世紀(jì),終于把插件安裝完了,新手上路!
[圖片上傳失敗...(image-84cf9f-1600846533354)]

Vue項(xiàng)目預(yù)覽

為了高度還原我們簡(jiǎn)單又繁瑣的打包場(chǎng)景,我特意在碼云(不是福報(bào)的那個(gè)哦)上新建了一個(gè)SVN項(xiàng)目,并初始化了一些簡(jiǎn)單配置,如區(qū)分環(huán)境、打包文件添加時(shí)間注釋。關(guān)于Vue項(xiàng)目配置或者webpack配置可移步Vue CLI官方文檔webpack配置的話推薦接地氣的帶你深度解鎖Webpack系列。
本次演示vuedemo項(xiàng)目地址:svn://gitee.com/hu-qi/vue-demo
[圖片上傳失敗...(image-a23a00-1600846533354)]

  • .env文件區(qū)分環(huán)境變量

    .env                # 在所有的環(huán)境中被載入,默認(rèn)開發(fā)
    .env.test           # 只在測(cè)試模式中被載入
    .env.prod           # 只在生產(chǎn)模式中被載入
    
  • package.json
    通過(guò)定義不同指定區(qū)分運(yùn)行/打包不同環(huán)境。

    "serve": "vue-cli-service serve --mode development",
    "serve:test": "vue-cli-service serve --mode test",
    "serve:prod": "vue-cli-service serve --mode prod",
    "dev": "vue-cli-service build --mode development",
    "build": "vue-cli-service build --mode prod",
    "test": "vue-cli-service build --mode test",
    
  • vue.config.js
    簡(jiǎn)單配置webpack輸入目錄,通過(guò) BannerPlugin插件為每個(gè) chunk 文件頭部添加自定義的時(shí)間注釋,以便區(qū)分是否為最新一次發(fā)布。

    const webpack = require('webpack');
    module.exports = {
        publicPath: './',
        outputDir: process.env.outputDir,
        configureWebpack: {
            plugins: [
                new webpack.BannerPlugin(new Date().toLocaleString())
            ]
        }
    };
    
  • 業(yè)務(wù)代碼中獲取環(huán)境配置
    通過(guò)process.env訪問(wèn).env設(shè)置的環(huán)境配置參數(shù)

    
     <template>
         <div class="hello">
             <h1>{{ msg }} - {{ title }}</h1>
             <h2>API: {{ apiUrl }}</h2>
         </div>
     </template>
    
     // ...
     <script>
     export default {
       name: 'HelloWorld',
       props: {
         msg: String
       },
       data() {
         return {
           title: '',
           apiUrl: ''
         }
       },
       created() {
         this.title = process.env.VUE_APP_TITLE
         this.apiUrl = process.env.VUE_APP_URL
       }
     }
     </script>
    
  • 運(yùn)行預(yù)覽
    通過(guò)package.json中定義的運(yùn)行指令,能達(dá)到預(yù)期的效果。
    [圖片上傳失敗...(image-f0aa43-1600846533353)]

  • 打包預(yù)覽
    通過(guò)package.json中定義的打包,能分別打出devtest、prod文件夾,并且文件中的時(shí)間注釋符合預(yù)期。
    [圖片上傳失敗...(image-6337a4-1600846533353)]

  • 發(fā)布到nginx
    這里我依舊通過(guò)docker安裝nginx,將打包出來(lái)的文件夾上傳到放到nginx的靜態(tài)目錄下實(shí)現(xiàn)發(fā)布。這里docker安裝nginx我也只是簡(jiǎn)單安裝實(shí)踐:

    docker pull nginx // 拉取nginx
    docker run -d --name nginxtest -p 80:80 nginx // 啟個(gè)test驗(yàn)證配置
    mkdir -p /home/nginx/{conf,html,logs}  // 宿主新建配置文件夾
    docker cp nginxtest:/etc/nginx/nginx.conf /home/nginx/conf/nginx.conf // 復(fù)制配置文件
    docker stop nginxtest // 停止nginxtest
    docker rm nginxtest // 刪除nginxtest
    docker run  --name nginx -d -p 80:80 -v /home/nginx/conf/nginx.conf:/etc/nginx/nginx.conf -v /home/nginx/logs:/var/log/nginx  -v /home/nginx/html:/usr/share/nginx/html nginx // 運(yùn)行正式nginx并掛載到宿主
    

    只需將打包出來(lái)的文件丟到宿主的/home/nginx/html下就能正常訪問(wèn)了。我這里上傳的prod文件夾,所以可以通過(guò)***/prod訪問(wèn)。
    [圖片上傳失敗...(image-28485b-1600846533352)]

    jenkins打包發(fā)布Vue項(xiàng)目

    回顧一下測(cè)試妹妹純手工打包發(fā)布的步驟:從svn拉取代碼-->安裝npm install依賴包-->npm run build打包prod-->將prod上傳到服務(wù)器nginx靜態(tài)目錄(包括備份上一個(gè)版本)。通過(guò)學(xué)習(xí)和實(shí)踐,通過(guò)給jenkins安裝一些插件,我們能夠輕松的拉取代碼、安裝NodeJS、連接服務(wù)器執(zhí)行shell,構(gòu)建好流程之后只是點(diǎn)下按鈕,所有的事統(tǒng)統(tǒng)交給jenkins,再也不怕測(cè)試妹妹找我打包了。

  • jenkins安裝插件及nodejs
    我這里根據(jù)我們的打包需求安裝的插件主要有Subversion Plug-inPublish Over SSH、NodeJS Plugin。插件安裝在系統(tǒng)管理-->插件管理-->可選插件。搜索對(duì)應(yīng)的插件進(jìn)行安裝。
    [圖片上傳失敗...(image-7f7c84-1600846533353)]
    nodejs的安裝在系統(tǒng)管理-全局工具配置-NodeJS,默認(rèn)是沒有這個(gè)選項(xiàng)的,安裝了NodeJS Plugin就會(huì)有了,這里我安裝的是默認(rèn)的Node版本,一般根據(jù)實(shí)際情況設(shè)置,另外設(shè)置鏡像 cnpm --registry=https://registry.npm.taobao.org
    [圖片上傳失敗...(image-5beed0-1600846533353)]

  • Publish over SSH設(shè)置
    我們安裝了Publish Over SSH插件,在系統(tǒng)管理-->系統(tǒng)設(shè)置能找到對(duì)應(yīng)的設(shè)置位置,這里配置一下我們要部署的服務(wù)器。后面步驟我們通過(guò)執(zhí)行shell腳本在部署的服務(wù)器中打包發(fā)布。
    [圖片上傳失敗...(image-95b3c-1600846533352)]

  • 配置jenkins構(gòu)建任務(wù)
    如果您也有幸苦于打包,您一定和我一定對(duì)于一些簡(jiǎn)單的rm -rf、mvtar等命令已經(jīng)存在你深深的腦海。我這里新建工程命名為vueDemo\-prod。選擇對(duì)應(yīng)的工程-->配置即可進(jìn)入工程配置。首先General我配置的是丟棄舊的構(gòu)建、保持3天構(gòu)建天數(shù)、保持10個(gè)構(gòu)建的最大;然后源碼管理我選擇從svn拉取代碼。
    [圖片上傳失敗...(image-102f93-1600846533352)]
    再然后構(gòu)建環(huán)境我們使用之前安裝的node,用于后面步驟的打包。
    [圖片上傳失敗...(image-bbd3fd-1600846533352)]
    環(huán)境有了,再然后就是構(gòu)建,構(gòu)建這里我們選執(zhí)行shell,命令主要和前端項(xiàng)目配置的打包命令一致,然后再壓縮,方面后續(xù)上傳。
    [圖片上傳失敗...(image-491c5a-1600846533352)]
    最后構(gòu)建后操作就是連接到發(fā)布服務(wù)器,依舊以shell命令的形式執(zhí)行文件上傳、備份、解壓。確保打包出來(lái)的文件夾最終發(fā)布到/home/nginx/html下。
    [圖片上傳失敗...(image-3492a-1600846533352)]

    基本上一套下來(lái),就沒太大問(wèn)題了。應(yīng)用保存一下,點(diǎn)擊立即構(gòu)建。一杯茶的時(shí)間,等待jenkins構(gòu)建成功!
    [圖片上傳失敗...(image-194a24-1600846533352)]

    關(guān)于調(diào)試

    往往前方的路不一定一路順風(fēng),通過(guò)上面的圖能看出即使構(gòu)建成功了,我也踩了不少坑。通過(guò)前面幾次構(gòu)建失敗的日志,我們能清晰的定位到問(wèn)題并予以解決,當(dāng)然整個(gè)流程也十分方便調(diào)試。工程的首頁(yè)面板中的工作空間能查看具體的代碼,點(diǎn)擊某個(gè)構(gòu)建歷史進(jìn)去之后查看控制臺(tái)輸出能看到每次構(gòu)建失敗的具體原因。我遇到過(guò)的問(wèn)題也不少,包括node安裝失敗,時(shí)間不是標(biāo)準(zhǔn)時(shí)間,以及一些shell命令書寫不當(dāng)導(dǎo)致構(gòu)建失??;甚至還遇到docker restart jenkins依舊無(wú)法網(wǎng)頁(yè)的問(wèn)題。失敗并不可怕,可怕的是失敗之后不愿再嘗試!

尾聲

在家“云辦公”的這段時(shí)間,我有很多機(jī)會(huì)來(lái)寫這篇實(shí)踐記錄文章,奈何惰性太強(qiáng),而且實(shí)踐過(guò)程中也屢次碰壁。不過(guò),最終還是有幸產(chǎn)出這篇水文,期待評(píng)論區(qū)各位大佬批評(píng)指正!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容