03-Service 与网络
Service 与网络Part 1Service —— 稳定的访问入口概念引入还记得港口的比喻吗Pod 是货船但货船会来来去去——有的卸完货走了有的坏了被替换。如果客户每次都要找到具体的某艘船那就太麻烦了。Service 就是港口的接待处。不管后面的船怎么换接待处的地址永远不变。客户只需要找接待处接待处自动把请求转发给可用的船。固定地址Pod 挂了客户端Service接待处Pod 1Pod 2Pod 3❌新 Pod 4Service 自动把流量切到存活的 Pod原理讲解为什么需要 ServicePod 有两个问题IP 会变Pod 重启后 IP 地址变化数量会变扩缩容时 Pod 数量不固定Service 解决了这两个问题提供一个稳定的访问入口自动管理后端 Pod 的流量分发。Service 的类型类型谁能访问用途ClusterIP仅集群内部微服务之间互相调用NodePort集群外部通过节点端口暴露服务LoadBalancer公网云厂商提供的负载均衡器ExternalName映射外部服务把集群内名称映射到外部域名外部访问节点端口 30080公网 IPNodePort ServicePodLoadBalancer集群内部ClusterIP ServicePodPod标签选择器Service 怎么知道哪些 Pod 是它的后端和 ReplicaSet 一样通过标签选择器selector:app:nginx# 匹配所有 labels 里有 app: nginx 的 PodDNS 服务发现K8s 内置了 DNSCoreDNS每个 Service 自动获得一个域名service-name.namespace.svc.cluster.local比如名为nginx-svc的 Service 在同 namespace 下可以直接用nginx-svc访问。Service YAML 结构apiVersion:v1kind:Servicemetadata:name:nginx-svcspec:type:ClusterIP# Service 类型selector:app:nginx# 匹配哪些 Podports:-port:80# Service 暴露的端口targetPort:80# Pod 上的目标端口动手实验步骤 1创建 Deploymentkubectl create deployment nginx--imagenginx:1.27--replicas3步骤 2创建 ClusterIP Servicecatnginx-svc.yamlEOF apiVersion: v1 kind: Service metadata: name: nginx-svc spec: type: ClusterIP selector: app: nginx ports: - port: 80 targetPort: 80 EOFkubectl apply-fnginx-svc.yaml步骤 3查看 Servicekubectl get services预期输出NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 (none) 443/TCP 10m nginx-svc ClusterIP 10.96.45.123 (none) 80/TCP 5s步骤 4测试集群内访问启动一个临时 Pod 来访问 Servicekubectl run curl-test--imagecurlimages/curl--rm-it--curlnginx-svc预期输出Nginx 的 HTML 页面内容。步骤 5创建 NodePort Servicecatnginx-nodeport.yamlEOF apiVersion: v1 kind: Service metadata: name: nginx-nodeport spec: type: NodePort selector: app: nginx ports: - port: 80 targetPort: 80 nodePort: 30080 EOFkubectl apply-fnginx-nodeport.yaml步骤 6查看 NodePortkubectl getservicenginx-nodeport预期输出NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-nodeport NodePort 10.96.78.45 (none) 80:30080/TCP 5s步骤 7从外部访问如果你在创建 Kind 集群时使用了包含extraPortMappings的配置NodePort 30080 已映射到宿主机可以直接访问curlhttp://localhost:30080如果没有配置 extraPortMappingsKind 节点的 IP 是 Docker 内部网络宿主机无法直接访问。此时可以用kubectl port-forward service/nginx-nodeport 8080:80临时转发但这不是 NodePort 的工作方式——port-forward 是 kubectl 的独立机制与 NodePort 无关。步骤 8清理kubectl delete-fnginx-svc.yaml-fnginx-nodeport.yaml kubectl delete deployment nginxrmnginx-svc.yaml nginx-nodeport.yamlPart 2网络基础 —— 从 Pod 到 Ingress概念引入你的 K8s 集群里跑着好几个微服务前端、后端、数据库。它们之间怎么通信外部用户怎么访问你的网站K8s 提供了三层网络能力第一层Pod 网络第二层Service第三层IngressPod IP 直连Ingress - HTTP 路由Service - 稳定的访问入口Pod APod BPod C外部用户Pod 网络每个 Pod 有独立 IPPod 之间可以直接通信Service提供稳定的访问入口前面讲过IngressHTTP 层的智能路由根据域名/路径转发到不同 Service原理讲解Ingress 是什么Service 的 NodePort 方式虽然能从外部访问但有缺点端口范围有限30000-32767、不支持域名路由。Ingress 就是 K8s 的HTTP 路由器可以根据域名和路径把请求转发到不同的 Serviceapi.example.comwww.example.com/admin用户请求Ingressapi-svc:80web-svc:80admin-svc:80Ingress ControllerIngress 资源本身只是一组规则你需要一个Ingress Controller来执行这些规则Controller特点Nginx Ingress最流行功能丰富Traefik自动发现配置简单KongAPI 网关插件丰富Kind 集群默认不带 Ingress Controller需要手动安装。DNS 服务发现K8s 集群内置 CoreDNS每个 Service 自动获得域名# 同 namespace 访问 nginx-svc # 跨 namespace 访问 nginx-svc.production # 完整域名 nginx-svc.production.svc.cluster.localPod 之间的网络K8s 保证每个 Pod 有唯一 IP任意两个 Pod 可以直接通信不需要 NAT同一节点的 Pod 和不同节点的 Pod 都能互通这个扁平网络由 CNI 插件实现Kind 默认用 kindnet。动手实验⚠️前置条件确保你的 Kind 集群使用了包含 80/443 端口映射的配置。否则curl localhost将无法连通。步骤 1安装 Ingress Controllerkubectl apply-fhttps://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml# 等待就绪kubectlwait--forconditionready pod\-lapp.kubernetes.io/componentcontroller\-ningress-nginx--timeout90s⚠️重要Kind 集群只在 control-plane 节点上做了 80/443 端口映射。必须确保 Ingress Controller 运行在 control-plane 节点上否则curl localhost无法连通。# 将 Ingress Controller 固定到 control-plane 节点kubectl labelnodek8s-guide-control-plane ingress-readytrue kubectl patch deployment-ningress-nginx ingress-nginx-controller\-p{spec:{template:{spec:{nodeSelector:{ingress-ready:true}}}}}# 等待 Pod 重新调度完成kubectl rollout status deployment-ningress-nginx ingress-nginx-controller--timeout120s步骤 2创建两个应用# 应用 Awebkubectl create deployment web--imagenginx:1.27 kubectl expose deployment web--port80# 应用 Bapikubectl create deployment api--imagehashicorp/http-echo -- /http-echo-textHello from APIkubectl expose deployment api--port5678步骤 3测试 DNS 解析kubectl run dns-test--imagebusybox--rm-it--nslookupweb预期输出包含 web Service 的 ClusterIPName: web.default.svc.cluster.local Address 1: 10.96.xx.xx步骤 4创建 Ingresscatmy-ingress.yamlEOF apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-ingress spec: ingressClassName: nginx rules: - http: paths: - path: / pathType: Prefix backend: service: name: web port: number: 80 - path: /api pathType: Prefix backend: service: name: api port: number: 5678 EOFkubectl apply-fmy-ingress.yaml步骤 5通过 Ingress 访问# 访问根路径 - webNginx 欢迎页curllocalhost# 访问 /api - apicurllocalhost/api预期输出/api返回 “Hello from API”步骤 6清理kubectl delete ingress my-ingress kubectl delete deployment web api kubectl deleteserviceweb apirmmy-ingress.yaml自检问题ClusterIP 和 NodePort 的区别是什么查看答案 ClusterIP 只能在集群内部访问NodePort 通过在每个节点上开一个端口30000-32767允许外部访问。Service 和 Ingress 的区别是什么查看答案 Service 是 L4TCP/UDP层的负载均衡提供稳定的 IP/端口。Ingress 是 L7HTTP层的路由器可以根据域名和 URL 路径把请求转发到不同的 Service。为什么需要 Ingress Controller查看答案 Ingress 资源只是一组路由规则本身不执行任何操作。Ingress Controller如 Nginx Ingress是实际处理流量的组件它读取 Ingress 规则并配置自己的转发逻辑。Pod A 怎么通过名字找到 Service B查看答案 通过 K8s 内置的 CoreDNS。每个 Service 自动注册域名如 my-svc.default.svc.cluster.local同 namespace 下可直接用 Service 名字访问。下一步应用能访问了但配置信息数据库地址、API 密钥等怎么管理扩缩容怎么自动化→ 04. 配置与扩缩本文来自 K8s Guide—— 开源免费的 Kubernetes 中文学习指南️ 初学者轨道 面试轨道从零基础到拿 Offer 一站式覆盖 每篇文章配套 Kind 实验脚本本地一键运行 本文源码docs/beginner/06-service.md / docs/beginner/09-networking-basics.md⭐如果对你有帮助欢迎 Stargithub.com/callmebg/k8s-guide