| 备注 | 修改日期 | 修改人 |
| 内容更新 | 2026-01-21 20:47:21[当前版本] | 文艺范儿 |
| 内容更新 | 2026-01-21 20:46:57 | 文艺范儿 |
| 创建版本 | 2026-01-03 22:54:01 | 文艺范儿 |
Service 是 Kubernetes 中暴露 Pod 稳定访问入口的资源对象,核心作用:
my-svc.default.svc.cluster.local)或 ClusterIP 访问后端 Pod,避免直接使用易变的 Pod IP。核心类型(本文聚焦):
| 类型 | 作用 | 访问范围 | 典型场景 |
|---|---|---|---|
ClusterIP |
分配集群内虚拟 IP |
仅集群内 Pod/节点可访问 |
内部服务通信(如前端 → 后端 API) |
NodePort |
在每个节点开放静态端口(30000-32767) |
集群外可通过 |
测试环境外部访问、无 Ingress 时的临时暴露 |
LoadBalancer |
将集群内的 Service 暴露到集群外部(公网或内网) |
集群外可见:外部客户端(浏览器、手机、其他系统)可通过负载均衡器的 IP 或 DNS 访问集群内的服务。 |
对外提供 Web 服务<br />暴露 Ingress Controller<br />内网高可用访问<br />云环境中使用 |
ExternalName |
为集群内的应用提供一种 稳定、可声明的方式来访问集群外的服务 |
集群内可见:Service 名称和 DNS 记录只在 Kubernetes 集群内部有效 |
访问云托管数据库<br />跨集群服务访问 |
场景:创建一个 Deployment 运行 3 个 Nginx Pod(标签 app=nginx-svc),再通过 ClusterIP 类型的 Service 暴露这些 Pod,实现:
# 1. 前置准备:创建 Deployment(Pod 后端)
[root@k8s-master-01 ~]# vim nginx-deploy-for-svc.yaml
[root@k8s-master-01 ~]# cat .
cat: .: Is a directory
[root@k8s-master-01 ~]# cat nginx-deploy-for-svc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy-for-svc
namespace: default
spec:
replicas: 3 # 3 个 Pod 副本
selector:
matchLabels:
app: nginx-svc # 标签选择器,匹配 Pod
template:
metadata:
labels:
app: nginx-svc # Pod 标签(需与 Service selector 一致)
spec:
containers:
- name: nginx
image: harbor.wyasw.com/library/nginx:1.21
ports:
- containerPort: 80 # 容器内暴露的端口(Service targetPort 需匹配)
# 部署 Deployment
[root@k8s-master-01 ~]# kubectl apply -f nginx-deploy-for-svc.yaml
[root@k8s-master-01 ~]# kubectl get pods -l app=nginx-svc # 确认 3 个 Pod 均为 Running
# 2. 创建 ClusterIP 类型 Service
[root@k8s-master-01 ~]# vim nginx-svc-clusterip.yaml
[root@k8s-master-01 ~]# cat nginx-svc-clusterip.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-svc-clusterip # Service 名称(DNS 域名的一部分)
namespace: default
labels:
app: nginx-svc
spec:
type: ClusterIP # 类型:集群内虚拟 IP
selector:
app: nginx-svc # 标签选择器:匹配带有 app=nginx-svc 的 Pod(与 Deployment 的 Pod 标签一致)
ports:
- name: http # 端口名称(可选,多端口时必须指定)
port: 80 # Service 暴露的端口(集群内访问时使用,如 ClusterIP:80)
targetPort: 80 # 后端 Pod 的容器端口(需与 Pod 内 containerPort 一致)
protocol: TCP # 协议(TCP/UDP/SCTP,默认 TCP)
# 创建Service
[root@k8s-master-01 ~]# kubectl apply -f nginx-svc-clusterip.yaml
# 3.验证service基本状态
# 查看 Service 详情(确认 ClusterIP、PORT(S))
[root@k8s-master-01 ~]# kubectl get svc nginx-svc-clusterip -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
nginx-svc-clusterip ClusterIP 10.200.90.196 <none> 80/TCP 71s app=nginx-svc
# 查看 Endpoints(Service 后端 Pod 的 IP:Port 列表,自动同步 Pod 变化)
[root@k8s-master-01 ~]# kubectl get endpoints nginx-svc-clusterip
NAME ENDPOINTS AGE
nginx-svc-clusterip 10.100.1.27:80,10.100.2.37:80,10.100.2.38:80 90s
# 4. 创建测试数据
[root@k8s-master-01 ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deploy-for-svc-855cd8d787-9zktp 1/1 Running 0 11m 10.100.2.38 k8s-worker-02 <none> <none>
nginx-deploy-for-svc-855cd8d787-p94l4 1/1 Running 0 11m 10.100.1.27 k8s-worker-01 <none> <none>
nginx-deploy-for-svc-855cd8d787-s49dv 1/1 Running 0 11m 10.100.2.37 k8s-worker-02 <none> <none>
test-pod 1/1 Running 0 2m13s 10.100.2.39 k8s-worker-02 <none> <none>
[root@k8s-master-01 ~]#
[root@k8s-master-01 ~]# kubectl exec -it nginx-deploy-for-svc-855cd8d787-9zktp -- sh
# echo 1111111111111 > /usr/share/nginx/html/index.html
# exit
[root@k8s-master-01 ~]# kubectl exec -it nginx-deploy-for-svc-855cd8d787-p94l4 -- sh
# echo 22222222222 > /usr/share/nginx/html/index.html
# exit
[root@k8s-master-01 ~]# kubectl exec -it nginx-deploy-for-svc-855cd8d787-s49dv -- sh
# echo 33333333333 > /usr/share/nginx/html/index.html
# exit
# 5. 验证服务发现与负载均衡(集群内访问)
# Kubernetes 内置 DNS 服务(CoreDNS)会自动为 Service 创建 DNS 记录:
# 格式:<service-name>.<namespace>.svc.cluster.local(集群内全局唯一)
# 同一命名空间可简化为 <service-name>
# 创建临时测试 Pod 并访问 Service:
# 创建 busybox 测试 Pod
[root@k8s-master-01 ~]# kubectl run test-pod --image=harbor.wyasw.com/library/busybox:1.36 --rm -it -- sh
# # 在 Pod 内访问 Service(通过名称或 ClusterIP)
[root@k8s-master-01 ~]# kubectl run test-pod --image=harbor.wyasw.com/library/busybox:1.36 --rm -it -- sh
...
/ # wget -qO- http://nginx-svc-clusterip:80 # 通过 Service 名称访问
1111111111111
/ # wget -qO- http://nginx-svc-clusterip:80
33333333333
/ # wget -qO- http://nginx-svc-clusterip:80
22222222222
/ # wget -qO- http://10.200.90.196:80 # 通过 ClusterIP 访问
33333333333
/ # wget -qO- http://10.200.90.196:80
22222222222
/ # wget -qO- http://10.200.90.196:80
1111111111111
/ #
场景描述:基于案例1的 Nginx Deployment,创建 NodePort 类型的 Service,允许集群外通过 节点IP:NodePort访问 Nginx(适用于测试环境或无 Ingress 控制器的场景)。
# 1. 配置yaml
[root@k8s-master-01 ~]# vim nginx-svc-nodeport.yaml
[root@k8s-master-01 ~]# cat nginx-svc-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-svc-nodeport
namespace: default
spec:
type: NodePort # 类型:NodePort(在每个节点开放静态端口)
selector:
app: nginx-svc # 复用案例1的 Pod 标签(匹配 3 个 Nginx Pod)
ports:
- name: http
port: 80 # Service 集群内端口(同 ClusterIP)
targetPort: 80 # 后端 Pod 容器端口
nodePort: 30080 # 节点开放的静态端口(可选,范围 30000-32767,不指定则随机分配)
protocol: TCP
# 创建 NodePort Service
[root@k8s-master-01 ~]# kubectl apply -f nginx-svc-nodeport.yaml
# 2. 验证 NodePort 端口分配
[root@k8s-master-01 ~]# kubectl get svc nginx-svc-nodeport -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
nginx-svc-nodeport NodePort 10.200.214.60 <none> 80:30080/TCP 36s app=nginx-svc
# 3. 集群外访问验证(通过节点 IP)
# 通过 Master 节点 IP:NodePort 访问
[root@k8s-master-01 ~]# curl http://192.168.1.231:30080
22222222222
[root@k8s-master-01 ~]# curl http://192.168.1.231:30080
1111111111111
[root@k8s-master-01 ~]# curl http://192.168.1.231:30080
33333333333
# 通过 Worker 节点 IP:NodePort 访问(效果相同,流量会被转发到后端 Pod)
[root@k8s-master-01 ~]# curl http://192.168.1.233:30080
1111111111111
[root@k8s-master-01 ~]# curl http://192.168.1.233:30080
33333333333
[root@k8s-master-01 ~]# curl http://192.168.1.233:30080
22222222222
#多次执行 curl http://节点IP:30080,会看到返回的 Pod-内容轮询变化,证明 NodePort 负载均衡生效。
场景描述:创建一个后端 Pod 同时暴露 HTTP(80)和 HTTPS(443)端口,通过 Service 的多端口配置分别映射,实现外部通过不同端口访问不同协议服务。
# 1. yaml配置
[root@k8s-master-01 ~]# vim multi-port-svc.yaml
[root@k8s-master-01 ~]# cat multi-port-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: multi-port-svc
spec:
type: NodePort
selector:
app: multi-port-app # 匹配后端 Pod 标签
ports:
- name: http # 端口名称必须唯一(多端口时必填)
port: 8080 # Service 集群内 HTTP 端口
targetPort: 80 # 后端 Pod HTTP 容器端口
nodePort: 30081 # 节点 HTTP 端口
protocol: TCP
- name: https
port: 8443 # Service 集群内 HTTPS 端口
targetPort: 443 # 后端 Pod HTTPS 容器端口
nodePort: 30443 # 节点 HTTPS 端口
protocol: TCP
---
# 后端 Pod(同时暴露 80 和 443 端口)
apiVersion: apps/v1
kind: Deployment
metadata:
name: multi-port-deploy
spec:
replicas: 2
selector:
matchLabels:
app: multi-port-app
template:
metadata:
labels:
app: multi-port-app
spec:
containers:
- name: app
image: harbor.wyasw.com/library/nginx:1.21 # 简化示例,实际需配置 HTTPS 证书
ports:
- containerPort: 80
- containerPort: 443
# 部署
[root@k8s-master-01 ~]# kubectl apply -f multi-port-svc.yaml
# 2. 部署后,通过不同 NodePort 访问不同端口:
# 访问 HTTP 服务
curl http://192.168.1.231:30081
# 访问 HTTPS 服务(忽略证书验证)
curl -k https://节点IP:30443
IPVS 依赖内核模块,需在所有 Master 和 Worker 节点执行:
临时加载(重启失效)
# 加载核心模块 modprobe ip_vs modprobe ip_vs_rr modprobe ip_vs_wrr modprobe ip_vs_sh modprobe nf_conntrack_ipv4 # ubuntu不需要 CentOS 7系统需要 # 验证模块是否加载成功 lsmod | grep ip_vs
输出应包含 ip_vs、ip_vs_rr等模块。
永久加载(开机自启)
为避免节点重启后模块丢失,需将模块加入开机加载配置:
CentOS/RHEL:
# 创建模块加载配置文件 cat > /etc/modules-load.d/ipvs.conf << EOF ip_vs ip_vs_rr ip_vs_wrr ip_vs_sh nf_conntrack_ipv4 EOF # 立即加载(无需重启) systemctl restart systemd-modules-load.service
Ubuntu/Debian:
# 编辑 /etc/modules 文件,追加模块名 echo -e "ip_vs\nip_vs_rr\nip_vs_wrr\nip_vs_sh\nip_conntrack" >> /etc/modules # 立即加载 modprobe -a ip_vs ip_vs_rr ip_vs_wrr ip_vs_sh ip_conntrack
kube-proxy 通常以 DaemonSet 部署在集群中,需先找到其配置:
kubectl get daemonset kube-proxy -n kube-system -o yaml > kube-proxy-daemonset.yaml
kube-proxy 模式通过 ConfigMap 或 命令行参数 控制,推荐通过 ConfigMap 统一管理(适合 kubeadm 部署集群)。
方法1:通过 ConfigMap 修改(kubeadm 集群推荐)
# 1. 查看现有 kube-proxy ConfigMap kubectl get configmap kube-proxy -n kube-system -o yaml > kube-proxy-configmap.yaml # 2.编辑 ConfigMap,设置 mode: "ipvs" ,strictARP 为 true sed -i "s/strictARP: false/strictARP: true/" kube-proxy-configmap.yaml sed -i 's/mode: ""/mode: "ipvs"/' kube-proxy-configmap.yaml # 3.应用 ConfigMap 更新 kubectl apply -f kube-proxy-configmap.yaml # 4. 验证 kubectl -n kube-system describe cm kube-proxy | egrep "mode|strictARP"
方法2:直接修改 kube-proxy DaemonSet 启动参数(非 kubeadm 集群)
若集群非 kubeadm 部署(如二进制部署),可直接修改 kube-proxy 的启动参数:
kubectl edit daemonset kube-proxy -n kube-system
在 spec.template.spec.containers[0].command中添加 --proxy-mode=ipvs,例如:
containers: - command: - /usr/local/bin/kube-proxy - --config=/var/lib/kube-proxy/config.conf - --proxy-mode=ipvs # 直接指定模式(优先级高于 config.conf)
修改 ConfigMap/DaemonSet 后,需重启 kube-proxy Pod 加载新配置:
# 删除现有 kube-proxy Pod(DaemonSet 会自动重建) kubectl delete pod -l k8s-app=kube-proxy -n kube-system # 等待 Pod 重建并就绪 kubectl get pods -n kube-system -l k8s-app=kube-proxy -w
查看任意 kube-proxy Pod 日志,确认模式切换为 IPVS:
[root@k8s-master-01 ~]# kubectl get pods -n kube-system -l k8s-app=kube-proxy NAME READY STATUS RESTARTS AGE kube-proxy-chkbg 1/1 Running 0 2m30s kube-proxy-fngz8 1/1 Running 0 2m30s kube-proxy-l9bnz 1/1 Running 0 2m30s [root@k8s-master-01 ~]# [root@k8s-master-01 ~]# kubectl -n kube-system logs kube-proxy-chkbg | grep -A 2 "Using ipvs Proxier" I0115 14:47:20.562563 1 server_linux.go:189] "Using ipvs Proxier" I0115 14:47:20.563439 1 proxier.go:353] "IPVS scheduler not specified, use rr by default" ipFamily="IPv4" I0115 14:47:20.563858 1 proxier.go:353] "IPVS scheduler not specified, use rr by default" ipFamily="IPv6"
在任意节点执行以下命令,查看 IPVS 虚拟服务(对应 Service):
# 安装 ipvsadm 工具(若未安装) yum install -y ipvsadm # CentOS/RHEL apt-get install -y ipvsadm # Ubuntu/Debian # 查看 IPVS 规则 ipvsadm -Ln
正常输出示例(假设存在名为 kubernetes的 Service,ClusterIP: 10.100.0.1):
IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 172.17.0.1:30094 rr -> 10.100.2.53:443 Masq 1 0 0 TCP 172.17.0.1:32583 rr -> 10.100.2.53:80 Masq 1 0 0 TCP 192.168.1.231:30094 rr -> 10.100.2.53:443 Masq 1 0 0 TCP 192.168.1.231:32583 rr -> 10.100.2.53:80 Masq 1 0 0 TCP 192.168.31.231:30094 rr -> 10.100.2.53:443 Masq 1 0 0 TCP 192.168.31.231:32583 rr -> 10.100.2.53:80 Masq 1 0 0 TCP 10.100.0.0:30094 rr -> 10.100.2.53:443 Masq 1 0 0 TCP 10.100.0.0:32583 rr -> 10.100.2.53:80 Masq 1 0 0 TCP 10.200.0.1:443 rr -> 192.168.1.231:6443 Masq 1 0 0 TCP 10.200.0.10:53 rr -> 10.100.1.30:53 Masq 1 0 0 -> 10.100.1.31:53 Masq 1 0 0
Scheduler显示配置的算法(如 rr轮询)。Forward为 Masq(伪装模式,即 SNAT),符合 kube-proxy IPVS 默认行为。创建一个测试 Service,通过 ipvsadm观察连接是否正常转发:
# 部署测试 Deployment 和 Service kubectl create deployment nginx-test --image=harbor.wyasw.com/test/nginx:v1 --replicas=2 -n default kubectl expose deployment nginx-test --port=80 --target-port=80 -n default # 查看 Service ClusterIP kubectl get svc nginx-test -n default # 假设 ClusterIP: 10.200.164.81 # 在节点访问 Service,触发连接 curl http://10.200.164.81 # 再次查看 IPVS 规则,ActiveConn/InActConn 会增加 ipvsadm -Ln | grep 10.200.164.81 # 删除测试环境 kubectl delete deployment nginx-test -n default
MetalLB 是 Kubernetes 的 开源负载均衡器实现,专为 Bare-Metal(裸金属)、虚拟机、私有云 等非云环境设计。
type: LoadBalancer的 Service 时,MetalLB 会自动为该 Service 分配一个 外部可访问的 IP 地址(从预先配置的 IP 池中),并配置相应的网络路由,使外部流量能够到达集群内的 Pod。LoadBalancer类型依赖云厂商的 cloud-controller-manager自动创建云负载均衡器(如 AWS ELB、阿里云 SLB)。在没有云厂商的环境中,这类 Service 会一直处于 <pending>状态,无法获取外部 IP。MetalLB 解决了这一痛点。# 1. 安装 MetalLB # 使用官方 manifest 安装(包含 CRD、Controller、Speaker) # 先在三个节点拉取镜像 docker pull quay.io/metallb/controller:v0.14.8 docker pull quay.io/metallb/speaker:v0.14.8 # 主节点部署 wget https://raw.githubusercontent.com/metallb/metallb/v0.14.8/config/manifests/metallb-native.yaml kubectl apply -f metallb-native.yaml # 2. 验证安装 kubectl get pods -n metallb-system # 预期输出: # NAME READY STATUS RESTARTS AGE # controller-55b679bf65-abcde 1/1 Running 0 2m # speaker-xyz12 1/1 Running 0 2m # speaker-xyz34 1/1 Running 0 2m # speaker-jw2sh 1/1 Running 0 2m # 3. 配置 IP 地址池(AddressPool CRD)和 L2Advertisement(Layer 2 模式) # 创建 IPAddressPool定义可用的外部 IP 范围: vim metallb-ippool-l2adv.yaml cat metallb-ippool-l2adv.yaml apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: prod-public-ips namespace: metallb-system spec: addresses: - 192.168.1.210-192.168.1.220 # 按需修改为你的 IP 段 --- apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: l2-adv namespace: metallb-system spec: ipAddressPools: - prod-public-ips # 部署 kubectl apply -f metallb-ippool-l2adv.yaml
# 1.创建测试service
vim nginx-lb-test.yaml
cat nginx-lb-test.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-metallb-test
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-test
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: harbor.wyasw.com/test/nginx:v1
ports:
- containerPort: 80
# 2. 部署
kubectl apply -f nginx-lb-test.yaml
# 3.验证外部IP
kubectl get svc nginx-metallb-test
# 输出
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# nginx-metallb-test LoadBalancer 10.200.197.241 192.168.1.211 80:30444/TCP 6s
# 基于metallb提供的地址池访问
curl http://192.168.1.211
# 基于NodePort访问
curl http://192.168.1.231:30444
MetalLB 是 Bare-Metal Kubernetes 集群实现 LoadBalancer 服务的关键组件,通过 Layer 2(ARP/NDP) 或 BGP 模式将外部流量引入集群,弥补了非云环境缺失云厂商负载均衡器的短板。
# 1. metallb自定义EXTERNAL-IP及NodePort端口
vim nginx-LoadBalancerIP-test.yaml
cat nginx-LoadBalancerIP-test.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-v2-metallb-test
spec:
type: LoadBalancer
loadBalancerIP: 192.168.1.212
selector:
app: nginx-v2
ports:
- port: 80
targetPort: 80
nodePort: 30090
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-test-v2
spec:
replicas: 2
selector:
matchLabels:
app: nginx-v2
template:
metadata:
labels:
app: nginx-v2
spec:
containers:
- name: nginx
image: harbor.wyasw.com/test/nginx:v2
ports:
- containerPort: 80
# 3.验证外部IP
kubectl get svc nginx-v2-metallb-test
# 输出
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# nginx-metallb-test LoadBalancer 10.200.150.177 192.168.1.212 80:30090/TCP 6s
# 基于metallb提供的地址池访问
curl http://192.168.1.212
# 基于NodePort访问
curl http://192.168.1.231:30090
作用:ExternalNameService 不代理或转发任何网络流量。它仅仅是在 Kubernetes 集群的 DNS 系统中,为集群内部的应用创建一个 别名(CNAME 记录),将这个别名指向一个外部的、完全限定域名(FQDN)。
工作原理:当集群内的应用尝试通过 ExternalNameService 的名称访问时,CoreDNS 会将其解析为 externalName字段中指定的外部地址。之后的所有网络通信都直接从应用 Pod 发往那个外部地址,完全绕过 Kubernetes 的网络组件(如 kube-proxy)。
我们定义一个 Service,它不包含任何选择器(selector),因为它不指向任何集群内的 Pod。它的全部意义在于 spec.externalName字段。
创建一个名为 external-postgres-service.yaml的文件:
apiVersion: v1
kind: Service
metadata:
name: external-postgres
namespace: default # 建议与你的应用在同一个 Namespace
labels:
app: external-services # 用于管理和识别
spec:
type: ExternalName
externalName: pgm-xxxxxxxxx.pg.rds.aliyuncs.com # 【重要】替换为你的真实 RDS 地址
ports:
- port: 5432 # Service 端口,主要起文档化作用
protocol: TCP
targetPort: 5432 # 外部服务的端口,主要起文档化作用
应用这个配置:
kubectl apply -f external-postgres-service.yaml
现在,我们可以创建一个临时的调试 Pod 来验证 Kubernetes DNS 是否正确地将我们的 Service 名称解析为了外部的 RDS 地址。
kubectl run -it --rm --image=busybox:1.36 dns-checker --restart=Never -- sh
在 busybox 容器内部,使用 nslookup或 ping进行测试:
# 使用 nslookup 查询 Service 的完整 DNS 名称 nslookup external-postgres.default.svc.cluster.local
预期的命令输出:
Name: external-postgres.default.svc.cluster.local Address: pgm-xxxxxxxxx.pg.rds.aliyuncs.com
请注意,返回的地址正是我们在 externalName中定义的 RDS 地址。这说明 DNS 别名已经成功创建。
你也可以用 ping来验证(尽管 PostgreSQL 不响应 ICMP 请求,但 DNS 解析会发生):
ping external-postgres
输出会类似于:
PING external-postgres.default.svc.cluster.local (pgm-xxxxxxxxx.pg.rds.aliyuncs.com): 56 data bytes
测试完成后,输入 exit退出并删除临时 Pod。
这是最关键的一步。现在,你的 Django 应用(或其他任何应用)不再需要关心 RDS 的具体地址。它只需要使用标准的 Kubernetes 内部 DNS 名称来连接数据库。
Django 的 settings.py配置示例:
旧的写法(硬编码外部地址,不推荐):
# settings.py - 不推荐的写法
import os
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'mydjango_db',
'USER': 'django_user',
'PASSWORD': os.environ.get('DB_PASSWORD'), # 密码仍然应该用 Secret 管理
'HOST': 'pgm-xxxxxxxxx.pg.rds.aliyuncs.com', # 硬编码!难以维护。
'PORT': '5432',
}
}
新的写法(使用 Service 名称,推荐):
# settings.py - 推荐的写法
import os
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'mydjango_db',
'USER': 'django_user',
'PASSWORD': os.environ.get('DB_PASSWORD'),
# 核心改动:使用 Kubernetes Service 名称作为 HOST
# K8s DNS 会自动将其解析为 RDS 的真实地址
'HOST': 'external-postgres',
'PORT': '5432',
}
}
注意:数据库密码等敏感信息依然应该使用 Kubernetes Secret 来存储和管理,并通过环境变量(如 DB_PASSWORD)注入到 Pod 中,这与是否使用 ExternalName无关。
external-postgres-service.yaml文件中修改 externalName字段,然后重新执行 kubectl apply -f external-postgres-service.yaml即可。所有引用该 Service 的应用程序都无需进行任何代码或配置修改,实现了配置与代码的解耦。ExternalNameService 不提供任何健康检查。Kubernetes 无法知道 pgm-xxxxxxxxx.pg.rds.aliyuncs.com这个外部服务是否真的在线。因此,应用程序本身必须具备处理数据库连接失败的能力(例如,通过重试、熔断等机制)。默认情况下,这个范围是 30000-32767。出于安全策略(例如,为了避免与服务器上已有的服务端口冲突)或特定业务需求(例如,需要使用小于 30000 的端口以便于记忆和访问),我们可能需要修改这个范围。
核心原理:修改此范围不会改变已存在的 Service 的端口,它只会影响之后新创建的 NodePort Service。已存在的 Service 会一直保持它们原有的端口。
# 1. 定位 kube-apiserver 静态 Pod 清单文件
# 在主流的 Kubernetes 发行版(如 kubeadm)中,kube-apiserver是以 静态 Pod 的形式运行的。其配置文件通常位于 /etc/kubernetes/manifests/目录下。
# 进入 manifests 目录
cd /etc/kubernetes/manifests/
# 查看目录下的文件,寻找 apiserver 的清单文件
ls -l kube-apiserver.yaml
# 2. 备份原始配置文件
cp kube-apiserver.yaml kube-apiserver.yaml.bak_$(date +%F-%T)
# 3.编辑 kube-apiserver.yaml 文件
vim kube-apiserver.yaml
# 在文件中找到 spec.containers[0].command部分,这里定义了 kube-apiserver容器的所有启动参数。你需要在这个列表中查找或添加 --service-node-port-range参数。
# 情况 A:如果参数已存在
# 如果已经存在一行类似 - --service-node-port-range=30000-32767的配置,直接修改其值即可。
# 情况 B:如果参数不存在
# 如果列表中没有这个参数,你需要在其他 --开头的参数附近添加一行新的。
# 修改示例:
# 假设我们想将端口范围修改为 10000-20000。
...
spec:
containers:
- command:
- kube-apiserver
- --service-node-port-range=10000-20000 # 进行添加这一行即可
...
# 4.应用配置并重启 kubelet
# 当你保存对 kube-apiserver.yaml文件的修改后,Kubernetes 的静态 Pod 管理机制(由 kubelet负责)会检测到文件的变化。它会自动终止当前的 kube-apiserverPod,并根据新的清单文件重新创建一个新的 Pod。
# 你可以通过以下命令观察这个过程:
# 在一个终端窗口监控 kube-apiserver pod 的重启
watch kubectl get pods -n kube-system -l component=kube-apiserver
# 在另一个终端窗口,你可以看到 kubelet 正在重新创建 Pod
# 通常几秒钟内就会完成
journalctl -u kubelet -f
# 等待片刻,直到 kube-apiserverPod 的状态再次变为 Running。
# 5. 创建测试应用