k8s通过service访问pod(五)

service

每个 Pod 都有自己的 IP 地址。当 controller 用新 Pod 替代发生故障的 Pod 时,新 Pod 会分配到新的 IP 地址。这样就产生了一个问题:文章源自靠谱运维-https://www.ixdba.net/archives/1381

如果一组 Pod 对外提供服务(比如 HTTP),它们的 IP 很有可能发生变化,那么客户端如何找到并访问这个服务呢?文章源自靠谱运维-https://www.ixdba.net/archives/1381

Kubernetes 给出的解决方案是 Service。文章源自靠谱运维-https://www.ixdba.net/archives/1381

创建 Service

Kubernetes Service 从逻辑上代表了一组 Pod,具体是哪些 Pod 则是由 label 来挑选。Service 有自己 IP,而且这个 IP 是不变的。客户端只需要访问 Service 的 IP,Kubernetes 则负责建立和维护 Service 与 Pod 的映射关系。无论后端 Pod 如何变化,对客户端不会有任何影响,因为 Service 没有变。文章源自靠谱运维-https://www.ixdba.net/archives/1381

第一步:创建下面的这个 Deployment:文章源自靠谱运维-https://www.ixdba.net/archives/1381

查看支持的apiversion使用命令kubectl api-versions文章源自靠谱运维-https://www.ixdba.net/archives/1381

k8s通过service访问pod(五)文章源自靠谱运维-https://www.ixdba.net/archives/1381

第二步:部署并查看pod文章源自靠谱运维-https://www.ixdba.net/archives/1381

我们启动了三个 Pod,运行 httpd 镜像,label 是 run: httpd,Service 将会用这个 label 来挑选 Pod。文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken ~]# kubectl apply -f httpd.yml
deployment.apps/httpd created
[root@ken ~]# kubectl get pod -o wide
NAME                    READY   STATUS    RESTARTS   AGE   IP            NODE    NOMINATED NODE   READINESS GATES
httpd-8c6c4bd9b-ljvlb   1/1     Running   0          41s   10.244.1.27   host1   <none>           <none>
httpd-8c6c4bd9b-ngxqv   1/1     Running   0          41s   10.244.1.28   host1   <none>           <none>
httpd-8c6c4bd9b-wxblj   1/1     Running   0          41s   10.244.2.18   host2   <none>           <none>

第三步:集群内部测试连通性文章源自靠谱运维-https://www.ixdba.net/archives/1381

Pod 分配了各自的 IP,这些 IP 只能被 Kubernetes Cluster 中的容器和节点访问。文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken ~]# curl 10.244.1.28
<html><body><h1>It works!</h1></body></html>
[root@ken ~]# curl 10.244.1.27
<html><body><h1>It works!</h1></body></html>
[root@ken ~]# curl 10.244.2.18
<html><body><h1>It works!</h1></body></html>

第四步:接下来创建 Service,其配置文件如下:文章源自靠谱运维-https://www.ixdba.net/archives/1381

k8s通过service访问pod(五)文章源自靠谱运维-https://www.ixdba.net/archives/1381

① v1 是 Service 的 apiVersion。文章源自靠谱运维-https://www.ixdba.net/archives/1381

② 指明当前资源的类型为 Service。文章源自靠谱运维-https://www.ixdba.net/archives/1381

③ Service 的名字为 httpd-svc。文章源自靠谱运维-https://www.ixdba.net/archives/1381

④ selector 指明挑选那些 label 为 run: httpd 的 Pod 作为 Service 的后端。文章源自靠谱运维-https://www.ixdba.net/archives/1381

⑤ 将 Service 的 8080 端口映射到 Pod 的 80 端口,使用 TCP 协议。文章源自靠谱运维-https://www.ixdba.net/archives/1381

第五步: 执行 kubectl apply 创建 Service httpd-svc。文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken ~]# kubectl apply -f service.yml
service/httpd-svc created
[root@ken ~]# kubectl get service
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
httpd-svc    ClusterIP   10.106.64.97   <none>        8080/TCP   17s
kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP    11h

httpd-svc 分配到一个 CLUSTER-IP 10.106.64.97。可以通过该 IP 访问后端的 httpd Pod。文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken ~]# curl 10.106.64.97:8080
<html><body><h1>It works!</h1></body></html>

根据前面的端口映射,这里要使用 8080 端口。另外,除了我们创建的 httpd-svc,还有一个 Service kubernetes,Cluster 内部通过这个 Service 访问 kubernetes API Server。文章源自靠谱运维-https://www.ixdba.net/archives/1381

通过 kubectl describe 可以查看 httpd-svc 与 Pod 的对应关系。文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken ~]# kubectl describe service httpd-svc
Name:              httpd-svc
Namespace:         default
Labels:            <none>
Annotations:       kubectl.kubernetes.io/last-applied-configuration:
                     {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"httpd-svc","namespace":"default"},"spec":{"ports":[{"port":8080,"...
Selector:          run=httpd
Type:              ClusterIP
IP:                10.106.64.97
Port:              <unset>  8080/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.27:80,10.244.1.28:80,10.244.2.18:80
Session Affinity:  None
Events:            <none>

Endpoints 罗列了三个 Pod 的 IP 和端口。文章源自靠谱运维-https://www.ixdba.net/archives/1381

service ip底层原理分析

我们知道 Pod 的 IP 是在容器中配置的,那么 Service 的 Cluster IP 又是配置在哪里的呢?CLUSTER-IP 又是如何映射到 Pod IP 的呢?文章源自靠谱运维-https://www.ixdba.net/archives/1381

答案是 iptables文章源自靠谱运维-https://www.ixdba.net/archives/1381

Service Cluster IP 是一个虚拟 IP,是由 Kubernetes 节点上的 iptables 规则管理的。文章源自靠谱运维-https://www.ixdba.net/archives/1381

查看svc文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken1 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP   15d
my-svc       ClusterIP   10.107.111.108   <none>        80/TCP    16s

可以通过 iptables-save 命令打印出当前节点的 iptables 规则,因为输出较多,这里只截取与my-svc Cluster IP 10.99.229.179 相关的信息:文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken1 ~]# iptables-save | grep 10.107.111.108 
-A KUBE-SERVICES ! -s 10.244.0.0/16 -d 10.107.111.108/32 -p tcp -m comment --comment "default/my-svc: cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.107.111.108/32 -p tcp -m comment --comment "default/my-svc: cluster IP" -m tcp --dport 80 -j KUBE-SVC-NSPZQM4WNKQARS3D

这两条规则的含义是:文章源自靠谱运维-https://www.ixdba.net/archives/1381

  1. 如果 Cluster 内的 Pod(源地址来自 10.244.0.0/16)要访问 httpd-svc,则允许。
  2. 其他源地址访问 my-svc,跳转到规则 KUBE-SVC-NSPZQM4WNKQARS3D。

KUBE-SVC-NSPZQM4WNKQARS3D规则如下:文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken1 ~]# iptables-save | grep KUBE-SVC-NSPZQM4WNKQARS3D
:KUBE-SVC-NSPZQM4WNKQARS3D - [0:0]
-A KUBE-SERVICES -d 10.107.111.108/32 -p tcp -m comment --comment "default/my-svc: cluster IP" -m tcp --dport 80 -j KUBE-SVC-NSPZQM4WNKQARS3D
-A KUBE-SVC-NSPZQM4WNKQARS3D -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-PHYMVJLGA3SBF53W
-A KUBE-SVC-NSPZQM4WNKQARS3D -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-6WM3EVRMZRPSARU6
-A KUBE-SVC-NSPZQM4WNKQARS3D -j KUBE-SEP-MF65K4BIWBNT73JP
  1. 1/3 的概率跳转到规则 KUBE-SEP-PHYMVJLGA3SBF53W
  2. 1/3 的概率(剩下 2/3 的一半)跳转到规则 KUBE-SEP-6WM3EVRMZRPSARU6
  3. 1/3 的概率跳转到规则 KUBE-SEP-MF65K4BIWBNT73JP

上面三个跳转的规则如下:文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken1 ~]# iptables-save | grep KUBE-SEP-PHYMVJLGA3SBF53W
-A KUBE-SEP-PHYMVJLGA3SBF53W -s 10.244.1.50/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-PHYMVJLGA3SBF53W -p tcp -m tcp -j DNAT --to-destination 10.244.1.50:80

[root@ken1 ~]# iptables-save | grep KUBE-SEP-6WM3EVRMZRPSARU6
-A KUBE-SEP-6WM3EVRMZRPSARU6 -s 10.244.2.129/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-6WM3EVRMZRPSARU6 -p tcp -m tcp -j DNAT --to-destination 10.244.2.129:80

[root@ken1 ~]# iptables-save | grep KUBE-SEP-MF65K4BIWBNT73JP
-A KUBE-SEP-MF65K4BIWBNT73JP -s 10.244.2.130/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-MF65K4BIWBNT73JP -p tcp -m tcp -j DNAT --to-destination 10.244.2.130:80

即将请求分别转发到后端的三个 Pod。通过上面的分析,我们得到如下结论:文章源自靠谱运维-https://www.ixdba.net/archives/1381

iptables 将访问 Service 的流量转发到后端 Pod,而且使用类似轮询的负载均衡策略。文章源自靠谱运维-https://www.ixdba.net/archives/1381

另外需要补充一点:Cluster 的每一个节点都配置了相同的 iptables 规则,这样就确保了整个 Cluster 都能够通过 Service 的 Cluster IP 访问 Service。文章源自靠谱运维-https://www.ixdba.net/archives/1381

DNS访问service

在 Cluster 中,除了可以通过 Cluster IP 访问 Service,Kubernetes 还提供了更为方便的 DNS 访问。文章源自靠谱运维-https://www.ixdba.net/archives/1381

第一步:查看coredns文章源自靠谱运维-https://www.ixdba.net/archives/1381

kubeadm 部署时会默认安装 coredns 组件。文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken ~]# kubectl get deployment --namespace=kube-system
NAME      READY   UP-TO-DATE   AVAILABLE   AGE
coredns   2/2     2            2           11h

coredns 是一个 DNS 服务器。每当有新的 Service 被创建,coredns 会添加该 Service 的 DNS 记录。Cluster 中的 Pod 可以通过 <SERVICE_NAME>.<NAMESPACE_NAME> 访问 Service。文章源自靠谱运维-https://www.ixdba.net/archives/1381

第二步:dns访问文章源自靠谱运维-https://www.ixdba.net/archives/1381

比如可以用 httpd-svc.default 访问 Service httpd-svc。文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken ~]# kubectl run busybox --rm -it --image=busybox /bin/sh
/ # wget httpd-svc:8080  
Connecting to httpd-svc:8080 (10.106.64.97:8080)
index.html           100% |*************|    45  0:00:00 ETA
/ # ls
bin         home        root        usr
dev         index.html  sys         var
etc         proc        tmp
/ # cat index.html 
<html><body><h1>It works!</h1></body></html>
注意:wget httpd-svc:8080  后面的这个port必须是service的port不是nodeport

由于这个 Pod 与 httpd-svc 同属于 default namespace,可以省略 default 直接用 httpd-svc 访问 Service。文章源自靠谱运维-https://www.ixdba.net/archives/1381

第三步:查看namespace文章源自靠谱运维-https://www.ixdba.net/archives/1381

如果要访问其他 namespace 中的 Service,就必须带上 namesapce 了。kubectl get namespace 查看已有的 namespace。文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken ~]# kubectl get namespace
NAME          STATUS   AGE
default       Active   11h
kube-public   Active   11h
kube-system   Active   11h

第四步:在 kube-public 中部署 Service httpd2-svc文章源自靠谱运维-https://www.ixdba.net/archives/1381

配置如下:文章源自靠谱运维-https://www.ixdba.net/archives/1381

k8s通过service访问pod(五)文章源自靠谱运维-https://www.ixdba.net/archives/1381

第五步:创建资源文章源自靠谱运维-https://www.ixdba.net/archives/1381

通过 namespace: kube-public 指定资源所属的 namespace。多个资源可以在一个 YAML 文件中定义,用 — 分割。执行 kubectl apply 创建资源:文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken ~]# kubectl apply -f service.yml
deployment.apps/httpd2 created
service/httpd2-svc created

第六步:查看 kube-public 的 Service:文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken ~]# kubectl get service --namespace=kube-public
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
httpd2-svc   ClusterIP   10.111.175.138   <none>        8080/TCP   63s

第七步:在 busybox Pod 中访问 httpd2-svc:文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken ~]# kubectl run busybox --rm -it --image=busybox /bin/sh
/ # wget httpd2-svc:8080
wget: bad address 'httpd2-svc:8080'
/ # wget httpd2-svc.kube-public:8080
Connecting to httpd2-svc.kube-public:8080 (10.111.175.138:8080)
index.html           100% |*************|    45  0:00:00 ETA

因为属于不同的 namespace,必须使用 httpd2-svc.kube-public 才能访问到。文章源自靠谱运维-https://www.ixdba.net/archives/1381

外网访问service

除了 Cluster 内部可以访问 Service,很多情况我们也希望应用的 Service 能够暴露给 Cluster 外部。Kubernetes 提供了多种类型的 Service,默认是 ClusterIP。文章源自靠谱运维-https://www.ixdba.net/archives/1381

ClusterIP

Service 通过 Cluster 内部的 IP 对外提供服务,只有 Cluster 内的节点和 Pod 可访问,这是默认的 Service 类型,前面实验中的 Service 都是 ClusterIP。文章源自靠谱运维-https://www.ixdba.net/archives/1381

NodePort

Service 通过 Cluster 节点的静态端口对外提供服务。Cluster 外部可以通过 <NodeIP>:<NodePort> 访问 Service。文章源自靠谱运维-https://www.ixdba.net/archives/1381

LoadBalancer

Service 利用 cloud provider 特有的 load balancer 对外提供服务,cloud provider 负责将 load balancer 的流量导向 Service。目前支持的 cloud provider 有 GCP、AWS、Azur 等。文章源自靠谱运维-https://www.ixdba.net/archives/1381

第一步:实践 NodePort,Service httpd-svc 的配置文件修改如下:文章源自靠谱运维-https://www.ixdba.net/archives/1381

k8s通过service访问pod(五)文章源自靠谱运维-https://www.ixdba.net/archives/1381

添加 type: NodePort,重新创建 httpd-svc。文章源自靠谱运维-https://www.ixdba.net/archives/1381

第二步:创建service文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken ~]# kubectl apply -f service.yml
service/httpd-svc created
[root@ken ~]# kubectl get service httpd-svc
NAME        TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
httpd-svc   NodePort   10.108.118.202   <none>        8080:31785/TCP   12s

Kubernetes 依然会为 httpd-svc 分配一个 ClusterIP,不同的是:文章源自靠谱运维-https://www.ixdba.net/archives/1381

EXTERNAL-IP 为 nodes,表示可通过 Cluster 每个节点自身的 IP 访问 Service。文章源自靠谱运维-https://www.ixdba.net/archives/1381

PORT(S) 为 8080:31785。8080 是 ClusterIP 监听的端口(每个节点都有该端口),31785 则是节点上监听的端口。Kubernetes 会从 30000-32767 中分配一个可用的端口,每个节点都会监听此端口并将请求转发给 Service。文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken ~]# ss -tnl | grep 31785
LISTEN     0      128         :::31785                   :::*

第三步:测试nodeport是否正常工作文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken ~]# curl 172.20.10.2:31785
<html><body><h1>It works!</h1></body></html>
[root@ken ~]# curl 172.20.10.7:31785
<html><body><h1>It works!</h1></body></html>
[root@ken ~]# curl 172.20.10.9:31785
<html><body><h1>It works!</h1></body></html>

通过三个节点 IP + 32312 端口都能够访问 httpd-svc。文章源自靠谱运维-https://www.ixdba.net/archives/1381

第四步:指定特定端口文章源自靠谱运维-https://www.ixdba.net/archives/1381

NodePort 默认是的随机选择,不过我们可以用 nodePort 指定某个特定端口。文章源自靠谱运维-https://www.ixdba.net/archives/1381

k8s通过service访问pod(五)文章源自靠谱运维-https://www.ixdba.net/archives/1381

现在配置文件中就有三个 Port 了:文章源自靠谱运维-https://www.ixdba.net/archives/1381

nodePort 是节点上监听的端口。文章源自靠谱运维-https://www.ixdba.net/archives/1381

port 是 ClusterIP 上监听的端口。文章源自靠谱运维-https://www.ixdba.net/archives/1381

targetPort 是 Pod 监听的端口。文章源自靠谱运维-https://www.ixdba.net/archives/1381

最终,Node 和 ClusterIP 在各自端口上接收到的请求都会通过 iptables 转发到 Pod 的 targetPort。文章源自靠谱运维-https://www.ixdba.net/archives/1381

第四步:应用新的 nodePort 并验证:文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken ~]# kubectl apply -f service.yml
service/httpd-svc configured

[root@ken ~]# kubectl get service httpd-svc
NAME        TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
httpd-svc   NodePort   10.108.118.202   <none>        8080:30000/TCP   6m8s

[root@ken ~]# curl 172.20.10.2:30000
<html><body><h1>It works!</h1></body></html>
[root@ken ~]# curl 172.20.10.7:30000
<html><body><h1>It works!</h1></body></html>
[root@ken ~]# curl 172.20.10.9:30000
<html><body><h1>It works!</h1></body></html>

nodePort: 30000 已经生效了。文章源自靠谱运维-https://www.ixdba.net/archives/1381

接下来我们深入探讨一个问题:Kubernetes 是如何将 <NodeIP>:<NodePort> 映射到 Pod 的呢?文章源自靠谱运维-https://www.ixdba.net/archives/1381

与 ClusterIP 一样,也是借助了 iptables。与 ClusterIP 相比,每个节点的 iptables 中都增加了下面两条规则:文章源自靠谱运维-https://www.ixdba.net/archives/1381

第一步:查看svc端口文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken1 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        15d
my-svc       NodePort    10.107.111.108   <none>        80:32287/TCP   14m

第二步:查看iptables规则文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken1 ~]# iptables-save | grep 32287
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/my-svc:" -m tcp --dport 32287 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/my-svc:" -m tcp --dport 32287 -j KUBE-SVC-NSPZQM4WNKQARS3D

规则的含义是:访问当前节点 32312 端口的请求会应用规则 KUBE-SVC-NSPZQM4WNKQARS3D文章源自靠谱运维-https://www.ixdba.net/archives/1381

第三步:相应规则KUBE-SVC-NSPZQM4WNKQARS3D文章源自靠谱运维-https://www.ixdba.net/archives/1381

[root@ken1 ~]# iptables-save | grep KUBE-SVC-NSPZQM4WNKQARS3D
-A KUBE-SERVICES -d 10.107.111.108/32 -p tcp -m comment --comment "default/my-svc: cluster IP" -m tcp --dport 80 -j KUBE-SVC-NSPZQM4WNKQARS3D
-A KUBE-SVC-NSPZQM4WNKQARS3D -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-PHYMVJLGA3SBF53W
-A KUBE-SVC-NSPZQM4WNKQARS3D -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-6WM3EVRMZRPSARU6
-A KUBE-SVC-NSPZQM4WNKQARS3D -j KUBE-SEP-MF65K4BIWBNT73JP

其作用就是负载均衡到每一个 Pod。文章源自靠谱运维-https://www.ixdba.net/archives/1381

  • 本文由 发表于 2020年3月25日12:53:13
  • 转载请务必保留本文链接:https://www.ixdba.net/archives/1381
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: