云原生 ·

Kubernetes (K8s) 入门:核心对象、kubectl 常用命令与排障全解

K8s 是容器编排的事实标准。本文从 Pod、Deployment、Service、Ingress、PV/PVC 五大基础对象入手,配合 kubectl 常用命令、集群搭法、以及 CrashLoopBackOff / ImagePullBackOff 等 20+ 常见报错的排查路径。

Kubernetes (K8s) 入门:核心对象、kubectl 常用命令与排障全解

Kubernetes(简称 K8s,K + 8 个字母 + s) 是 Google 开源的容器编排与调度平台。你把一组容器的期望状态(多少副本、暴露什么端口、挂哪个盘、健康检查怎么算)用 YAML 声明,K8s 就会自动把它调度到合适的机器、不断观察、失败自动恢复、滚动升级、自动扩缩容。

一、架构总览

1.1 控制平面(Control Plane,以前叫 Master)

组件作用
kube-apiserver集群唯一入口,所有组件都通过它读写 etcd;kubectl 也是连它
etcd分布式 KV 数据库,存集群所有状态(“事实唯一来源”)
kube-scheduler看着新建的 Pod 还没绑定节点 → 选一台合适的 Node 绑上去
kube-controller-manager一堆”控制环”:Node Controller、Replication(副本数)、Endpoint、ServiceAccount…
cloud-controller-manager对接公有云:LB、云盘、路由(可选,用云厂商 K8s 服务就有)

1.2 工作节点(Worker Node)

组件作用
kubeletNode 上的代理:APIServer 说这台机要跑哪些 Pod → 真的把容器拉起来、做健康检查
kube-proxy在每台 Node 上维护 iptables / ipvs 规则,实现 Service 网络转发
容器运行时containerd(默认) / cri-o 等,真正跑容器(Docker Engine 1.24+ 弃用)
PodK8s 最小调度单元。一个 Pod 里可以有多个容器(共享网络栈 + 共享卷),通常”一个 Pod = 一个主容器”

二、先搭一个最小化集群(学习用)

方案 A:kind 最快(Docker 起 3 个容器当 3 个节点)

# 装 kind(macOS)
brew install kind kubectl

# 建集群
cat > kind.yaml << 'EOF'
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  - role: control-plane
  - role: worker
  - role: worker
EOF
kind create cluster --name demo --config kind.yaml

# 切到 demo 上下文
kubectl cluster-info
kubectl get nodes -o wide

方案 B:minikube / k3s

  • minikube:单机体验型,VM/Docker 都能装,addon 多
  • k3s:Rancher 出品,二进制 <100MB,砍掉了云插件,适合边缘/测试。生产小规模也能直接用

方案 C:生产级:kubeadm 三台裸机 / ECS

# 所有节点:装 containerd / kubeadm / kubelet / kubectl(版本 1.30)
# 然后在 Master:
sudo kubeadm init \
  --kubernetes-version=v1.30.0 \
  --apiserver-advertise-address=192.168.1.100 \
  --pod-network-cidr=10.244.0.0/16 \
  --service-cidr=10.96.0.0/12 \
  --upload-certs

# 按输出让 Worker 节点 join
# 在本机:
mkdir -p ~/.kube
sudo cp -i /etc/kubernetes/admin.conf ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config

# 装 CNI 网络插件(必须,不然 CoreDNS 起不来),这里选 Flannel:
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

# 等 30s,看 Node 状态 Ready 没
kubectl get nodes -w

三、五大核心对象

3.1 Pod:最小调度单元

pod-demo.yaml

apiVersion: v1
kind: Pod
metadata:
  name: nginx-demo
  labels:
    app: nginx
    tier: web
spec:
  containers:
    - name: nginx
      image: nginx:1.27-alpine
      ports:
        - containerPort: 80
      resources:
        requests: { cpu: 100m, memory: 128Mi }
        limits:   { cpu: 500m, memory: 512Mi }
      readinessProbe:
        httpGet: { path: /, port: 80 }
        initialDelaySeconds: 3
        periodSeconds: 10
      livenessProbe:
        httpGet: { path: /, port: 80 }
        initialDelaySeconds: 10
        periodSeconds: 20

实际项目里几乎不会手写 Pod,而是用下面的 Deployment 来管理。

3.2 Deployment:管理 Pod 副本 + 滚动升级

deploy-nginx.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
spec:
  replicas: 3
  revisionHistoryLimit: 10
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1        # 升级时最多多起 1 个 Pod
      maxUnavailable: 0  # 升级时最少保持 3 个 Pod 可用
  selector:
    matchLabels:
      app: nginx
  template:             # 下面就是 Pod 的 template,直接复用上面 Pod 的 spec
    metadata:
      labels: { app: nginx }
    spec:
      containers:
        - name: nginx
          image: nginx:1.27-alpine
          ports: [{ containerPort: 80 }]
          resources:
            requests: { cpu: 100m, memory: 128Mi }
            limits:   { cpu: 500m, memory: 512Mi }
          readinessProbe: { httpGet: { path: /, port: 80 }, initialDelaySeconds: 3, periodSeconds: 10 }
          livenessProbe:  { httpGet: { path: /, port: 80 }, initialDelaySeconds: 10, periodSeconds: 20 }

3.3 Service:给一组 Pod 一个稳定的访问入口

svc-nginx.yaml

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  type: ClusterIP          # 仅集群内访问。可选 NodePort / LoadBalancer / ExternalName
  selector: { app: nginx } # 把流量转给所有带 app=nginx 的 Pod
  ports:
    - name: http
      port: 80             # Service 端口
      targetPort: 80       # Pod 容器端口

四种 Service 类型:

类型说明场景
ClusterIP(默认)分配一个集群内虚拟 IP,其他 Pod / Service 能访问绝大多数内部服务
NodePort在每台 Node 上开一个端口(30000-32767)外部就能 <任意NodeIP:NodePort> 访问临时测试、配合外层 LB
LoadBalancer调云厂商 API 自动分配一个公网 LB 挂到 Service 上云上对外服务(Nginx Ingress Controller 常用这种)
ExternalName直接 CNAME 到外部域名,比如 xxx.rds.aliyuncs.com让集群内访问外部 DB 像访问内部 Service 一样

3.4 Ingress:把 7 层域名路由到 Service

先装 Nginx Ingress Controller(kind 自带):

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml

ing-nginx.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ing
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
  ingressClassName: nginx
  rules:
    - host: nginx.k8s.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx-svc
                port: { number: 80 }

3.5 PV / PVC:持久化存储

  1. StorageClass(集群管理员先配好,大多数云 K8s 自带)
  2. PVC(PersistentVolumeClaim):用户声明”我要 10GB ReadWriteOnce”
  3. PV(PersistentVolume):对应真实的磁盘(云盘 / NFS / Ceph / LocalPath)

pvc-demo.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
spec:
  accessModes: ["ReadWriteOnce"]
  resources:
    requests:
      storage: 10Gi
  storageClassName: standard
---
apiVersion: apps/v1
kind: Deployment
metadata: { name: mysql }
spec:
  selector: { matchLabels: { app: mysql } }
  template:
    metadata: { labels: { app: mysql } }
    spec:
      containers:
        - name: mysql
          image: mysql:8.0
          env:
            - { name: MYSQL_ROOT_PASSWORD, value: "ChangeMe123" }
          ports: [{ containerPort: 3306 }]
          volumeMounts:
            - { name: data, mountPath: /var/lib/mysql }
      volumes:
        - name: data
          persistentVolumeClaim: { claimName: mysql-pvc }

3.6 ConfigMap & Secret:放配置

apiVersion: v1
kind: ConfigMap
metadata: { name: app-cm }
data:
  APP_ENV: "production"
  DB_HOST: "mysql.default.svc.cluster.local"
  config.toml: |
    [server]
    port = 3000
---
apiVersion: v1
kind: Secret            # 只是默认 base64,不是加密!生产用 SealedSecret / ExternalSecret / Vault
metadata: { name: app-secret }
type: Opaque
stringData:
  DB_PASSWORD: "s3cret!p@ss"
---
# Pod 里引用
envFrom:
  - configMapRef: { name: app-cm }
  - secretRef:    { name: app-secret }
volumeMounts:
  - { name: cm, mountPath: /etc/app/config.toml, subPath: config.toml }
volumes:
  - name: cm
    configMap: { name: app-cm }

四、kubectl 常用命令速查

4.1 看

kubectl get nodes / pods / deploy / svc / ing / pvc / sc / events -o wide -w
# -A = --all-namespaces;-n 指定命名空间
kubectl describe pod <POD>          # 最有用:调度/事件/探针失败/卷挂不上都在 Events
kubectl logs -f --tail=200 <POD> -c <CONTAINER>  # 多容器要加 -c
kubectl logs -f deployment/nginx-deploy --all-containers=true
kubectl exec -it <POD> -- bash      # 进 Pod

4.2 改 / 应用

kubectl apply -f xxx.yaml                           # 声明式改(推荐,会算 diff)
kubectl create -f xxx.yaml                          # 命令式(一次性)
kubectl delete -f xxx.yaml
kubectl set image deploy/nginx-deploy nginx=nginx:1.28-alpine --record    # 换镜像 + 记原因
kubectl rollout status  deploy/nginx-deploy
kubectl rollout history deploy/nginx-deploy
kubectl rollout undo    deploy/nginx-deploy                    # 回滚到上一版
kubectl rollout undo    deploy/nginx-deploy --to-revision=3    # 回滚到指定版本
kubectl scale deploy/nginx-deploy --replicas=5
kubectl autoscale deploy/nginx-deploy --min=2 --max=10 --cpu-percent=70   # 基于 CPU 自动扩缩

4.3 排错”三板斧”

# 1. 看 Pod 状态
kubectl get pods -A -o wide
# 2. 看事件(调度、绑定、拉镜像、探针失败都在这)
kubectl describe pod -n <NS> <POD>
# 3. 看真实日志
kubectl logs -n <NS> --previous <POD>      # --previous 看上次挂掉那一版的日志

五、学习路线建议

  1. 会写五大核心对象的 YAML:Pod / Deploy / Service / Ingress / PVC
  2. 理解调度nodeSelector / affinity / taint & toleration / 资源 requests & limits
  3. 理解配置管理:ConfigMap、Secret、Downward API、Helm Charts
  4. 理解网络:kube-proxy iptables 模式、Service ClusterIP 怎么来的、CNI 插件(Flannel / Calico / Cilium)
  5. 理解存储:StorageClass、CSI、扩容、快照
  6. 可观测性:Metrics Server(HPA 要)/ Prometheus + Grafana / ELK / Jaeger
  7. 包管理:Helm → 进阶 Helmfile、ArgoCD (GitOps)
  8. 安全:RBAC、SA + Token、NetworkPolicy、PodSecurity / PSA、OPA Gatekeeper

六、日常排障手册

6.1 Pod 常见状态速查

STATUS含义典型原因
Pending还没调度到节点 / 调度到了但卷没挂上资源不够 / PVC 没绑定 / 镜像拉取中慢 / 污点不匹配
ContainerCreating容器创建中多半是镜像在拉(慢)或 init container 没完
ImagePullBackOff / ErrImagePull镜像拉取失败镜像名写错、私人仓库没登、网络不通 Docker Hub、tag 不存在、exec format error 架构不对
CrashLoopBackOff容器一启动就挂,K8s 指数退避重试程序本身 panic / exit 1 / 配置错 / 健康检查配错 / 端口占用
RunContainerError容器跑不起来启动命令写错、挂载点目录不存在、磁盘只读没权限
Error / ExitCode 非 0容器启动直接报错退出同上,logs --previous 看真因
OOMKilled内存越界被宿主机 kill调大 resources.limits.memory 或查程序 leak
Evicted节点 Disk / Memory 压力大,kubelet 把 Pod 赶出来了清节点磁盘 / 调 requests 避免争抢
Terminating在删 Pod 但一直删不掉1) 容器里进程没响应 SIGTERM;2) 挂载卷脱不下来。kubectl delete pod --force --grace-period=0

6.2 常用报错排查路径

A. CrashLoopBackOff(最常见)

# ① 事件里看看是什么错
kubectl describe pod <POD> | grep -A 20 Events
# ② 看上次启动为什么退出(重要!)
kubectl logs --previous <POD> -c <CONTAINER>
# ③ 退出码
kubectl get pod <POD> -o jsonpath='{.status.containerStatuses[0].lastState.terminated}' | jq

B. ImagePullBackOff

# ① 先在同一台 Node 上 docker pull / crictl pull 同款镜像试
# ② 看事件里具体报错:"not found" / "unauthorized" / "i/o timeout"
# ③ 私有仓库:加 imagePullSecrets 到 Pod 或 ServiceAccount
kubectl create secret docker-registry regcred \
  --docker-server=registry.cn-hangzhou.aliyuncs.com \
  --docker-username=xxx --docker-password=xxx
# 在 Pod spec 里写:
#   imagePullSecrets: [{ name: regcred }]

C. Service 连不通

# ① Endpoints 有没有?(Service selector 有没有匹配到 Pod)
kubectl get endpoints <SVC>
# 为空 = selector 写错 / Pod 没就绪(检查 Pod labels & readiness)

# ② 直接打 Pod IP + 端口通不通?
kubectl run tmp --rm -it --image=nicolaka/netshoot -- bash
  # 进了容器里:
  curl -v http://<POD_IP>:80

# ③ Pod 通但 Service 不通:
  # a. Pod 没 readiness,还没进 endpoints
  # b. kube-proxy 挂了:journalctl -u kube-proxy
  # c. iptables/ipvs 规则错:iptables-save | grep <SVC ClusterIP>

D. Ingress 404 / 502 / 503

# 1. Ingress Controller Pod 是否 healthy?
kubectl -n ingress-nginx get pod

# 2. Controller 日志看请求有没有到
kubectl -n ingress-nginx logs -f deployment/ingress-nginx-controller

# 3. Ingress 规则 + IngressClass 是否匹配
kubectl get ing -A -o wide
kubectl get ingressclass

# 4. 503 = Service 或 Endpoints 空 / Service 端口名写错
# 5. 404 = pathType / host / rewrite 规则不匹配

E. PVC 一直 Pending

kubectl describe pvc <PVC> | grep Events
# 常见原因:
# ① 没有 StorageClass(名字写错)
# ② 存储池容量满
# ③ 云盘/存储插件报错,看 controller-manager 日志或 csi-provisioner

F. Node NotReady

# ① ssh 上去看 kubelet
systemctl status kubelet
journalctl -u kubelet -n 200 --no-pager
crictl ps   # 看容器运行时

# ② 常见根因:
# - 节点磁盘满(docker system prune / /var/lib/kubelet / journalctl --vacuum-size=500M)
# - 时间不同步(timedatectl set-ntp true)
# - apiserver 网络不通(curl https://<APISERVER>:6443/version)
# - kubelet 证书过期(kubeadm certs renew all 后重启)

6.3 通用 Debug Pod(进入集群任意节点网络视角)

# 临时起一个"排障工具箱 Pod":自带 curl/wget/dig/traceroute/iperf3/tcpdump/strace/lsof...
kubectl run tmp-shell --rm -it --image=nicolaka/netshoot -- bash

# 想共享某个 Pod 的网络栈(不用进容器本身,省得它没装工具):
kubectl debug -it <POD> --image=nicolaka/netshoot --target=<容器名> --share-processes

6.4 集群慢 / 性能分析

  1. kubectl top nodes / top pods -A → 看 CPU / 内存水位(要装 metrics-server)
  2. 某 Pod CPU 高:kubectl exec -it <POD> -- sh -c 'apk add htop 2>/dev/null; htop',或宿主机 pidstat / perf
  3. 调度慢:看 kube-scheduler 日志 → 所有 Node 都被过滤器(资源、亲和、污点)拒了?
  4. apiserver 慢:
    kubectl top pod -n kube-system | grep kube-apiserver
    # 看 etcd:ETCD 写 WAL 慢是常见瓶颈(盘慢 → SSD 升级)
  5. kube-proxy 规则爆炸(万级 Service 用 iptables 模式很慢)→ 切 mode: ipvs

七、安全与 RBAC 速记

K8s 权限三件套:

  • Role / ClusterRole:定义”对什么资源可以做什么操作”(verbs: get/list/watch/create/update/patch/delete…)
  • RoleBinding / ClusterRoleBinding:把上面的 Role 绑定到”谁”(User / Group / ServiceAccount)

示例:给某个 ServiceAccount 只能看 default 命名空间的 Pod:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata: { name: pod-reader, namespace: default }
rules:
  - apiGroups: [""]
    resources: ["pods", "pods/log"]
    verbs:     ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata: { name: read-pods, namespace: default }
subjects:
  - kind: ServiceAccount
    name: default   # 某个 SA
    namespace: default
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

八、进阶学习方向

  1. Helm:K8s 的包管理,K8s 生态 90% 的组件都是 Helm chart 发的
  2. ArgoCD / Flux(GitOps):Git 改了自动 apply 到集群
  3. Cilium / eBPF:取代 kube-proxy,提供更好的网络、网络策略、可观测
  4. Istio / Linkerd 服务网格:mTLS、灰度、流量镜像、熔断
  5. KEDA:基于事件(Kafka lag / 队列)的自动扩缩容
  6. Kyverno / Gatekeeper(OPA):策略引擎,“所有镜像必须来自公司私有仓库”这种规则强制
  7. kube-state-metrics + Prometheus + Grafana + Alertmanager:标准监控三件套
  8. Karpenter / Cluster Autoscaler:集群级自动扩节点

参考资料

问问 AI