Skip to content

CI/CD git基本操作 启动jenkins jenkins.maven 需要在gitlab上放上jenkins的公钥以便jenkins可以拉取gitlab的仓库 ! 配置全局变量 ! 配置mvn ...

CICD

git基本操作

git init                      //初始化 
git add main.cpp              //将某一个文件添加到暂存区 
git add .                     //将文件夹下的所有的文件添加到暂存区 
git commit -m ‘note‘          //将暂存区中的文件保存成为某一个版本 
git log                       //查看所有的版本日志 
git status                    //查看现在暂存区的状况 
git diff                      //查看现在文件与上一个提交-commit版本的区别 
git reset --hard HEAD^        //回到上一个版本 
git reset --hard XXXXX        //XXX为版本编号,回到某一个版本 
git pull origin master        //从主分支pull到本地 
git push -u origin master     //从本地push到主分支 
git pull                      //pull默认主分支 
git push                      //push默认主分支 ...
git checkout -b dev     // 创建dev分支,然后切换到dev分支
git checkout            // 命令加上-b参数表示创建并切换,相当于以下两条命令:
git branch dev git checkout dev
git branch              // 命令查看当前分支,
git branch              // 命令会列出所有分支,当前分支前面会标一个*号
git branch * dev   master
git add readme.txt git commit -m "branch test"  //  在dev分支上正常提交.

启动jenkins

nohup java -jar jenkins.war --httpPort=8080 &nohup java -jar jenkins.war --httpPort=8080 &

jenkins.maven

需要在gitlab上放上jenkins的公钥以便jenkins可以拉取gitlab的仓库

image-20250323114548139

配置全局变量

image-20250322220309535

配置mvn git jdk环境

mvn -version
which git 
which java    -->>   ll  /usr/bin/java

下载mvn插件能够让job构建一个maven项目

image-20250322220917348

image-20250322222318167

执行docker远程主机命令需要下载插件Publish Over SSH

image-20250322223005097

执行webhoob钩子需要下载插件Generic Webhook Trigger

image-20250322222731099

需要在gitlab上配置 搭配webhook

image-20250322223110245

image-20250322223331581

pipeline

pipeline {
    agent any
    tools {
        maven "mvn"   ##配置mvn环境 mvn是在配置变量里面写的名字
    }
    stages {
        stage('拉取仓库') {
            steps {
                git branch: 'slave', url: 'git@192.168.85.131:ceshi/test.git'
                echo '拉取成功'
            }
        }

      stage('mvn打包') {
         steps {
            sh '''cd /root/.jenkins/workspace/java-pipeline
               mvn clean package'''
               echo '打包完成'
            }
        }
        stage('docker执行') {
            steps {
               sshPublisher(publishers: [sshPublisherDesc(configName: 'docker-java', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '/root', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '**/*.jar'), sshTransfer(cleanRemote: false, excludes: '', execCommand: '''cd /root/root

docker stop java 
docker rm -f java
docker rmi java
docker build -t java .
docker run -d --name java -p 8081:8080 java''', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '/root', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '**/Dockerfile')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
                echo '执行成功'
            }
        }
    }
}

基于k8s流水线

需要让jenkins机器能够调用api

# scp ~/.kube/config  192.168.85.132:~/.kube/

gitlab的配置

# cat k8s/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{PACKAGE_NAME}}
  namespace: {{K8S_NAMESPACE}}
spec:
  replicas: {{K8S_REPLICAS}}
  selector:
    matchLabels:
      app: {{PACKAGE_NAME}}
  template:
    metadata:
      labels:
        app: {{PACKAGE_NAME}}
    spec:
      containers:
        - name: {{PACKAGE_NAME}}
          image: "{{IMAGE_NAME}}"
          imagePullPolicy: Always
          ports:
            - containerPort: 8080
# cat Dockerfile 
from openjdk
expose 8080
add ./target/simple-jar-project-1.0-SNAPSHOT.jar /root/
entrypoint ["java",  "-jar", "/root/simple-jar-project-1.0-SNAPSHOT.jar"]

# cat Jenkinsfile

pipeline {
    agent any

    tools {
        maven 'mvn' 
    } 
    parameters {
        // GitLab 分支选择,允许用户选择需要部署的分支
        string(name: 'GITLAB_BRANCH', defaultValue: 'slave', description: 'GitLab 分支名称')

        // Java 包名字,允许用户自定义包名
        string(name: 'PACKAGE_NAME', defaultValue: 'your-java-app', description: 'Java 包名字')

        // 版本号,允许用户自定义
        string(name: 'VERSION', defaultValue: '1.0.0', description: 'Java 包版本号')

        // 部署类型选择,用户选择 deploy 或 update
        choice(name: 'DEPLOY_TYPE', choices: ['deploy', 'update'], description: '选择部署或更新操作')

        // Docker Registry,允许用户指定 Docker 镜像仓库
        string(name: 'DOCKER_REGISTRY', defaultValue: '192.168.85.128', description: 'Docker 镜像仓库地址')

        // Kubernetes 部署命名空间,允许用户自定义
        string(name: 'K8S_NAMESPACE', defaultValue: 'default', description: 'Kubernetes 命名空间')

        // Kubernetes 部署副本数,用户可以自定义
        string(name: 'K8S_REPLICAS', defaultValue: '1', description: 'Kubernetes 部署副本数')

        // 服务暴露端口,允许用户指定
        string(name: 'SERVICE_PORT', defaultValue: '8080', description: '服务暴露端口')

        // 自定义 Kubernetes 部署的其他信息,比如镜像仓库、标签等
        string(name: 'K8S_DEPLOYMENT_FILE', defaultValue: 'k8s/deployment.yaml', description: 'Kubernetes 部署文件路径')
    }

    environment {
        // 构建 Docker 镜像标签
        IMAGE_NAME = "${params.DOCKER_REGISTRY}/nb/${params.PACKAGE_NAME}:${params.VERSION}"
        // Kubernetes 配置文件临时路径
        K8S_TEMP_FILE = "${WORKSPACE}/k8s-deployment-temp.yaml"
    }

    stages {
        stage('检出代码') {
            steps {
                script {
                    echo "正在从 GitLab 拉取分支 ${params.GITLAB_BRANCH} 的代码..."
                    git branch: "${params.GITLAB_BRANCH}", url: 'git@192.168.85.131:ceshi/test.git'
                }
            }
        }

        stage('构建 Java 应用') {
            steps {
                script {
                    echo "正在构建 Java 包 ${params.PACKAGE_NAME} 版本 ${params.VERSION}..."
                    sh "pwd && /usr/local/apache-maven-3.8.8/bin/mvn clean package -DskipTests -DartifactId=${params.PACKAGE_NAME} -Dversion=${params.VERSION}"
                }
            }
        }

        stage('构建 Docker 镜像') {
            steps {
                script {
                    echo "正在构建 Docker 镜像 ${env.IMAGE_NAME}..."
                    sh "docker build -t ${env.IMAGE_NAME} ."
                }
            }
        }

        stage('推送 Docker 镜像到镜像仓库') {
            steps {
                script {
                    echo "正在将 Docker 镜像 ${env.IMAGE_NAME} 推送到 ${params.DOCKER_REGISTRY}..."
                    sh "docker push ${env.IMAGE_NAME}"
                }
            }
        }

        stage('生成动态 Kubernetes 部署文件') {
            steps {
                script {
                    // 替换 Kubernetes 部署模板中的变量
                    echo "正在生成动态的 Kubernetes 部署文件..."

                    // 读取 Kubernetes 部署模板
                    def yamlTemplate = readFile("${params.K8S_DEPLOYMENT_FILE}")

                    // 使用 Groovy 的字符串替换功能,替换变量
                    def modifiedYaml = yamlTemplate.replace("{{IMAGE_NAME}}", env.IMAGE_NAME)
                                                  .replace("{{K8S_NAMESPACE}}", params.K8S_NAMESPACE)
                                                  .replace("{{K8S_REPLICAS}}", params.K8S_REPLICAS)
                                                  .replace("{{PACKAGE_NAME}}", params.PACKAGE_NAME)

                    // 写入临时文件
                    writeFile file: env.K8S_TEMP_FILE, text: modifiedYaml

                    echo "生成的 Kubernetes 部署文件路径: ${env.K8S_TEMP_FILE}"
                }
            }
        }

        stage('在 Kubernetes 上部署或更新') {
            steps {
                script {
                    echo "正在执行 Kubernetes 部署或更新..."

                    // 根据部署类型选择执行的操作
                    if (params.DEPLOY_TYPE == 'deploy') {
                        echo "正在将 ${params.PACKAGE_NAME} 版本 ${params.VERSION} 部署到 Kubernetes 命名空间 ${params.K8S_NAMESPACE}..."
                        // 执行 Kubernetes 部署,使用自定义的副本数和命名空间
                        sh """
                            kubectl apply -f ${env.K8S_TEMP_FILE} \
                            --namespace=${params.K8S_NAMESPACE}
                        """
                    } else if (params.DEPLOY_TYPE == 'update') {
                        echo "正在更新 Kubernetes 中的 ${params.PACKAGE_NAME} 版本 ${params.VERSION}..."
                        // 更新 Kubernetes 部署镜像
                        // 更新副本数
                        sh """
                            #  kubectl set image deployment/${params.PACKAGE_NAME} \
                            # ${params.PACKAGE_NAME}=${env.IMAGE_NAME} \
                            # --namespace=${params.K8S_NAMESPACE} --record \
                            # && \
                            # kubectl scale deployment ${params.PACKAGE_NAME} \
                            # --replicas=${params.K8S_REPLICAS} \
                            # --namespace=${params.K8S_NAMESPACE} --record 这样是分别记录 但是会有两个吧N本
                            kubectl apply -f  ${env.K8S_TEMP_FILE} --namespace=${params.K8S_NAMESPACE}
                          """

                    } else {
                        error "未知的部署类型: ${params.DEPLOY_TYPE}"
                    }
                }
            }
        }
        stage('创建 Kubernetes Service') {
            steps {
                script {
                    echo "正在创建 Kubernetes 服务 ${params.PACKAGE_NAME}..."
                    // 创建 Kubernetes 服务,将容器端口暴露出来
                    if (params.DEPLOY_TYPE == 'deploy') {
                    sh """
                        kubectl expose deployment ${params.PACKAGE_NAME} \
                        --type=NodePort \
                        --name=${params.PACKAGE_NAME}-svc \
                        --port=${params.SERVICE_PORT} \
                        --target-port=8080 \
                        --namespace=${params.K8S_NAMESPACE}
                    """
                    }
                }
            }
        }
    }

    post {
        success {
            echo "流水线执行成功!"
        }
        failure {
            echo "流水线执行失败!"
        }
    }
}

测试

1.在gitlab修改java代码

image-20250506190019992

2.在jenkins构建

image-20250506190530570

image-20250506190610011

就是把变量赋值到gitlab 的 k8s/deployment.yaml下 然后 写入到jenkins机器上 writeFile file: env.K8S_TEMP_FILE, text: modifiedYaml

3.构建

image-20250506191617139

有红的也不用慌 控制台有报错原因 找找原因即可

再看下k8s机器 pod有两个容器因为里面我注入了sidecar

image-20250506191806352

image-20250506191835889