摘要: 一、場景: 開發者將代碼提交(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的鏡像,並自動部署。未完待續