文章目录
- [Kubernetes Service 核心概念与实操指南(使用yaml文件版)](#Kubernetes Service 核心概念与实操指南(使用yaml文件版))
-
- 引言
- [一、Service 核心作用](#一、Service 核心作用)
- [二、kube-proxy 三种代理模式](#二、kube-proxy 三种代理模式)
-
- [2.1 userspace 模式(第一代)](#2.1 userspace 模式(第一代))
- [2.2 iptables 模式(第二代)](#2.2 iptables 模式(第二代))
- [2.3 ipvs 模式(第三代)](#2.3 ipvs 模式(第三代))
- 三种模式对比
- [三、Service 类型及实操](#三、Service 类型及实操)
-
- [3.1 ClusterIP(默认类型)](#3.1 ClusterIP(默认类型))
-
- [3.1.1 普通 ClusterIP Service(命令行创建)](#3.1.1 普通 ClusterIP Service(命令行创建))
- [3.1.2 普通 ClusterIP Service(YAML 创建)](#3.1.2 普通 ClusterIP Service(YAML 创建))
- [3.1.3 Headless Service(无头服务)](#3.1.3 Headless Service(无头服务))
- [3.2 NodePort(外部访问入口)](#3.2 NodePort(外部访问入口))
- [3.3 LoadBalancer(云厂商负载均衡)](#3.3 LoadBalancer(云厂商负载均衡))
-
- [3.3.1 自建集群解决方案:MetalLB](#3.3.1 自建集群解决方案:MetalLB)
-
- [版本 1:MetalLB v0.12(基于 ConfigMap 配置)](#版本 1:MetalLB v0.12(基于 ConfigMap 配置))
- [版本 2:MetalLB v0.15(基于 CRD 配置)](#版本 2:MetalLB v0.15(基于 CRD 配置))
- [3.4 ExternalName(引入外部服务)](#3.4 ExternalName(引入外部服务))
- 四、特殊场景配置
-
- [4.1 跨命名空间访问](#4.1 跨命名空间访问)
-
- [场景:ns1 与 ns2 命名空间互访](#场景:ns1 与 ns2 命名空间互访)
- [4.2 会话粘黏(Session Affinity)](#4.2 会话粘黏(Session Affinity))
- 五、总结
- [Kubernetes Service :从不懂到会用(使用命令行版)](#Kubernetes Service :从不懂到会用(使用命令行版))
-
- 前置说明
- [一、为啥需要 Service?(大白话总结)](#一、为啥需要 Service?(大白话总结))
- [二、Service 的 "3 种快递分拣方式"(kube-proxy 模式)](#二、Service 的 “3 种快递分拣方式”(kube-proxy 模式))
- [三、4 种 Service 类型:对应不同 "访问场景"](#三、4 种 Service 类型:对应不同 “访问场景”)
-
- [3.1 ClusterIP:只让集群内部访问(比如公司内部用)](#3.1 ClusterIP:只让集群内部访问(比如公司内部用))
-
- [操作步骤(以 nginx 为例)](#操作步骤(以 nginx 为例))
-
- [第一步:先创建 2 个 nginx "临时工"(Pod)](#第一步:先创建 2 个 nginx “临时工”(Pod))
- [第二步:创建 "前台"(ClusterIP Service)](#第二步:创建 “前台”(ClusterIP Service))
- 第三步:测试访问(集群内才能用)
- [3.2 NodePort:让集群外也能访问(比如你本地电脑访问)](#3.2 NodePort:让集群外也能访问(比如你本地电脑访问))
-
- 操作步骤
-
- [第一步:还是先有 nginx Pod(同 3.1 第一步,不用重复做)](#第一步:还是先有 nginx Pod(同 3.1 第一步,不用重复做))
- [第二步:创建 NodePort 类型的 Service](#第二步:创建 NodePort 类型的 Service)
- 第三步:本地电脑访问
- [3.3 LoadBalancer:公司级对外访问(用 MetalLB 实现)](#3.3 LoadBalancer:公司级对外访问(用 MetalLB 实现))
-
- 操作步骤(小白版,复制粘贴就行)
-
- [第一步:安装 MetalLB(负载均衡器工具)](#第一步:安装 MetalLB(负载均衡器工具))
- [第二步:给 MetalLB 分配 IP(让它有地址可分配)](#第二步:给 MetalLB 分配 IP(让它有地址可分配))
- [第三步:创建 LoadBalancer 类型的 Service](#第三步:创建 LoadBalancer 类型的 Service)
- 第四步:访问测试
- [3.4 ExternalName:让集群内 Pod 访问外部服务(比如访问百度)](#3.4 ExternalName:让集群内 Pod 访问外部服务(比如访问百度))
-
- 操作步骤
-
- [第一步:创建 ExternalName 类型的 Service](#第一步:创建 ExternalName 类型的 Service)
- [第二步:测试访问(集群内 Pod 访问)](#第二步:测试访问(集群内 Pod 访问))
- 四、小白常遇到的问题(避坑指南)
- [五、总结:小白怎么选 Service 类型?](#五、总结:小白怎么选 Service 类型?)
Kubernetes Service 核心概念与实操指南(使用yaml文件版)
引言
在 Kubernetes 集群中,Pod 具有 "用后即焚" 的特性,IP 地址会随重建频繁变动,导致服务访问不稳定。Service 作为 Pod 的统一访问入口,通过 Label 关联 Pod,动态跟踪 Pod IP 变化,同时提供负载均衡、访问策略定义等核心能力,是 K8s 服务暴露与访问的关键组件。
一、Service 核心作用
- 固定访问入口:为 Pod 提供统一的虚拟 IP(ClusterIP),屏蔽 Pod IP 变动影响
- 动态关联 Pod:通过 Label Selector 自动关联匹配的 Pod,Pod 增减或 IP 变化时自动更新端点列表(Endpoints)
- 负载均衡:支持 TCP/UDP 4 层负载均衡,分发请求到后端多个 Pod
- 访问策略定义:控制集群内外对 Pod 的访问规则
- 防止 Pod 失联:通过端点监控确保请求仅转发到健康的 Pod
二、kube-proxy 三种代理模式
kube-proxy 是实现 Service 功能的核心组件,通过监控 kube-apiserver 中 Service 和 Endpoints 的变化,在节点上生成转发规则。支持三种代理模式,各有优劣:
2.1 userspace 模式(第一代)
- 版本支持:K8s v1.0 起支持
- 核心原理:kube-proxy 为每个 Service 监听随机端口,通过 iptables 规则将 ClusterIP:Port 请求转发到该端口,再由 kube-proxy 采用轮询(默认)或会话亲和性策略分发到 Pod
- 优缺点:
- 缺点:请求需在用户态与内核态之间切换,性能损耗大,效率低
- 优点:实现简单,兼容性好(仅作了解,不推荐使用)
2.2 iptables 模式(第二代)
- 版本支持:K8s v1.1 起支持,v1.2 起成为默认模式
- 核心原理:kube-proxy 仅作为控制器,通过 netfilter/iptables 规则直接实现请求转发,无需用户态干预
- 优缺点:
- 优点:性能优于 userspace 模式,内核态转发效率高
- 缺点:规则过多时呈线性匹配延时,转发算法单一(仅轮询、随机)
2.3 ipvs 模式(第三代)
- 版本支持:K8s v1.8 引入,v1.11 正式可用,v1.11+ 默认推荐
- 核心原理:基于 Linux 内核 IPVS(IP Virtual Server)模块,提供 4 层负载均衡,通过 ipset 存储地址集合优化规则匹配
- 核心优势:
- 支持更丰富的负载均衡算法(最小负载、最少连接、加权轮询等)
- 规则查找效率高(ipset 为索引结构,而非 iptables 的线性结构)
- 支持服务器健康检查、连接重试功能
- 动态修改规则不影响现有连接
- 依赖:内核版本需 4.0+,需加载 ipvs 模块,否则自动降级为 iptables 模式
三种模式对比
| 模式 | 内核态 / 用户态 | 性能 | 负载均衡算法 | 适用场景 |
|---|---|---|---|---|
| userspace | 两者切换 | 低 | 轮询、会话亲和 | 早期版本兼容(不推荐) |
| iptables | 内核态 | 中 | 轮询、随机 | 小型集群(规则少) |
| ipvs | 内核态 | 高 | 多种算法 | 中大型集群(推荐) |
三、Service 类型及实操
K8s 提供 4 种核心 Service 类型,适配不同访问场景,以下是详细配置与实操步骤:
3.1 ClusterIP(默认类型)
仅集群内部可访问,分配集群唯一虚拟 IP。分为普通 Service 和 Headless Service 两类。
3.1.1 普通 ClusterIP Service(命令行创建)
- 先创建 Deployment 应用
yaml
# nginx_deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-server1
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: c1
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
- 应用 YAML 并验证
bash
kubectl apply -f nginx_deployment.yml
# 查看 Pod 和 Deployment
kubectl get pod -o wide
kubectl get deployment.apps
- 创建 ClusterIP Service 并关联 Deployment
bash
kubectl expose deployment nginx-server1 --type=ClusterIP --target-port=80 --port=80
- 验证 Service 与访问
bash
# 查看 Service 详情(ClusterIP、Endpoints)
kubectl get svc
kubectl describe service nginx-server1
# 集群内访问(curl ClusterIP)
curl http://10.100.88.200 # 替换为实际 ClusterIP
3.1.2 普通 ClusterIP Service(YAML 创建)
yaml
# nginx_service.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-server1
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: c2
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
type: ClusterIP
ports:
- protocol: TCP
port: 80 # Service 访问端口
targetPort: 80 # Pod 容器端口
selector:
app: nginx # 关联 Label 为 app=nginx 的 Pod
应用并验证:
bash
kubectl apply -f nginx_service.yml
kubectl get svc,pod
curl http://10.109.23.95 # 替换为实际 ClusterIP
3.1.3 Headless Service(无头服务)
- 特点:不分配 ClusterIP,不提供负载均衡,通过 DNS 直接解析为后端 Pod IP 列表
- 适用场景:需要直接访问单个 Pod(如 StatefulSet 应用)
创建 YAML:
yaml
# headless-service.yml
apiVersion: v1
kind: Service
metadata:
name: headless-service
namespace: default
spec:
type: ClusterIP
clusterIP: None # 关键配置:无头服务标识
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
应用并验证 DNS 解析:
bash
kubectl apply -f headless-service.yml
# 集群内通过 DNS 解析 Pod IP(格式:<service名>.<命名空间>.svc.cluster.local)
dig -t a headless-service.default.svc.cluster.local. @10.96.0.10 # 10.96.0.10 为 kube-dns IP
# 或在 Pod 内访问
kubectl run -it centos --image=centos:7
curl http://headless-service.default.svc.cluster.local
3.2 NodePort(外部访问入口)
在每个 Node 上开放一个固定端口(30000-32767),外部可通过 NodeIP:NodePort 访问服务。
创建 YAML:
yaml
# nginx_nodeport.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-app
labels:
app: nginx-app
spec:
replicas: 2
selector:
matchLabels:
app: nginx-app
template:
metadata:
labels:
app: nginx-app
spec:
containers:
- name: c2
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-app
spec:
type: NodePort
ports:
- protocol: TCP
nodePort: 31111 # 自定义 NodePort(需在 30000-32767 范围内)
port: 8060 # Service 内部端口
targetPort: 80 # Pod 容器端口
selector:
app: nginx-app
应用并验证:
bash
kubectl apply -f nginx_nodeport.yml
kubectl get svc,pod
# 外部访问(浏览器或 curl)
http://192.168.100.128:31111 # 替换为实际 NodeIP 和 NodePort
3.3 LoadBalancer(云厂商负载均衡)
依赖云厂商(如 AWS、GCP、阿里云)提供的负载均衡服务,自动分配公网 IP,外部通过该 IP 访问服务。
3.3.1 自建集群解决方案:MetalLB
自建 K8s 集群无云厂商 LB 支持,可通过 MetalLB 实现 LoadBalancer 功能,核心提供 IP 地址分配和外部通告(ARP/NDP/BGP)。
版本 1:MetalLB v0.12(基于 ConfigMap 配置)
- 下载资源清单
bash
wget https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/namespace.yaml
wget https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/metallb.yaml
- 应用清单
bash
kubectl apply -f namespace.yaml
kubectl apply -f metallb.yaml
# 查看 MetalLB 组件(确保 Running)
kubectl get pod -n metallb-system
- 配置 IP 地址池
yaml
# metallb-conf.yaml
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: |
address-pools:
- name: default
protocol: layer2
addresses:
- 192.168.100.180-192.168.100.200 # 与集群节点同网段
运行
bash
kubectl apply -f metallb-conf.yaml
- 创建 Deployment 和 LoadBalancer Service
yaml
# nginx-metallb.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-metallb
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-metallb1
image: nginx:1.26-alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-metallb
spec:
type: LoadBalancer
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
运行
bash
kubectl apply -f nginx-metallb.yaml
# 查看 Service(EXTERNAL-IP 为 MetalLB 分配的 IP)
kubectl get svc
# 外部访问
curl http://192.168.100.180 # 替换为实际 EXTERNAL-IP
版本 2:MetalLB v0.15(基于 CRD 配置)
- 修改 kube-proxy 配置
bash
kubectl edit configmap -n kube-system kube-proxy
# 确保以下配置
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
strictARP: true
- 安装 MetalLB
bash
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.2/config/manifests/metallb-native.yaml
- 配置 IP 地址池(IPAddressPool CRD)
yaml
# ipaddresspool.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 192.168.18.200-192.168.18.209 # IP 池范围
运行
bash
kubectl apply -f ipaddresspool.yaml
kubectl get ipaddresspool -n metallb-system
- 创建 Service 并验证(同 v0.12 步骤 4)
3.4 ExternalName(引入外部服务)
将集群外部服务(如公网 API、数据库)通过域名引入集群内部,实现 Pod 与外部服务通信。
创建 YAML:
yaml
# externelname.yml
apiVersion: v1
kind: Service
metadata:
name: my-externalname
namespace: default
spec:
type: ExternalName
externalName: www.baidu.com # 外部服务域名
应用并验证:
bash
kubectl apply -f externelname.yml
# 集群内解析验证
dig -t A my-externalname.default.svc.cluster.local. @10.96.0.10
# Pod 内访问外部服务
kubectl run -it expod --image=busybox:1.28
nslookup my-externalname.default.svc.cluster.local.
四、特殊场景配置
4.1 跨命名空间访问
通过 ExternalName 类型 Service 实现不同命名空间的服务互通。
场景:ns1 与 ns2 命名空间互访
- 创建 ns1 资源(Deployment + Headless Service + ExternalName Service)
yaml
# ns1-nginx.yaml
apiVersion: v1
kind: Namespace
metadata:
name: ns1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: ns1
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.26-alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: svc1
namespace: ns1
spec:
clusterIP: None # Headless Service
ports:
- port: 80
targetPort: 80
selector:
app: nginx
---
apiVersion: v1
kind: Service
metadata:
name: external-svc1
namespace: ns1
spec:
type: ExternalName
externalName: svc2.ns2.svc.cluster.local # 引入 ns2 的 svc2
- 创建 ns2 资源(与 ns1 对称,引入 ns1 的 svc1)
yaml
# ns2-nginx.yaml
apiVersion: v1
kind: Namespace
metadata:
name: ns2
---
# 其余 Deployment、svc2、external-svc1 配置与 ns1 一致,仅 externalName 改为 svc1.ns1.svc.cluster.local
- 应用并验证
bash
kubectl apply -f ns1-nginx.yaml
kubectl apply -f ns2-nginx.yaml
# ns1 Pod 内访问 ns2 服务
kubectl exec -it deploy-nginx-66d785bdb5-2rf6x -n ns1 -- /bin/sh
nslookup svc2.ns2.svc.cluster.local.
4.2 会话粘黏(Session Affinity)
让同一客户端 IP 始终访问同一 Pod(类似 Nginx 的 ip_hash、LVS 的 sh 算法),默认失效时间 3 小时(10800 秒)。
配置步骤:
- 创建 Deployment 和 Service
yaml
# deployment-nginx-svc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-server
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: c1
image: nginx:1.26-alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
selector:
app: nginx
- 应用并修改 Pod 首页内容(用于区分)
bash
kubectl apply -f deployment-nginx-svc.yaml
# 分别修改两个 Pod 的 index.html 为 web1 和 web2
kubectl exec -it nginx-server-5b6d5cd699-8vk6v -- sh -c "echo web1 > /usr/share/nginx/html/index.html"
kubectl exec -it nginx-server-5b6d5cd699-z8t4f -- sh -c "echo web2 > /usr/share/nginx/html/index.html"
- 启用会话粘黏
bash
# 修改 Service 的 sessionAffinity 为 ClientIP
kubectl patch svc nginx-svc -p '{"spec":{"sessionAffinity":"ClientIP"}}'
# 验证(多次 curl 同一 ClusterIP,返回相同内容)
curl http://10.102.250.195
五、总结
- Service 核心价值:解决 Pod IP 动态变化问题,提供稳定访问入口和负载均衡
- 模式选型:中大型集群优先使用 ipvs 模式,小型集群可使用 iptables 模式
- 类型选型:
- 集群内访问:ClusterIP(普通 / Headless)
- 外部简单访问:NodePort
- 生产环境外部访问:LoadBalancer + MetalLB(自建集群)
- 集群内外服务互通:ExternalName
- 进阶配置:跨命名空间访问、会话粘黏可满足特殊业务需求
Kubernetes Service :从不懂到会用(使用命令行版)
前置说明
先跟小白们同步 2 个基础认知,避免后面懵:
- Pod 是啥? 可以理解成 "临时工"------K8s 里跑应用的最小单位,但它很不稳定,比如重启后 IP 会变(就像临时工换了手机号),直接找它干活很麻烦。
- Service 是啥? 就是 "前台小姐姐"------ 不管 "临时工"(Pod)怎么换手机号(IP),前台都知道最新联系方式,你要找临时工干活,直接找前台就行,不用管后面谁换了。
一、为啥需要 Service?(大白话总结)
- 不用记 Pod 的 IP:Pod 重启 IP 就变,Service 有个固定的 "虚拟手机号"(ClusterIP),记这个就行。
- 自动找能用的 Pod:如果多个 Pod 跑同一个应用(比如 2 个 nginx),Service 会自动把请求分给它们,不用你手动选。
- 控制谁能访问:比如只让公司内部(集群内)访问,或者允许外面的人(集群外)访问。
二、Service 的 "3 种快递分拣方式"(kube-proxy 模式)
Service 能干活,靠的是一个叫kube-proxy的组件,它有 3 种 "分拣快递" 的方式(转发请求),小白不用深究原理,记 "选哪种" 就行:
| 模式名字 | 通俗理解 | 优点 | 缺点 | 推荐场景 |
|---|---|---|---|---|
| userspace | 快递先拿进前台再分(慢) | 老版本能用 | 慢,现在基本不用 | 没人用(了解下) |
| iptables | 直接在仓库分拣(中速) | 比第一种快 | 快递多了会变慢 | 小集群(几十 Pod) |
| ipvs | 专业分拣机(最快) | 快、支持多种分法 | 需要新一点的系统 | 中大型集群(推荐) |
小白结论 :不用管前两种,默认选ipvs就行,K8s 会自动配置(系统太老会自动用iptables)。
三、4 种 Service 类型:对应不同 "访问场景"
这部分是重点!小白只要搞清楚 "我要让谁访问",就能选对类型。每种类型都带 "场景例子 + 一步一步操作",命令复制粘贴就能用。
3.1 ClusterIP:只让集群内部访问(比如公司内部用)
场景:集群里的 PodA 想访问 PodB 跑的 nginx,不用记 PodB 的 IP,用 Service 的固定地址就行。
操作步骤(以 nginx 为例)
第一步:先创建 2 个 nginx "临时工"(Pod)
先写一个 "工作清单"(YAML 文件),告诉 K8s 要创建 2 个 nginx Pod:
yaml
# 文件名:nginx_deploy.yml(随便起,后缀是.yml就行)
apiVersion: apps/v1
kind: Deployment # 表示要创建"一组Pod"(比如2个nginx)
metadata:
name: nginx-group # 这组Pod的名字,随便起
spec:
replicas: 2 # 要创建2个Pod
selector:
matchLabels:
app: nginx # 给这组Pod贴个标签:"工种=nginx"
template:
metadata:
labels:
app: nginx # 每个Pod都带这个标签,方便Service找
spec:
containers:
- name: nginx-box # 每个Pod里的"容器名字",随便起
image: nginx:1.26-alpine # 用nginx的镜像(类似"软件安装包")
ports:
- containerPort: 80 # nginx默认用80端口干活
然后执行命令创建 Pod:
bash
# 执行这个命令,K8s会根据上面的清单创建Pod
kubectl apply -f nginx_deploy.yml
# 查看Pod是否创建成功(看到"Running"就是好的)
kubectl get pod
# 成功会显示类似:
# nginx-group-xxxx-xxxx 1/1 Running 0 2m
# nginx-group-xxxx-xxxx 1/1 Running 0 2m
第二步:创建 "前台"(ClusterIP Service)
执行命令创建 Service,让它自动找带 "app=nginx" 标签的 Pod:
bash
# 创建Service,类型是ClusterIP,把80端口的请求转发给Pod的80端口
kubectl expose deployment nginx-group --type=ClusterIP --port=80 --target-port=80
# 查看Service信息(重点看"CLUSTER-IP",这是前台的固定地址)
kubectl get svc
# 会显示类似:
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# nginx-group ClusterIP 10.96.123.45 <none> 80/TCP 1m
第三步:测试访问(集群内才能用)
在 K8s 集群的任意节点(比如 master 节点)执行:
bash
# 把10.96.123.45换成你上面看到的CLUSTER-IP
curl http://10.96.123.45
# 成功会显示nginx的欢迎页面(一堆HTML代码)
3.2 NodePort:让集群外也能访问(比如你本地电脑访问)
场景:你在自己的电脑上想打开 K8s 里的 nginx,ClusterIP 只能集群内用,这时候用 NodePort------ 给每个节点开个 "对外窗口"(端口),你用 "节点 IP: 窗口端口" 就能访问。
操作步骤
第一步:还是先有 nginx Pod(同 3.1 第一步,不用重复做)
如果已经有了,直接下一步;没有就执行 3.1 的第一步。
第二步:创建 NodePort 类型的 Service
bash
# 创建Service,类型是NodePort,指定窗口端口31234(必须在30000-32767之间)
kubectl expose deployment nginx-group --type=NodePort --port=80 --target-port=80 --node-port=31234
# 查看Service信息(重点看"PORT(S)"里的31234)
kubectl get svc
# 会显示类似:
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# nginx-group NodePort 10.96.123.45 <none> 80:31234/TCP 1m
第三步:本地电脑访问
- 找一个 K8s 节点的 IP(比如 master 节点的 IP 是 192.168.1.100);
- 打开本地浏览器,输入:
http://192.168.1.100:31234; - 能看到 nginx 的欢迎页面,就成功了!
3.3 LoadBalancer:公司级对外访问(用 MetalLB 实现)
场景 :如果公司用 K8s,想让用户通过一个固定的公网 IP 访问应用,NodePort 的端口太乱,这时候用 LoadBalancer------ 需要一个 "负载均衡器",自建集群用MetalLB这个工具来模拟。
操作步骤(小白版,复制粘贴就行)
第一步:安装 MetalLB(负载均衡器工具)
bash
# 1. 创建MetalLB的命名空间(类似"文件夹")
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/namespace.yaml
# 2. 安装MetalLB组件
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/metallb.yaml
# 3. 查看是否安装成功(看到"Running"就好)
kubectl get pod -n metallb-system
第二步:给 MetalLB 分配 IP(让它有地址可分配)
写一个配置文件,告诉 MetalLB 能用哪些 IP:
yaml
# 文件名:metallb_ip.yml
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system # 必须跟MetalLB在同一个"文件夹"
name: config
data:
config: |
address-pools:
- name: default
protocol: layer2
addresses:
- 192.168.1.200-192.168.1.210 # 把这里换成你集群能用的IP段(比如跟节点同网段)
执行命令应用配置:
bash
kubectl apply -f metallb_ip.yml
第三步:创建 LoadBalancer 类型的 Service
bash
# 创建Service,类型是LoadBalancer
kubectl expose deployment nginx-group --type=LoadBalancer --port=80 --target-port=80
# 查看Service(重点看"EXTERNAL-IP",这是MetalLB分配的固定IP)
kubectl get svc
# 会显示类似:
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# nginx-group LoadBalancer 10.96.123.45 192.168.1.200 80:31456/TCP 1m
第四步:访问测试
本地浏览器输入http://192.168.1.200(上面的 EXTERNAL-IP),就能看到 nginx 页面,而且这个 IP 是固定的,重启 Pod 也不变!
3.4 ExternalName:让集群内 Pod 访问外部服务(比如访问百度)
场景 :K8s 里的 Pod 想访问百度(www.baidu.com),可以给百度起个 "集群内的小名",比如baidu-in-cluster,Pod 直接访问这个小名就行。
操作步骤
第一步:创建 ExternalName 类型的 Service
写一个配置文件:
yaml
# 文件名:baidu_service.yml
apiVersion: v1
kind: Service
metadata:
name: baidu-in-cluster # 给百度起的小名
spec:
type: ExternalName
externalName: www.baidu.com # 实际要访问的外部地址
执行命令创建:
bash
kubectl apply -f baidu_service.yml
# 查看Service
kubectl get svc
# 会显示类似:
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# baidu-in-cluster ExternalName <none> www.baidu.com <none> 1m
第二步:测试访问(集群内 Pod 访问)
在 K8s 里创建一个临时 Pod,测试能不能通过 "小名" 访问百度:
bash
# 创建一个临时的busybox Pod,进去执行命令
kubectl run -it test-pod --image=busybox:1.28 --rm
# 进入Pod后,执行下面的命令(访问百度的小名)
nslookup baidu-in-cluster.default.svc.cluster.local
# 成功会显示百度的IP(比如180.101.49.44)
# 再试一次curl(如果提示curl不存在,不用管,nslookup成功就说明通了)
curl baidu-in-cluster.default.svc.cluster.local
四、小白常遇到的问题(避坑指南)
- 执行 kubectl 命令提示 "找不到命令":说明没装 kubectl 工具,先装 kubectl 并配置 K8s 集群连接。
- Pod 状态一直是 Pending :可能是集群资源不够(比如 CPU、内存),或者镜像拉不下来(换国内镜像,比如
nginx:1.26-alpine换成registry.cn-hangzhou.aliyuncs.com/google_containers/nginx:1.26-alpine)。 - 访问 NodePort 时打不开页面 :检查节点的防火墙(比如关闭 firewalld:
systemctl stop firewalld),或者端口没在 30000-32767 之间。
五、总结:小白怎么选 Service 类型?
| 我要做什么? | 选哪种 Service? | 简单记法 |
|---|---|---|
| 集群内 Pod 之间访问 | ClusterIP | 内部用 |
| 本地电脑访问集群内应用 | NodePort | 个人测试用 |
| 公司用户访问,要固定 IP | LoadBalancer | 公司生产用 |
| 集群内 Pod 访问外部服务(比如百度) | ExternalName | 连外部用 |