本文介紹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 定義流程
- stage('CI Build and push snapshot') 定義子流程
- 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: v1
description: A Helm chart for Kubernetes
icon: https://raw.githubusercontent.com/jenkins-x/jenkins-x-platform/master/images/java.png
name: x-nginx
version: 0.1.0-SNAPSHOT
~
templates
templates存放的是模板文件,遵循Go template語法,結合values.yaml的數據,可以生成部署到K8S所需的yaml配置文件。
來簡單看下deployment.yaml:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
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: 1
image:
repository: draft
tag: dev
pullPolicy: IfNotPresent
service:
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: 512Mi
terminationGracePeriodSeconds: 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.yaml
apiVersion: 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.yaml
apiVersion: 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/v1alpha2
kind: Config
build:
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 Charts -
draft 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
您的支持是對博主最大的鼓勵,感謝您的認真閱讀。
本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。