4. Kubernetes核心概念:Pod、Service、Deployment、Namespace、ConfigMap、Secret

说实话,Kubernetes刚出来那会儿,我第一反应是「这玩意儿也太复杂了吧」。但真正用起来之后才发现,它的核心概念其实就那么几个。你只要把这六个概念吃透了,整个K8s的骨架就搭起来了。

我个人习惯把这六个概念分成三组来理解:Pod是原子Deployment和Service是管理手段Namespace、ConfigMap、Secret是辅助设施。咱们一个一个聊。

4.1 Pod:最小的调度单元

Pod是Kubernetes里你能创建和部署的最小单位。它不是单个容器,而是一个或多个容器的组合。这些容器共享网络栈、存储卷,以及它们运行的环境。

我在项目中遇到过一个问题:两个服务需要频繁通信,而且必须跑在同一台机器上。当时我第一反应是「用同一个Pod啊」。没错,Pod里的容器可以通过localhost互相访问,端口不能冲突,但共享存储卷让数据交换变得极其简单。

核心要点:Pod是短暂的,它随时可能被销毁、重建。不要把Pod当成虚拟机来用,它更像是一个「一次性餐具」。

一个Pod里通常只放一个容器,除非你有强耦合的场景。比如一个主容器加一个sidecar容器,sidecar负责日志收集或代理转发。嗯,这里要注意:不要为了省资源把多个无关的服务塞进同一个Pod,那样会破坏扩缩容的灵活性。

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: nginx
    image: nginx:1.21
    ports:
    - containerPort: 80

你看,这个YAML定义了一个最简单的Pod。它只有一个nginx容器,暴露80端口。但实际生产中,我们很少直接创建Pod,而是通过Deployment来管理。

4.2 Deployment:声明式的应用管理

Deployment说白了就是Pod的「管家」。你告诉它「我要跑3个nginx副本」,它就会帮你创建3个Pod,并且持续监控。如果某个Pod挂了,它会自动再拉起一个。

我记得有一次线上服务突然流量暴增,我赶紧修改了Deployment的replicas字段,从3改成10。几秒钟后,新的Pod就全部就绪了。这种体验,用传统运维方式根本不敢想。

避坑指南:我曾经犯过一个错误——直接修改了Pod的标签,导致Deployment认为Pod「丢失」了,又创建了一个新的。记住:永远不要手动修改由Deployment管理的Pod,所有变更都通过Deployment的YAML来操作。

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

Deployment还支持滚动更新和回滚。你更新了镜像版本,它会逐步替换旧Pod,整个过程对用户无感。如果新版本出了问题,一条命令就能回滚到上一个版本。

4.3 Service:稳定的网络入口

Pod是动态的,IP地址随时会变。那客户端怎么访问你的服务呢?Service就是来解决这个问题的。它提供一个稳定的虚拟IP和DNS名称,背后代理一组Pod。

你想想看,如果没有Service,每次Pod重启你都得去更新客户端的配置,那得多崩溃。Service通过标签选择器(selector)来匹配Pod,只要Pod的标签匹配,流量就能自动转发过去。

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: ClusterIP

Service有几种类型:ClusterIP(集群内访问)、NodePort(节点端口访问)、LoadBalancer(云负载均衡器)。我个人习惯,内部服务用ClusterIP,需要对外暴露的用LoadBalancer,调试时偶尔用NodePort。

类型 访问方式 适用场景
ClusterIP 集群内部IP 服务间调用
NodePort 节点IP+端口 测试、调试
LoadBalancer 云厂商LB 对外暴露服务

4.4 Namespace:逻辑隔离的利器

Namespace就是Kubernetes里的「虚拟集群」。同一个物理集群里,你可以用Namespace把不同环境、不同团队、不同项目隔离开来。

我在公司里通常这样划分:devtestprod各一个Namespace。开发人员只能在dev里折腾,测试在test里跑,生产环境严格隔离。这样即使有人在dev里误删了所有Pod,也不会影响到生产。

注意:Namespace只提供逻辑隔离,不提供安全隔离。如果你需要严格的安全边界,还得靠网络策略(NetworkPolicy)和RBAC。

创建Namespace很简单:

apiVersion: v1
kind: Namespace
metadata:
  name: dev

然后在其他资源里指定namespace字段即可。如果不指定,默认放在default命名空间里。我个人建议:永远不要在生产环境使用default命名空间,那会让资源管理变得一团糟。

4.5 ConfigMap:配置与应用的解耦

ConfigMap是用来存储非敏感配置的,比如环境变量、配置文件内容。它的核心思想是:把配置从应用镜像中剥离出来,这样同一个镜像可以在不同环境里跑出不同的行为。

举个例子,你的应用需要连接数据库。开发环境连dev-db,生产环境连prod-db。如果没有ConfigMap,你得为每个环境打不同的镜像。有了ConfigMap,镜像不变,只换ConfigMap就行。

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DB_HOST: "dev-db.example.com"
  DB_PORT: "3306"
  APP_MODE: "development"

使用方式有两种:环境变量注入挂载成文件。我个人更推荐挂载成文件的方式,因为环境变量在Pod运行期间无法动态更新,而挂载的文件可以热更新(虽然需要应用自己监听文件变化)。

避坑指南:我曾经把数据库密码也放进了ConfigMap,结果被安全审计打了个大大的红叉。记住:ConfigMap只放非敏感数据,密码、密钥、Token这些请用Secret。

4.6 Secret:敏感信息的保险箱

Secret和ConfigMap很像,但它的值是Base64编码的(注意,只是编码,不是加密)。它专门用来存储敏感信息,比如密码、OAuth Token、SSH密钥。

你可能会问:「Base64编码谁都能解码,这安全吗?」嗯,你说得对。Secret本身并不提供加密,它只是把数据从明文中隐藏起来。真正的安全要靠:RBAC控制谁可以访问Secret启用etcd加密使用外部密钥管理服务(如Vault)

apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
data:
  username: YWRtaW4=   # admin
  password: cGFzc3dvcmQxMjM=  # password123

使用Secret时,我建议用stringData字段(明文写入),Kubernetes会自动帮你做Base64编码。这样YAML文件更易读,也方便版本管理。

还有一个细节:Secret的大小限制是1MB。如果你有更大的敏感数据,考虑用外部存储。

小结

这六个概念,说白了就是Kubernetes的「六脉神剑」。Pod是基础单元,Deployment负责管理Pod的生命周期,Service提供稳定的网络入口,Namespace做逻辑隔离,ConfigMap和Secret管理配置。

我个人建议的学习路径是:先玩熟Pod和Deployment,再引入Service,然后慢慢加上Namespace和配置管理。别想一口吃成胖子,K8s这东西,得慢慢品。

下一章咱们聊聊服务发现与负载均衡,到时候你会看到Service是怎么和DNS、kube-probe配合工作的。嗯,那才是真正有意思的部分。