朋友的真实操作流程,使用 Jenkins 和 Kubernetes 完成持续集成和持续部署,有搭建,有入门,手把手教学文档,干得拧不出水来,分享一波。

目录

安装 Jenkins

启动 Jenkins 容器

配置 Jenkins

实现 Java 应用持续集成和持续发布

Fork 和 Clone GitHub 示例仓库

在 Jenkins 中创建流水线

安装 K8S 插件

对接 K8S 集群

申请 K8S 凭据

配置 K8S 集群的对接

K8S pod template 配置

Jenkins pipeline 说明

Jenkins pipeline 入门

创建并运行 pipeline 

在 Slave 中运行 Pipeline

完整 pipeline 示例

克隆代码

maven 打包 

构建镜像 

推送镜像 ​​​​​​​

拉取镜像 ​​​​​​​

替换 YAML 文件变量 ​​​​​

部署

最终执行效果如下 


安装 Jenkins

启动 Jenkins 容器

docker run -d -u root -v /workspace/jenkins-home/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock -v "$HOME":/home -p 8080:8080 -p 50000:50000 jenkinsci/blueocean

参数

说明

-d

d 指 daemon,后台启动

-u

指定运行用户

-v

-v /workspace/jenkins-home:/var/jenkins_home

hostDir:containerDir

表示将容器中 jenkins_home 映射到宿主机 jenkins-home 目录

-p

-p 8080:8080

hostPort:containerPort

检查 Jenkins 服务状态

docker ps | grep jenkins

启动成功后,就可以通过 ip:port 在浏览器上访问了。ip 为 docker 所在机器的 ip, port 为 Jenkins 容器映射的宿主机端口

配置 Jenkins

Jenkins 启动成功后,需要执行一些快速的 "一次性" 步骤。当你第一次访问一个新的 Jenkins 实例时, 要求你使用自动生成的密码对其进行解锁。密码为 Jenkins 所在容器的 /var/jenkins_home/secrets/initialAdminPassword 的内容:

docker exec -it <jenkins_container> bash -c "cat /var/jenkins_home/secrets/initialAdminPassword"

或者用 K8S 命令 kubectl 

kubectl exec -it <jenkins_container> bash -c "cat /var/jenkins_home/secrets/initialAdminPassword"

在 Unlock Jenkins 页面, 粘贴该密码到 Administrator password 字段并点击 Continue。解锁 Jenkins 后,插件安装页面出现,点击 Install suggested plugins 即可。

这个过程会耗时一段时间。

创建第一个管理员用户,可以填写,也可以跳过,直接使用 admin 账户继续。

这边我选择了跳过,点击开始使用 Jenkins,就可以使用 Jenkins 了。

实现 Java 应用持续集成和持续发布

Fork 和 Clone GitHub 示例仓库

  1. 登录 GitHub 账号:https://github.com

  2. 上传代码到 GitHub 代码仓库中,或 Fork 到你的 GitHub 仓库中,演示代码 prometheus-test-demo,地址为 https://github.com/0820sdd/prometheus-test-demo

  3. 将你的 GitHub 账户中的 prometheus-test-demo 仓库 Clone 到本地机器:

  1. 打开一个终端/命令提示符,并且进入正确的目录路径: Mac OS 系统路径为 /Users/<your-username>/Documents/GitHub/ Linux 系统路径为/home/<your-username>/GitHub/ Windows 系统路径为 C:\Users\<your-username>\Documents\GitHub\  (推荐使用 Git bash 命令行,而不是通常的 Microsoft 命令提示符)

  2. 运行以下命令完成仓库的 clone:git clone https://github.com/YOUR-GITHUB-ACCOUNT-NAME/simple-java-maven-app 其中 YOUR-GITHUB-ACCOUNT-NAME 是你的 GitHub 账户的名称。

在 Jenkins 中创建流水线

登录 Jenkins,点击页面创建一个新任务。若是你无法看见该内容,点击左上方的新建 item。

为新建的流水线项目指定名称(例如 prometheus-test-demo),选择流水线,点击确定。

安装 K8S 插件

登录 Jenkins,系统管理→ 插件管理 → 搜索 kubernetes,选择第二个 Kubernetes,点击 安装,安装完成后重启 Jenkins 。

对接 K8S 集群

申请 K8S 凭据

因为 Jenkins 服务器在 kubernetes 集群之外,所以我们准备以下文件才能从外面连接到 kubernetes 集群。

登录 Jenkins,点击右上角「用户」 → 左下角「凭据」:

然后点击 Jenkins,选择全局凭据(Unrestricted)

添加凭据,类型选择 X.509 Client Certificate

  • Client Key:  .kube/config文件中 client-key 对应的 key 文件

  • Client Certificate:  .kube/config文件中 client-certificate 对应的 crt 或是 pem 文件

  • Server CA Certificate:.kube/config 文件中 certificate-authority 对应的 crt 或是 pem 文件,K8S 的最高权限证书

  • ID:可不填写,默认会自动生成一串字符串,也可以自行设置

  • 描述:描述下这个凭据的作用,比如这个可以写 对接 K8S 集群凭据

填写完毕,点击确定。

配置 K8S 集群的对接

登录 Jenkins,点击 系统管理 → 系统配置 → 滑动到页面最下面

点击 a separate configuration page:

  • Kubernetes 地址:kubernetes服务地址,也就是 apiserver 的地址,一般是master 节点 NodeIP+6443 端口

  • Kubernetes 服务证书 key:kube-ca.crt 文件的内容

  • 凭据:刚才创建的 certificate 凭据

  • Jenkins 地址:Agent 连接 Jenkins Master 的地址

其他都使用默认配置,点击连接测试,连接测试成功,点击 Save 存储

K8S pod template 配置

Jenkins 的 kubernetes-plugin 在执行构建时会在 kubernetes 集群中自动创建一个 Pod,并在 Pod 内部创建一个名为 jnlp 的容器,该容器会连接 Jenkins 并运行 Agent 程序,形成一个 Jenkins 的 Master 和 Slave 架构,然后 Slave 会执行构建脚本进行构建,但如果构建内容是要创建 Docker Image 就要实现 Docker In Docker 方案(在 Docker 里运行 Docker),如果要在集群集群内部进行部署操作可以使用 kubectl 执行命令,要解决 kubectl 的安装和权限分配问题。

为了方便配置一个 Pod Templates,在配置 kubernetes 连接内容的下面,这里的模板只是模板(与类一样使用时还要实例化过程),名称和标签列表不要以为是 Pod 的 name 和 label,这里的名称和标签列表只是 Jenkins 查找选择模板时使用的,Jenkins 自动创建 Pod 的 name 是项目名称+随机字母的组合,所以我们填写 jenkins-slave,命名空间填写对应的 namespace。

这边要注意,添加 2 个 container,第一个,Pod 内添加一个容器名称是 jnlp,Docker 镜像填写:jenkins/jnlp-slave:4.3-7,后面的使用默认的即可,然后在添加一个 container,容器名称是 jnlp-kubectl,是这个容器里面有 kubectl 的命令,镜像名称填写 harbor.edu.cn/library/centos-docker-kubectl:v1.0,下面增加了 Host Path Volume:/var/run/docker.sock、/root/.kube/、/etc/kubernetes/pki,这边便是为了 jenkins-slave 下有足够的权限可以执行 docker 及 kubectl 部署到 k8s 集群的权限,因为 jenkins-slave pod 有可能会被调度到任一 worker 节点,所以所有的 worker 节点上都必须有 /root/.kube/、/etc/kubernetes/pki,配置好之后点击保存。

Jenkins pipeline 说明

Pipeline,简单来说,就是一套运行在 Jenkins 上的工作流框架,将原来独立运行于单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂流程编排和可视化的工作。

Jenkins Pipeline 有几个核心概念:

  • Node:节点,一个 Node 就是一个 Jenkins 节点,Master 或者 Agent,是执行 Step 的具体运行环境,比如我们之前动态运行的 Jenkins Slave 就是一个 Node 节点

  • Stage:阶段,一个 Pipeline 可以划分为若干个 Stage,每个 Stage 代表一组操作,比如:Build、Test、Deploy,Stage 是一个逻辑分组的概念,可以跨多个 Node

  • Step:步骤,Step 是最基本的操作单元,可以是打印一句话,也可以是构建一个 Docker 镜像,由各类 Jenkins 插件提供,比如命令:sh 'make',就相当于我们平时 shell 终端中执行 make 命令一样。

Pipeline的使用:

  • Pipeline 脚本是由 Groovy 语言实现的

  • Pipeline 支持两种语法:Declarative(声明式)和 Scripted Pipeline(脚本式)语法

  • Pipeline 也有两种创建方法:可以直接在 Jenkins 的 Web UI 界面中输入脚本;也可以通过创建一个 Jenkinsfile 脚本文件放入项目源码库中

  • 一般我们都推荐在 Jenkins 中直接从源代码控制(SCMD)中直接载入 Jenkinsfile Pipeline 这种方法,但是本次为了更直观的展示,我们在 Web UI 界面中输入脚本

Jenkins pipeline 入门

创建并运行 pipeline 

  • 进入到 Jenkins 首页,点击项目 prometheus-test-demo,点击左侧 配置

  • 点击页面顶部的 Pipeline 选项卡,向下滚动到 Pipeline 部分

  • 在定义域中,选择 Pipeline script 选项

node {  stage('Clone') {    echo "1.Clone Stage"  }  stage('Test') {    echo "2.Test Stage"  }  stage('Build') {    echo "3.Build Stage"  }  stage('Deploy') {    echo "4. Deploy Stage"  }}

点击保存,切换到 Jenkins 页面,点击左侧的 打开 Blue Ocean 进入Jenkins的Blue Ocean界面,进入到 相应的项目下,点击 运行 。

也可以在 Jenkins prometheus-test-demo 项目下,点击左侧菜单 立即构建,然后点击正在构建的任务,就可以看到 Console Output:

在 Slave 中运行 Pipeline

上面对 Jenkins 的 Pipeline 做了简单的测试,但是其并未在我们的 Slave中运行,如果要在 Slave 中运行,其就要使用我们在对接 K8S 集群时 Pod Template 指定的标签列表 ,点击进 prometheus-test-demo 项目,点击左侧菜单 配置,进入到 pipeline scripts 部分,修改 pipeline scripts 如下:

node('slave') {  stage('Clone') {    echo "1.Clone Stage"  }  stage('Test') {    echo "2.Test Stage"  }  stage('Build') {    echo "3.Build Stage"  }  stage('Deploy') {    echo "4. Deploy Stage"  }}

点击立即构建,同时可以登录到k8s集群,使用 kubectl get po -w 可以看到 jenkins-slave pod 的生命周期,就是我们开始构建这个任务,选择了使用 jenkins slave,所以在执行过程中jenkins-slave就会自动创建,任务执行完成,jenkins-slave 对应的pod会自动回收:

在构建日志里我们也可以看到 jenkins 启动了 jenkins-slave-dj3vc pod 进行这个任务的执行,也和上面的 pod 名称对应起来了。

完整 pipeline 示例

部署应用的流程如下:

  • 拉取 Github 代码

  • maven 打包

  • 编写 Dockerfile

  • 构建打包 Docker 镜像

  • 推送 Docker 镜像到仓库

  • 编写 Kubernetes YAML 文件

  • 更改 YAML 文件中 Docker 镜像 TAG

  • 利用 kubectl 工具部署应用

最终的 Pipeline 脚本如下:

pipeline {
    agent none
    stages {
        stage('Clone Code') {
            agent {
                label 'master'
            }
            steps {
                echo "1.Git Clone Code"
                git url: "https://github.com/0820sdd/prometheus-test-demo.git"
            }
        }
        stage('Maven Build') {
            agent {
                docker {
                    image 'maven:latest'
                    args '-v /root/.m2:/root/.m2'
                }
            }
            steps {
                echo "2.Maven Build Stage"
                sh 'mvn -B clean package -Dmaven.test.skip=true'
            }
        }
        stage('Image Build') {
            agent {
                label 'master'
            }
            steps {
            echo "3.Image Build Stage"
            sh 'docker build -f Dockerfile --build-arg jar_name=target/prometheus-test-demo-0.0.1-SNAPSHOT.jar -t prometheus-test-demo:${BUILD_ID} . '
            sh 'docker tag  prometheus-test-demo:${BUILD_ID}  harbor.edu.cn/library/prometheus-test-demo:${BUILD_ID}'
            }
        }
        stage('Push') {
            agent {
                label 'master'
            }
            steps {
            echo "4.Push Docker Image Stage"
            sh "docker login --username=admin harbor.edu.cn -p Harbor12345"
            sh "docker push harbor.edu.cn/library/prometheus-test-demo:${BUILD_ID}"
            }
        }
    }
}
 
node('slave') {
    container('jnlp-kubectl') {
        
        stage('Clone YAML') {
        echo "5. Git Clone YAML To Slave"
        git url: "https://github.com/0820sdd/prometheus-test-demo.git"
        }
        
        stage('YAML') {
        echo "6. Change YAML File Stage"
        sh 'sed -i "s#{VERSION}#${BUILD_ID}#g" ./jenkins/scripts/prometheus-test-demo.yaml'
        }
    
        stage('Deploy') {
        echo "7. Deploy To K8s Stage"
        sh 'kubectl apply -f ./jenkins/scripts/prometheus-test-demo.yaml'
        }
    }
}

注意,prometheus-test-demo.yaml 可放在 GitHub 的 prometheus-test-demo 仓库里,也可以另外新建一个仓库专门放 YAML 文件。

下面我们分解讲下上面过程的具体含义:

克隆代码​​​​​​​

        stage('Clone to master') {            agent {                label 'master'            }            steps {                echo "1.Git Clone Stage"                git url: "https://github.com/0820sdd/prometheus-test-demo.git"            }        }

这步就是从 GitHub 上拉取代码,注意这边的 GitHub 仓库仓库比如是 公开的,因为 private 的需要各种权限配置,Jenkins 必须有一个公网 IP 或者是公网域名,但因资源问题,这部分暂时没有办法实现。注意,这边 agent 里面指定运行环境,选择了 master,即是这个步骤在 Jenkins master节点执行。

maven 打包 ​​​​​​​

        stage('Maven Build') {            agent {                docker {                    image 'maven:latest'                    args '-v /root/.m2:/root/.m2'                }            }            steps {                echo "2.Maven Build Stage"                sh 'mvn -B clean package -Dmaven.test.skip=true'            }        }

maven 构建,我们指定了 maven 打包的 agent 是在 Jenkins 所在节点另起一个 docker 容器,容器的 image 为 maven:latest,并且使用 -v 参数把本地的 /root/.m2 挂载到 容器的 /root/.m2  目录下,下面 steps 的步骤即是在这个 maven 容器里面的具体操作:mvn -B clean package -Dmaven.test.skip=true。

构建镜像 ​​​​​​​

stage('Image Build') {
            agent {
                label 'master'
            }
            steps {
            echo "3.Image Build Stage"
            sh 'docker build -f Dockerfile --build-arg jar_name=target/prometheus-test-demo-0.0.1-SNAPSHOT.jar -t prometheus-test-demo:${BUILD_ID} . '
            sh 'docker tag  prometheus-test-demo:${BUILD_ID}  harbor.edu.cn/library/prometheus-test-demo:${BUILD_ID}'
            }
        }

maven 构建成功,下一步就是使用 maven build 生成的 prometheus-test-demo-0.0.1-SNAPSHOT.jar 包进行 docker build,docker build 的具体命令有2条 bash 命令 组成,第一步 docker build 使用 -f 指定了 Dockerfile 的文件,使用 --build-arg 参数指定了一些参数,比如上面指定了 jar_name 是 target/prometheus-test-demo-0.0.1-SNAPSHOT.jar,最后使用 -t 参数指定了 docker  build 的 image 的名称及版本号。第二步就是 使用 docker tag 命令把上一步 docker build 完成的镜像 打 tag 为 harbor.edu.cn/library/prometheus-test-demo:${BUILD_ID},这步打 tag 的步骤是为了上传到  harbor 镜像仓库,可以随时使用。

推送镜像 

stage('Push') {
            agent {
                label 'master'
            }
            steps {
            echo "4.Push Docker Image Stage"
            sh "docker login --username=admin harbor.edu.cn -p Harbor12345"
            sh "docker push harbor.edu.cn/library/prometheus-test-demo:${BUILD_ID}"
            }
        }

镜像 build 完成,就可以使用 docker push 命令推送到 harbor.edu.cn 镜像仓库。

拉取镜像 ​​​​​​​

node('slave') {
    container('jnlp-kubectl') {
        
        stage('Clone YAML') {
        echo "5. Git Clone YAML To Slave"
        git url: "https://github.com/0820sdd/prometheus-test-demo.git"
        }
     }
  }

现在镜像已经打包完成,并推送到了镜像仓库,后面我们所要做的就是拉取 k8s 编排文件,这一步和第一步的 拉取代码实际是一样的,只不过上面的拉取代码是为了 build image,这一步是为了进行部署到 K8S。

注意:这边指定了运行此步骤的节点是在 Jenkins 的 slave 节点下的 jnlp-kubectl container 下,这个 slave 是指在配置 对接 K8S 集群时,在 Pod Template 下指定的 标签列表的名称,必须与这个名称一致,不然 jenkins 执行过程中就会报找不到对应的 label 。还有这边指定了 jnlp-kubectl container ,这是因为 jnlp-kubectl container下有 kubectl 命令,且配置 对接 k8s 集群时,指定了把宿主机的 /root/.kube  /etc/kubernetes/pki 目录分别挂载到 container 的 /root/.kube  /etc/kubernetes/pki目录下,这边就是 jnlp-kubectl container 可以访问 K8S 集群的原因。

替换 YAML 文件变量 ​​​​​

stage('YAML') {
        echo "6. Change YAML File Stage"
        sh 'sed -i "s#{VERSION}#${BUILD_ID}#g" ./jenkins/scripts/prometheus-test-demo.yaml'
        }

yaml文件拉取完毕,替换其中的变量。

部署

stage('Deploy') {
            echo "5. Deploy To K8s Stage"
            sh 'kubectl apply -f ./jenkins/scripts/prometheus-test-demo.yaml -n default'
        }

使用 kubectl 命令部署 prometheus-test-demo 应用到 K8S 集群。

最终执行效果如下 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐