篇幅使用的組件docker,dockerfile,docker-compose,registry,jenkins,gitlab,釘釘通知,篇幅有限,有些未詳細寫到的東西可能需要大家自行摸索。
來介紹下這套自動發布的工作流程及搭建步驟,此文檔只為記錄及展示,為了篇幅不過長,docker,docker-compose,不做贅述,其余組件均使用docker運行,
初始環境:
IP1 : 192.168.18.221,jenkins+gitlab+docker-registry
IP2:192.168.18.222,web
關閉selinux
關閉防火牆
一,安裝docker(兩台機器都裝)
# step 1: 安裝必要的一些系統工具 yum install -y yum-utils device-mapper-persistent-data lvm2 # Step 2: 添加軟件源信息 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo # Step 3: 更新並安裝Docker-CE yum makecache fast yum -y install docker-ce # Step 4: 開啟Docker服務 systemctl start docker
#這里還是添加下鏡像加速
vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://8****lj0.mirror.aliyuncs.com"]
}
二,安裝gtitlab
# 不加 tag 則默認為最新版本 latest docker pull gitlab/gitlab-ce #通常會將 GitLab 的配置 (etc) 、 日志 (log) 、數據 (data) 放到容器之外, 便於日后升級, 因此請先准備這三個目錄。 mkdir -p /srv/gitlab/config mkdir -p /srv/gitlab/logs mkdir -p /srv/gitlab/data #啟動運行gitlab docker run --detach \ --hostname gitlab.example.com \ --publish 8443:443 --publish 8880:80 --publish 8222:22 \ --name gitlab \ --restart always \ --volume /srv/gitlab/config:/etc/gitlab \ --volume /srv/gitlab/logs:/var/log/gitlab \ --volume /srv/gitlab/data:/var/opt/gitlab \
--add-host code.shiji.com:192.168.18.221 \ --privileged=true \ gitlab/gitlab-ce:latest
#這里能成功訪問后就不做額外的配置了,注意修改下配置文件里面的默認訪問地址
#配置下nginx代理后的訪問地址 http://code.shiji.com (這里域名是使用的本地解析,當需要拉取代碼的時候必須要能解析這個域名,)
三,安裝jenkins(這里放上官方文檔 https://jenkins.io/zh/doc/pipeline/tour/deployment/)
#拉取鏡像(這里建議大家使用官方推介的鏡像) docker pull jenkinsci/blueocean:lts
#創建掛載目錄並修改權限
mkdir /home/jenkins
#創建並運行 docker run \ -u root \ -d \ -p 8080:8080 \ -p 50000:50000 \ -v /home/jenkins:/var/jenkins_home \ -v /var/run/docker.sock:/var/run/docker.sock \ #如果需要在容器中運行docker命令,這條必須加上
--add-host code.shiji.com:192.168.18.221 \ #這里我給jenkins添加了一條本地解析
--restart always \
--name jenkins \ jenkinsci/blueocean:latest
#在log中找到初始密碼
docker logs jenkins
#修改密碼后jenkins安裝部分完成
#訪問地址,http://192.168.18.221:8080
#備注,安裝完成記得安裝插件,這里用docker構建,需要安裝 CloudBees Docker Build and Publish
四,搭建registary私倉(需要把把代碼用dockerfile構建后上傳到私倉庫,然后web服務器在拉下來重構,如果希望便捷操作可以使用雲上的私人倉庫)
#拉取鏡像 docker pull registry #創建registry鏡像存儲目錄 mkdir -p /data/registry #創建啟動registry docker run -d -p 5000:5000 --restart=always --name registry -v /data/registry:/var/lib/registry registry:latest
#修改web服務的docker配置文件daemon.json,添加http
vim /etc/docker/daemon.json
{
"insecure-registries": ["http://192.168.18.221:5000"],
"registry-mirrors": ["https://8****lj0.mirror.aliyuncs.com"]
}
#構建完成后registry地址 http://192.168.18.221:5000
五,配置持續集成,這里再次梳理下工作流程,開發人員提交代碼 --> 觸發gitlab鈎子 --jenkins拉取代碼構建 -->構建成功,推送鏡像至私倉 -->web服務器拉取私倉鏡像創建容器 -->通知用戶;當然,失敗的時候也會通知用戶。
1,配置pipeline,
我們在jenkins里創建一個名為多分支的流水線,並且配置好代碼倉,並且讓他每次自動檢出分支,以及檢出前后都清理工作目錄,其他選項使用默認即可,Build Configuration選擇jenkinsfile;
注意:此處配置完成后,scan流水線時會自動從gtilab里識別jenkinsfile文件,
2,配置jenkinsfile文件,語法參考 https://jenkins.io/zh/doc/book/pipeline/,這里直接放出這邊配置好的文件
pipeline { agent any parameters { string(name:'BRANCH_FOR_BODY',defaultValue:"${BRANCH_NAME}",description:'parameters used by ding talk') #此處的兩個參數是為了后面釘釘通知的時候使用,這里后面再說 string(name:'BUILD_URL_FOR_BODY',defaultValue:"${BUILD_URL}",description:'build uri for body') } stages { stage('Deploy-Production') { when { branch 'master' } steps { sh ''' docker build -t ${DOCKER_IMAGE_NAME}:latest -f Dockerfile . ''' sh 'docker push ${DOCKER_IMAGE_NAME}:latest' #這里選擇每次都推送為lastest標簽 sh 'docker rmi ${DOCKER_IMAGE_NAME}:latest' #同時刪除本地構建打好標簽的鏡像 } post { #根據執行標記來決定處理內容 success { sh 'sh notice.sh "test生產環境鏡像推送成功通知" "nginx-test" "推送鏡像成功" ${BRANCH_NAME} ${BUILD_URL}' #此處的釘釘推送腳本最后會放出 } failure{ sh 'sh notice.sh "test生產環境鏡像推送失敗通知" "nginx-test" "推送鏡像失敗" ${BRANCH_NAME} ${BUILD_URL}' } } } } environment { DOCKER_DEPLOY_URI = 'http://nginx.test.shiji.com' #這里只是為了個人使用,此篇幅未用到 DOCKER_IMAGE_NAME = '192.168.18.221:5000/test/nginx-test' #鏡像名稱 DOCKER_SERVICE_NAME = 'TestService' #項目名稱 } }
3,在上面的步驟中我們在構建的時候使用了dockerfile,這里使用個簡單的nginx作為測試
FROM nginx RUN echo 'This is the first version' > /usr/share/nginx/html/index.html
4,接下來我們把dockerfile也上傳至代碼倉,這時構建當然是失敗的,因為后續的釘釘通知腳本還沒有上傳,
查看輸出,可以看到鏡像已經上傳成功
5,至此,持續構建算初步完成,放上釘釘推送信息的腳本,記得把tocken換成自己的,(注意新版本的釘釘機器人要加簽了)
gitAuthor='' gitAuthor=`git show --stat | awk '$0~/Author/{print $2}'` response=`curl -X POST -H 'Content-Type:application/json; charset=utf-8' \ -d '{"msgtype":"markdown",\ "markdown":{"title":"'$1'",\ "text":"## '$1'\n\n**項目名稱**:'$2'\n\n**提交人**:'$gitAuthor'\n\n**狀態**:'$3'\n\n**分支**:'$4'\\n\\n有關更多構建的過程、錯誤信息、單元測試覆蓋率報告請參照 [構建日志]('$5')"\ }}' https://oapi.dingtalk.com/robot/send?access_token=d7f17229b054200xxxxxxxxxxxxxxxxxxxx3204e4dee` echo $response
6,gitlab自動推送,自動構建
1,在jenkins安裝gitlab插件,注意這里並不是哪個gitlabhook的插件
&插件安裝成功后我們修改jenkinsfile增加tigger,關於tigger的語法,官方文檔和往上都給的不太詳細,這里如果想過濾分支等操作參考下這兩篇文章
https://blog.51cto.com/ygqygq2/2461766
http://www.eryajf.net/3298.html
&放上修改完成的jenkinsfile
pipeline { agent any parameters { string(name:'BRANCH_FOR_BODY',defaultValue:"${BRANCH_NAME}",description:'parameters used by ding talk') string(name:'BUILD_URL_FOR_BODY',defaultValue:"${BUILD_URL}",description:'build uri for body') } triggers{ gitlab( triggerOnPush: true, triggerOnMergeRequest: true, branchFilterType: "NameBasedFilter", includeBranchesSpec: "master,dev", secretToken: "028d848ab64f" ) } stages { stage('Deploy-Production') { when { branch 'master' } steps { sh ''' docker build -t ${DOCKER_IMAGE_NAME}:latest -f Dockerfile . ''' sh 'docker push ${DOCKER_IMAGE_NAME}:latest' sh 'docker rmi ${DOCKER_IMAGE_NAME}:latest' } post { success { sh 'sh notice.sh "test生產環境鏡像推送成功通知" "nginx-test" "推送鏡像成功" ${BRANCH_NAME} ${BUILD_URL}' } failure{ sh 'sh notice.sh "test生產環境鏡像推送失敗通知" "nginx-test" "推送鏡像失敗" ${BRANCH_NAME} ${BUILD_URL}' } } } } environment { DOCKER_DEPLOY_URI = 'http://nginx.test.shiji.com' DOCKER_IMAGE_NAME = '192.168.18.221:5000/test/nginx-test' DOCKER_SERVICE_NAME = 'TestService' } }
2,jenkins設置里添加倉庫(這里的tocken需要去gitlab里生成)
3,gitlab項目里創建webhook
4,最后提交一次測試效果(釘釘通知)
7,到這里為止算是初步完成了自動構建,接下來要說說自動發布了,我們已經把鏡像推送到了私倉,接下來只需要在應用服務器上執行命令構建就行,這里說說我們是怎么做的。
應用服務器發布腳本,腳本使用compose發布,腳本執行也是放在Jenkins file里,(這里配置了兩條是為了后續的pipeline多分支),腳本接受兩個參數,一個名稱及標簽,標簽是為了多分支的pipeline准備的,后續再說。
腳本:
tag="$2" # test if [ $1 == "test" ] then cd /docker/compose/test pwd docker pull 192.168.18.221:5000/test/nginx-test:$tag docker-compose up -d test echo "success" elif [ $1 == "test1" ] then cd /docker/compose/test1 docker pull 192.168.18.221:5000/test/nginx-test:$tag docker-compose up -d test2 echo "success" else echo "no equal service" fi
jenkinsfile:(寫在setp階段執行,這里我們使用的是接口的方式,需要在應用服務器上寫個接口去執行上面的腳本,當然你也可以直接遠程執行腳本,過程就不在贅述)
steps { sh ''' docker build -t ${DOCKER_IMAGE_NAME}:latest -f Dockerfile . ''' sh 'docker push ${DOCKER_IMAGE_NAME}:latest' sh 'docker rmi ${DOCKER_IMAGE_NAME}:latest'
sh 'curl ${DOCKER_DEPLOY_URI}/staging?service=${DOCKER_SERVICE_NAME}' #請求接口去執行上面的腳本發布,接口怎么寫的這里我就不放出來了,大家可以省略這一步直接遠程執行腳本(要配置ssh互信)
}
最后:多分支pipeline
上面內容設置了一些變量,就是為此准備的,在這里我們可以對應環境分成多個流水線分支,主要還是修改jenkinsfile:
pipeline { agent any parameters { string(name:'BRANCH_FOR_BODY',defaultValue:"${BRANCH_NAME}",description:'parameters used by ding talk') string(name:'BUILD_URL_FOR_BODY',defaultValue:"${BUILD_URL}",description:'build uri for body') } triggers{ gitlab( triggerOnPush: true, triggerOnMergeRequest: true, branchFilterType: "NameBasedFilter", includeBranchesSpec: "master,dev", secretToken: "028d848ab64f" ) } stages { stage('Deploy-Production') { when { branch 'master' } steps { sh ''' docker build -t ${DOCKER_IMAGE_NAME}:latest -f Dockerfile . ''' sh 'docker push ${DOCKER_IMAGE_NAME}:latest' sh 'docker rmi ${DOCKER_IMAGE_NAME}:latest' sh 'curl ${DOCKER_DEPLOY_URI}/staging?service=${DOCKER_SERVICE_NAME}&tags=latest' } post { success { sh 'sh notice.sh "test生產環境鏡像推送成功通知" "nginx-test" "推送鏡像成功" ${BRANCH_NAME} ${BUILD_URL}' } failure{ sh 'sh notice.sh "test生產環境鏡像推送失敗通知" "nginx-test" "推送鏡像失敗" ${BRANCH_NAME} ${BUILD_URL}' } } } stage('Deploy-Dev') { when { branch 'dev' } steps { sh ''' docker build -t ${DOCKER_IMAGE_NAME}:dev -f Dockerfile . ''' sh 'docker push ${DOCKER_IMAGE_NAME}:dev' sh 'docker rmi ${DOCKER_IMAGE_NAME}:dev' sh 'curl ${DOCKER_DEPLOY_URI}/dev?service=${DOCKER_SERVICE_NAME}&tags=dev' } post { success { sh 'sh notice.sh "test測試環境部署成功通知" "nginx-test" "成功" ${BRANCH_NAME} ${BUILD_URL}' } failure{ sh 'sh notice.sh "test測試環境部署失敗通知" "nginx-test" "失敗" ${BRANCH_NAME} ${BUILD_URL}' } } } } environment { DOCKER_DEPLOY_URI = 'http://dockerup.test.shiji.com' DOCKER_IMAGE_NAME = '192.168.18.221:5000/test/nginx-test' DOCKER_SERVICE_NAME = 'TestService' } }
最后效果
jenkins:
釘釘通知:(這里在實際的生產環境中,並沒有持續部署,所以通知是有區別的)
寫在最后:這篇是使用dockerfile的持續集成,當然還有其他方式,上面文中的連接作了更詳細的講解,各位看官如果能看到最后,歡迎留言指出文中不足的地方。