K8s学习文档

集群基础

K8s 架构与核心组件

步骤1: 理解 Kubernetes 架构

Kubernetes 是一个容器编排平台,核心组件分为两类:

控制平面 (Control Plane): – kube-apiserver — 集群统一入口,所有操作都通过 API Server – etcd — 分布式键值存储,保存集群所有数据 – kube-scheduler — 调度器,决定 Pod 运行在哪个节点 – kube-controller-manager — 控制器管理器,维护集群期望状态

工作节点 (Worker Node): – kubelet — 节点代理,管理 Pod 生命周期 – kube-proxy — 网络代理,维护节点上的网络规则 – Container Runtime — 容器运行时(containerd / CRI-O)

步骤2: 集群组件通信流程

用户 → kubectl → API Server → etcd (存储)
                ↓
          Scheduler (选择节点)
                ↓
          Controller Manager
                ↓
        kubelet (在目标节点启动 Pod)

了解这些组件如何协作是学习 K8s 的第一步。

步骤3: 名词概念

概念说明
PodK8s 最小调度单元,可包含 1 个或多个容器
Node工作机器,可以是物理机或虚拟机
Namespace资源隔离的虚拟集群
Service为 Pod 提供稳定的网络访问入口
Deployment管理 Pod 的声明式更新和伸缩
ConfigMap非敏感配置数据
Secret敏感数据(密码、Token 等)

步骤4: kubectl 基本命令格式

kubectl <verb> <resource> [options]

常用 verb: – get — 查看资源 – describe — 查看资源详情 – create — 创建资源 – apply — 声明式创建/更新 – delete — 删除资源 – logs — 查看日志 – exec — 进入容器

步骤5: 集群信息概览

kubectl cluster-info
kubectl version
kubectl api-resources

了解集群提供了哪些 API 资源,这是后续所有操作的基础。

kubectl 命令行基础

步骤1: kubectl 命令结构

kubectl 是 K8s 的命令行工具,所有操作都通过它与集群交互:

kubectl <verb> <resource> [flags]

常用 verb 速查:

命令用途示例
get查看资源列表kubectl get pods
describe查看资源详细信息kubectl describe pod my-pod
create创建资源kubectl create -f pod.yaml
apply声明式创建/更新kubectl apply -f manifest.yaml
delete删除资源kubectl delete pod my-pod
logs查看日志kubectl logs my-pod
exec进入容器执行命令kubectl exec -it my-pod -- /bin/sh
explain查看资源字段文档kubectl explain pod.spec

步骤2: 探索集群资源

# 查看所有 API 资源类型
kubectl api-resources
​
# 查看集群节点
kubectl get nodes -o wide
​
# 查看所有命名空间
kubectl get namespaces
​
#查看自己命名空间
kubectl describe namespace user-176-1514

理解 -o 输出格式: – -o wide — 显示额外列(IP、节点) – -o yaml — 完整 YAML 定义 – -o json — JSON 格式 – -o jsonpath=... — 提取特定字段

步骤3: 创建第一个 Pod

右側编辑器粘贴以下内容,执行 kubectl apply -f manifest.yaml:

执行之前先检查

kubectl apply --dry-run=server -f manifest.yaml
apiVersion: v1
kind: Pod
metadata:
name: hello-k8s
labels:
  app: demo
spec:
containers:
- name: busybox
  image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/busybox:latest
  command: ["/bin/sh", "-c", "echo 'Hello K8s!'; sleep 3600"]
  resources:
    requests:
      cpu: 10m
      memory: 32Mi
    limits:
      cpu: 100m
      memory: 64Mi

查看 Pod 的所有信息:

kubectl get pod hello-k8s -o wide
kubectl describe pod hello-k8s
kubectl get pod hello-k8s -o yaml | head -30

临时启pod,类似docker run

基本格式

kubectl run <Pod名> --image=<镜像> [flags]
#新版 kubectl 默认给你造的是 Deployment 而不是 Pod——想"临时起个 Pod"就必须显式声明   --restart=Never 
kubectl run web-demo --image=nginx:stable-alpine --restart=Never
#做端口转发
kubectl port-forward pod/web-demo 800:80 -n user-176-1514
# 临时 Pod,跑完就删(-it 交互 + --rm)
kubectl run tmp --image=<busybox地址> --restart=Never -it --rm -- /bin/sh

#指定容器名(旧版不支持,使用这个命令查询👉)kubectl run --help | grep container-name
kubectl run web-demo --image=<地址> --restart=Never \
--container-name=nginx -n user-176-1514

导出run命令为yaml

#--dry-run=client 只生成不提交,改好文件再 apply:
kubectl run web-demo --image=<地址> --restart=Never \
--dry-run=client -o yaml > web-demo.yaml

步骤4: Label 和 Selector

Label 是 K8s 的核心组织机制:

# 给 Pod 添加标签
kubectl label pod hello-k8s env=dev version=v1

# 按标签筛选
kubectl get pods -l env=dev
kubectl get pods -l 'env in (dev,staging)'

# 查看 Pod 的标签
kubectl get pods --show-labels

步骤5: 清理

kubectl delete pod hello-k8s

步骤6: 常用调试命令

# 实时跟踪 Pod 状态变化
kubectl get pods -w

#查看所有 Pod 及其容器
kubectl get pods \
-n user-176-1514 \
-o custom-columns='POD:.metadata.name,CONTAINERS:.spec.containers[*].name'



# 查看 Pod 日志
kubectl logs hello-k8s

#容器创建中时看不到log只能查看events
kubectl describe pod raft-test -n user-176-1514 | tail -30

kubectl get pod raft-test -n user-176-1514 \
-o jsonpath='{.status.containerStatuses[*].state}{"\n"}'

#查看有多个容器的pod 可以使用这个命令,会提示Defaulted container "app" out of: app, log-tailer
kubectl logs hello-k8s
#查看pod的全部容器命令
kubectl logs more-con --all-containers=true

# 进入 Pod shell
kubectl exec -it hello-k8s -- /bin/sh

# 从 Pod 复制文件到本地(工具箱)
kubectl cp hello-k8s:/etc/hostname /tmp/hostname
cat /tmp/hostname

#查看当前用户资源限制
kubectl describe limitrange -n user-176-1514
kubectl describe resourcequota -n user-176-1514
kubectl get resourcequota web-apps-quota -n user-176-1514

修改资源限制持久化

#编辑某一资源限制配置
kubectl edit resourcequota web-apps-quota -n user-176-1514

toolbox:/# cat /data/4h4g.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: web-apps-quota
namespace: user-176-1514
spec:
hard:
requests.cpu: "4"
requests.memory: 4Gi
limits.cpu: "4"
limits.memory: 4Gi
count/deployments.apps: "8"

kubectl get resourcequota web-apps-quota -n user-176-1514 -o yaml
kubectl describe resourcequota web-apps-quota -n user-176-1514

登录镜像仓库

#防止密码输出到shell
read -rsp "请输入 ACR 密码: " ACR_PASSWORD
echo

kubectl create secret docker-registry aliyun-acr --docker-server=crpi-xfeuebyl27sae6su.ap-northeast-1.personal.cr.aliyuncs.com --docker-username=hs888p --docker-password=Linuxjk.cn6 --namespace=user-176-1514

#清除密码变量
unset ACR_PASSWORD

#查看当前镜像仓库配置
kubectl get secret aliyun-acr -n user-176-1514
#查看基本信息
kubectl describe secret aliyun-acr -n user-176-1514
#编辑非敏感信息
kubectl edit secret aliyun-acr -n user-176-1514

默认上下文配置

kubectl config set-context --current --namespace=user-176-1514

#配置好就是持久化的,会写入 ~/.kube/config
#查看是否生效,NAMESPACE 一列应该显示:
kubectl config get-contexts

#只查看当前 context:
kubectl config current-context
#查看完整配置
kubectl config view --minify
#只查看当前默认 namespace:
kubectl config view --minify -o jsonpath='{..namespace}{"\n"}'

集群节点管理

步骤1: 查看集群节点

kubectl get nodes -o wide
kubectl describe node $(kubectl get nodes -o name | head -1 | cut -d/ -f2)

重点观察: – Conditions: Ready / MemoryPressure / DiskPressure / PIDPressure – Capacity vs Allocatable: 节点总资源 vs 可分配资源 – Taints: 节点污点(阻止 Pod 调度的标记)

步骤2: 理解 Taint 和 Toleration

Taint(污点)标记在节点上,排斥不匹配的 Pod。Toleration(容忍)标记在 Pod 上,允许调度到有特定 Taint 的节点。

查看节点的 Taint:

kubectl describe nodes | grep -A1 Taints

常见 Taint 示例: – node.kubernetes.io/not-ready:NoSchedule — 节点未就绪 – node-role.kubernetes.io/master:NoSchedule — Master 节点默认不调度用户 Pod

给控制平面恢复标准污点:

kubectl taint nodes k8s-001 k8s-002 k8s-003 \
node-role.kubernetes.io/control-plane=:NoSchedule

确认:

kubectl get nodes -o custom-columns='NAME:.metadata.name,TAINTS:.spec.taints'

这个操作:

  • 不会驱逐已经运行在控制平面的普通 Pod,因为是 NoSchedule
  • 只阻止后续不具备对应 toleration 的 Pod 调度过去
  • 控制平面静态 Pod 不受影响
  • DaemonSet 是否继续运行取决于其 tolerations,常见系统组件通常已经兼容

建议先检查当前有哪些非系统 Pod 跑在控制平面:

kubectl get pods -A -o wide \
--field-selector spec.nodeName=k8s-001

kubectl get pods -A -o wide \
--field-selector spec.nodeName=k8s-002

kubectl get pods -A -o wide \
--field-selector spec.nodeName=k8s-003

删除标准污点:

kubectl taint nodes k8s-001 \
node-role.kubernetes.io/control-plane:NoSchedule-

污点可以自定义,格式是:key=value:effect

例如:

kubectl taint nodes k8s-001 dedicated=control-plane:NoSchedule

但是针对控制平面节点,推荐使用 Kubernetes 的标准污点,而不是自定义污点

node-role.kubernetes.io/control-plane 是 key

value 为空,所以写成 =

NoSchedule 是 effect

三种 effect 的区别:

  • NoSchedule:不再调度新的、不容忍该污点的 Pod;不影响已运行 Pod。控制平面隔离通常选这个。
  • PreferNoSchedule:尽量不调度,但资源不足时仍可能调度。
  • NoExecute:既禁止新调度,也会驱逐现有不容忍该污点的 Pod,使用要谨慎。

步骤3: Cordon — 标记节点不可调度

Cordon 阻止新 Pod 调度到该节点,但不驱逐已有 Pod:

# 查看当前节点名
NODE=$(kubectl get nodes -o name | head -1 | cut -d/ -f2)
echo "目标节点: $NODE"

# Cordon(封锁节点)
kubectl cordon $NODE
kubectl get nodes # 观察 STATUS 列出现 SchedulingDisabled

# Uncordon(取消封锁)
kubectl uncordon $NODE

步骤4: Drain — 安全驱逐

Drain 会先 cordon 节点,再逐出所有 Pod:

# 安全驱逐(忽略 DaemonSet 和 emptyDir)
kubectl drain $NODE --ignore-daemonsets --delete-emptydir-data --force

Deployment 管理的 Pod 会在其他节点重建,DaemonSet 的 Pod 会被忽略。

注意:在生产环境中,drain 操作需要谨慎——确保有足够的资源在其他节点上重建 Pod。

步骤5: 节点标签

# 查看节点标签
kubectl get nodes --show-labels

# 添加自定义标签
kubectl label node $NODE disktype=ssd
#这里可以加上--overwrite 用于标签已存在时覆盖原值
# 给多个工作节点打同一个标签
kubectl label node k8s-w2-005 k8s-w2-006 pool=work

#验证自定义标签
kubectl get nodes -l pool=work
kubectl get nodes --show-labels

# 删除标签(key 后面加减号)
kubectl label node k8s-w5-008 pool-

# 使用 nodeSelector 调度 Pod 到特定节点
kubectl run nginx-ssd --image=swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/nginx:alpine --dry-run=client -o yaml > /tmp/ns.yaml
  • 根据命令生成一个 Pod YAML
  • --dry-run=client 表示只生成,不创建 Pod
  • -o yaml 表示输出 YAML

编辑 /tmp/ns.yaml,添加 nodeSelector:

spec:
nodeSelector:
disktype: ssd
containers:
- name: nginx
image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/nginx:alpine
resources:
requests: {cpu: 50m, memory: 64Mi}
limits: {cpu: 200m, memory: 128Mi}
kubectl uncordon $NODE  # 确保节点可调度
kubectl apply -f /tmp/ns.yaml
kubectl get pod nginx-ssd -o wide # 验证调度到了 ssd 节点

步骤6: 清理

kubectl delete pod nginx-ssd
kubectl label node $NODE disktype-

应用部署

Pod 深度解析

步骤1: 理解 Pod — K8s 最小调度单元

Pod 是 K8s 中最小的部署和调度单元。一个 Pod 可以包含 1 个或多个容器,这些容器共享网络命名空间和存储卷。

关键特性: – 共享网络:同一 Pod 内的容器共享 IP 和端口空间(通过 localhost 通信) – 共享存储:Pod 内的 Volume 可被所有容器挂载 – 原子调度:Pod 作为整体被调度到同一节点

步骤2: 多容器 Pod — Sidecar 模式

apiVersion: v1
kind: Pod
metadata:
name: more-container
spec:
containers:
- name: app
image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/busybox:latest
command:
- /bin/sh
- -c
- |
while true; do
echo "$(date) - App Log" >> /var/log/app.log
sleep 5
done
volumeMounts:
- name: log
mountPath: /var/log
resources:
requests: {cpu: 10m, memory: 32Mi}
limits: {cpu: 100m, memory: 64Mi}
- name: log-tailer
image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/busybox:latest
command: ["/bin/sh", "-c", "tail -f /var/log/app.log"]
volumeMounts:
- name: log
mountPath: /var/log
resources:
requests: {cpu: 10m, memory: 32Mi}
limits: {cpu: 100m, memory: 64Mi}
volumes:
- name: log
emptyDir: {}
kubectl apply -f manifest.yaml

结构说明:

  • app 容器 负责持续写入日志到/var/log 也就是数据卷log,日志输出到文件而不是标准输出,所以kubectl logs more-container -c app 看不到容器日志
  • log 容器负责读取日志文件,tail -f 命令输出到 log-tailer 容器的标准输出,可以用kubectl logs 查看输出
    • 这种“Sidecar 读取共享文件,再输出到自己的 stdout”是 Kubernetes 官方文档描述的一种日志方案。Kubernetes 日志架构不过,如果应用本身可以直接输出日志,通常更推荐让应用直接写 stdout/stderr,而不是先写文件,再由另一个容器读取。
  • 两个 volumeMounts 使用了同一个数据卷log;把名为 log 的 Volume 挂载到了自己的 /var/log
  • emptyDir: {}表示声明了一个初始为空的临时数据卷

分别查看两个容器的日志:

kubectl logs more-container -c app
kubectl logs more-container -c log-tailer

步骤3: Init Container — 初始化容器

Init Container 在应用容器启动前按顺序执行:

apiVersion: v1
kind: Pod
metadata:
name: init-demo
spec:
initContainers:
- name: init-step1
image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/busybox:latest
command: ["/bin/sh", "-c", "echo 'Step 1: Checking prerequisites...'; sleep 3; echo 'OK'"]
- name: init-step2
image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/busybox:latest
command: ["/bin/sh", "-c", "echo 'Step 2: Preparing data...'; echo 'data ready' > /work/data.txt; sleep 2"]
volumeMounts:
- name: work
mountPath: /work
containers:
- name: app
image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/busybox:latest
command: ["/bin/sh", "-c", "cat /work/data.txt; echo 'App running...'; sleep 3600"]
volumeMounts:
- name: work
mountPath: /work
resources:
requests: {cpu: 10m, memory: 32Mi}
limits: {cpu: 100m, memory: 64Mi}
volumes:
- name: work
emptyDir: {}
kubectl apply -f manifest.yaml

上面的yaml里面是顺序启动两个init容器,然后再启动业务容器,都用相同的数据卷

initContainers 适合“执行完成后才能启动主程序”的前置任务;普通 containers 适合需要和主程序长期并行运行的 Sidecar。

在上一个yaml中,app先启动,log才能正常启动,但是 log-tailer 必须长期运行,所以不能直接改成普通 init container,但可以添加一个 init container 来预先创建日志文件。把下面的部分加进去,和containers同级即可

  initContainers:
- name: prepare-log
image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/busybox:latest
command:
- /bin/sh
- -c
- touch /var/log/app.log
volumeMounts:
- name: log
mountPath: /var/log

观察 Init Container 执行:

kubectl get pods -w
kubectl logs init-demo -c init-step1

步骤4: 资源请求与限制

字段含义超标后果
requests.cpu调度保证的 CPU不够则不调度
requests.memory调度保证的内存不够则不调度
limits.cpuCPU 使用上限限流(throttle)
limits.memory内存使用上限OOMKill→重启

步骤5: Pod 调度 — nodeSelector

kubectl get nodes --show-labels
kubectl run scheduled-pod --image=swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/nginx:alpine --dry-run=client -o yaml

在 YAML 中添加 nodeSelector:

spec:
nodeSelector:
kubernetes.io/os: linux

步骤6: 清理

kubectl delete pod more-container init-demo

Deployment 控制器实战

步骤1: 创建你的第一个 Pod

实验环境的 sandbox 命名空间配置了资源配额,创建 Pod 时必须指定 CPU / 内存的 requests 和 limits。将以下 YAML 粘贴到右侧编辑器中,然后执行 kubectl apply -f manifest.yaml:

apiVersion: v1
kind: Pod
metadata:
name: my-nginx
spec:
containers:
- name: nginx
image: harbor.sunnysfamily.cn:9443/public/nginx:1.29.0-alpine
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi

查看 Pod 状态:

kubectl get pods -o wide

在输出中观察:NAME、READY、STATUS、RESTARTS、AGE、IP、NODE。

步骤2: 理解 Pod 生命周期

Pod 有以下几个阶段:

Pending → Running → Succeeded/Failed

查看 Pod 详细信息:

kubectl describe pod my-nginx

重点查看 Events 部分,可以看到 Pod 从调度到启动的完整过程。

步骤3: 使用 Deployment 管理副本

Deployment 提供声明式更新和自愈能力。将以下 YAML 粘贴到右侧编辑器,然后执行 kubectl apply -f manifest.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: nginx
image: harbor.sunnysfamily.cn:9443/public/nginx:1.29.0-alpine
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi

同一个 YAML 里,Pod 写 v1 而 Deployment 写 apps/v1 它们本来就属于两套不同的 API

你写的实际含义完整接口路径
v1核心组(core / legacy group),版本 v1/api/v1/...
apps/v1组名 apps,版本 v1/apis/apps/v1/...
batch/v1组名 batch,版本 v1/apis/batch/v1/...
networking.k8s.io/v1组名 networking.k8s.io/apis/networking.k8s.io/v1/...

查看 Deployment 创建的资源:

kubectl get deploy,rs,pods -l app=web-app

可以拆成两部分:

kubectl get deploy,rs,pods  和  -l app=web-app

表示一次查看三种资源:逗号只是表示同时查询多种资源,并不表示 Kubernetes 按 Deployment → ReplicaSet → Pod 的层级递归查询。

  • deploy:Deployment
  • rs:ReplicaSet
  • pods:Pod

你会看到:Deployment → ReplicaSet → 3 个 Pod。这是 K8s 的层级管理关系。

步骤4: 自愈能力验证

手动删除其中一个 Pod,观察 Deployment 如何自动恢复:

POD=$(kubectl get pods -l app=web-app -o jsonpath='{.items[0].metadata.name}')
kubectl delete pod $POD
kubectl get pods -w

按 Ctrl+C 停止 watch。可以看到被删的 Pod 被自动重建,而其余 Pod 不受影响——这是 K8s 自愈能力的核心。

步骤5: 水平伸缩

kubectl scale deployment web-app --replicas=5
kubectl get pods -l app=web-app

扩容是即时的,K8s 会在可用节点上调度新的 Pod。

步骤6: 滚动更新

更新容器镜像触发滚动更新:

kubectl set image deployment/web-app nginx=crpi-xfeuebyl27sae6su.ap-northeast-1.personal.cr.aliyuncs.com/linuxjkcn/nginx:alpine

滚动更新会逐个替换 Pod,保证服务不中断。

这里的原理就是旧的replicaset有5个pod,然后执行修改新镜像地址的命令,会开始创建一个新的replicaset,逐步增加pod数量,旧的replicaset逐步减少pod数量

旧 ReplicaSet:5 -> 4 -> 3 -> 2 -> 1 -> 0 新 ReplicaSet:0 -> 1 -> 2 -> 3 -> 4 -> 5

对于 replicas: 5: 默认策略通常允许:

maxSurge: 25% 允许暂时少几个可用 Pod;此处是向上取整,最多额外创建 2 个 Pod

maxUnavailable: 25%允许临时多创建几个 Pod ;此处是25% 向下取整,最多允许 1 个 Pod 不可用

所以更新期间可能短暂存在 6 或 7 个 Pod,然后逐步缩回 5 个。

例如镜像不存在、仓库认证失败:

新 Pod 会创建失败,Deployment 会继续保留部分旧 Pod,不会立即把所有旧 Pod 删除。这样可以尽量保证原版本仍然提供服务。

#使用回滚命令
kubectl rollout undo deployment/web-app
#查看回滚状态
kubectl rollout status deployment web-app
#查看更新历史:
kubectl rollout history deployment web-app
#回滚到指定版本:
kubectl rollout undo deployment/web-app --to-revision=2

如果想给这次回滚添加说明,可以在回滚完成后添加注解:

kubectl annotate deployment/web-app \
kubernetes.io/change-cause="这次操作是回滚到稳定版本" \
--overwrite
#在不同 Kubernetes/kubectl 版本中,kubectl rollout history 是否把回滚后的说明精确显示在对应 revision 上,可能有差异。CHANGE-CAUSE 只是说明信息,不参与回滚逻辑。

更推荐的操作习惯是,在执行每次版本变更前写清楚变更原因:

kubectl annotate deployment/web-app \
kubernetes.io/change-cause="更新nginx镜像为alpine版本" \
--overwrite

kubectl set image deployment/web-app \
nginx=.../nginx:alpine

回滚时:

kubectl rollout undo deployment/web-app
kubectl rollout status deployment/web-app

kubectl annotate deployment/web-app \
kubernetes.io/change-cause="已执行完镜像回滚操作" \
--overwrite

步骤7: 查看 Pod 日志

kubectl logs -l app=web-app --tail=20 --prefix

--prefix 会在每行前显示 Pod 名称,方便区分。

步骤8: 进入容器调试

kubectl exec -it deployment/web-app -- /bin/sh

注:这里Kubernetes 会先根据 Deployment 的 Pod 模板找到一个可用 Pod,然后选择其中一个执行。

指定 Pod:

kubectl exec -it pod/web-app-668db98c7f-552dz -- /bin/bash

或者省略 pod/:

kubectl exec -it web-app-668db98c7f-552dz -- /bin/bash

如果 Pod 中有多个容器,需要使用 -c 指定容器名:

kubectl exec -it web-app-668db98c7f-552dz \
-c nginx \
-- /bin/bash

容器名来自 YAML:

containers:
- name: nginx

也可以指定 Deployment 和容器,但 Pod 仍然会由 Kubernetes 自动选择:

kubectl exec -it deployment/web-app \
-c nginx \
-- /bin/sh
deployment/web-app:指定 Deployment,但不指定具体副本
pod/xxx:指定具体 Pod
-c nginx:指定 Pod 内的具体容器

在容器内运行:

hostname
env | sort
df -h
exit

步骤9: 清理资源

kubectl delete deployment web-app
kubectl delete pod my-nginx

DaemonSet 与 StatefulSet

步骤1: DaemonSet — 每节点一个 Pod

DaemonSet 确保所有(或部分)节点上运行一个 Pod 副本: – 日志采集(Fluentd、Filebeat) – 监控代理(node-exporter) – 网络插件(Calico、Flannel)

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-logger
spec:
selector:
matchLabels:
app: logger
template:
metadata:
labels:
app: logger
spec:
containers:
- name: logger
image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/busybox:latest
command:
- /bin/sh
- -c
- |
while true; do
echo "[$(hostname)] $(date)" >> /var/log/node.log
sleep 10
done
resources:
requests: {cpu: 50m, memory: 32Mi}
limits: {cpu: 100m, memory: 64Mi}
kubectl apply -f manifest.yaml
kubectl get pods -l app=logger -o wide
# 观察 NODE 列,每个节点都有一个 Pod

步骤2: StatefulSet — 有状态应用

StatefulSet 提供:稳定的网络标识(name-0/1/2)、独立的持久化存储、有序的部署和终止。

常用于各种数据库,可以做主从,pod名不变,如果做主从可以使用下面的方案:

独立持久卷:配置 volumeClaimTemplates
mysql-0 是主库:不会自动,需要数据库方案决定
默认启动顺序:OrderedReady,有序创建
并行启动:podManagementPolicy: Parallel
apiVersion: v1
kind: Service
metadata:
name: stateful-svc
spec:
clusterIP: None
selector:
app: stateful-demo
ports:
- port: 80
---
apiVersion: v1
kind: Service
metadata:
name: stateful-public
spec:
type: NodePort
selector:
app: stateful-demo
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30081
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: stateful-demo
spec:
serviceName: stateful-svc
replicas: 3
selector:
matchLabels:
app: stateful-demo
template:
metadata:
labels:
app: stateful-demo
spec:
containers:
- name: nginx
image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/nginx:alpine
command: ["/bin/sh", "-c", "echo Pod: $HOSTNAME > /usr/share/nginx/html/index.html; nginx -g 'daemon off;'"]
resources:
requests: {cpu: 50m, memory: 64Mi}
limits: {cpu: 200m, memory: 128Mi}
kubectl get pods -w -l app=stateful-demo
# 看到 stateful-demo-0 → 1 → 2 依次启动
kubectl exec stateful-demo-0 -- hostname # stateful-demo-0

这里我把原有示例service:stateful-svc 是 none的Headless Service 不变,加了一个nodeport

目的是为了公网访问其中的三个nginx网址,而本机属于内网环境,所以使用nodeport + 内网穿透的方案

给集群外部提供一个可以访问的入口,普通 ClusterIP 只能在集群内部访问

NodePort 的核心作用不是让 Pod 之间通信,而是把 Service 暴露到节点 IP 上,方便:

  • 实验环境外部访问
  • 内网穿透转发
  • 没有云 LoadBalancer 时提供入口
  • 临时测试 HTTP 服务

生产环境通常更推荐:

Ingress + Ingress Controller

或者:

LoadBalancer Service

因为 NodePort 需要手动管理节点 IP 和端口,路由能力和安全控制也比较有限。

步骤3: 控制器对比

控制器Pod 标识存储特点副本规则典型场景
Deployment随机名称不要求持久化,也可挂载 PVC指定 replicasWeb/API
StatefulSet固定序号常见为每 Pod 独立 PVC指定 replicas数据库/MQ
DaemonSetPod 名称通常含节点关联信息常见挂载 hostPath 或节点设备每个符合条件的节点一个日志/监控/网络

步骤4: 清理

kubectl delete statefulset stateful-demo
kubectl delete service stateful-svc
kubectl delete daemonset node-logger
滚动至顶部