发布时间:2022年10月12日
Kubernetes 是一个开源容器编排平台(也可以叫做分布式资源管理框架),用于调度以及自动部署、管理和扩展容器化应用,消除了容器化应用程序在部署、伸缩时涉及到的许多手动操作。
一般简称为 k8s ,官方文档:Kubernetes 文档 | Kubernetes
架构中的一些概念
在 k8s 中,集群管理的一切内容均称之为资源,包括:集群节点、应用、存储卷等,我们一般通过创建对应 YAML 文件的方式声明式的创建我们想要的资源清单类型。
作为 k8s 集群的使用方,我们只需要关注在编排应用中可能用到的资源类型即可,从资源对应能力角度,我们可以将其分为以下几类:
以上几种资源组合起来就可以形成一个下图中的完整应用
下面我们就按照从内到外的顺序,介绍一下这些资源各自的能力
apiVersion: v1
kind: Pod
metadata:
name: show-default-pod
namespace: mocha
spec:
containers:
- name: default-nginx
image: docker.io/nginx:latest
ports:
- containerPort: 80
name: "http-server"
然后执行 kubectl apply -f pod.yaml
# 删除pod
kubectl dele pod ${pod-name}
# 修改 Pod 镜像版本
kubectl set image pod ${pod-name} ${container-name}=${image-name}
在 k8s 中,Deployment 是最常用的用来编排 Pod 的资源清单,通过使用 Deployment 来控制 Pod,我们可以轻松的实现如 滚动更新、应用回滚、自动负载均衡/扩缩容功能。
除 Deployment 外,StatefulSet、ReplicaSet、DaemonSet、Job、CronJob 都、也可以用来编排 Pod。
值得一提的是,Deployment 并不直接负责 Pod 的创建。当我们创建/更新一个 Deployment 时,其都会创建一个对应版本的 ReplicaSet,并由 RS 完成对应 Pod 的创建。
三者的关系可以从下图中看出
通过这个特性,我们可以实现滚动更新、应用回滚的功能。
当 Deployment 更新时,其会创建一个新版本的 RS,此时新的 RS 会创建对应版本的 Pod,在新的 Pod 尚未完全启动前,所有对该应用的访问都会调度到老版本的应用中。当 Deployment 配置了多个副本时,k8s 会遵循启动一个销毁一个的逻辑实现应用的更新。
有了上面的设计,实现应用的回滚也很简单,我们在回滚 Deployment 的更新时,Deploy 会将回滚目标版本对应的 RS 重新激活,然后就是与应用更新相同的过程,启动一个新 Pod 销毁一个当前 Pod,直至回滚完成。
声明一个最简单的 Deployment 所需要配置的 YAML 文件如下
apiVersion: apps/v1
kind: Deployment // 声明类型
metadata:
name: nginx-deployment // deployment的名字
spec:
selector: // 定义选择器,用于控制创建的pod
matchLabels: // Deployment管理的 Pod Label
app: nginx // 与要管理的 Pod 的 label 相同
replicas: 2 // 创建几个副本
revisionHistoryLimit: 3 // 保存的历史版本数
template: // 创建的Pod的模板属性
metadata:
labels: // 创建的Pod的label属性,需要与 Selector 中一致,否则无法管理
app: nginx // Pod的Label key:value 允许任意定义
spec: // 与pod定义中的spec相同
containers:
- name: anyname // 这个容器的名字无所谓随便取
image: docker.io/nginx:latest
ports:
- containerPort: 80
然后手动创建该 Deploy
kubectl apply -f deployment.yaml
创建结果如下图:
当所有 Pod 创建完成后可以通过 k get po -n namespace 命令查看 Pod
为了查看是否我们的前端应用是否启动完成,可以直接在对应 Pod 中执行 curl 127.0.0.1 命令来查看 nginx 服务是否返回了正常页面
# 修改镜像
kubectl set image deploy ${deployment-name} ${container-name}=${image-name}
# 伸缩副本
kubectl scale deploy ${deployment-name} --replicas=${replicas-number}
# 回滚升级
kubectl rollout undo deploy ${deployment-name}
# 查看历史版本
kubectl rollout history deploy ${deployment-name}
# 回滚到指定版本
kubectl rollout undo deploy ${deploy-name} --to-revision=${visionId}
# 重启Deploy控制的所有Pod
kubectl rollout restart deploy ${deployment-name}
在 k8s 集群中,Pod 是无法直接对外提供服务的,原因有两个:
apiVersion: v1
kind: Service
metadata:
name: share-svc
namespace: mocha
spec:
selector:
app: share-nginx-pod
ports:
- port: 80 # svc 监听的端口,互相之间可以重复,一般与TargetPort相同
protocol: TCP # 协议
targetPort: 80 # svc 关联 Pod 中服务的监听端口
type: ClusterIP # 集群IP,不直接对外提供访问
与 Deployment - ReplicaSet - Pod 类似,Service - Pod 之间也存在一个中间角色:EndPoints,简写为 ep。
当我们声明一个 svc 后,集群会自动创建一个相对应的 ep,同时收集与 selector
相匹配的 Pod 的信息并记录在 ep 内,当 svc 收到网络请求时,会根据 ep 中记录的信息将请求转发给具体的 Pod。
Service 根据类型可以分为:CluserIP、NodePort 两种模式:
此外,针对每一个 svc,k8s 集群都为其创建了一个供集群内部访问的地址,组成方式为 {svc-name}.{namespace}.svc.cluster.local。
如果集群内部的 Pod 之间存在相互调用,可以通过内部地址来请求,k8s 会自动将其转换成对应 svc 的地址并分发到具体的应用中
原理:创建 svc 时,k8s 将 svc 信息写入自己的 dns 服务,并使用 etcd 持久化存储,当集群内通过 svc 地址请求时,利用 iptables 将其请求重定向
通常情况下,service 和 pod 仅可在集群内部网络中通过 IP 地址访问。此时所有访问集群的流量都会被丢弃或转发到其他地方,也就是说 service 通常不直接对外提供服务,而 Ingress 便是流量与 service 的连接器。
具体来说,Ingress 是流量与服务对应关系的规则集合,是从 Kubernetes 集群外部访问集群内部服务的入口,我们可以在 Ingress 中配置 域名/Path 与 svc的关系、配置 SSL 连接、负载均衡等
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: default-ingress
namespace: default
spec:
rules:
- host: mdks.top
http:
paths:
- backend:
service:
name: mdks-svc
port:
number: 80
path: /
pathType: Prefix
tls:
- hosts:
- mdks.top
secretName: mdks-tls