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。真正跑容器的地方。
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"
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
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=
3.7 实战:搭建一个完整的应用
光说不练假把式。咱们来搭一个完整的应用:Nginx + ConfigMap + Service + Ingress。
- 创建 ConfigMap 存放 Nginx 配置
- 创建 Deployment 部署 Nginx
- 创建 Service 暴露内部端口
- 创建 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 都会轻松很多。
下一章咱们聊聊容器网络,那可是个有意思的话题。