Kubernetes从入门到精通

一、缘起:容器多了,也便有了烦恼

前回说到 Docker,一只只容器跑起来,倒也利落。然而容器一多,烦恼便来了。

一个人养三五只猫,尚且照应得过来;一旦养到三五百万只,便非得有个章程不可。哪只病了,哪只跑了,哪只该喂食,哪只该隔离,总不能全凭主人一双眼睛盯着。容器也是一样。一台机器上几十个,还好说;若是几百台机器,成千上万个容器,谁来管它们死活?谁来做主,让它们此起彼伏,各得其所?

这便是”容器编排”的由来。世间编排的工具原不止一种,但最终拔得头筹、几乎一统江湖的,是 Kubernetes。这名字源自希腊语,意为”舵手”——掌舵的人。Google 把自家内部用了十年的 Borg 系统的道理,开源了出来,便成了它。如今大抵简称 K8s——K 与 s 之间隔着八个字母,故云。

我以为,学 K8s 之前,先把 Docker 弄明白,是断然必要的。容器尚且不知为何物,便谈编排,无异于不会走路便要学骑马,非摔不可。

二、它究竟管些什么

舵手的职责,无非是让船开得稳。K8s 管的,也无非这么几桩:

  • 调度:新来的容器,该放到哪台机器上?它替你定夺。
  • 自愈:容器死了,它拉起来;机器坏了,它把上头的活儿挪到别处。
  • 扩缩容:忙了多起几个,闲了收掉几个。
  • 滚动更新与回滚:换新版,一点一点换;出了岔子,退回去。
  • 服务发现与负载均衡:容器之间彼此怎么找,怎么分担,它管。
  • 存储编排:数据往哪里搁,它替你张罗。

一言以蔽之,它替你照看着那一群朝生暮死的容器,叫它们此起彼伏,却总体上稳如泰山。

三、几个名词,先要弄清

K8s 的行话,比 Docker 还要多些。然而真正入门,要紧的也就下面这些。不必望而生畏。

Pod —— 最小的小卒

K8s 里调度的最小单位,不叫容器,叫 Pod。一个 Pod 里头,可以装一个或几个容器,它们同生共死,共享网络和存储。大抵相当于几个同住一间屋的伙计,一荣俱荣,一损俱损。日常用得最多的,是一个 Pod 一个容器——那多出来的位置,是留给”边车”的,比如顺带做个日志收集、代理转发之类。

Node —— 干活的机器

集群里的机器,叫 Node。分两种:Master(控制面)和 Worker(干活节点)。Master 是发号施令的,Worker 是实干的。Master 自己不下场跑业务,它只管调度指挥。

Deployment —— 带兵的将官

你平日说”我要三个 Nginx”,其实并非直接造三个 Pod,而是造一个 Deployment,告诉它”给我维持三个副本”。Deployment 便忠实地替你维持着,死一个补一个。它还管滚动更新——换版本时,新旧交替,缓缓而行。

Service —— 给 Pod 一个名分

Pod 是朝生暮死的,今日这个 IP,明日重启便换了。别的程序要寻它,总不能靠这朝三暮四的 IP。于是有 Service:它给一组 Pod 盖一个章,定一个固定的名字和 IP,无论底下 Pod 怎么换,寻这名字总找得到。它顺便还做负载均衡,把请求分到各 Pod 上。

Ingress —— 门房

Service 固然给了名字,可外头的世界要进来,总得有个门。Ingress 便是这扇门,管着 HTTP/HTTPS 的路由——哪个域名走哪个 Service,谁该走 HTTPS,它说了算。

ConfigMap 与 Secret —— 账本与密件

配置信息,写在 ConfigMap 里,像个账本,谁要谁来取;敏感的密码密钥,则放进 Secret,虽也是存着,却做了 base64 的一层遮掩,且可以挂载为文件或环境变量,不叫它明晃晃地写在镜像里。

Volume —— 给数据留的后路

Pod 一死,里头的文件便没了。要紧的数据,得挂个 Volume,独立于 Pod 而活。这点道理,与 Docker 一脉相承。

Namespace —— 分而治之

一个大集群,许多人共用,总得划出几间屋子,各管各的,互不相扰。这屋子便是 Namespace。生产一个、测试一个,或这个团队一个、那个团队一个,井水不犯河水。

四、架构:一座小小的朝廷

K8s 的架构,活像一个小朝廷,分作”控制面”与”工作节点”两头。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
┌─────────────── 控制面 (Control Plane) ───────────────┐
│ kube-apiserver —— 朝廷的门口,所有命令由此进出 │
│ etcd —— 档案库,集群一切状态都存于此 │
│ kube-scheduler —— 调度官,新 Pod 该去哪个 Node │
│ kube-controller-manager —— 各路监工,盯着各种活计 │
│ cloud-controller-manager —— 与云厂商打交道的 │
└──────────────────────────────────────────────────────┘

┌────────────────┼────────────────┐
▼ ▼ ▼
┌─ Worker ─┐ ┌─ Worker ─┐ ┌─ Worker ─┐
│ kubelet │ │ kubelet │ │ kubelet │ ← 每个 Node 上的监工
│ kube-proxy│ │ kube-proxy│ │ kube-proxy│ ← 管网络规则的
│ 容器运行时 │ │ 容器运行时 │ │ 容器运行时 │ ← containerd / docker
│ Pod Pod │ │ Pod Pod │ │ Pod Pod │
└──────────┘ └──────────┘ └──────────┘
  • kube-apiserver:一切命令的入口。你用 kubectl 敲的每条命令,都先到它这里。
  • etcd:一个键值数据库,集群的全部家底——有哪些 Pod、哪些 Node、什么配置——都记在它里头。它是命根子,丢了它,整个集群便失了忆。
  • kube-scheduler:新来的 Pod 没着落,它来安排去哪个 Node。
  • kube-controller-manager:一群监工的合集。Deployment 的副本数对不对、Node 掉线了要不要挪 Pod,都归它管。
  • kubelet:每个 Node 上一个,听 Master 的令,照看着本机的 Pod,该起起,该停停。
  • kube-proxy:每个 Node 上一个,管着网络转发与负载均衡的规则。
  • 容器运行时:真正跑容器的家伙,如今多用 containerd,Docker 也行,但已渐渐退居二线。

五、安装:搭一个练手的集群

生产环境的 K8s,装起来颇为繁复(推荐用 kubeadm,或干脆用云厂商的托管服务如 AKS/EKS/GKE)。但若是练手,我劝你用轻量工具,三五分钟便起一套,免得在安装上耗尽了兴致。

minikube —— 单机练手

1
2
3
4
5
6
7
8
9
# 装 minikube(Linux)
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube

# 起一个集群
minikube start

# 看看
kubectl get nodes

kind —— 用 Docker 跑 K8s

1
2
3
# 装好后
kind create cluster --name mycluster
kubectl get nodes

kubectl —— 那条指挥棒

无论哪种集群,你都得装 kubectl,这是你与集群说话的嘴。

1
2
3
4
5
# Linux
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

kubectl version --client

装好,连上集群,kubectl get nodes 能看到节点,便算成了。

开启 kubectl 自动补全

1
2
3
echo 'source <(kubectl completion bash)' >> ~/.bashrc
source ~/.bashrc
# 此后按 Tab,命令自会补全,省却许多记忆之苦

六、kubectl:那条指挥棒

kubectl 的命令,大抵是这个模样:kubectl <动作> <资源类型> [名字] [选项]。例如 kubectl get pod nginx,便是”取一下名叫 nginx 的 Pod 看看”。

查看类

1
2
3
4
5
6
7
8
kubectl get nodes                  # 看节点
kubectl get pods # 看当前 Namespace 的 Pod
kubectl get pods -A # 看所有 Namespace 的 Pod
kubectl get pods -o wide # 看得详细些,带 IP、所在 Node
kubectl get deploy,svc,ingress # 一并看几种资源
kubectl describe pod <名字> # 看某 Pod 的来龙去脉(排错利器)
kubectl get pod -l app=nginx # 按标签筛
kubectl explain pod.spec # 查字段说明,如同随身的文档

操作类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
kubectl create deployment nginx --image=nginx:1.25 --replicas=3
kubectl scale deployment nginx --replicas=5 # 扩到五个
kubectl rollout status deployment/nginx # 看滚动更新进度
kubectl rollout undo deployment/nginx # 回滚到上一版
kubectl rollout history deployment/nginx # 看历史版本

kubectl expose deployment nginx --port=80 --type=NodePort # 暴露一个 Service

kubectl exec -it <pod> -- bash # 钻进 Pod
kubectl logs -f <pod> # 看日志
kubectl logs <pod> -c <容器名> # 多容器时指定看哪个
kubectl cp <pod>:/path ./local # 拷文件出来

kubectl apply -f xxx.yaml # 照着文件部署(推荐)
kubectl delete -f xxx.yaml # 照着文件删
kubectl delete pod <名字> # 删一个 Pod(Deployment 会再补一个)
kubectl edit deployment nginx # 直接改配置(临时改用)

kubectl top nodes # 看节点资源占用
kubectl top pods # 看 Pod 资源占用

Namespace 的进退

1
2
3
kubectl get ns                       # 看有哪些屋子
kubectl create ns dev # 造一间 dev
kubectl config set-context --current --namespace=dev # 以后默认在 dev 里干活

一句话:记住 kubectl getkubectl describekubectl apply -f 这三板斧,便能走遍天下。其余的,用得着时再查不迟。

七、第一个实战:部署一个 Nginx

道理说了这许多,不如动手。我们来部署一个 Nginx,三层都搭齐:Deployment、Service、Ingress。

然而,真正像样的做法,不是敲 kubectl create 那种一次性的命令,而是写 YAML——把你想的样子,用文字白纸黑字写下来,存进版本库。这便是所谓”声明式”的道理:你不说”去给我做这个”,只说”我要它变成这个样子”,K8s 自会去把现实捋成你写的样子。

Deployment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 3 # 我要三个副本
selector:
matchLabels:
app: nginx # 我管的,是带 app=nginx 标签的 Pod
strategy:
type: RollingUpdate # 滚动更新
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template: # Pod 的模样
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests: # 至少要这些
cpu: 100m
memory: 128Mi
limits: # 最多用这些
cpu: 500m
memory: 256Mi
readinessProbe: # 准备好了才接客
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe: # 还活着吗
httpGet:
path: /
port: 80
initialDelaySeconds: 15
periodSeconds: 20
1
2
kubectl apply -f nginx-deployment.yaml
kubectl get pods -l app=nginx

Service

1
2
3
4
5
6
7
8
9
10
11
12
# nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
selector:
app: nginx # 把流量引到带这标签的 Pod
type: ClusterIP # 仅集群内可达
ports:
- port: 80 # Service 的端口
targetPort: 80 # Pod 的端口
1
2
kubectl apply -f nginx-service.yaml
kubectl get svc nginx

Service 有几种类型,用途各异:

  • ClusterIP(默认):集群内部一个虚拟 IP,外头进不来。
  • NodePort:在每个 Node 上开一个端口(30000–32767),外头能进。练手用。
  • LoadBalancer:云上自动给你配一个负载均衡器,生产常用。
  • ExternalName:做个 DNS 别名,指向集群外的服务。

Ingress

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# nginx-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx
spec:
rules:
- host: nginx.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx
port:
number: 80

用 Ingress,得先装个 Ingress Controller(如 ingress-nginx),否则这规则写了也没人执行,如同贴了告示却没有门房。

八、YAML 的骨架

所有的 K8s YAML,骨架都是这么个模样,记住它,便算入门了一半:

1
2
3
4
5
6
7
8
9
apiVersion: apps/v1        # 用哪个 API 版本
kind: Deployment # 这是个什么资源
metadata: # 元数据:名字、标签、Namespace
name: nginx
namespace: default
labels:
app: nginx
spec: # 规格:你想要它变成什么样
... # 不同 kind,这里头写法不同

最常搅混的,是 Deployment 里 selectortemplate 的标签必须对得上——selector.matchLabels 说”我管带这些标签的”,而 template 造出来的 Pod 必须带着这些标签。两者对不上,Deployment 便不认自己造的 Pod,白白干着急。

九、配置与敏感信息

镜像是死的,配置却是活的。同一套镜像,开发用一套配置,生产用另一套,这才像样。所以配置不该塞进镜像,而该分开来放。

ConfigMap —— 账本

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
LOG_LEVEL: "info"
DB_HOST: "db.default.svc.cluster.local"
nginx.conf: |
server {
listen 80;
location / { proxy_pass http://backend; }
}

Secret —— 密件

1
2
3
4
5
6
7
8
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
# 值是 base64 编码的(注意:这只是遮掩,并非加密)
password: cGFzczEyMw== # echo -n 'pass123' | base64

用法:挂为环境变量,或挂为文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
spec:
containers:
- name: app
image: myapp:1.0
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
# 或者整个挂成文件
volumeMounts:
- name: config-vol
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: config-vol
configMap:
name: app-config

须注意:Secret 的 base64,只是不让人一眼看清,并非真加密。真正要紧的密钥,该上 Vault、云 KMS,或开启 etcd 的静态加密,方才稳妥。

十、数据持久化:StatefulSet 与 PVC

Deployment 管的是无状态的兵——死一个补一个,谁是谁无所谓。可有些应用是有状态的:数据库便是。它的数据不能丢,它的身份也不能乱——主从之分,各司其职。这类,得用 StatefulSet。

StatefulSet 造出来的 Pod,名字是排了号的:db-0、db-1、db-2,顺序井然,各有各的存储,各记各的账。即便重建,db-0 还是 db-0,还连着 db-0 那块旧盘。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql # 必须配一个 headless Service
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
volumeMounts:
- name: data
mountPath: /var/lib/mysql
volumeClaimTemplates: # 每个 Pod 自动申请一块盘
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi

这里头出现了 volumeClaimTemplates,便是 PVC——向存储系统申请一块地。这块地由 StorageClass(存储类)来供给,云上自动给你造一块云盘,本地则有 local、nfs 等。

三种负载类型,理清它们

类型 用谁 何时用
Deployment 无状态应用 Nginx、Tomcat、Web 后端
StatefulSet 有状态应用 数据库、消息队列、需稳定身份/存储的
DaemonSet 每个 Node 一个 日志采集、监控代理、网络插件

外加一个 Job / CronJob:跑完即退的活儿,如数据迁移;定时跑的,如备份。

十一、调度:谁去哪台机器

Pod 该落到哪个 Node 上,本是调度器的事。但有时你总想插一手——这几个 Pod 不能挤一台,那几个只准跑在带 SSD 的机器上。这便靠”亲和性”与”污点”。

节点选择器(最简)

1
2
3
spec:
nodeSelector:
disktype: ssd # 只去带 disktype=ssd 标签的 Node

亲和与反亲和(更精细)

1
2
3
4
5
6
7
8
9
10
spec:
affinity:
podAntiAffinity: # 反亲和:别和同类挤一块
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: nginx
topologyKey: kubernetes.io/hostname
# 意思:带 app=nginx 的 Pod,别落在同一个 Node 上
# 于是三个副本,会尽量分散到三个 Node

污点与容忍

有些 Node 你想专用——比如 GPU 机器,只准跑 AI 的活。便给这 Node 打个”污点”,别人家的 Pod 嫌脏不肯来;只有声明了”容忍”的 Pod,才上得去。

1
2
# 给节点打污点
kubectl taint nodes gpu-node dedicated=gpu:NoSchedule
1
2
3
4
5
6
spec:
tolerations:
- key: "dedicated"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"

十二、HPA:忙则增,闲则减

人来人往,流量有高低。固定副本数,既费钱又怕扛不住。HPA(Horizontal Pod Autoscaler)便是管这事:看着 CPU 或自定义指标,忙了加 Pod,闲了减 Pod。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # CPU 超过 70% 就加 Pod

用 HPA,得先装个 metrics-server,否则它没处看指标。

十三、Helm:包管理,一捆一捆地装

手写一堆 YAML,部署一个应用尚可;若要部署一整套(如 Prometheus 监控全家桶),一个个文件敲下来,未免啰嗦。于是有 Helm——K8s 的包管理器,相当于 Ubuntu 的 apt、CentOS 的 yum。它把一组 YAML 打成一个”Chart”,配置项抽出来,改几个值便成一套新部署。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 装 Helm
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# 加个仓库
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update

# 搜、装
helm search repo nginx
helm install my-nginx bitnami/nginx

# 看装了什么
helm list

# 升级、卸载
helm upgrade my-nginx bitnami/nginx --set replicaCount=5
helm uninstall my-nginx

自定义 Chart:

1
2
3
4
helm create myapp          # 生成一个 Chart 骨架
# 改 myapp/values.yaml 里的值,改 myapp/templates/ 里的模板
helm install myapp ./myapp -f myapp/values.yaml
helm template ./myapp # 先渲染看看生成什么,不真部署

十四、排错:出了岔子怎么办

我以为,学 K8s,一半的功夫在排错上。集群这东西,不出问题则已,一出便叫人抓瞎。这里有几条路数,按图索骥便好。

第一招:看 Pod 状态

1
kubectl get pods

常见的几种异常状态:

  • Pending:Pod 没被调度。多半是资源不够、没合适的 Node、或被污点挡了。kubectl describe pod <名字>,看最底下的 Events。
  • ContainerCreating:正在创建,卡住多半是拉镜像失败、挂存储失败、或 ConfigMap/Secret 不存在。
  • CrashLoopBackOff:起来就崩,崩了又起,循环往复。多半是程序自身的问题。kubectl logs <名字> 看它说了什么。
  • ImagePullBackOff:镜像拉不下来。检查镜像名对不对、仓库凭证配没配。
  • OOMKilled:内存超了 limits 被杀。调大 limits,或查程序为何吃内存。

第二招:describe 看 Events

1
kubectl describe pod <名字>

最底下的 Events 一栏,往往直指病根——什么时候调度了、什么时候拉镜像了、为什么失败。这是排错头一等的工具。

第三招:看日志

1
2
3
kubectl logs <pod>
kubectl logs <pod> --previous # 看上一次崩掉前的日志(极有用)
kubectl logs -f <pod> # 实时跟

第四招:钻进去

1
2
kubectl exec -it <pod> -- bash
# 在里头 ping、curl、看文件,排查网络与配置问题

第五招:看节点

1
2
3
kubectl get nodes -o wide
kubectl describe node <名字> # 看资源分配、污点、状态
kubectl top nodes # 看实际占用

Node 若是 NotReady,多半是 kubelet 挂了、或机器本身出了问题。

常见疑难

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# Pod 一直 Pending
kubectl describe pod <名字> # 看 Events,常是资源不足或调度约束太严

# 镜像拉不下来
# 若是私有仓库,需配 imagePullSecrets
kubectl create secret docker-registry regcred \
--docker-server=registry.example.com \
--docker-username=user \
--docker-password=pass \
--docker-email=user@example.com
# 然后在 Pod spec 里:
# imagePullSecrets:
# - name: regcred

# Service 不通
kubectl get endpoints <svc> # 若 ENDPOINTS 是空的,说明 selector 没匹配上 Pod
kubectl exec -it <某pod> -- curl <svc名>:<端口>

# DNS 解析不了
kubectl exec -it <pod> -- nslookup kubernetes.default
# 多半是 CoreDNS 的问题
kubectl get pods -n kube-system -l k8s-app=kube-dns

# 证书过期(kubeadm 集群)
kubeadm certs check-expiration
kubeadm certs renew all
systemctl restart kubelet

# etcd 备份(命根子,要常备份)
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
snapshot save /backup/etcd-snapshot.db

十五、安全:几分警惕

K8s 默认并非铁桶一只,该加固处仍须加固。我以为有几条,断不可省:

1
2
3
4
5
6
7
8
9
10
1. RBAC:用最小权限。ServiceAccount 别图省事绑 cluster-admin,
该用 Role/RoleBinding 限定到某 Namespace。
2. 网络策略(NetworkPolicy):默认 Pod 之间是互通的,
生产环境该用 NetworkPolicy 限定谁能访问谁。
3. Pod Security:禁用特权容器、禁用挂载宿主路径、以非 root 运行。
新版用 Pod Security Admission,替代旧的 PodSecurityPolicy。
4. Secret 该加密:开启 etcd 静态加密,或接外部 KMS/Vault。
5. API Server 别裸奔:用 TLS、开审计日志、限制匿名访问。
6. 镜像该扫描:trivy、clair,堵住已知漏洞。
7. 及时升级:K8s 漏洞年年有,别守着三年前的旧版本不放。

RBAC 一例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
apiVersion: v1
kind: ServiceAccount
metadata:
name: ci-bot
namespace: dev
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-manager
namespace: dev
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ci-bot-pod-manager
namespace: dev
subjects:
- kind: ServiceAccount
name: ci-bot
namespace: dev
roleRef:
kind: Role
name: pod-manager
apiGroup: rbac.authorization.k8s.io

十六、速查表

要做什么 念这句
看节点 kubectl get nodes
看 Pod kubectl get pods -A
看 Pod 详情 kubectl describe pod <名字>
看日志 kubectl logs -f <名字>
看崩前的日志 kubectl logs <名字> --previous
进 Pod kubectl exec -it <名字> -- bash
部署 kubectl apply -f xxx.yaml
kubectl delete -f xxx.yaml
扩缩容 kubectl scale deploy <名字> --replicas=5
回滚 kubectl rollout undo deploy/<名字>
看资源 kubectl top nodes / kubectl top pods
切 Namespace kubectl config set-context --current --namespace=dev
看所有资源 kubectl get all -n <ns>
查字段 kubectl explain pod.spec.containers

结尾的话

K8s 这东西,初看庞杂得吓人——概念多,名词多,YAML 又长。然而细细理来,脉络其实分明:无非是用 声明式 的 YAML,描述你想要的模样,然后让控制面去把现实捋成那个模样。Pod 是兵,Deployment 是将,Service 是名分,Ingress 是门,ConfigMap/Secret 是账本与密件,StatefulSet 管有状态的,PVC 管存数据的。把这些个角色的道理弄通,大半的场面便能应付了。

学它的法子,我以为别无他途:先 minikube 起一套,亲手写几个 YAML,部署、扩缩、更新、回滚、排错,各做一遍。看十遍文档,不如自己崩一次 Pod 再救回来。纸上得来终觉浅,绝知此事要躬行——这话虽是古人说的,放在 K8s 上,再贴切不过。

至于再往前的 operator、service mesh(Istio)、CI/CD 流水线、多集群管理,那是各人的造化与机缘了。地基打牢了,上头盖什么楼,都好说。

参考的所在: