博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
理解Kubernetes(2): 应用的各种访问方式
阅读量:6220 次
发布时间:2019-06-21

本文共 11517 字,大约阅读时间需要 38 分钟。

理解Kubernetes系列文章:

 

1. 通过 Pod 的 IP 地址访问应用

1.1 Pod 的IP地址

每个Pod 都会被分配一个IP地址,比如下面这儿pod的IP地址是 10.1.79.11.

root@kub-node-0:/home/ubuntu# kubectl get pod -o wideNAME                        READY     STATUS    RESTARTS   AGE       IP           NODEmy-nginx8-b77fdd7bc-4t2kb   1/1       Running   0          3d        10.1.79.11   172.23.100.6

该 Pod 在某个 node 上有两个容器:

root@kub-node-2:/home/ubuntu# docker psCONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS               NAMESd199cb090c13        sammyliu8/nginx      "nginx -g 'daemon of…"   3 days ago          Up 3 days                               k8s_my-nginx8_my-nginx8-b77fdd7bc-4t2kb_default_cd1425fd-f48a-11e7-a605-fa163e9a22a6_00c647fb76c0b        kubernetes/pause     "/pause"                 3 days ago          Up 3 days                               k8s_POD_my-nginx8-b77fdd7bc-4t2kb_default_cd1425fd-f48a-11e7-a605-fa163e9a22a6_0

dockerd 会给 pause 容器分配一个ip,这个ip 就是 pod 的ip:

root@kub-node-2:/home/ubuntu# ip netns exec pause0b ip addr77: eth0@if78: 
mtu 1400 qdisc noqueue state UP group default link/ether 02:42:0a:01:4f:0b brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 10.1.79.11/24 brd 10.1.79.255 scope global eth0 valid_lft forever preferred_lft forever

而 nginx 容器是跟 pause 容器共享 network namespace 的:

root@kub-node-2:/home/ubuntu# ip netns exec nginx13 ip addr77: eth0@if78: 
mtu 1400 qdisc noqueue state UP group default link/ether 02:42:0a:01:4f:0b brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 10.1.79.11/24 brd 10.1.79.255 scope global eth0 valid_lft forever preferred_lft forever

IP 所在的网段是在 dockerd 的启动参数中给的:

root     11183     1  1  2017 ?        03:04:26 /usr/bin/dockerd -g /data/docker --bip=10.1.79.1/24 --mtu=1400

 1.2 Pod IP 地址的由来

(1)管理员配置 flannel 使用的 network,并将配置保存在 etcd 中

/opt/bin/etcdctl --endpoints="http://172.23.100.4:2379,http://172.23.100.5:2379,http://172.23.100.4:2379" mk /coreos.com/network/config \ '{"Network":"10.1.0.0/16", "Backend": {"Type": "vxlan"}}'

(2)在每个 minion 节点上,flannel 启动。它从 etcd 中获取 network 配置,并为本节点产生一个 subnet,也保存在 etcd 中。并且产生 /run/flannel/subnet.env 文件:

FLANNEL_NETWORK=10.1.0.0/16  #这是全局的 falnnel networkFLANNEL_SUBNET=10.1.1.1/24   #这是本节点上 falnnel subnetFLANNEL_MTU=1400             #本节点上 flannel mtuFLANNEL_IPMASQ=true

(3)flannel deamon 还会创建 flannel.1 的 vxlan vtep 端点:

root@kub-node-1:/opt/bin# ifconfig flannel.1flannel.1 Link encap:Ethernet  HWaddr 0a:6e:a6:6f:95:04          inet addr:10.1.1.0  Bcast:0.0.0.0  Mask:255.255.255.255root@kub-node-1:/opt/bin# ip link show dev flannel.13: flannel.1: 
mtu 1400 qdisc noqueue state UNKNOWN mode DEFAULT group default link/ether 0a:6e:a6:6f:95:04 brd ff:ff:ff:ff:ff:ff

其 mtu 正好是 1400. 该端点会负责接收和发送 vxlan 数据包。

(3)使用 subnet.env 中的变量,启动 dockerd 进程,它的 bip 对应 FLANNEL_SUBNET,mtu 对应 FLANNEL_MTU。

/usr/bin/dockerd -g /data/docker --bip=10.1.1.1/24 --mtu=1400

(4)dockerd deamon 会创建 docker0 网桥

root@kub-node-1:/opt/bin# ifconfig docker0docker0   Link encap:Ethernet  HWaddr 02:42:30:ef:ef:18          inet addr:10.1.1.1  Bcast:10.1.1.255  Mask:255.255.255.0

本节点上的容器都会使用一个 veth 设备挂接在该网桥上比如:

root@kub-node-1:/opt/bin# brctl show docker0bridge name    bridge id        STP enabled    interfacesdocker0        8000.024230efef18    no        veth295ded4                                              veth5459316

(5)对每一个被调度到本节点上的 POD,kubelet 都会创建一个 pause 容器,该容器会通过一个 veth 设备挂接到 docker0 上;同时,POD 中的其他容器会共享 pause 容器的 network namespace。

1.3 POD 间通信

首先看下本节点上的路由表:

root@kub-node-1:/opt/bin# route -nKernel IP routing tableDestination     Gateway         Genmask         Flags Metric Ref    Use Iface0.0.0.0         172.23.100.1    0.0.0.0         UG    0      0        0 ens310.1.0.0        0.0.0.0         255.255.0.0     U     0      0        0 flannel.1   #flannel 网络内跨节点的通信会交给 flannel.1 处理10.1.1.0        0.0.0.0         255.255.255.0   U     0      0        0 docker0     #flannel 网络内节点内的通信会走 docker0169.254.169.254 172.23.100.1    255.255.255.255 UGH   0      0        0 ens3172.23.100.0    0.0.0.0         255.255.255.0   U     0      0        0 ens3

如果是同一个 deployment 的位于同一个 minon 上的两个 POD 之间通信,那实际上是同一个 subnet 间通信,此时经过 docker0 网桥即可;

如果是同一个 deployment 的位于两个 minon 上的两个 POD 之间通信,另一个POD 的IP 在 10.1.79.0 子网上,那么首先到 flannel.1, flannel 查询 etcd 获取对方容器所在的节点的IP地址,然后封装为 vxlan 的 udp 包,发到 ens3,走物理机网络达到对方节点。此时,完整的路径是:

containerA --> docker0 --> flannel.1 --> NodeA --> (IP Address) -->  NodeB --> flannel.1 --> docker0 --> containerB

根据subnet 从 etcd 中获取 node ip:

root@kub-node-0:/home/ubuntu/kub# /opt/bin/etcdctl --endpoints="http://172.23.100.4:2379,http://172.23.100.5:2379,http://172.23.100.4:2379" get /coreos.com/network/subnets/10.1.79.0-24{
"PublicIP":"172.23.100.6","BackendType":"vxlan","BackendData":{
"VtepMAC":"6e:10:b3:53:1e:f4"}}

 1.4 通过POD IP 访问应用

POD 的 IP 地址是 docker 分配的,在 falnnel 网络范围内,也就是 K8S 集群范围内,都可以使用 POD 的 IP 访问 POD 中的应用。比如:

root@kub-node-0:/home/ubuntu/kub# kubectl get pods -o wideNAME                        READY     STATUS    RESTARTS   AGE       IP           NODEmy-nginx8-b77fdd7bc-4t2kb   1/1       Running   0          4d        10.1.79.11   172.23.100.6root@kub-node-0:/home/ubuntu/kub# curl 10.1.79.11:80

Welcome to nginx!

If you see this page, the nginx web server is successfully installed andworking. Further configuration is required.

For online documentation and support please refer tonginx.org.

Commercial support is available atnginx.com.

Thank you for using nginx.

而在集群之外,是无法访问POD的IP的。

2. 通过 Cluster Service 的IP地址访问应用

2.1 Service 的 Cluster IP

从上面内容可以看出,每个POD的IP 跟所在节点的配置有关,因此,随着POD在不同节点上的生生死死,其IP地址会发生变化。为了解决这个问题,K8S 提供了 Cluster 类型的 service。

创建一个 Cluster 类型的 service:

root@kub-node-0:/home/ubuntu/kub# kubectl expose deployment my-nginx8 --type ClusterIP --name nginx-cluster-svcservice "nginx-cluster-svc" exposed

该 service 由 kube-apiserver 服务分配了虚拟的 IP 地址 192.1.47.211:

root@kub-node-0:/home/ubuntu/kub# kubectl get svcNAME                TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGEkubernetes          ClusterIP   192.1.0.1      
443/TCP 13dnginx-cluster-svc ClusterIP 192.1.47.211
80/TCP 1m

而这些 IP 地址的区间则是其启动参数 service-cluster-ip-range 指定的。在当前测试环境中,其值是 --service-cluster-ip-range=192.1.0.0/16。

2.2 Service Cluster IP 地址的由来

只能在 minon 节点上,而且只能使用 IP:Port/协议 才能访问 service。其它地方或者其它方式都不可以。

root@kub-node-1:/home/ubuntu# iptables -S -t nat | grep KUBE-SERVICES-N KUBE-SERVICES-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES-A OUTPUT -m comment --comment "kubernetes service portals" -j KUBE-SERVICES-A KUBE-SERVICES -d 192.1.47.211/32 -p tcp -m comment --comment "default/nginx-cluster-svc: cluster IP" -m tcp --dport 80 -j KUBE-SVC-XQHY67DURS27F2QJ-A KUBE-SERVICES -d 192.1.0.1/32 -p tcp -m comment --comment "default/kubernetes:https cluster IP" -m tcp --dport 443 -j KUBE-SVC-NPX46M4PTMTKRN6Y-A KUBE-SERVICES -d 192.1.233.219/32 -p tcp -m comment --comment "kube-system/kubernetes-dashboard: cluster IP" -m tcp --dport 443 -j KUBE-SVC-XGLOHA7QRQ3V22RZ-A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS root@kub-node-1:/home/ubuntu# iptables -S -t nat | grep KUBE-SVC-XQHY67DURS27F2QJ-N KUBE-SVC-XQHY67DURS27F2QJ-A KUBE-SERVICES -d 192.1.47.211/32 -p tcp -m comment --comment "default/nginx-cluster-svc: cluster IP" -m tcp --dport 80 -j KUBE-SVC-XQHY67DURS27F2QJ-A KUBE-SVC-XQHY67DURS27F2QJ -m comment --comment "default/nginx-cluster-svc:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-FO4LSVXACD7WOMVW-A KUBE-SVC-XQHY67DURS27F2QJ -m comment --comment "default/nginx-cluster-svc:" -j KUBE-SEP-DCSHEKS5WGS4LYVT root@kub-node-1:/home/ubuntu# iptables -S -t nat | grep KUBE-SEP-FO4LSVXACD7WOMVW-N KUBE-SEP-FO4LSVXACD7WOMVW-A KUBE-SEP-FO4LSVXACD7WOMVW -s 10.1.1.4/32 -m comment --comment "default/nginx-cluster-svc:" -j KUBE-MARK-MASQ-A KUBE-SEP-FO4LSVXACD7WOMVW -p tcp -m comment --comment "default/nginx-cluster-svc:" -m tcp -j DNAT --to-destination 10.1.1.4:80

  root@kub-node-1:/home/ubuntu# iptables -S -t nat | grep KUBE-SEP-DCSHEKS5WGS4LYVT

  -N KUBE-SEP-DCSHEKS5WGS4LYVT
  -A KUBE-SEP-DCSHEKS5WGS4LYVT -s 10.1.79.11/32 -m comment --comment "default/nginx-cluster-svc:" -j KUBE-MARK-MASQ
  -A KUBE-SEP-DCSHEKS5WGS4LYVT -p tcp -m comment --comment "default/nginx-cluster-svc:" -m tcp -j DNAT --to-destination 10.1.79.11:80

从以上 iptables 规则可以看出,在该节点上通过 192.1.47.211:80 访问 cluster service,最终结果是以50% 和 50% 的概率发到了 10.1.1.4:80 和 10.1.79.11:80 上,而这两个的地址正是该service 的 两个 POD 的 IP 地址。

所以主要流程是:

  • kube-proxy 根据 cluster service 的CRUD 来在每个节点上生成对应的 iptables 规则
  • 当通过 cluster ip 访问时,这些 iptables 规则会通过 NAT 方式把流量导向 service的 POD

3. 通过 NodePort service 的 IP 访问应用

Cluster service 的 IP 地址是虚拟的,因此,只能从minon 节点上使用该IP 地址访问应用。为了从集群外访问应用,K8S 提供了使用 minon 节点的IP 地址访问应用的方式。

3.1 NodePort Service

创建一个 NodePort 类型的 service,系统会自动创建一个 cluster-ip,同时还多了一个 port。下图中是 31295. 该端口号的范围是 kube-apiserver 的启动参数 --service-node-port-range指定的,在当前测试环境中其值是 30000-32767。

root@kub-node-0:/home/ubuntu/kub# kubectl expose deployment my-nginx8 --type NodePort --name nginx-nodeport-svcservice "nginx-nodeport-svc" exposedroot@kub-node-0:/home/ubuntu/kub# kubectl get svcNAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGEkubernetes           ClusterIP   192.1.0.1     
443/TCP 13dnginx-nodeport-svc NodePort 192.1.88.35
80:31295/TCP 5s

通过每个 minon 节点的IP 和 31295 端口可以访问该service。

3.2 Service NodePort 的由来

root@kub-node-1:/var/log/kubernetes# iptables -S -t nat | grep KUBE-NODEPORTS-N KUBE-NODEPORTS-A KUBE-NODEPORTS -p tcp -m comment --comment "default/nginx-nodeport-svc:" -m tcp --dport 31295 -j KUBE-MARK-MASQ-A KUBE-NODEPORTS -p tcp -m comment --comment "default/nginx-nodeport-svc:" -m tcp --dport 31295 -j KUBE-SVC-YN4D7LGVMIQA3S2Yroot@kub-node-1:/var/log/kubernetes# iptables -S -t nat | grep KUBE-SVC-YN4D7LGVMIQA3S2Y-N KUBE-SVC-YN4D7LGVMIQA3S2Y-A KUBE-SVC-YN4D7LGVMIQA3S2Y -m comment --comment "default/nginx-nodeport-svc:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-H7QSASJ4XBTCRED7
root@kub-node-1:/var/log/kubernetes# iptables -S -t nat | grep KUBE-SEP-H7QSASJ4XBTCRED7-N KUBE-SEP-H7QSASJ4XBTCRED7-A KUBE-SEP-H7QSASJ4XBTCRED7 -s 10.1.1.4/32 -m comment --comment "default/nginx-nodeport-svc:" -j KUBE-MARK-MASQ-A KUBE-SEP-H7QSASJ4XBTCRED7 -p tcp -m comment --comment "default/nginx-nodeport-svc:" -m tcp -j DNAT --to-destination 10.1.1.4:80-A KUBE-SVC-YN4D7LGVMIQA3S2Y -m comment --comment "default/nginx-nodeport-svc:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-H7QSASJ4XBTCRED7root@kub-node-1:/var/log/kubernetes# iptables -S -t nat | grep KUBE-SEP-YLSXRQMQKCP2ZZ6B-N KUBE-SEP-YLSXRQMQKCP2ZZ6B-A KUBE-SEP-YLSXRQMQKCP2ZZ6B -s 10.1.79.11/32 -m comment --comment "default/nginx-nodeport-svc:" -j KUBE-MARK-MASQ-A KUBE-SEP-YLSXRQMQKCP2ZZ6B -p tcp -m comment --comment "default/nginx-nodeport-svc:" -m tcp -j DNAT --to-destination 10.1.79.11:80-A KUBE-SVC-YN4D7LGVMIQA3S2Y -m comment --comment "default/nginx-nodeport-svc:" -j KUBE-SEP-YLSXRQMQKCP2ZZ6B

可见,同样地,通过 iptables 规则,通过 nodeport 访问service,最终转到了对该 servide 的所有 pod 轮流地访问。

即使某个 node 上没有service 的 pod,这些规则也会被创建,也就是说,NodePort 模式会在每个节点上开起一个端口,然后转发到内部 Pod IP 。这样可以保证使用任何一个 node 的ip,结合 nodeport,都可以访问到 service。

4. 采用云 load balancer

NodePort  方式虽然可以被数据中心内部访问,但是它无法被互联网访问。为了解决这个问题,某些公有云平台向 Kubernetes 集群提供了负载均衡,产生了一个可以在公网上访问到的虚拟IP。示意图如下:

等将来有机会再试试。

 

转载地址:http://kpoja.baihongyu.com/

你可能感兴趣的文章
我的友情链接
查看>>
nginx在reload时候报错invalid PID number
查看>>
神经网络和深度学习-第二周神经网络基础-第二节:Logistic回归
查看>>
Myeclipse代码提示及如何设置自动提示
查看>>
setTimeOut(),和setInterVal()调用函数加不加括号!!!
查看>>
c/c++中保留两位有效数字
查看>>
urlparse获取url后面的参数
查看>>
ElasticSearch 2 (32) - 信息聚合系列之范围限定
查看>>
VS2010远程调试C#程序
查看>>
notepad++正则表达式例子
查看>>
[MicroPython]TurniBit开发板DIY自动窗帘模拟系统
查看>>
由String类的Split方法所遇到的两个问题
查看>>
Python3.4 12306 2015年3月验证码识别
查看>>
从Handler.post(Runnable r)再一次梳理Android的消息机制(以及handler的内存泄露)
查看>>
自制操作系统Antz day11——实现shell(下)命令响应
查看>>
windows查看端口占用
查看>>
js,php获取中文长度,比较简洁的方法汇总
查看>>
Windows内核新手上路1——挂钩SSDT
查看>>
strongswan ikev2 server on ubuntu 14.04
查看>>
Yii用ajax实现无刷新检索更新CListView数据
查看>>