云原生Devops最佳实践(1):持续集成(CI)+ OpenKruise镜像预热
什么是Devops?
DevOps 就是开发(Development)、测试(QA)、运维(Operations)这三个领域的合并。DevOps是一种思想、一组最佳实践、以及一种文化。 DevOps是CI/CD思想的延伸,CI/CD是DevOps的基础核心,如果没有CI/CD自动化的工具和流程,DevOps是没有意义的。

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

使用场景
- 长期预热公共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,如下: 
2. Tekton构建-测试-推送镜像Task,并且需要生成docker registry secret(用于push image),如下:
# docker registry密钥,用于docker push imageapiVersion: v1data:.dockerconfigjson: xxxxxxkind: Secretmetadata:name: dockersecrettype: kubernetes.io/dockerconfigjson---apiVersion: tekton.dev/v1beta1kind: Taskmetadata:labels:app: helloworldname: helloworld-build-pushspec:stepTemplate:workingDir: /workspaceparams:- name: gitrepositoryurltype: string- name: branchtype: string- name: short_shatype: string- name: docker_repotype: string- name: app_nametype: stringsteps:# git clone- name: git-clone-and-checkoutimage: bitnami/git:latestcommand: ["sh", "-ce"]args:- >set -eecho $(params.gitrepositoryurl)git clone $(params.gitrepositoryurl) ./ && git checkout $(params.branch)# unit test- name: auto-testimage: golang:1.16command: [ "sh", "-ce" ]args:- >set -ecp -R /workspace/$(params.app_name) /go/src/ && cd /go/src/$(params.app_name) && pwd;go test# docker build & push registry- name: push-to-registryimage: gcr.io/kaniko-project/executor:latestargs:- --dockerfile=Dockerfile- --destination=$(params.docker_repo):$(params.branch)-$(params.short_sha)- --context=./$(params.app_name)- --cache=true- --cache-dir=/cache- --use-new-runvolumeMounts:- name: kaniko-secretmountPath: "/kaniko/.docker"volumes:# docker push secret- name: kaniko-secretsecret:secretName: dockersecretitems:- key: .dockerconfigjsonpath: 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/v1alpha1kind: CloneSet/StatefulSetmetadata:annotations:apps.kruise.io/image-predownload-parallelism: "5"
Kubernetes原生Workload,例如:Deployment, StatefulSet, DaemonSet, Job等
1. 配置镜像预热 ImagePullJob CRD资源,并配置到k8s configmap资源中,如下:
apiVersion: v1kind: ConfigMapmetadata:name: imagePullJobdata:imagepulljob.yaml: |apiVersion: apps.kruise.io/v1alpha1kind: ImagePullJobmetadata:name: APP_NAMEspec:# 需要预热的镜像地址image: APP_IMAGEparallelism: 10# 你可以在 selector 字段中指定节点的 名字列表 或 标签选择器 (只能设置其中一种),如果没有设置 selector 则会选择所有节点做预热。selector:names:- node-1- node-2matchLabels:node-type: xxxcompletionPolicy:type: AlwaysactiveDeadlineSeconds: 1200ttlSecondsAfterFinished: 300pullPolicy:backoffLimit: 3timeoutSeconds: 300
2. 下发镜像预热 ImagePullJob CRD资源TASK,其中kubeconfig配置存储在secret中,如下:
# kubeconfig配置apiVersion: v1data:kubeconfig: xxxxxxkind: Secretmetadata:name: kubeconfig---apiVersion: tekton.dev/v1beta1kind: Taskmetadata:labels:app: helloworldname: helloworld-image-predownloadspec:params:- name: branchtype: string- name: short_shatype: string- name: docker_repotype: string- name: app_nametype: stringsteps:- name: image-predownloadimage: bitnami/kubectl:latestcommand: [ "sh", "-ce" ]args:- >set -eecho "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: kubeconfigmountPath: "/var/kube"- name: imagepulljobmountPath: "/var/crd"volumes:- name: kubeconfigsecret:secretName: kubeconfig- name: imagepulljobconfigmap:name: imagepulljob
一键执行Tekton Pipeline
1. 定义tekton pileline,总共由上面两个task任务组成,并且执行完 构建-测试-推送镜像Task之后,再执行镜像预热Task如下:
apiVersion: tekton.dev/v1beta1kind: Pipelinemetadata:name: helloworld-pipelinespec:params:- name: gitrepositoryurltype: string- name: branchtype: string- name: short_shatype: string- name: docker_repotype: string- name: app_nametype: stringtasks:- name: helloworld-build-pushtaskRef:name: helloworld-build-pushparams:- name: gitrepositoryurlvalue: $(params.gitrepositoryurl)- name: short_shavalue: $(params.short_sha)- name: branchvalue: $(params.branch)- name: docker_repovalue: $(params.docker_repo)- name: app_namevalue: $(params.app_name)- name: helloworld-image-predownloadtaskRef:name: helloworld-image-predownloadparams:- name: short_shavalue: $(params.short_sha)- name: branchvalue: $(params.branch)- name: docker_repovalue: $(params.docker_repo)- name: app_namevalue: $(params.app_name)runAfter:- helloworld-build-push
2. 定义PipelineRun CRD资源,并kubectl apply -f 到k8s集群执行Pipeline,如下:
apiVersion: tekton.dev/v1beta1kind: PipelineRunmetadata:name: helloworld-pipeline-run-1spec:pipelineRef:name: helloworld-pipelineparams:- name: gitrepositoryurlvalue: https://github.com/zmberg/samples.git- name: branchvalue: hello_world- name: short_shavalue: d92ae174b- name: docker_repovalue: zhaomingshan/kruise- name: app_namevalue: helloworld
3. 可以通过tekton命令行工具tkn查看执行结果,如下:

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