从一次线上故障说起

深夜,告警铃声刺破了宁静。监控大屏显示,核心交易服务的响应时间飙升至10秒,用户支付失败率骤增。你迅速登录集群,kubectl get pods 显示一切“Running”,但 kubectl describe pod 揭示了真相:某个Pod反复重启,Last State 显示 Terminated,原因为 OOMKilled。你意识到,这个容器因内存溢出被系统“杀死”了。更棘手的是,由于没有设置就绪探针(Readiness Probe),Kubernetes在容器启动过程中就将其IP加入了Service的负载均衡池,导致部分流量被导入了这个不健康的Pod,引发了雪崩。

这次故障的根源,在于对Kubernetes核心概念理解不深:我们只定义了“要运行什么镜像”,却忽略了定义“容器健康的标准”和“资源使用的边界”。Kubernetes的强大,正源于其对应用生命周期和资源抽象的一套精妙模型。

一、总览 - Kubernetes的设计哲学与核心价值

Kubernetes并非简单的“容器调度器”,它是一个以应用为中心的声明式容器编排平台。其核心设计哲学是:

  1. 声明式API:你告诉Kubernetes“期望的状态”(Desired State),而非具体操作步骤。它负责驱动当前状态向期望状态收敛。
  2. 控制器模式:一系列独立的控制循环(Control Loop)持续监听资源状态,并进行调谐(Reconcile)。
  3. 抽象与封装:将复杂的分布式应用部署、运维细节抽象成一系列易于理解和操作的对象。

它解决了什么问题?

  • 自动化运维:自动部署、扩缩容、自愈(重启、替换、重新调度)。
  • 资源高效利用:混合部署,提升数据中心资源利用率。
  • 环境一致性:从开发到生产,环境高度统一。
  • 松耦合的微服务架构:提供服务发现、负载均衡、配置管理,是微服务理念的天然载体。

二、集群架构审视 - 不仅仅是Master和Node

核心交互流程(创建一个Pod):

  1. 用户通过 kubectlkube-apiserver 提交一个Pod定义(YAML)。
  2. kube-apiserver 验证请求,并将其持久化存储到 etcd
  3. kube-scheduler 监听(Watch)到新建的、未分配节点的Pod,根据资源需求、策略等,选择一个最合适的Node,并通过 kube-apiserver 更新Pod的节点绑定信息(写回etcd)。
  4. 目标Node上的 kubelet 监听(Watch)到属于自己节点的、待创建的Pod,调用 容器运行时(如containerd)拉取镜像并启动容器。
  5. kubelet 同时将容器状态通过 kube-apiserver 报告回etcd。
  6. kube-controller-manager 中的各种控制器(如Deployment Controller)持续运行,确保实际状态与声明的期望状态一致。

三、Pod:Kubernetes的原子单元

是什么?
Pod是Kubernetes中可以创建和管理的最小、最简单的部署单元。它是一个或多个容器的组合,这些容器共享存储、网络和命名空间。

解决什么问题?
容器本身是轻量隔离的,但有些进程需要紧密协作(如日志收集sidecar与服务容器)。Pod将它们包装成一个“逻辑主机”,使它们能通过localhost通信,共享Volume。

应用场景:

  • 主应用容器 + 日志代理Sidecar容器。
  • 主应用容器 + 配置文件热加载Sidecar容器。
  • 紧密耦合的服务,如Web服务器与内容同步器。

YAML配置深度解析:

# kubernetes-pod-demo.yaml
apiVersion: v1          # Kubernetes API版本,Pod属于核心v1 API
kind: Pod               # 资源类型,这里是Pod
metadata:               # 元数据,用于标识和描述资源
  name: webapp-pod      # Pod名称,在命名空间内必须唯一
  namespace: default    # 命名空间,默认是'default'
  labels:               # 标签,键值对,用于识别、选择和分组对象
    app: webapp         # 标签键'app',值'webapp'
    tier: frontend      # 标签键'tier',值'frontend'
  annotations:          # 注解,非标识性元数据,可存储较大数据
    owner: "dev-team-a" # 注解,说明此Pod的负责人
spec:                   # 规约,定义Pod的期望状态
  containers:           # 容器列表,定义Pod中运行的容器
  - name: webapp        # 容器名称
    image: nginx:1.25-alpine  # 容器镜像地址与标签
    imagePullPolicy: IfNotPresent  # 镜像拉取策略:本地有则用,无则拉
    ports:              # 容器暴露的端口列表(仅声明,不直接映射主机端口)
    - name: http        # 端口名称
      containerPort: 80 # 容器内监听的端口
      protocol: TCP     # 协议,TCP或UDP
    env:                # 注入到容器的环境变量列表
    - name: LOG_LEVEL   # 环境变量名
      value: "INFO"     # 环境变量值
    - name: DB_HOST
      valueFrom:        # 从其他资源获取值
        configMapKeyRef:
          name: app-config
          key: database.host
    resources:          # 资源请求与限制,**生产环境必须配置!**
      requests:         # 调度时保证的最小资源量
        memory: "64Mi"  # 64 Mebibytes内存
        cpu: "250m"     # 0.25个CPU核心 (250 millicores)
      limits:           # 容器运行时允许使用的最大资源量
        memory: "128Mi" # 内存限制128Mi,超过会被OOMKill
        cpu: "500m"     # CPU限制0.5核心,超过会被限流
    livenessProbe:      # 存活探针,检测容器是否“活着”
      httpGet:          # 通过HTTP GET请求检查
        path: /healthz
        port: 80
      initialDelaySeconds: 10  # 容器启动后等待10秒开始探测
      periodSeconds: 5         # 每5秒探测一次
      failureThreshold: 3      # 连续失败3次判定为不健康
    readinessProbe:     # 就绪探针,检测容器是否“就绪”(可服务流量)
      httpGet:
        path: /ready
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 5
    volumeMounts:       # 将卷挂载到容器内的路径
    - name: app-config  # 卷名称,需与下方volumes列表匹配
      mountPath: /etc/app/config
      readOnly: true
  - name: log-sidecar   # 第二个容器:日志收集sidecar
    image: busybox:latest
    command: ['sh', '-c', 'tail -f /var/log/app.log']
    volumeMounts:
    - name: app-logs
      mountPath: /var/log
  volumes:              # 定义Pod级别的存储卷
  - name: app-config    # 卷1:来自ConfigMap
    configMap:
      name: app-config-map
  - name: app-logs      # 卷2:emptyDir临时存储
    emptyDir: {}
  restartPolicy: Always # 容器退出时的重启策略:Always, OnFailure, Never
  nodeSelector:         # 节点选择器,将Pod调度到有特定标签的节点
    disktype: ssd
  affinity:             # 亲和性规则,更高级的调度约束
    podAntiAffinity:    # Pod反亲和,避免同类Pod部署在同一节点
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchLabels:
              app: webapp
          topologyKey: kubernetes.io/hostname

运行示例:

# 1. 创建Pod
kubectl apply -f kubernetes-pod-demo.yaml
# 输出:pod/webapp-pod created

# 2. 查看Pod状态
kubectl get pod/webapp-pod -o wide
# 输出:
# NAME         READY   STATUS    RESTARTS   AGE   IP            NODE         NOMINATED NODE
# webapp-pod   2/2     Running   0          30s   10.244.1.5    worker-node-1   <none>
# 注意:READY列显示 2/2,表示Pod内两个容器都就绪了。

# 3. 查看Pod详情(包括事件、配置、状态等)
kubectl describe pod/webapp-pod

# 4. 查看Pod内部容器日志
kubectl logs webapp-pod -c webapp # 查看主容器日志
kubectl logs webapp-pod -c log-sidecar # 查看sidecar容器日志

四、 工作负载控制器:管理Pod的生命周期

直接管理Pod是脆弱的。工作负载控制器(Controller)通过更高级别的抽象来管理Pod副本,实现自愈、扩缩等。

1. Deployment:无状态应用的管家

是什么? 声明式地管理Pod副本集(ReplicaSet),提供滚动更新、回滚等核心功能。
解决什么问题? Pod自身没有自愈能力。Deployment确保指定数量的、完全相同的Pod副本持续运行。

YAML配置深度解析:

# kubernetes-deployment-demo.yaml
apiVersion: apps/v1  # 注意:Deployment API版本是 apps/v1
kind: Deployment
metadata:
  name: webapp-deployment
  labels:
    app: webapp
spec:
  replicas: 3  # 期望的Pod副本数,核心参数
  selector:    # 标签选择器,决定管理哪些Pod
    matchLabels:
      app: webapp
  strategy:    # 更新策略
    type: RollingUpdate  # 滚动更新,默认
    rollingUpdate:
      maxSurge: 1        # 更新过程中最多可超出 replicas 的Pod数(可百分比或整数)
      maxUnavailable: 0  # 更新过程中最多不可用的Pod数,0表示“零停机”
  minReadySeconds: 5     # Pod就绪后,等待多少秒才视为可用,用于让流量完全切入
  progressDeadlineSeconds: 600 # 部署进度超时时间(秒),超过标记为失败
  revisionHistoryLimit: 10 # 保留的历史ReplicaSet数量,用于回滚
  template:              # Pod模板,与Pod spec定义一致
    metadata:
      labels:
        app: webapp
    spec:
      containers:
      - name: webapp
        image: nginx:1.25-alpine
        ports: [ { containerPort: 80 } ]
        readinessProbe: { ... } # 省略,同Pod示例
        resources: { ... }      # 省略,同Pod示例

运行示例:

# 1. 创建Deployment
kubectl apply -f kubernetes-deployment-demo.yaml
# 输出:deployment.apps/webapp-deployment created

# 2. 查看Deployment及其管理的ReplicaSet和Pod
kubectl get deployment,replicaset,pod -l app=webapp
# 输出:
# NAME                                    READY   UP-TO-DATE   AVAILABLE   AGE
# deployment.apps/webapp-deployment   3/3     3            3           1m
#
# NAME                                               DESIRED   CURRENT   READY   AGE
# replicaset.apps/webapp-deployment-7d8f9c8b9b   3         3         3       1m
#
# NAME                                        READY   STATUS    RESTARTS   AGE
# pod/webapp-deployment-7d8f9c8b9b-abcx1   1/1     Running   0          1m
# pod/webapp-deployment-7d8f9c8b9b-defx2   1/1     Running   0          1m
# pod/webapp-deployment-7d8f9c8b9b-ghix3   1/1     Running   0          1m

# 3. 模拟容器故障(删除一个Pod)
kubectl delete pod webapp-deployment-7d8f9c8b9b-abcx1
# 输出:pod "webapp-deployment-7d8f9c8b9b-abcx1" deleted

# 4. 再次查看Pod,发现Deployment自动创建了新Pod
kubectl get pod -l app=webapp
# 输出:可以看到一个新名字的Pod在创建/运行,始终保持3个副本。

# 5. 滚动更新镜像版本
kubectl set image deployment/webapp-deployment webapp=nginx:1.26-alpine
# 或通过 kubectl apply -f 更新YAML文件中的镜像
# 查看更新状态
kubectl rollout status deployment/webapp-deployment
# 输出:Waiting for rollout to finish: 1 out of 3 new replicas have been updated...
#       deployment "webapp-deployment" successfully rolled out

# 6. 查看更新历史
kubectl rollout history deployment/webapp-deployment

# 7. 回滚到上一个版本
kubectl rollout undo deployment/webapp-deployment

2. StatefulSet:有状态应用的守护者

是什么? 用于管理有状态应用,为Pod提供稳定的标识(有序编号、持久化存储、稳定网络标识)。
解决什么问题? 对于数据库(MySQL集群)、消息队列(Kafka)、注册中心(ZooKeeper)等,Pod需要稳定的网络标识和持久化存储,且启停顺序有要求。

关键特性:

  • 稳定的Pod标识:Pod名称形如 <statefulset-name>-0, -1, -2
  • 稳定的持久化存储:通过PVC模板,每个Pod对应独立的PV,即使Pod被重新调度,也会挂载原来的数据。
  • 有序部署/扩缩容:按索引顺序创建(0->1->2…),逆序删除(2->1->0)。
  • 稳定的网络标识:Headless Service提供DNS记录:<pod-name>.<svc-name>.<namespace>.svc.cluster.local

YAML配置核心:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: "mysql-headless"  # 必须关联一个Headless Service
  replicas: 3
  selector: { ... }
  template: { ... } # Pod模板
  volumeClaimTemplates:  # PVC模板,每个Pod动态创建一个PVC
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 10Gi

3. DaemonSet:节点守护者

是什么? 确保集群中所有(或部分)节点上都运行一个Pod副本。
解决什么问题? 运行集群级别的守护进程,如日志收集(Fluentd)、监控代理(Node Exporter)、网络插件(Calico)。
特点:当节点加入集群时,Pod会被调度上去;节点移除时,Pod被回收。

4. Job & CronJob:批处理任务

Job:创建一个或多个Pod,并确保指定数量的Pod成功终止。用于一次性任务。
CronJob:基于Cron时间表周期性运行的Job。用于定时任务。

五:Service与Ingress:网络抽象与流量入口

1. Service:服务的稳定访问点

是什么? 定义一组Pod的逻辑集合和访问它们的策略。为Pod提供稳定的IP地址、DNS名称和负载均衡。
解决什么问题? Pod是临时的(IP会变),Service提供了一个稳定的VIP(Cluster IP)和DNS名,将前端与后端Pod解耦。

类型:

  • ClusterIP(默认):集群内部IP,只能在集群内部访问。
  • NodePort:在每个节点上开放一个静态端口(NodePort),将流量转发到Service。
  • LoadBalancer:使用云提供商的负载均衡器,将外部流量导入Service。
  • ExternalName:将Service映射到外部DNS名称。

YAML配置深度解析:

# kubernetes-service-demo.yaml
apiVersion: v1
kind: Service
metadata:
  name: webapp-service
spec:
  selector:        # 标签选择器,选择后端Pod
    app: webapp
  type: ClusterIP  # Service类型
  clusterIP: 10.96.100.100 # 可指定固定ClusterIP,通常自动分配
  ports:
  - name: http    # 端口名称
    port: 80      # Service自身的端口
    targetPort: 80 # 后端Pod容器的端口
    protocol: TCP
  - name: https
    port: 443
    targetPort: 443
    protocol: TCP
  sessionAffinity: None  # 会话亲和性,ClientIP/None
  # externalTrafficPolicy: Local # 外部流量策略,仅对NodePort/LB有意义

运行示例:

# 1. 创建Service
kubectl apply -f kubernetes-service-demo.yaml
# 输出:service/webapp-service created

# 2. 查看Service
kubectl get svc webapp-service
# 输出:
# NAME              TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
# webapp-service    ClusterIP   10.96.100.100   <none>        80/TCP,443/TCP   10s

# 3. 在集群内部访问Service
kubectl run curl-test --image=radial/busyboxplus:curl -i --rm --restart=Never -- curl -I http://webapp-service.default.svc.cluster.local
# 或者使用简化的DNS名(同一命名空间下)
kubectl run curl-test --image=radial/busyboxplus:curl -i --rm --restart=Never -- curl -I http://webapp-service
# 输出:应能看到HTTP 200/OK等响应头。

# 4. 查看Service的Endpoints(实际关联的Pod IP和端口)
kubectl get endpoints webapp-service
# 输出:列出后端Pod的IP:Port

深入原理: Service的实现依赖于 kube-proxy 组件,它通过配置节点上的iptables/IPVS规则,将发往Service ClusterIP的流量负载均衡到后端Pod。

2. Ingress:集群的HTTP/HTTPS流量路由器

是什么? 管理集群外部访问内部服务的HTTP/HTTPS路由规则的API对象。本身不是服务,需要配合Ingress Controller(如Nginx Ingress Controller, Traefik)才能生效。
解决什么问题? Service的LoadBalancer类型每个服务都需要一个外部IP,昂贵且不便管理。Ingress可以提供基于域名和路径的路由、TLS终止等功能。

YAML配置深度解析:

# kubernetes-ingress-demo.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: webapp-ingress
  annotations:  # 注解,用于配置特定的Ingress Controller
    nginx.ingress.kubernetes.io/rewrite-target: /$1
    cert-manager.io/cluster-issuer: "letsencrypt-prod" # 使用cert-manager自动签发证书
spec:
  ingressClassName: nginx  # 指定使用哪个Ingress Controller
  tls:                     # TLS配置
  - hosts:
    - webapp.example.com
    secretName: webapp-tls-secret  # 存储证书的Secret
  rules:                  # 路由规则
  - host: webapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: webapp-service
            port:
              number: 80
  - host: api.example.com
    http:
      paths:
      - path: /v1(/|$)(.*)  # 路径匹配
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080

六、ConfigMap与Secret:配置与敏感信息管理

核心思想:将应用配置与容器镜像解耦,实现“一次构建,多处运行”。

1. ConfigMap:配置管理中心

是什么? 用于存储非机密的、键值对或配置文件形式的数据。Pod可以将其作为环境变量、命令行参数或配置文件卷挂载。

# kubernetes-configmap-demo.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:                     # 数据部分
  # 键值对形式
  LOG_LEVEL: "DEBUG"
  DATABASE_URL: "jdbc:mysql://mysql:3306/appdb"
  # 文件形式(多行文本)
  application.properties: |
    server.port=8080
    spring.datasource.url=${DATABASE_URL}
    logging.level.root=${LOG_LEVEL}

在Pod中使用:

# 方式1:作为环境变量
env:
- name: LOG_LEVEL
  valueFrom:
    configMapKeyRef:
      name: app-config
      key: LOG_LEVEL
# 方式2:作为卷挂载
volumes:
- name: config-volume
  configMap:
    name: app-config
    items: # 可选,选择特定键
    - key: application.properties
      path: app.properties

2. Secret:敏感信息保险箱

是什么? 用于存储敏感信息,如密码、OAuth令牌、SSH密钥。数据以Base64编码存储(非加密),确保不直接出现在命令行或环境变量中。

# kubernetes-secret-demo.yaml
apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque  # 通用类型
stringData:   # 方便书写,k8s会将其base64后存入data字段
  username: admin
  password: Sup3rS3cr3t!
# 或者使用data字段直接写base64编码值
# data:
#   username: YWRtaW4=
#   password: U3VwM3JTM2NyM3Qh
# 从文件创建Secret更安全
kubectl create secret generic db-secret \
  --from-file=./username.txt \
  --from-file=./password.txt

七、Volume与PersistentVolume:存储抽象

Volume:Pod中容器可访问的共享目录。生命周期与Pod相同。
PersistentVolume (PV):集群级别的存储资源,由管理员预先创建或动态供应(StorageClass)。
PersistentVolumeClaim (PVC):用户对存储的“请求”,类似于Pod消耗Node资源,PVC消耗PV资源。

工作流程:Pod -> PVC -> PV -> 实际存储(NFS, Ceph, 云盘等)。

YAML配置示例(动态供应):

# 1. StorageClass (集群管理员定义)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: disk.csi.azure.com  # 指定存储供应者
parameters:
  skuName: Premium_LRS
  kind: managed
reclaimPolicy: Retain
allowVolumeExpansion: true  # 允许卷扩容

# 2. PersistentVolumeClaim (用户/开发者请求)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: app-data-pvc
spec:
  accessModes:
    - ReadWriteOnce  # 访问模式:RWO(单节点读写),RWX(多节点读写),ROX(多节点只读)
  storageClassName: fast-ssd
  resources:
    requests:
      storage: 10Gi

# 3. Pod中使用PVC
apiVersion: v1
kind: Pod
metadata:
  name: app-with-pvc
spec:
  containers:
  - name: app
    image: nginx
    volumeMounts:
    - name: data-storage
      mountPath: /data
  volumes:
  - name: data-storage
    persistentVolumeClaim:
      claimName: app-data-pvc

八、深度原理与机制剖析

1. 控制器原理(Control Loop)

Kubernetes所有自动化能力的核心。以Deployment为例:

  1. 监听:Deployment Controller 持续监听(通过apiserver)所有Deployment和ReplicaSet对象的变化。
  2. 比较:将对象的 spec(期望状态)与当前集群中关联的ReplicaSet/Pod的实际状态进行比较。
  3. 调谐:如果状态不一致(如Pod副本数不足),则执行调谐操作(创建/删除Pod)。对于Deployment,它通过控制ReplicaSet来实现。
  4. 更新状态:将调谐后的结果更新到对象的 status 字段。

这是一种声明式的最终一致性系统。

2. 调度原理(Scheduler)

调度分为两步:过滤(Filtering)评分(Scoring)

  1. 过滤:从所有节点中找出可调度的节点。检查节点资源是否充足、节点/Pod亲和性、污点与容忍、节点Selector等。
  2. 评分:对过滤后的节点打分。考虑因素包括资源平衡、Pod亲和性、数据本地性等。选择分数最高的节点。
  3. 绑定:将Pod绑定到选定的节点(更新Pod的 nodeName 字段)。

3. 网络模型

Kubernetes强制要求所有容器无需NAT就能同其他所有容器通信,所有节点无需NAT就能同所有容器通信。这通常由CNI插件(如Calico, Flannel, Cilium)实现,它们负责配置Pod网络、网络策略等。

九、企业级最佳实践与避坑指南

结合开篇的故障,我们总结以下核心实践:

  1. 必须配置资源限制(Resources Limits/Requests)

    • 原因:防止单个Pod耗尽节点资源,影响其他应用。requests用于调度,limits用于运行限制。
    • 错误示例:不配置或只配置limits
    • 正确做法:根据应用压测结果,合理设置两者。通常 requests < limits
  2. 必须配置健康检查(Liveness & Readiness Probes)

    • Liveness Probe:告诉K8s何时重启容器。失败会重启Pod。
    • Readiness Probe:告诉K8s何时可将流量导入Pod。失败会将Pod从Service端点移除。
    • 启动探针(Startup Probe) (K8s 1.16+):用于保护慢启动容器,在启动成功前禁用其他探针。
    • 路径必须真实有效,且检查逻辑要轻量。
  3. 使用有意义的标签(Labels)

    • 标签是K8s中进行分组、选择、操作资源的基石。
    • 遵循命名规范,如 app, component, version, environment
  4. 为容器配置合理的镜像拉取策略

    • imagePullPolicy: IfNotPresent(默认非latest标签)或 Always(生产环境推荐,确保使用指定版本)。
  5. 安全性

    • 容器以非root用户运行(securityContext.runAsUser)。
    • 设置文件系统只读(securityContext.readOnlyRootFilesystem: true)。
    • 使用NetworkPolicy进行网络隔离。
  6. 常见错误与排查命令

    • Pod一直Pendingkubectl describe pod <pod-name> 查看事件,通常是资源不足、节点选择器/污点不匹配。
    • Pod一直CrashLoopBackOffkubectl logs <pod-name> --previous 查看前一个容器的日志。
    • Service无法访问kubectl get endpoints <svc-name> 检查后端Pod是否就绪并被正确选中。
    • 配置不生效kubectl get -f your-config.yaml -o yaml 查看K8s中实际的资源定义。

十、实战演练 - 部署一个完整的Web应用

让我们将上述概念串联,部署一个具有高可用、配置化、健康检查的Web应用。

步骤1:创建命名空间

kubectl create namespace demo-app

步骤2:创建ConfigMap和Secret

# config-and-secret.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: demo-app
data:
  APP_COLOR: "blue"
  LOG_LEVEL: "INFO"
---
apiVersion: v1
kind: Secret
metadata:
  name: app-secret
  namespace: demo-app
type: Opaque
stringData:
  DB_PASSWORD: "demo123!"
kubectl apply -f config-and-secret.yaml

步骤3:创建Deployment

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
  namespace: demo-app
  labels:
    app: webapp
    version: v1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: webapp
  template:
    metadata:
      labels:
        app: webapp
        version: v1
    spec:
      containers:
      - name: webapp
        image: nginx:1.25-alpine
        ports:
        - containerPort: 80
        env:
        - name: APP_COLOR
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: APP_COLOR
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: app-secret
              key: DB_PASSWORD
        resources:
          requests:
            memory: "64Mi"
            cpu: "100m"
          limits:
            memory: "128Mi"
            cpu: "200m"
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 5
kubectl apply -f deployment.yaml
# 查看部署状态
kubectl -n demo-app get deployment,pod

步骤4:创建Service

# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: webapp-service
  namespace: demo-app
spec:
  selector:
    app: webapp
  ports:
  - port: 80
    targetPort: 80
kubectl apply -f service.yaml
# 在集群内测试访问
kubectl -n demo-app run test --image=busybox -it --rm --restart=Never -- wget -qO- http://webapp-service.demo-app.svc.cluster.local
# 应该能看到nginx欢迎页面的HTML代码

步骤5:(可选)创建Ingress
(假设已安装Nginx Ingress Controller)

# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: webapp-ingress
  namespace: demo-app
spec:
  ingressClassName: nginx
  rules:
  - host: demo.k8s.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: webapp-service
            port:
              number: 80
kubectl apply -f ingress.yaml
# 配置本地hosts文件,将 demo.k8s.local 指向Ingress Controller的IP
# 然后在浏览器访问 http://demo.k8s.local

至此,一个符合生产级基础要求的应用已在Kubernetes中运行起来。它具备了配置分离、秘密管理、资源限制、健康检查、服务发现和外部访问能力。

结语

理解Kubernetes的核心概念,是掌握这门云原生操作系统的基础。从Pod这个最小调度单元,到管理Pod生命周期的各种Controller,再到定义访问方式的Service和Ingress,以及解耦配置的ConfigMap/Secret和提供持久化的Volume,共同构成了Kubernetes声明式应用编排的基石。

Kubernetes是一个“状态驱动”的系统。我们的角色是声明应用的期望状态,而Kubernetes的职责是不断驱动现实世界向这个状态收敛。掌握这些核心概念,才能更好地设计和部署云原生应用,让K8s真正成为你业务稳定运行的强大引擎。

更多推荐