Skip to content

1. Jenkins部署

1.1 基于k8s部署

1.1.1 创建命名空间

bash
kubectl create namespace devops
kubectl create namespace devops

1.1.2 创建RABC

1.jenkins-rbac.yaml

yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins-sa
  namespace: devops

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: jenkins-cr
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"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: jenkins-crd
roleRef:
  kind: ClusterRole
  name: jenkins-cr
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: jenkins-sa
  namespace: devops
apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins-sa
  namespace: devops

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: jenkins-cr
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"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: jenkins-crd
roleRef:
  kind: ClusterRole
  name: jenkins-cr
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: jenkins-sa
  namespace: devops
  • 执行
bash
kubectl apply -f 1.jenkins-rbac.yaml
kubectl apply -f 1.jenkins-rbac.yaml

1.1.3 创建存储

2.jenkins-pvc-nfs.yaml

yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: jenkins-pvc
  namespace: devops
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: "nfs-provisioner-storage"
  resources:
    requests:
      storage: 5Gi #根据线上环境修改
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: jenkins-pvc
  namespace: devops
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: "nfs-provisioner-storage"
  resources:
    requests:
      storage: 5Gi #根据线上环境修改
  • 执行
bash
kubectl apply -f 2.jenkins-pvc-nfs.yaml
kubectl apply -f 2.jenkins-pvc-nfs.yaml

1.1.4 创建svc

3.jenkins-deploy-svc.yaml

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-sa
      containers:
      - name: jenkins
        image: registry.cn-zhangjiakou.aliyuncs.com/hsuing/jenkins:2.452.3-lts
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          name: web
          protocol: TCP
        - containerPort: 50000
          name: agent
          protocol: TCP
        resources:
          limits:
            cpu: 1000m
            memory: 1Gi
          requests:
            cpu: 500m
            memory: 1Gi
        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
          mountPath: /var/jenkins_home
        env:
          - name: JAVA_OPTS
            value: -XshowSettings:vm -Dhudson.slaves.NodeProvisioner.initialDelay=0 -Dhudson.slaves.NodeProvisioner.MARGIN=50 -Duser.timezone=Asia/Shanghai -Dhudson.slaves.NodeProvisioner.MARGIN0=0.85
      securityContext:
        #ifsGroup: 1000
        runAsUser: 0
      volumes:
      - name: jenkinshome
        persistentVolumeClaim:
          claimName: jenkins-pvc

---
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: apps/v1
kind: Deployment
metadata:
  name: jenkins
  namespace: devops
spec:
  selector:
    matchLabels:
      app: jenkins
  template:
    metadata:
      labels:
        app: jenkins
    spec:
      terminationGracePeriodSeconds: 10
      serviceAccount: jenkins-sa
      containers:
      - name: jenkins
        image: registry.cn-zhangjiakou.aliyuncs.com/hsuing/jenkins:2.452.3-lts
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          name: web
          protocol: TCP
        - containerPort: 50000
          name: agent
          protocol: TCP
        resources:
          limits:
            cpu: 1000m
            memory: 1Gi
          requests:
            cpu: 500m
            memory: 1Gi
        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
          mountPath: /var/jenkins_home
        env:
          - name: JAVA_OPTS
            value: -XshowSettings:vm -Dhudson.slaves.NodeProvisioner.initialDelay=0 -Dhudson.slaves.NodeProvisioner.MARGIN=50 -Duser.timezone=Asia/Shanghai -Dhudson.slaves.NodeProvisioner.MARGIN0=0.85
      securityContext:
        #ifsGroup: 1000
        runAsUser: 0
      volumes:
      - name: jenkinshome
        persistentVolumeClaim:
          claimName: jenkins-pvc

---
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
  • 执行
bash
kubectl apply -f 3.jenkins-deploy-svc.yaml
kubectl apply -f 3.jenkins-deploy-svc.yaml

参数介绍:

默认情况下,Jenkins生成代理是保守的。

例如,如果队列中有两个构建,它不会立即生成两个执行器。它将生成一个执行器,并等待某个时间释放第一个执行器,然后再决定生成第二个执行器。Jenkins确保它生成的每个执行器都得到了最大限度的利用。

如果你想覆盖这个行为,并生成一个为每个构建队列不等待的执行器,所以在Jenkins启动时候添加这些参数:

  • -Dhudson.slaves.NodeProvisioner.initialDelay=0
  • -Dhudson.slaves.NodeProvisioner.MARGIN=50
  • -Dhudson.slaves.NodeProvisioner.MARGIN0=0.85

1.1.5 创建ingress

4.jenkins-ing.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: jenkins-ingress
  namespace: devops
spec:
  ingressClassName: nginx
  rules:
  - host: jenkins.ikubernetes.net
    http:
      paths:
      - path: /
        pathType: ImplementationSpecific
        backend:
          service:
            name: jenkins
            port:
              number: 8080
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: jenkins-ingress
  namespace: devops
spec:
  ingressClassName: nginx
  rules:
  - host: jenkins.ikubernetes.net
    http:
      paths:
      - path: /
        pathType: ImplementationSpecific
        backend:
          service:
            name: jenkins
            port:
              number: 8080
  • 执行
bash
kubectl apply -f 4.jenkins-ing.yaml
kubectl apply -f 4.jenkins-ing.yaml

1.1.6 访问

image-20240731150102546

  • 查看密码
bash
kubectl logs jenkins-6b59fcc49-4dwnc -n devops
kubectl logs jenkins-6b59fcc49-4dwnc -n devops

2. Jenkins Slave部署

2.0 Jenkins Master/Slave架构

k8s+jenkins+gitlab+harbor实现自动化部署应用至k8s集群

基于k8s拉起的服务,实际上都是以Pod形式存在的,而Pod是个容器组, 最终服务实际是以Pod内的Container来支撑运行的。那么针对Slave的应用场景, Container应该如何设计?

  • Jenkins-Master在构建Job的时候,Kubernetes会创建Jenkins-Slave的Pod来完成 Job的构建
  • 我们选择运行Jenkins-Slave的镜像为官方推荐镜像:jenkins/inbound-agent:latest,但是这个镜像里面并没有Maven 环境,为了方便使用,我们需要自定义一个新的镜像

这里我们使用docker进行slave的构建,Dockerfile

yaml
#FROM jenkins/jnlp-slave:latest
#FROM jenkins/jnlp-slave:4.13.3-1-jdk11
#
FROM registry.cn-zhangjiakou.aliyuncs.com/hsuing/inbound-agent:latest-jdk11

MAINTAINER han

# 切换到 root 账户进行操作
USER root

# 安装 maven
COPY apache-maven-3.3.9-bin.tar.gz .

RUN tar -zxf apache-maven-3.3.9-bin.tar.gz && \
    mv apache-maven-3.3.9 /usr/local && \
    rm -f apache-maven-3.3.9-bin.tar.gz && \
    ln -s /usr/local/apache-maven-3.3.9/bin/mvn /usr/bin/mvn && \
    ln -s /usr/local/apache-maven-3.3.9 /usr/local/apache-maven && \
    mkdir -p /usr/local/apache-maven/repo

COPY settings.xml /usr/local/apache-maven/conf/settings.xml

USER jenkins
#FROM jenkins/jnlp-slave:latest
#FROM jenkins/jnlp-slave:4.13.3-1-jdk11
#
FROM registry.cn-zhangjiakou.aliyuncs.com/hsuing/inbound-agent:latest-jdk11

MAINTAINER han

# 切换到 root 账户进行操作
USER root

# 安装 maven
COPY apache-maven-3.3.9-bin.tar.gz .

RUN tar -zxf apache-maven-3.3.9-bin.tar.gz && \
    mv apache-maven-3.3.9 /usr/local && \
    rm -f apache-maven-3.3.9-bin.tar.gz && \
    ln -s /usr/local/apache-maven-3.3.9/bin/mvn /usr/bin/mvn && \
    ln -s /usr/local/apache-maven-3.3.9 /usr/local/apache-maven && \
    mkdir -p /usr/local/apache-maven/repo

COPY settings.xml /usr/local/apache-maven/conf/settings.xml

USER jenkins

❌ 注意

这里的jdk一定的和jenkins中的jdk保持一致,否则会出现通信问题

  • 构建镜像
bash
docker build -t registry.cn-zhangjiakou.aliyuncs.com/hsuing/jenkins-slave-maven:v1 .
docker build -t registry.cn-zhangjiakou.aliyuncs.com/hsuing/jenkins-slave-maven:v1 .
  • 上传镜像
bash
git push registry.cn-zhangjiakou.aliyuncs.com/hsuing/jenkins-slave-maven:v1
git push registry.cn-zhangjiakou.aliyuncs.com/hsuing/jenkins-slave-maven:v1

为了不侵入宿主机Node上的docker服务,那么目前最佳的思路是要引入Docker in Docker技术来完成:

bash
docker tag docker:stable registry.cn-zhangjiakou.aliyuncs.com/hsuing/docker:stable
docker tag docker:stable registry.cn-zhangjiakou.aliyuncs.com/hsuing/docker:stable

2.1 原理

当 Jenkins Master 接受到 Build 请求时,会根据配置的 Label 动态创建一个运行在 Pod 中的 Jenkins Slave 并注册到 Master 上,当运行完 Job 后,这个 Slave 会被注销并且这个 Pod 也会自动删除,恢复到最初状态。

2.2 优势

  • 负载均衡:Master-Slave模式让Jenkins可以在多台机器中分布任务,从而提高Jenkins处理任务的能力。
  • 故障容错:Master-Slave模式在Jenkins系统出现故障时能够提供更好的支持。
  • 扩展性:使用Master-Slave模式可以帮助Jenkins系统轻松扩展。
  • 分布式构建:在Master-Slave模式下,Jenkins可以在多个Slave节点运行不同的任务,从而实现分布式构建。
  • 安全性:Master-Slave模式可以提高Jenkins系统的安全性。

2.3 测试验证

yaml
def git_address = "http://house.freehan.ink/root/springdemo.git" 
def git_auth = "731f32c4-0a6d-4dca-989f-50b7cdc0c85c"

//创建一个Pod的模板,label为jenkins-slave
podTemplate(label: 'jenkins-slave', cloud: 'kubernetes', containers: [ 
    containerTemplate(
        name: 'jnlp',
        image: "registry.cn-zhangjiakou.aliyuncs.com/hsuing/jenkins-slave-maven:v1"
    )
  ]
)
{
    //引用jenkins-slave的pod模块来构建Jenkins-Slave的pod 
    node("jenkins-slave"){
        stage('拉取代码'){
            checkout([$class: 'GitSCM', branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_address}"]]])
        }
    }
}
def git_address = "http://house.freehan.ink/root/springdemo.git" 
def git_auth = "731f32c4-0a6d-4dca-989f-50b7cdc0c85c"

//创建一个Pod的模板,label为jenkins-slave
podTemplate(label: 'jenkins-slave', cloud: 'kubernetes', containers: [ 
    containerTemplate(
        name: 'jnlp',
        image: "registry.cn-zhangjiakou.aliyuncs.com/hsuing/jenkins-slave-maven:v1"
    )
  ]
)
{
    //引用jenkins-slave的pod模块来构建Jenkins-Slave的pod 
    node("jenkins-slave"){
        stage('拉取代码'){
            checkout([$class: 'GitSCM', branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_address}"]]])
        }
    }
}

731f32c4-0a6d-4dca-989f-50b7cdc0c85c 这个是当时创建凭证时创建出来的

  • 效果

image-20240805115754818

bash
#会产生一个slave的pod进行编译,编译完自动销毁这个pod
[root@kube-master jenkins]# kubectl get pod |grep jenkins
jenkins-slave-wwd15-qkbv3                 1/1     Running   0                9s
#会产生一个slave的pod进行编译,编译完自动销毁这个pod
[root@kube-master jenkins]# kubectl get pod |grep jenkins
jenkins-slave-wwd15-qkbv3                 1/1     Running   0                9s

3. jenkins加速

bash
cd /data/nfs/pv01/devops/jenkins-pvc/updates
sed -i 's#http://updates.jenkins-ci.org/download#https://mirrors.tuna.tsinghua.edu.cn/jenkins#g;s#http://www.google.com#https://www.baidu.com#g' default.json
cd /data/nfs/pv01/devops/jenkins-pvc/updates
sed -i 's#http://updates.jenkins-ci.org/download#https://mirrors.tuna.tsinghua.edu.cn/jenkins#g;s#http://www.google.com#https://www.baidu.com#g' default.json

4. jenkins界面重启

  • 安全重启:http://[jenkins-server]/safeRestart
  • 立即重启:http://[jenkins-server]/restart

5. jenkins关闭更新

bash
忽略Jenkins系统警告 转到Manage Jenkins => Configure System => Administrative monitors configuration,不勾选 Jenkins Update Notification

忽略插件升级或安全警告,转到 Manage Jenkins => Configure Global Security => Hidden security warnings,不勾选插件警告
忽略Jenkins系统警告 转到Manage Jenkins => Configure System => Administrative monitors configuration,不勾选 Jenkins Update Notification

忽略插件升级或安全警告,转到 Manage Jenkins => Configure Global Security => Hidden security warnings,不勾选插件警告

6. helm部署Jenkins

https://github.com/civo/kubernetes-marketplace/blob/master/jenkins/install.sh