📘 Day 08:Service 与集群内服务发现 🎯 今日目标
🧠 理论精讲(30 分钟) Service 解决了什么问题 Pod 是短暂的 (IP 会变),Service 提供稳定的访问入口 :
1 2 3 Pod-A (IP: 10.244.1.5) ─┐ Pod-B (IP: 10.244.2.3) ─┤──→ Service (ClusterIP: 10.96.0.1) ──→ 客户端 Pod-C (IP: 10.244.1.9) ─┘
无论后端 Pod 如何变化,Service 的 ClusterIP 不变。
kube-proxy 工作模式
模式
原理
性能
iptables
通过 iptables 规则随机转发
规则数多时性能下降
IPVS
内核级负载均衡
高性能,支持多种调度算法
四种 Service 类型
类型
访问范围
典型场景
ClusterIP
集群内部
内部服务间通信
NodePort
节点 IP + 端口
开发调试、简单外部访问
LoadBalancer
外部 LB 分发
生产环境外部入口
ExternalName
DNS CNAME
外部服务映射
CoreDNS 域名格式 1 <service-name>.<namespace>.svc.cluster.local
1 2 3 api-server.default.svc.cluster.local redis-cache.production.svc.cluster.local
🔧 动手实操(120 分钟) 练习 8.1:ClusterIP Service 基础 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 kubectl create deploy backend --image=nginx:alpine --replicas=3 kubectl expose deploy backend --port=80 --target-port=80 kubectl get svc backend kubectl get endpoints backend kubectl run test-client --image=busybox:1.36 --rm -it --restart=Never -- \ wget -q -O- http://backend kubectl run test-dns --image=busybox:1.36 --rm -it --restart=Never -- \ wget -q -O- http://backend.default.svc.cluster.local
练习 8.2:NodePort Service 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 kubectl expose deploy backend --type =NodePort --port=80 --name=backend-np kubectl get svc backend-np kubectl get nodes -o wide curl http://<任意节点IP>:30080 kubectl run test-np --image=busybox:1.36 --rm -it --restart=Never -- \ wget -q -O- http://backend-np kubectl delete svc backend-np
练习 8.3:ExternalName Service 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Service metadata: name: external-db spec: type: ExternalName externalName: database.example.com EOF kubectl get svc external-db kubectl run dns-check --image=busybox:1.36 --rm -it --restart=Never -- \ nslookup external-db kubectl delete svc external-db
练习 8.4:Headless Service + 直接 Pod DNS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Service metadata: name: headless-svc spec: clusterIP: None selector: app: backend ports: - port: 80 EOF kubectl get svc headless-svc kubectl run dns-hl --image=busybox:1.36 --rm -it --restart=Never -- \ nslookup headless-svc kubectl delete svc headless-svc
练习 8.5:Service 负载均衡验证 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 cat <<'EOF' | kubectl apply -f -apiVersion: apps/v1 kind: Deployment metadata: name: lb-test spec: replicas: 3 selector: matchLabels: app: lb-test template: metadata: labels: app: lb-test spec: containers: - name: http image: busybox:1.36 command : - sh - -c - | echo -e "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nHello from $(hostname) " > /tmp/response while true ; do nc -l -p 8080 < /tmp/response; done ports: - containerPort: 8080 EOF kubectl expose deploy lb-test --port=8080 --target-port=8080 kubectl run lb-client --image=busybox:1.36 --rm -it --restart=Never -- \ sh -c 'for i in $(seq 1 10); do wget -q -O- http://lb-test:8080; echo; done' kubectl logs -n kube-system -l k8s-app=kube-proxy | grep "Using" kubectl delete deploy backend lb-test kubectl delete svc backend lb-test
🐛 排错练习(30 分钟) 场景 1:Service 无法访问 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 kubectl get svc <svc-name> -o jsonpath='{.spec.selector}' kubectl get pod -l <key>=<value> kubectl get endpoints <svc-name> kubectl get svc <svc-name> -o jsonpath='{.spec.ports[*].targetPort}' kubectl get pod -l app=<name> -o jsonpath='{.spec.containers[*].ports}' kubectl get networkpolicies
场景 2:CoreDNS 解析失败 1 2 3 4 5 6 7 8 9 10 11 kubectl run dns-debug --image=busybox:1.36 --rm -it --restart=Never -- nslookup kubernetes.default kubectl get pods -n kube-system -l k8s-app=kube-dns kubectl logs -n kube-system -l k8s-app=kube-dns --tail =20 kubectl rollout restart deploy/coredns -n kube-system
🏆 赛题模拟(40 分钟)
⚠️ 严格限时 35 分钟
题目:多层服务暴露
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 【操作要求】 1. 创建 Deployment app-v1(3 副本,nginx:alpine),暴露为 ClusterIP Service app-svc 2. 创建 Deployment app-v2(2 副本,httpd:alpine),暴露为 ClusterIP Service app-v2-svc 3. 在 app-v1 的 nginx 中配置反向代理到 app-v2-svc(通过 Service 名称) 4. 创建 NodePort Service app-gateway,暴露 app-svc 到节点 31080 端口 5. 验证: - 集群内 curl http://app-svc → 返回 nginx 页面 - 集群内 curl http://app-v2-svc → 返回 httpd 页面 - 节点 IP:31080 → 返回 nginx 页面 - CoreDNS 解析 app-svc 和 app-v2-svc 均正常 6. 输出所有 Service 的 Endpoint 信息 【评分标准】 - Service 创建正确(30 分) - 集群内通信正常(25 分) - NodePort 访问正常(20 分) - DNS 解析正常(15 分) - Endpoint 正确(10 分)
📋 命令速查
命令
功能
注解
kubectl get svc
列出所有 Service
TYPE 列显示 ClusterIP/NodePort/LoadBalancer/ExternalName
kubectl get svc -o wide
Service + 选择器/端口
确认 Selector 和暴露的端口
kubectl get endpoints
查看 Service 后端端点
为空说明 Selector 没匹配到 Running Pod
kubectl describe svc <name>
Service 详细信息
查看 SessionAffinity、Endpoints、Events
kubectl expose deploy <name> --port=80 --target-port=8080
快速创建 Service 暴露 Deployment
默认创建 ClusterIP 类型
kubectl expose deploy <name> --type=NodePort --port=80 --target-port=8080
创建 NodePort Service
节点 IP:30000-32767 可外部访问
kubectl expose deploy <name> --type=LoadBalancer --port=80
创建 LoadBalancer Service
云厂商分配外部 LB IP(学习环境会一直 Pending)
kubectl run test --image=busybox --rm -it -- wget -O- http://<svc-name>
临时 Pod 测试 Service 可达性
--rm 退出即删除,网络调试首选
kubectl exec <pod> -- nslookup <svc-name>
验证 CoreDNS 解析
解析失败说明 CoreDNS 故障或 SVC 不存在
kubectl exec <pod> -- nslookup <svc-name>.<ns>.svc.cluster.local
验证 FQDN 解析
全限定域名格式:<svc>.<namespace>.svc.cluster.local
kubectl exec <pod> -- curl -s <svc-name>.<ns>.svc.cluster.local:<port>
通过 FQDN 访问服务
跨命名空间通信必须用 FQDN
kubectl get pods -l app=<label>
按标签查 Pod
验证 Service Selector 是否匹配到正确的 Pod
kubectl patch svc <name> -p '{"spec":{"sessionAffinity":"ClientIP"}}'
修改会话亲和性
同一客户端 IP 始终路由到同一 Pod
kubectl create svc clusterip <name> --tcp=80:8080 --dry-run=client -o yaml
生成 ClusterIP Service YAML
--tcp 指定 <port>:<targetPort>
kubectl create svc nodeport <name> --tcp=80:8080 --node-port=30080 --dry-run=client -o yaml
生成 NodePort Service YAML
指定固定 NodePort 而非随机端口
kubectl -n kube-system logs -l k8s-app=kube-dns
查看 CoreDNS 日志
DNS 解析故障时首要排查
📚 参考来源