Online process deployment of Jenkins CI/CD version based on Kubernetes cluster

Posted by veroaero on Thu, 23 Dec 2021 22:29:09 +0100

CICD continuous integration based on kubernetes platform

1. Continuous integration of Jenkins based on k8s cluster

The process of Jenkins updating the traditional LNMT project is very simple. Jenkins only needs to be deployed on the physical server to realize the continuous update iteration of the project version

If the project is deployed in the k8s cluster and Jenkins is still deployed on the physical machine, the project update process will become cumbersome. The general process is as follows: firstly, Jenkins compiles the project into a war package, and then runs the war on a physical machine. If the operation is successful, another Jenkins task will be called, The main function of Jenkins task is to copy the war package and ROOT directory into the initial image. After the image is built, push the image to the harbor platform, and then the operation and maintenance department takes the image version and puts it in k8s to upgrade.

If Jenkins is only deployed on a physical machine, the whole CI/CD platform will not be able to update and iterate after a Jenkins hangs up, which is a very serious consequence. If Jenkins is deployed on the k8s platform, with the help of the k8s pod self-healing function, Jenkins hangs up almost never.

After Jenkins is deployed in the k8s environment, by establishing RBAC authorization mechanism, Jenkins can realize one click Update iteration to the k8s environment without the cumbersome steps of using the physical machine environment

Update process after Jenkins and kubernetes integration:

1) Jenkins pulls the development submitted code from gitlab

2) Jenkins calls maven to compile the project

3) Jenkins calls docker to build the written dockerfile into an image

4) Push the image to the harbor warehouse

5) Jenkins calls k8s to deploy the image in the k8s environment

2. Deploy Jenkins in k8s cluster

Deployment idea:

1. Because Jenkins wants to update items to various namespaces, it needs to do RBAC authorization, prepare a ServiceAccount, and directly bind the ServiceAccount to the cluster admin cluster role, so that Jenkins has operation permissions on items under all namespaces.

2. The Jenkins deployment adopts the statefullset controller and cooperates with StorageClass to dynamically persist Jenkins data.

3. Prepare svc resources and expose ports 8080 / 50000 of Jenkins.

2.1. Write Jenkins namespace file

[root@k8s-master1 jenkins]# cat jenkins-namespace.yaml 
apiVersion: v1 
kind: Namespace 
metadata: 
    name: jenkins 

2.2. Prepare Jenkins rbac authorization document

Create a serviceaccount account Jenkins, and directly bind the sa account to the cluster admin cluster role

[root@k8s-master1 jenkins]# cat jenkins-rbac.yaml 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins
  namespace: jenkins

---

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: jenkins-crb
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: jenkins
  namespace: jenkins

2.3. Write Jenkins statefullset resource file

Jenkins also generates data, so stateful services are deployed with stateful set, and storage systems are dynamically created with StorageClass

[root@k8s-master1 jenkins]# cat jenkins-statefulset.yaml 
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: jenkins-master
  namespace: jenkins
spec:
  replicas: 1
  serviceName: jenkins
  selector:
    matchLabels:
      app: jenkins-master
  template:
    metadata:
      labels:
        app: jenkins-master
    spec:
      serviceAccount: jenkins
      initContainers:
      - name: jenkins-chown
        image: harbor.jiangxl.com/jenkins/busybox:1.30
        command: ["sh","-c","chown -R 1000:1000 /var/jenkins_home"]
        securityContext:
          privileged: true
        volumeMounts:
        - name: jenkins-data
          mountPath: /var/jenkins_home
      containers:
      - name: jenkins-master
        image: harbor.jiangxl.com/jenkins/jenkinsci-blueocean:1.24.6
        env:
        - name: JAVA_OPTS
          value: "-Xms4096m -Xmx5120m -Duser.timezone=Asia/Shanghai -Dhudson.model.DirectoryBrowserSupport.CSP="
        ports:
        - name: http
          containerPort: 8080
        - name: slave
          containerPort: 50000
        volumeMounts:
        - name: jenkins-data
          mountPath: /var/jenkins_home
  volumeClaimTemplates:
    - metadata:
        name: jenkins-data
      spec:
        storageClassName: jenkins-storageclass
        accessModes:
        - ReadWriteMany
        resources:
          requests:
            storage: 10Gi

2.4. Write Jenkins StorageClass resource file

[root@k8s-master1 jenkins]# cat jenkins-storageclass.yaml 
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: jenkins-storageclass
provisioner: nfs-storage-01
reclaimPolicy: Retain

2.5. Write Jenkins svc resource file

[root@k8s-master1 jenkins]# cat jenkins-svc.yaml 
apiVersion: v1
kind: Service
metadata:
  labels:
    app: jenkins-master
  name: jenkins-svc
  namespace: jenkins
spec:
  ports:
  - name: http
    port: 8080
    targetPort: 8080
    nodePort: 38080
  - name: slave
    port: 50000
    targetPort: 50000
    nodePort: 50000
  selector: 
    app: jenkins-master
  type: NodePort

2.6. Prepare Jenkins images and push them to harbor

[root@k8s-master1 jenkins]# docker pull jenkinsci/blueocean:1.24.6
[root@k8s-master1 jenkins]# docker tag jenkinsci/blueocean:1.24.6 harbor.jiangxl.com/jenkins/jenkinsci-blueocean:1.24.6
[root@k8s-master1 jenkins]# docker push harbor.jiangxl.com/jenkins/jenkinsci-blueocean:1.24.6

2.7. Create all resources and view their status

1.Create all resources
[root@k8s-master1 jenkins]# kubectl apply -f ./
namespace/jenkins created
serviceaccount/jenkins created
clusterrolebinding.rbac.authorization.k8s.io/jenkins-crb created
statefulset.apps/jenkins-master created
storageclass.storage.k8s.io/jenkins-storageclass created
service/jenkins-svc created

2.View resource status
[root@k8s-master1 jenkins]# kubectl get pod,statefulset,svc,storageclass,sa -n jenkins
NAME                   READY   STATUS    RESTARTS   AGE
pod/jenkins-master-0   1/1     Running   0          31m

NAME                              READY   AGE
statefulset.apps/jenkins-master   1/1     31m

NAME                  TYPE       CLUSTER-IP   EXTERNAL-IP   PORT(S)                         AGE
service/jenkins-svc   NodePort   10.101.2.5   <none>        8080:38080/TCP,50000:50000/TCP   31m

NAME                                               PROVISIONER      RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
storageclass.storage.k8s.io/jenkins-storageclass   nfs-storage-01   Retain          Immediate           false                  31m

NAME                     SECRETS   AGE
serviceaccount/jenkins   1         31m

3.see pvc,Created dynamically
[root@k8s-master1 jenkins]# kubectl get pvc -n jenkins
NAME                            STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS           AGE
jenkins-data-jenkins-master-0   Bound    pvc-3f49831b-7faa-456e-9a2f-65b6085933de   10Gi       RWX            jenkins-storageclass   32m

2.8. Jenkins installation page

Access any ip+38080 port of the cluster node

Visit the following page to see that Jenkins is still starting. When the log is output to the following figure, refresh Jenkins to enter the system, copy the password in the log and unlock Jenkins

[the external chain picture transfer fails, and the source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-Gq67dowz-1629451468833)(.\k8s+jenkins realize continuous integration - note picture storage \ 1621415881187.png)]

1) Unlock Jenkins

You can copy the password in the log or view / var/jenkins_home/secrets/initialAdminPassword this file

2) Select the plug-in to install

Check all plug-ins to avoid software dependency in the later stage

Click all to check all

3) Wait until the plug-in is installed

4) Create Jenkins account

5) Set instance address

6) Restart Jenkins

2.9. Login Jenkins

Account admin password admin

3. Deploy gitlab using docker

Here is just an extension of how to deploy gitlab with docker. It is recommended to deploy gitlab with k8s in 4

3.1. Deploy gitlab

[root@k8s-master2 ~]# docker run -d --hostname 192.168.16.105 -p 8443:443 -p 8080:80 -p 8022:22 --name gitlab --restart always -v /data2/k8s/gitlab-data/config/:/etc/gitlab -v /data2/k8s/gitlab-data/logs/:/var/log/gitlab -v /data2/k8s/gitlab-data/data/:/var/opt/gitlab gitlab/gitlab-ce:13.11.4-ce.0

[root@k8s-master2 ~]# docker ps
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS                   PORTS                                                               NAMES
33d868fe0369        gitlab/gitlab-ce:13.11.4-ce.0   "/assets/wrapper"        14 minutes ago      Up 4 minutes (healthy)   0.0.0.0:8022->22/tcp, 0.0.0.0:8080->80/tcp, 0.0.0.0:8443->443/tcp   gitlab

When the following page appears, gitlab startup is complete

3.2. Access gitlab

visit http://192.168.16.105:8080/

The root password needs to be set for the first login

After setting the password, you can log in to the system

4. Deploy gitlab in k8s cluster

Deployment Analysis:

  • Gitlab is deployed by the statefullset controller, and the gitlab configuration file and gitlab data file are persistently stored through StorageClass
  • Because the gitlab image integrates many components, and the user groups used by each component in the gitlab data directory are different, you need to modify the corresponding user for each component, otherwise you have no permission to start relevant components. First, run the gitlab image with docker to query the different users corresponding to different components in the gitlab data directory, Then weight it in the initialization container
  • Modify the configuration file of gitlab to determine the url for external access
  • Port 80 of gitlab is exposed through svc resources

4.1. Push gitlab image to harbor warehouse

[root@k8s-master1 ~]# docker tag gitlab/gitlab-ce:13.11.4-ce.0 harbor.jiangxl.com/jenkins/gitlab-ce:13.11.4-ce.0 
[root@k8s-master1 ~]# docker push  harbor.jiangxl.com/jenkins/gitlab-ce:13.11.4-ce.0 

4.2. Use docker to run gitlab to query the user's id number

Each component of gitlab is managed by different users. We don't know the uid and gid of each user, so we need to start the query with docker first

Remember the user uid and gid of these components, which will be used later when defining the initialization container in the statful resource

1.use docker function gitlab container
[root@k8s-master1 ~]# docker run -d harbor.jiangxl.com/jenkins/gitlab-ce:13.11.4-ce.0

2.Enter container
[root@k8s-master1 ~]# docker exec -it 33d868fe0369 bash

3.see gitlab The user of each component in the data path
root@192:/# ll /var/opt/gitlab/
total 20
drwxr-xr-x 20 root              root       4096 May 20 09:12 ./
drwxr-xr-x  1 root              root         20 May 14 15:17 ../
drwxr-xr-x  2 git               git           6 May 20 09:01 .bundle/
-rw-r--r--  1 git               git         363 May 20 09:01 .gitconfig
drwx--->--->  2 git               git          29 May 20 09:01 .ssh/
drwxr-x--->  3 gitlab-prometheus root         42 May 20 09:11 alertmanager/
drwx--->--->  2 git               root          6 May 20 09:01 backups/
-rw--->--->-  1 root              root         38 May 20 09:06 bootstrapped
drwx--->--->  3 git               git          26 May 20 09:01 git-data/
drwx--->--->  3 git               root        123 May 20 09:11 gitaly/
drwxr-xr-x  3 git               root         20 May 20 09:01 gitlab-ci/
drwxr-xr-x  2 git               root         53 May 20 09:11 gitlab-exporter/
drwxr-xr-x  9 git               root        160 May 20 09:11 gitlab-rails/
drwx--->--->  2 git               root         24 May 20 09:10 gitlab-shell/
drwxr-x--->  3 git               gitlab-www   55 May 20 09:11 gitlab-workhorse/
drwx--->--->  4 gitlab-prometheus root         83 May 20 09:12 grafana/
drwx--->--->  3 root              root         71 May 21 02:21 logrotate/
drwxr-x--->  9 root              gitlab-www  163 May 20 09:05 nginx/
drwx--->--->  2 gitlab-psql       root         26 May 20 09:11 postgres-exporter/
drwxr-xr-x  3 gitlab-psql       root         81 May 20 09:11 postgresql/
drwxr-x--->  4 gitlab-prometheus root         53 May 20 09:11 prometheus/
-rw-r--r--  1 root              root        226 May 20 09:12 public_attributes.json
drwxr-x--->  2 gitlab-redis      git          60 May 21 02:29 redis/
-rw-r--r--  1 root              root         40 May 20 09:01 trusted-certs-directory-hash

4.Just look postgresql,reids,gitlab-data,prometheus Directory users can, mainly these four
#You can see that gitlab data users are git, postgresql users are gitlab PSQL, and redis users are gitlab redis
root@192:/# id git
uid=998(git) gid=998(git) groups=998(git)
root@192:/# 
root@192:/# id gitlab-psql
uid=996(gitlab-psql) gid=996(gitlab-psql) groups=996(gitlab-psql)
root@192:/# 
root@192:/# id gitlab-redis
uid=997(gitlab-redis) gid=997(gitlab-redis) groups=997(gitlab-redis)
root@192:/# 
root@192:/# id gitlab-prometheus
uid=992(gitlab-prometheus) gid=992(gitlab-prometheus) groups=992(gitlab-prometheus)

4.3. Write gitlab StorageClass resource file

[root@k8s-master1 gitlab]# vim gitlab-storageclass.yaml 
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gitlab-storageclass
provisioner: nfs-storage-01
reclaimPolicy: Retain

4.4. Write gitlab statefullset resource file

The StorageClass pvc template defines two, one for storing gitlab data and the other for storing gitlab configuration files

Assign the user uid and gid just found to each component directory through the initialization container

[root@k8s-master1 gitlab]# vim gitlab-statefulset.yaml 
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: gitlab
  namespace: jenkins
spec:
  replicas: 1
  serviceName: gitlab
  selector:
    matchLabels:
      app: gitlab
  template:
    metadata:
      labels:
        app: gitlab
    spec:
      initContainers:							#Define the initialization container and assign each component path to the corresponding user permissions
      - name: gitlab-data-git
        image: harbor.jiangxl.com/jenkins/busybox:1.30
        command: ["sh","-c","chown -R 998:998 /var/opt/gitlab"]			#git users authorize the entire gitlab data directory
        securityContext:			#Enable privileged mode
          privileged: true	
        volumeMounts:				#Mount the data persistent pvc
        - name: gitlab-data
          mountPath: /var/opt/gitlab
      - name: gitlab-data-psql
        image: harbor.jiangxl.com/jenkins/busybox:1.30
        command: ["sh","-c","chown -R 996:996 /var/opt/gitlab/postgresql*"]			#Gitlab PSQL authorization postgresql directory
        securityContext:
          privileged: true
        volumeMounts:
        - name: gitlab-data
          mountPath: /var/opt/gitlab
      - name: gitlab-data-redis
        image: harbor.jiangxl.com/jenkins/busybox:1.30
        command: ["sh","-c","chown -R 997:997 /var/opt/gitlab/redis"]		#Gitlab redis authorized redis directory
        securityContext:
          privileged: true
        volumeMounts:
        - name: gitlab-data
          mountPath: /var/opt/gitlab
      - name: gitlab-data-prome									#Gitlab prometheus user authorization prometheus directory
        image: harbor.jiangxl.com/jenkins/busybox:1.30
        command: ["sh","-c","chown -R 992:992 /var/opt/gitlab/alertmanager /var/opt/gitlab/grafana /var/opt/gitlab/prometheus"]
        securityContext:
          privileged: true
        volumeMounts:
        - name: gitlab-data
          mountPath: /var/opt/gitlab

      - name: gitlab-config-chown					#The initialization container is mainly used to authorize the configuration directory, which is optional, because the user of this directory is root, and the storage path created by nfs is also the owner of root by default
        image: harbor.jiangxl.com/jenkins/busybox:1.30
        command: ["sh","-c","chown -R 998:998 /etc/gitlab"]			#Authorized to gitlab users
        securityContext:	
          privileged: true
        volumeMounts:
        - name: gitlab-config
          mountPath: /etc/gitlab
      containers:										#Define master container
      - name: gitlab
        image: harbor.jiangxl.com/jenkins/gitlab-ce:13.11.4-ce.0
        ports:
        - name: http
          containerPort: 80
        volumeMounts:							#The path to mount the persistent data volume to the container
        - name: gitlab-data
          mountPath: /var/opt/gitlab
        - name: gitlab-config
          mountPath: /etc/gitlab
  volumeClaimTemplates:						#Define pvc template
    - metadata:								#Metadata is in the form of an array, so multiple can be defined. A metadata is a pvc template
        name: gitlab-data					#pvc name
      spec:
        storageClassName: gitlab-storageclass			#StorageClass name used
        accessModes:
        - ReadWriteMany						#The access mode is multi host read-write
        resources:
          requests:
            storage: 10Gi
    - metadata:
        name: gitlab-config
      spec:
        storageClassName: gitlab-storageclass
        accessModes:
        - ReadWriteMany
        resources:
          requests:
            storage: 1Gi

4.5. Write gitlab service resource file

[root@k8s-master1 gitlab]# vim gitlab-svc.yaml 
apiVersion: v1
kind: Service
metadata:
  labels:
    app: gitlab
  name: gitlab-svc
  namespace: jenkins
spec:
  ports:
  - name: http
    port: 80 
    targetPort: 80
    nodePort: 30080
  selector: 
    app: gitlab
  type: NodePort

4.6. Create all resources and view status

1.Create all resources
[root@k8s-master1 gitlab]# kubectl apply -f ./
statefulset.apps/gitlab created
storageclass.storage.k8s.io/gitlab-storageclass created
service/gitlab-svc created

2.View the status of resources
[root@k8s-master1 gitlab]# kubectl get all -n jenkins
NAME                   READY   STATUS    RESTARTS   AGE
pod/gitlab-0           1/1     Running   0          4m21s
pod/jenkins-master-0   1/1     Running   0          18h

NAME                  TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                          AGE
service/gitlab-svc    NodePort   10.101.97.95    <none>        80:30080/TCP                     57m
service/jenkins-svc   NodePort   10.99.113.179   <none>        8080:38080/TCP,50000:50000/TCP   23h

NAME                              READY   AGE
statefulset.apps/gitlab           1/1     57m
statefulset.apps/jenkins-master   1/1     23h

3.see pvc Status of the resource
[root@k8s-master1 gitlab]# kubectl get pvc -n jenkins
NAME                            STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS           AGE
gitlab-config-gitlab-0          Bound    pvc-91e63538-e07d-4196-82e8-4195b29d9352   1Gi        RWX            gitlab-storageclass    64m
gitlab-data-gitlab-0            Bound    pvc-2a300c8d-49e6-4035-99f1-81c3e190fe3e   10Gi       RWX            gitlab-storageclass    57m
jenkins-data-jenkins-master-0   Bound    pvc-9efb572b-d566-418d-bb6e-b225b43de4a5   10Gi       RWX            jenkins-storageclass   23h

4.7. Modify gitlab configuration

After the gitlab service is started, the configuration file and data directory will be stored on pvc. We need to modify the gitlab configuration file to specify the access address

Main: only write the address here and do not add the port. If a port other than 80 is added, the 80 of gitlab in the container will be changed to the port you specify, and the svc will fail to expose gitlab

This step can also be omitted, because for k8s, it is mapped through the ip of any node in the cluster

[root@k8s-master2 ~]# vim /data2/k8s/storageclass/jenkins-gitlab-config-gitlab-0-pvc-91e63538-e07d-4196-82e8-4195b29d9352/gitlab.rb 
external_url 'http://192.168.16.106'

After modification, redeploy gitlab

[root@k8s-master1 gitlab]# kubectl replace -f gitlab-statefulset.yaml 
statefulset.apps/gitlab replaced

4.8. Access gitlab

Access http: / / any node of the cluster ip:30080 port

Gitlab starts slowly. Enter the container to check the status of gitlab. You can access it after run ning

1) Set user password

At least 8 bits. admin123 is set here

2) Enter gitlab

3) Set language to Chinese

5. Submit the program code to gitlab

5.1. Create a new project

1) Click new item

2) Create a blank item

3) Fill in project information

The visibility level is set to public

4) Creation complete

5.2. Submit the program code to gitlab

[root@k8s-master1 python-demo]# git init
 Initialize empty Git Version library at /root/gitlab_project/python-demo/.git/
[root@k8s-master1 python-demo]# git remote add origin http://192.168.16.106:30080/root/blog_project.git
[root@k8s-master1 python-demo]# git add .
[root@k8s-master1 python-demo]# git commit -m "Initial commit"
[root@k8s-master1 python-demo]# git push -u origin master
Username for 'http://192.168.16.106:30080': root 				# enter one user name
Password for 'http://root@192.168.16.106:30080':  				# Input password
Counting objects: 48, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (44/44), done.
Writing objects: 100% (48/48), 978.49 KiB | 0 bytes/s, done.
Total 48 (delta 4), reused 0 (delta 0)
To http://192.168.16.106:30080/root/blog_project.git
 * [new branch]      master -> master
 branch master Set to track from origin Remote branch of master. 

6.Jenkins integrated gitlab

gitlab address must be configured in jenkins, otherwise pipeline cannot find git lab address

6.1. Installing the gitlab plug-in on Jenkins

Modify Jenkins default source to Tsinghua source

1.Modify source
cd /data2/k8s/storageclassjenkins-jenkins-data-jenkins-master-0-pvc-9efb572b-d566-418d-bb6e-b225b43de4a5/updates
sed -i 's/http:\/\/updates.jenkins- ci.org\/download/https:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins/g' default.json
sed -i 's/http:\/\/www.google.com/https:\/\/www.baidu.com/g' default.json

2.restart Jenkins
[root@k8s-master1 ~]# kubectl replace -f /root/k8s1.19/jenkins/jenkins-statefulset.yaml 
statefulset.apps/jenkins-master replaced

System management - > plug-in management - > optional plug-ins - > search gitlab - > install

6.2. Generate token on gitlab

edit profile - > access token - > fill in the token name - > check the permission range

The token is displayed only once and kept properly: F4N8_LrfC7BdNWXXyJA2

6.3. Add gitlab api token in Jenkins

System management - > find gitlab - > configure it

Connection name: gitlab-token

Gitlab host URL: http://192.168.16.104:30080/

After filling in the basic information, click add gitlab token. You can only select gitlab api token as the type and paste it in

After adding the token, select the token just added from the drop-down list. It will no longer turn red, indicating that the connection to gitlab is successful

7.Jenkins distributed master slave mode

Jenkins distributed means that there are multiple slave nodes. When there are many projects to be built, the performance of the master will be affected. The slave will bear the workload of the master and create projects on the slave. The difference between the slave node and the master node is that the slave does not need to install Jenkins

slave nodes can be deployed in many ways. We use

7.1. Add Jenkins node

1) System management - > node management - > new node - > fill in node name - > fixed node - > OK

2) Add node details

Name: Jenkins-slave1-107

Number of actuators: 3

Remote working directory: / data/jenkins_jobs

Label: Jenkins-slave1-107 # is used to make Jenkins run a task on a node

Usage: use this node as much as possible

Start method: start the agent through java web

Custom working directory: / data/jenkins_jobs

3) After adding the node, it is found that the node is red, which indicates that the agent has not been started, and Jenkins does not know who the node is

Click the node and you will see how to start the agent. Right click to copy the agent Get the link address of jar, download the jar package on the corresponding server, and then start to successfully add the node

1.Create node working directory
[root@k8s-node2 ~]# mkdir /data/jenkins_jobs
[root@k8s-node2 ~]# cd /data/jenkins_jobs

2.download agent program
[root@k8s-node2 /data/jenkins_jobs]# wget http://192.168.16.104:38080/jnlpJars/agent.jar

3.start-up agent
[root@k8s-node2 /data/jenkins_jobs]# nohup java -jar agent.jar -jnlpUrl http://192.168.16.104:38080/computer/Jenkins-slave1-107/jenkins-agent.jnlp -secret efbde6c51590ca2c9097e6866de9f2d18520bfc05440a1872135e78b47283721 -workDir "/data/jenkins_jobs" &


Command interpretation:
 java -jar agent.jar \			#Start the jar package
 -jnlpUrl http://192.168.16.104:38080/computer/Jenkins-slave1-107/jenkins-agent.jnlp \  	# This path is the path of the node after we create a new node on Jenkins. If it is not specified, Jenkins does not know which server this node corresponds to
 -secret efbde6c51590ca2c9097e6866de9f2d18520bfc05440a1872135e78b47283721 \		#authentication
 -workDir "/data/jenkins_obs" &			#working directory

After the agent is started, observe the node on the Jenkins page and find that it is already available

7.2. Create a new task to run on the slave1 node

1) Configure task - > General - > restrict the running node of the project - > fill in the label set by the node

2) Run the task to observe which node it is running on

Select the master branch to start building

The task has been run on the jenkins-slave 1-107 node

The nail has received the information and has generated data in the node working directory

7.3. Execution tasks associated with observation nodes

At this stage, the CI/CD platform has been deployed. We can create a new process and update the program to the kubernetes platform

8. Update the know system project to the kubernetes environment using the pipeline pipeline

There are two ways to update k8s

​ 1. Upload the resource yaml file to the code warehouse. After the project is mirrored, we can replace the latest version of the image into the deployment resource by replacing the string of the image specified by the deployment resource. Finally, execute kubectl apply/ Update complete

​ 2. Execute the kubectl command to update the image of the deployment resource

Since our construction tasks are run through agent s, which are deployed on the k8s node and inherit the docker and kubectl commands, there is no need to worry about the failure of the kubectl command

8.1. Realization idea

1. First, deploy the know system in k8s to realize the accessible state

2. Copy the yaml file of the deployment know system to the code directory, and change the image corresponding to the container image in the deployment resource to a string, so that when the pipeline is updated, the latest image version can be replaced into the deployment resource by replacing the string, and finally push the code and deployment file to gitlab

3. Optimize pipeline script and add k8s deployment steps

4. Update the code and use the pipeline to update the project to k8s

8.2. Deploy the know system in k8s

1) Prepare project yaml files

1.prepare deployment resources
[root@k8s-master1 know-system]# cat nginx-depoly.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: know-system
  namespace: know-system
spec:
  replicas: 3
  selector:
    matchLabels:
      app: know-system
  template:
    metadata:
      labels:
        app: know-system
    spec:
      containers:
      - name: nginx
        image: harbor.jiangxl.com/project/nginx-project:v1-code
        ports:
        - containerPort: 80
        volumeMounts:
        - name: nginx-data
          mountPath: /data/code
        - name: nginx-config
          mountPath: /data/nginx/conf/conf.d/
      volumes:
        - name: nginx-config
          configMap:
            name: nginx-configmap
        - name : nginx-data
          persistentVolumeClaim:
            claimName: pvc-know
            readOnly: false

2.prepare configmap resources
[root@k8s-master1 know-system]# cat nginx-configmap.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-configmap
  namespace: know-system
data:
  know.jiangxl.com.conf: |
    server {
      listen 80;
      server_name know.jiangxl.com;
      location / {
        root /data/code/know_system;
        index index.html;
      }
    }

3.prepare svc resources
[root@k8s-master1 know-system]# cat nginx-svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: know-system
spec:
  selector:
    app: know-system
  type: NodePort
  ports:
  - port: 80		
    targetPort: 80

2) Create all resources

[root@k8s-master1 know-system]# kubectl apply -f ./
configmap/nginx-configmap unchanged
deployment.apps/know-system configured
service/nginx-service configured

3) View project home page

8.3. Submit the k8s resource file to gitlab

1.Copy the deployment file to the code directory
[root@k8s-master1 know_system]# mkdir deploy
[root@k8s-master1 know_system]# cp /root/k8s1.19/know-system/* deploy/

2.modify deployment In resources image
#Change the image corresponding to the image into a string. When updating the pipeline, you can replace the latest image into the deployment resource by replacing this string
[root@k8s-master1 know_system]# vim deploy/nginx-depoly.yaml 
        image: {{updateimage}}

2.Submit to gitlab
[root@k8s-master1 know_system]# git add .
[root@k8s-master1 know_system]# git commit -m "deploy"
[root@k8s-master1 know_system]# git push origin master

8.4. Write Jenkins pipeline to update the project to k8s

The current pipeline script mainly updates the project pod created with yaml file

pipeline {
    agent { label 'Jenkins-slave1-107' }                //Make the pipeline always run on the Jenkins-slave1-107 Jenkins agent node, because the server where this node is located can run the docker and kubelet commands of the k8s cluster

    environment {                                   //Environment is mainly used to define environment variables. Some commonly used values can be made into environment variables
        IMAGE_REPO="harbor.jiangxl.com/project"
    }

	parameters {                               //Define parametric build process
		gitParameter(name: 'VERSION',defaultValue: 'master',type: 'BRANCH',description: 'Select the branch to update')             //Define a gitparamters parameterized build process for selecting updated code
		string(name: 'project',defaultValue: 'know-system',description: 'entry name',trim: true)                  //Define a blank string to declare the project name
	}	
    stages {                        //Define pipeline execution phase
        stage('Operation and maintenance confirmation information') {                                 //In phase 1, an interactive is used to let the operation confirm the update information. If there is an error, you can directly exit the update to avoid the update error
            steps {
                input message: """                          
                jobname: ${project}
                branch: ${VERSION}""", ok: "to update"                       //Interactively output an updated item and branch number
            }
        }
        stage('Pull item code') {                                  //Phase 2 is used to pull the corresponding project code on git
            steps {
				checkout([$class: 'GitSCM', branches: [[name: '$VERSION']], extensions: [], userRemoteConfigs: [[credentialsId: 'gitlab-root', url: 'http://192.168.16.106:30080/root/know_system.git']]])
            }
        }  
        stage('Build project image') {			                        //Phase 3 It is used to update the project code to the initial docker image. The main step is to produce a dockerfile, copy the code to the image, and finally build the image according to the dockerfile
            steps {
				sh """              
                pwd
				echo "
FROM harbor.jiangxl.com/project/nginx-project:v1-code

RUN mkdir /data/code/know_system
COPY  ./* /data/code/know_system/
EXPOSE 80
				" >Dockerfile
				"""                             //Write a Dockerfile, define the initial image, and copy the updated code to the specified path of the container

 				sh 'docker build -t ${IMAGE_REPO}/${project}:master-v${BUILD_ID} .'		//The name of the final image is harbor jiangxl. com/project/know-system:master-v1                
            }
        }   

        stage('Push mirror to harbor Warehouse') {             //In phase 4, the constructed image is pushed to the harbor warehouse to k8s pull the update program
            steps {
 				sh 'docker push ${IMAGE_REPO}/${project}:master-v${BUILD_ID}'		//Push image to harbor warehouse
            }
        }           
        stage('Update project to k8s') {                     //Phase 5 is mainly to update k8s the container used by the project, replace the newly built image with the project pod, and then update the pod
            steps {                                     //Update the project using the kubectl command
 				sh "sed -i 's#{{updateimage}}#${IMAGE_REPO}/${project}:master-v${BUILD_ID}#g' deploy/*" 		    // Replace the image version string we wrote in the deployment resource with the image version just pushed to the harbor warehouse
                sh 'kubectl apply -f deploy/'                   //When the image version is replaced, the project update can be completed by updating the yaml file of the resource
            }
        }                  
    }
    post {
    	success {				//The build successfully sends a message constituting success to the nail
    			echo "Build succeeded, send message to nail"
    			sh """
    			curl 'https://oapi.dingtalk.com/robot/send?access_token=6719ac958daf4f31114cb0c1289837c9aca45d111d8653b04c3d6ae164f25146' \
 -H 'Content-Type: application/json' \
 -d '{"msgtype": "text","text": {"content":"😄👍Build successful👍😄\n keyword: jenkins\n Project name: ${JOB_BASE_NAME}\n Updated branch number: ${VERSION}\n Image version of this build: ${IMAGE_REPO}/${project}:master-v${BUILD_ID}\n Build address: ${RUN_DISPLAY_URL} "}}'
    			"""
    	}
    	failure {				//The build failed. Send a success message to the nail
    			echo "Build failed, send message to pin"
    			sh """
    			curl 'https://oapi.dingtalk.com/robot/send?access_token=6719ac958daf4f31114cb0c1289837c9aca45d111d8653b04c3d6ae164f25146' \
 -H 'Content-Type: application/json' \
 -d '{"msgtype": "text","text": {"content":"😖❌Build failed❌😖\n keyword: jenkins\n Project name: ${JOB_BASE_NAME}\n Updated branch number: ${VERSION}\n Image version of this build: ${IMAGE_REPO}/${project}:master-v${BUILD_ID}\n Build address: ${RUN_DISPLAY_URL} "}}'
 				"""
    	}
    	always {					//Perform this step regardless of success or failure
    		echo "End of construction process"
    	}
    }
}

8.5. Paste pipeline into pipeline task

8.6. Build master branch to complete project update

1) Select update information

2) Operation and maintenance confirmation information

3) pipeline task updated successfully

4) View the updated image version in blue ocean

5) Observe whether the project is updated to the latest mirror version on rancher

The update process completed successfully!

Topics: Kubernetes