Jenkins Master
- PVC
1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jenkins
namespace: devops
spec:
accessModes:
- ReadWriteMany
volumeMode: Filesystem
resources:
requests:
storage: 2Gi
#storageClassName: "managed-nfs-storage"
- Install
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins
namespace: devops
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: jenkins
rules:
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets"]
verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
- apiGroups: ["batch"]
resources: ["cronjobs"]
verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
- apiGroups: [""] # 安装 jenkins master 不需要 "services" 权限,这是后来 jenkins slave 用 ServiceAccount['jenkins'] 部署 service 时增加的
resources: ["services"]
verbs: ["create", "delete", "get", "list", "patch", "update", "watch"]
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses"]
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", "events"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["secrets", "configmaps"]
verbs: ["get"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: jenkins
subjects:
- kind: ServiceAccount
name: jenkins
namespace: devops
roleRef:
kind: ClusterRole
name: jenkins
apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins
namespace: devops
spec:
selector:
matchLabels:
app: jenkins
template:
metadata:
labels:
app: jenkins
spec:
serviceAccount: jenkins
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- jenkins
topologyKey: kubernetes.io/hostname
containers:
- name: jenkins
#image: jenkins/jenkins:lts-jdk17
image: jenkins/jenkins:2.426.2-lts-jdk17
imagePullPolicy: IfNotPresent
securityContext:
privileged: true # 拥有特权
runAsUser: 0 # 设置以ROOT用户运行容器
ports:
- containerPort: 8080
name: web
protocol: TCP
- containerPort: 50000
name: agent
protocol: TCP
resources:
limits:
cpu: 1500m
memory: 1024Mi
requests:
cpu: 100m
memory: 512Mi
env:
- name: TZ
value: 'Asia/Shanghai'
- name: LIMITS_MEMORY
valueFrom:
resourceFieldRef:
divisor: 1Mi
resource: limits.memory
- 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
readinessProbe:
httpGet:
path: /login
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 5
failureThreshold: 12
volumeMounts:
- name: jenkinshome
mountPath: /var/jenkins_home
volumes:
- name: jenkinshome
persistentVolumeClaim:
claimName: jenkins
---
apiVersion: v1
kind: Service
metadata:
name: jenkins
namespace: devops
labels:
app: jenkins
spec:
selector:
app: jenkins
type: ClusterIP
ports:
- name: web
port: 8080
targetPort: web
- name: agent
port: 50000
targetPort: agent
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: jenkins
namespace: devops
spec:
ingressClassName: nginx
tls:
- hosts:
- jenkins.zhch.lan
secretName: zhch.lan
rules:
- host: jenkins.zhch.lan
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: jenkins
port:
number: 8080
-
访问
-
https://jenkins.zhch.lan
1 2
[root@k8s-master1 ~]# cat /root/nfs_data/rw/default/devops-jenkins-pvc-b3bbf3a2-e00a-4e8a-b51f-5f3cd9753cfa/secrets/initialAdminPassword 70e04c70b96d4dba894916e82ea7714f
-
暂先不安装任何插件
-
修改
/var/lib/jenkins/updates/default.json
文件,替换插件地址1 2
sed -i 's/https:\/\/updates.jenkins.io\/download\/plugins/https:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins\/plugins/g' default.json sed -i 's/https:\/\/www.google.com/https:\/\/www.baidu.com/g' default.json
-
修改插件更新地址为国内地址
- Manage Jenkins -> Plugins -> Advanced settings -> Update Site
https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
- 通过
https://jenkins.zhch.lan/restart
重启 jenkins
-
按需安装插件
-
Localization: Chinese (Simplified)
- Git
-
正常情况下,想要通过 SSH 拉取代码,需要将 Gitlab host 添加到 Jenkins 的 ~/.ssh/known_hosts 中
-
可通过命令
[root@Jenkins ~]# ssh -T git@git.zhch.lan
达成该目的 -
但现在 Gitlab 和 Jenkins 均是部署在容器中,因此不便如此操作,故而取消 Git Host Key 验证
-
-
Gitlab
-
Git Parameter
- 用于动态从 Github 或者 Gitlab 中检索项目分支信息,在 Jenkins Job 参数化构建中提供选择分支项,方便用户在执行构建时候执行选择的分支。
-
Pipeline
-
Pipeline: Stage View
-
Environment Injector
- Item 范围的环境变量
-
Extended Choice Parameter
- 复选框
-
Kubernetes
-
Config File Provider
-
Build Authorization Token Root
-
SonarQube Scanner
- Node and Label parameter
-
-
自定义 Jenkins Slave 镜像
1
2
3
4
5
6
7
8
9
# 准备工作
# 1. 下载 Maven (略)
# 2. 下载 sonar-scanner-cli
wget https://repo1.maven.org/maven2/org/sonarsource/scanner/cli/sonar-scanner-cli/5.0.1.3006/sonar-scanner-cli-5.0.1.3006-linux.zip
# Dockerfile ADD 时不能自动解压 zip 文件
unzip sonar-scanner-cli-5.0.1.3006-linux.zip
[root@k8s-master1 jenkins-slave]# ls
apache-maven-3.9.6-bin.tar.gz Dockerfile sonar-scanner-5.0.1.3006-linux sonar-scanner-cli-5.0.1.3006-linux.zip
Maven
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
# Dockerfile
# https://github.com/jenkinsci/docker-inbound-agent
# https://hub.docker.com/r/jenkins/inbound-agent/
# 选择源镜像时,注意其使用的 Java 版本,要与 Jenkins Master 的镜像使用的 JDK 版本一致
# 若使用 Java 8 ,可使用 Tag 3046.v38db_38a_b_7a_86-1-jdk8
FROM jenkins/inbound-agent:3198.v03a_401881f3e-1-jdk17
MAINTAINER vito<hczhch@yeah.net>
# 切换到 root 账户进行操作
USER root
# 时区
ENV TZ Asia/Shanghai
# RUN ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 安装 maven
ADD apache-maven-3.9.6-bin.tar.gz .
RUN mv apache-maven-3.9.6 /usr/local/maven
RUN ln -s /usr/local/maven/bin/mvn /usr/bin/mvn
# 安装 sonar-scanner-cli
COPY sonar-scanner-5.0.1.3006-linux /usr/local/sonar-scanner
RUN ln -s /usr/local/sonar-scanner/bin/sonar-scanner /usr/bin/sonar-scanner
# 解决使用 sonar-scanner 命令时因自签证书问题,无法连接 SonarQube 服务器问题
# 方法一:将 SonarQube 服务的证书添加到 sonar-scanner 使用的 jre 的信任证书库
# COPY zhch.lan.crt /home/jenkins/
# RUN echo 'yes' | keytool -importcert -trustcacerts -keystore '/usr/local/sonar-scanner/jre/lib/security/cacerts' -storepass changeit -alias zhch.lan -file /home/jenkins/zhch.lan.crt
# 方法二:在 Jenkins Master 中配置 SonarQube servers 时使用内部地址,例如:http://sonarqube.devops:9000
# 安装 sudo
RUN apt-get update
RUN apt-get install -y sudo
# 在镜像挂载 /var/run/docker.sock 和 /usr/bin/docker 后,让 jenkins 用户能够免密执行 sudo docker 命令
RUN echo 'jenkins ALL=(ALL) NOPASSWD: /usr/bin/docker' >> /etc/sudoers
USER jenkins
1
2
3
4
5
docker build -t harbor.zhch.lan/library/inbound-agent:3198.jdk17-maven3.9 .
docker login -u vito -p Harbor12345 harbor.zhch.lan
docker push harbor.zhch.lan/library/inbound-agent:3198.jdk17-maven3.9
- Maven settings.xml
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
apiVersion: v1
kind: ConfigMap
metadata:
name: maven
namespace: devops
data:
settings.xml: |
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
<localRepository>/home/jenkins/repo</localRepository>
<pluginGroups>
<!-- <pluginGroup>org.sonarsource.scanner.maven</pluginGroup> -->
</pluginGroups>
<proxies>
</proxies>
<servers>
</servers>
<mirrors>
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>https://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>
<profiles>
<!-- <profile>
<id>sonar</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<sonar.host.url>http://sonarqube.devops:9000</sonar.host.url>
</properties>
</profile> -->
</profiles>
<activeProfiles>
</activeProfiles>
</settings>
NodeJS
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
# Dockerfile
# https://github.com/jenkinsci/docker-inbound-agent
# https://hub.docker.com/r/jenkins/inbound-agent/
# 选择源镜像时,注意其使用的 Java 版本,要与 Jenkins Master 的镜像使用的 JDK 版本一致
# 若使用 Java 8 ,可使用 Tag 3046.v38db_38a_b_7a_86-1-jdk8
FROM jenkins/inbound-agent:3198.v03a_401881f3e-1-jdk17
MAINTAINER vito<hczhch@yeah.net>
# 切换到 root 账户进行操作
USER root
# 时区
ENV TZ Asia/Shanghai
# RUN ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 安装 NodeJS
# https://nodejs.org/dist/v12.22.12/node-v12.22.12-linux-x64.tar.gz
ADD node-v12.22.12-linux-x64.tar.gz .
RUN mv node-v12.22.12-linux-x64 /usr/local/nodejs
RUN ln -s /usr/local/nodejs/bin/node /usr/bin/node
RUN ln -s /usr/local/nodejs/bin/npm /usr/bin/npm
RUN ln -s /usr/local/nodejs/bin/npx /usr/bin/npx
# 安装 cnpm (需要主要 cnpm 与 node 的版本兼容问题)
RUN npm install cnpm@7.1.1 -g --registry=https://registry.npm.taobao.org
RUN ln -s /usr/local/nodejs/bin/cnpm /usr/bin/cnpm
# 安装 sonar-scanner-cli
COPY sonar-scanner-5.0.1.3006-linux /usr/local/sonar-scanner
RUN ln -s /usr/local/sonar-scanner/bin/sonar-scanner /usr/bin/sonar-scanner
# 解决使用 sonar-scanner 命令时因自签证书问题,无法连接 SonarQube 服务器问题
# 方法一:将 SonarQube 服务的证书添加到 sonar-scanner 使用的 jre 的信任证书库
# COPY zhch.lan.crt /home/jenkins/
# RUN echo 'yes' | keytool -importcert -trustcacerts -keystore '/usr/local/sonar-scanner/jre/lib/security/cacerts' -storepass changeit -alias zhch.lan -file /home/jenkins/zhch.lan.crt
# 方法二:在 Jenkins Master 中配置 SonarQube servers 时使用内部地址,例如:http://sonarqube.devops:9000
# 安装 sudo
RUN apt-get update
RUN apt-get install -y sudo
# 在镜像挂载 /var/run/docker.sock 和 /usr/bin/docker 后,让 jenkins 用户能够免密执行 sudo docker 命令
RUN echo 'jenkins ALL=(ALL) NOPASSWD: /usr/bin/docker' >> /etc/sudoers
USER jenkins
1
2
3
4
5
docker build -t harbor.zhch.lan/library/inbound-agent:3198.jdk17-node12 .
docker login -u vito -p Harbor12345 harbor.zhch.lan
docker push harbor.zhch.lan/library/inbound-agent:3198.jdk17-node12
Jenkins Slave NFS 权限问题
- 观察 Jenkins Slave 镜像的构建过程,该镜像创建了组 ID 为 1000 的用户组
jenkins
,并在该用户组中创建了用户 ID 为 1000 的用户jenkins
;并最终以jenkins
身份运行。 - 在 NFS 服务器中创建挂载目录,用户存储 maven 下载的依赖包,并修改该目录的权限
1
[root@k8s-master1 ~]# chown 1000:1000 -R /root/nfs_data/rw/maven/repo
- 把该目录挂载到 jenkins slave 中
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
// https://www.jenkins.io/doc/pipeline/steps/kubernetes/ podTemplate(label: 'jenkins-slave', cloud: 'k8s', containers: [ containerTemplate( name: 'jnlp', image: "harbor.zhch.lan/library/inbound-agent:3198.jdk17-maven3.9" ), containerTemplate( name: 'docker', image: "docker:24.0.7", ttyEnabled: true, command: 'cat' ) ], volumes: [ hostPathVolume(mountPath: '/var/run/docker.sock', hostPath: '/var/run/docker.sock'), nfsVolume(mountPath: '/home/jenkins/repo', serverAddress: 'k8s-master1.zhch.lan' , serverPath: '/root/nfs_data/rw/maven/repo', readOnly: false), configMapVolume(mountPath: '/usr/local/maven/conf/settings.xml', subPath: 'settings.xml', configMapName: 'maven') ], //security(fsGroup: 2000) ) { node("jenkins-slave") { } }