Kubernetes Service与Pod深度解析
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-nginxnamespace: dev
spec:clusterIP: 10.109.179.231 # 固定Service的内网IP(可选)ports:- port: 80protocol: TCPtargetPort: 80selector:run: nginx # 关联标签为“run=nginx”的Podtype: 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: value1key2: 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: stringvalue: stringtcpSocket: # TCP连接检查(连接成功表示健康)port: numberinitialDelaySeconds: 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: valueimagePullSecrets: # 可选,拉取私有镜像的密钥(引用Secret资源)- name: stringhostNetwork: 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: stringpath: 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-basenamespace: 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-imagepullpolicynamespace: test
spec:containers:- name: nginximage: nginx:1.17.1imagePullPolicy: Never # 仅使用本地镜像,不远程拉取- name: busyboximage: busybox:1.30imagePullPolicy: 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-command1namespace: test
spec:containers:- name: nginximage: nginx:1.17.1imagePullPolicy: Never- name: busyboximage: busybox:1.30imagePullPolicy: 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中的ENTRYPOINT,args对应CMD,两者配合实现命令覆盖:- 若均不配置:使用Dockerfile默认的
ENTRYPOINT和CMD。 - 仅配置
command:覆盖ENTRYPOINT,忽略Dockerfile的CMD。 - 仅配置
args:保留Dockerfile的ENTRYPOINT,用args替换CMD。 - 均配置:完全覆盖Dockerfile的
ENTRYPOINT和CMD,执行command + args。
- 若均不配置:使用Dockerfile默认的
4. 容器环境变量配置
通过env为容器设置环境变量,用于传递配置信息(如数据库账号、服务地址等)。
- 配置文件(pod-env.yaml):
apiVersion: v1
kind: Pod
metadata:name: pod-envnamespace: test
spec:containers:- name: busyboximage: busybox:1.30imagePullPolicy: Nevercommand: ["/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资源存储敏感信息,再通过env或volumeMounts引用。
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-portsnamespace: test
spec:containers:- name: nginximage: nginx:1.17.1imagePullPolicy: Neverports:- 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.1imagePullPolicy: Nevername: nginxports:- containerPort: 80name: nginx-portprotocol: TCP
......
- 访问容器服务:通过Pod IP和
containerPort访问Nginx服务。- 获取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)、Mi、G(1G=1000M)、M,推荐使用Gi/Mi(二进制单位,更符合内存计算逻辑)。
- 配置文件(pod-resources.yaml):
apiVersion: v1
kind: Pod
metadata:name: pod-resourcesnamespace: test
spec:containers:- name: nginximage: nginx:1.17.1imagePullPolicy: Neverresources:limits: # 资源上限cpu: "2" # 最大CPU占用:2核memory: "10Gi" # 最大内存占用:10Girequests: # 资源请求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.memory为10Gi(超过节点可用内存),Pod会处于Pending状态,无法调度。- 修改配置文件:
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关键工具命令
- 查看资源可配置项:通过
kubectl explain命令查看Pod及子资源的可配置项,便于编写配置文件。- 查看Pod一级属性:
kubectl explain pod
- 查看Pod元数据(metadata)子属性:
kubectl explain pod.metadata
- 查看容器(containers)子属性:
kubectl explain pod.spec.containers
- 进入容器执行命令:通过
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
- 查看Pod日志:通过
kubectl logs命令查看容器日志,排查故障。
kubectl logs <pod名称> -n <命名空间> -c <容器名称> # 查看指定容器日志
kubectl logs -f <pod名称> -n <命名空间> -c <容器名称> # 实时查看日志(类似tail -f)
三、总结
- Service核心价值:为动态变化的Pod提供固定访问入口,实现集群内/外服务访问与负载均衡,解决Pod IP动态变化和外部访问问题。
- Pod核心特性:作为最小部署单元,支持多容器协同运行,通过资源清单精细控制容器的镜像、命令、环境变量、端口、资源配额等配置,满足不同业务场景需求。
- 实践建议:
- 生产环境中,优先通过YAML配置文件管理Service和Pod,便于版本控制和批量部署。
- 容器资源配额需合理配置,避免资源浪费或不足导致的服务不稳定。
- 敏感信息(如密码、密钥)避免直接写在配置文件中,应使用Secret资源管理。
- 定期通过
kubectl describe、kubectl logs等命令排查Pod故障,保障服务正常运行。
