本章概述
- K8S集群镜像更新
- 结合k8s实现CI/CD
- 基于脚本实现代码部署与回滚案例
- 蓝绿发布和灰度发布
CI/CD说明
CI:持续集成,开发持续更新代码,常用工具:svn(早期),gitlab
CD:持续部署,运维将集成代码部署到环境中,常用工具:jenkins
14.1 K8S集群镜像更新
14.1.1 镜像更新方式
常见的更新方式有三大类。
1、更新yaml
2、kubecetl set image
3、API调用
注意:为了便于演示效果,这里准备了几个测试镜像,这些镜像已经上传到阿里云镜像仓库,可以直接下载
分别是:
registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v1
registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v2
registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v3
registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v4
registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v5
然后创建pod
vim
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app1-deployment-label
name: magedu-tomcat-app1-deployment
namespace: magedu
spec:
replicas: 3
selector:
matchLabels:
app: magedu-tomcat-app1-selector
template:
metadata:
labels:
app: magedu-tomcat-app1-selector
spec:
containers:
- name: magedu-tomcat-app1-container
image: registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v1
#command: ["/apps/tomcat/bin/run_tomcat.sh"]
imagePullPolicy: IfNotPresent
#imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
resources:
limits:
cpu: 1
memory: "512Mi"
requests:
cpu: 500m
memory: "512Mi"
volumeMounts:
- name: magedu-images
mountPath: /usr/local/nginx/html/webapp/images
readOnly: false
- name: magedu-static
mountPath: /usr/local/nginx/html/webapp/static
readOnly: false
volumes:
- name: magedu-images
nfs:
server: 172.31.7.109
path: /data/k8sdata/magedu/images
- name: magedu-static
nfs:
server: 172.31.7.109
path: /data/k8sdata/magedu/static
---
kind: Service
apiVersion: v1
metadata:
labels:
app: magedu-tomcat-app1-service-label
name: magedu-tomcat-app1-service
namespace: magedu
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
nodePort: 30092
selector:
app: magedu-tomcat-app1-selector
查看pod
为了便于查看版本更新效果,我们在另外一台主机或另起一个窗口一直访问tomcat服务
14.1.1.1 更新yaml文件
1、更新yaml文件中image的版本,然后kubectl apply -f app.yaml
将yaml文件中的镜像版本从registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v1更新为registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v2
然后重新apply,查看效果
在版本更新时,容器新建过程中会出现新旧版本共存的现象
当容器完全新建完成后,版本会全部更新为v2版本
注意:curl命令过程中可能会存在一些报错,这是因为在版本升级过程中,容器需要重建,curl命令无法获取服务导致的报错,后续添加就绪探针就可以避免此类报错
14.1.1.2 通过命令更新
使用kubectl命令实现镜像更新及回滚:
镜像更新命令格式为:
kubectl set image deployment/deployment-name container-name=image -n namespace
命令格式:kubectl set image deployment/deployment名称 容器名=容器镜像 -n namespace
执行命令如下:kubectl set image deployment/magedu-tomcat-app1-deployment magedu-tomcat-app1-container=registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v3 -n magedu
查看另一个窗口,curl命令输出结果:
可以看到镜像版本从v2升级v3
注意:curl命令过程中存在一些报错,这是因为在版本升级过程中,容器需要重建,旧版本容器会被删除,删除后curl命令无法获取服务导致的报错,后续添加就绪探针就可以避免此类报错
查看升级历史版本信息:
kubectl rollout history deployment/magedu-tomcat-app1-deployment -n magedu
当前存在1、2、3 共三个版本
回退到上一个版本:
kubectl rollout undo deployment/magedu-tomcat-app1-deployment -n magedu
查看curl命令输出结果,回退到v2版本
再次查看rollout历史版本,2变成了4,现存1、3、4三个版本
注意:版本回滚是基于当前版本,回退到上一版本,当前的REVISION是4,镜像版本是v2,如果再次回滚,将会回退到REVISION是3,镜像版本是v3。
kubectl rollout undo deployment/magedu-tomcat-app1-deployment -n magedu
镜像版本从v2回滚到v3,而不是回滚到v1
回退到指定版本:
有两种方式:
方法一:通过--to-revision,回退至某个指定版本
kubectl rollout undo deployment/magedu-tomcat-app1-deployment --to-revision=1 -n magedu
方法二:通过kubectl set image命令将当前版本升级至某个旧的版本,类似于变相的版本回退,命令为:kubectl set image deployment/magedu-tomcat-app1-deployment magedu-tomcat-app1-container=registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v1 -n magedu
版本从v3直接回退到指定的v1版本
14.1.1.3 通过调用API更新
开发debops平台调用API更新
调度流程图:
调度流程:
(1)jenkins配置任务从gitlab拉取开发上传代码
(2)在maven上进行编译
(3)编译完成后上传dockerfile,打成镜像
(4)上传harbor私有镜像仓库
(5)jenkins调用kubernetes api接口在k8s集群内部进行镜像版本更新
版本升级有两种方式:
(1)jenkins ssh远程到k8s集群内部执行k8s原生命令kubectl set image进行版本升级
(2)jenkins使用模块调用k8s的api进行升级
这里通过脚本调用API接口实现版本更新
环境准备:
准备一台机器:172.31.7.155
以下命令在172.31.7.155上执行:
1、安装工具和依赖:
#yum -y install python3-pip #安装pip
#pip3 install --upgrade pip #更新pip版本
#pip3 install kubernetes #安装kubernetes模块、
#mkdir /data/.kube -p
#scp 172.31.7.101:/root/.kube/config /data/.kube/ #将k8s集群的认证文件复制到jenkins主机,便于jenkins连接k8s集群执行命令
2、准备Python脚本用于版本更新
vim 1.update-image.py
#!/usr/bin/env python
#coding:utf-8
#Author:Zhang ShiJie
import os
from kubernetes import client, config
from kubernetes.client.rest import ApiException
#拼接要更新的namespace、deployment name及目的镜像为一个请求body
def update_deployment_image(namespace,deployment_name,update_image):
body = api_instance.read_namespaced_deployment(deployment_name,namespace)
#指定deployment下pod中第一个container的镜像
body.spec.template.spec.containers[0].image = update_image
return body
#执行镜像更新并打印response信息
def replace_deployment(deployment_name,namespace,body):
try:
api_response = api_instance.replace_namespaced_deployment(deployment_name,namespace,body)
#print(api_response)
print("\033[0;32mnamespace:{}, deployment:{},当前镜像版本:{}, 更新完成!!!\033[0m".format(namespace,deployment_name,update_image))
except ApiException as e:
print("Exception when calling AppsV1Api->replace_namespaced_deployment: %s\n" % e)
if __name__ == "__main__":
#kubernetes的认证文件,一般位于master节点的/root/.kube/config
kube_conf = os.path.join('/data/.kube/config')
config.load_kube_config(kube_conf)
api_instance = client.AppsV1Api()
#配置更新参数,指定要更新的namespace、deployment name及目的镜像名称
namespace = 'magedu'
deployment_name = 'magedu-tomcat-app1-deployment'
update_image = 'registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v4'
#调用update_deployment_image函数
body = update_deployment_image(namespace,deployment_name,update_image)
#调用replace_deployment执行镜像更新并打印response信息
replace_deployment(deployment_name, namespace, body)
执行python脚本,进行镜像更新
python3 1.update-image.py
然后查看另一个窗口的curl命令输出结果,镜像版本从v1变成了v4
可以通过jenkins传参实现通过脚本进行版本更新
14.1.2 暂停更新与恢复更新:
便于观察更新效果,可以暂停更新,查看容器版本更新效果,有一定的灰度作用
官网链接:Deployments | Kubernetes
kubectl rollout pause deployment magedu-tomcat-app1-deployment -n magedu #暂停更新
kubectl rollout resume deployment magedu-tomcat-app1-deployment -n magedu #恢复更新
示例:
将镜像版本设置为v3版本,在镜像更新过程中执行暂停命令,查看效果
(1)设置镜像版本为v3kubectl set image deployment/magedu-tomcat-app1-deployment magedu-tomcat-app1-container=registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v3 -n magedu
(2)暂停更新
kubectl rollout pause deployment magedu-tomcat-app1-deployment -n magedu
查看效果,此时v3和v4版本共存
恢复更新:
kubectl rollout resume deployment magedu-tomcat-app1-deployment -n magedu
查看效果,全部更新为v3版本
14.1.3 镜像更新类型
14.1.3.1 Recreate(重建更新)
重建更新Recreate:
先删除现有的pod,然后基于新版本的镜像重建,Pod重建期间服务是不可用的,其优势是同时只有一个版本在线,不会产生多版本在线问题,缺点是pod删除后到pod重建成功中间的时间会导致服务无法访问,因此较少使用。
具体流程为先删除旧版本Pod,然后deployment控制器再新建一个ReplicaSet控制器并基于新版本镜像创建新的Pod。
旧版本的ReplicaSet控制会保留用于版本回退。
示例:
vim 1.tomcat-app1-Recreate.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app1-deployment-label
name: magedu-tomcat-app1-deployment
namespace: magedu
spec:
replicas: 2
strategy:
type: Recreate #指定镜像更新策略为重建更新Recreate
selector:
matchLabels:
app: magedu-tomcat-app1-selector
template:
metadata:
labels:
app: magedu-tomcat-app1-selector
spec:
containers:
- name: magedu-tomcat-app1-container
image: registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v1
#command: ["/apps/tomcat/bin/run_tomcat.sh"]
#imagePullPolicy: IfNotPresent
imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
resources:
limits:
cpu: 1
memory: "512Mi"
requests:
cpu: 500m
memory: "512Mi"
startupProbe: #指定启动探针
httpGet:
path: /myapp/index.html
port: 8080
initialDelaySeconds: 5 #首次检测延迟5s
failureThreshold: 3 #从成功转为失败的次数
periodSeconds: 3 #探测间隔周期
readinessProbe: #指定就绪探针
httpGet:
#path: /monitor/monitor.html
path: /myapp/index.html
port: 8080
initialDelaySeconds: 5
periodSeconds: 3
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
livenessProbe:
httpGet:
#path: /monitor/monitor.html
path: /myapp/index.html
port: 8080
initialDelaySeconds: 5
periodSeconds: 3
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
---
kind: Service
apiVersion: v1
metadata:
labels:
app: magedu-tomcat-app1-service-label
name: magedu-tomcat-app1-service
namespace: magedu
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
nodePort: 30092
selector:
app: magedu-tomcat-app1-selector
1、创建pod
kubectl apply -f 1.tomcat-app1-Recreate.yaml
查看另一个窗口curl命令结果
2、进行版本更新,更新到v2版本:
kubectl set image deployment/magedu-tomcat-app1-deployment magedu-tomcat-app1-container=registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v2 -n magedu
查看pod状态,一旦进行更新,所有pod都会被重建
此时,外部访问均会被拒绝
因此,重建更新方式,pod在更新过程中无法访问,直到pod重建完成
14.1.3.2 RollingUpdate(滚动更新)
滚动更新(RollingUpdate):
滚动更新是默认的更新策略,滚动更新是新建一个ReplicaSet并基于新版本镜像创建一部分新版本的pod,然后删除一部分旧版本的Pod,然后再创建新一部分版本Pod,再删除一部分旧版本Pod,直到旧版本Pod删除完成,滚动更新优势是在升级过程当中不会导致服务不可用,缺点是升级过程中会导致新版本和旧版本两个版本在短时间内的并存。
具体升级过程是在执行更新操作后k8s会再创建一个新版本的ReplicaSet控制器,再删除旧版本的ReplicaSet控制器下的一部分Pod的同时会在新版本的ReplicaSet控制器下创建新的Pod,直到旧版本的Pod全部被删除完成。
旧版本的ReplicaSet控制会保留用于版本回退。
注意:由于滚动更新是先新建pod,待pod拉起可用后再删除旧的pod,因此在更新过程中,允许pod数临时超出yaml文件配置的pod数,如:yaml文件配置pod副本数为10,在滚动更新过程中,pod数会超出10个。
镜像更新类型-RollingUpdate更新过程:
在执行滚动更新时,为了保证服务的可用性,当前控制器内不可用的pod(pod需要拉取镜像执行创建和执行探针探测期间是不可用的)不能超出一定范围,因此需要至少保留一定数量的pod以保证服务可以被客户端正常访问,可以通过以下参数指定:
kubectl explain deployment.spec.strategy
deployment.spec.strategy.rollingUpdate.maxSurge #指定在升级期间pod总数可以超出定义好的期望pod数量或者百分比,maxSurge如果是百分比会向上取pod整数,默认为25%,如果设置为10%,假如当前是100个pod,那么升级时最多将创建110个pod即额外有10%的pod临时会超出当前(replicas)指定的副本数限制。
deployment.spec.strategy.rollingUpdate.maxUnavailable #指定在升级期间最大不可用的pod数(不为整则向下取整)当前pod的百分比,而maxUnavailable如果是百分比则向下取pod整数,默认是25%,假如当前是100个pod,那么升级时最多可以有25个(25%)pod不可用即还要75个(75%)pod是可用的。
注意:以上两个值不能同时为0,如果maxUnavailable最大不可用pod为0,maxSurge超出pod数也为0,那么将会导致pod无法进行滚动更新。
假如副本数正好是10个,maxSurge和maxUnavailable的值都是默认的25%。
1、可超出指定pod副本数的数量为10x25%=2.5,向上取整为3,即可超出的pod数为3
2、不可用pod副本数的数量为10x2.5%=2.5,向下取整为2,即不可用pod数为2,则可用pod副本数为10-2=8
那么,更新过程中,pod总数为:指定副本数10+可超出pod数3=13,整体不可用pod数为13-8=5台
因此,如果有10个pod,在基于RollingUpdate升级过程中会出现13个pod,其中8个可用的以及5个不可用的,直到滚动全部更新后恢复10个。
示例:
vim 2.tomcat-app1-RollingUpdate.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app1-deployment-label
name: magedu-tomcat-app1-deployment
namespace: magedu
spec:
replicas: 3 #指定副本数为3
strategy:
type: RollingUpdate #指定镜像更新策略为滚动更新
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
selector:
matchLabels:
app: magedu-tomcat-app1-selector
template:
metadata:
labels:
app: magedu-tomcat-app1-selector
spec:
containers:
- name: magedu-tomcat-app1-container
image: registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v1
#command: ["/apps/tomcat/bin/run_tomcat.sh"]
#imagePullPolicy: IfNotPresent
imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
resources:
limits:
cpu: 1
memory: "512Mi"
requests:
cpu: 500m
memory: "512Mi"
startupProbe:
httpGet:
path: /myapp/index.html
port: 8080
initialDelaySeconds: 15 #首次检测延迟5s
failureThreshold: 3 #从成功转为失败的次数
periodSeconds: 3 #探测间隔周期
readinessProbe:
httpGet:
#path: /monitor/monitor.html
path: /myapp/index.html
port: 8080
initialDelaySeconds: 15
periodSeconds: 3
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
livenessProbe:
httpGet:
#path: /monitor/monitor.html
path: /myapp/index.html
port: 8080
initialDelaySeconds: 15
periodSeconds: 3
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
---
kind: Service
apiVersion: v1
metadata:
labels:
app: magedu-tomcat-app1-service-label
name: magedu-tomcat-app1-service
namespace: magedu
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
nodePort: 30092
selector:
app: magedu-tomcat-app1-selector
1、创建pod
kubectl apply -f 2.tomcat-app1-RollingUpdate.yaml
查看另一个窗口curl命令结果
2、进行版本更新,更新到v2版本:kubectl set image deployment/magedu-tomcat-app1-deployment magedu-tomcat-app1-container=registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v2 -n magedu
查看pod状态
一旦进行更新,pod会新建1个pod,更新完成后,再删除旧的pod
3、新建1个pod的原因:
yaml文件指定3个副本,3x25%=0.75,向上取整为1,因此可超出1个pod
更新过程中创建pod总数为4,可用pod为3,不可用pod为1
在pod滚动更新过程中,由于配置了就绪探针,当探测到后端服务不可用时,会将pod从service上摘除,当更新完成后,就绪探针探测成功,会再将后端pod加入service,因此服务不会中断。但是会存在v1和v2版本共存的现象
滚动更新完成后,双版本共存的现象消失,更新为v2版本
14.2 结合k8s实现CI/CD
环境准备:
由于CI/CD会用到gitlab和jenkins,因此准备两台主机,分别安装gitlab和jenkins
gitlab地址:172.31.7.156(gitlab节点内存要求不能低于2G)
jenkins地址:172.31.7.155
14.2.1 安装gitlab
1、下载gitlab安装包并安装gitlab
cd /root
wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-14.2.5-ce.0.el7.x86_64.rpm
yum -y install gitlab-ce-14.2.5-ce.0.el7.x86_64.rpm
2、对gitlab配置进行更改
(1)修改配置
vim /etc/gitlab/gitlab.rb
external_url 'http://172.31.7.156' #指定gitlab地址,这里指向本机地址
#如果要配置邮件通知,可以加上以下配置
gitlab_rails['smtp_enable'] = true #开启smtp
gitlab_rails['smtp_address'] = "smtp.qq.com" #smtp的地址,这里使用qq邮箱
gitlab_rails['smtp_port'] = 465 #端口
gitlab_rails['smtp_user_name'] = "xxxx@qq.com" #指定接收告警的邮箱
gitlab_rails['smtp_password'] = "zdhudwexecjbdhda" #qq邮箱授权码
gitlab_rails['smtp_domain'] = "qq.com" #域名
gitlab_rails['smtp_authentication'] = :login #认证方式,通过登录认证
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_tls'] = true #开启ssl
gitlab_rails['gitlab_email_from'] = "2973707860@qq.com" #指定收件邮箱
user["git_user_email"] = "2973707860@qq.com" #指定git用户邮箱
如何获取qq邮箱授权码
登录qq邮箱—选择设置
选择账户
开启POP3/SMTP服务,点击下方生成授权码
编辑发送短信后,点击我已发送
获取生成的授权码
(2)配置完成后,重新加载配置
gitlab-ctl reconfigure
执行命令后,会进行环境初始化,需要等待3-5分钟左右。
(3)执行完成后,查看输出结果获取登录的初始密码
图1:
图2:
3、登录gitlab
(1)浏览器输入gitlab地址:172.31.7.156,登录gitlab
账号:root
密码:1S0wAT/B32Cx6CXjQJnjeGEuMsq2okG3L+HjosOxBk8= #刚才获取的初始密码
(2)更改密码
图1:
图2:
密码改完后需要再次进行登录,输入新的密码即可登录
(3)设置中文显示
选择简体中文
保存后刷新页面,显示为中文
4、创建组
(1)点击菜单,选择admin
(2)创建新组(一个组为一个项目)
(3)设置组名为magedu,其他保持默认
5、创建project
(1)点击菜单,选择admin
图1:
图2:
(2)新建空的project
Project name:填写App1
Project URL:在下拉列表选择magedu
Project slug:填写app1
(3)填写完成后,点击下方creata project
此时,一个空的project被创建出来
6、创建模板文件
(1)点击README.md进行修改
图1:
图2:
(2)将README.md重命名为index.html,并添加文件内容,然后点击现房commit change进行保存
修改内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test page</title>
</head>
<body>
<h1>当前版本v1111</h1>
</body>
</html>
如下图所示:
7、验证
在jenkins主机使用git命令验证是否可以正常上传下载代码
(1)获取代码clone地址,登录gitlab获取代码clone地址
图1:
图2:
复制地址
(2)jenkins主机下载代码
a、安装git命令
yum -y install git
b、通过命令clone代码到本地
cd /root
git clone http://172.31.7.156/magedu/app1.git
c、在当前目录下会生成app1目录,app1目录下为index.html,其内容正是在gitlab上输入的内容,说明可以正常下载代码
(3)jenkins主机上传
在本地修改index.html内容,然后上传gitlab
cd /root/app1
vim index,html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test page</title>
</head>
<body>
<h1>当前版本v1111</h1>
<h1>当前版本v2222</h1>
</body>
</html>
如下图所示:
上传代码到gitlab
#git add .
#git commit -m "v2" #添加备注信息为v2版本
注意:这里执行git commit命令可能会存在以下提示,无法正常执行命令:
注意:此时出现以上报错信息,要添加邮箱和用户。但该邮箱和用户并不是做认证用的,而是一个格式验证,因此可以不用填写真是邮箱和用户
报错解决方法:
方法一:通过命令解决
git config --global user.email "XXX@qq.com"
git config --global user.name "XXX"
方法二:修改配置文件
vim /root/app1/.git/config #注意这里的/root/app1为clone代码到本地时自动生成的目录
手动添加以下三行内容保存即可。
修改完成后再次执行git commit命令
git push
注意:执行git push命令后需要输入gitlab账号和密码
在gitlab查看提交的index.html文件内容是否发生变化
备注信息变更为v2
查看index.html内容为最新内容,说明可以正常上传代码
14.2.2 安装jenkins
1、jenkins依赖java,先安装java(java8也可以,这里安装java11)
yum -y install java-11-openjdk
安装完成后进行验证
java -version
2、下载并安装jenkins
(1)下载jenkins
cd /root
wget https://mirrors.tuna.tsinghua.edu.cn/jenkins/redhat-stable/jenkins-2.303.3-1.1.noarch.rpm --no-check-certificate
(2)安装jenkins
yum -y install jenkins-2.303.3-1.1.noarch.rpm
注意:如果不使用yum安装,需要先安装jenkins依赖包daemonize,然后再安装jenkins
如果是ubuntu系统会自动拉起jenkins,要先停止jenkins服务,方便后续配置文件的修改
3、修改jenkins配置文件并重启服务
vim /etc/sysconfig/jenkins
JENKINS_USER="root" #为了便于实验,将jenkins用户更改为root,如果是生产环境则使用jenkins用户
JENKINS_ARGS="-Dhudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=true" #添加参数,当需要配置webhook(即一旦有代码提交就让jenkins执行代码构建,让gitlab远程触发jenkins),要实现该功能,需要加上该参数,否则会报403
启动jenkins服务
systemctl start jenkins
4、在浏览器访问jenkins
浏览器输入172.31.7.155:8080,在本机获取jenkins密码并输入,进入下一页面
5、jenkins初始化
(1)安装插件
如果是新手,可以根据推荐安装插件,如果对jenkins比较熟悉,则可以根据需求来安装插件。
自动安装插件:(插件安装成功显示为绿色,安装失败为红色)
注意:如果jenkins不能联网,无法下载插件,可以使用一台可以联网的jenkins把插件下载完成后,复制到当前不能联网jenkins的/var/lib/jenkins/plugins/目录下,也可以正常记载。不过要保证jenkins版本一致。
(2)创建账号和密码
这里不用改动,下一步
(3)开始使用jenkins
进入主界面
这时需要重启jenkins,加载刚才下载的插件,然后重新刷新jenkins页面
systemctl restart jenkins
14.3 基于脚本实现代码部署与回滚案例
这里共有两个脚本,一个是python脚本,一个shell脚本
14.3.1 通过python脚本更新和回滚示例
1、在jenkins主机创建脚本
mkdir /data/scripts -p
vim /data/scripts/magedu-n66-app1-deploy.py
#!/usr/bin/env python
#coding:utf-8
#Author:Zhang ShiJie
import os
from kubernetes import client, config
from kubernetes.client.rest import ApiException
#拼接要更新的namespace、deployment name及目的镜像为一个请求body
def update_deployment_image(namespace,deployment_name,update_image):
body = api_instance.read_namespaced_deployment(deployment_name,namespace)
#指定deployment下pod中第一个container的镜像
body.spec.template.spec.containers[0].image = update_image
return body
#执行镜像更新并打印response信息
def replace_deployment(deployment_name,namespace,body):
try:
api_response = api_instance.replace_namespaced_deployment(deployment_name,namespace,body)
#print(api_response)
print("\033[0;32mnamespace:{}, deployment:{},当前镜像版本:{}, 更新完成!!!\033[0m".format(namespace,deployment_name,update_image))
except ApiException as e:
print("Exception when calling AppsV1Api->replace_namespaced_deployment: %s\n" % e)
if __name__ == "__main__":
#kubernetes的认证文件,一般位于master节点的/root/.kube/config
kube_conf = os.path.join('/data/.kube/config')
config.load_kube_config(kube_conf)
api_instance = client.AppsV1Api()
#配置更新参数,指定要更新的namespace、deployment name及目的镜像名称
namespace = 'magedu'
deployment_name = 'magedu-tomcat-app1-deployment'
update_image = 'registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v4'
#调用update_deployment_image函数
body = update_deployment_image(namespace,deployment_name,update_image)
#调用replace_deployment执行镜像更新并打印response信息
replace_deployment(deployment_name, namespace, body)
为脚本添加可执行权限
chmod a+x /data/scripts/*
2、在jenkins上创建任务
任务名称:magedu-n66-app1-deploy
选择:构建一个自由风格的软件项目
选择构建触发器
选择执行shell
添加以下内容,然后保存
/usr/bin/python3 /data/scripts/magedu-n66-app1-deploy.py
3、在jenkins主机上将脚本中镜像版本更新为v3,然后在jenkins上执行构建
在jenkins控制台上,选择立即构建
查看控制台输出结果
14.3.2 通过shell脚本更新和回滚示例
14.3.2.1 对gitlab和镜像服务器做免密认证
1、为了便于脚本以非交互方式进行,在gitlab上配置免密认证,jenkins主机以非交互方式做代码clone
(1)在jenkins主机172.31.7.155上生成密钥
ssh-keygen
(2)获取公钥信息:
cat /root/.ssh/id_rsa.pub
公钥内容如下:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC1wi0XW0+NqjBFafxFVWINM0YU+ysHXy6hfUzVn4YmjbbbHZgNkSPfHRgS42Aph3WzW0fwqw0XV7/5ONVmLXbX8AkNADo0oheLBT3W0pxaqKVYWnLkbSbv6OW013VGSBwcPLnlmhSE04aWR/f+/yAvwVwQIIMcmwS30CCH7aZw/s1HPNQRSuM0bYoF5k4v/jkjWIYXy4HyoJorEKsN+UDJXOYkajYmurnLUtE1QFa6gDKG1fWVuLfxtnrtZoWX6GO90EEVbJI8Bi2IFaootYCkgjHLcdy/9/ArA+++QIZS6hmjNoPhtVQWSdqdson7yOLldmJvWP0sEEg5ayHos5vF root@jenkins
(3)把公钥信息放在gitlab上,以便于jenkins可以从gitlab上免密clone代码
登录gitlab
存放jenkins主机的公钥信息
(4)进行验证:在jenkins上通过git协议clone代码
获取git协议代码clone url:git@172.31.7.156:magedu/app1.git
在jenkins主机执行git命令进行代码clone测试:
在/tmp目录下进行测试(不能在root目录下,不能跟之前app1在相同目录)
cd /tmp
git clone git@172.31.7.156:magedu/app1.git
这时不需要输入账号密码就可以clone代码。
2、由于jenkins需要远程到镜像构建服务器(172.31.7.101)执行一系列命令进行镜像更新,因此jenkins需要对镜像构建服务器(172.31.7.101)配置免密认证
在jenkins主机上执行命令
ssh-copy-id 172.31.7.101
14.3.2.2 创建shell脚本
1、在jenkins主机172.31.7.155上创建代码存放目录
mkdir -p /data/gitdata/magedu
2、创建存放脚本目录,并编辑脚本
mkdir /data/scripts -p
vim /data/scripts/magedu-n66-app1-deploy.sh
#!/bin/bash
#Author: ZhangShiJie
#Date: 2018-10-24
#Version: v1
#记录脚本开始执行时间,用于计算脚本执行时间
starttime=`date +'%Y-%m-%d %H:%M:%S'`
#变量
SHELL_DIR="/data/scripts"
SHELL_NAME="$0"
K8S_CONTROLLER1="172.31.7.101"
K8S_CONTROLLER2="172.31.7.102"
DATE=`date +%Y-%m-%d_%H_%M_%S`
METHOD=$1 #设置位置变量,通过输入来控制脚本执行镜像更新还是回滚
Branch=$2 #设置位置变量,通过输入来控制脚本执行镜像更新还是回滚
#判断输入的位置变量,如果不输入,变量为空,则Branch默认等于develop
if test -z $Branch;then
Branch=develop
fi
#进行代码克隆并进行编译
function Code_Clone(){
Git_URL="git@172.31.7.156:magedu/app1.git" #注意要修改gitlab代码的url
DIR_NAME=`echo ${Git_URL} |awk -F "/" '{print $2}' | awk -F "." '{print $1}'` #获取代码在本地生成的目录名称,用于目录切换(即app1项目,在jenkins上生成的/root/app1目录)
DATA_DIR="/data/gitdata/magedu" #指定clone代码的目录
Git_Dir="${DATA_DIR}/${DIR_NAME}" #设置变量,指定本地clone代码时自动生成的目录,即/data/gitdata/magedu/app1,后面用于打包代码
cd ${DATA_DIR} && echo "即将清空上一版本代码并获取当前分支最新代码" && sleep 1 && rm -rf ${DIR_NAME}
echo "即将开始从分支${Branch} 获取代码" && sleep 1
git clone -b ${Branch} ${Git_URL}
echo "分支${Branch} 克隆完成,即将进行代码编译!" && sleep 1
#cd ${Git_Dir} && mvn clean package
#echo "代码编译完成,即将开始将IP地址等信息替换为测试环境"
#####################################################
sleep 1
cd ${Git_Dir}
tar czf ${DIR_NAME}.tar.gz ./* #把代码打包,打成以项目名称命名的tar包
}
#将打包好的压缩文件拷贝到k8s 控制端服务器,这里需要指定构建服务器上存放dockerfile的路径,将代码和dockerfile存放在一块,便于打包镜像,这里路径为172.31.7.101节点的/root/k8s-data/dockerfile/web/magedu/tomcat-app1目录
function Copy_File(){
echo "压缩文件打包完成,即将拷贝到k8s 控制端服务器${K8S_CONTROLLER1}" && sleep 1
scp ${Git_Dir}/${DIR_NAME}.tar.gz root@${K8S_CONTROLLER1}:/root/k8s-data/dockerfile/web/magedu/tomcat-app1
echo "压缩文件拷贝完成,服务器${K8S_CONTROLLER1}即将开始制作Docker 镜像!" && sleep 1
}
#到控制端执行脚本制作并上传镜像,远程到构建服务器执行镜像构建脚本上传镜像到harbor服务器,会调用DATE变量(即执行脚本时的时间)作为镜像版本
function Make_Image(){
echo "开始制作Docker镜像并上传到Harbor服务器" && sleep 1
ssh root@${K8S_CONTROLLER1} "cd /root/k8s-data/dockerfile/web/magedu/tomcat-app1 && bash build-command.sh ${DATE}"
echo "Docker镜像制作完成并已经上传到harbor服务器" && sleep 1
}
#到控制端更新k8s yaml文件中的镜像版本号,从而保持yaml文件中的镜像版本号和k8s中版本号一致,这里存放yaml文件目录为172.31.7.101上/root/k8s-data/yaml/magedu/tomcat-app1目录,注意查看镜像地址是否正确
function Update_k8s_yaml(){
echo "即将更新k8s yaml文件中镜像版本" && sleep 1
ssh root@${K8S_CONTROLLER1} "cd /root/k8s-data/yaml/magedu/tomcat-app1 && sed -i 's/image: harbor.magedu.*/image: harbor.magedu.local\/magedu\/tomcat-app1:${DATE}/g' tomcat-app1.yaml"
echo "k8s yaml文件镜像版本更新完成,即将开始更新容器中镜像版本" && sleep 1
}
#到控制端更新k8s中容器的版本号,有两种更新办法,一是指定镜像版本更新,二是apply执行修改过的yaml文件
function Update_k8s_container(){
#第一种方法
ssh root@${K8S_CONTROLLER1} "kubectl set image deployment/magedu-tomcat-app1-deployment magedu-tomcat-app1-container=harbor.magedu.local/magedu/tomcat-app1:${DATE} -n magedu"
#第二种方法,推荐使用第一种
#ssh root@${K8S_CONTROLLER1} "cd /root/k8s-data/yaml/magedu/tomcat-app1 && kubectl apply -f tomcat-app1.yaml --record"
echo "k8s 镜像更新完成" && sleep 1
echo "当前业务镜像版本: harbor.magedu.local/magedu/tomcat-app1:${DATE}"
#计算脚本累计执行时间,如果不需要的话可以去掉下面四行
endtime=`date +'%Y-%m-%d %H:%M:%S'`
start_seconds=$(date --date="$starttime" +%s);
end_seconds=$(date --date="$endtime" +%s);
echo "本次业务镜像更新总计耗时:"$((end_seconds-start_seconds))"s"
}
#基于k8s 内置版本管理回滚到上一个版本
function rollback_last_version(){
echo "即将回滚之上一个版本"
ssh root@${K8S_CONTROLLER1} "kubectl rollout undo deployment/magedu-tomcat-app1-deployment -n magedu"
sleep 1
echo "已执行回滚至上一个版本"
}
#使用帮助
usage(){
echo "部署使用方法为 ${SHELL_DIR}/${SHELL_NAME} deploy "
echo "回滚到上一版本使用方法为 ${SHELL_DIR}/${SHELL_NAME} rollback_last_version"
}
#主函数
main(){
case ${METHOD} in
deploy)
Code_Clone;
Copy_File;
Make_Image;
Update_k8s_yaml;
Update_k8s_container;
;;
rollback_last_version)
rollback_last_version;
;;
*)
usage;
esac;
}
main $1 $2
3、为脚本添加可执行权限
chmod a+x /data/scrpts/*
注意:该脚本需要传参,来指定进行更新还是回滚
分别有两个参数:
METHOD参数是指对镜像的操作,其值分别是deploy(进行镜像更新)和rollback_last_version(将镜像回滚到上一个版本)
Branch参数是指分支,其值包括main
如何查看分支:
14.3.2.3 脚本验证
1、在jenkins节点上执行脚本进行测试
cd /root/scripts
bash magedu-n66-app1-deploy.sh deploy main #传递两个位置参数,分别是deploy(进行镜像更新)和main(指定代码分支)
2、验证
(1)在镜像构建服务器上查看复制过去的代码包的时间戳是否发生了变化
cd /root/k8s-data/dockerfile/web/magedu/tomcat-app1
ls -lh
app1的tar包已经更新,说明脚本执行代码上传镜像服务器成功。
(2)查看harbor镜像仓库,新版本镜像是否已经上传
可以看到新版本镜像已经上传,说明脚本执行没有问题
(3)查看yaml文件中镜像版本是否发生变化
cd /root/k8s-data/yaml/magedu/tomcat-app1
cat tomcat-app1.yaml |grep image
镜像版本已经发生变化,说明脚本执行镜像更新成功
14.3.2.4 k8s部署容器
1、在k8s集群上部署容器,然后在Jenkins上进行脚本,查看更新效果
在master1节点172.31.7.101上,部署pod
cd /root/k8s-data/yaml/magedu/tomcat-app1
vim tomcat-app1.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app1-deployment-label
name: magedu-tomcat-app1-deployment
namespace: magedu
spec:
replicas: 6
selector:
matchLabels:
app: magedu-tomcat-app1-selector
template:
metadata:
labels:
app: magedu-tomcat-app1-selector
spec:
containers:
- name: magedu-tomcat-app1-container
image: harbor.magedu.local/magedu/tomcat-app1:2022-05-27_17_33_37 #指定tomcat镜像,在该镜像中随意指定web文件index.html的内容
#command: ["/apps/tomcat/bin/run_tomcat.sh"]
imagePullPolicy: IfNotPresent
#imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
resources:
limits:
cpu: 1
memory: "512Mi"
requests:
cpu: 500m
memory: "512Mi"
volumeMounts:
- name: magedu-images
mountPath: /usr/local/nginx/html/webapp/images
readOnly: false
- name: magedu-static
mountPath: /usr/local/nginx/html/webapp/static
readOnly: false
volumes:
- name: magedu-images
nfs:
server: 172.31.7.109
path: /data/k8sdata/magedu/images
- name: magedu-static
nfs:
server: 172.31.7.109
path: /data/k8sdata/magedu/static
---
kind: Service
apiVersion: v1
metadata:
labels:
app: magedu-tomcat-app1-service-label
name: magedu-tomcat-app1-service
namespace: magedu
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
nodePort: 30092
selector:
app: magedu-tomcat-app1-selector
注意:yaml文件中的镜像必须是私有仓库镜像,镜像中的index.html文件的内容可随意编写
2、创建pod
kubectl apply -f kubectl apply -f tomcat-app1.yaml
3、另开一个窗口,使用死循环执行curl命令,便于查看镜像更新效果while true ; do curl http://172.31.7.111:30092/myapp/index.html ; sleep 0.5 ;done
14.3.2.5 执行脚本进行镜像更新和回滚测试
1、在jenkins主机172.31.7.155上修改代码内容,重新提交,然后执行脚本更新,查看更新效果
cd /root/app1
vim index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test page</title>
</head>
<body>
<h1>当前版本v1111</h1>
<h1>当前版本v2222</h1>
<h1>当前版本v3333</h1> #新增v3版本
</body>
</html>
git add .
git commit -m “v3”
git push
2、执行脚本,进行更新
bash /data/scripts/magedu-n66-app1-deploy.sh deploy main
3、查看curl命令抽口,查看镜像是否更新
可以看到内容已经更新
4、进行回滚测试
bash /data/scripts/magedu-n66-app1-deploy.sh rollback_last_version #回滚时只需传递一个位置变量,第二个变量可以不传
查看curl命令窗口,查看镜像更新效果
14.3.3 jenkins调用shell脚本进行更新和回滚
14.3.3.1 jenkins控制台配置参数
1、对创建的任务进行配置
2、勾选参数化构建过程,在添加参数下拉列表中选择“选项参数”
(1)添加第一个选项参数
名称:METHOD
选项:deploy
rollback_last_version
注意:要一行一个,不能并列
描述:deploy-代码部署
rollback_last_version-回滚到上一个版本
如下图所示:
(2)添加第二个选项参数
名称:BRANCH
选项:main
develop
注意:要一行一个,不能并列
描述:main-生产分支
develop-开发分支
如下图所示:
14.3.3.2 调用shell脚本,引用变量
1、添加shell命令,引用参数
2、添加以下内容:
bash /data/scripts/magedu-n66-app1-deploy.sh $METHOD $BRANCH
注意:引用变量时,要按照脚本中变量顺序添加(脚本中$1为method,$2为branch)
最后点击保存
参数说明:
可以选择参数,进行更新或者回滚
每个参数均由两个选项,根据选项进行更新或者回滚
注意:选择回滚上一个版本时,不需要选择分支,因此第二个参数不生效
14.3.3.3 jenkins控制台进行更新和回滚
1、通过jenkins进行代码更新
(1)在jenkins主机修改代码内容
cd /root/app1
vim index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test page</title>
</head>
<body>
<h1>当前版本v1111</h1>
<h1>当前版本v2222</h1>
<h1>当前版本v3333</h1>
<h1>当前版本v4444</h1>
</body>
</html>
如下图所示:
(2)提交gitlab
git add .
git commit -m "v4"
git push
(3)在jenkins进行版本更新
参数分别选择:deploy 和 main
点击开始构建
查看构建过程输出信息
图1:
图2:
(4)在curl命令窗口查看更新效果,已经更新成功
2、通过jenkins进行代码回滚
参数分别选择:第一个参数选择rollback_last_version,第二个参数可以不选择
点击开始构建
查看curl命令输出,已经回滚到上一个版本
14.4 蓝绿发布和灰度发布
14.4.1 蓝绿发布
实现机制:
1.部署当前版本
2.部署service:
3.部署新版本(使用新的deployment 名称、新的label标签)
4.切换service 标签到新的pod
注意:service中多个selector条件必须同时满足,即a和b条件是同时满足(和)的关系
蓝绿部署特点:
不需要停止老版本代码(不影响上一个版本访问),而是在另外一套环境部署新版本然后进行测试,测试通过后将用户流量切到新版本,其特点为业务无中断,升级风险相对较小。但是需要两套完全一样的环境,资源消耗较大。
蓝绿发布示例
蓝绿发布需要两套环境,通过修改service yaml文件中标签过滤器来匹配pod标签实现
1、部署第一套环境:
vim 1.tomcat-app1-v1.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app1-deployment-label
name: magedu-tomcat-app1-deployment #当前版本的deployment 名称
namespace: magedu
spec:
replicas: 3
selector:
matchLabels:
app: magedu-tomcat-app1-selector
version: v1
template:
metadata:
labels:
app: magedu-tomcat-app1-selector
version: v1 #在label中指定容器版本,通过serivce指定版本实现蓝绿发布
spec:
containers:
- name: magedu-tomcat-app1-container
image: registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v1
#command: ["/apps/tomcat/bin/run_tomcat.sh"]
#imagePullPolicy: IfNotPresent
imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
resources:
limits:
cpu: 1
memory: "512Mi"
requests:
cpu: 500m
memory: "512Mi"
startupProbe:
httpGet:
path: /myapp/index.html
port: 8080
initialDelaySeconds: 5 #首次检测延迟5s
failureThreshold: 3 #从成功转为失败的次数
periodSeconds: 3 #探测间隔周期
readinessProbe:
httpGet:
#path: /monitor/monitor.html
path: /myapp/index.html
port: 8080
initialDelaySeconds: 5
periodSeconds: 3
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
livenessProbe:
httpGet:
#path: /monitor/monitor.html
path: /myapp/index.html
port: 8080
initialDelaySeconds: 5
periodSeconds: 3
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
创建容器
kubectl apply -f 1.tomcat-app1-v1.yaml
2、创建service
vim tomcat-service.yaml
---
kind: Service
apiVersion: v1
metadata:
labels:
app: magedu-tomcat-app1-service-label
name: magedu-tomcat-app1-service
namespace: magedu
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
nodePort: 40080
selector: #通过标签选择器过滤转发给后端pod(pod标签为magedu-tomcat-app1-selector:v1,即第一套环境中部署的pod)
app: magedu-tomcat-app1-selector
version: v1
创建service
kubectl apply -f tomcat-service.yaml
通过访问service端口访问tomcat服务
while true ; do curl http://172.31.7.111:40080/myapp/index.html ; sleep 0.5 ;done
3、部署第二套环境
vim 2.tomcat-app1-v2.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app1-deployment-label-v2
version: v2
name: magedu-tomcat-app1-deployment-v2 #灰度版本的deployment 名称,与第一套环境不同,用来区分两套环境
namespace: magedu
spec:
replicas: 2
selector:
matchLabels:
app: magedu-tomcat-app1-selector
version: v2
template:
metadata:
labels:
app: magedu-tomcat-app1-selector
version: v2
spec:
containers:
- name: magedu-tomcat-app1-container
image: registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v2
#command: ["/apps/tomcat/bin/run_tomcat.sh"]
#imagePullPolicy: IfNotPresent
imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
resources:
limits:
cpu: 1
memory: "512Mi"
requests:
cpu: 500m
memory: "512Mi"
startupProbe:
httpGet:
path: /myapp/index.html
port: 8080
initialDelaySeconds: 5 #首次检测延迟5s
failureThreshold: 3 #从成功转为失败的次数
periodSeconds: 3 #探测间隔周期
readinessProbe:
httpGet:
#path: /monitor/monitor.html
path: /myapp/index.html
port: 8080
initialDelaySeconds: 5
periodSeconds: 3
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
livenessProbe:
httpGet:
#path: /monitor/monitor.html
path: /myapp/index.html
port: 8080
initialDelaySeconds: 5
periodSeconds: 3
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
创建容器
kubectl apply -f 2.tomcat-app1-v2.yaml
4、修改service文件,实现蓝绿发布
通过更改service yaml文件中标签过滤器的版本,匹配pod标签实现蓝绿发布
vim tomcat-service.yaml #备注部分为修改内容
---
kind: Service
apiVersion: v1
metadata:
labels:
app: magedu-tomcat-app1-service-label
name: magedu-tomcat-app1-service
namespace: magedu
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
nodePort: 40080
selector:
app: magedu-tomcat-app1-selector
version: v2 #修改版本号
重新加载yaml文件,查看curl命令窗口,查看是否已经更新
kubectl apply -f tomcat-service.yaml #可以看到已经从v1变为v2版本
14.4.2 灰度发布
金丝雀发布也叫灰度发布,是指在黑与白之间,能够平滑过渡的一种发布方式,灰度发布是增量发布的一种类型,灰度发布是在原有版本可用的情况下,同时部署一个新版本应用作为“金丝雀”(小白鼠),测试新版本的性能和表现,以保障整体系统稳定的情况下,尽早发现、调整问题。
实现机制:
1.部署当前版本,使用多副本。
kubectl apply -f 1.tomcat-app1-v1.yaml
2.部署service,匹配一个label标签。
kubectl apply -f tomcat-service.yaml
3.部署新版本(使用新的deployment 名称,但是label标签和之前保持一致),新版本running之后service 会自动匹配label并将pod添加至service的endpoint接受客户端请求。
4.灰度版本测试没有问题,将灰度版本的pod副本数逐渐增加为生产数量。
5.将旧版本pod逐渐调低直至为0,此时数流量将全部转发至新版本。
kubectl scale deployment magedu-tomcat-app1-deployment --replicas=0 -n magedu
灰度发布示例
1、部署第一套环境
vim 1.tomcat-app1-v1.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app1-deployment-label
name: magedu-tomcat-app1-deployment #当前版本的deployment 名称
namespace: magedu
spec:
replicas: 1
selector:
matchLabels:
app: magedu-tomcat-app1-selector #指定pod标签
template:
metadata:
labels:
app: magedu-tomcat-app1-selector
spec:
containers:
- name: magedu-tomcat-app1-container
image: registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v1
#command: ["/apps/tomcat/bin/run_tomcat.sh"]
#imagePullPolicy: IfNotPresent
imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
resources:
limits:
cpu: 1
memory: "512Mi"
requests:
cpu: 500m
memory: "512Mi"
startupProbe:
httpGet:
path: /myapp/index.html
port: 8080
initialDelaySeconds: 5 #首次检测延迟5s
failureThreshold: 3 #从成功转为失败的次数
periodSeconds: 3 #探测间隔周期
readinessProbe:
httpGet:
#path: /monitor/monitor.html
path: /myapp/index.html
port: 8080
initialDelaySeconds: 5
periodSeconds: 3
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
livenessProbe:
httpGet:
#path: /monitor/monitor.html
path: /myapp/index.html
port: 8080
initialDelaySeconds: 5
periodSeconds: 3
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
创建容器
kubectl apply -f 1.tomcat-app1-v1.yaml
2、部署service
vim tomcat-service.yaml
---
kind: Service
apiVersion: v1
metadata:
labels:
app: magedu-tomcat-app1-service-label
name: magedu-tomcat-app1-service
namespace: magedu
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
nodePort: 40080
selector:
app: magedu-tomcat-app1-selector
创建service
kubectl apply -f tomcat-service.yaml
通过访问service端口访问tomcat服务
while true ; do curl http://172.31.7.111:40080/myapp/index.html ; sleep 0.5 ;done
3、部署第二套环境:
注意:新版本使用新的deployment名称,但是label标签和之前保持一致,这样一来,新版本容器running之后service 会自动匹配label并将pod添加至service的endpoint接受客户端请求。
注意:刚开始部署时,副本数要调至很低,灰度没问题后,在逐渐增加副本数
vim 2.tomcat-app1-v2.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app1-deployment-label-v2
version: v2
name: magedu-tomcat-app1-deployment-v2 #灰度版本的deployment名称,与第一套环境不通
namespace: magedu
spec:
replicas: 1 #指定副本数为1
selector:
matchLabels:
app: magedu-tomcat-app1-selector #与第一套环境中pod标签一致,一旦创建会加入service的endpoint
template:
metadata:
labels:
app: magedu-tomcat-app1-selector
spec:
containers:
- name: magedu-tomcat-app1-container
image: registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v2
#command: ["/apps/tomcat/bin/run_tomcat.sh"]
#imagePullPolicy: IfNotPresent
imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
resources:
limits:
cpu: 1
memory: "512Mi"
requests:
cpu: 500m
memory: "512Mi"
startupProbe:
httpGet:
path: /myapp/index.html
port: 8080
initialDelaySeconds: 5 #首次检测延迟5s
failureThreshold: 3 #从成功转为失败的次数
periodSeconds: 3 #探测间隔周期
readinessProbe:
httpGet:
#path: /monitor/monitor.html
path: /myapp/index.html
port: 8080
initialDelaySeconds: 5
periodSeconds: 3
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
livenessProbe:
httpGet:
#path: /monitor/monitor.html
path: /myapp/index.html
port: 8080
initialDelaySeconds: 5
periodSeconds: 3
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
创建pod
kubectl apply -f 2.tomcat-app1-v2.yaml
由于新建的pod会加入service,因此会有一部分流量转发到新建的pod上,因此存在双版本共存的情况
查看curl命令结果:
4、灰度
双版本共存验证无问题后,增加新版本yaml文件pod副本数,然后重新加载yaml文件
将副本数由1调整至3
vim 2.tomcat-app1-v2.yaml #备注字体为修改内容
spec:
replicas: 3 #修改副本数
selector:
matchLabels:
app: magedu-tomcat-app1-selector
template:
metadata:
labels:
app: magedu-tomcat-app1-selector
重新加载文件
kubectl apply -f 2.tomcat-app1-v2.yaml
查看curl命令输出结果,此时新旧版本容器承载流量为1:1
将旧版本容器副本数调整为0,下线旧版本容器,实现灰度发布
vim 1.tomcat-app1-v2.yaml #备注字体为修改内容
pec:
replicas: 1 #修改副本数
selector:
matchLabels:
app: magedu-tomcat-app1-selector
template:
metadata:
labels:
app: magedu-tomcat-app1-selector
kubectl apply -f 1.tomcat-app1-v1.yaml
查看curl命令输出结果,此时均为新版本