# Jenkins 云环境部署
# Namespace
$ kubectl create namespace devops
# PV 和 PVC
jenkins-pv-pvc.yaml 文件内容如下
apiVersion: v1
kind: PersistentVolume
metadata:
name: jenkins-pv
spec:
capacity:
storage: 20Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Delete
nfs:
path: /backup/data/jenkins
server: 10.16.16.41
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: jenkins-work-claim
namespace: devops
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 50Gi
创建 PV 和 PVC
$ kubectl create -f jenkins-pv-pvc.yaml
# RBAC
jenkins-rbac.yaml 文件内容如下
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins
namespace: devops
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
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"]
- apiGroups: [""]
resources: ["events"]
verbs: ["get","list","watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: jenkins
namespace: devops
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: jenkins
subjects:
- kind: ServiceAccount
name: jenkins
namespace: devops
创建 RBAC
$ kubectl create -f jenkins-rbac.yaml
# Deployment 和 Service
jenkins-deployment.yaml 文件内容如下
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins
namespace: devops
spec:
selector:
matchLabels:
app: jenkins
template:
metadata:
labels:
app: jenkins
spec:
terminationGracePeriodSeconds: 10
serviceAccount: jenkins
containers:
- name: jenkins
image: 10.16.16.47:8082/devops-docker-image-dev-local/jenkins:2.368
imagePullPolicy: Always
ports:
- containerPort: 8080
name: web
protocol: TCP
- containerPort: 50000
name: agent
protocol: TCP
resources:
limits:
cpu: 2000m
memory: 4Gi
requests:
cpu: 2000m
memory: 4Gi
livenessProbe:
httpGet:
path: /login
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 5
failureThreshold: 12
readinessProbe:
httpGet:
path: /login
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 5
failureThreshold: 12
env:
- name: JAVA_OPTS
value: -Dhudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=true -Dorg.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval.ADMIN_AUTO_APPROVAL_ENABLED=true
volumeMounts:
- name: jenkins-data
mountPath: /var/jenkins_home # Jenkins 数据存储目录,里边包含了Jobs、插件等文件信息,需将其进行挂载持久化
- name: timezone
mountPath: /etc/localtime # 挂载时区
securityContext:
fsGroup: 1000
volumes:
- name: jenkins-data
persistentVolumeClaim:
claimName: jenkins-work-claim
- name: timezone
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai # 挂载时区
jenkins-svc.yaml 文件内容如下
---
apiVersion: v1
kind: Service
metadata:
name: jenkins
namespace: devops
labels:
app: jenkins
spec:
selector:
app: jenkins
type: NodePort
ports:
- name: web
port: 8080
targetPort: web
nodePort: 30081
- name: agent
port: 50000
targetPort: agent
nodePort: 30082
创建 Service 和 Deployment,将 Jenkins 部署到 Kubernetes 集群中,并暴露服务供外部访问
$ kubectl create -f jenkins-deployment.yaml
$ kubectl create -f jenkins-svc.yaml
# 初始化配置
等到服务启动成功后,可以根据 Node 节点的 IP:30081 端口就可以访问 jenkins 服务了,可以根据提示信息进行安装配置即可
获取初始密码:
$ kubectl exec -it $(kubectl get pods -n devops | awk '{print $1}' | grep jenkins) -n devops -- cat /var/jenkins_home/secrets/initialAdminPassword
# 安装插件
安装前需先停用 Jenkins 应用。
Jenkins 应用停止后,将提供的 Jenkins 插件包解压至容器内部的 /var/jenkins_home/plugins
目录下并重启应用即可。
# 动态 Slave 节点配置
登入 Jenkins 平台,安装 Kubernetes 插件, 依次点击系统管理(Manage Jenkins) -> 插件管理(Manage Plugins) -> Available -> 输入 Kubernetes 勾选安装,等待安装完成,然后重启Jenkins,使之生效。
依次点击系统管理(Manage Jenkins)→节点管理(Manage Nodes and Clouds)→Configure Clouds→Add a new cloud→选择Kubernetes→Kubernetes Cloud details,然后填写Kubernetes和Jenkins配置信息。
注意命名空间配置,这里填 devops(即当前 Jenkins 应用所属 namespace),然后点击连接测试,如果出现 Connected to Kubernetes [K8S版本号] 的提示信息,就说明 Jenkins 已经可以和 Kubernetes 系统正常通信了。
Jenkins 地址:http://jenkins.devops.svc.cluster.local:8080,其格式为:http://{serviceName}.{namespace}.svc.cluster.local:8080
新增一个 Pod Template,其名称和标签均取为 ci
在 Pod Template 中添加容器模板列表
Git 容器
Maven 容器
Docker 容器
JNLP 容器
注意
在离线环境下,每个 Pod Template 中都必须添加上一个 JNLP 容器(名称必须取为 jnlp),并且其运行命令和命令参数这两个参数的内容都必须置空。
JNLP 容器的作用是让 Jenkins 的 Master 和 Slave 节点之间保持交互通信。
如未自行配置 JNLP 容器,Jenkins 调度生成的 Pod 中默认也会带上一个 JNLP 容器(该容器镜像从公网中获取)。
主机目录挂载
挂载以下主机目录,用于 Pod 中的容器能够共享宿主机的 Docker,即实现 Docker in Docker
工作空间卷
在容器云环境新增一个 PVC,取名为 jenkins-slave-work-claim(参考 jenkins-pv-pvc.yaml),其目的在于将动态 Slave 节点运行时生成的工作空间进行持久化。
说明
因 Pod Slave 每次执行完就会自动销毁,如果一个流水线周期中会有启动两个或多个 Pod 的情况,一般可将工作目录挂载到 PVC 上,实现 Pod 之间的数据共享。
Pod Template 在被流水线调度创建时的内部情况
流水线执行调度生成动态 Slave 节点时,如果指定的节点(即 Pod Template)的容器列表配置了多少容器信息,那么在节点创建时,就会启动多少容器。
此示例中的 ci 这个 Pod Template,里边配置了 jnlp、git 、maven 以及 docker 这四个容器。当流水线执行时指定了此 Pod Template,运行期间节点内部将存在有四个容器,分别为 jnlp、git、maven 以及 docker。
# DevOps 集成云上 Jenkins
# 构建流水线配置示例
原子任务基本信息
拉取 Git 代码
Maven 构建
上传程序包
Docker 镜像构建并上传
原子任务节点及容器信息
流水线运行只在一个Pod中运行,其节点和容器配置如下:
说明
此处节点对应 Jenkins 引擎里的 Pod Template 的标签名(Label),容器则对应 Jenkins 引擎里的 Pod Template 里容器列表中的某个容器名称