1. 程式人生 > >基於Docker容器的,Jenkins、GitLab構建持續整合CI

基於Docker容器的,Jenkins、GitLab構建持續整合CI

摘要: 一、場景: 開發者將程式碼提交(push)到GitLab後,GitLab通過Hook通知jenkins,jenkins自動從GitLab中獲取專案最新的原始碼進行整合和釋出。 二、準備: 基於Docker,建立一個私有GitLab的容器,建立一個jenkins的容器 三、步驟 1、構建Jenkins容器 Jenkins容器安裝Jenkins的rpm包,Jenkins依賴 JDK,所以需要在Jenkins的容器中安裝配置jdk,本人使用jdk1.8,同時需要Jenkins的容器呼叫maven的打包命令,所以也需要配置安裝maven,本人使用maven 3.3.9。

** 開發者將程式碼提交(push)到GitLab後,GitLab通過Hook通知jenkins,jenkins自動從GitLab中獲取專案最新的原始碼進行整合和釋出。

基於Docker,建立一個私有GitLab的容器,建立一個jenkins的容器**

1. 構建私有的GitLab容器

https://about.gitlab.com/installation/#centos-7,直接安裝gitlab,不借助docker

通過docker-compose的方式安裝gitlab,docker-compose這個命令需要單獨安裝,docker-compose會對指定目錄下的docker-compose.yml檔案進行執行,這個檔案會一次性啟動所編輯的映象,及所要用到的引數,官方提供的yml檔案內容如下:

作為一個開發者,有一個學習的氛圍跟一個交流圈子特別重要這是一個我的

QQ群架構華山論劍:836442475,不管你是小白還是大牛歡迎入駐 ,分享BAT,阿里面試題、面試經驗,討論技術, 大家一起交流學習成長!

version: '2'

services:
  redis:
    restart: always
    image: sameersbn/redis:latest
    command:
    - --loglevel warning
    volumes:
    - /srv/docker/gitlab/redis:/var/lib/redis:Z   #檔案的掛載點

  postgresql:
    restart: always
    image: sameersbn/postgresql:9.6-2
    volumes:
    - /srv/docker/gitlab/postgresql:/var/lib/postgresql:Z   #檔案的掛載點
    environment:
    - DB_USER=gitlab
    - DB_PASS=password
    - DB_NAME=gitlabhq_production
    - DB_EXTENSION=pg_trgm

  gitlab:
    restart: always
    image: sameersbn/gitlab:9.1.4
    depends_on:
    - redis
    - postgresql
    ports:
    - "10080:80"
    - "10022:22"
    volumes:
    - /srv/docker/gitlab/gitlab:/home/git/data:Z  #檔案的掛載點
    environment:
    - DEBUG=false

    - DB_ADAPTER=postgresql
    - DB_HOST=postgresql
    - DB_PORT=5432
    - DB_USER=gitlab
    - DB_PASS=password
    - DB_NAME=gitlabhq_production

    - REDIS_HOST=redis
    - REDIS_PORT=6379

    - TZ=Asia/Kolkata
    - GITLAB_TIMEZONE=Kolkata

    - GITLAB_HTTPS=false
    - SSL_SELF_SIGNED=false

    - GITLAB_HOST=localhost
    - GITLAB_PORT=10080
    - GITLAB_SSH_PORT=10022
    - GITLAB_RELATIVE_URL_ROOT=
    - GITLAB_SECRETS_DB_KEY_BASE=long-and-random-alphanumeric-string
    - GITLAB_SECRETS_SECRET_KEY_BASE=long-and-random-alphanumeric-string
    - GITLAB_SECRETS_OTP_KEY_BASE=long-and-random-alphanumeric-string

    - GITLAB_ROOT_PASSWORD=
    - GITLAB_ROOT_EMAIL=

    - GITLAB_NOTIFY_ON_BROKEN_BUILDS=true
    - GITLAB_NOTIFY_PUSHER=false

    - 
[email protected]
- [email protected] - [email protected] - GITLAB_BACKUP_SCHEDULE=daily - GITLAB_BACKUP_TIME=01:00 - SMTP_ENABLED=false - SMTP_DOMAIN=www.example.com - SMTP_HOST=smtp.gmail.com - SMTP_PORT=587 - [email protected] - SMTP_PASS=password - SMTP_STARTTLS=true - SMTP_AUTHENTICATION=login - IMAP_ENABLED=false - IMAP_HOST=imap.gmail.com - IMAP_PORT=993 - [email protected] - IMAP_PASS=password - IMAP_SSL=true - IMAP_STARTTLS=false - OAUTH_ENABLED=false - OAUTH_AUTO_SIGN_IN_WITH_PROVIDER= - OAUTH_ALLOW_SSO= - OAUTH_BLOCK_AUTO_CREATED_USERS=true - OAUTH_AUTO_LINK_LDAP_USER=false - OAUTH_AUTO_LINK_SAML_USER=false - OAUTH_EXTERNAL_PROVIDERS= - OAUTH_CAS3_LABEL=cas3 - OAUTH_CAS3_SERVER= - OAUTH_CAS3_DISABLE_SSL_VERIFICATION=false - OAUTH_CAS3_LOGIN_URL=/cas/login - OAUTH_CAS3_VALIDATE_URL=/cas/p3/serviceValidate - OAUTH_CAS3_LOGOUT_URL=/cas/logout - OAUTH_GOOGLE_API_KEY= - OAUTH_GOOGLE_APP_SECRET= - OAUTH_GOOGLE_RESTRICT_DOMAIN= - OAUTH_FACEBOOK_API_KEY= - OAUTH_FACEBOOK_APP_SECRET= - OAUTH_TWITTER_API_KEY= - OAUTH_TWITTER_APP_SECRET= - OAUTH_GITHUB_API_KEY= - OAUTH_GITHUB_APP_SECRET= - OAUTH_GITHUB_URL= - OAUTH_GITHUB_VERIFY_SSL= - OAUTH_GITLAB_API_KEY= - OAUTH_GITLAB_APP_SECRET= - OAUTH_BITBUCKET_API_KEY= - OAUTH_BITBUCKET_APP_SECRET= - OAUTH_SAML_ASSERTION_CONSUMER_SERVICE_URL= - OAUTH_SAML_IDP_CERT_FINGERPRINT= - OAUTH_SAML_IDP_SSO_TARGET_URL= - OAUTH_SAML_ISSUER= - OAUTH_SAML_LABEL="Our SAML Provider" - OAUTH_SAML_NAME_IDENTIFIER_FORMAT=urn:oasis:names:tc:SAML:2.0:nameid-format:transient - OAUTH_SAML_GROUPS_ATTRIBUTE= - OAUTH_SAML_EXTERNAL_GROUPS= - OAUTH_SAML_ATTRIBUTE_STATEMENTS_EMAIL= - OAUTH_SAML_ATTRIBUTE_STATEMENTS_NAME= - OAUTH_SAML_ATTRIBUTE_STATEMENTS_FIRST_NAME= - OAUTH_SAML_ATTRIBUTE_STATEMENTS_LAST_NAME= - OAUTH_CROWD_SERVER_URL= - OAUTH_CROWD_APP_NAME= - OAUTH_CROWD_APP_PASSWORD= - OAUTH_AUTH0_CLIENT_ID= - OAUTH_AUTH0_CLIENT_SECRET= - OAUTH_AUTH0_DOMAIN= - OAUTH_AZURE_API_KEY= - OAUTH_AZURE_API_SECRET= - OAUTH_AZURE_TENANT_ID=

在docker-compose.yml檔案所在目錄下,執行docker-compose up命令(docker-compose命令需要安裝),如果之前沒有下載過GitLab的映象會自動下載,如果下載過就直接啟動已有的容器。

這裡會在docker建立一個新的網橋,gitlab所需要的gitlab容器和redis容器及postgresql容器都在這個網橋指定的網段內,可以通過docker network ls檢視.

網橋的名稱通常為你yml檔案所在目錄名稱的小寫加上下劃線default,例如mygitlab_default。這個很有用,因為如果你想要容器內部互聯,就需要指定所要連線的容器在一個網段內,例如jenkins容器如果想內部連線gitlab容器,就得都在mygitlab_default這個網橋提供的網段內,Docker預設會為容器指定在docker0這個網段內的一個ip,通常會是172.17.. 我的gitlab預設在172.18,所以需要在接下來建立jenkins容器並啟動時,指定到18這個網段內,當然你想通過宿主機的ip和埠也是可以的

執行完成之後,gitlab容器的80埠繫結在了宿主機的10080埠,同時gitlab容器的22埠(ssh)繫結在宿主機10022埠。可以通過訪問localhost:10080來訪問私有倉庫

2. 構建Jenkins容器

Jenkins容器安裝Jenkins的rpm包,Jenkins依賴 JDK,所以需要在Jenkins的容器中安裝配置jdk,本人使用jdk1.8,同時需要Jenkins的容器呼叫maven的打包命令,所以也需要配置安裝maven,本人使用maven 3.3.9。

a.通過Dockerfile構建一個jenkins容器,基於centos7的映象。



這裡不推薦將一個基礎映象一次性打包成完整的應用映象,建議構建三層映象模型。
所謂三層映象就是,基礎映象,中介軟體映象,應用映象。例如我要構建一個Jenkins 的映象,打包一個基於Centos7 和一些常用工具的映象就是基礎映象,例如叫Centos7-base。然後這裡Jenkins依賴Java和Maven,所以在基於Centos7-base的基礎上安裝配置java及maven後,再打包的映象為中介軟體映象,例如叫Centos7-jdk8-mvn3,這層中介軟體的映象我們為來的複用會很高,以後只要有基於java1.8和maven3的,就可以直接使用這個映象進行構建。最後我們再在Centos7-jdk8-mvn3的基礎上安裝配置jenkins,最後打包運用在生產環境。

b.構建基礎映象,整合jdk及mvn。配置PATH ,安裝所需要的工具,Dockerfile如下:

#base on centos 7 image

FROM daocloud.io/centos:7
MAINTAINER hoewon
LABEL JDK \ 1.8

COPY jdk1.8 /usr/local/jdk1.8/  \
             maven /usr/local/maven/

RUN yum install -y openssh-server openssh-clients git 

RUN yum install -y iproute  net-tools

ENV JAVA_HOME /usr/local/jdk1.8


ENV PATH $JAVA_HOME/bin:$PATH

EXPOSE 8080


ENTRYPOINT /bin/bash
將要複製進映象裡的jdk和maven檔案放到與Dockerfile相同的目錄下

執行命令打包映象

#最後 . 是當前目錄的意思,不可省略,或自定義Dockerfile所在目錄

docker build -t repo/name:tag  .  

#成功後檢視本地映象

docker images 

c.通過基礎映象安裝jenkins,也是通過Dockerfile

#A jenkins 2.7.4 on centos 7 image
#基於剛才做好的基礎映象
FROM 127.0.0.1:5000/env/centos7-jdk8-mvn:1.3
MAINTAINER hoewon
LABEL JDK1.8 \ Jenkins-2.7.4
#複製jenkins rpm至映象
COPY jenkins.rpm /usr/local/

#建立jenkins使用者,並更改密碼

RUN useradd jenkins && echo "jenkins password"  > passwd jenkins --stdin

#安裝jenkins

RUN rpm -ivh /usr/local/jenkins.rpm

#更改jenkins安裝檔案的所有者

RUN rpm -ql jenkins | xargs chown -R jenkins:jenkins

#建立jenkins日誌檔案

RUN touch /usr/lib/jenkins/jenkins-logs 

#更改日誌檔案所有者

RUN chown jenkins:jenkins /usr/lib/jenkins/jenkins-logs

#曝光8080埠

EXPOSE 8080

#啟動容器時使用jenkins使用者

USER jenkins

#定義使用者空間為工作空間

WORKDIR /home/jenkins

#啟動容器時啟動jenkins

ENTRYPOINT java -jar /usr/lib/jenkins/jenkins.war &> /usr/lib/jenkins/jenkins-logs

d.執行jenkins容器,這裡需要將container的網路設定跟GtiLab同網路的環境下,同時我們希望jenkins容器在用maven打包之後,在呼叫docker驚醒封裝映象,然後推送映象至私有的映象倉庫,所以我們把宿主機的/usr/bin/docker 和/run/docker.sock 和所依賴的共享庫檔案,在啟動容器時一併掛載至容器內部。

# --net 指定docker的網橋
 docker run -idt   --net mygitlab_default --name jenkins_c -p 8888:8080 -v /usr/lib64/libltdl.so.7:/usr/lib64/libltdl.so.7  -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker 127.0.0.1:5000/myjenkins:1.0 /bin/bash

e.容器啟動後,8080埠被繫結到了宿主機的8888埠,訪問localhost:8888來訪問jenkins
首次登入jenkins會需要輸入jenkins的超級管理員密碼,這個密碼在jenkins第一次啟動的日誌中,可以進入jenkins容器,檢視執行日誌,也可以根據頁面提示,直接去jenkins的家目錄下一個.jenkins/secrets/init…..的檔案內檢視密碼。登入後註冊一個使用者,並在系統管理-管理外掛下,安裝GitLab的外掛。第一次執行jenkins會讓你選擇安裝外掛,選擇第一個推薦的安裝後,在管理外掛的可選外掛tab下搜尋Gitlab Plugin 和Gitlab Hook Plugin外掛進行安裝,然後重啟jenkins

3.構建私有的Docker 映象倉庫
拉取一個docker 的映象倉庫映象,並執行該容器,容器執行後會繫結宿主機5000埠,我個人用的是daocloud.io提供的映象,這個映象倉庫需要註冊。

docker run \
         -e SETTINGS_FLAVOR=s3 \
         -e AWS_BUCKET=acme-docker \
         -e STORAGE_PATH=/registry \
         -e AWS_KEY=AKIAHSHB43HS3J92MXZ \
         -e AWS_SECRET=xdDowwlK7TJajV1Y7EoOZrmuPEJlHYcNP2k4j49T \
         -e SEARCH_BACKEND=sqlalchemy \
         -p 5000:5000 \
         daocloud.io/registry

執行成功後,可以訪問http://localhost:5000/v2/_catalog 來檢視本地倉庫資訊

4.構建持續整合環境
萬事具備,下面我們開始利用gitlab,jenkins,來構建持續整合環境。

a.在gitlab中建立一個專案,專案類為public,建立後會有如下提示,這些提示用來告訴你如何通過客戶端下載專案,並提交專案

#Command line instructions 
#Git global setup
git config --global user.name "jenkins"
git config --global user.email "[email protected]"
#Create a new repository
git clone ssh://[email protected]:10022/jenkins/demo.git
cd demo
touch README.md
git add README.md
git commit -m "add README"
git push -u origin master
#Existing folder
cd existing_folder
git init
git remote add origin ssh://[email protected]:10022/jenkins/demo.git
git add .
git commit
git push -u origin master
#Existing Git repository
cd existing_repo
git remote add origin ssh://[email protected]:10022/jenkins/demo.git
git push -u origin --all
git push -u origin --tags

b.進入jenkins容器,然後通過git客戶端,拉取專案。在拉取之前,需要用使用ssh-keygen來生成當前jenkins使用者在jenkins容器的公鑰金鑰,ssh-keygen需要安裝openssh。

ssh-keygen – t rsa

可以一路回車,預設生成在jenkins使用者的家目錄下的一個.ssh的資料夾,將.ssh/id_rsa.pub的內容全部複製

c.登入gitlab,右上角下拉列表下選擇setting,然後在主頁面有一個SSH Keys的tab頁,將你剛才複製的公鑰內容新增至Key這個文字框,然後點選Add key。這個步驟的意思是,如果你想讓jenkins通過ssh協議從gitlab拉取專案,需要認證,配置的公鑰就是允許jenkins容器的jenkins使用者所執行的jenkins從gitlab通過ssh協議拉取專案(有點彆扭,但是需要注意的是jenkins這個容器主機和jenkins使用者,jenkins程式是jenkins使用者啟動的)。
(這裡有一個沒有解決的問題,就是關於拉取private型別的專案,需要做的ssh認證,需要公鑰金鑰匹配,但是沒有實現,所以暫時專案都是public。如果public的專案的話,可以通過http協議進行拉取,但是需不需要配置ssh的公鑰,我也沒試過,因該是不需要把。)

在配置好key之後,我們回到jenkins容器,當前使用者為jenkins。我們想通過git客戶端拉取專案的第二個準備工作,需要配置git的全域性配置。

git  config --global   user.name=”yourName”

我的gitlab 和jenkins的使用者都是jenkins,這裡應該填寫的是git使用者名稱

git config –global user.email=”your email”

這兩個配置完成後,我們可以就可以拉取專案到本地了,以我自己demo為例

git clone ssh://[email protected]:10022/jenkins/eurka.git

d.現在拉取到當前目錄的eurka是個空專案,我們把我們要上傳的專案原始碼和Dockerfile(用來jenkins呼叫docker打包映象用的)新增至這個目錄,然後git add ,git commit ,git push 命令將本地檔案新增提交併推送整合至gitlab這個專案的某個分支下,預設是master

e.提交完成後,我們開始配置jenkins,以jenkins使用者登入jenkins,新建,選擇 --構建一個自由風格的軟體專案然後確定

f.然後進入到這個專案的配置下,在原始碼管理選擇Git,然後在Repository URL下,填入專案的ssh地址,注意這裡不可一世用localhost,你可以填寫主機的ip加上10022埠,也可以配置gitlab容器的ip地址加上22埠,我這裡配置的是我的容器地址,例如ssh://[email protected]:22/jenkins/eurka.git,這裡不要寫10022埠!!!!因為是public專案,所以不需要新增認證
g.在構建觸發器下,選擇Build wher a chage is pushed to GitLab……….將後面的地址複製,然後在gitlab這個專案的Setting下的Integrations下,勾選Push Event,找到Add webhook,並填寫剛才複製的路徑,我這裡寫的依然是容器ip,http://172.18.0.5:8080/project/eurka,沒有使用localhost:8888這個url,儲存

h.回到jenkins的設定,在構建中下Execute shell下,編寫shell指令碼,這裡就是gitlab被push後,通過webhook的方式讓jenkins自動從gitlab下拉取專案之後,要執行的程式碼
預設拉取之後,會在這個專案的路徑下,如果不確定自己當前的工作目錄,可以通過echo $WORKDIR來檢視當前位置,例如我的專案叫eurka,這個專案下我上傳了一個maven專案,所以我如果想要對這個maven專案打包,我得進入這個專案目錄,然後對這個專案下的pom檔案進行操作,貼出我的shell:

作為一個開發者,有一個學習的氛圍跟一個交流圈子特別重要這是一個我的QQ群架構華山論劍:836442475,不管你是小白還是大牛歡迎入駐 ,分享BAT,阿里面試題、面試經驗,討論技術, 大家一起交流學習成長!

#先列印當前位置
pwd
#進入到我的maven專案
cd spring-cloud-02-service
#maven打包
mvn clean compile package -Dmaven.test.skip=true
#回到上一級,因為上一級有Dockerfile檔案
cd ../
#這裡我先移除掉了我之前的映象,然後再重新構建一個映象,如果當前有#這個映象執行的容器,需要先停止容器,移除容器,最後移除映象
docker rmi 127.0.0.1:5000/auto/eurka:1.0 . || docker build -t 127.0.0.1:5000/auto/eurka:1.0 .
#將打包的映象推送到本地的docker倉庫
docker push 127.0.0.1:5000/auto/eurka:1.0
#檢視本地是否打包成功
docker images
#最後可以執行docker run -itd –name container_name -p xxxx:xxxx  repo/im#g:tag /bin/bash讓jenkins呼叫宿主機的docker,執行剛才打包好的映象,不#出意外,應該在我們指定的埠上可以訪問這個專案了。

最初我們在run jenkins容器的時候,將宿主機的docker檔案掛載進了容器內部,這個操作很重要,但我也很迷糊,但可以肯定的是,jenkins容器所執行的docker及操作是針對宿主機的docker的

後續的持續整合,要基於kubernetes,kubernetes會自動的找其節點自動拉取剛push的映象,並自動部署。未完待續