基於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://git@localhost: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://git@localhost:10022/jenkins/demo.git
git add .
git commit
git push -u origin master
#Existing Git repository
cd existing_repo
git remote add origin ssh://git@localhost: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://git@localhost: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的鏡像,並自動部署。未完待續

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章