使用Jenkins整合Sonarqube/Gitlab/Harbor/Kubernetes的Demo工程

gitlab创建project

  1. 在gitlab创建一个Project, k8s-cicd-demo
  2. 将本地的ssh公钥添加到gitlab
bash 复制代码
cat ~/.ssh/id_rsa.pub

登录GitLab,点击用户图标 > Preferences > Access > SSH Keys > Add new key

将id_rsa.pub的内容输入到Key输入框,点击Add key

  1. clone 到本地
bash 复制代码
git clone http://{gitlab-host}:{gitlab-port}/root/k8s-cicd-demo.git'

源文件准备

pom.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.my.learning</groupId>
    <artifactId>k8s-cicd-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.9</version>
    </parent>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.sonarsource.scanner.maven</groupId>
                    <artifactId>sonar-maven-plugin</artifactId>
                    <version>4.0.0.4121</version>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Jenkinsfile

复制代码
pipeline {
    agent {
        kubernetes {
            label 'maven'
        }
    }

    parameters {
        gitParameter name: 'BRANCH_NAME', branch: '', branchFilter: '.*', defaultValue: 'origin/main', description: '请选择要发布的分支', quickFilterEnabled: false, selectedValue: 'NONE', tagFilter: '*', type: 'PT_BRANCH'
        string(name: 'TAG_NAME', defaultValue: 'snapshot', description: '标签名称,必须以 v 开头,例如:v1、v1.0.0')
    }

    environment {
	    REGISTRY = '{harbor-host}:{harbor-port}'   //harbor地址
	    DOCKER_CREDENTIAL_ID = 'harbor-user-pwd' //harbor凭证,对应jenkins创建凭证的id
	    GIT_REPO_URL = '{gitlab-host}:{gitlab-port}'    //gitlab地址
	    GIT_CREDENTIAL_ID = 'git-user-pwd'   //gitlab凭证,对应jenkins创建凭证的id
	    KUBECONFIG_CREDENTIAL_ID = '30629742-ddae-4c80-a3ad-5807ffc6ff5a'  //对应jenkins创建kubeconfig文件时的id
	    DOCKERHUB_NAMESPACE = 'wolfcode //镜像私服的命名空间
	    GITHUB_ACCOUNT = 'root'  //git账号
	    APP_NAME = 'demo-k8s'  //应用名称
	    SONAR_SERVER_URL='http://{sonarqube-host}:{sonarqube-port}'  //sonarqube地址
	    SONAR_CREDENTIAL_ID='sonarqube-token'  //jenkins创建的凭证
    }

    stages {

        stage('checkout scm') {
            steps {
                checkout scmGit(branches: [[name: "$BRANCH_NAME"]], extensions: [], userRemoteConfigs: [[credentialsId: "$GIT_CREDENTIAL_ID", url: 'http://{gitlab-host}:{gitlab-port}/root/k8s-cicd-demo.git']])
            }
        }

        stage('unit test') {
            steps {
                sh 'mvn clean test'
            }
        }

        stage('sonarqube analysis') {
            steps {
                withCredentials([string(credentialsId: "$SONAR_CREDENTIAL_ID", variable: 'SONAR_TOKEN')]) {
                    withSonarQubeEnv('sonarqube') {
                        sh 'mvn sonar:sonar -Dsonar.projectKey=$APP_NAME'
                    }
                }
                timeout(time: 1, unit: 'HOURS') {
                    waitForQualityGate abortPipeline: true
                }
            }
        }

        stage('build & push') {
            steps {
                sh 'mvn clean package -DskipTests'
                sh 'docker build -f Dockerfile -t $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BUILD_NUMBER .'
                withCredentials([usernamePassword(passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME', credentialsId: "$DOCKER_CREDENTIAL_ID",)]) {
                    sh 'echo "$DOCKER_PASSWORD" | docker login $REGISTRY -u "$DOCKER_USERNAME" --password-stdin'
                    sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BUILD_NUMBER'
                }
            }
        }

        stage('push latest') {
            steps {
                sh 'docker tag $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BUILD_NUMBER $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:latest'
                sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:latest'
            }
        }

        stage('deploy to dev') {
            steps {
                input(id: 'deploy-to-dev', message: 'deploy to dev?')
                sh '''
                    sed -i "s#REGISTRY#$REGISTRY#" deploy/cicd-demo-dev.yaml
                    sed -i "s#DOCKERHUB_NAMESPACE#$DOCKERHUB_NAMESPACE#" deploy/cicd-demo-dev.yaml
                    sed -i "s#APP_NAME#$APP_NAME#" deploy/cicd-demo-dev.yaml
                    sed -i "s#BUILD_NUMBER#$BUILD_NUMBER#" deploy/cicd-demo-dev.yaml
                    kubectl apply -f deploy/cicd-demo-dev.yaml
                '''
            }
        }
        stage('push with tag') {
            when {
                expression {
                    return params.TAG_NAME =~ /v.*/
                }
            }
            steps {
                input(id: 'release-image-with-tag', message: 'release image with tag?')
                withCredentials([usernamePassword(credentialsId: "$GIT_CREDENTIAL_ID", passwordVariable: 'GIT_PASSWORD', usernameVariable: 'GIT_USERNAME')]) {
                    sh 'git config --global user.email "liugang@wolfcode.cn" '
                    sh 'git config --global user.name "xiaoliu" '
                    sh 'git tag -a $TAG_NAME -m "$TAG_NAME" '
                    sh 'git push http://$GIT_USERNAME:$GIT_PASSWORD@$GIT_REPO_URL/$GIT_ACCOUNT/k8s-cicd-demo.git --tags --ipv4'
                }
                sh 'docker tag $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BUILD_NUMBER $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:$TAG_NAME'
                sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:$TAG_NAME'
            }
        }
        stage('deploy to production') {
            when {
                expression {
                    return params.TAG_NAME =~ /v.*/
                }
            }
            steps {
                input(id: 'deploy-to-production', message: 'deploy to production?')
                sh '''
                    sed -i "s#REGISTRY#$REGISTRY#" deploy/cicd-demo.yaml
                    sed -i "s#DOCKERHUB_NAMESPACE#$DOCKERHUB_NAMESPACE#" deploy/cicd-demo.yaml
                    sed -i "s#APP_NAME#$APP_NAME#" deploy/cicd-demo.yaml
                    sed -i "s#TAG_NAME#$TAG_NAME#" deploy/cicd-demo.yaml
	               kubectl apply -f deploy/cicd-demo.yaml
                '''
            }
        }
    }
}

Dockerfile

复制代码
## 基础镜像
FROM openjdk:21

## 作者
LABEL org.opencontainers.image.authors="myname"

## 定义参数

## 创建并进入工作目录
RUN mkdir -p /wolfcode
WORKDIR /wolfcode

## maven 插件构建时得到 buildArgs 种的值
COPY target/*.jar app.jar

## 设置 TZ 时区
## 设置 JAVA_OPTS 环境变量,可通过 docker run -e "JAVA_OPTS=" 进行覆盖
ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms256m -Xmx256m"

## 暴露端口
EXPOSE 8080

## 容器启动命令
## CMD 第一个参数之后的命令可以在运行时被替换
CMD java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar app.jar

cicd-demo-dev.yaml

yaml 复制代码
---
apiVersion: v1
kind: Namespace
metadata:
  name: k8s-cicd-dev
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: k8s-cicd-demo
    component: wolfcode-devops
    tier: backend
  name: k8s-cicd-demo
  namespace: k8s-cicd-dev
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  selector:
    matchLabels:
      app: k8s-cicd-demo
      component: wolfcode-devops
      tier: backend
  strategy:
    rollingUpdate:
      maxSurge: 100%
      maxUnavailable: 100%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: k8s-cicd-demo
        component: wolfcode-devops
        tier: backend
    spec:
      nodeName: master001
      tolerations: # 允许调度到master节点
        - key: node-role.kubernetes.io/control-plane # 控制平面节点
          effect: NoSchedule # 容忍该污点的影响NoSchedule
          operator: Exists # 该标签存在
      imagePullSecrets:
        - name: harbor-secret
      containers:
        - name: k8s-cicd-demo
          image: REGISTRY/DOCKERHUB_NAMESPACE/APP_NAME:SNAPSHOT-BUILD_NUMBER
          readinessProbe:
            httpGet:
              path: /users
              port: 8080
            initialDelaySeconds: 60
            timeoutSeconds: 10
            failureThreshold: 30
            periodSeconds: 5
          imagePullPolicy: Always
          ports:
            - containerPort: 8080
              protocol: TCP
          resources:
            limits:
              cpu: 300m
              memory: 600Mi
            requests:
              cpu: 100m
              memory: 100Mi
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: k8s-cicd-demo
    component: wolfcode-devops
  name: k8s-cicd-demo
  namespace: k8s-cicd-dev
spec:
  ports:
    - name: http
      port: 8080
      protocol: TCP
      targetPort: 8080
  selector:
    app: k8s-cicd-demo
    component: wolfcode-devops
    tier: backend
  sessionAffinity: None
  type: NodePort

cicd-demo.yaml

yaml 复制代码
---
apiVersion: v1
kind: Namespace
metadata:
  name: k8s-cicd
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: k8s-cicd-demo
    component: wolfcode-devops
    tier: backend
  name: k8s-cicd-demo
  namespace: k8s-cicd
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  selector:
    matchLabels:
      app: k8s-cicd-demo
      component: wolfcode-devops
      tier: backend
  strategy:
    rollingUpdate:
      maxSurge: 100%
      maxUnavailable: 100%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: k8s-cicd-demo
        component: wolfcode-devops
        tier: backend
    spec:
      nodeName: master001
      tolerations: # 允许调度到master节点
        - key: node-role.kubernetes.io/control-plane # 控制平面节点
          effect: NoSchedule # 容忍该污点的影响NoSchedule
          operator: Exists # 该标签存在
      imagePullSecrets:
        - name: harbor-secret
      containers:
        - name: k8s-cicd-demo
          image: REGISTRY/DOCKERHUB_NAMESPACE/APP_NAME:TAG_NAME
          readinessProbe:
            httpGet:
              path: /users
              port: 8080
            initialDelaySeconds: 60
            timeoutSeconds: 10
            failureThreshold: 30
            periodSeconds: 5
          imagePullPolicy: Always
          ports:
            - containerPort: 8080
              protocol: TCP
          resources:
            limits:
              cpu: 300m
              memory: 600Mi
            requests:
              cpu: 100m
              memory: 100Mi
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: k8s-cicd-demo
    component: wolfcode-devops
  name: k8s-cicd-demo
  namespace: k8s-cicd
spec:
  ports:
    - name: http
      port: 8080
      protocol: TCP
      targetPort: 8080
  selector:
    app: k8s-cicd-demo
    component: wolfcode-devops
    tier: backend
  sessionAffinity: None
  type: NodePort

K8sCicdDemoApplication.java

java 复制代码
package cn.wolfcode;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class K8sCicdDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(K8sCicdDemoApplication.class, args);
    }
}

UserController.java

java 复制代码
package cn.wolfcode.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("/users")
public class UserController {
    @GetMapping
    public String users(Integer age) {
        log.info("test:{}", age);
        return "<h1>all users: v1.0.0</h1>";
    }
}

完整结构如下

k8s-cicd-demo

├─ pom.xml

├─ Dockerfile

├─ Jenkinsfile

├─ deploy

│ │ └─cicd-demo.yaml

│ │ └─cicd-demo-dev.yaml

├─src

│ ├─main

│ │ ├─java

│ │ │ │ └─cn

│ │ │ │ │ └─wolfcode

│ │ │ │ │ │ └─K8sCicdDemoApplication.java

│ │ │ │ │ │ └─controller

│ │ │ │ │ │ │ └─UserController.java

│ │ └─resources

│ └─test

│ └─java

相关推荐
Patrick_Wilson1 小时前
Node.js SSR 内存治理:为什么 --max-old-space-size 不等于进程内存
kubernetes·node.js·v8
开发者联盟league1 小时前
使用k8s安装Jenkins
容器·kubernetes·jenkins
成为你的宁宁2 小时前
【基于 Prometheus Operator 实现 K8s 环境下 Redis Cluster 集群监控部署】
redis·kubernetes·prometheus
是一个Bug3 小时前
Docker 与 Kubernetes:从“集装箱”到“远洋舰队”
docker·容器·kubernetes
java_cj3 小时前
阅读 k8s 源码的准备工作
云原生·容器·kubernetes
开发者联盟league3 小时前
使用Jenkins整合Sonarqube/Gitlab/Harbor/Kubernetes实现CICD
kubernetes·gitlab·jenkins
zyl837214 小时前
前后端项目自动部署方案主流实现方案
ci/cd·gitlab·github
serve the people13 小时前
Elasticsearch(1) could you tell me how to use es if i am a beginner
大数据·elasticsearch·jenkins
鹤落晴春17 小时前
【K8s】Pod调度、configMaps
云原生·容器·kubernetes