Kubernetes Service与Pod深度解析

一、Service:Pod的统一访问入口

在Kubernetes集群中,Deployment可创建多副本Pod以实现服务高可用,但Pod存在两个关键问题:一是Pod重建时IP会动态变化,二是Pod IP仅集群内部可见,外部无法直接访问。Service作为Pod的抽象访问层,完美解决了这些问题,它为一组同类Pod提供固定访问接口,同时实现服务发现与负载均衡。

(一)Service核心原理

Service通过标签选择器(Selector) 与Pod关联,只要Pod拥有Service指定的标签,就会被自动纳入Service的管理范围。Service会分配一个固定的Cluster IP,该IP在Service生命周期内保持不变,客户端通过Cluster IP访问服务,Service再将请求转发到后端Pod,实现负载均衡。

(二)Service实操案例

1. 创建集群内部可访问的Service(ClusterIP类型)

ClusterIP类型的Service仅在集群内部可见,适用于集群内服务间的通信。

  • 暴露Service:基于已有的Deployment(如名为nginx的Deployment,命名空间为dev)创建Service,指定Service名称为svc-nginx1,类型为ClusterIP,Service对外暴露端口80,并转发到Pod的80端口。
[root@master ~]# kubectl expose deploy nginx --name=svc-nginx1 --type=ClusterIP --port=80 --target-port=80 -n dev
service/svc-nginx1 exposed
  • 查看Service:通过kubectl get svc命令查看Service详情,可获取CLUSTER-IP(如10.109.179.231)、端口、关联的Pod标签选择器(run=nginx)等信息。
[root@master ~]# kubectl get svc svc-nginx1 -n dev -o wide
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE     SELECTOR
svc-nginx1   ClusterIP   10.109.179.231   <none>        80/TCP    3m51s   run=nginx
  • 访问Service:在集群内部(如Master节点或其他Pod),通过CLUSTER-IP:端口即可访问Service后端的Pod服务。
[root@master ~]# curl 10.109.179.231:80
<!DOCTYPE html><html><head><title>Welcome to nginx!</title></head><body><h1>Welcome to nginx!</h1>
.......</body></html>
2. 创建集群外部可访问的Service(NodePort类型)

NodePort类型的Service会在集群所有Node节点上开放一个固定端口,外部客户端可通过“Node IP:NodePort”访问服务,适用于需要对外暴露服务的场景。

  • 创建NodePort类型Service:基于nginxDeployment创建Service,名称为svc-nginx2,类型指定为NodePort,其他端口配置与ClusterIP类型一致。
[root@master ~]# kubectl expose deploy nginx --name=svc-nginx2 --type=NodePort --port=80 --target-port=80 -n dev
service/svc-nginx2 exposed
  • 查看NodePort Service:查看结果中PORT(S)列会显示“Service端口:NodePort端口”(如80:31928/TCP),其中31928是Node节点上开放的端口,范围通常为30000-32767
[root@master ~]# kubectl get svc  svc-nginx2  -n dev -o wide
NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE    SELECTOR
svc-nginx2    NodePort    10.100.94.0      <none>        80:31928/TCP   9s     run=nginx
  • 外部访问Service:在集群外部的主机(如本地电脑),通过浏览器或curl命令访问“Node IP:NodePort”,即可访问服务(假设Node IP为192.168.100.10)。
http://192.168.100.10:31928/
3. 删除Service

当Service不再需要时,可通过名称或配置文件删除。

  • 通过名称删除:
[root@master ~]# kubectl delete svc svc-nginx-1 -n dev
service "svc-nginx-1" deleted
4. 通过配置文件创建Service

除了命令行方式,还可通过YAML配置文件定义Service,便于版本控制和批量部署。

  • 创建配置文件(svc-nginx.yaml):指定Service的API版本、类型、元数据、端口、标签选择器等信息,可手动固定clusterIP(需确保该IP未被占用)。
apiVersion: v1
kind: Service
metadata:
  name: svc-nginx
  namespace: dev
spec:
  clusterIP: 10.109.179.231  # 固定Service的内网IP(可选)
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: nginx  # 关联标签为“run=nginx”的Pod
  type: ClusterIP  # Service类型
  • 通过配置文件创建/删除Service
    • 创建:
kubectl create -f svc-nginx.yaml
  • 删除:
kubectl delete -f svc-nginx.yaml

二、Pod:Kubernetes最小部署单元

Pod是Kubernetes中最小的部署和调度单元,一个Pod可包含一个或多个容器,这些容器共享Pod的网络命名空间、存储卷等资源,在同一节点上协同运行。

(一)Pod资源清单完整解析

Pod的配置通过YAML资源清单定义,包含API版本、资源类型、元数据、规格等核心部分,以下是完整的资源清单结构及说明:

apiVersion: v1  # 必选,API版本(需通过kubectl api-versions查询确认)
kind: Pod       # 必选,资源类型(固定为Pod)
metadata:       # 必选,元数据(用于标识Pod)
  name: string  # 必选,Pod名称(在命名空间内唯一)
  namespace: string  # 可选,Pod所属命名空间(默认“default”)
  labels:       # 可选,自定义标签(键值对形式,用于Service关联、Pod筛选)
    key1: value1
    key2: value2
spec:  # 必选,Pod核心规格(定义容器、资源、调度等配置)
  containers:  # 必选,容器列表(一个Pod可包含多个容器)
  - name: string  # 必选,容器名称(在Pod内唯一)
    image: string  # 必选,容器镜像地址(如nginx:1.17.1)
    imagePullPolicy: [Always|Never|IfNotPresent]  # 可选,镜像拉取策略
    command: [string]  # 可选,容器启动命令(覆盖Dockerfile中的ENTRYPOINT)
    args: [string]     # 可选,启动命令参数(配合command使用)
    workingDir: string  # 可选,容器工作目录(默认容器根目录)
    volumeMounts:       # 可选,容器挂载存储卷配置
    - name: string      # 必选,引用spec.volumes中定义的存储卷名称
      mountPath: string # 必选,存储卷在容器内的挂载路径(绝对路径)
      readOnly: boolean # 可选,是否为只读模式(默认false)
    ports:  # 可选,容器暴露端口列表
    - name: string        # 可选,端口名称(在Pod内唯一)
      containerPort: int  # 必选,容器监听端口(1-65535)
      hostPort: int       # 可选,容器在主机上暴露的端口(默认与containerPort一致,不推荐设置,可能导致端口冲突)
      protocol: string    # 可选,端口协议(TCP/UDP/SCTP,默认TCP)
    env:  # 可选,容器环境变量列表
    - name: string  # 必选,环境变量名称
      value: string # 必选,环境变量值
    resources:  # 可选,容器资源限制与请求
      limits:  # 可选,资源上限(超过会导致容器重启)
        cpu: string     # CPU限制(单位:core,如“1”表示1核,“0.5”表示半核)
        memory: string  # 内存限制(单位:Gi/Mi,如“1Gi”“512Mi”)
      requests:  # 可选,资源请求(环境资源不足时Pod无法启动)
        cpu: string    # CPU请求(最小所需CPU)
        memory: string # 内存请求(最小所需内存)
    lifecycle:  # 可选,容器生命周期钩子(在特定阶段执行命令)
      postStart:  # 容器启动后立即执行(执行失败会触发重启策略)
        exec:
          command: [string]  # 执行的命令
      preStop:    # 容器终止前执行(无论结果如何,容器都会终止)
        exec:
          command: [string]
    livenessProbe:  # 可选,容器健康检查(探测失败多次后重启容器)
      exec:        # 执行命令检查(命令退出码为0表示健康)
        command: [string]
      httpGet:     # HTTP请求检查(返回2xx/3xx表示健康)
        path: string    # 请求路径
        port: number    # 请求端口
        host: string    # 请求主机(默认Pod IP)
        scheme: string  # 协议(HTTP/HTTPS,默认HTTP)
        httpHeaders:    # 自定义请求头
        - name: string
          value: string
      tcpSocket:   # TCP连接检查(连接成功表示健康)
        port: number
      initialDelaySeconds: 0  # 容器启动后首次探测延迟(单位:秒,默认0)
      timeoutSeconds: 1       # 探测超时时间(单位:秒,默认1)
      periodSeconds: 10       # 探测间隔时间(单位:秒,默认10)
      successThreshold: 1     # 探测成功次数阈值(默认1)
      failureThreshold: 3     # 探测失败次数阈值(默认3,超过则触发重启)
    securityContext:  # 可选,容器安全上下文(如特权模式)
      privileged: false  # 是否开启特权模式(默认false)
  restartPolicy: [Always|Never|OnFailure]  # 可选,Pod重启策略(默认Always)
    # Always:无论容器退出码如何,都重启(适用于长期运行服务)
    # Never:从不重启(适用于一次性任务)
    # OnFailure:仅当容器退出码非0时重启(适用于批处理任务)
  nodeName: <string>  # 可选,指定Pod调度到的节点名称(强制调度)
  nodeSelector: object  # 可选,基于节点标签调度(Pod仅调度到匹配标签的节点)
    key: value
  imagePullSecrets:  # 可选,拉取私有镜像的密钥(引用Secret资源)
  - name: string
  hostNetwork: false  # 可选,是否使用主机网络(默认false,true表示共享主机网络命名空间)
  volumes:  # 可选,Pod存储卷列表(供容器共享存储)
  - name: string  # 必选,存储卷名称
    emptyDir: {}  # 临时存储卷(与Pod生命周期一致,Pod删除后数据丢失)
    hostPath:     # 主机路径卷(挂载主机目录到Pod,适用于数据持久化到主机)
      path: string  # 主机上的目录路径
    secret:       # Secret卷(挂载Secret资源,存储敏感信息如密码)
      secretName: string  # Secret资源名称
      items:
      - key: string  # Secret中的键
        path: string # 挂载到容器内的路径
    configMap:    # ConfigMap卷(挂载ConfigMap资源,存储配置信息)
      name: string  # ConfigMap资源名称
      items:
      - key: string
        path: string
status:  # 可选,Pod状态信息(由Kubernetes自动生成,无需手动配置)
  phase: [Pending|Running|Succeeded|Failed|Unknown]  # Pod当前阶段
  conditions:  # Pod状态条件(如就绪状态、调度状态)
  containersStatuses:  # 容器状态列表(如启动状态、重启次数)

(二)Pod配置实操案例

1. 基础Pod配置(多容器示例)

创建包含两个容器(Nginx和Busybox)的Pod,用于演示基础配置。

  • 配置文件(pod-base.yaml)
apiVersion: v1
kind: Pod
metadata:
  name: pod-base
  namespace: test  # 自定义命名空间(需提前创建,命令:kubectl create ns test)
  labels:
    user: user1    # 自定义标签
spec:
  containers:
  - name: nginx    # 第一个容器(Nginx,轻量级Web服务)
    image: nginx:1.17.1
  - name: busybox  # 第二个容器(Busybox,Linux命令工具集)
    image: busybox:1.30
  • 创建与查看Pod
    • 创建Pod:
[root@master ~]# kubectl create -f pod-base.yaml
pod/pod-base created
  • 查看Pod状态:刚创建时Pod处于ContainerCreating状态,等待容器拉取和启动;正常启动后READY列显示“2/2”(表示两个容器均就绪)。
[root@master ~]# kubectl get pod -n test
NAME       READY   STATUS              RESTARTS   AGE
pod-base   0/2     ContainerCreating   0          12s
# 等待片刻后再次查看
[root@master ~]# kubectl get pod -n test
NAME       READY   STATUS    RESTARTS   AGE
pod-base   2/2     Running   0          1m
2. 镜像拉取策略配置

imagePullPolicy用于控制容器镜像的拉取行为,避免重复拉取或拉取失败问题。

  • 配置文件(pod-imagepullpolicy.yaml)
apiVersion: v1
kind: Pod
metadata:
  name: pod-imagepullpolicy
  namespace: test
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    imagePullPolicy: Never  # 仅使用本地镜像,不远程拉取
  - name: busybox
    image: busybox:1.30
    imagePullPolicy: IfNotPresent  # 本地有则用本地,无则远程拉取(默认策略)
  • 镜像拉取策略说明
    • Always:每次启动Pod都从远程仓库拉取镜像(适用于镜像标签为latest的场景,默认策略)。
    • IfNotPresent:本地存在镜像则直接使用,不存在时从远程拉取(适用于镜像标签为固定版本的场景,默认策略)。
    • Never:仅使用本地镜像,若本地不存在则启动失败(适用于离线环境或本地测试)。
  • 创建Pod
[root@master ~]# kubectl create -f pod-imagepullpolicy.yaml
pod/pod-imagepullpolicy created
3. 容器启动命令配置

部分容器(如Busybox)启动后会自动退出,需通过command配置自定义启动命令,让容器保持运行。

  • 问题分析:Busybox是工具集而非长期运行服务,默认启动后无持续任务,会立即退出,导致Pod中Busybox容器反复重启。
  • 解决方案:通过command配置循环任务(如每隔3秒向文件写入当前时间),让容器持续运行。
  • 配置文件(pod-command.yaml)
apiVersion: v1
kind: Pod
metadata:
  name: pod-command1
  namespace: test
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    imagePullPolicy: Never
  - name: busybox
    image: busybox:1.30
    imagePullPolicy: Never
    # 启动命令:创建文件并循环写入时间
    command: ["/bin/sh", "-c", "touch /tmp/hello.txt; while true; do /bin/echo $(date +%T) >> /tmp/hello.txt; sleep 3; done;"]
  • 命令说明
    • /bin/sh -c:使用sh解释器执行后续命令。
    • touch /tmp/hello.txt:在容器内创建/tmp/hello.txt文件。
    • while true; do ...; done:循环执行命令,每隔3秒将当前时间(date +%T)追加到文件中。
  • 创建与验证Pod
    • 创建Pod:
[root@master ~]# kubectl create -f pod-command.yaml
pod/pod-command1 created
  • 查看Pod状态:两个容器均处于Running状态(READY列显示“2/2”)。
[root@master ~]# kubectl get pods -n test
pod-command1           2/2     Running             0               2s
  • 进入Busybox容器验证:通过kubectl exec命令进入容器,查看文件内容,确认命令正常执行。
# 进入容器(-it表示交互式终端,-c指定容器名称)
[root@master ~]# kubectl exec pod-command1 -n test -it -c busybox /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # tail -f /tmp/hello.txt  # 实时查看文件内容
17:22:11
17:22:14
17:22:17
17:22:20
  • command与args的关系command对应Dockerfile中的ENTRYPOINTargs对应CMD,两者配合实现命令覆盖:
    1. 若均不配置:使用Dockerfile默认的ENTRYPOINTCMD
    2. 仅配置command:覆盖ENTRYPOINT,忽略Dockerfile的CMD
    3. 仅配置args:保留Dockerfile的ENTRYPOINT,用args替换CMD
    4. 均配置:完全覆盖Dockerfile的ENTRYPOINTCMD,执行command + args
4. 容器环境变量配置

通过env为容器设置环境变量,用于传递配置信息(如数据库账号、服务地址等)。

  • 配置文件(pod-env.yaml)
apiVersion: v1
kind: Pod
metadata:
  name: pod-env
  namespace: test
spec:
  containers:
  - name: busybox
    image: busybox:1.30
    imagePullPolicy: Never
    command: ["/bin/sh", "-c", "while true; do /bin/echo $(date +%T); sleep 60; done;"]
    env:  # 环境变量列表
    - name: "username"  # 环境变量名称
      value: "admin"    # 环境变量值
    - name: "password"
      value: "redhat"
  • 创建与验证环境变量
    • 创建Pod:
[root@master ~]# kubectl create -f pod-env.yaml
pod/pod-env created
  • 查看Pod状态:
[root@master ~]# kubectl get pod -n test
pod-env                1/1     Running            0               16s
  • 进入容器验证环境变量:通过echo $变量名查看环境变量值。
[root@master ~]# kubectl exec pod-env -n test -c busybox -it /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # echo $username
admin
/ # echo $password
redhat
  • 注意事项:直接在配置文件中写敏感信息(如密码)存在安全风险,推荐使用Secret资源存储敏感信息,再通过envvolumeMounts引用。
5. 容器端口配置

通过ports配置容器暴露的端口,便于Service关联和内部通信。

  • 查看ports子选项:通过kubectl explain命令查看ports支持的配置项。
[root@k8s-master01 ~]# kubectl explain pod.spec.containers.ports
KIND:     Pod
VERSION:  v1
RESOURCE: ports <[]Object>
FIELDS:
   name         <string>  # 端口名称(Pod内唯一,可选)
   containerPort<integer> # 容器监听端口(1-65535,必选)
   hostPort     <integer> # 主机暴露端口(可选,不推荐,易冲突)
   hostIP       <string>  # 主机IP(可选,默认0.0.0.0)
   protocol     <string>  # 协议(TCP/UDP/SCTP,默认TCP)
  • 配置文件(pod-ports.yaml)
apiVersion: v1
kind: Pod
metadata:
  name: pod-ports
  namespace: test
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    imagePullPolicy: Never
    ports:
    - name: nginx-port  # 端口名称
      containerPort: 80  # 容器监听端口(Nginx默认端口)
      protocol: TCP      # 协议
  • 创建与验证端口配置
    • 创建Pod:
[root@master ~]# kubectl create -f pod-ports.yaml
pod/pod-ports created
  • 查看Pod详情:通过-o yaml查看完整配置,确认端口配置生效。
[root@master ~]# kubectl get pod pod-ports -n test -o yaml
......
spec:
  containers:
  - image: nginx:1.17.1
    imagePullPolicy: Never
    name: nginx
    ports:
    - containerPort: 80
      name: nginx-port
      protocol: TCP
......
  • 访问容器服务:通过Pod IP和containerPort访问Nginx服务。
    1. 获取Pod IP:
[root@master ~]# kubectl get pod pod-ports -n test -o wide
NAME        READY   STATUS    RESTARTS   AGE     IP            NODE    NOMINATED NODE   READINESS GATES
pod-ports   1/1     Running   0          3m40s   10.244.1.16   node1   <none>           <none>
2. 访问服务:
[root@master ~]# curl http://10.244.1.16:80
<!DOCTYPE html><html><head><title>Welcome to nginx!</title></head><body><h1>Welcome to nginx!</h1>
......</body></html>
6. 容器资源配额配置

通过resources配置容器的CPU和内存资源限制(limits)与请求(requests),避免单个容器占用过多资源,保障集群稳定性。

  • 资源配额核心概念
    • limits:容器运行时的最大资源占用(超过会触发容器重启)。
    • requests:容器启动所需的最小资源(集群资源不足时Pod无法调度)。
  • 资源单位说明
    • CPU:单位为“core”,支持整数(如“1”)或小数(如“0.5”,表示半核)。
    • 内存:单位支持Gi(1Gi=1024Mi)、MiG(1G=1000M)、M,推荐使用Gi/Mi(二进制单位,更符合内存计算逻辑)。
  • 配置文件(pod-resources.yaml)
apiVersion: v1
kind: Pod
metadata:
  name: pod-resources
  namespace: test
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    imagePullPolicy: Never
    resources:
      limits:  # 资源上限
        cpu: "2"        # 最大CPU占用:2核
        memory: "10Gi"  # 最大内存占用:10Gi
      requests:  # 资源请求
        cpu: "1"         # 最小CPU需求:1核
        memory: "10Mi"   # 最小内存需求:10Mi
  • 创建与验证资源配置
    • 正常创建(资源充足场景):
[root@master ~]# kubectl create -f pod-resources.yaml
pod/pod-resources created
[root@master ~]# kubectl get pods -n test
pod-resources          1/1     Running            0                10s
  • 资源不足场景(模拟):修改requests.memory10Gi(超过节点可用内存),Pod会处于Pending状态,无法调度。
    1. 修改配置文件:
requests:
  memory: "10Gi"
2. 重新创建Pod:
[root@master ~]# kubectl delete -f pod-resources.yaml
pod "pod-resources" deleted
[root@master ~]# kubectl create -f pod-resources.yaml
pod/pod-resources created
3. 查看Pod状态:
[root@master ~]# kubectl get pods -n test
pod-resources          0/1     Pending            0                16s
4. 查看调度失败原因:通过`kubectl describe`查看事件,显示“Insufficient memory”(内存不足)。
[root@master ~]# kubectl describe pod pod-resources -n test
Warning  FailedScheduling  87s   default-scheduler  0/3 nodes are available: 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }, 3 Insufficient memory. preemption: 0/3 nodes are available: 1 Preemption is not helpful for scheduling, 2 No preemption victims found for incoming pod.

(三)Pod关键工具命令

  1. 查看资源可配置项:通过kubectl explain命令查看Pod及子资源的可配置项,便于编写配置文件。
    • 查看Pod一级属性:
kubectl explain pod
  • 查看Pod元数据(metadata)子属性:
kubectl explain pod.metadata
  • 查看容器(containers)子属性:
kubectl explain pod.spec.containers
  1. 进入容器执行命令:通过kubectl exec命令进入Pod中的指定容器,进行调试或操作。
kubectl exec -it <pod名称> -n <命名空间> -c <容器名称> -- <命令>
# 示例:进入pod-command1的busybox容器,执行/bin/sh
kubectl exec -it pod-command1 -n test -c busybox -- /bin/sh
  1. 查看Pod日志:通过kubectl logs命令查看容器日志,排查故障。
kubectl logs <pod名称> -n <命名空间> -c <容器名称>  # 查看指定容器日志
kubectl logs -f <pod名称> -n <命名空间> -c <容器名称>  # 实时查看日志(类似tail -f)

三、总结

  1. Service核心价值:为动态变化的Pod提供固定访问入口,实现集群内/外服务访问与负载均衡,解决Pod IP动态变化和外部访问问题。
  2. Pod核心特性:作为最小部署单元,支持多容器协同运行,通过资源清单精细控制容器的镜像、命令、环境变量、端口、资源配额等配置,满足不同业务场景需求。
  3. 实践建议
    • 生产环境中,优先通过YAML配置文件管理Service和Pod,便于版本控制和批量部署。
    • 容器资源配额需合理配置,避免资源浪费或不足导致的服务不稳定。
    • 敏感信息(如密码、密钥)避免直接写在配置文件中,应使用Secret资源管理。
    • 定期通过kubectl describekubectl logs等命令排查Pod故障,保障服务正常运行。

更多推荐