案例描述 本案例主要使用Kubernetes+Jenkins+GitLab构建持续集成项目,具体如下:
(1)掌握Jenklins和GitLab的基本使用。
(2)了解Blue Ocean的使用和管理。
(3)掌握Jenkinsfile的语法和编写方式。
规划节点 节点规划见表1-1。
表1-1节点规划
IP
主机名
节点
10.26.15.244
master
Kubernetes单节点集群
10.26.15.243
桌面化的测试节点
基础准备 确保Kubernetes集群已部署完成。
案例实施 概述 Kubernetes构建CI/CD的流程拓扑图如下:
图1
涉及到的工具与技术包括:
GitLab:常用的源代码管理系统。
Jenkins、Jenkins Pipeline:常用的自动化构建、部署工具,Pipeline以流水线的方式将构建、部署的各个步骤组织起来。
Docker、Dockerfile:容器引擎,所有应用最终都要以Docker容器运行,Dockerfile是Docker镜像定义文件。
Kubernetes:Google开源的容器编排管理系统。
部署Harbor (1)基础准备
下载软件包到本地:
1 2 [root@master ~]# ls BlueOcean.tar.gz
解压软件包:
1 [root@master ~]# tar -zxf BlueOcean.tar.gz
(2)部署Harbor
安装Docker Compose:
1 2 3 4 5 6 [root@master ~]# cp BlueOcean/tools/docker-compose-Linux-x86_64 /usr/bin/docker-compose [root@master ~]# docker-compose version docker-compose version 1.25.0, build 0a186604 docker-py version: 4.1.0 CPython version: 3.7.4 OpenSSL version: OpenSSL 1.1.0l 10 Sep 2019
安装Harbor仓库:
1 2 [root@master ~]# tar -zxf BlueOcean/harbor-offline-installer.tar.gz -C /opt/ [root@master ~]# sh /opt/harbor/install.sh
部署完成后Harbor镜像仓库默认用户为admin,密码为Harbor12345。
(3)访问Harbor
在Web端使用火狐浏览器登录Harbor(http://master),登录成功后如图2所示:
图2
新建springcloud项目,访问级别设置为公开,如图3所示:
图3
创建完成后如图4所示:
图4
上传镜像到Harbor(IP为master节点地址):
1 2 3 4 5 6 7 [root@master ~]# docker login -uadmin -pHarbor12345 10.26.15.244 [root@master ~]# docker load -i BlueOcean/images/maven_latest.tar [root@master ~]# docker tag maven 10.26.15.244/library/maven [root@master ~]# docker push 10.26.15.244/library/maven [root@master ~]# docker load -i BlueOcean/images/java_8-jre.tar [root@master ~]# docker load -i BlueOcean/images/jenkins_jenkins_latest.tar [root@master ~]# docker load -i BlueOcean/images/gitlab_gitlab-ce_latest.tar
部署Jenkins (1)安装Jenkins
新建命名空间:
1 [root@master ~]# kubectl create ns devops
部署Jenkins需要使用到一个拥有相关权限的serviceAccount,名称为jenkins-admin,可以给jenkins-admin赋予一些必要的权限,也可以直接绑定一个cluster-admin的集群角色权限,此处选择给予集群角色权限。编写Jenkins资源清单文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 [root@master ~]# vi jenkins-deploy.yaml apiVersion: v1 kind: Service metadata: name: jenkins labels: app: jenkins spec: type: NodePort ports: - name: http port: 8080 targetPort: 8080 nodePort: 30880 - name: agent port: 50000 targetPort: agent nodePort: 30850 selector: app: jenkins --- apiVersion: apps/v1 kind: Deployment metadata: name: jenkins labels: app: jenkins spec: selector: matchLabels: app: jenkins template: metadata: labels: app: jenkins spec: serviceAccountName: jenkins-admin containers: - name: jenkins image: jenkins/jenkins:latest imagePullPolicy: IfNotPresent securityContext: runAsUser: 0 privileged: true ports: - name: http containerPort: 8080 volumeMounts: - mountPath: /var/jenkins_home name: jenkinshome - mountPath: /usr/bin/docker name: docker - mountPath: /var/run/docker.sock name: dockersock - mountPath: /usr/bin/kubectl name: kubectl - mountPath: /root/.kube name: kubeconfig volumes: - name: jenkinshome hostPath: path: /home/jenkins_home - name: docker hostPath: path: /usr/bin/docker - name: dockersock hostPath: path: /var/run/docker.sock - name: kubectl hostPath: path: /usr/bin/kubectl - name: kubeconfig hostPath: path: /root/.kube --- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: jenkinshome annotations: volume.beta.kubernetes.io/storage-class: local-path spec: accessModes: - ReadWriteMany resources: requests: storage: 1024Mi --- apiVersion: v1 kind: ServiceAccount metadata: name: jenkins-admin labels: name: jenkins --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: jenkins-admin labels: name: jenkins subjects: - kind: ServiceAccount name: jenkins-admin namespace: default roleRef: kind: ClusterRole name: cluster-admin apiGroup: rbac.authorization.k8s.io
这里通过NodePort的形式来暴露了Jenkins的8080端口,另外还需要暴露一个agent的端口,这个端口主要用于Jenkins的Master和Slave之间的通信。
部署Jenkins:
1 [root@master ~]# kubectl -n devops apply -f jenkins-deploy.yaml
查看Pod:
1 2 3 [root@master ~]# kubectl -n devops get pods NAME READY STATUS RESTARTS AGE jenkins-cc97fd4fc-v5dh2 1/1 Running 0 21s
(2)访问Jenkins
查看Jenkins Service端口:
1 2 3 [root@master ~]# kubectl -n devops get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE jenkins NodePort 192.96.215.194 <none> 8080:30880/TCP,50000:30850/TCP 47s
在Web端使用浏览器访问Jenkins(http://master:30880),如图5所示:
图5
获取Jenkins密码:
1 2 [root@master ~]# kubectl -n devops exec deploy/jenkins -- cat /var/jenkins_home/secrets/initialAdminPassword a3ac7ba3812746d0bc8ed40e122ba20b
输入密码后单击“继续”按钮,如图6所示:
图6
将离线插件包拷贝到Jenkins:
1 [root@master ~]# kubectl -n devops cp BlueOcean/plugins/ jenkins-cc97fd4fc-v5dh2:/var/jenkins_home
重启Jenkins:
1 [root@master ~]# kubectl -n devops rollout restart deployment jenkins
刷新Jenkins页面,选择“跳过插件安装”,安装完成后进入用户创建页面,创建一个用户jenkins,密码000000,如图7所示:
图7
单击“保存并完成”按钮,如图8所示:
图8
单击“保存并完成”,如图9所示:
图9
单击“开始使用Jenkins”按钮并使用新创建的用户登录Jenkins,如图10所示:
图10
部署GitLab GitLab是利用Ruby on Rails一个开源的版本管理系统,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目。与GitHub类似,GitLab能够浏览源代码,管理缺陷和注释,可以管理团队对仓库的访问,它非常易于浏览提交过的版本并提供一个文件历史库,团队成员可以利用内置的简单聊天程序(Wall)进行交流。GitLab还提供一个代码片段收集功能可以轻松实现代码复用,便于日后有需要的时候进行查找。
本项目GitLab与Harbor共用一台服务器。
(1)部署GitLab
编写GitLab资源清单文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 [root@master ~]# vi gitlab-deploy.yaml apiVersion: v1 kind: Service metadata: name: gitlab spec: type: NodePort ports: - port: 443 nodePort: 30443 targetPort: 443 name: gitlab-443 - port: 80 nodePort: 30888 targetPort: 80 name: gitlab-80 selector: app: gitlab --- apiVersion: apps/v1 kind: Deployment metadata: name: gitlab spec: selector: matchLabels: app: gitlab revisionHistoryLimit: 2 template: metadata: labels: app: gitlab spec: containers: - image: gitlab/gitlab-ce:latest name: gitlab imagePullPolicy: IfNotPresent env: - name: GITLAB_ROOT_PASSWORD # 设置root用户密码 value: admin@123 - name: GITLAB_PORT value: "80" ports: - containerPort: 443 name: gitlab-443 - containerPort: 80 name: gitlab-80
部署GitLab:
1 [root@master ~]# kubectl -n devops apply -f gitlab-deploy.yaml
查看Pod:
1 2 3 4 [root@master ~]# kubectl -n devops get pods NAME READY STATUS RESTARTS AGE gitlab-645dd88cd7-6vv2q 1/1 Running 0 29s jenkins-cc97fd4fc-kmjtl 1/1 Running 0 7m20s
查看GitLab Service:
1 2 3 4 [root@master ~]# kubectl -n devops get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE gitlab NodePort 192.104.250.77 <none> 443:30443/TCP,80:30888/TCP 57s jenkins NodePort 192.98.107.152 <none> 8080:30880/TCP,50000:30850/TCP 7m48s
GitLab启动较慢,可以通过“kubectl logs”查看其启动状态。启动完成后,在Web端访问GitLab(http://master:30888),如图11所示:
图11
登录GitLab,如图12所示:
图12
(2)创建项目
单击“New project”按钮,如图13所示:
图13
单击“Create blank project”按钮创建项目springcloud,可见等级选择“Public”,如图14所示:
图14
单击“Create project”按钮,进入项目,如图15所示:
图15
push源代码到GitLab的springcloud项目:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 [root@master ~]# cd BlueOcean/springcloud/ [root@master springcloud]# git config --global user.name "administrator" [root@master springcloud]# git config --global user.email "admin@example.com" [root@master springcloud]# git remote remove origin [root@master springcloud]# git remote add origin http://10.26.10.143:30888/root/springcloud.git [root@master springcloud]# git add . [root@master springcloud]# git commit -m "initial commit" # On branch master nothing to commit, working directory clean [root@master springcloud]# git push -u origin master Username for 'http://10.26.10.143:30888': root Password for 'http://root@10.26.15.244:30888': Counting objects: 3192, done. Delta compression using up to 8 threads. Compressing objects: 100% (1428/1428), done. Writing objects: 100% (3192/3192), 1.40 MiB | 1.70 MiB/s, done. Total 3192 (delta 1233), reused 3010 (delta 1207) remote: Resolving deltas: 100% (1233/1233), done. remote: remote: To create a merge request for master, visit: remote: http://gitlab-6778c45f9-xx5gs/root/springcloud/-/merge_requests/new?merge_request%5Bsource_branch%5D=master remote: To http://10.26.15.244:30888/root/springcloud.git * [new branch] master -> master Branch master set up to track remote branch master from origin.
刷新网页,springcloud项目master分支中的文件已经更新了(使用火狐浏览器打开网页),如图16所示:
图16
配置Jenkins连接GitLab (1)设置Outbound requests
登录Gitlab管理员界面(http://master:30888/admin),如图17所示:
图17
在左侧导航栏选择“Settings→Network”,设置“Outbound requests”,勾选“Allow requests to the local network from web hooks and services”复选框,如图18所示:
图18
配置完成后保存。
(2)创建GitLab API Token
单击GitLab用户头像图标,如图19所示:
图19
在左侧导航栏选择“Preferences”,如图20所示: 图20
在左侧导航栏选择“Access Tokens”添加Token,如21图所示: 图21
单击“Create personal access token”按钮生成Token,如图22所示: 图22
记录下Token(U6p_ubRixGSdRvs6MGft),后面配置Jenkins时会用到。
(3)设置Jenkins
登录Jenkins首页,选择“系统管理→系统配置”,配置GitLab信息,取消勾选“Enable authentiviion for ‘/project’ end-point”,输入“Connection name”和“Gitlab host URL”,如图23所示: 图23
添加Credentials,单击“添加”→“Jenkins”按钮添加认证信息,将Gitlab API Token填入,如图24所示: 图24
选择新添加的证书,然后单击“Test Connection”按钮,如图25所示: 图25
返回结果为Success,说明Jenkins可以正常连接GitLab。
Jenkinsfile (1)新建任务
登录Jenkins首页,新建任务springcloud,任务类型选择“流水线”,如图26所示: 图26
单击“确定”按钮,配置构建触发器,如图27所示: 图27
记录下GitLab webhook URL的地址(http://10.26.15.244:30880/project/springcloud),后期配置webhook需要使用。
配置流水线,在定义域中选择“Pipeline script from SCM”,此选项指示Jenkins从源代码管理(SCM)仓库获取流水线。在SCM域中选择“Git”,然后输入“Repository URL”,如图28所示: 图28
在Credentials中选择“添加”,凭据类型选择“Username with password”,然后输入对应信息,如图29所示:
图29
单击“保存”按钮,回到流水线中,在Credentials域选择刚才添加的凭证,如图30所示:
图30
保存任务。
(2)编写流水线
Pipeline有两种创建方法——可以直接在Jenkins的Web UI界面中输入脚本;也可以通过创建一个Jenkinsfile脚本文件放入项目源码库中。
一般推荐在Jenkins中直接从源代码控制(SCMD)中直接载入Jenkinsfile Pipeline这种方法。
登录GitLab进入springcloud项目,选择新建文件,如图31所示:
图31
将流水线脚本输入到Jenkinsfile中,如图32所示:
图32
Pipeline包括声明式语法和脚本式语法。声明式和脚本式的流水线从根本上是不同的。声明式是Jenkins流水线更友好的特性。脚本式的流水线语法,提供更丰富的语法特性。声明式流水线使编写和读取流水线代码更容易设计。
此处选择声明式Pipeline,完整的流水线脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 pipeline{ agent none stages{ stage('mvn-build'){ agent { docker { image '10.26.15.244/library/maven' args '-v /root/.m2:/root/.m2' } } steps{ sh 'cp -rfv /opt/repository /root/.m2/ && ls -l /root/.m2/repository' sh 'mvn package -DskipTests' archiveArtifacts artifacts: '**/target/*.jar', fingerprint: true } } stage('image-build'){ agent any steps{ sh 'cd gateway && docker build -t 10.26.15.244/springcloud/gateway -f Dockerfile .' sh 'cd config && docker build -t 10.26.15.244/springcloud/config -f Dockerfile .' sh 'docker login 10.26.15.244 -u=admin -p=Harbor12345' sh 'docker push 10.26.15.244/springcloud/gateway' sh 'docker push 10.26.15.244/springcloud/config' } } stage('cloud-deploy'){ agent any steps{ sh 'sed -i "s/sqshq\\/piggymetrics-gateway/10.26.15.244\\/springcloud\\/gateway/g" yaml/deployment/gateway-deployment.yaml' sh 'sed -i "s/sqshq\\/piggymetrics-config/10.26.15.244\\/springcloud\\/config/g" yaml/deployment/config-deployment.yaml' sh 'kubectl create ns springcloud' sh 'kubectl apply -f yaml/deployment/gateway-deployment.yaml' sh 'kubectl apply -f yaml/deployment/config-deployment.yaml' sh 'kubectl apply -f yaml/svc/gateway-svc.yaml' sh 'kubectl apply -f yaml/svc/config-svc.yaml' } } } }
(3)开启Jenkins匿名访问
登录Jenkins首页,选择“系统管理→全局安全配置”,授权策略选择“任何用户可以做任何事(没有任何限制)”,如图33所示。 图33
构建CI/CD (1)触发构建
在GitLab的项目中,通常会使用Webhook的各种事件来触发对应的构建,通常配置好后会向设定好的URL发送post请求。
登录GitLab,进入springcloud项目,现在左侧导航栏“Settings→Webhooks”,将前面记录的GitLab webhook URL地址填入URL处,禁用SSL认证,如图34所示。 图34
单击“Add webhook”按钮添加webhook,完成后如图35所示: 图35
单击“Test→Push events”按钮进行测试,如图36所示: 图36
结果返回HTTP 200则表明Webhook配置成功。
(2)Jenkins查看
登录Jenkins,可以看到springcloud项目已经开始构建,如图37所示:
图37
若是执行 kubectl create ns springcloud 报错
Unable to connect to the server: dial tcp: lookup apiserver.cluster.local on 10.96.0.10:53: no such host
修改 /root/.kube/config
把 apiserver.cluster.local 改为 master 节点 IP
选择左侧导航栏“打开Blue Ocean”,如图38所示: 图38
Blue Ocean是pipeline的可视化UI,同时兼容经典的自由模式的job。Jenkins Pipeline从头开始设计,但仍与自由式作业兼容,Blue Ocean减少了经典模式下的混乱并为团队中的每个成员增加了清晰度。
单击项目名称springcloud,如图39所示: 图39
单击正在构建的pipeline可以查看阶段视图,如图40所示: 图40
单击任意“>”符号可查看每个Step的构建详情,如图41所示: 图41
若构建成功,Blue Ocean界面会变为绿色。构建完成后如图42所示: 图42
退出阶段试图界面,如图43所示: 图43
返回Jenkins首页,如图44所示: 图44
(3)Harbor查看
进入Harbor仓库springcloud项目查看镜像列表,可以看到已自动上传了一个gateway镜像,如图45所示: 图45
(4)Kubernetes查看
Pod的启动较慢,需等待3–5分钟。在命令行查看Pod:
1 2 3 4 [root@master ~]# kubectl -n springcloud get pods NAME READY STATUS RESTARTS AGE config-6b6875fffd-p2g7j 1/1 Running 0 3m6s gateway-5d5f8cc944-vstgm 1/1 Running 0 3m6s
查看service:
1 2 3 4 [root@master ~]# kubectl -n springcloud get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE config NodePort 192.109.170.192 <none> 8888:30015/TCP 3m18s gateway NodePort 192.110.243.17 <none> 4000:30010/TCP 3m18s
通过端口30010访问服务,如图46所示: 图46
至此,完整的CI/CD流程就完成了。