Skip to main content
版本:v1.2

云原生Devops最佳实践(1):持续集成(CI)+ OpenKruise镜像预热

什么是Devops?

DevOps 就是开发(Development)、测试(QA)、运维(Operations)这三个领域的合并。DevOps是一种思想、一组最佳实践、以及一种文化。 DevOps是CI/CD思想的延伸,CI/CD是DevOps的基础核心,如果没有CI/CD自动化的工具和流程,DevOps是没有意义的。

ci/cd pipeline

持续集成(CI)+ OpenKruise镜像预热

核心概念

  • 持续集成(CI)是一个将集成提前至开发周期的早期阶段的实践方式,让构建、测试和集成代码更经常反复地发生。
  • 镜像预热是OpenKruise提供的在应用部署之前提前将应用镜像拉取到具体的Node节点上面,进而达到镜像预热的目的,能够极大的提升应用的部署效率。

整体架构

ci+image pre-download

使用场景

  • 长期预热公共sidecar镜像、基础镜像,例如:istio envoy、日志采集容器
  • 大规模场景下,提前预热业务app镜像到特定的K8s Node,进而降低部署过程中对镜像仓库的压力,主要针对Deployment、StatefulSet等k8s原生资源
  • OpenKruise CloneSet原地升级时,内置了镜像预热能力,参考CloneSet文档

注意:OpenKruise镜像预热能力只能针对常规的Kubelet节点,而virtual kubelet则不能适用。

Tekton(CI)+ 镜像预热实践

前置条件

  • Kubernetes集群,从v1.0.0(alpha/beta)开始,OpenKruise要求在Kubernetes >= 1.16以上版本的集群中安装和使用。
  • 安装Tekton, 参考官方文档。Tekton是一种适用于创建持续集成和持续部署/交付(CI/CD)系统的谷歌开源的Kubernetes原生框架。
  • Helm安装OpenKruise,需要v0.9.0及更新的版本,参考安装文档

构建-测试-镜像推送

1. Git Repo:本文提供了一个helloworld http服务demo,其中包含Code、Dockerfile以及Unit Test,如下: git helloworld

2. Tekton构建-测试-推送镜像Task,并且需要生成docker registry secret(用于push image),如下:

# docker registry密钥,用于docker push image
apiVersion: v1
data:
.dockerconfigjson: xxxxxx
kind: Secret
metadata:
name: dockersecret
type: kubernetes.io/dockerconfigjson
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
labels:
app: helloworld
name: helloworld-build-push
spec:
stepTemplate:
workingDir: /workspace
params:
- name: gitrepositoryurl
type: string
- name: branch
type: string
- name: short_sha
type: string
- name: docker_repo
type: string
- name: app_name
type: string
steps:
# git clone
- name: git-clone-and-checkout
image: bitnami/git:latest
command: ["sh", "-ce"]
args:
- >
set -e

echo $(params.gitrepositoryurl)

git clone $(params.gitrepositoryurl) ./ && git checkout $(params.branch)
# unit test
- name: auto-test
image: golang:1.16
command: [ "sh", "-ce" ]
args:
- >
set -e

cp -R /workspace/$(params.app_name) /go/src/ && cd /go/src/$(params.app_name) && pwd;

go test
# docker build & push registry
- name: push-to-registry
image: gcr.io/kaniko-project/executor:latest
args:
- --dockerfile=Dockerfile
- --destination=$(params.docker_repo):$(params.branch)-$(params.short_sha)
- --context=./$(params.app_name)
- --cache=true
- --cache-dir=/cache
- --use-new-run
volumeMounts:
- name: kaniko-secret
mountPath: "/kaniko/.docker"
volumes:
# docker push secret
- name: kaniko-secret
secret:
secretName: dockersecret
items:
- key: .dockerconfigjson
path: config.json

镜像预热

Kruise CloneSet & Advanced StatefulSet原地升级内置镜像预热能力

Note:此种场景不再需要下发ImagePullJob CRD资源

如果你在安装或升级 Kruise 的时候启用了 PreDownloadImageForInPlaceUpdate feature-gate, CloneSet & Advanced StatefulSet 控制器会自动在所有旧版本 pod 所在 node 节点上预热你正在灰度发布的新版本镜像。 这对于应用发布加速很有帮助。

# Firstly add openkruise charts repository if you haven't do this.
$ helm repo add openkruise https://openkruise.github.io/charts/

# [Optional]
$ helm repo update

# Install the latest version.
$ helm install kruise openkruise/kruise --set featureGates="PreDownloadImageForInPlaceUpdate=true"

# Those that have been installed need to be upgraded
$ helm upgrade kruise openkruise/kruise --set featureGates="PreDownloadImageForInPlaceUpdate=true"

默认情况下 CloneSet & Advanced StatefulSet 每个新镜像预热时的并发度都是 1,也就是一个个节点拉镜像。如果需要调整,你可以在 annotation 上设置并发度:

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet/StatefulSet
metadata:
annotations:
apps.kruise.io/image-predownload-parallelism: "5"

Kubernetes原生Workload,例如:Deployment, StatefulSet, DaemonSet, Job等

1. 配置镜像预热 ImagePullJob CRD资源,并配置到k8s configmap资源中,如下:

apiVersion: v1
kind: ConfigMap
metadata:
name: imagePullJob
data:
imagepulljob.yaml: |
apiVersion: apps.kruise.io/v1alpha1
kind: ImagePullJob
metadata:
name: APP_NAME
spec:
# 需要预热的镜像地址
image: APP_IMAGE
parallelism: 10
# 你可以在 selector 字段中指定节点的 名字列表 或 标签选择器 (只能设置其中一种),如果没有设置 selector 则会选择所有节点做预热。
selector:
names:
- node-1
- node-2
matchLabels:
node-type: xxx
completionPolicy:
type: Always
activeDeadlineSeconds: 1200
ttlSecondsAfterFinished: 300
pullPolicy:
backoffLimit: 3
timeoutSeconds: 300

2. 下发镜像预热 ImagePullJob CRD资源TASK,其中kubeconfig配置存储在secret中,如下:

# kubeconfig配置
apiVersion: v1
data:
kubeconfig: xxxxxx
kind: Secret
metadata:
name: kubeconfig
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
labels:
app: helloworld
name: helloworld-image-predownload
spec:
params:
- name: branch
type: string
- name: short_sha
type: string
- name: docker_repo
type: string
- name: app_name
type: string
steps:
- name: image-predownload
image: bitnami/kubectl:latest
command: [ "sh", "-ce" ]
args:
- >
set -e

echo "pre download image"

cat /var/crd/imagepulljob.yaml | sed 's#JOB_NAME#$(params.app_name)-$(params.short_sha)#' | sed 's#APP_IMAGE#$(params.docker_repo):$(params.branch)-$(params.short_sha)#' | kubectl apply --kubeconfig=/var/kube/kubeconfig -f -
volumeMounts:
- name: kubeconfig
mountPath: "/var/kube"
- name: imagepulljob
mountPath: "/var/crd"
volumes:
- name: kubeconfig
secret:
secretName: kubeconfig
- name: imagepulljob
configmap:
name: imagepulljob

一键执行Tekton Pipeline

1. 定义tekton pileline,总共由上面两个task任务组成,并且执行完 构建-测试-推送镜像Task之后,再执行镜像预热Task如下:

apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: helloworld-pipeline
spec:
params:
- name: gitrepositoryurl
type: string
- name: branch
type: string
- name: short_sha
type: string
- name: docker_repo
type: string
- name: app_name
type: string
tasks:
- name: helloworld-build-push
taskRef:
name: helloworld-build-push
params:
- name: gitrepositoryurl
value: $(params.gitrepositoryurl)
- name: short_sha
value: $(params.short_sha)
- name: branch
value: $(params.branch)
- name: docker_repo
value: $(params.docker_repo)
- name: app_name
value: $(params.app_name)
- name: helloworld-image-predownload
taskRef:
name: helloworld-image-predownload
params:
- name: short_sha
value: $(params.short_sha)
- name: branch
value: $(params.branch)
- name: docker_repo
value: $(params.docker_repo)
- name: app_name
value: $(params.app_name)
runAfter:
- helloworld-build-push

2. 定义PipelineRun CRD资源,并kubectl apply -f 到k8s集群执行Pipeline,如下:

apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
name: helloworld-pipeline-run-1
spec:
pipelineRef:
name: helloworld-pipeline
params:
- name: gitrepositoryurl
value: https://github.com/zmberg/samples.git
- name: branch
value: hello_world
- name: short_sha
value: d92ae174b
- name: docker_repo
value: zhaomingshan/kruise
- name: app_name
value: helloworld

3. 可以通过tekton命令行工具tkn查看执行结果,如下:

tekton pipeline

总结

Tekton是google开源的目前社区非常流行的云原生CI Pipeline工具,本篇文章旨在将OpenKruise提供的镜像预热能力与CI Pipeline结合,进而能够极大的提升用户在应用部署阶段的部署效率,并且能够降低在大规模部署下对于镜像仓库的压力。 后面一篇文章将会聚焦在CD Pipeline应用部署阶段,敬请期待。