ReplicaSet - rs
示例
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: rs-ft
namespace: default
labels:
app: guestbook
tier: frontend
spec:
replicas: 3
selector: # 在.spec.selector中定义的标签选择器必须能够匹配到spec.template.metadata.labels里定义的Pod标签
matchLabels:
tier1: frontend1
template:
metadata:
labels:
tier1: frontend1
spec:
containers:
- name: samples-gb-frontend
image: docker.io/yecc/gcr.io-google_samples-gb-frontend:v3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
缺点
- 更新管理上不如deployment灵活。现在不推荐使用。都使用deployment来管理。
deployment
概述
- Deployment是kubernetes中最常用的资源对象,为ReplicaSet和Pod的创建提供了一种声明式的定义方法,在Deployment对象中描述一个期望的状态,Deployment控制器就会按照一定的控制速率把实际状态改成期望状态,通过定义一个Deployment控制器会创建一个新的ReplicaSet控制器。
- 使用Deployment而不直接创建ReplicaSet是因为Deployment对象拥有许多ReplicaSet没有的特性,例如滚动升级、金丝雀发布、蓝绿部署和回滚。
工作原理
RS管理
- Deployment控制器是建立在rs之上的一个控制器,可以管理多个rs:
-
每次更新,都会生成一个新的rs,把旧的rs替换掉;多个rs同时存在,但是只有一个rs运行。
-
如下图:rs-v1控制三个pod,删除一个pod,在rs-v2上重新建立一个,依次类推,直到全部都是由rs-v2控制,如果rs-v2有问题,还可以回滚。Deployment是建构在rs之上的,多个rs组成一个Deployment,但是只有一个rs处于活跃状态。

更新管理
说明
只有在deploytment.spec.template产生变化之后,deployment才会触发更新,产生新的RS
- 比如说Deployment控制5个pod副本,pod的期望值是5个,但是升级的时候需要额外多几个pod,控制器可以控制在5个pod副本之外还能再增加几个pod副本:
- 比方说能多一个,但是不能少,那么升级的时候就是先增加一个,再删除一个,始终保持pod副本数是5个
- 比如最多允许多一个,最少允许少一个;也就是最多6个,最少4个;加一个,删除两个,依次类推。
-
可以自己控制更新方式,这种滚动更新需要加readinessProbe和livenessProbe探测,确保pod中容器里的应用都正常启动了才删除之前的pod。
-
更新策略定义:
kubectl explain deploy.spec.strategy.rollingUpdate
maxSurge <string>
# 更新过程最多允许超出的指定的目标副本数有几个。
# 它有两种取值方式,第一种直接给定数量;第二种根据百分比,如最多可以超出20%,滚动更新开始时,马上scale up pod数为120%。然后逐渐的kill旧的,创建新的。
# Absolute number is calculated from percentage by rounding up. ==> 出现小数向上取整
maxUnavailable <string>
# 最多允许几个不可用,数字或百分比。如果是30%,滚动更新开始,旧pod马上scale down到70%,然后随着新pod ready,旧pod再进一步scale down。
# Absolute number is calculated from percentage by rounding down. ==> 出现小数向下取整
replicas: 5
maxSurge: 25% 5*25%=1.25 ->5+2=7
maxUnavailable: 25% 5%25%=1.25 -> 5-1=4 #滚动更新时最少4个,最多7个
yaml示例
- 用kubectl explain一层一层的查下去慢慢写完yaml文件
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep-myapp-blue
spec:
replicas: 2
selector:
matchLabels:
app: myapp
version: v1
template:
metadata:
labels:
app: myapp
version: v1
spec:
containers:
- name: myapp
image: janakiramm/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
重启deployment
kubectl rollout restart deploy nginx: 会轮替重启deployment里面的pod
扩缩容
- 修改yaml文件replicas的值,重新kubectl apply -f
- kubectl scale deploy --replicas=5
注意不要盲目扩容,特别是对于后端服务,连了数据库的那种。如果访问慢的原因并不是由于并发数不够,而是由于后端数据库有压力,比如慢查询太多、数据库CPU内存满了,盲目扩容java程序可能会导致适得其反。所以要去分析慢的原因再看优化。
滚动更新
滚动更新是一种自动化程度较高的发布方式,用户体验比较平滑,是目前成熟型技术组织所采用的主流发布方式,一次滚动发布一般由若干个发布批次组成,每批的数量一般是可以配置的(可以通过发布模板定义),例如第一批1台,第二批10%,第三批50%,第四批100%。每个批次之间留观察间隔,通过手工验证或监控反馈确保没有问题再发下一批次,所以总体上滚动式发布过程是比较缓慢的
yaml定义
#查看rolling update的参数定义
kubectl explain deploy.spec.strategy
#type:指定策略类型,支持两种策略
#Recreate:在创建出新的Pod之前会先杀掉所有已存在的Pod
#RollingUpdate:滚动更新,就是杀死一部分,就启动一部分,在更新过程中,存在两个版本Pod。(默认值)
#rollingUpdate:当type为RollingUpdate时生效,用于为RollingUpdate设置参数,支持两个属性:
#maxUnavailable:用来指定在升级过程中不可用Pod的最大数量,默认为25%。
#maxSurge: 用来指定在升级过程中可以超过期望的Pod的最大数量,默认为25%。
#查看当前deploy的rolling update策略
kubectl describe deploy
查看滚动更新历史版本
kubectl rollout <参数> deploy <deploy name>: 版本升级相关功能,支持下面的选项:-
status 显示当前升级状态
-
history 显示 升级历史记录
-
pause 暂停版本升级过程
-
resume 继续已经暂停的版本升级过程
-
restart 重启版本升级过程
-
undo 回滚到上一级版本(可以使用--to-revision回滚到指定版本)
- --to-version:指的是rollout history里面显示的
REVISION字段
- --to-version:指的是rollout history里面显示的
kubectl rollout history deploy dep-myapp-blue
deployment.apps/dep-myapp-blue
REVISION CHANGE-CAUSE
1 <none>
2 <none>
kubectl get rs #能看到两个rs,有一个旧版本的rs都是0.
- change cause字段:
- 如果用kubectl set --record去改,会自动帮你加上,内容就是这个命令本身。
- 也是可以自己指定的,在deploy的annotation里面写:
kubernetes.io/change-cause: kubectl set image deployment nginx nginx=registry.cn-beijing.aliyuncs.com/dotbalo/canary:v1 --record=true
回滚到历史版本
kubectl rollout undo deploy dep-myapp-blue --to-revision=1
# 也是滚动的方式,ready一个新的干掉一个旧的。
历史保留策略
在默认情况下,revision 保留 10 个旧的 ReplicaSet,其余的将在后台进行垃圾回收.
可以在deploy.spec.revisionHistoryLimit 设置保留 ReplicaSet 的个数。
当设置为 0 时,不保留历史记录。
自定义更新策略
maxSurge和maxUnavailable用来控制滚动更新的更新策略:
-
maxUnavailable: [0, 副本数]
-
maxSurge: [0, 副本数]
比例:
-
maxUnavailable: [0%, 100%] 向下取整,比如10个副本,5%的话==0.5个,但计算按照0个;
-
maxSurge: [0%, 100%] 向上取整,比如10个副本,5%的话==0.5个,但计算按照1个;
总结:
-
maxUnavailable:和期望的副本数比,不可用副本数最大比例(或最大值),这个值越小,越能保证服务稳定,更新越平滑;
-
maxSurge:和期望的副本数比,超过期望副本数最大比例(或最大值),这个值调的越大,副本更新速度越快。
- 建议采用百分比的形式设置两者的值。
最佳实践
对于非常重要的服务比如网关,建议这样配置:
-
副本数低于5个:
-
maxUnavailable == 0
-
maxSurge == 1
最佳实践
这是我们生产环境提供给用户的默认配置。即”一上一下,先上后下”最平滑原则:1个新版本pod ready(结合readiness)后,才销毁旧版本pod。此配置适用场景是平滑更新、保证服务平稳,但也有缺点,就是太慢了。
-
副本数高于5个:这样设会稍微快一些
-
maxUnavailable == 0
-
maxSurge == 2-3
对于普通服务,用默认的25%+25%就行了。
修改策略
修改deployment的更新策略:
#通过kubectl patch改
kubectl patch deployment myapp-v1 -p '{"spec":{"strategy":{"rollingUpdate": {"maxSurge":1,"maxUnavailable":0}}}}'
#通过yaml文件改
kubectl explain deploy.spec.strategy
#yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep-myapp-blue
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: myapp
version: v1
template:
metadata:
labels:
app: myapp
version: v1
spec:
containers:
- name: myapp
image: janakiramm/myapp:v2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
...
暂停和恢复更新
kubectl set命令去更改配置,更改后立即触发更新,大多数情况下可能需要针对一个资源文件更改多处地方,而并不需要多次触发更新。
(如果使用的是 kubectl edit 命令,可以直接进行多次修改,无需暂停更新。有些场景,kubectl set 命令集成在 CICD 流水线中):
此时可以使用 Deployment 暂停功能,临时禁用更新操作,对 Deployment 进行多次修改后在进行更新。使用 kubectl rollout pause 命令即可暂停 Deployment 更新:
kubectl rollout pause deploy nginx
deployment.extensions/nginx paused
然后对 Deployment 进行相关更新操作,比如先更新镜像,然后对其资源进行限制
进行完最后一处配置更改后,使用 kubectl rollout resume deploy nginx 恢复 Deployment 更新
蓝绿部署
原理
-
蓝绿部署中,一共有两套系统:一套是正在提供服务系统,标记为“绿色”;另一套是准备发布的系统,标记为“蓝色”。两套系统都是功能完善的、正在运行的系统,只是系统版本和对外服务情况不同。
-
开发新版本,要用新版本替换线上的旧版本,在线上的系统之外,搭建了一个使用新版本代码的全新系统。 这时候,一共有两套系统在运行,正在对外提供服务的老系统是绿色系统,新部署的系统是蓝色系统。

- 蓝色系统不对外提供服务,用来做发布前测试,测试过程中发现任何问题,可以直接在蓝色系统上修改,不干扰用户正在使用的系统。(注意,两套系统没有耦合的时候才能百分百保证不干扰)蓝色系统经过反复的测试、修改、验证,确定达到上线标准之后,直接将用户切换到蓝色系统:

-
切换后的一段时间内,依旧是蓝绿两套系统并存,但是用户访问的已经是蓝色系统。这段时间内观察蓝色系统(新系统)工作状态,如果出现问题,直接切换回绿色系统。
-
当确信对外提供服务的蓝色系统工作正常,不对外提供服务的绿色系统已经不再需要的时候,蓝色系统正式成为对外提供服务系统,成为新的绿色系统。 原先的绿色系统可以销毁,将资源释放出来,用于部署下一个蓝色系统。
优缺点
优点:
1、更新过程无需停机,风险较少
2、回滚方便,只需要更改路由或者切换DNS服务器,效率较高
缺点:
1、成本较高,需要部署两套环境。如果新版本中基础服务出现问题,会瞬间影响全网用户;如果新版本有问题也会影响全网用户。
2、需要部署两套机器,费用开销大
3、在非隔离的机器(Docker、VM)上操作时,可能会导致蓝绿环境被摧毁风险
4、负载均衡器/反向代理/路由/DNS处理不当,将导致流量没有切换过来情况出现
实现
K8S本身不支持原生的蓝绿部署,目前最好方法是:部署deployment,更新应用程序的service以指向新的deployment部署的应用
- 部署green应用
#部署deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-v1
namespace: blue-green
spec:
replicas: 3
selector:
matchLabels:
app: myapp
version: v2
template:
metadata:
labels:
app: myapp
version: v2
spec:
containers:
- name: myapp
image: janakiramm/myapp:v2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
kubectl create ns blue-green
ctr -n=k8s.io images import myapp-blue.tar.gz
ctr -n=k8s.io images import myapp-green.tar.gz
#创建前端service
apiVersion: v1
kind: Service
metadata:
name: myapp-lan-lv
namespace: blue-green
labels:
app: myapp
spec:
type: NodePort
ports:
- port: 80
nodePort: 30062
name: http
selector:
app: myapp
version: v2
- 部署blue应用
#创建deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-v2
namespace: blue-green
spec:
replicas: 3
selector:
matchLabels:
app: myapp
version: v1
template:
metadata:
labels:
app: myapp
version: v1
spec:
containers:
- name: myapp
image: janakiramm/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
- 修改svc yaml文件,使其标签选择器指向blue应用
金丝雀发布
金丝雀发布的由来:17 世纪,英国矿井工人发现,金丝雀对瓦斯这种气体十分敏感。空气中哪怕有极其微量的瓦斯,金丝雀也会停止歌唱;当瓦斯含量超过一定限度时,虽然人类毫无察觉,金丝雀却早已毒发身亡。当时在采矿设备相对简陋的条件下,工人们每次下井都会带上一只金丝雀作为瓦斯检测指标,以便在危险状况下紧急撤离。
金丝雀发布(又称灰度发布、灰度更新):金丝雀发布一般先发1台,或者一个小比例,例如2%的服务器,主要做流量验证用,也称为金丝雀 (Canary) 测试 (国内常称灰度测试)。
- 简单的金丝雀测试一般通过手工测试验证,复杂的金丝雀测试需要比较完善的监控基础设施配合,通过监控指标反馈,观察金丝雀的健康状况,作为后续发布或回退的依据。 如果金丝测试通过,则把剩余的V1版本全部升级为V2版本。如果金丝雀测试失败,则直接回退金丝雀,发布失败。

实现
# 创建deployment
kubectl apply -f dep-green.yaml
# 更新镜像 && 暂停rollout
kubectl set image deployment myapp-v1 myapp=nginx:latest -n blue-green && kubectl rollout pause deployment myapp-v1 -n blue-green
# 注:把myapp这个容器的镜像更新到nginx:latest版本 更新镜像之后,创建一个新的pod就立即暂停,这就是我们说的金丝雀发布;如果暂停几个小时之后没有问题,那么取消暂停,就会依次执行后面步骤,把所有pod都升级。
# 验证没问题,取消暂停更新,让deployment执行完滚动更新
kubectl rollout resume deployment myapp-v1 -n blue-green
提示
金丝雀发布功能,用istio实现,更加方便
迁移服务到k8s
- 查看镜像版本
- 查看暴露的端口号
- 查看是否需要配置环境变量、配置文件、启动参数等。(有些服务需要配置环境变量才能启动,比如mysql密码等)
- 查看数据目录,是否需要持久化数据目录