基于 k8s Jenkins CICD

基于 Kubernetes Jenkins CICD
Jenkins
更多内容:https://i4t.com

一、在 Kubernetes 安装 Jenkins 优点
目前很多公司采用 Jenkins 集群搭建复合需求的 CI/CD 流程,但是会存在一些问题

主 Master 发生单点故障时,整个流程都不可用
每个 Slave 的环境配置不一样,来完成不同语言的编译打包,但是这些差异化的配置导致管理起来不方便,维护麻烦
资源分配不均衡,有的 slave 要运行的 job 出现排队等待,而有的 salve 处于空闲状态
资源有浪费,每台 slave 可能是物理机或者虚拟机,当 slave 处于空闲状态时,也不能完全释放掉资源
正因为上面的问题,我们需要采用一种更高效可靠的方式来完成这个 CI/CD 流程,而 Docker 虚拟化容器技能很好的解决这个痛点,又特别是在 Kubernetes 集群环境下面能够更好来解决上面的问题
image_1djmeig52of315pukfvpcspsm1t.png-63.4kB

如上图我们可以看到 Jenkins master 和 Jenkins slave 以 Pod 形式运行在 Kubernetes 集群的 Node 上,Master 运行在其中一个节点,并且将其配置数据存储到一个 volume 上去,slave 运行在各个节点上,但是它的状态并不是一直处于运行状态,它会按照需求动态的创建并自动删除

这种方式流程大致为: 当 Jenkins Master 接受到 Build 请求后,会根据配置的 Label 动态创建一个运行在 Pod 中的 Jenkins Slave 并注册到 Master 上,当运行完 Job 后,这个 Slave 会被注销并且这个 Pod 也会自动删除,恢复到最初的状态 (这个策略可以设置)

服务高可用,当 Jenkins Master 出现故障时,Kubernetes 会自动创建一个新的 Jenkins Master 容器,并且将 Volume 分配给新创建的容器,保证数据不丢失,从而达到集群服务高可用的作用
动态伸缩,合理使用资源,每次运行 Job 时,会自动创建一个 Jenkins Slave,Job 完成后,Slave 自动注销并删除容器,资源自动释放,并且 Kubernetes 会根据每个资源的使用情况,动态分配 slave 到空闲的节点上创建,降低出现因某节点资源利用率高,降低出现因某节点利用率高出现排队的情况
扩展性好,当 Kubernetes 集群的资源严重不足导致 Job 排队等待时,可以很容器的添加一个 Kubernetes Node 到集群,从而实现扩展
二、Kubernetes 安装 Jenkins
这里我们使用 k8s 的 pv 进行存储数据,当然也可以使用 storage class 对象来自动创建

创建 pv 需要使用 nfs,我这里直接创建一台 nfs 服务器

我们在 k8s 集群的任意一个节点配置一台 nfs 集群,其他节点主要是挂载
for i in k8s-01 k8s-02 k8s-03 k8s-04;do ssh root@$i “yum install nfs-utils rpcbind -y”;done
#我这里使用单独的 NFS 服务器,IP 为 192.168.0.100
#NFS 服务节点操作如下
mkdir -p /data1/k8s-vloume
echo “/data1/k8s-vloume *(rw,no_root_squash,sync)” >/etc/exports
systemctl start rpcbind
systemctl enable rpcbind
systemctl enable nfs
systemctl restart nfs
#IP 改成网段
其他 k8s 节点直接启动 rpcbind 并且挂载目录就可以
#挂载
systemctl start rpcbind
systemctl enable rpcbind
mkdir /data1/k8s-vloume -p
mount -t nfs 192.168.0.100:/data1/k8s-vloume /data1/k8s-vloume
#创建完成你们自己测一下就可以了
这里需要创建一个命名空间

kubectl create namespace abcdocker
#在创建一下 jenkins 存储 yaml 的目录
mkdir -p /opt/jenkins
接下来我们开始创建 Jenkins Deployment

vim /opt/jenkins/jenkins_deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: jenkins #deployment 名称
namespace: abcdocker #命名空间
spec:
template:
metadata:
labels:
app: jenkins
spec:
terminationGracePeriodSeconds: 10 #优雅停止 pod
serviceAccount: jenkins #后面还需要创建服务账户
containers:
- name: jenkins
image: jenkins/jenkins:lts #镜像版本
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080 #外部访问端口
name: web
protocol: TCP
- containerPort: 50000 #jenkins save 发现端口
name: agent
protocol: TCP
resources:
limits:
cpu: 1000m
memory: 1Gi
requests:
cpu: 500m
memory: 512Mi
livenessProbe:
httpGet:
path: /login
port: 8080
initialDelaySeconds: 60 #容器初始化完成后,等待 60 秒进行探针检查
timeoutSeconds: 5
failureThreshold: 12 #当 Pod 成功启动且检查失败时,Kubernetes 将在放弃之前尝试 failureThreshold 次。放弃生存检查意味着重新启动 Pod。而放弃就绪检查,Pod 将被标记为未就绪。默认为 3. 最小值为 1
readinessProbe:
httpGet:
path: /login
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 5
failureThreshold: 12
volumeMounts: #需要将 jenkins_home 目录挂载出来
- name: jenkinshome
subPath: jenkins
mountPath: /var/jenkins_home
env:
- name: LIMITS_MEMORY
valueFrom:
resourceFieldRef:
resource: limits.memory
divisor: 1Mi
- name: JAVA_OPTS
value: -Xmx$(LIMITS_MEMORY)m -XshowSettings:vm -Dhudson.slaves.NodeProvisioner.initialDelay=0 -Dhudson.slaves.NodeProvisioner.MARGIN=50 -Dhudson.slaves.NodeProvisioner.MARGIN0=0.85 -Duser.timezone=Asia/Shanghai
securityContext:
fsGroup: 1000
volumes:
- name: jenkinshome
persistentVolumeClaim:
claimName: opspvc #这里将上面创建的 pv 关联到 pvc 上
#这里不进行创建
因为要保证 Jenkins 持久化缓存数据,我们创建了一个 PV

cat >/opt/jenkins/jenkins_pv.yaml <<EOF
apiVersion: v1
kind: PersistentVolume
metadata:
name: opspv
spec:
capacity:
storage: 20Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Delete
nfs:
server: 192.168.0.100
path: /data1/k8s-vloume

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: opspvc
namespace: abcdocker
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 20Gi
EOF
#注意修改 NFS 挂载目录以及 NFS Server
另外还需要一个拥有相关权限的 serviceAccount 的 Jenkins 用户,这里我们手动赋予 Jenkins 一些必要的权限,当然直接给 cluster-admin 的集群角色权限也是可以的

cat >/opt/jenkins/jenkins_rbac.yaml <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins
namespace: abcdocker

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: jenkins
rules:
- apiGroups: [“extensions”, “apps”]
resources: [“deployments”]
verbs: [“create”, “delete”, “get”, “list”, “watch”, “patch”, “update”]
- apiGroups: [""]
resources: [“services”]
verbs: [“create”, “delete”, “get”, “list”, “watch”, “patch”, “update”]
- apiGroups: [""]
resources: [“pods”]
verbs: [“create”,“delete”,“get”,“list”,“patch”,“update”,“watch”]
- apiGroups: [""]
resources: [“pods/exec”]
verbs: [“create”,“delete”,“get”,“list”,“patch”,“update”,“watch”]
- apiGroups: [""]
resources: [“pods/log”]
verbs: [“get”,“list”,“watch”]
- apiGroups: [""]
resources: [“secrets”]
verbs: [“get”]

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: jenkins
namespace: abcdocker
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: jenkins
subjects:
- kind: ServiceAccount
name: jenkins
namespace: abcdocker
EOF
现在还缺少一个 svc,因为我们虽然现在 jenkins 已经在内部可以访问,但是我们在外面是无法访问的。接下来我们创建一个 svc

cat >/opt/jenkins/jenkins_svc.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
name: jenkins
namespace: abcdocker
labels:
app: jenkins
spec:
selector:
app: jenkins
type: NodePort
ports:
- name: web
port: 8080
targetPort: web
nodePort: 30002
- name: agent
port: 50000
targetPort: agent
EOF
接下来我们进行创建

[root@abcdocker-k8s01 jenkins]# ll
total 16
-rw-r–r– 1 root root 2453 Aug 29 17:42 jenkins_deployment.yaml
-rw-r–r– 1 root root 407 Aug 29 17:43 jenkins_pv.yaml
-rw-r–r– 1 root root 1120 Aug 29 17:43 jenkins_rbac.yaml
-rw-r–r– 1 root root 289 Aug 29 17:43 jenkins_svc.yaml
这里可以直接使用 kubectl apple -f .,我为了排查错误,进行一个顺序执行

#这里我先执行 pv 然后在执行 rbac,依次 deployment 和 svc
[root@abcdocker-k8s01 jenkins]# kubectl apply -f jenkins_pv.yaml
persistentvolume/opspv created
persistentvolumeclaim/opspvc created
[root@abcdocker-k8s01 jenkins]# kubectl apply -f jenkins_rbac.yaml
serviceaccount/jenkins created
clusterrole.rbac.authorization.k8s.io/jenkins created
clusterrolebinding.rbac.authorization.k8s.io/jenkins created
[root@abcdocker-k8s01 jenkins]# kubectl apply -f jenkins_deployment.yaml
deployment.extensions/jenkins created
[root@abcdocker-k8s01 jenkins]# kubectl apply -f jenkins_rbac.yaml
serviceaccount/jenkins unchanged
clusterrole.rbac.authorization.k8s.io/jenkins unchanged
clusterrolebinding.rbac.authorization.k8s.io/jenkins unchanged
[root@abcdocker-k8s01 jenkins]# kubectl apply -f jenkins_svc.yaml
service/jenkins created
创建完毕后,我们进行检查

#首先查看 pvc 状态
kubectl get pv,pvc -n abcdocker
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/opspv 20Gi RWX Delete Bound abcdocker/opspvc 65s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/opspvc Bound opspv 20Gi RWX 65s
#接下来查看 rbac
kubectl get serviceaccounts -n abcdocker |grep jenkins
jenkins 1 104s
#最后检查 pod 和 svc
kubectl get pod,svc -n abcdocker
NAME READY STATUS RESTARTS AGE
pod/jenkins-6b874b8d7-dhv57 1/1 Running 0 8m26s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/jenkins NodePort 10.254.154.161 8080:30002/TCP,50000:21866/TCP 62s
#需要说明一下 8080 端口为我们 jenkins 访问端口
#50000 端口为 jenkins save 发现端口
Pod 正常运行了,我们就可以通过浏览器访问集群任意 IP 的 svc 端口

image_1djg8bsio1n3j19dmuq71lk6efc9.png-94.8kB

管理员密码文件路径,也可以在 pod 日志里面看到

cat /data/k8s/jenkins/secrets/initialAdminPassword
6d3c67495bcb43c2a74d97309702dab7
#因为我们持久化在 /data/k8s 下,所以 jenkins 的所有配置都在这下面
直接选择推荐安装就可以
image_1djg8djcioh724rbsr1m7n5t8m.png-134kB

等待安装完毕
image_1djg8tlku1ko01d1c1sr114dcaab13.png-162kB

安装完成后我们进入 jenkins 主页面
image_1djmdslf9su1tbm1101ia7bgi1g.png-100.2kB

接下来就是配置 Jenkins

我们需要安装 k8s 插件,让 Jenkins 构建 Job 可以动态生成 Slave 的 Pod

点击 Jenkins—> 插件—> 安装插件 Kubernetes

image_1djoevce7schvri3hp6vs1shh2a.png-138.1kB

安装完毕后会重启 Jenkins,然后我们就可以配置插件
Manage Jenkins >>Configure System 找到插件

image_1djohlpeapn715ud1amigjd11ul37.png-92.3kB

在配置上拉到最下面,ADD 一个 Kubernetes
image_1djoib1i31bli1vkkn74f018f3k.png-40.3kB

Name 配置的名称
Kubernetes URL 这里的 URL 是 K8s 内部的 URL,实际上就是 svcname 这里不需要修改直接复制就行
Kubernetes Namespace k8s 的命名空间 (实际上就是 Jenkins 所在的命名空间)
https://kubernetes.default.svc.cluster.local
svcname+default+ 后面参数复制就可以

image_1djoj2sjn12d7if21c7q1ghc1rg54h.png-52.1kB

Jenkins URL 这里的 URL 是 jenkins 的 svc 名称加上命名空间,实际上就是在 k8s 集群内部访问 jenkins 的一个方法,这里也不需要修改
http://jenkins.abcdocker.svc.cluster.local:8080
#其他默认即可
image_1djojk9kl181f39hf8v1r11gjv4u.png-89kB

添加一个 Jenkins Slave Pod 模板
image_1djojonu41n391rd7imi6gc13du5r.png-24.6kB

Name = Pod 名称
Namespave = Pod 命名空间
Labels = Pod 标签
image_1djr71qi9k4e1kr918q61j5a1o35p.png-65.5kB

接下来是容器的模板配置

Name 容器的名称
Docker image 镜像,这里直接使用我的镜像
#jenkins 2.176.x 版本以上使用:registry.cn-beijing.aliyuncs.com/abcdocker/jenkins:v1.2
#jenkins 2.176.x 版本以下使用:registry.cn-beijing.aliyuncs.com/abcdocker/jenkins:v1.1
#jenkins 2.176 以上版本有 maven 命令使用:registry.cn-beijing.aliyuncs.com/abcdocker/jenkins:v1.4
#镜像里面主要是运行了 kubectl 命令和 Docker 的配置,下面我们还需要将 kubeconfig 挂载进来
########
如果需要自定义 maven 仓库可以使用下面的 dockerfile
[root@k8s-01 jenkins]# cat Dockerfile
FROM registry.cn-beijing.aliyuncs.com/abcdocker/jenkins:v1.2
MAINTAINER abcdocker “i4t.com”
COPY maven /usr/local/maven
RUN cd /usr/local/maven
红色代表不可以修改,否则 jenkins slave 启动会提示错误,反复重启

image_1djt412951cc54k21c5i1p01roaal.png-141.4kB

如果 jenkins 提示权限错误,请在配置中添加 jenkins rbac 创建的 serviceaccounts

image_1djt43r32185thvu13qs6u41bd8b2.png-45.9kB

上面说了,镜像主要是用于 kubectl,kubectl 是需要 kubeconfig 文件,所以我们还需要创建一个 volume 的配置
image_1djr7j2n7s3e16hgvse1jbe1gm81j.png-73.4kB

如果我们想在容器里面执行 docker 命令,需要将 docker.sock 挂载进去
还需要将 kubeconfig 挂在进容器

1.png-97.7kB

image_1djr8a7g71urojok1du7tq31gqo45.png-60.5kB

然后我们点击保存即可

接下来添加一个 job,来测试一下 jenkins 是否可以在 slave 节点上执行
image_1djr8kk151mg5lflaa115sj197g4i.png-172kB

接下来进行配置 Jenkins

这里的 label 标签就是我们在配置中配置的标签
image_1djr8o25j1fp61mlovt5ubvm0u5c.png-75kB

配置标签的地方
image_1djr8mhrdm94f8n18j7ibud6i4v.png-34.9kB

添加一个 shell 命令,测试 docker 和 kubectl

2.png-125.8kB

现在我们先看一下 Pod 是否可以动态获取

$ kubectl get pod -n abcdocker
NAME READY STATUS RESTARTS AGE
jenkins-6b874b8d7-xxwwr 1/1 Running 0 31h
#目前只有一个 jenkins 在运行,接下来我们进行构建项目
容器正在创建,目前属于等待状态
image_1djr99gd91i661pen2gc1m33ldr6u.png-86.9kB

这里可以看到已经新启动了一个 pod 节点

$ kubectl get pod -n abcdocker
NAME READY STATUS RESTARTS AGE
jenkins-6b874b8d7-xxwwr 1/1 Running 0 2d
jenkins-slave-423xz 0/1 ContainerCreating 0 5s
等待容器创建成功,Jenkins 就会绑定到这个 Pod 节点上,进行执行任务
image_1djt3sn0i14ki57d1t189auivua2.png-172.8kB

当 Jenkins slave 节点执行完毕任务后,默认情况下执行完 job 就会被删除

$ kubectl get pod -n abcdocker
NAME READY STATUS RESTARTS AGE
jenkins-6b874b8d7-xxwwr 1/1 Running 0 2d
如果想让 job 等待 30 分钟释放,可以在下图添加

11111.png-139.9kB

小结 Jenkins Master 收到 Build 请求时,会根据配置的 Label 动态创建一个运行在 Pod 中的 Jenkins Slave 并注册到 Master 上,当 Job 运行完,这个 Slave 会被注销并且这个 Pod 也会自动删除,恢复到最初状态

三、项目演示 使用 Jenkins Pipline 部署
Jenkins Pipline 介绍

Gitlab 配置
接下来我们在代码仓库创建一个分支
image_1dk07h04h18vop2g9rs1un0ncad4.png-229.1kB

配置 root 用户免密

首先先查看服务器公钥
DE94CCEF-4B5E-4A8E-AF23-8888478C086C.png-246.1kB

上 git 配置 key
4444.png-256.1kB

接下来在服务器上提交 git 代码就可以
image_1dk088jcosei15oughj1kvaopgg7.png-178kB

上传代码

#这里需要有 git 命令
yum install -y git
git config –global user.name “root”
git config –global user.email “admin@example.com
#克隆
git clone git@10.4.82.15:root/abcdocker-test.git
cd abcdocker-test
wget http://down.i4t.com/hello-world-war-master.zip
unzip hello-world-war-master.zip
mv hello-world-war-master/* .
rm -rf hello-world-war-master*
#提交代码
#接下来看图就行了
gitlab 配置完毕
image_1dk08c1ip1sbu1bju1c4j11spiiigk.png-119.7kB

四、配置 Dockerfile
首先我们需要自定义一个 tomcat 基础镜像,也可以使用 dockerhub 提供的

cat >>Dockerfile <<EOF
FROM centos
MAINTAINER www.i4t.comcyh@i4t.com
WORKDIR /tmp

Please see https://i4t.com/3552.html install JDK

COPY jdk1.8.0_66.tar.gz /tmp
RUN tar zxf /tmp/jdk1.8.0_66.tar.gz -C /usr/local/ && rm -rf /tmp/jdk1.8.0_66.tar.gz &&
ln -s /usr/local/jdk1.8.0_66 /usr/local/jdk
#/etc/profile
ENV JAVA_HOME /usr/local/jdk
ENV CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV PATH $PATH:$JAVA_HOME/bin

add apache

Please see i4t.com && baidu.com

COPY apache-tomcat-8.5.39.tar.gz /tmp
RUN tar zxf apache-tomcat-8.5.39.tar.gz -C /usr/local  && rm -rf /tmp/apache-tomcat-8.5.39.tar.gz && \
    mv /usr/local/apache-tomcat-8.5.39 /usr/local/tomcat && \
    rm -rf /usr/local/tomcat/webapps/docs examples host-manager manager

EXPOSE 8080
ENTRYPOINT /usr/local/tomcat/bin/startup.sh && tail -f /usr/local/tomcat/logs/catalina.out
EOF
### 接下来需要下载相对应的安装包 (Dockerfile 和 JDK 和 tomcat 需要放在一个目录下)
wget http://down.i4t.com/jdk1.8.0_66.tar.gz
wget http://down.i4t.com/apache-tomcat-8.5.39.tar.gz
接下来可以进行打包

docker build -t registry.cn-beijing.aliyuncs.com/abcdocker/tomcat:v2 .
#如果不想自己做 tomcat 镜像,也可以使用 dockerhub 上的镜像。也可以使用我这里打包好的镜像
现在我们已经完成 tomcat 镜像的创建,接下来配置 Jenkins,每次打包上线自动替换 ROOT 目录

五、编写 jenkins Pipline
Jenkins pipline 语法介绍

配置 gitlab 账号密码
由于 Jenkins 需要使用 gitlab 账号密码,这里我们做一下免密
image_1dk86d5me1asa1kqketn1r651sc09.png-84.9kB
image_1dk86e298etledshpl9l817u7m.png-92.2kB
image_1dk86enal1ovc1msc8q918hj1bcu13.png-90.6kB

配置如下
image_1dk86gi361nkt1tjf1gat3hgrei1g.png-88.1kB

创建 Jenkins pipline 项目
image_1dk86j6fgo14ps41b9ahnkp3r1t.png-179.7kB

我这里添加参数化构建
image_1dk86ljv31bjaoq016v95eqakh2a.png-91.6kB

接下来编写 jenkins pipline 脚本

node(‘abcdocker-slave’) {
stage(‘Git Clone’) {
checkout([$class: ‘GitSCM’, branches: name: ’${git}’, doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: credentialsId: ’gitlab_password’, url: ’http://192.168.0.100/root/abcdocker-test.git’])
}
stage(‘Maven Build’) {
sh '''
/usr/local/maven/bin/mvn clean package -Dmaven.test.skip=true -f $WORKSPACE
echo FROM registry.cn-beijing.aliyuncs.com/abcdocker/tomcat:test2 >$WORKSPACE/target/Dockerfile
echo RUN rm -rf /usr/local/tomcat/webapps/* >>$WORKSPACE/target/Dockerfile
echo COPY hello-world-war-1.0.0 /usr/local/tomcat/webapps/ROOT >>$WORKSPACE/target/Dockerfile
'''
echo “3.Docker Build Stage”
sh '''
docker build -t registry.cn-beijing.aliyuncs.com/abcdocker/tomcat:${git} ${WORKSPACE}/target/
docker login –username= 用户名 registry.cn-beijing.aliyuncs.com –password 镜像密码
docker push registry.cn-beijing.aliyuncs.com/abcdocker/tomcat:${git}
'''
}
stage(‘Deploy’) {
echo “4. Deploy Stage”
sh’kubectl set image deployment/tomcat -n abcdocker-test my-tomcat=registry.cn-beijing.aliyuncs.com/abcdocker/tomcat:${git}’
}
}
Pipline 脚本讲解

node(‘abcdocker-slave’) {
#这里代表 node 节点运行在标签为 abcdocker-slave 上,前面已经定义了,这里就不在定义
gitlab 拉取代码配置

stage('Git Clone') {
     checkout([$class: 'GitSCM', branches: [[name: '${git}']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'gitlab_password', url: 'http://192.168.0.100/root/abcdocker-test.git']]])    
}

#这里就是一个选择 git 地址,然后分支。不会生成可以参考 pipline 语法
在下图生成的配置直接拷贝到 pipline 里面 ji
image_1dk86t1co11gdsf91j7u1rn7k0l2n.png-100.5kB

Java maven 打包步骤

我这里使用阿里云的镜像仓库,演示一下如何上传。

这里需要注意的是,我们的 jenkins slave 节点的 Pod 镜像需要使用下面我提供的版本,否则没有 maven 命令
registry.cn-beijing.aliyuncs.com/abcdocker/jenkins:v1.4

stage('Maven Build') {
    sh '''
    /usr/local/maven/bin/mvn clean package -Dmaven.test.skip=true -f $WORKSPACE
    echo FROM registry.cn-beijing.aliyuncs.com/abcdocker/tomcat:test2 >$WORKSPACE/target/Dockerfile
    echo RUN  rm -rf /usr/local/tomcat/webapps/* >>$WORKSPACE/target/Dockerfile
    echo COPY hello-world-war-1.0.0 /usr/local/tomcat/webapps/ROOT >>$WORKSPACE/target/Dockerfile
    '''
  echo "3.Docker Build Stage"
       sh '''
      docker build -t registry.cn-beijing.aliyuncs.com/abcdocker/tomcat:${git} ${WORKSPACE}/target/
      docker login --username=cyh60441314 registry.cn-beijing.aliyuncs.com --password XXXX密码
      docker push registry.cn-beijing.aliyuncs.com/abcdocker/tomcat:${git}
          '''
}

接下来是使用 kubectl set 替换镜像

stage('Deploy') {
  echo "4. Deploy Stage"
  sh'kubectl set image deployment/tomcat -n abcdocker-test my-tomcat=registry.cn-beijing.aliyuncs.com/abcdocker/tomcat:${git}'
}

命令参数解释

kubectl set image deployment/SVC_NAME -n namespace_name container_name=images:v1
#注意后面是容器名称,并不是 svc 名称
完整 Jenkins Pipline 脚本如下

node(‘abcdocker-slave’) {
stage(‘Git Clone’) {
checkout([$class: ‘GitSCM’, branches: name: ’${git}’, doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: credentialsId: ’gitlab_password’, url: ’http://192.168.0.100/root/abcdocker-test.git’])
}
stage(‘Maven Build’) {
sh '''
/usr/local/maven/bin/mvn clean package -Dmaven.test.skip=true -f $WORKSPACE
echo FROM registry.cn-beijing.aliyuncs.com/abcdocker/tomcat:test2 >$WORKSPACE/target/Dockerfile
echo RUN rm -rf /usr/local/tomcat/webapps/* >>$WORKSPACE/target/Dockerfile
echo COPY hello-world-war-1.0.0 /usr/local/tomcat/webapps/ROOT >>$WORKSPACE/target/Dockerfile
'''
echo “3.Docker Build Stage”
sh '''
docker build -t registry.cn-beijing.aliyuncs.com/abcdocker/tomcat:${git} ${WORKSPACE}/target/
docker login –username= 用户名 registry.cn-beijing.aliyuncs.com –password harbor 密码
docker push registry.cn-beijing.aliyuncs.com/abcdocker/tomcat:${git}
'''
}
stage(‘Deploy’) {
echo “4. Deploy Stage”
sh’kubectl set image deployment/tomcat -n abcdocker-test my-tomcat=registry.cn-beijing.aliyuncs.com/abcdocker/tomcat:${git}’
}
}
然后 jenkins 我们点击保存

创建 tomcat svc 环境

#创建命名空间
kubectl create namespace abcdocker-test
创建 tomcat deploy 文件

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
name: tomcat
name: tomcat
namespace: abcdocker-test
spec:
replicas: 1
selector:
matchLabels:
name: tomcat
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: tomcat
name: tomcat
spec:
containers:
- env:
- name: JAVA_OPTS
value: -server -d64 -XX:MetaspaceSize=256m
- name: MAX_HEAP
value: 512m
- name: MIN_HEAP
value: 512m
image: registry.cn-beijing.aliyuncs.com/abcdocker/tomcat:v2
imagePullPolicy: IfNotPresent
name: my-tomcat
ports:
- containerPort: 8080
protocol: TCP
resources:
limits:
memory: 1536Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
创建 svc

apiVersion: v1
kind: Service
metadata:
name: my-tomcat-svc
namespace: abcdocker-test
labels:
app: tomcat
spec:
selector:
app: tomcat
type: NodePort
ports:
- name: web
port: 8080
#targetPort: 8080
nodePort: 30005
创建之后我们查看状态

[root@k8s-01 ~]# kubectl get pod,svc -n abcdocker-test
NAME READY STATUS RESTARTS AGE
pod/tomcat-855dccd5bc-wkn5z 1/1 Running 0 27m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/my-tomcat-svc NodePort 10.254.62.11 8080:30005/TCP 26h
访问页面,查看是否正常 (集群任意 IP+30005)
image_1dk87u5co1q8c1rih4qp1pueei434.png-416.9kB

项目部署
接下来我们演示一下环境部署
image_1dk880p6a1d011ige7fn18dp6ts3h.png-153.9kB

点击 Build
image_1dk881m36lq61vl3mjq10jp11af3u.png-110.5kB

我这里没有区分环境,这里也是可以区分环境的
image_1dk882n411kro1vd516s0n9m1uvr4b.png-111.4kB

日志分析
image_1dk884gmquvg1srv1goo19qc9m14o.png-125.1kB

image_1dk885c5g1qs81m4t125g5portb55.png-178.5kB

image_1dk8866ipvdv1f8t16bs3qfm1c5i.png-184.5kB

image_1dk887rj51kh184i1r4912rn1vl25v.png-185.9kB

替换镜像
image_1dk888a6keq31t4h4o91pp6fu6c.png-43.9kB

效果图
image_1dk8895tu7ou17ddnai1toagj66p.png-59.9kB

Jenkins 上也可以看到每个步骤的构建时间
image_1dk88a6cb1i91pq21ck332ni3u76.png-109.3kB