循序渐进kubenetes Service(Cluster ip、Nodeport、Loadbalancer)
文章目录
- 部署一个web服务
- Kubernetes Port Forward
- Kubernetes Services
- ClusterIP Service
- NodePort Service
- LoadBalancer Service
部署一个web服务
准备 Kubernetes 集群后,创建一个名为 web 的新 namespace,然后在该 namespace 中部署一个简单的 web 应用。
cat <<EOF | kubectl apply -n web -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: webserver
spec:
replicas: 1
selector:
matchLabels:
app: webserver
template:
metadata:
labels:
app: webserver
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: web-content
mountPath: /usr/share/nginx/html
volumes:
- name: web-content
configMap:
name: webserver-config
---
apiVersion: v1
kind: ConfigMap
metadata:
name: webserver-config
data:
index.html: |
<html>
<head><title>Hello World</title></head>
<body>
<h1>Hello, world!</h1>
</body>
</html>
EOF
通过执行 kubectl get po -n web 检查 web 服务器是否部署成功。该命令列出 web namespace 中的部署,输出结果应类似于提供的示例。
❯ kubectl get po -n web
NAME READY STATUS RESTARTS AGE
webserver-7823kj2ka-32k23 1/1 Running 0 22s
Kubernetes 完成 Web 服务的部署流程:Deployment 创建副本(Replica),再生成 Pod,最终通过 Pod 提供 ConfigMap 定义的“Hello, World”页面内容。
Kubernetes Port Forward
使用 kubectl port-forward 命令,可以快速验证已部署的 Web 服务是否正常提供内容。
❯ kubectl port-forward pod/<POD_NAME> 8080:80 -n web
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
将 <POD_NAME> 替换为实际的 Pod 名称后,您可以通过 kubectl port-forward 命令在本地访问 Web 服务器,可以使用 curl 或网页浏览器等工具进行访问。
curl 127.0.0.1:8080
<html>
<head><title>Hello World</title></head>
<body>
<h1>Hello, world!</h1>
</body>
</html>
虽然 port-forward 提供了对 Web 服务器的即时访问,但它并不是一个永久性的解决方案。当您终止该命令时,端口转发会停止,而且这种方法仅在本地环境中有效,其他人无法通过此方法访问 Web 服务器。
Kubernetes Services
在 Kubernetes 中,Service 用于提供稳定的网络连接,定义如何访问一组逻辑上的 Pod。它通过分配一致的 IP 地址和可选的 DNS 名称,确保即使 Pod 更新或扩展后仍然可以被访问。
- 检查服务:运行 kubectl get svc 查看当前服务列表。
- 多种服务类型:Kubernetes 提供不同类型的服务以满足多样化需求,后续将详细说明每种类型的用途及适用场景。
ClusterIP Service
ClusterIP 类型的 Service 允许内部网络与 Pod 之间的通信。如果您想设置一个能让外部访问您的应用的服务,这并不是合适的选择。
执行 YAML 配置文件以创建一个 ClusterIP 类型的服务。
cat <<EOF | kubectl apply -n web -f -
apiVersion: v1
kind: Service
metadata:
name: webserver-service
namespace: web
spec:
type: ClusterIP
selector:
app: webserver
ports:
- port: 80
targetPort: 80
EOF
设置完成后,我们验证 ClusterIP 类型服务是否正常,方法是在集群内启动一个临时容器,并使用它来尝试连接 Web 服务器。
kubectl run curlpod --image=radial/busyboxplus:curl -i --tty --rm --namespace web
驗證內部對我們 Web 服務器的訪問
[ root@curlpod:/ ]$ wget -O- http://webserver-service:80
Connecting to webserver-service:80 (10.97.170.117:80)
<html>
<head><title>Hello World</title></head>
<body>
<h1>Hello, world!</h1>
</body>
</html>
- 100% |*******************************| 93 0:00:00 ETA
测试成功,但要记住 ClusterIP 的局限性:它仅提供内部网络的访问。使用这种设置,无法实现对服务的外部访问。
NodePort Service
NodePort 服务为集群和 Web 应用程序提供了一个外部访问的网关。它通过在 Kubernetes 集群的节点级别上暴露一个特定端口来运行。到达该节点端口的流量会被转发到相应的服务,而服务会进一步将流量路由到你的 Web 应用程序。
以下是一张图表,展示了 NodePort 服务在 Kubernetes 集群中的工作原理。
首先,使用以下命令删除现有的服务:
kubectl delete svc webserver-service -n web
接下来,将创建一个 NodePort 类型的服务。将以下内容复制粘贴到终端中执行。
cat <<EOF | kubectl apply -n web -f -
apiVersion: v1
kind: Service
metadata:
name: webserver-nodeport
namespace: web
spec:
type: NodePort
selector:
app: webserver
ports:
- port: 80
targetPort: 80
nodePort: 30007
EOF
通过运行命令,可以验证 NodePort 服务的正确配置,特别是检查分配的节点端口是否符合预期。
kubectl get service webserver-nodeport -n web -o=jsonpath='{.spec.ports[0].nodePort}'
要测试对我们 Web 服务器的外部访问,我们需要获取节点的 IP 地址。可以使用以下命令获取:
kubectl get nodes -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
webserver-nodeport NodePort 10.99.77.25 172.19.6.5 80:30007/TCP 56m
external ip返回為空,Kubernetes 集群是纯内部网络环境,未设置外部访问,也就是默认未启用externalIPs,现在给它patch上
kubectl patch svc webserver-nodeport -n web -p '{"spec":{"externalIPs":["172.19.6.5"]}}'
service/webserver-nodeport patched
kubectl get svc -n web
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
webserver-nodeport NodePort 10.99.77.25 172.19.6.5 80:30007/TCP 58m
结合节点 IP 和 NodePort,验证 NodePort 服务的外部访问是否正常。
curl http://172.19.6.5:30007
<html>
<head><title>Hello World</title></head>
<body>
<h1>Hello, world!</h1>
</body>
</html>
kubeuser@k8smaster:~/yaml$ curl http://172.19.6.5:30007
<html>
<head><title>Hello World</title></head>
<body>
<h1>Hello, world!</h1>
</body>
</html>
看到“Hello, World”。代表连接成功,如果无法连接,请检查网络的防火墙规则,确保端口 30007 的入站流量被允许。
注意:
由于我的环境使用的是cilium cni插件,默认enable-node-port: “false”,需要使用如下命令设置enable-node-port: “true”
kubectl edit configmap cilium-config -n kube-system
NodePort 提供了快速的外部访问,但通常不会在生产环境中使用,因为它暴露的范围较广且缺乏负载均衡功能。它会在所有集群节点上暴露相同的端口,这可能导致流量集中于某个节点,从而造成潜在的瓶颈。因此,NodePort 更适合用于开发和测试场景,优先解决快速便捷的外部访问需求。
LoadBalancer Service
ClusterIP 仅支持内部通信的局限性,以及 NodePort 在生产环境中存在缺点缺点(如缺乏流量均衡)
而LoadBalancer 服务利用云提供商的负载均衡器为 Kubernetes 提供高效的外部流量管理。它结合了云基础设施的能力,适合需要稳定、高效流量分发的生产环境,弥补了 ClusterIP 和 NodePort 的不足之处。
LoadBalancer 服务 通过分配公网 IP 或 DNS 名称,简化了从外部访问服务的过程。它将流量路由到服务的端口,并最终分发到目标 Pod,是生产环境中常用的解决方案。配置步骤包括先移除 NodePort 服务,然后定义新的 LoadBalancer 服务配置文件并应用。
kubectl delete svc webserver-nodeport --namespace=web
创建loadbalancer
kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
name: webserver-loadbalancer
namespace: web
spec:
type: LoadBalancer
selector:
app: webserver
ports:
- protocol: TCP
port: 80
targetPort: 80
EOF
创建 LoadBalancer 服务时,Kubernetes 会与云提供商交互,自动配置外部负载均衡器。在负载均衡器完成部署之前,您可能会看到 EXTERNAL-IP 的状态为“pending”,需等待一段时间以完成整个流程。
kubectl get svc -n web
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
webserver-loadbalancer LoadBalancer 10.99.54.59 <pending> 80:32391/TCP 7s
当负载均衡器启动后,其 IP 地址(在 kubectl get svc 输出中的 EXTERNAL-IP 列下显示)将允许您从外部访问您的 Web 服务器。尝试使用以下命令进行访问:
curl http://32.151.191.41:80
<html>
<head><title>Hello World</title></head>
<body>
<h1>Hello, world!</h1>
</body>
</html>
删除 LoadBalancer 服务会连同云提供商创建的负载均衡器一并移除。尽管 LoadBalancer 提供了外部访问能力,但生产环境中更推荐使用 Ingress,因其更灵活且适合复杂流量管理需求。
删除loadbalancer
kubectl delete svc webserver-loadbalancer -n web
#总结
Kubernetes 服务的三种常用类型:ClusterIP、NodePort 和 LoadBalancer。ClusterIP 用于内部通信,NodePort 提供外部访问但有局限性,而 LoadBalancer 则与云服务结合,提供更高效的流量管理。每种类型都有其特定的使用场景和限制,理解这些有助于为更复杂的网络解