基于Kubernetes、Docker、Helm、Jenkins的CI/CD实践,对于前文Jenkins-pipeline-Docker 实现CI/CD 的补充扩展

Helm

Helm是Kubernetes生态系统中的一个包管理工具;Helm使用的包格式称为 charts,chart就是一个描述Kubernetes相关资源的文件集合。

Kubernetes应用部署面临的一些问题

kubernetes提供了基于容器的应用集群管理,容器编排,路由网关、水平扩展、监控、备份、灾难恢复等运维功能。用户通过使用Kubernetes API对象来描述应用程序规格,如Pod,Service,Volume,Namespace,ReplicaSet,Deployment,Job…;而对这些对象的操作都需要写入到yaml文件通过kubectl进行部署;这时就会遇到如下的几个问题:

  • 如何对kubernetes应用配置文件进行管理
  • 如何把一套的相关配置文件作为一个应用进行管理
  • 如何分发和重用Kubernetes的应用配置

这时候就可以引进Helm之类的包管理工具解决如上问题

Helm提供了什么功能

对于开发者而言,可以通过Helm打包应用,管理应用依赖关系,管理应用版本并发布应用到软件仓库;Helm提供了Kubernetes上的软件部署,删除,升级,回滚应用的功能。

Helm相关组件

  • Helm Client: Kubernetes应用打包工具。
  • Tiller: Helm服务端,部署于Kubernetes集群中,用于接收处理Helm的相关命令(Helm3中将要被移除,改为从Kubernetes API server获取信息,在Helm Client处理并在Kubernetes中存储安装记录)。
  • Chart: Helm的打包格式,描述Kubernetes相关资源的文件集合。
  • Repoistory: Helm的软件仓库。

图片

相关内容可以参考helm官方文档:https://helm.sh/zh/docs

Kubernetes Helm Jenkins CI/CD流程

准备

  • 一个安装了Tiller的kubernetes集群
  • 部署服务器,安装配置了Helm、Docker、Kubectl、Jenkins、Git
  • 代码托管服务,如Gitlab、Github
  • Docker Registry

基本流程

image

  1. 开发人员提交代码到Git仓库
  2. 运维人员触发Jenkins deploy任务,拉取代码进行Docker镜像打包,推送到远程仓库
  3. Jenkins使用 Helm 更新 Release到Kubernetes集群中

实践

项目

本次实践的项目是一个简单的Spring Boot 后端服务

仓库地址为:https://github.com/ChinaLHR/shovel-kubernetes-helm-devops

项目目录如下:

├── Jenkinsfile (Jenkins Pipeline Script)
├── Makefile (打包构建相关markfile)
├── README.md
├── chart (chart文件夹)
│   ├── Chart.yaml
│   ├── templates
│   │   ├── NOTES.txt
│   │   ├── _helpers.tpl
│   │   ├── configmap.yaml
│   │   ├── deployment.yaml
│   │   ├── service.yaml
│   │   ├── serviceaccount.yaml
│   │   └── tests
│   └── values.yaml
├── package.Dockerfile
├── pom.xml
├── release.Dockerfile
├── script (运行脚本)
│   └── bin
│       └── deploy.sh
└── src	(项目源码)
    ├── main
    │   ├── java
    │   └── resources
    └── test
        └── java

Jenkins Pipeline

  • Jenkins流水线项目配置

新增一个流水线项目,配置Pipeline from SCM,配置对应的参数BRANCH

image
image

  • 代码拉取

这里使用Jenkins Checkout插件进行Git代码拉取

stage('Clone target repo') {
             checkout([$class: 'GitSCM', branches: [[name: branch]],
             doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [],
             userRemoteConfigs: [[credentialsId: 'deploy', url: 'https://gitee.com/***.git']]])
        }
  • 代码编译打包-Docker镜像构建

这里使用Docker多阶段构建,第一阶段使用maven:3-jdk-8基础镜像对项目进行打包,第二阶段将第一阶段生成的jar与项目的script部署脚本添加到镜像中进行镜像打包。

最后编写makefile,使用make命令进行构建打包镜像、项目打包操作、构建项目镜像、推送项目镜像到远程Docker仓库的操作。

具体可以参考项目对应package.Dockerfilerelease.DockerfileMakefiledeploy.sh文件;相关pipeline script如下:

stage('Build package') {
            sh "make build-package-image package-image=${packageImage}"
            sh "make package package-image=${packageImage}"
}

stage('Build release') {
            sh "make build-release-image release-image=${releaseImage}"
}

stage('Push release image to registry') {
						withDockerRegistry(credentialsId: 'docker-user', url: 'https://registry.cn-hangzhou.aliyuncs.com') {
                sh "docker push ${releaseImage}"
            }
}
  • Helm Chart更新 Release到Kubernetes集群中

初始化Helm Chart:

helm create shovel
mv shovel chart
# 删除非必要文件
cd chart-copy/templates && rm hpa.yaml && rm ingress.yaml

修改Chart配置文件:

# values.yaml文件
# 修改镜像image相关配置,去除ingress相关配置,增加自定义配置如下:
env:
  app:
    port: 8088
    name: shovel-server-app

# templates/deployment.yaml
# 修改containers下的configMap、ports、livenessProbe标签配置
containers:
        - name: {{ .Chart.Name }}
          securityContext:
            {{- toYaml .Values.securityContext | nindent 12 }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          envFrom:
            - configMapRef:
                name: {{ include "shovel.fullname" . }}
          ports:
            - name: http
              containerPort: 8088
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /ping
              port: http
          readinessProbe:
            httpGet:
              path: /ping
              port: http
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
            
# 添加templates/configmap.yaml设置应用的环境变量
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "shovel.fullname" . }}
  labels:
  {{- include "shovel.labels" . | nindent 4 }}

data:
  SERVER_PORT: "{{ .Values.env.app.port}}"
  APPLICATION_NAME: {{ .Values.env.app.name }}
  • 使用Helm发布/更新服务

切换当前context到dev(这里的env可以通过jenkins parameters 进行传递),使用Helm发布/更新服务

stage('Deploy') {
            sh """
               kubectl config use-context dev
               helm -n ${namespace} upgrade ${project} chart \
                    -f chart/values.yaml \
                    --set-string image.tag=${imageTag} \
                    --wait --install
                """
        }