• 理解Kubernetes(2): 应用的各种访问方式


    理解Kubernetes系列文章:

    1. 手工搭建环境
    2. 应用的各种访问方式

    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 wide
    NAME                        READY     STATUS    RESTARTS   AGE       IP           NODE
    my-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 ps
    CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS               NAMES
    d199cb090c13        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_0
    0c647fb76c0b        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: <BROADCAST,MULTICAST,UP,LOWER_UP> 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 addr
    77: eth0@if78: <BROADCAST,MULTICAST,UP,LOWER_UP> 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 network
    FLANNEL_SUBNET=10.1.1.1/24   #这是本节点上 falnnel subnet
    FLANNEL_MTU=1400             #本节点上 flannel mtu
    FLANNEL_IPMASQ=true

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

    root@kub-node-1:/opt/bin# ifconfig flannel.1
    flannel.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.255
    
    root@kub-node-1:/opt/bin# ip link show dev flannel.1
    3: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> 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 docker0
    docker0   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 docker0
    bridge name    bridge id        STP enabled    interfaces
    docker0        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 -n
    Kernel IP routing table
    Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
    0.0.0.0         172.23.100.1    0.0.0.0         UG    0      0        0 ens3
    10.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 网络内节点内的通信会走 docker0
    169.254.169.254 172.23.100.1    255.255.255.255 UGH   0      0        0 ens3
    172.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 wide
    NAME                        READY     STATUS    RESTARTS   AGE       IP           NODE
    my-nginx8-b77fdd7bc-4t2kb   1/1       Running   0          4d        10.1.79.11   172.23.100.6
    root@kub-node-0:/home/ubuntu/kub# curl 10.1.79.11:80
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>
    
    <p>For online documentation and support please refer to
    <a href="http://nginx.org/">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="http://nginx.com/">nginx.com</a>.</p>
    
    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>

    而在集群之外,是无法访问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-svc
    service "nginx-cluster-svc" exposed

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

    root@kub-node-0:/home/ubuntu/kub# kubectl get svc
    NAME                TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
    kubernetes          ClusterIP   192.1.0.1      <none>        443/TCP   13d
    nginx-cluster-svc   ClusterIP   192.1.47.211   <none>        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-svc
    service "nginx-nodeport-svc" exposed
    root@kub-node-0:/home/ubuntu/kub# kubectl get svc
    NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
    kubernetes           ClusterIP   192.1.0.1     <none>        443/TCP        13d
    nginx-nodeport-svc   NodePort    192.1.88.35   <none>        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-YN4D7LGVMIQA3S2Y
    
    root@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-H7QSASJ4XBTCRED7
    
    root@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。示意图如下:

    等将来有机会再试试。

  • 相关阅读:
    hive数据仓库入门到实战及面试
    clickhouse入门到实战及面试
    透过源码看懂Flink核心框架的执行流程
    hive经典练习题
    flink批处理从0到1学习
    flink基础篇
    flink进阶篇
    flink源码阅读
    spark优化总结
    uni-app跨平台移动应用开发
  • 原文地址:https://www.cnblogs.com/sammyliu/p/8274478.html
Copyright © 2020-2023  润新知