Service 类型与网络访问
High Contrast
Dark Mode
Light Mode
Sepia
Forest
2 min read482 words

Service 类型与网络访问

核心问题:Pod IP 会随着重建而改变——怎样给应用一个稳定的访问入口?外部用户怎样访问集群内的服务?


为什么需要 Service

Pod 是短暂的,它的 IP 在每次重建后都会改变。Service 提供一个稳定的虚拟 IP(ClusterIP)和 DNS 名称,始终指向满足条件的 Pod 集合。

graph LR CLIENT["客户端
或其他 Pod"] SVC["Service
10.96.10.100
(ClusterIP,永远不变)"] P1["Pod A
10.244.1.5"] P2["Pod B
10.244.2.8"] P3["Pod C
10.244.3.12"] CLIENT --> SVC SVC -->|kube-proxy 负载均衡| P1 SVC -->|kube-proxy 负载均衡| P2 SVC -->|kube-proxy 负载均衡| P3

Service 通过 Label Selector 关联 Pod

# Service 选择所有 app=api 的 Pod
apiVersion: v1
kind: Service
metadata:
name: api-service
namespace: production
spec:
selector:
app: api-server        # 匹配 Pod 的 labels
ports:
- name: http
protocol: TCP
port: 80             # Service 对外暴露的端口
targetPort: 3000     # Pod 上实际的端口(containerPort)

四种 Service 类型

ClusterIP(默认)

仅集群内部可访问,分配一个虚拟 IP。微服务间调用的标准方式:

spec:
type: ClusterIP   # 默认值,可省略
selector:
app: api-server
ports:
- port: 80
targetPort: 3000
# 其他 Pod 通过 DNS 访问:
# http://api-service.production.svc.cluster.local:80
# 同 Namespace 内简写:http://api-service:80

NodePort

在每个节点上暴露一个端口(30000–32767),适合开发测试:

spec:
type: NodePort
selector:
app: api-server
ports:
- port: 80          # ClusterIP 端口(内部访问)
targetPort: 3000  # Pod 端口
nodePort: 30080   # 节点端口(可省略,自动分配)

访问方式:http://<任意节点IP>:30080

⚠️ 生产环境不推荐:端口范围有限,需要在安全组开放所有节点的这个端口。

LoadBalancer

在云平台上自动创建云负载均衡器(ALB / NLB / GCE LB),分配公网 IP:

spec:
type: LoadBalancer
selector:
app: api-server
ports:
- port: 80
targetPort: 3000
# AWS 注解(可选)
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
kubectl get service api-service -n production
# NAME          TYPE           CLUSTER-IP     EXTERNAL-IP
# api-service   LoadBalancer   10.96.10.100   52.1.2.3     ← 公网 IP

⚠️ 每个 LoadBalancer Service 都会创建一个云负载均衡器,费用高昂。生产建议用 Ingress 统一入口。

ExternalName

将 Service 映射到集群外部的 DNS 名称:

spec:
type: ExternalName
externalName: rds-endpoint.ap-southeast-1.rds.amazonaws.com

集群内 Pod 通过 db-service.production.svc.cluster.local 访问外部 RDS。


Ingress:HTTP 路由层

Ingress 是 HTTP/HTTPS 的 L7 路由规则,通过 Ingress Controller 实现:

graph LR USER["用户请求"] LB["云 LoadBalancer
(一个,共享成本)"] ING["Ingress Controller
(Nginx / Traefik / ALB)"] SVC1["api-service
:80"] SVC2["web-service
:80"] SVC3["admin-service
:80"] USER --> LB --> ING ING -->|api.example.com/v1| SVC1 ING -->|www.example.com| SVC2 ING -->|admin.example.com| SVC3
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: main-ingress
namespace: production
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"  # 自动 TLS
spec:
ingressClassName: nginx
tls:
- hosts:
- api.example.com
- www.example.com
secretName: example-com-tls
rules:
- host: api.example.com
http:
paths:
- path: /v1
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- host: www.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80

安装 Ingress Controller

# Nginx Ingress Controller(最通用)
helm upgrade --install ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace ingress-nginx \
--create-namespace \
--set controller.replicaCount=2 \
--set controller.metrics.enabled=true
# AWS Load Balancer Controller(EKS 原生方案)
helm upgrade --install aws-load-balancer-controller \
eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName=prod-cluster \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller

NetworkPolicy:Pod 间网络隔离

默认情况下,所有 Pod 之间互通。NetworkPolicy 实现微隔离:

# 只允许来自 api 服务的请求到达 db
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-access-policy
namespace: production
spec:
podSelector:
matchLabels:
app: postgres      # 应用于 postgres Pod
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: api-server   # 只允许 api-server Pod 进入
ports:
- protocol: TCP
port: 5432
egress:
- to:
- namespaceSelector:
matchLabels:
name: kube-system  # 允许 DNS 查询
ports:
- protocol: UDP
port: 53

DNS 解析规则

<service>.<namespace>.svc.cluster.local
例:
api-service.production.svc.cluster.local    → 完整 FQDN
api-service.production                       → 跨 Namespace 简写
api-service                                  → 同 Namespace 内访问
# 在 Pod 内调试 DNS
kubectl run -it dns-test --image=busybox --rm -- nslookup api-service.production
# 查看 Service 的 Endpoints(确认 Pod 正确关联)
kubectl get endpoints api-service -n production
kubectl describe service api-service -n production

常见错误

问题 原因 解决
Service 有 ClusterIP 但无 Endpoints Pod 的 labels 与 selector 不匹配 kubectl get endpoints 确认,检查 label
Ingress 无法路由(404 / 503) Ingress Controller 未安装,或 ingressClassName 不对 检查 kubectl get ingressclass
集群内 DNS 解析失败 CoreDNS 崩溃 kubectl get pods -n kube-system 检查 coredns 状态
LoadBalancer 一直 Pending 云平台权限不足,无法创建负载均衡器 检查 Node IAM Role 是否有 elasticloadbalancing:* 权限

下一章Kubernetes 实战:应用部署、扩缩容与存储