本文介绍jenkins X(以下简称jx)相关的背景技术。
jenkins X 简介
Jenkins X 是一个高度集成化的CI/CD平台,基于Jenkins和Kubernetes实现,旨在解决微服务体系架构下的云原生应用的持续交付的问题,简化整个云原生应用的开发、运行和部署过程。
jx 基于gitops,将k8s分为preview、staging、production几个环境,
详细的devops可以查看下图:
jx是云原生CICD,devops的一个最佳实践之一,目前在快速的发展成熟中。最近调研了JX,准备写一个jx实践系列,这里为第一篇,介绍jx用到的一些相关组件,作为了解jx的背景知识。
jenkins pipeline
jx使用Jenkins Pipeline来执行CI流程,Jenkins Pipeline是jenkins的一套插件,支持将连续输送Pipeline实施和整合到Jenkins。Pipeline 提供了一组可扩展的工具,用于通过Pipeline DSL为代码创建简单到复杂的传送Pipeline 。
Jenkinsfile pipeline使用Groovy脚本来定义CI流程,来看一个jx生成的实际案例:
pipeline { agent { label "jenkins-maven" } environment { ORG = 'jqpeng' APP_NAME = 'x-nginx' CHARTMUSEUM_CREDS = credentials('jenkins-x-chartmuseum') } stages { stage('CI Build and push snapshot') { when { branch 'PR-*' } environment { PREVIEW_VERSION = "0.0.0-SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER" PREVIEW_NAMESPACE = "$APP_NAME-$BRANCH_NAME".toLowerCase() HELM_RELEASE = "$PREVIEW_NAMESPACE".toLowerCase() } steps { container('maven') { sh "mvn versions:set -DnewVersion=$PREVIEW_VERSION" sh "mvn package -DskipTests" sh 'export VERSION=$PREVIEW_VERSION && skaffold build -f skaffold.yaml' sh "jx step post build --image $DOCKER_REGISTRY/$ORG/$APP_NAME:$PREVIEW_VERSION" } dir ('./charts/preview') { container('maven') { sh 'helm init --client-only --stable-repo-url=http://charts.iflyresearch.com/' sh "make preview" sh "jx preview --app $APP_NAME --dir ../.." } } } } stage('Build Release') { when { branch 'master' } steps { container('maven') { // ensure we're not on a detached head sh "git checkout master" sh "git config --global credential.helper store" sh "jx step git credentials" // so we can retrieve the version in later steps sh "echo \$(jx-release-version) > VERSION" sh "mvn versions:set -DnewVersion=\$(cat VERSION)" } dir ('./charts/x-nginx') { container('maven') { sh "make tag" } } container('maven') { sh 'mvn package -DskipTests' sh 'export VERSION=`cat VERSION` && skaffold build -f skaffold.yaml' sh "jx step post build --image $DOCKER_REGISTRY/$ORG/$APP_NAME:\$(cat VERSION)" } } } stage('Promote to Environments') { when { branch 'master' } steps { dir ('./charts/x-nginx') { container('maven') { sh 'jx step changelog --version v\$(cat ../../VERSION)' sh 'helm init --client-only --stable-repo-url=http://charts.iflyresearch.com/' // release the helm chart sh 'jx step helm release' // promote through all 'Auto' promotion Environments sh 'jx promote -b --all-auto --timeout 1h --version \$(cat ../../VERSION)' } } } } } post { always { cleanWs() } } }
pipeline 定义是一个pipeline
environment 定义环境变量
stages 定义流程
when 匹配条件
environment 定义子流程环境变量
steps 定义流程制定的具体步骤
container('maven') 使用maven镜像来构建
sh "git checkout master" 在maven镜像执行命令
stage('CI Build and push snapshot') 定义子流程
其余的看字面意思就可以理解了
执行构建后,打开jenkins web页面,可以看到构建pipelines
同时可以查看Blue Ocean页面
helm与charts
Helm是管理Kubernetes charts的工具,charts是预先配置好的安装包资源,有点类似于Ubuntu的APT和CentOS中的yum。
可以使用helm来:
查找并使用已打包为Helm charts的热门应用在Kubernetes中运行
封装并分享自己的应用
创建可重复的Kubernetes应用程序版本
智能管理应用依赖
管理Helm软件包的版本
安装helm
安装helm很简单,下载离线二进制包,加压后加入path即可
wget https://kubernetes-helm.storage.googleapis.com/helm-canary-linux-amd64.tar.gz
helm需要服务端Tiller支持,需要安装到集群中,可以使用下面的命令来安装最新的2.11版本:
helm init --tiller-image anjia0532/kubernetes-helm.tiller:v2.11.0 --skip-refresh
参见:google gcr.io、k8s.gcr.io 国内镜像
helm错误解决
Helm: Error: no available release name found
helm报这个错误 Helm: Error: no available release name found
错误的原因大概是因为 tiller没有正确的角色权限。
执行以下命令可解决这个问题。
kubectl create serviceaccount --namespace kube-system tiller kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'
charts入门
先来看一个jx生成的charts文件:
tree charts/ charts/ ├── preview │ ├── Chart.yaml │ ├── Makefile │ ├── requirements.yaml │ └── values.yaml ├── x-nginx │ ├── Chart.yaml │ ├── Makefile │ ├── README.md │ ├── templates │ │ ├── deployment.yaml │ │ ├── _helpers.tpl │ │ ├── NOTES.txt │ │ └── service.yaml │ └── values.yaml
Chart.yaml
chart文件首先是一个Chart.yaml描述文件,描述chart的基本信息,包含name,version等描述信息
cat charts/x-nginx/Chart.yaml apiVersion: v1description: A Helm chart for Kubernetesicon: https://raw.githubusercontent.com/jenkins-x/jenkins-x-platform/master/images/java.pngname: x-nginxversion: 0.1.0-SNAPSHOT ~
templates
templates存放的是模板文件,遵循Go template语法,结合values.yaml的数据,可以生成部署到K8S所需的yaml配置文件。
来简单看下deployment.yaml:
apiVersion: extensions/v1beta1kind: Deploymentmetadata: name: {{ template "fullname" . }} labels: draft: {{ default "draft-app" .Values.draft }} chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"spec: replicas: {{ .Values.replicaCount }} template: metadata: labels: draft: {{ default "draft-app" .Values.draft }} app: {{ template "fullname" . }}{{- if .Values.podAnnotations }} annotations:{{ toYaml .Values.podAnnotations | indent 8 }}{{- end }} spec: containers: - name: {{ .Chart.Name }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - containerPort: {{ .Values.service.internalPort }} terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}
注意,模板遵循Go template语法,都是go生态,可以稍微学习了解下。上面的模板是Deployment的yaml配置文件,大括号包裹起来的部分是Go template,对应的Values是在values.yaml
文件中定义的:
# Default values for Maven projects.# This is a YAML-formatted file.# Declare variables to be passed into your templates.replicaCount: 1image: repository: draft tag: dev pullPolicy: IfNotPresentservice: name: x-nginx type: ClusterIP externalPort: 80 internalPort: 8080 annotations: fabric8.io/expose: "true" fabric8.io/ingress.annotations: "kubernetes.io/ingress.class: nginx"resources: limits: cpu: 500m memory: 512Mi requests: cpu: 400m memory: 512MiterminationGracePeriodSeconds: 10
简单学习下常用语法:
{{ .Values.replicaCount }} 对应
values.yaml
中的replicaCount,通过{{ .Values.$varname }} 语法引用{{ default "draft-app" .Values.draft }} 如果draft没有定义,使用默认的"draft-app"
{{- if .Values.podAnnotations }} {{- end }} 条件语法
{{ toYaml .Values.podAnnotations | indent 8 }} 输出为yaml,indent指定缩进
验证模板
charts通过go模板渲染后,最后生成yaml格式部署文件,可以使用helm install --dry-run --debug <chart_dir>
命令来验证chart配置,查看最终生成的配置文件。
$:~/workspace/xnginx/charts/x-nginx$ helm install --dry-run --debug . [debug] Created tunnel using local port: '40868'[debug] SERVER: "127.0.0.1:40868"[debug] Original chart version: ""[debug] CHART PATH: /workspace/xnginx/charts/x-nginx NAME: messy-seastar REVISION: 1 RELEASED: Tue Nov 20 09:20:39 2018 CHART: x-nginx-0.1.0-SNAPSHOT USER-SUPPLIED VALUES: {} COMPUTED VALUES: image: pullPolicy: IfNotPresent repository: draft tag: dev replicaCount: 1 resources: limits: cpu: 500m memory: 512Mi requests: cpu: 400m memory: 512Mi service: annotations: fabric8.io/expose: "true" fabric8.io/ingress.annotations: 'kubernetes.io/ingress.class: nginx' externalPort: 80 internalPort: 8080 name: x-nginx type: ClusterIP terminationGracePeriodSeconds: 10 HOOKS: MANIFEST: ---# Source: x-nginx/templates/service.yamlapiVersion: v1 kind: Service metadata: name: x-nginx labels: chart: "x-nginx-0.1.0-SNAPSHOT" annotations: fabric8.io/expose: "true" fabric8.io/ingress.annotations: 'kubernetes.io/ingress.class: nginx' spec: type: ClusterIP ports: - port: 80 targetPort: 8080 protocol: TCP name: http selector: app: messy-seastar-x-nginx ---# Source: x-nginx/templates/deployment.yamlapiVersion: extensions/v1beta1 kind: Deployment metadata: name: messy-seastar-x-nginx labels: draft: draft-app chart: "x-nginx-0.1.0-SNAPSHOT"spec: replicas: 1 template: metadata: labels: draft: draft-app app: messy-seastar-x-nginx spec: containers: - name: x-nginx image: "draft:dev" imagePullPolicy: IfNotPresent ports: - containerPort: 8080 terminationGracePeriodSeconds: 10
其他命令
部署
helm install .
打包分享
helm package .
charts mirror 镜像
官方的charts镜像由于GFW原因,不能访问,可以使用github镜像:
helm repo add stable https://burdenbear.github.io/kube-charts-mirror/
当然,为了更好使用,可以部署本地镜像
clone mirror仓库到本地,存放到cephfs /charts目录,然后创建一个nginx,挂载这个pv即可。
cat <<EOF | kubectl apply -f - apiVersion: v1 kind: PersistentVolume metadata: name: cephfs-charts-pv namespace: nginx-ingress labels: name: cephfs-charts-pv spec: capacity: storage: 5Gi accessModes: - ReadWriteMany cephfs: monitors: - 192.168.86.156:6789 path: /charts/kube-charts-mirror-master/docs/ user: admin secretRef: name: ceph-secret readOnly: false persistentVolumeReclaimPolicy: Retain EOF
skaffold
Skaffold 是谷歌开源的简化本地 Kubernetes 应用开发的工具。它将构建镜像、推送镜像以及部署 Kubernetes 服务等流程自动化,可以方便地对 Kubernetes 应用进行持续开发。其功能特点包括
没有服务器组件
自动检测代码更改并自动构建、推送和部署服务
自动管理镜像标签
支持已有工作流
保存文件即部署
直接进入正题,skaffold通过skaffold.yaml
来定义build、deploy,并且可以区分dev环境和正式环境:
apiVersion: skaffold/v1alpha2kind: Configbuild: tagPolicy: envTemplate: template: "{{.DOCKER_REGISTRY}}/jqpeng/x-nginx:{{.VERSION}}" artifacts: - imageName: changeme workspace: ./xnginx-admin docker: {} local: {}deploy: kubectl: manifests:profiles:- name: dev build: tagPolicy: envTemplate: template: "{{.DOCKER_REGISTRY}}/jqpeng/x-nginx:{{.DIGEST_HEX}}" artifacts: - docker: {} local: {} deploy: helm: releases: - name: x-nginx chartPath: charts/x-nginx setValueTemplates: image.repository: "{{.DOCKER_REGISTRY}}/jqpeng/x-nginx" image.tag: "{{.DIGEST_HEX}}"
apiVersion 指定API版本,jx用的还是v1alpha2,相对较老
build.tagPolicy.template 配置了image的名称模板,DOCKER_REGISTRY,Version等是环境变量
artifacts 数组,用于指定构建docker镜像,可以有多个,workspace制定工作目录(新版本的api变为了context)
deploy 指定部署方式
profiles 区分环境,这里定义了dev环境
设置template ,image的tag为DIGEST_HEX,校验码
部署使用helm
如上的配置,在jx里如何运作的呢?
正式构建环境,只进行构建
在jenkinsfile里
sh 'export VERSION=`cat VERSION` && skaffold build -f skaffold.yaml'
在devpod里,实现构建和部署
skaffold run -p dev
Draft
draft 是微软开源的“A tool for developers to create cloud-native applications on Kubernetes”,一个为方便开发者在K8S创建云原生应用的工具,它可以帮助开发人员简化容器应用程序的开发流程。
上面我们了解了JENKINSFile,charts配置文件,难道每个项目需要按我们自己来写这些配置文件吗?
Draft告诉你,可以不!Draft最大的益处是,可以自动识别你的工程,然后根据模板库生成对应的配置文件,酷不酷?
Draft 主要由三个命令组成
draft init
:初始化 docker registry 账号,并在 Kubernetes 集群中部署 draftd(负责镜像构建、将镜像推送到 docker registry 以及部署应用等)draft create
:draft 根据 packs 检测应用的开发语言,并自动生成 Dockerfile 和 Kubernetes Helm Chartsdraft up
:根据 Dockfile 构建镜像,并使用 Helm 将应用部署到 Kubernetes 集群(支持本地或远端集群)。同时,还会在本地启动一个 draft client,监控代码变化,并将更新过的代码推送给 draftd。
不过,在jx中,仅仅只使用了draft的识别语言,生成配置文件的功能,相关的draft模板可以在# draft-packs 里看到。
Nexus
jx使用Nexus 来做默认的制品仓库(Artifact repository),Nexus大家应该不默认,好多公司和团队的maven仓库均是通过Nexus搭建的。
Nexus还可以作为npm,nuget,docker仓库。
Chartmuseum 与Monocular
Chartmuseum - 是一个helm chart仓库,jx用他来做chart仓库。
Monocular是一个web应用可以用来从helm charts仓库搜索和发现charts。
作者:Jadepeng
出处:jqpeng的技术记事本--http://www.cnblogs.com/xiaoqi
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。