# 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 服务了,可以根据提示信息进行安装配置即可

jenkins-getting-start

获取初始密码:

$ 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 节点配置

  1. 登入 Jenkins 平台,安装 Kubernetes 插件, 依次点击系统管理(Manage Jenkins) -> 插件管理(Manage Plugins) -> Available -> 输入 Kubernetes 勾选安装,等待安装完成,然后重启Jenkins,使之生效。

  2. 依次点击系统管理(Manage Jenkins)→节点管理(Manage Nodes and Clouds)→Configure Clouds→Add a new cloud→选择Kubernetes→Kubernetes Cloud details,然后填写Kubernetes和Jenkins配置信息。

    kubernetes-jenkins-configuration

    注意命名空间配置,这里填 devops(即当前 Jenkins 应用所属 namespace),然后点击连接测试,如果出现 Connected to Kubernetes [K8S版本号] 的提示信息,就说明 Jenkins 已经可以和 Kubernetes 系统正常通信了。

    Jenkins 地址:http://jenkins.devops.svc.cluster.local:8080,其格式为:http://{serviceName}.{namespace}.svc.cluster.local:8080

  3. 新增一个 Pod Template,其名称和标签均取为 ci

    jenkins-slave-pod-template

  4. 在 Pod Template 中添加容器模板列表

    • Git 容器

      jenkins-slave-git-container

    • Maven 容器

      jenkins-slave-maven-container

    • Docker 容器

      jenkins-slave-docker-container

    • JNLP 容器

      jenkins-slave-jnlp-container

      注意

      在离线环境下,每个 Pod Template 中都必须添加上一个 JNLP 容器(名称必须取为 jnlp),并且其运行命令和命令参数这两个参数的内容都必须置空。

      JNLP 容器的作用是让 Jenkins 的 Master 和 Slave 节点之间保持交互通信。

      如未自行配置 JNLP 容器,Jenkins 调度生成的 Pod 中默认也会带上一个 JNLP 容器(该容器镜像从公网中获取)。

  5. 主机目录挂载

    挂载以下主机目录,用于 Pod 中的容器能够共享宿主机的 Docker,即实现 Docker in Docker

    jenkins-slave-docker-in-docker

  6. 工作空间卷

    在容器云环境新增一个 PVC,取名为 jenkins-slave-work-claim(参考 jenkins-pv-pvc.yaml),其目的在于将动态 Slave 节点运行时生成的工作空间进行持久化。

    jenkins-slave-work-claim

    说明

    因 Pod Slave 每次执行完就会自动销毁,如果一个流水线周期中会有启动两个或多个 Pod 的情况,一般可将工作目录挂载到 PVC 上,实现 Pod 之间的数据共享。

  7. Pod Template 在被流水线调度创建时的内部情况

    流水线执行调度生成动态 Slave 节点时,如果指定的节点(即 Pod Template)的容器列表配置了多少容器信息,那么在节点创建时,就会启动多少容器。

    此示例中的 ci 这个 Pod Template,里边配置了 jnlp、git 、maven 以及 docker 这四个容器。当流水线执行时指定了此 Pod Template,运行期间节点内部将存在有四个容器,分别为 jnlp、git、maven 以及 docker。


# DevOps 集成云上 Jenkins

# 构建流水线配置示例

  1. 原子任务基本信息

    • 拉取 Git 代码

      devops-git-pull

    • Maven 构建

      devops-maven-build

    • 上传程序包

      devops-artifact-release-1

      devops-artifact-release-2

    • Docker 镜像构建并上传

      devops-docker-build-1

      devops-docker-build-2

  2. 原子任务节点及容器信息

    流水线运行只在一个Pod中运行,其节点和容器配置如下:

    devops-node-configuration

    说明

    此处节点对应 Jenkins 引擎里的 Pod Template 的标签名(Label),容器则对应 Jenkins 引擎里的 Pod Template 里容器列表中的某个容器名称

    devops-git-pull-container-configuration

    devops-maven-build-container-configuration

    devops-artifact-release-container-configuration

    devops-docker-build-container-configuration

上次更新: 2023-4-25 16:27:23