3. Kubernetes入门:从零搭建你的容器王国

说实话,Kubernetes 刚出来那会儿,我第一反应是「这玩意儿也太复杂了吧」。但真正用起来之后,你会发现它的设计其实非常优雅。今天我就带你从架构开始,一步步把 K8s 的核心组件、Pod、Service、Ingress 这些东西理清楚。

3.1 K8s 架构:控制面与数据面

Kubernetes 的架构,说白了就是「一个大脑管一群小弟」。

控制面(Master) 负责决策,工作节点(Node) 负责干活。我刚开始接触时总记不住谁是谁,后来想了个办法:Master 就是项目经理,Node 就是程序员。

控制面核心组件

  • kube-apiserver:所有操作的入口。你敲的每个 kubectl 命令,最终都打到它这里。我遇到过有人直接连 apiserver 的端口,结果被限流了——嗯,它是有 QPS 限制的。
  • etcd:集群的数据库,存着所有状态。千万别小看它,etcd 挂了整个集群就废了。我建议生产环境至少 3 节点 etcd 集群。
  • kube-scheduler:决定 Pod 该跑在哪台 Node 上。它看资源、看亲和性、看污点,挺智能的。
  • kube-controller-manager:各种控制器的集合。比如你声明要 3 个副本,它负责保证一直有 3 个在跑。

工作节点核心组件

  • kubelet:Node 上的「监工」。它跟 apiserver 通信,确保 Pod 按预期运行。
  • kube-proxy:负责网络代理和负载均衡。它维护着 iptables 或 IPVS 规则。
  • 容器运行时:比如 Docker、containerd。真正跑容器的地方。
我的小技巧:排查问题时,先看 kubelet 日志。大部分 Node 异常都能在 /var/log/messages 或 journalctl -u kubelet 里找到线索。

3.2 Pod:K8s 里最小的调度单元

Pod 是啥?就是一个或多个容器的组合。它们共享网络栈、存储卷,跑在同一台 Node 上。

你可能会问:「为啥不直接跑容器,非要包一层 Pod?」

原因很简单:有些场景下,多个容器需要紧密协作。比如一个容器跑应用,另一个容器做日志收集,它们需要共享网络和存储。Pod 就是为这种场景设计的。

Pod 的 YAML 示例

apiVersion: v1
kind: Pod
metadata:
  name: my-app-pod
  labels:
    app: my-app
spec:
  containers:
  - name: app-container
    image: nginx:1.21
    ports:
    - containerPort: 80
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
我曾经踩过的坑:没设置 resources.requests 和 limits。结果某个 Pod 把 Node 内存吃光了,其他 Pod 全被 OOM Kill。记住:生产环境一定要设资源限制!

3.3 工作负载:Deployment、StatefulSet、DaemonSet

Pod 是基础,但直接管理 Pod 太累了。所以 K8s 提供了更高层的抽象——工作负载。

Deployment:无状态应用的首选

我最常用的就是 Deployment。它支持滚动更新、回滚、扩缩容。说白了,你告诉它「我要 3 个副本」,它就能一直维持 3 个。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.21
        ports:
        - containerPort: 80

StatefulSet:有状态应用的救星

数据库、消息队列这类有状态应用,用 Deployment 就不合适了。因为每个 Pod 需要稳定的网络标识和持久化存储。StatefulSet 就是干这个的。

我记得有一次帮客户部署 MySQL 集群,用 StatefulSet 配合 Headless Service,每个 Pod 都有固定的 hostname,数据不会乱。

DaemonSet:每个 Node 跑一个

日志收集、监控代理这类组件,需要在每个 Node 上都跑一个实例。DaemonSet 就是干这个的。你加一个新 Node,它自动部署上去;你删一个 Node,它自动清理。

3.4 Service:稳定的网络入口

Pod 是会漂移的。今天在这台 Node,明天可能就跑到另一台了。那客户端怎么访问?

Service 就是解决这个问题的。它提供一个稳定的虚拟 IP(ClusterIP),背后代理一组 Pod。

Service 类型

类型 说明 使用场景
ClusterIP 集群内部可访问 内部服务调用
NodePort 通过 Node IP + 端口访问 开发测试环境
LoadBalancer 云厂商提供负载均衡器 生产环境对外暴露
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: my-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
  type: ClusterIP
关键点:Service 的 selector 要和 Pod 的 labels 匹配。不匹配的话,Service 背后就没有 Endpoint,流量就丢了。我排查过好几次这种问题,最后发现是 label 写错了。

3.5 Ingress:七层流量入口

Service 是四层(TCP/UDP)的,但很多时候我们需要七层(HTTP/HTTPS)的路由能力。比如根据域名、路径转发到不同的 Service。

Ingress 就是干这个的。它需要配合 Ingress Controller 使用,比如 Nginx Ingress Controller、Traefik。

Ingress 示例

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /v1
        pathType: Prefix
        backend:
          service:
            name: v1-service
            port:
              number: 80
      - path: /v2
        pathType: Prefix
        backend:
          service:
            name: v2-service
            port:
              number: 80

你想想看,如果没有 Ingress,每个 Service 都得暴露一个 NodePort,管理起来多麻烦。Ingress 统一了入口,还能做 SSL 终止、限流、认证,非常方便。

3.6 ConfigMap 与 Secret:配置管理

应用配置不应该硬编码在镜像里。环境不同,配置不同。ConfigMap 和 Secret 就是用来解耦配置的。

ConfigMap:明文配置

存放非敏感信息,比如配置文件、环境变量。

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  app.properties: |
    db.host=localhost
    db.port=3306
    log.level=INFO

Secret:敏感信息

存放密码、密钥、证书等。数据用 Base64 编码,但注意这只是编码,不是加密。生产环境建议用外部密钥管理工具,比如 HashiCorp Vault。

apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
data:
  username: YWRtaW4=
  password: cGFzc3dvcmQxMjM=
我曾经犯过的错:把 Secret 的 YAML 文件提交到了 Git 仓库。虽然内容是 Base64 编码的,但解码后就是明文。后来我养成了习惯:所有 Secret 都用 kubectl create secret 命令创建,或者用 Sealed Secrets 这类工具加密后再提交。

3.7 实战:搭建一个完整的应用

光说不练假把式。咱们来搭一个完整的应用:Nginx + ConfigMap + Service + Ingress。

  1. 创建 ConfigMap 存放 Nginx 配置
  2. 创建 Deployment 部署 Nginx
  3. 创建 Service 暴露内部端口
  4. 创建 Ingress 对外提供访问
# 1. ConfigMap
kubectl create configmap nginx-config --from-file=nginx.conf

# 2. Deployment
kubectl create deployment nginx --image=nginx:1.21 --replicas=2

# 3. Service
kubectl expose deployment nginx --port=80 --target-port=80 --type=ClusterIP

# 4. Ingress
kubectl create ingress nginx-ingress --rule="nginx.example.com/*=nginx:80"

跑完这几步,你的应用就能通过 nginx.example.com 访问了。当然,前提是你得配置好 DNS 解析和 Ingress Controller。

嗯,Kubernetes 入门其实没那么难。关键是理解它的设计思想:声明式 API、控制循环、分层抽象。把这些搞懂了,后面学什么 Operator、Helm、Service Mesh 都会轻松很多。

下一章咱们聊聊容器网络,那可是个有意思的话题。