pod控制器进阶
简介
Controller Manager 由 kube-controller-manager 和 cloud-controller-manager 组成, 是 Kubernetes 的大脑, 它通过 apiserver 监控整个集群的状态, 并确保集群处于预期的工作状态。
kube-controller-manager 由一系列的控制器组成
1 Replication Controller
2 Node Controller
3 CronJob Controller
4 DaemonSet Controller
5 Deployment Controller
6 Endpoint Controller
7 Garbage Collector
8 Namespace Controller
9 Job Controller
10 Pod AutoScaler
11 RelicaSet
12 Service Controller
13 ServiceAccount Controller
14 StatefulSet Controller
15 Volume Controller
16 Resource quota Controller
cloud-controller-manager 在 Kubernetes 启用 Cloud Provider 的时候才需要, 用来配合云服务 提供商的控制, 也包括一系列的控制器
1 Node Controller
2 Route Controller
3 Service Controller
从v1.6开始,cloud provider已经经历了几次重大重构,以便在不修改Kubernetes核心代码的同时构建 自定义的云服务商支持
常见Pod控制器及含义
- ReplicaSet:适合无状态的服务部署
用户创建指定数量的pod副本数量,确保pod副本数量符合预期状态,并且支持滚动式自动扩容和 缩容功能。
帮助用户管理无状态的pod资源,精确反应用户定义的目标数量,但是RelicaSet不是直接使用的 控制器,而是使用Deployment。
ReplicaSet主要三个组件组成:- 用户期望的pod副本数量
- 标签选择器,判断哪个pod归自己管理
- 当现存的pod数量不足,会根据pod资源模板进行新建
- deployment:适合无状态的服务部署
工作在ReplicaSet之上,用于管理无状态应用,目前来说最好的控制器。支持滚动更新和回滚功 能,还提供声明式配置。 - StatefullSet:适合有状态的服务部署。需要学完存储卷后进行系统学习。
- DaemonSet:一次部署,所有的node节点都会部署,例如一些典型的应用场景:
- 运行集群存储 daemon,例如在每个Node上运行 glusterd、ceph
- 在每个Node上运行日志收集 daemon,例如 fluentd、 logstash
- 在每个Node上运行监控 daemon,例如 Prometheus Node Exporter
用于确保集群中的每一个节点只运行特定的pod副本,通常用于实现系统级后台任务。比如ELK服 务
特性:服务是无状态的
服务必须是守护进程
- Job:一次性的执行任务。 只要完成就立即退出,不需要重启或重建。
- Cronjob:周期性的执行任务。 周期性任务控制,不需要持续后台运行。
使用镜像
演示pod的控制器升级使用:
docker pull nginx:1.17.10-alpine
docker pull nginx:1.18.0-alpine
docker pull nginx:1.19.2-alpine
replication Controller控制器
replication controller简称RC,是kubernetes系统中的核心概念之一,简单来说,它其实定义了一个期 望的场景,即声明某种pod的副本数量在任意时刻都复合某个预期值,所以RC的定义包含以下部分:
- pod期待的副本数量
- 用于筛选目标pod的Label Selector
- 当pod的副本数量小于期望值时,用于创建新的pod的pod模板(template)
ReplicaSet
ReplicationController用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退 出,会自动创建新的Pod来替代;而如果异常多出来的容器也会自动回收。
在新版本的Kubernetes中建议使用ReplicaSet来取代ReplicationController。ReplicaSet跟 ReplicationController没有本质的不同,只是名字不一样,并且ReplicaSet支持集合式的selector。
虽然ReplicaSet可以独立使用,但一般还是建议使用 Deployment 来自动管理ReplicaSet,这样就无需 担心跟其他机制的不兼容问题(比如ReplicaSet不支持rolling-update但Deployment支持)。
ReplicaSet模板说明
apiVersion: apps/v1 #api版本定义
kind: ReplicaSet #定义资源类型为ReplicaSet
metadata: #元数据定义
name: myapp
namespace: default
spec: #ReplicaSet的规格定义
replicas: 2 #定义副本数量为2个
selector: #标签选择器,定义匹配pod的标签
matchLabels:
app: myapp
release: canary
template: #pod的模板定义
metadata: #pod的元数据定义
name: myapp-pod #自定义pod的名称
labels: #定义pod的标签,需要和上面定义的标签一致,也可以多出其他标签
app: myapp
release: canary
environment: qa
spec: #pod的规格定义
containers: #容器定义
- name: myapp-container #容器名称
image: nginx:1.17.10-alpine #容器镜像
ports: #暴露端口
- name: http
containerPort: 80
可以通过kubectl命令行方式获取更加详细信息
kubectl explain rs
kubectl explain rs.spec
kubectl explain rs.spec.template.spec
部署ReplicaSet
controller/replicasetdemo.yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: replicasetdemo
labels:
app: replicasetdemo
spec:
replicas: 3
template:
metadata:
name: replicasetdemo
labels:
app: replicasetdemo
spec:
containers:
- name: replicasetdemo
image: nginx:1.17.10-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
restartPolicy: Always
selector:
matchLabels:
app: replicasetdemo
运行ReplicaSet
运行ReplicaSet
kubectl apply -f replicasetdemo.yml
查看rs控制器
kubectl get rs
查看pod信息
kubectl get pod
查看pod详细信息
kubectl describe pod replicasetdemo-7fdd7b5f67-5gzfg
测试controller控制器下的pod删除、重新被controller控制器拉起
kubectl delete pod --all
kubectl get pod
修改pod的副本数量:通过命令行方式
kubectl scale replicaset replicasetdemo --replicas=8
kubectl get rs
修改pod的副本数量:通过资源清单方式
kubectl edit replicasets.apps replicasetdemo
kubectl get rs
显示pod的标签
kubectl get pod --show-labels
修改pod标签(label)
kubectl label pod replicasetdemo-652lc app=lagou --overwrite=True
再次显示pod的标签:发现多了一个pod,原来的rs中又重新拉起一个pod,说明rs是通过label去管
理pod
kubectl get pod --show-labels
删除rs
kubectl delete rs replicasetdemo
总结
kubectl命令行工具适用于RC的绝大部分命令同样适用于ReplicaSet,此外,我们当前很少单独适用 ReplicaSet,它主要被Deployment这个更高层的资源对象所使用,从而形成一整套Pod创建,删除, 更新的编排机制,我们在使用Deployment时无需关心它是如何维护和创建ReplicaSet的,这一切都是 自动发生的
最后,总结一下RC(ReplicaSet)的一些特性和作用:
- 在绝大多数情况下,我们通过定义一个RC实现Pod的创建及副本数量的自动控制
- 在RC里包括完整的Pod定义模板
- RC通过Label Selector机制实现对Pod副本的自动控制
- 通过改变RC里的Pod副本数量,可以实现Pod的扩容和缩容
- 通过改变RC里Pod模板中的镜像版本,可以实现滚动升级
Deployment
Deployment是kubernetes在1.2版本中引入的新概念,用于更好的解决Pod的编排问题,为此, Deployment在内部使用了ReplicaSet来实现目的,我们可以把Deployment理解为ReplicaSet的一次升 级,两者的相似度超过90%
Deployment的使用场景有以下几个:
- 创建一个Deployment对象来生成对应的ReplicaSet并完成Pod副本的创建
- 检查Deployment的状态来看部署动作是否完成(Pod副本数量是否达到了预期的值)
- 更新Deployment以创建新的Pod(比如镜像升级)
- 如果当前Deployment不稳定,可以回滚到一个早先的Deployment版本
- 暂停Deployment以便于一次性修改多个PodTemplateSpec的配置项,之后在恢复Deployment, 进行新的发布
- 扩展Deployment以应对高负载
- 查看Deployment的状态,以此作为发布是否成功的标志
- 清理不在需要的旧版本ReplicaSet
Deployment模板说明
可以通过kubectl命令行方式获取更加详细信息
kubectl explain deploy
kubectl explain deploy.spec
kubectl explain deploy.spec.template.spec
部署Deployment
除了API生命与Kind类型有区别,Deployment的定义与Replica Set的定义很类似。
controller/deploymentdemo.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploymentdemo1
labels:
app: deploymentdemo1
spec:
replicas: 10
template:
metadata:
name: deploymentdemo1
labels:
app: deploymentdemo1
spec:
containers:
- name: deploymentdemo1
image: nginx:1.17.10-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
restartPolicy: Always
selector:
matchLabels:
app: deploymentdemo1
运行Deployment
kubectl apply -f deploymentdemo.yml
查看deployment
kubectl get rs
查看rs:deployment名称+hashcode码组成
查看pod
kubectl get pod
镜像更新升级
命令行方式
升级nginx镜像版本为1.18.0
kubectl set image deployment deploymentdemo1 deploymentdemo1=nginx:1.18.0-
alpine
查看pod升级情况
kubectl get pods -w
进去某一个pod内部,查看nginx升级版本信息
kubectl exec -it deploymentdemo1-df6bc5d4c-flc7b sh
nginx -v
exit
yml文件方式
升级nginx镜像版本为1.19.2-alpine
kubectl edit deployments.apps deploymentdemo1
查看pod升级情况
kubectl get pods -w
进去某一个pod内部,查看nginx升级版本信息
kubectl exec -it deploymentdemo1-584f6b54dd-4l62t sh
nginx -v
exit
Deployment扩容
命令行方式
kubectl scale deployment deploymentdemo1 --replicas=15
kubectl get pods
yml文件方式
kubectl edit deployments.apps deploymentdemo1
kubectl get pods
滚动更新
概述
微服务部署:蓝绿部署、滚动部署、灰度发布、金丝雀发布。
- 蓝绿部署是不停老版本,部署新版本然后进行测试,确认OK,将流量切到新版本,然后老版本同 时也升级到新版本。 蓝绿部署无需停机,并且风险较小。
- 滚动发布:一般是取出一个或者多个服务器停止服务,执行更新,并重新将其投入使用。周而复 始,直到集群中所有的实例都更新成新版本。 这种部署方式相对于蓝绿部署,更加节约资源—— 它不需要运行两个集群、两倍的实例数。我们可以部分部署,例如每次只取出集群的20%进行升 级。
- 灰度发布是指在黑与白之间,能够平滑过渡的一种发布方式。AB test就是一种灰度发布方式,让 一部分用户继续用A,一部分用户开始用B,如果用户对B没有什么反对意见,那么逐步扩大范围, 把所有用户都迁移到B上面来。灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发 现、调整问题,以保证其影响度,而我们平常所说的金丝雀部署也就是灰度发布的一种方式。
金丝雀发布
Deployment控制器支持自定义控制更新过程中的滚动节奏,如“暂停(pause)”或“继续(resume)”更新操 作。比如等待第一批新的Pod资源创建完成后立即暂停更新过程,此时,仅存在一部分新版本的应用, 主体部分还是旧的版本。然后,再筛选一小部分的用户请求路由到新版本的Pod应用,继续观察能否稳 定地按期望的方式运行。确定没问题之后再继续完成余下的Pod资源滚动更新,否则立即回滚更新操 作。这就是所谓的金丝雀发布(Canary Release)
更新deployment的nginx:1.18.0-alpine版本,并配置暂停deployment
kubectl set image deployment deploymentdemo1 deploymentdemo1=nginx:1.18.0-
alpine && kubectl rollout pause deployment deploymentdemo1
观察更新状态
kubectl rollout status deployments deploymentdemo1
监控更新的过程,可以看到已经新增了一个资源,但是并未按照预期的状态去删除一个旧的资源,就是
因为使用了pause暂停命令
kubectl get pods -l app=deploymentdemo1 -w
确保更新的pod没问题了,继续更新
kubectl rollout resume deploy deploymentdemo1
查看最后的更新情况
kubectl get pods -l app=deploymentdemo1 -w
进去某一个pod内部,查看nginx更新版本信息
kubectl exec -it deploymentdemo1-df6bc5d4c-flc7b sh
nginx -v
Deployment版本回退
默认情况下,kubernetes 会在系统中保存前两次的 Deployment 的 rollout 历史记录,以便可以随 时回退(您可以修改 revision history limit 来更改保存的revision数)。
注意: 只要 Deployment 的 rollout 被触发就会创建一个 revision。也就是说当且仅当 Deployment 的 Pod template(如 .spec.template )被更改,例如更新template 中的 label 和容器 镜像时,就会创建出一个新的 revision。
其他的更新,比如扩容 Deployment 不会创建 revision——因此我们可以很方便的手动或者自动扩容。 这意味着当您回退到历史 revision 时,只有 Deployment 中的 Pod template 部分才会回退。
rollout常见命令
![](https://wp.wxrwcz.cn/wp-content/uploads/2020/11/image.png)
history操作
kubectl rollout history deployment deploymentdemo1
status操作
kubectl rollout status deployment deploymentdemo1
undo操作
回滚版本信息
kubectl rollout undo deployment deploymentdemo1
查看pod回滚情况
kubectl get pods -w
进去某一个pod内部,查看nginx回滚版本信息
kubectl exec -it deploymentdemo1-df6bc5d4c-flc7b sh
Deployment 更新策略
Deployment 可以保证在升级时只有一定数量的 Pod 是 down 的。默认的,它会确保至少有比期望的 Pod数量少
一个是up状态(最多一个不可用)
Deployment 同时也可以确保只创建出超过期望数量的一定数量的 Pod。默认的,它会确保最多比期望 的Pod数
量多一个的 Pod 是 up 的(最多1个 surge )
Kuberentes 版本v1.17.5中,从1-1变成25%-25%
kubectl describe deployments.apps deploymentdemo1
查看到属性:
RollingUpdateStrategy: 25% max unavailable, 25% max surge
kubectl describe deployments.apps deploymentdemo1 查看到属性: RollingUpdateStrategy: 25% max unavailable, 25% max surge
总结
Deployment为Pod和Replica Set(下一代Replication Controller)提供声明式更新。
只需要在 Deployment 中描述想要的目标状态是什么,Deployment controller 就会帮您将 Pod 和 ReplicaSet 的实际状态改变到您的目标状态。也可以定义一个全新的 Deployment 来创建 ReplicaSet 或者删除已有的 Deployment 并创建一个新的来替换。
Replicas(副本数量):
.spec.replicas 是可以选字段,指定期望的pod数量,默认是1。
Selector(选择器):
.spec.selector是可选字段,用来指定 label selector ,圈定Deployment管理的pod范围。如果被指 定, .spec.selector 必须匹配 .spec.template.metadata.labels,否则它将被API拒绝。如果 .spec.selector 没有被指定, .spec.selector.matchLabels 默认是.spec.template.metadata.labels。
在Pod的template跟.spec.template不同或者数量超过了.spec.replicas规定的数量的情况下, Deployment会杀掉label跟selector不同的Pod。
Pod Template(Pod模板):
.spec.template 是 .spec中唯一要求的字段。
.spec.template 是 pod template. 它跟 Pod有一模一样的schema,除了它是嵌套的并且不需要 apiVersion 和 kind字段。
另外为了划分Pod的范围,Deployment中的pod template必须指定适当的label(不要跟其他 controller重复了,参考selector)和适当的重启策略。
.spec.template.spec.restartPolicy 可以设置为 Always , 如果不指定的话这就是默认配置。
strategy(更新策略):
.spec.strategy 指定新的Pod替换旧的Pod的策略。 .spec.strategy.type 可以是"Recreate"或者是 "RollingUpdate"。"RollingUpdate"是默认值。
Recreate: 重建式更新,就是删一个建一个。类似于ReplicaSet的更新方式,即首先删除现有的 Pod对象,然后由控制器基于新模板重新创建新版本资源对象。
rollingUpdate:滚动更新,简单定义 更新期间pod最多有几个等。可以指定 maxUnavailable 和 maxSurge 来控制 rolling update 进程。
maxSurge: .spec.strategy.rollingUpdate.maxSurge 是可选配置项,用来指定可以超过期 望的Pod数量的最大个数。该值可以是一个绝对值(例如5)或者是期望的Pod数量的百分比(例如 10%)。当 MaxUnavailable 为0时该值不可以为0。通过百分比计算的绝对值向上取整。默认值是1。
例如,该值设置成30%,启动rolling update后新的ReplicatSet将会立即扩容,新老Pod的总数不 能超过期望的Pod数量的130%。旧的Pod被杀掉后,新的ReplicaSet将继续扩容,旧的ReplicaSet会进 一步缩容,确保在升级的所有时刻所有的Pod数量和不会超过期望Pod数量的130%。
maxUnavailable: .spec.strategy.rollingUpdate.maxUnavailable 是可选配置项,用来指 定在升级过程中不可用Pod的最大数量。该值可以是一个绝对值(例如5),也可以是期望Pod数量的百 分比(例如10%)。通过计算百分比的绝对值向下取整。 如 果 .spec.strategy.rollingUpdate.maxSurge 为0时,这个值不可以为0。默认值是1。
例如,该值设置成30%,启动rolling update后旧的ReplicatSet将会立即缩容到期望的Pod数量的 70%。新的Pod ready后,随着新的ReplicaSet的扩容,旧的ReplicaSet会进一步缩容确保在升级的所有 时刻可以用的Pod数量至少是期望Pod数量的70%。
rollbackTo:
.spec.rollbackTo 是一个可以选配置项,用来配置Deployment回退的配置。设置该参数将触发 回退操作,每次回退完成后,该值就会被清除。
revision: .spec.rollbackTo.revision 是一个可选配置项,用来指定回退到的revision。默认 是0,意味着回退到上一个revision。
progressDeadlineSeconds:
.spec.progressDeadlineSeconds 是可选配置项,用来指定在系统报告Deployment的failed progressing——表现为resource的状态中 type=Progressing 、 Status=False 、 Reason=ProgressDeadlineExceeded 前可以等待的Deployment进行的秒数。Deployment controller会继续重试该Deployment。未来,在实现了自动回滚后, deployment controller在观察到 这种状态时就会自动回滚。
如果设置该参数,该值必须大于 .spec.minReadySeconds 。
paused:
.spec.paused 是可以可选配置项,boolean值。用来指定暂停和恢复Deployment。Paused和没有 paused的Deployment之间的唯一区别就是,所有对paused deployment中的PodTemplateSpec的修 改都不会触发新的rollout。Deployment被创建之后默认是非paused。
DaemonSet
DaemonSet 确保全部Node 上运行一个 Pod 的副本。当有 Node 加入集群时,也会为他们新增一 个 Pod 。当有 Node 从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。
在每一个node节点上只调度一个Pod,因此无需指定replicas的个数,比如:
- 在每个node上都运行一个日志采集程序,负责收集node节点本身和node节点之上的各个Pod所产 生的日志
- 在每个node上都运行一个性能监控程序,采集该node的运行性能数据
DaemonSet模板说明
可以通过kubectl命令行方式获取更加详细信息
kubectl explain daemonset
kubectl explain daemonset.spec
kubectl explain daemonset.spec.template.spec
部署DaemonSet
controller/daemonsetdemo.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: demonsetdemo
labels:
app: demonsetdemo
spec:
template:
metadata:
name: demonsetdemo
labels:
app: demonsetdemo
spec:
containers:
- name: demonsetdemo
image: nginx:1.17.10-alpine
imagePullPolicy: IfNotPresent
restartPolicy: Always
selector:
matchLabels:
app: demonsetdemo
运行DaemonSet
运行demonset
kubectl apply -f demonsetdemo.yml
查看pod详细信息:只有工作节点创建pod,master节点并不会创建。
kubectl get pod -o wide
DaemonSet的滚动更新
DaemonSet有两种更新策略类型:
- OnDelete:这是向后兼容性的默认更新策略。使用 OnDelete 更新策略,在更新DaemonSet模板 后,只有在手动删除旧的DaemonSet pod时才会创建新的DaemonSet pod。这与Kubernetes 1.5或更早版本中DaemonSet的行为相同。
- RollingUpdate:使用 RollingUpdate 更新策略,在更新DaemonSet模板后,旧的DaemonSet pod将被终止,并且将以受控方式自动创建新的DaemonSet pod。
Job
- 一次性执行任务,类似Linux中的job
- 应用场景:如离线数据处理,视频解码等业务
使用镜像
docker pull perl:slim
部署Job
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: perl:slim
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(6000)"]
restartPolicy: Never
backoffLimit: 4
backoffLimit说明
.spec.backoffLimit用于设置Job的容错次数,默认值为6。当Job运行的Pod失败次数到 达.spec.backoffLimit次时,Job Controller不再新建Pod,直接停止运行这个Job,将其运行结 果标记为Failure。另外,Pod运行失败后再次运行的时间间隔呈递增状态,例如10s,20s, 40s。。。
运行Job
运行job
kubectl apply -f jobdemo.yml
查看pod日志
kubectl logs -f pi-7nrtv
删除job
kubectl delete -f jobdemo.yml
StatefulSet
在kubernetes系统中,Pod的管理对象RC,Deployment,DaemonSet和Job都面向无状态的服务,但 现实中有很多服务时有状态的,比如一些集群服务,例如mysql集群,集群一般都会有这四个特点:
- 每个节点都是有固定的身份ID,集群中的成员可以相互发现并通信
- 集群的规模是比较固定的,集群规模不能随意变动
- 集群中的每个节点都是有状态的,通常会持久化数据到永久存储中
- 如果磁盘损坏,则集群里的某个节点无法正常运行,集群功能受损
如果你通过RC或Deployment控制Pod副本数量来实现上述有状态的集群,就会发现第一点是无法满足 的,因为Pod名称和ip是随机产生的,并且各Pod中的共享存储中的数据不能都动,因此StatefulSet在 这种情况下就派上用场了,那么StatefulSet具有以下特性:
- StatefulSet里的每个Pod都有稳定,唯一的网络标识,可以用来发现集群内的其它成员,假设, StatefulSet的名称为lagou,那么第1个Pod叫lagou-0,第2个叫lagou-1,以此类推
- StatefulSet控制的Pod副本的启停顺序是受控的,操作第N个Pod时,前N-1个Pod已经是运行且准 备状态
- StatefulSet里的Pod采用稳定的持久化存储卷,通过PV或PVC来实现,删除Pod时默认不会删除与 StatefulSet相关的存储卷(为了保证数据的安全
StatefulSet除了要与PV卷捆绑使用以存储Pod的状态数据,还要与Headless,Service配合使用,每个 StatefulSet定义中都要生命它属于哪个Handless Service,Handless Service与普通Service的关键区别 在于,它没有Cluster IP
service
简介
通过以前的学习,我们已经能够通过Deployment来创建一组Pod来提供具有高可用性的服务。虽然每 个Pod都会分配一个单独的Pod IP,然而却存在如下两问题:
- Pod IP仅仅是集群内可见的虚拟IP,外部无法访问。
- Pod IP会随着Pod的销毁而消失,当Deployment对Pod进行动态伸缩时,Pod IP可能随时随地都 会变化,这样对于我们访问这个服务带来了难度。
- Service能够提供负载均衡的能力,但是在使用上有以下限制。只提供 4 层负载均衡能力,而没有 7 层功能,但有时我们可能需要更多的匹配规则来转发请求,这点上 4 层负载均衡是不支持的
因此,Kubernetes中的Service对象就是解决以上问题的实现服务发现核心关键。
Service 在 K8s 中有以下四种类型
- ClusterIp:默认类型,自动分配一个仅 Cluster 内部可以访问的虚拟 IP
- NodePort:在 ClusterIP 基础上为 Service 在每台机器上绑定一个端口,这样就可以通过 :
NodePort 来访 问该服务 - LoadBalancer:在 NodePort 的基础上,借助 cloud provider 创建一个外部负载均衡器,并将请 求转发 到NodePort。是付费服务,而且价格不菲。
- ExternalName:把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理 被创建,
这只有 kubernetes 1.7 或更高版本的 kube-dns 才支持
详解4 种 Service 类型
Services 和 Pods
Kubernetes的Pods是有生命周期的。他们可以被创建,而且销毁不会再启动。如果您使用 Deployment来运行您的应用程序,则它可以动态创建和销毁 Pod。
一个Kubernetes的Service是一种抽象,它定义了一组Pods的逻辑集合和一个用于访问它们的策略 - 有 的时候被称之为微服务。一个Service的目标Pod集合通常是由Label Selector 来决定的
举个例子,想象一个处理图片的后端运行了三个副本。这些副本都是可以替代的 - 前端不关心它们使用 的是哪一个后端。尽管实际组成后端集合的Pod可能会变化,前端的客户端却不需要知道这个变化,也 不需要自己有一个列表来记录这些后端服务。Service抽象能让你达到这种解耦。
不像 Pod 的 IP 地址,它实际路由到一个固定的目的地,Service 的 IP 实际上不能通过单个主机来进行 应答。相反,我们使用 iptables(Linux 中的数据包处理逻辑)来定义一个虚拟IP地址(VIP),它可以 根据需要透明地进行重定向。当客户端连接到 VIP 时,它们的流量会自动地传输到一个合适的 Endpoint。环境变量和 DNS,实际上会根据 Service 的 VIP 和端口来进行填充。
kube-proxy支持三种代理模式: 用户空间,iptables和IPVS;它们各自的操作略有不同。
- Userspace代理模式
Client Pod要访问Server Pod时,它先将请求发给本机内核空间中的service规则,由它再将请求,转给监 听在指定套接字上的kube-proxy,kube-proxy处理完请求,并分发请求到指定Server Pod后,再将请求 递交给内核空间中的service,由service将请求转给指定的Server Pod。由于其需要来回在用户空间和内 核空间交互通信,因此效率很差 。
当一个客户端连接到一个 VIP,iptables 规则开始起作用,它会重定向该数据包到 Service代理 的端 口。Service代理 选择一个 backend,并将客户端的流量代理到 backend 上。
这意味着 Service 的所有者能够选择任何他们想使用的端口,而不存在冲突的风险。客户端可以简单地 连接到一个 IP 和端口,而不需要知道实际访问了哪些 Pod。 - iptables代理模式
当一个客户端连接到一个 VIP,iptables 规则开始起作用。一个 backend 会被选择(或者根据会话亲和 性,或者随机),数据包被重定向到这个 backend。不像 userspace 代理,数据包从来不拷贝到用户 空间,kube-proxy 不是必须为该 VIP 工作而运行,并且客户端 IP 是不可更改的。当流量打到 Node 的 端口上,或通过负载均衡器,会执行相同的基本流程,但是在那些案例中客户端 IP 是可以更改的。 - IPVS代理模式
在大规模集群(例如10,000个服务)中,iptables 操作会显着降低速度。IPVS 专为负载平衡而设计, 并基于内核内哈希表。因此,您可以通过基于 IPVS 的 kube-proxy 在大量服务中实现性能一致性。同 时,基于 IPVS 的 kube-proxy 具有更复杂的负载平衡算法(最小连接,局部性,加权,持久性)。
在 Kubernetes 集群中,每个 Node 运行一个 kube-proxy 进程。 kube-proxy 负责为 Service 实现了一 种 VIP(虚拟 IP)的形式,而不是 ExternalName 的形式。 在 Kubernetes v1.0 版本,代理完全在 userspace。在 Kubernetes v1.1 版本,新增了 iptables 代理,但并不是默认的运行模式。 从 Kubernetes v1.2 起, 默认就是 iptables 代理。 在 Kubernetes v1.8.0-beta.0 中,添加了 ipvs 代理在 Kubernetes 1.14 版本开始默认 使用 ipvs 代理。在 Kubernetes v1.0 版本, Service 是 “4层”(TCP/UDP over IP)概念。 在 Kubernetes v1.1 版本,新增了Ingress API(beta 版),用来表示 “7层”(HTTP)服务 。
这种模式,kube-proxy 会监视 Kubernetes Service 对象和 Endpoints ,调用 netlink 接口以相应地创 建 ipvs 规则并定期与 Kubernetes Service 对象和 Endpoints 对象同步 ipvs 规则,以确保 ipvs 状态与期 望一 致。访问服务时,流量将被重定向到其中一个后端 Pod与 iptables 类似,ipvs 于 netfilter 的 hook 功 能,但使用哈希表作为底层数据结构并在内核空间中工作。这意味着 ipvs 可以更快地重定向流量,并 且在同步代理规则时具有更好的性能。此外,ipvs 为负载均衡算法提供了更多选项。
ClusterIP
类型为ClusterIP的service,这个service有一个Cluster-IP,其实就一个VIP。具体实现原理依靠 kubeproxy组件,通过iptables或是ipvs实现。
clusterIP 主要在每个 node 节点使用 iptables,将发向 clusterIP 对应端口的数据,转发到 kube-proxy 中。然 后 kube-proxy 自己内部实现有负载均衡的方法,并可以查询到这个 service 下对应 pod 的地址和端 口,进而把 数据转发给对应的 pod 的地址和端口
这种类型的service 只能在集群内访问。
使用镜像
docker pull tomcat:9.0.20-jre8-alpine
部署service
service/clusteripdemo.yml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: clusteripdemo
labels:
app: clusteripdemo
spec:
replicas: 3
template:
metadata:
name: clusteripdemo
labels:
app: clusteripdemo
spec:
containers:
- name: clusteripdemo
image: tomcat:9.0.20-jre8-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
restartPolicy: Always
selector:
matchLabels:
app: clusteripdemo
---
apiVersion: v1
kind: Service
metadata:
name: clusterip-svc
spec:
selector:
app: clusteripdemo
ports:
- port: 8080
targetPort: 8080
type: ClusterIP
运行service
运行服务
kubectl apply -f clusteripdemo.yml
查看服务
kubectl get svc
访问服务
curl 10.1.15.24:8080
删除服务
kubectl delete -f clusteripdemo.yml
NodePort
我们的场景不全是集群内访问,也需要集群外业务访问。那么ClusterIP就满足不了了。NodePort当然 是其中的一种实现方案。nodePort 的原理在于在 node 上开了一个端口,将向该端口的流量导入到 kube-proxy,然后由 kube-proxy 进一步到给对应的 pod 。
使用镜像
docker pull tomcat:9.0.20-jre8-alpine
部署service
service/nodeportdemo.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: clusteripdemo
labels:
app: clusteripdemo
spec:
replicas: 3
template:
metadata:
name: clusteripdemo
labels:
app: clusteripdemo
spec:
containers:
- name: clusteripdemo
image: tomcat:9.0.20-jre8-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
restartPolicy: Always
selector:
matchLabels:
app: clusteripdemo
---
apiVersion: v1
kind: Service
metadata:
name: clusterip-svc
spec:
selector:
app: clusteripdemo
ports:
- port: 8080
targetPort: 8080
nodePort: 30088
type: NodePort
运行service
运行服务
kubectl apply -f nodeportdemo.yml
查看服务
kubectl get svc
访问服务
curl 10.1.61.126:8080
浏览器访问服务
http://192.168.198.156:30088
删除服务
kubectl delete -f nodeportdemo.yml
LoadBalancer
LoadBalancer类型的service 是可以实现集群外部访问服务的另外一种解决方案。不过并不是所有的 k8s集群都会支持,大多是在公有云托管集群中会支持该类型。负载均衡器是异步创建的,关于被提供 的负载均衡器的信息将会通过Service的status.loadBalancer字段被发布出去。
创建 LoadBalancer service 的yaml 如下:
apiVersion: v1
kind: Service
metadata:
name: service-lagou
spec:
ports:
- port: 3000
protocol: TCP
targetPort: 443
nodePort: 30080
selector:
run: pod-lagou
type: LoadBalancer
ExternalName
类型为 ExternalName 的service将服务映射到 DNS 名称,而不是典型的选择器,例如my-service或者 cassandra。您可以使用spec.externalName参数指定这些服务。
这种类型的 Service 通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容( 例 如:
hub.lagouedu.com )。ExternalName Service 是 Service 的特例,它没有 selector,也没有定义任何 的端口和 Endpoint。相反的,对于运行在集群外部的服务,它通过返回该外部服务的cname(别名)这种方式来提 供服务
创建 ExternalName 类型的服务的 yaml 如下:
kind: Service
apiVersion: v1
metadata:
name: service-lagou
spec:
ports:
- port: 3000
protocol: TCP
targetPort: 443
type: ExternalName
externalName: www.lagou.com
ingress网络
什么是Ingress?
K8s集群对外暴露服务的方式目前只有三种:loadblancer、nodeport、ingress。前两种熟悉起来比较 快,而且使用起来也比较方便,前面课程已经讲解过两种技术。在此就不进行介绍了。
下面详细讲解下ingress这个服务,ingress由两部分组成:ingress controller和ingress服务。
其中ingress controller目前主要有两种:基于nginx服务的ingress controller和基于traefik的ingress controller。
而其中traefik的ingress controller,目前支持http和https协议。由于对nginx比较熟悉,而且需要使用 TCP负载,所以在此我们选择的是基于nginx服务的ingress controller。
在kubernetes集群中,我们知道service和pod的ip仅在集群内部访问。如果外部应用要访问集群内的服 务,集群外部的请求需要通过负载均衡转发到service在Node上暴露的NodePort上,然后再由kubeproxy组件将其转发给相关的pod。
而Ingress就是为进入集群的请求提供路由规则的集合,通俗点就是提供外部访问集群的入口,将外部 的HTTP或者HTTPS请求转发到集群内部service上。
Ingress-nginx组成
Ingress-nginx一般由三个组件组成:
- 反向代理负载均衡器:通常以service的port方式运行,接收并按照ingress定义的规则进行转发, 常用的有nginx,Haproxy,Traefik等,本次实验中使用的就是nginx。
- Ingress Controller:监听APIServer,根据用户编写的ingress规则(编写ingress的yaml文件), 动态地去更改nginx服务的配置文件,并且reload重载使其生效,此过程是自动化的(通过lua脚本 来实现)。
- Ingress:将nginx的配置抽象成一个Ingress对象,当用户每添加一个新的服务,只需要编写一个 新的ingress的yaml文件即可。
Ingress-nginx的工作原理
- ingress controller通过和kubernetes api交互,动态的去感知集群中ingress规则变化。然后读取 它,按照自定义的规则,规则就是写明了那个域名对应哪个service,生成一段nginx配置。
- 再写到nginx-ingress-controller的pod里,这个Ingress controller的pod里运行着一个Nginx服 务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中。然后reload一下使配置生效,以此 达到分配和动态更新问题。
官网地址
基于nginx服务的ingress controller根据不同的开发公司,又分为k8s社区的ingres-nginx和nginx 公司的nginx-ingress。
Ingress-Nginx github 地址:
https://github.com/kubernetes/ingress-nginx
Ingress-Nginx 官方网站:
https://kubernetes.github.io/ingress-nginx/
下载资源文件
根据github上的活跃度和关注人数,我们选择的是k8s社区的ingres-nginx。
下载ingrees-controller
打开github官网:选择某一个具体版本后进入deploy/static/目录中,复制mandatory.yaml文件
内容。
https://github.com/kubernetes/ingress-nginx/tree/nginx0.30.0/deploy/static/mandatory.yaml
下载镜像
需要将镜像pull到k8s集群各个node节点
ocker pull registry.cn-hangzhou.aliyuncs.com/google_containers/nginxingress-controller:0.30.0
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingresscontroller:0.30.0 quay.io/kubernetes-ingress-controller/nginx-ingresscontroller:0.30.0
docker rmi -f registry.cn-hangzhou.aliyuncs.com/google_containers/nginxingress-controller:0.30.0
ingress与ingress-controller
要理解ingress,需要区分两个概念,ingress和ingress-controller:
- ingress对象:
指的是k8s中的一个api对象,一般用yaml配置。作用是定义请求如何转发到service的规则,可以 理解为配置模板。 - ingress-controller:
具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,根据配置的规则来实现请 求转发。
简单来说,ingress-controller才是负责具体转发的组件,通过各种方式将它暴露在集群入口,外部对集 群的请求流量会先到ingress-controller,而ingress对象是用来告诉ingress-controller该如何转发请 求,比如哪些域名哪些path要转发到哪些服务等等。
ingress-controller
ingress-controller并不是k8s自带的组件,实际上ingress-controller只是一个统称,用户可以选择不同 的ingress-controller实现,目前,由k8s维护的ingress-controller只有google云的GCE与ingress-nginx 两个,其他还有很多第三方维护的ingress-controller,具体可以参考官方文档。但是不管哪一种 ingress-controller,实现的机制都大同小异,只是在具体配置上有差异。一般来说,ingress-controller 的形式都是一个pod,里面跑着daemon程序和反向代理程序。daemon负责不断监控集群的变化,根 据ingress对象生成配置并应用新配置到反向代理,比如nginx-ingress就是动态生成nginx配置,动态更 新upstream,并在需要的时候reload程序应用新配置。
ingress
ingress是一个API对象,和其他对象一样,通过yaml文件来配置。ingress通过http或https暴露集群内 部service,给service提供外部URL、负载均衡、SSL/TLS能力以及基于host的方向代理。ingress要依 靠ingress-controller来具体实现以上功能。
ingress网络实验一
使用镜像
docker pull tomcat:9.0.20-jre8-alpine
docker pull quay.io/kubernetes-ingress-controller/nginx-ingresscontroller:0.30.0
运行ingress-controller
在mandatory.yaml文件的Deployment资源中增加属性sepc.template.sepc.hostNetWork
hostNetwork: true
hostNetwork网络,这是一种直接定义Pod网络的方式。如果在Pod中使用hostNetwork:true配置网
络,那么Pod中运行的应用程序可以直接使用node节点的端口
运行ingress/mandatory.yaml文件
kubectl apply -f mandatory.yaml
运行ingress服务
运行ingress/service-nodeport.yaml文件
kubectl apply -f service-nodeport.yaml
部署tomcat-服务
ingress/tomcat-service.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deploy
labels:
app: tomcat-deploy
spec:
replicas: 1
template:
metadata:
name: tomcat-deploy
labels:
app: tomcat-deploy
spec:
containers:
- name: tomcat-deploy
image: tomcat:9.0.20-jre8-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
restartPolicy: Always
selector:
matchLabels:
app: tomcat-deploy
---
apiVersion: v1
kind: Service
metadata:
name: tomcat-svc
spec:
selector:
app: tomcat-deploy
ports:
- port: 8080
targetPort: 8080
type: NodePort
运行tomcat-service
kubectl apply -f tomcat-service.yml
部署ingress规则文件
ingress/ingress-tomcat.yml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-ingress-test
spec:
backend:
serviceName: tomcat-svc
servicePort: 8080
运行ingress规则
kubectl apply -f ingress-tomcat.yml
查看ingress
kubectl get ingress
查看ingress服务:查看service的部署端口号
kubectl get svc -n ingress-nginx
查看ingress-controller运行在那个node节点
kubectl get pod -n ingress-nginx -o wide
通过ingress访问tomcat
ingress网络实验二
上边案例的部署方式只能通过ingress-controller部署的节点访问。集群内其他节点无法访问ingress规 则。本章节通过修改mandatory.yaml文件的控制类类型,让集群内每一个节点都可以正常访问ingress 规则。
ingress-controller
ingress/mandatory.yaml
修改mandatory.yaml配置文件
1.将Deployment类型控制器修改为:DaemonSet
2.属性:replicas: 1 # 删除这行
service-nodeport固定端口
ingress/service-nodeport.yml
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
nodePort: 31188
protocol: TCP
- name: https
port: 443
targetPort: 443
nodePort: 31443
protocol: TCP
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
域名访问ingress规则
service/ingress-tomcat.yml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-ingress-test
spec:
rules:
- host: ingress-tomcat.lagou.com
http:
paths:
- path: /
backend:
serviceName: nodeporttomcat-svc
servicePort: 8080
修改宿主机hosts文件
C:\Windows\System32\drivers\etc\hosts
增加ingress-tomcat.lagou.com 域名配置:
192.168.198.157 ingress-tomcat.lagou.com
部署服务
kubectl apply -f .
浏览器测试
http://ingress-tomcat.lagou.com:31188/
nginx-controller原理
查看ingress-nginx 命名空间下的pod
kubectl get pods -n ingress-nginx
进入ingress-nginx 的pod
kubectl exec -it nginx-ingress-controller-5gt4l -n ingress-nginx sh
查看nginx反向代理域名ingress-tomcat.lagou.com
cat nginx.conf