|
12-Kubernetes-CI/CD实践 |
|
01-Docker基础 02-Kubernetes基础 03-K8SCI-基本配置 04-K8SCI-添加构建镜像步骤 05-K8SCD-手动部署应用 06-K8SCD-自动化部署应用 07-K8SCD-添加应用回滚 08-K8SCD-GitOps流水线优化 09-HELM-手动发布Chart 10-HELM-CI流水线配置 11-HELM-添加上传Chart步骤 12-HELM-CD发布Chart 13-ArgoCD-发布manifest 14-ArgoCD-发布Helm Chart |
必修 |
|
一、Kubectl 发布流水线


我用夸克网盘给你分享了 链接:https://pan.quark.cn/s/ce015bdb3f78
CI流水线:
- 下载代码
- 构建单元测试
- 代码扫描
- 构建镜像
- 更新发布文件
CD流水线:
- 输入版本,从git下载部署文件;
- 使用kubectl发布;
- 使用kubectl回滚;
1.1 CI流水线
此次项目我们使用了jenkins共享库来完成最佳实践。 jenkinsfile第一行就是要导入我们的共享库。@Library("devops5") _
我们在共享库中编写了一些特定的处理类。在Jenkinsfile中导入这些类
@Library("devops5") _
//Lib
def build = new org.devops.Build()
def myTool = new org.devops.Tools()
def sonar = new org.devops.Sonar()
def art = new org.devops.Artifact()
def gitlabTool = new org.devops.Gitlab()
有些参数需要用户在Jenkins页面构建前填写的:
- 用户需要在jenkins作业中配置好要构建的代码仓库的地址。(一般不需要改, 可以使用选项参数)
- 每次构建需要输入此代码库要构建的代码分支。 (字符串参数)
- 选择本次构建要使用的构建工具(选项参数maven、ant、gradle、npm)

流水线运行
此条流水线运行在标签为"build"的节点上, 跳过默认的checkout步骤。
agent { label "build01"}
options{
skipDefaultCheckout true
}
阶段与节点

下载代码
stage("CheckOut"){
steps{
script{
//下载代码
currentBuild.description = "branch: ${env.branchName}"
myTool.GetCode("${env.branchName}", "${env.srcUrl}")
}
}
}
构建代码和单元测试
stage("Build"){
steps{
script{
// 构建阶段
build.Build()
}
}
}
stage("UnitTest"){
when {
environment name: 'skipUnitTest' , value: 'false'
}
steps{
script{
// 单元测试
build.UnitTest()
}
}
}
代码扫描
stage("CodeScan"){
steps{
script{
// 代码扫描
env.commitID = myTool.GetCommitID()
sonar.CodeScan()
}
}
}
构建上传镜像
- 需要将docker镜像仓库的用户认证信息,以用户名和密码类型的凭据在Jenkins中存储;
- docker仓库:192.168.1.200:8088/${repoName}/${projectName};
- 镜像标签: ${env.branchName} 即 版本分支名称;
- 步骤: 登录镜像仓库> 构建镜像 > 上传镜像 > 删除本地镜像(节省空间);
stage("DockerImage"){
steps{
script{
//生成Docker镜像
repoName = "${JOB_NAME}".split("/")[0] //devops5
projectName = "${JOB_NAME}".split("/")[-1].split("_")[0] //devops5-npm-web
env.registry = "192.168.1.200:8088" //harbor
env.imageName = "${env.registry}/${repoName}/${projectName}:${env.branchName}"
withCredentials([usernamePassword(credentialsId: 'd12269dd-2439-4d3e-8917-915e8404e97a',
passwordVariable: 'DOCKER_PASSWD',
usernameVariable: 'DOCKER_USER')]) {
sh """
# 构建镜像
docker build -t ${env.imageName} .
#登录镜像仓库
docker login -u ${DOCKER_USER} -p ${DOCKER_PASSWD} ${env.registry}
# 上传镜像
docker push ${env.imageName}
# 删除镜像
sleep 2
docker rmi ${env.imageName}
"""
}
}
}
}
【GitOps最重要的一个特性: 自动更新部署文件】
更新生成版本文件
- 步骤: 拿到 env仓库中的deployments.yaml模板文件, 然后替换内容,更新到版本库。

更新对象:
__RELEASE_VERSION__(镜像TAG)
stage("UpdateEnvFile"){
steps{
script {
// 更新部署文件
//下载发布文件
projectId = 12
filePath = "devops5-npm-web-deployment.yaml"
branchName = "main"
fileData = gitlabTool.GetRepoFile(projectId,filePath, branchName )
sh "rm -fr ${filePath}"
writeFile file: filePath , text: fileData
env.deployFile = filePath
sh "sed -i 's#__RELEASE_VERSION__#${env.branchName}#g' ${env.deployFile} "
sh "ls -l ; cat ${filePath}"
//创建/更新发布文件
newYaml = sh returnStdout: true, script: "cat ${env.deployFile}"
println(newYaml)
//更新gitlab文件内容
base64Content = newYaml.bytes.encodeBase64().toString()
env.groupName = "${JOB_NAME}".split("/")[0] //devops5
env.projectName = "${JOB_NAME}".split("/")[-1].split("_")[0] //devops5-npm-web
// 会有并行问题,同时更新报错
try {
gitlabTool.UpdateRepoFile(projectId,"${env.projectName}%2f${env.branchName}.yaml",base64Content, "main")
} catch(e){
gitlabTool.CreateRepoFile(projectId,"${env.projectName}%2f${env.branchName}.yaml",base64Content, "main")
}
}
}
}
更新后的版本文件

1.2 CD流水线
jenkinsfile第一行就是要导入我们的共享库。@Library("devops5@main") _
我们在共享库中编写了一些特定的处理类:
- src/org/devops/Gitlab.groovy 版本控制系统接口操作工具
在Jenkinsfile中导入这些类
@Library("devops5") _
//Lib
def gitlabTool = new org.devops.Gitlab()
只有一个参数需要用户在Jenkins页面构建前填写的:
- 用户在页面输入发布版本: branchName, 例如 RELEASE-1.1.0

我们在流水线中定义一些全局变量:
- 通过作业名称拿到业务简称(devops03)
- 通过作业名称拿到应用名称(devops03-devops-ui)
env.groupName = "${JOB_NAME}".split("/")[0]
env.projectName = "${JOB_NAME}".split("/")[-1].split("_")[0]
流水线运行
此条流水线运行在标签为"k8s"的节点上, 跳过默认的checkout步骤。(课程中是在k8s的master节点启动了一个jnlp的Jenkins Slave)
agent { label "build01"}
options{
skipDefaultCheckout true
}
阶段与节点

获取发布文件
- 下载CI流水线生成的版本文件到本地;
stage("GetDeployFile"){
steps{
script{
//下载发布文件
projectId = 12
env.deployFile = "${env.releaseVersion}.yaml"
filePath = "${env.projectName}%2f${env.deployFile}"
branchName = "main"
fileData = gitlabTool.GetRepoFile(projectId,filePath, branchName )
sh "rm -fr ${env.deployFile}"
writeFile file: env.deployFile , text: fileData
sh "ls -l ; cat ${env.deployFile}"
//sh "sed -i 's#__RELEASE_VERSION__#${env.releaseVersion}#g' ${env.deployFile} "
//sh "ls -l ; cat ${filePath}"
}
}
}
应用发布
- 创建名称空间,更新应用
stage("DeployAPP"){
steps{
script{
env.namespace = "${env.groupName}"
sh """
## 发布应用
kubectl apply -f ${env.deployFile} -n ${env.namespace}
"""
// 获取应用状态
5.times{
sh "sleep 2; kubectl -n ${env.namespace} get pod | grep ${env.projectName}"
}
}
}
}
回滚步骤(交互)
- 给用户提供两个选项 :yes执行回滚,no跳过;
- 使用kubectl rollout undo 默认回滚上个版本;
stage("RollOut"){
input {
message "是否进行回滚"
ok "提交"
submitter ""
parameters {
choice(choices: ['yes', 'no'], name: 'opts')
}
}
steps{
script{
switch("${opts}") {
case "yes":
sh "kubectl rollout undo deployment/${env.projectName} -n ${env.namespace} "
break
case "no":
break
}
}
}
}
二、Helm CI/CD流水线

我用夸克网盘 链接:https://pan.quark.cn/s/c19bbf182e2c
基于Helm CI/CD


2.1 CI流水线

此部分可以参考上面“基于kubectl发布”阶段, 相同的阶段代码。
阶段与节点
此部分可以参考上面“基于kubectl发布”阶段, 相同的阶段代码。
更新生成版本文件
此处的版本文件不再是一个文件了, 而是一个chart包。如何生成:
helm create "${appName}"
cd "${appName}"
git push 到版本库
- 步骤: 拿到 helm chart仓库中的values.yaml模板文件, 然后替换镜像,更新到版本库。
- 更新对象:
-
- image.tag (镜像标签)
stage("UpdateEnvFile"){
steps{
script {
// 更新部署文件
env.groupName = "${JOB_NAME}".split("/")[0] //devops5
env.projectName = "${JOB_NAME}".split("/")[-1].split("_")[0] //devops5-npm-web
//下载发布文件
projectId = 13
env.deployFile = "values.yaml"
filePath = "${env.projectName}%2f${env.deployFile}"
branchName = "master"
fileData = gitlabTool.GetRepoFile(projectId,filePath, branchName )
sh "rm -fr ${env.deployFile}"
yamlData = readYaml text: fileData
yamlData.image.tag = "${env.branchName}"
writeYaml file: "${env.deployFile}" , data: yamlData
//创建/更新发布文件
newYaml = sh returnStdout: true, script: "cat ${env.deployFile}"
println(newYaml)
//更新gitlab文件内容
base64Content = newYaml.bytes.encodeBase64().toString()
// 会有并行问题,同时更新报错
try {
gitlabTool.UpdateRepoFile(projectId,"${env.projectName}%2fvalues.yaml",base64Content, "master")
} catch(e){
gitlabTool.CreateRepoFile(projectId,"${env.projectName}%2fvalues.yaml",base64Content, "master")
}
}
}
}
Helm 打包阶段:
stage("HelmPackage"){
steps{
script{
// helm pakcage & push harbor
//download helm git repo
myTool.GetCode("master", "http://192.168.1.200:8076/devops5/devops5-helm-charts.git")
//helm package
chartVersion = "${env.branchName}".split("-")[-1]
sh "helm package ${env.projectName} –version ${chartVersion}"
//push package
sh "helm cm-push ${env.projectName}-${chartVersion}.tgz harborrepo"
}
}
}
2.2 CD流水线设计与实现

下载chart仓库
stage("GetHelmChart"){
steps{
script{
//下载helm chart
env.chartVersion = "${env.releaseVersion}".split("-")[-1]
sh """
helm repo update
helm pull harborrepo/${env.projectName} –version ${env.chartVersion}
"""
}
}
}
helm发布应用
- 创建名称空间,打包,获取REVISION历史(便于回滚)
stage("DeployAPP"){
steps{
script{
env.namespace = "${env.groupName}"
sh """
## 发布应用
helm upgrade –install –create-namespace "${env.projectName}" ./"${env.projectName}"-${env.chartVersion}.tgz -n ${env.namespace}
helm history "${env.projectName}" -n ${env.namespace}
"""
// 获取应用状态
5.times{
sh "sleep 2; kubectl -n ${env.namespace} get pod | grep ${env.projectName}"
}
//收集history
env.revision = sh returnStdout: true,
script: """helm history ${env.projectName} -n ${env.namespace} | grep -v 'REVISION' | awk '{print \\$1}' """
println("${env.revision}")
println("${env.revision.split('\\n').toString()}")
env.REVISION = "${env.revision.split('\\n').toString()}"
println("${env.REVISION}")
}
}
}
回滚步骤
- 交互式用户选择REVISION, 触发Helm rollback;
stage("CheckHealth"){
steps{
script{
result = sh returnStdout: true, script: """ curl "http://${env.domainName}/health" """
if (result == "ok\\n"){
println("success!")
}
}
}
}
stage("RollOut"){
input {
message "是否进行回滚"
ok "提交"
submitter ""
parameters {
choice(choices: ['yes', 'no'], name: 'opts')
}
}
steps{
script{
switch("${opts}") {
case "yes":
def result = input message: "选择回滚版本?",
parameters: [choice(choices: env.REVISION, name: 'rversion')]
println("${result}")
sh "helm rollback ${env.projectName} ${result} -n ${env.namespace} "
break
case "no":
break
}
}
}
}
三、ArgoCD实践
安装部署
## apply
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
## 查看部署状态
[root@master ~]# kubectl get pod -n argocd
NAME READY STATUS RESTARTS AGE
argocd-application-controller-0 1/1 Running 0 64m
argocd-dex-server-77dd4b844b-tkpxh 1/1 Running 0 64m
argocd-redis-74d8c6db65-b9dl9 1/1 Running 0 64m
argocd-repo-server-5674b858d5-255cc 1/1 Running 0 64m
argocd-server-59964ffc7d-szg4c 1/1 Running 0 64m
## 使用nodePort
kubectl patch svc argocd-server -p '{"spec": {"type": "NodePort"}}' -n argocd
## 默认情况下 admin 帐号的初始密码是自动生成的,会以明文的形式存储在 Argo CD 安装的命名空间中名为 password 的 Secret 对象下的 argocd-initial-admin-secret 字段下,我们可以用下面的命令来获取
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d && echo



连接K8s集群
Argo CD 支持部署应用到多集群,所以如果你要将应用部署到外部集群的时候,需要先将外部集群的认证信息注册到 Argo CD 中,如果是在内部部署(运行 Argo CD 的同一个集群,默认不需要配置),应该使用 https://kubernetes.default.svc 作为应用的 K8S APIServer 地址。
## 下载客户端工具
curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
chmod +x /usr/local/bin/argocd
## 添加集群
[root@master ~]# argocd-linux-amd64 login 192.168.1.230:30248
WARNING: server is not configured with TLS. Proceed (y/n)? y
Username: admin
Password:
'admin:login' logged in successfully
Context '192.168.1.230:30248' updated
## 列出当前 kubeconfig 中的所有集群上下文:
[root@master ~]# kubectl config get-contexts -o name
kubernetes-admin@kubernetes
## 注册集群
[root@master ~]# argocd-linux-amd64 cluster add kubernetes-admin@kubernetes
WARNING: This will create a service account `argocd-manager` on the cluster referenced by context `kubernetes-admin@kubernetes` with full cluster level admin privileges. Do you want to continue [y/N]? y
INFO[0002] ServiceAccount "argocd-manager" already exists in namespace "kube-system"
INFO[0002] ClusterRole "argocd-manager-role" updated
INFO[0002] ClusterRoleBinding "argocd-manager-role-binding" updated
Cluster 'https://192.168.10.100:6443' added

添加Git Repo



创建APP

四、发布策略(扩展)
滚动更新
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 ## 最多1个pod处于不可工作状态
maxSurge: 2 ## 升级时可以比预期多出2个pod
minReadySeconds: 5 ## 容器启动后等待5秒
蓝绿发布
创建新的部署,然后修改service的标签来将流量指向新的部署。
[root@master b-g]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginxapp-1.19-bdb8dc6c4-2jfsw 1/1 Running 0 12m
nginxapp-1.19-bdb8dc6c4-79qrh 1/1 Running 0 12m
nginxapp-1.19-bdb8dc6c4-hbwkx 1/1 Running 0 12m
nginxapp-1.20-786464458-4zh5t 1/1 Running 0 91s
nginxapp-1.20-786464458-5bfwq 1/1 Running 0 91s
nginxapp-1.20-786464458-fwgxb 1/1 Running 0 91s
v1.1.4-blue.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
labels:
k8s-app: devops4-ops-service
version: "1.1.4"
name: devops4-ops-service-blue
namespace: devops4
spec:
replicas: 3
revisionHistoryLimit: 10
selector:
matchLabels:
k8s-app: devops4-ops-service
version: "1.1.4"
template:
metadata:
labels:
k8s-app: devops4-ops-service
version: "1.1.4"
namespace: devops4
name: devops4-ops-service
spec:
containers:
– name: devops4-ops-service
image: 192.168.1.200:8088/devops4/devops4-ops-service:RELEASE-1.1.4-c6b176ad
imagePullPolicy: IfNotPresent
ports:
– containerPort: 8080
name: web
protocol: TCP
serviceAccountName: devops4-ops-service
—
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
k8s-app: devops4-ops-service
name: devops4-ops-service
service.yaml
apiVersion: v1
kind: Namespace
metadata:
name: devops4
—
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
namespace: devops4
spec:
rules:
– host: devops4.ops.service
http:
paths:
– pathType: Prefix
path: "/"
backend:
service:
name: devops4-ops-service
port:
number: 8080
—
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: devops4-ops-service
name: devops4-ops-service
namespace: devops4
spec:
type: ClusterIP
ports:
– name: web
port: 8080
targetPort: 8080
selector:
k8s-app: devops4-ops-service
version: "1.1.4"
v1.1.5-green.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
labels:
k8s-app: devops4-ops-service
version: "1.1.5"
name: devops4-ops-service-green
namespace: devops4
spec:
replicas: 3
revisionHistoryLimit: 10
selector:
matchLabels:
k8s-app: devops4-ops-service
version: "1.1.5"
template:
metadata:
labels:
k8s-app: devops4-ops-service
version: "1.1.5"
namespace: devops4
name: devops4-ops-service
spec:
containers:
– name: devops4-ops-service
image: 192.168.1.200:8088/devops4/devops4-ops-service:RELEASE-1.1.5-bc630338
imagePullPolicy: IfNotPresent
ports:
– containerPort: 8080
name: web
protocol: TCP
serviceAccountName: devops4-ops-service
—
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
k8s-app: devops4-ops-service
name: devops4-ops-service
启动busybox容器调试(废弃)
kubectl run –restart=Never -it –image \\
infoblox/dnstools dnstools
修改流量(service)
kubectl patch svc devops4-ops-service -p '{"spec":{"selector":{"version": "1.1.5"}}}' -n devops4
测试验证
curl http://devops4.ops.service/hello
灰度发布
https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#canary
1.1.4
apiVersion: v1
kind: Namespace
metadata:
name: devops4
—
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress-1-4
namespace: devops4
spec:
rules:
– host: devops4.ops.service
http:
paths:
– pathType: Prefix
path: "/"
backend:
service:
name: devops4-ops-service-1-4
port:
number: 8080
—
kind: Deployment
apiVersion: apps/v1
metadata:
labels:
k8s-app: devops4-ops-service
name: devops4-ops-service-1-4
namespace: devops4
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
k8s-app: devops4-ops-service
template:
metadata:
labels:
k8s-app: devops4-ops-service
namespace: devops4
name: devops4-ops-service
spec:
containers:
– name: devops4-ops-service
image: 192.168.1.200:8088/devops4/devops4-ops-service:RELEASE-1.1.4-c6b176ad
imagePullPolicy: IfNotPresent
ports:
– containerPort: 8080
name: web
protocol: TCP
serviceAccountName: devops4-ops-service
—
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
k8s-app: devops4-ops-service
name: devops4-ops-service
namespace: devops4
—
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: devops4-ops-service
name: devops4-ops-service-1-4
namespace: devops4
spec:
type: ClusterIP
ports:
– name: web
port: 8080
targetPort: 8080
selector:
k8s-app: devops4-ops-service
1.1.5
apiVersion: v1
kind: Namespace
metadata:
name: devops5
—
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
namespace: devops5
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-cookie: "from"
spec:
rules:
– host: devops4.ops.service
http:
paths:
– pathType: Prefix
path: "/"
backend:
service:
name: devops4-ops-service-1-5
port:
number: 8080
—
kind: Deployment
apiVersion: apps/v1
metadata:
labels:
k8s-app: devops4-ops-service
name: devops4-ops-service
namespace: devops5
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
k8s-app: devops4-ops-service
template:
metadata:
labels:
k8s-app: devops4-ops-service
namespace: devops5
name: devops4-ops-service
spec:
containers:
– name: devops4-ops-service
image: 192.168.1.200:8088/devops4/devops4-ops-service:RELEASE-1.1.5-bc630338
imagePullPolicy: IfNotPresent
ports:
– containerPort: 8080
name: web
protocol: TCP
serviceAccountName: devops4-ops-service
—
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
k8s-app: devops4-ops-service
name: devops4-ops-service
namespace: devops5
—
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: devops4-ops-service
name: devops4-ops-service-1-5
namespace: devops5
spec:
type: ClusterIP
ports:
– name: web
port: 8080
targetPort: 8080
selector:
k8s-app: devops4-ops-service
创建资源:
[root@zeyang-nuc-service canary]# kubectl get all -n devops4
NAME READY STATUS RESTARTS AGE
pod/devops4-ops-service-1-4-7f97cb665c-vcntl 1/1 Running 0 16m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/devops4-ops-service-1-4 ClusterIP 10.96.65.65 <none> 8080/TCP 16m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/devops4-ops-service-1-4 1/1 1 1 16m
NAME DESIRED CURRENT READY AGE
replicaset.apps/devops4-ops-service-1-4-7f97cb665c 1 1 1 16m
[root@zeyang-nuc-service canary]# kubectl get all -n devops5
NAME READY STATUS RESTARTS AGE
pod/devops4-ops-service-5fbfb57777-6hc62 1/1 Running 0 15m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/devops4-ops-service-1-5 ClusterIP 10.96.64.251 <none> 8080/TCP 15m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/devops4-ops-service 1/1 1 1 15m
NAME DESIRED CURRENT READY AGE
replicaset.apps/devops4-ops-service-5fbfb57777 1 1 1 15m
测试:
## 编辑hosts文件
192.168.10.100 devops4.ops.service
for i in {1..10};do curl devops4.ops.service/hello ;done
基于权重的发布
<1.19.0
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-ingress
namespace: devops4
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
rules:
– host: devops4.ops.service
http:
paths:
– path: /
backend:
serviceName: devops4-ops-service
servicePort: 8080
Header报头流量分发
<1.19.0
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-ingress
namespace: devops4
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "Region"
nginx.ingress.kubernetes.io/canary-by-header-value: "bj"
spec:
rules:
– host: devops4.ops.service
http:
paths:
– path: /
backend:
serviceName: devops4-ops-service
servicePort: 8080
>1.19.0
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
namespace: devops4
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "Region"
nginx.ingress.kubernetes.io/canary-by-header-value: "bj"
spec:
rules:
– host: devops4.ops.service
http:
paths:
– pathType: Prefix
path: "/"
backend:
service:
name: devops4-ops-service
port:
number: 8080
for i in {1..10};do curl -H "region: bj" devops4.ops.service/hello;done
根据cookie流量分发
<1.19.0
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-ingress
namespace: devops4
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-cookie: "from"
spec:
rules:
– host: devops4.ops.service
http:
paths:
– path: /
backend:
serviceName: devops4-ops-service
servicePort: 8080
>1.19.0
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
namespace: devops4
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-cookie: "from"
spec:
rules:
– host: devops4.ops.service
http:
paths:
– pathType: Prefix
path: "/"
backend:
service:
name: devops4-ops-service
port:
number: 8080
[root@master ingress-gray]# curl devops4.ops.service/hello –cookie "from=always"
1.1.5
[root@master ingress-gray]# curl devops4.ops.service/hello –cookie "from=a"
1.1.4
[root@master ingress-gray]# curl devops4.ops.service/hello –cookie "from=a"
1.1.4



