Kubernetes入门,不仅需要先了解以下基础概念,并需要拥有编写基础yaml的能力。
我这里先从宏观上列出来:
- 基础资源:Namespace、Pod、Label、Deployment、Service
- Pod 详情:Pod 配置、生命周期、调度、亲和性、污点容忍
- Pod 控制器:ReplicaSet、Deployment、DaemonSet、Job、CronJob、HPA
- 网络访问:Service、Ingress
- 存储:EmptyDir、HostPath、NFS、PV、PVC
- 配置和安全:ConfigMap、Secret、认证、授权、准入控制
- 可视化管理:Dashboard
k8s 核心资源对象与应用编排基础
-
- 一、Kubernetes是什么?
- 二、必须掌握的知识
- 三、Kubernetes总图
- [四、Kubernetes 的YAML文件怎么看?](#四、Kubernetes 的YAML文件怎么看?)
- [五、NameSpace 作用](#五、NameSpace 作用)
- [六、Pod 是最小的运行单元](#六、Pod 是最小的运行单元)
- [七、Label 与 Selector 匹配规则](#七、Label 与 Selector 匹配规则)
- [八、Deployment 管理无状态应用的核心对象](#八、Deployment 管理无状态应用的核心对象)
- [九、Service 对外来访问提供一个核心入口](#九、Service 对外来访问提供一个核心入口)
- [十、Ingress 与 Gateway API 外部集群访问入口](#十、Ingress 与 Gateway API 外部集群访问入口)
- [十一、ConfigMap 与 Secret:配置不要写死在镜像里:](#十一、ConfigMap 与 Secret:配置不要写死在镜像里:)
- [十二、Pod 探针](#十二、Pod 探针)
- 十三、resources:requests与limits
- [十四、Pod 的声明周期与常见错误](#十四、Pod 的声明周期与常见错误)
- [十五、调度 Pod 会被安放到那个节点上。](#十五、调度 Pod 会被安放到那个节点上。)
- 十六、控制器
- 十七、存储
- 十八、RBAC
一、Kubernetes是什么?
他是一套,可以自动化部署、管理、扩缩容、自愈恢复应用的平台。
在我看来,k8s的核心思想就是声明 ,通过 yaml 声明状态,然后系统会尽量让 实际状态 向着 声明状态 靠近。
二、必须掌握的知识
就是我在文章开头,就有专门提到的哪些。
三、Kubernetes总图
Kubernetes不是单体软件,而是由多个组件组成的编排系统。
整体可以被划分成 控制平面 与 工作节点 两部分。
其中,控制平面 中,有
kube-apiserver 是k8s的通信总入口,像 kubectl 就是通过它才能控制集群;
etcd 保存整个集群的状态数据(一般通过yaml控制的,都会写道这里);
kube-scheduler 用来计算 Pod 调度位置;
controller-manager 用来控制实际情况向着期望靠近;
而工作节点 ,有
kubelet 每个节点的代理,负责管理 Pod 的生命周期,通过控制 containerd 来操控 Pod;
containterd 用于容器的 拉取、运行、删除等操作;
kube-proxy 通常用来实现 service 的网络转发规则,让请求可以打到 Pod 上;
创建过程 :
由 kubectl 将yaml 文件转发至 apiserver,
然后将 yaml 转化成的资源对象 存进 etcd 中,
而scheduler、controller 与 kubelet 通过监听 apiserver 感知资源变化,并进行 Pod 位置计算、与调度
最终由 kubelet 操控 containerd 让现实 情况,朝着期望靠近。
外来请求访问过程 :
一般先达到 Ingress 上,然后转发至 service 中,
然后 kube-proxy 根据 service 中的规则匹配,
将请求打到 Pod 上。
四、Kubernetes 的YAML文件怎么看?
如下,是一个典型的yaml文件。
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: demo
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
通常 yaml 文件的核心,是由四部分构成。
- apiVersion 用来声明所在组 和版本
- kind 用来声明新建的资源类型,比如 Pod、Service、Deployment 呀
- metadata 用来定义我是谁(元数据),比如名字、所在命名空间、该组件的标签、额外的注释等
- 而 spec 则来定义期望状态,希望如何被 k8s 维护,比如创建几个副本、开放哪个端口、生命周期是什么
最后,k8s 会尽量让实际状态朝着 spec 的定义靠拢。
五、NameSpace 作用
NameSpace 的作用就是给 kubernetes 进行逻辑分组。
很多时候,都是需要做到,权限划分、环境隔离的,
比如不同环境、不同项目、不同团队等;
一般命名空间可以定义成:test 用来测试、dev 用来开发、prod 用来生产等;
yaml
apiVersion: v1
Kind: Namespace
metadata:
name: dev
通常 namespace 只是通过为不同资源,打上一个标签字段,从而做到逻辑隔离。
他本是并不是物理隔离!
如果想要做到更强的隔离效果,需要结合RBAC进行权限控制、NetworkPolicy(类似于防火墙规则) 进行网络隔离。
六、Pod 是最小的运行单元
Pod 是 Kubernetes 里面的最小的可调度单元,
他内部可以运行多个容器,如果没有强绑定的要求,通常只会运行一个主容器,
Pod 拥有自己的 IP、生命周期、挂载卷、资源限制;
通常 Pod 的状态变化是从, pending、runing、最后或许会成为 succeed 或 faild。
但实际环境中,是不会直接创建 Pod 的,
而是通过 depolyment、Service、daemset 等进行间接创建;
因为直接创建的 Pod ,不容易管理状体、迭代、自愈等行为。
常见创建 yaml 文件:
yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
namespace: demo
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
常见操作方式:
cmd
kubectl apply -f pod.yaml
kubectl get pod -n demo
kubectl describe pod nginx-pod -n demo
kubectl logs nginx-pod -n demo
七、Label 与 Selector 匹配规则
Label 为资源打上标签;
Selector 根据标签,对资源进行筛选
这个机制在 k8s 中很重要,因为很多对象之间通常是通过标签 进行关联的,而非名字。
比如 Deployment 通过标签管理 Pod。Service 通过 selector 找到 Pod。
打标签:
yaml
metadata:
labels:
app: nginx
env: dev
# app=nginx、env=dev 这两个标签
匹配:
yaml
selector:
app: nginx
八、Deployment 管理无状态应用的核心对象
deployment 通常是借助的 replicaset 的手,间接管理一组无状态 的 Pod。
进行 版本迭代、滚动、扩缩容、自愈等功能。
创建 Deployment / yaml 的操作方式:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: demo
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
常见的操作命令:
yaml
kubectl apply -f deployment.yaml
kubectl get deploy -n demo
kubectl get rs -n demo
kubectl get pod -n demo
kubectl scale deploy nginx --replicas=5 -n demo
kubectl set image deployment/nginx nginx=nginx:1.28 -n demo
kubectl rollout status deployment/nginx -n demo
kubectl rollout history deployment/nginx -n demo
kubectl rollout undo deployment/nginx -n demo
九、Service 对外来访问提供一个核心入口
Pod 一经重启、扩缩容等操作,可能会导致IP发生改变,所以无法对外界提供稳定的访问入口。
而 Service 就是 一个暴露在一个或多个 Pod 上的网络访问方案 。把多个 Pod 的访问入口聚合在一起,提供统一的、稳定的访问集群的入口。
起作用的方式:Service 通过 label 与 selector 进行筛选作用域,
并维护一个 EndpointSlice 列表用来记录Pod 的 ip,用于将访问Service的请求转发到 Pod 上。
Service,有二个最常见的类型:
ClusterIP 只允许集群内部访问,是默认类型。
NodePort 每个节点开放对外端口,允许外部的访问集群。
其余两个类型因为不太常用,这里就不展开了;
创建方式:
yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: demo
spec:
type: ClusterIP
selector:
app: nginx
ports:
- port: 80
targetPort: 80
常用命令:
yaml
kubectl apply -f service.yaml
kubectl get svc -n demo
kubectl describe svc nginx-svc -n demo
kubectl get endpoints -n demo
十、Ingress 与 Gateway API 外部集群访问入口
Service 解决的是,如何访问一组 Pod;
而 Ingress 解决的是 http/https 请求的流量进入集群时,根据域名和路径,将请求分发到对应的 Service 上;
并且 Ingress 只是一种规则,具体的作用靠 Ingress Controller 实现。
Gateway API 是 Ingress 的新一代增强版。有更清晰的权限划分、更强的路由拓展能力,可以适应更复杂的流量治理场景。
yaml 文件编写:
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
namespace: demo
spec:
rules:
- host: www.metaassist.cn
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
十一、ConfigMap 与 Secret:配置不要写死在镜像里:
通常在运行容器的时候,
如 登录mysql、redis的账号密码、运行环境等
一些可变的配置,不应该直接写死在镜像里。
通常一些普通配置,可以写在 ConfigMap 中。
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: demo
data:
APP_ENV: "dev"
LOG_LEVEL: "debug"
使用时:
yaml
envFrom:
- configMapRef:
name: app-config
而一些敏感的配置项,可以放到 secret 中。
但 secret 的信息安全保证,不是通过 base64 的编码确定的。
而是通过,权限控制、etcd 静态加密,才做到保护隐私的。
其实 ConfigMap 与 Secret 主要区别于语义和习惯。
ConfigMap 多用于普通配置。
Secret 多用于敏感信息配置。
十二、Pod 探针
生产环境中,常遇到主进程启动了,但是他所运行的业务不一定可以用。
也就是说,虽然 Pod 进入 Running 状态了,但是并不代表,他就一定可以使用。
比如,
- 虽然启动进程了,但是端口可能没有监听、
- 应用启动较慢,还没准备好接收请求、
- 甚至是数据库没连接导致启动失败,但进程未退出。
所以 Pod 探针是监控状态,从而采取不同应对措施的。
有三类探针,分别是:
startupProbe 探针:用来判断是否成功启动,通常用于启动缓慢的Pod;
livenessProbe 探针:用来判断Pod是否还存活,用于判断异常,从而决定是否要重启;
ReadinessProbe 探针:用来判断Pod是否能接收外来访问流量,如果异常就直接从 service 名单上去除。
yaml
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 10
periodSeconds: 5
readinessProbe:
httpGet:
path: /ready
port: 80
initialDelaySeconds: 5
periodSeconds: 5
十三、resources:requests与limits
requests: 声明调度时最低资源需求,比如 cpu核数与所需内存;然后调度器会根据 requests 来判断哪个 Node 可以放下该 Pod。
limits:运行时,限定 cpu核数 与 所需内存 上限;
yaml 编写方式:
yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.27
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
十四、Pod 的声明周期与常见错误
Pending:Pod 刚被创建,但是还未运行;
Running:Pod内,至少有一个容器在运行;
Succeeded:Pod 已经成功运行完毕,并且已经已把 Pod 正常退出;
Failed:Pod 运行失败,并且已退出;
Unknown:无法确定 Pod 状态;
ImagePullBackOff:镜像拉取失败
ErrImagePull:镜像拉取错误
CrashLoopBackOff:容器反复崩溃重启
CreateContainerConfigError:创建容器时,配置错误
OOMKilled:内存超限。
一般出现错误的时候,先用 describe 查询 k8s 层面的错误,从宏观上定位;
确定之后,在用 logs 对具体容器的日志进行排查。
两者不在一个层次上。
yaml
kubectl get pod -n demo
kubectl describe pod <pod> -n demo
kubectl logs <pod> -n demo
kubectl logs <pod> -c <container> -n demo
kubectl get events -n demo
十五、调度 Pod 会被安放到那个节点上。
亲和性是 Pod 主动选择靠近、污点是 Node 节点主动排斥,容忍度是 Pod 表示可以接收 Node 的污点。
常用调度概念:
nodeSelector:最简单的节点选择
nodeAffinity:更灵活的节点亲和性
podAffinity:让 Pod 靠近某些 Pod
podAntiAffinity:让 Pod 避开某些 Pod
taint:节点打污点,拒绝普通 Pod
toleration:Pod 声明可以容忍某些污点
以 Deployment 为例的 yaml 文件:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ai-demo
spec:
replicas: 1
selector:
matchLabels:
app: ai-demo
template:
metadata:
labels:
app: ai-demo
spec:
# Pod 主动去靠近 带有 gpu=true 标签的节点
nodeSelector:
gpu: "true"
# 可以容忍 dedicated=gpu 节点上的,NoSchedule 的污点
tolerations:
- key: "dedicated"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"
containers:
- name: ai-demo
image: nginx:1.27
污点常见的几个效果:
NoSchedule:不允许新的普通 Pod 调度到这个节点;
PreferNoSchedule:尽量不允许,但不是绝对禁止;
NoExecute:不但不允许新的 Pod 进行调度,而且还会对旧的进行驱逐。
十六、控制器
ReplicaSet:保证Pod的副本数,一般不直接创建,而是由 Deployment 进行控制;
DaemonSet:对每个节点都创建固定容器;
Job:一次性任务清单,并会确保把清单内的所有 Pod 创建完毕。创建失败则会按照策略重试;
CronJob:定时任务;
HPA:自动扩缩容;
十七、存储
emptyDir :一个临时目录,Pod创建时产生、Pod销毁时同步销毁;
HostPath :将宿主机的目录进行挂载到Pod中;
NFS :多个Pod可以共享的,远程存储方式;
PV/PVC :
PV 是 Kubernetes 中抽象出来的持久化存储资源;
PVC 是用户对存储资源的申请。
Pod 不直接关心底层是 NFS、Ceph 还是云盘,而是通过 PVC 来申请和挂载存储。
最典型是 PVC + Pod 挂载:
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-pvc
namespace: demo
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
意思是:
我申请一块 1Gi 的持久化存储。
Pod 使用这个 PVC:
yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
namespace: demo
spec:
containers:
- name: nginx
image: nginx:1.27
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
volumes:
- name: data
persistentVolumeClaim:
claimName: app-pvc
意思是:
把 app-pvc 申请到的存储,挂载到容器里的 /usr/share/nginx/html 目录。
十八、RBAC
RBAC 是基于角色的访问控制。
官方文档上说,Kubernetes RBAC API 包含四种对象:Role、ClusterRole、RoleBinding、ClusterRoleBinding。
你要记住:
Role:命名空间级权限
ClusterRole:集群级权限
RoleBinding:把 Role 或 ClusterRole 绑定给用户 / ServiceAccount
ClusterRoleBinding:在集群级别绑定 ClusterRole
ServiceAccount:Pod 访问 apiserver 时使用的身份