在 kubernetes 上部署 Jenkins
在k8s上运行jenkins之前,我们需要知道几件事情:
- 可以通过
image
修改 jenkins 镜像的版本 - 可以通过
nodeSelector
选择 jenkins pod 运行在哪个 Node(cpu/mem 充足)节点上 - 我们对 Jenkins 的运行做了资源限制,如果不够,可以按需修改,
limits
和requests
中的 CPU 单位通常是指 CPU 的千分之一为最小单位,所以 1000m 就表示 1 个 CPU,200m 表示 0.2 个 - 我们对 jenkins 的数据做了持久化配置,通过 nfs 提供 pv,如果你有 ceph,glusterfs,可以按需修改
- jenkins 在 k8s 上被指定到了
kube-ops
命令空间下,如果没有,请提前创建kubectl create ns kube-ops
- 使用 jenkins 最头疼的事就是插件下载不下来,无法正常运行,因此有两个办法就是,第一,你把
基础插件
提前拷贝到存储卷上,第二就是通过把插件打到 jenkins docker 镜像内,其实都一样。
准备配置清单
配置清单的文件名称,使用者按需自己创建。
准备 pv 和 pvc 的清单配置文件
代码语言:javascript复制apiVersion: v1
kind: PersistentVolume
metadata:
name: jenkinspv
spec:
capacity:
storage: 15Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Delete
nfs:
server: 172.16.132.231
path: /data/k8s
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: jenkinspvc
namespace: kube-ops
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 15G
创建 pv/pvc 对象,这里我们要注意 nfs 提供给 jenkins 的存储目录的权限问题,否则服务因为权限无法写入数据:
在 nfs 服务主机上:
代码语言:javascript复制chown -R 1000 /data/k8s/jenkins2
然后,我们就可以配置 pv 了:
代码语言:javascript复制kubectl apply -f jenkins-storage.yaml
准备 ServiceAccount 资源对象
代码语言:javascript复制apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins2
namespace: kube-ops
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: jenkins2
namespace: kube-ops
rules:
- 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: RoleBinding
metadata:
name: jenkins2
namespace: kube-ops
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: jenkins2
subjects:
- kind: ServiceAccount
name: jenkins2
namespace: kube-ops
创建 sa 对象
代码语言:javascript复制kubectl apply -f jenkins-sa.yaml
准备 jenkins deployment 配置清单
在准备好 sa 和存储之后,我们就可以运行 jenkins 了,这里我们通过ClusterIP
访问 Jenkins pod,因此我们还会准备一个 jenkins service 资源对象在 deployment 下方
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins2
namespace: kube-ops
spec:
selector:
matchLabels:
app: jenkins2
template:
metadata:
labels:
app: jenkins2
spec:
nodeSelector:
kubernetes.io/hostname: dev-k8s-02.kubemaster.top
terminationGracePeriodSeconds: 10
serviceAccountName: jenkins2
containers:
- name: jenkins
image: jenkins/jenkins:lts
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
name: web
protocol: TCP
- containerPort: 50000
name: agent
protocol: TCP
resources:
limits:
cpu: 2000m
memory: 4Gi
requests:
cpu: 1000m
memory: 2Gi
livenessProbe:
httpGet:
path: /login
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 5
failureThreshold: 12
readinessProbe:
httpGet:
path: /login
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 5
failureThreshold: 12
volumeMounts:
- name: jenkinshome
subPath: jenkins2
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: jenkinspvc
---
apiVersion: v1
kind: Service
metadata:
name: jenkins2
namespace: kube-ops
labels:
app: jenkins2
spec:
selector:
app: jenkins2
ports:
- name: web
port: 8080
targetPort: web
- name: agent
port: 50000
targetPort: agent
此时我们就可以应用apply
这个 deployment 了,在应用之后,如果你的nodeSelector
服务器上没有这个 jenkins 的镜像,可能需要一段时间拉取
kubectl apply -f jenkins-deployment-with-svc.yaml
当 jenkins 运行成功之后,我们应该如何访问呢,此处我们通过 traefik 的ingressroute
增加一个路由,用于在(k8s 集群外)外部访问 jenkins,如果你还没有 Traefik,想要安装的话,可以查看 Traefik 在 k8s 的使用文章
准备 jenkins ingressroute 配置清单
代码语言:javascript复制apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: jenkinsingress
namespace: kube-ops
spec:
entryPoints:
- web
routes:
- match: Host(`jenkins.kubemaster.top`)
kind: Rule
services:
- name: jenkins2
port: 8080
将配置应用到 k8s 环境中
代码语言:javascript复制kubectl apply -f jenkins-ingressroute.yaml
准备域名以及 DNS 解析
准备一个域名,将域名解析到 Traefik 运行的主机上,通过 web 端口既可以访问 jenkins 了
代码语言:javascript复制☸️ devcluster? tracing ~/api master ? ? curl -I jenkins.kubemaster.top
HTTP/1.1 403 Forbidden
Content-Length: 793
Content-Type: text/html;charset=utf-8
Date: Tue, 21 Apr 2020 09:32:36 GMT
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Server: Jetty(9.4.25.v20191220)
Set-Cookie: JSESSIONID.b1161c1c=node07msgdvrmibs59emvt3tn25pp433368.node0; Path=/; HttpOnly
X-Content-Type-Options: nosniff
X-Hudson: 1.395
X-Hudson-Cli-Port: 50000
X-Jenkins: 2.204.3
X-Jenkins-Cli-Port: 50000
X-Jenkins-Cli2-Port: 50000
X-Jenkins-Session: d1c63459
X-Permission-Implied-By: hudson.security.Permission.GenericRead
X-Permission-Implied-By: hudson.model.Hudson.Administer
X-Required-Permission: hudson.model.Hudson.Read
X-You-Are-Authenticated-As: anonymous
X-You-Are-In-Group-Disabled: JENKINS-39402: use -Dhudson.security.AccessDeniedException2.REPORT_GROUP_HEADERS=true or use /whoAmI to diagnose