Kubernetes与容器一起工作,以pod的形式管理。我们可以使用pod对象创建单个pod,也可以使用replicaset或deployment对象创建多个pod。无论哪种方式,最终我们都会得到一组pod,并且在某个时刻我们需要访问这些pod。
-
在集群网络中,容器可以通过使用本地主机通信来与同一个pod中的其他容器进行通信。容器的行为就好像它们在同一个主机上一样,这没有任何问题!
-
当涉及到pod之间的通信时,IP地址似乎是解决方案。因为每个pod都有一个唯一的集群范围的IP地址。然而,这种通信方式存在一个问题。当pod失败或我们缩减副本时,pod会被终止。当然,被终止的pod会被新的pod取代,但新的pod会有一个新的IP地址。那么我们如何跟踪所有这些新的IP地址呢?
-
Kubernetes的Service对象提供了解决这个问题的方法。当我们创建一个Service对象时,它会有一个虚拟的IP地址,只要Service还存在,该IP地址就保持不变。
-
通过使用选择器,我们可以将pod与Service关联起来,所有的pod可以通过该Service相互通信,无需处理pod的IP地址变更。因此,终止一个pod并用新的IP地址重新创建一个pod都不会影响通信。简而言之,
Service
为在集群中统一工作的Pod提供网络连接性。
Kubernetes的Service对象还提供了一种负载均衡机制,kube-proxy将连接负载均衡到支持该Service的一组pod上。
ClusterIP
-
ClusterIP是Kubernetes中的默认服务类型。当创建一个服务时,如果省略了服务类型,它将默认为ClusterIP。
-
官方文档将ClusterIP定义为"在集群内部IP上公开服务。选择此值使服务仅能从集群内部访问。"
-
如果您不需要从集群外部访问您的pod,您可以使用这种类型的服务。ClusterIP将为每个Service分配一个唯一的虚拟IP地址,只能从集群内部访问。这意味着Service只能通过集群内部的其他pod来访问,无法从集群外部进行访问。这种类型的服务通常用于内部服务或其他Service的后端。
-
要创建一个ClusterIP服务,您可以创建一个YAML文件,指定Service的名称、选择器和端口映射。然后使用kubectl命令将该YAML文件应用到Kubernetes集群中。这样就会创建一个ClusterIP服务,并分配一个唯一的虚拟IP地址。
xml
➜ day1 kubectl create -f demo_cluster_ip.yaml
replicaset.apps/my-kubia-rs-1 created
service/kubia-service created
➜ day1 kubectl get svc,rs,pod -o wide -L app
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR APP
service/bar-service ClusterIP 10.96.10.193 <none> 8080/TCP 9d app=bar
service/foo-service ClusterIP 10.96.113.198 <none> 8080/TCP 9d app=foo
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9d <none>
service/kubia-service ClusterIP 10.96.251.111 <none> 9696/TCP 111s app=kubia
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR APP
replicaset.apps/my-kubia-rs-1 3 3 3 111s my-kubia-1 luksa/kubia app=kubia
replicaset.apps/nginx-deployment-74b6b979f 3 3 3 5d22h nginx nginx:1.16.1 app=nginx,pod-template-hash=74b6b979f nginx
replicaset.apps/nginx-deployment-cbdccf466 0 0 0 5d23h nginx nginx:1.14.2 app=nginx,pod-template-hash=cbdccf466 nginx
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES APP
pod/bar-app 1/1 Running 0 9d 10.244.3.14 my-k8s-cluster-3-worker <none> <none> bar
pod/foo-app 1/1 Running 0 9d 10.244.2.13 my-k8s-cluster-3-worker2 <none> <none> foo
pod/my-bootcamp-pod-2-annotation 1/1 Running 0 8d 10.244.1.14 my-k8s-cluster-3-worker3 <none> <none>
pod/my-bootcamp-pod-2-label 1/1 Running 0 8d 10.244.3.26 my-k8s-cluster-3-worker <none> <none>
pod/my-kubia-rs-1-glvqr 1/1 Running 0 111s 10.244.3.29 my-k8s-cluster-3-worker <none> <none> kubia
pod/my-kubia-rs-1-k5cws 1/1 Running 0 111s 10.244.1.17 my-k8s-cluster-3-worker3 <none> <none> kubia
pod/my-kubia-rs-1-rhk76 1/1 Running 0 111s 10.244.2.17 my-k8s-cluster-3-worker2 <none> <none> kubia
pod/nginx-deployment-74b6b979f-dcq8f 1/1 Running 0 5d22h 10.244.1.16 my-k8s-cluster-3-worker3 <none> <none> nginx
pod/nginx-deployment-74b6b979f-lb2tl 1/1 Running 0 5d22h 10.244.3.28 my-k8s-cluster-3-worker <none> <none> nginx
pod/nginx-deployment-74b6b979f-vm9ww 1/1 Running 0 5d22h 10.244.2.16 my-k8s-cluster-3-worker2 <none> <none> nginx
现在我们尝试通过服务的IP、Port进行访问,效果如下所示。不难看出服务同时具有负载均衡的功能了
python
day1 kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
bar-service ClusterIP 10.96.10.193 <none> 8080/TCP 9d
foo-service ClusterIP 10.96.113.198 <none> 8080/TCP 9d
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9d
kubia-service ClusterIP 10.96.251.111 <none> 9696/TCP 4m39s
➜ day1 kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
bar-service ClusterIP 10.96.10.193 <none> 8080/TCP 9d app=bar
foo-service ClusterIP 10.96.113.198 <none> 8080/TCP 9d app=foo
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9d <none>
kubia-service ClusterIP 10.96.251.111 <none> 9696/TCP 4m46s app=kubia
➜ day1 kubectl get pod
NAME READY STATUS RESTARTS AGE
bar-app 1/1 Running 0 9d
foo-app 1/1 Running 0 9d
my-bootcamp-pod-2-annotation 1/1 Running 0 8d
my-bootcamp-pod-2-label 1/1 Running 0 8d
my-kubia-rs-1-glvqr 1/1 Running 0 5m16s
my-kubia-rs-1-k5cws 1/1 Running 0 5m16s
my-kubia-rs-1-rhk76 1/1 Running 0 5m16s
nginx-deployment-74b6b979f-dcq8f 1/1 Running 0 5d23h
nginx-deployment-74b6b979f-lb2tl 1/1 Running 0 5d23h
nginx-deployment-74b6b979f-vm9ww 1/1 Running 0 5d23h
➜ day1 kubectl exec my-bootcamp-pod-2-label -- curl -s 10.96.251.111:9696
You've hit my-kubia-rs-1-glvqr
➜ day1 kubectl exec my-bootcamp-pod-2-label -- curl -s 10.96.251.111:9696
You've hit my-kubia-rs-1-rhk76
➜ day1 kubectl exec my-bootcamp-pod-2-label -- curl -s 10.96.251.111:9696
You've hit my-kubia-rs-1-k5cws
➜ day1 kubectl exec my-bootcamp-pod-2-label -- curl -s 10.96.251.111:9696
You've hit my-kubia-rs-1-k5cws
➜ day1 kubectl exec my-bootcamp-pod-2-label -- curl -s 10.96.251.111:9696
You've hit my-kubia-rs-1-rhk76
➜ day1 kubectl exec my-bootcamp-pod-2-label -- curl -s 10.96.251.111:9696
You've hit my-kubia-rs-1-rhk76
➜ day1
此外,还可以通过sessionAffinity配置服务的会话亲和性。当配置为ClientIP时,其可以保证将来自相同客户端IP的请求总是转发至同一个Pod中
yaml
apiVersion: v1
kind: Service
spec:
# 基于客户端IP的会话亲和性
sessionAffinity: ClientIP
需要注意的是,当Service暴露多个端口时,需要给每个端口指定名字。如下所示
yaml
apiVersion: v1
kind: Service
spec:
ports:
- name: http-port #名为http-port的端口转发
port: 80 # 服务监听端口
targetPort: 3080 # 服务将请求转发到的目标端口
- name: https-port #名为https-port的端口转发
port: 443 # 服务监听端口
targetPort: 3443 # 服务将请求转发到的目标端口
- name: test-port #名为test-port的端口转发
port: 69 # 服务监听端口
targetPort: 3069 # 服务将请求转发到的目标端口
NodePort
NodePort是一种服务类型,解决了ClusterIP无法从集群外部访问Pod的问题。
-
使用NodePort,您可以定义要公开的特定端口号,用户可以通过该端口号访问连接到NodePort类型服务的Pod中的应用程序。默认情况下,NodePort使用30000到32767之间的端口范围。您可以指定特定的端口号,也可以让服务从该范围内分配一个随机的端口号。这样,用户就可以通过集群节点上的该端口号与应用程序进行通信。
-
它允许外部流量通过节点的IP地址和指定的端口访问服务。与ClusterIP不同,NodePort类型的服务可以从集群外部访问。
-
要创建一个NodePort服务,您需要创建一个YAML文件,指定Service的名称、选择器、端口映射和NodePort。然后使用kubectl命令将该YAML文件应用到Kubernetes集群中。这样就会创建一个NodePort服务,并将指定的端口映射到每个节点的IP地址上。
-
NodePort类型的服务通常用于暴露集群内的服务到集群外部,但请注意,NodePort不提供负载均衡功能。如果您需要负载均衡,可以考虑使用LoadBalancer类型的服务或结合使用NodePort和外部负载均衡器来实现。
yaml
# API组、版本
apiVersion: apps/v1
# 资源类型
kind: ReplicaSet
metadata:
# RS名称
name: my-kubia-rs-1
spec:
# 副本数量
replicas: 3
# 标签选择器
selector:
matchLabels:
app: kubia
# Pod 模板
template:
metadata:
# 标签信息
labels:
app: kubia
spec:
# 容器信息
containers:
- name: my-kubia-1
image: luksa/kubia
# 仅用于展示容器所使用的端口
ports:
- containerPort: 8080
protocol: TCP
---
# API组、版本
apiVersion: v1
# 资源类型
kind: Service
metadata:
# 资源名称
name: my-nodeport-service-1
spec:
# Service类型
type: NodePort
selector:
app: kubia
ports:
- port: 80 # 服务监听端口
targetPort: 8080 # 服务将请求转发到Pod的目标端口
# 在集群各节点所打开的端口, 使得可以通过集群中任一节点IP、nodePort端口号访问该服务
nodePort: 30123
创建成功后如图所示
scss
➜ day1 kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
bar-app 1/1 Running 0 9d 10.244.3.14 my-k8s-cluster-3-worker <none> <none>
foo-app 1/1 Running 0 9d 10.244.2.13 my-k8s-cluster-3-worker2 <none> <none>
my-bootcamp-pod-2-annotation 1/1 Running 0 8d 10.244.1.14 my-k8s-cluster-3-worker3 <none> <none>
my-bootcamp-pod-2-label 1/1 Running 0 8d 10.244.3.26 my-k8s-cluster-3-worker <none> <none>
my-kubia-rs-1-glvqr 1/1 Running 0 16m 10.244.3.29 my-k8s-cluster-3-worker <none> <none>
my-kubia-rs-1-k5cws 1/1 Running 0 16m 10.244.1.17 my-k8s-cluster-3-worker3 <none> <none>
my-kubia-rs-1-rhk76 1/1 Running 0 16m 10.244.2.17 my-k8s-cluster-3-worker2 <none> <none>
nginx-deployment-74b6b979f-dcq8f 1/1 Running 0 5d23h 10.244.1.16 my-k8s-cluster-3-worker3 <none> <none>
nginx-deployment-74b6b979f-lb2tl 1/1 Running 0 5d23h 10.244.3.28 my-k8s-cluster-3-worker <none> <none>
nginx-deployment-74b6b979f-vm9ww 1/1 Running 0 5d23h 10.244.2.16 my-k8s-cluster-3-worker2 <none> <none>
➜ day1 kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
bar-service ClusterIP 10.96.10.193 <none> 8080/TCP 9d app=bar
foo-service ClusterIP 10.96.113.198 <none> 8080/TCP 9d app=foo
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9d <none>
kubia-service ClusterIP 10.96.251.111 <none> 9696/TCP 16m app=kubia
my-nodeport-service-1 NodePort 10.96.59.99 <none> 80:30123/TCP 2m9s app=kubia
➜ day1 kubectl exec my-bootcamp-pod-2-label -- curl -s 10.96.59.99:80
You've hit my-kubia-rs-1-rhk76
➜ day1 kubectl exec my-bootcamp-pod-2-label -- curl -s 10.96.59.99:80
You've hit my-kubia-rs-1-glvqr
➜ day1 kubectl exec my-bootcamp-pod-2-label -- curl -s 10.96.59.99:80
You've hit my-kubia-rs-1-glvqr
➜ day1 kubectl exec my-bootcamp-pod-2-label -- curl -s 10.96.59.99:80
You've hit my-kubia-rs-1-rhk76
➜ day1 kubectl exec my-bootcamp-pod-2-label -- curl -s 10.96.59.99:80
You've hit my-kubia-rs-1-rhk76
现在我们尝试通过集群节点IP、NodePort Service在节点上打开的端口来访问服务。
结论
总之,ClusterIP和NodePort是Kubernetes中常用的两种服务类型。ClusterIP仅在集群内部可访问,并为每个Service分配唯一的虚拟IP地址。NodePort允许从集群外部访问服务,通过节点的IP地址和指定的端口。