理解Kubernetes系列文章:

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

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

1.1 Pod 的IP地址

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

root@kub-node-:/home/ubuntu# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
my-nginx8-b77fdd7bc-4t2kb / Running 3d 10.1.79.11 172.23.100.6

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

root@kub-node-:/home/ubuntu# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d199cb090c13 sammyliu8/nginx "nginx -g 'daemon of…" days ago Up days k8s_my-nginx8_my-nginx8-b77fdd7bc-4t2kb_default_cd1425fd-f48a-11e7-a605-fa163e9a22a6_0
0c647fb76c0b kubernetes/pause "/pause" days ago Up days k8s_POD_my-nginx8-b77fdd7bc-4t2kb_default_cd1425fd-f48a-11e7-a605-fa163e9a22a6_0

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

root@kub-node-:/home/ubuntu# ip netns exec pause0b ip addr: eth0@if78: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu  qdisc noqueue state UP group default
link/ether ::0a::4f:0b brd ff:ff:ff:ff:ff:ff link-netnsid
inet 10.1.79.11/ brd 10.1.79.255 scope global eth0
valid_lft forever preferred_lft forever

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

root@kub-node-:/home/ubuntu# ip netns exec nginx13 ip addr
: eth0@if78: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc noqueue state UP group default
link/ether ::0a::4f:0b brd ff:ff:ff:ff:ff:ff link-netnsid
inet 10.1.79.11/ brd 10.1.79.255 scope global eth0
valid_lft forever preferred_lft forever

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

root               ?        :: /usr/bin/dockerd -g /data/docker --bip=10.1.79.1/ --mtu=

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-:/opt/bin# ifconfig flannel.
flannel. Link encap:Ethernet HWaddr 0a:6e:a6:6f::
inet addr:10.1.1.0 Bcast:0.0.0.0 Mask:255.255.255.255 root@kub-node-:/opt/bin# ip link show dev flannel.
: flannel.: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc noqueue state UNKNOWN mode DEFAULT group default
link/ether 0a:6e:a6:6f:: 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/ --mtu=

(4)dockerd deamon 会创建 docker0 网桥

root@kub-node-:/opt/bin# ifconfig docker0
docker0 Link encap:Ethernet HWaddr :::ef:ef:
inet addr:10.1.1.1 Bcast:10.1.1.255 Mask:255.255.255.0

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

root@kub-node-:/opt/bin# brctl show docker0
bridge name bridge id STP enabled interfaces
docker0 .024230efef18 no veth295ded4
veth5459316

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

1.3 POD 间通信

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

root@kub-node-:/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 ens3
10.1.0.0 0.0.0.0 255.255.0.0 U flannel.1 #flannel 网络内跨节点的通信会交给 flannel.1 处理
10.1.1.0 0.0.0.0 255.255.255.0 U docker0 #flannel 网络内节点内的通信会走 docker0
169.254.169.254 172.23.100.1 255.255.255.255 UGH ens3
172.23.100.0 0.0.0.0 255.255.255.0 U 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. --> NodeA --> (IP Address) -->  NodeB --> flannel. --> docker0 --> containerB

根据subnet 从 etcd 中获取 node ip:

root@kub-node-:/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-
{"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-:/home/ubuntu/kub# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
my-nginx8-b77fdd7bc-4t2kb / Running 4d 10.1.79.11 172.23.100.6
root@kub-node-:/home/ubuntu/kub# curl 10.1.79.11:
<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-:/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-:/home/ubuntu/kub# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 192.1.0.1 <none> /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-:/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/ -p tcp -m comment --comment "default/kubernetes:https cluster IP" -m tcp --dport -j KUBE-SVC-NPX46M4PTMTKRN6Y
-A KUBE-SERVICES -d 192.1.233.219/ -p tcp -m comment --comment "kube-system/kubernetes-dashboard: cluster IP" -m tcp --dport -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-:/home/ubuntu# iptables -S -t nat | grep KUBE-SVC-XQHY67DURS27F2QJ
-N KUBE-SVC-XQHY67DURS27F2QJ
-A KUBE-SERVICES -d 192.1.47.211/ -p tcp -m comment --comment "default/nginx-cluster-svc: cluster IP" -m tcp --dport -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-:/home/ubuntu# iptables -S -t nat | grep KUBE-SEP-FO4LSVXACD7WOMVW
-N KUBE-SEP-FO4LSVXACD7WOMVW
-A KUBE-SEP-FO4LSVXACD7WOMVW -s 10.1.1.4/ -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-:/home/ubuntu/kub# kubectl expose deployment my-nginx8 --type NodePort --name nginx-nodeport-svc
service "nginx-nodeport-svc" exposed
root@kub-node-:/home/ubuntu/kub# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 192.1.0.1 <none> /TCP 13d
nginx-nodeport-svc NodePort 192.1.88.35 <none> :/TCP 5s

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

3.2 Service NodePort 的由来

root@kub-node-:/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-:/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-:/var/log/kubernetes# iptables -S -t nat | grep KUBE-SEP-H7QSASJ4XBTCRED7
-N KUBE-SEP-H7QSASJ4XBTCRED7
-A KUBE-SEP-H7QSASJ4XBTCRED7 -s 10.1.1.4/ -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-:/var/log/kubernetes# iptables -S -t nat | grep KUBE-SEP-YLSXRQMQKCP2ZZ6B
-N KUBE-SEP-YLSXRQMQKCP2ZZ6B
-A KUBE-SEP-YLSXRQMQKCP2ZZ6B -s 10.1.79.11/ -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。示意图如下:

等将来有机会再试试。

理解Kubernetes(2): 应用的各种访问方式的更多相关文章

  1. Kubernetes的三种外部访问方式:NodePort、LoadBalancer和Ingress(转发)

    原文 http://cloud.51cto.com/art/201804/570386.htm Kubernetes的三种外部访问方式:NodePort.LoadBalancer和Ingress 最近 ...

  2. Kubernetes的三种外部访问方式:NodePort、LoadBalancer和Ingress

    NodePort,LoadBalancer和Ingress之间的区别.它们都是将集群外部流量导入到集群内的方式,只是实现方式不同. ClusterIP ClusterIP服务是Kubernetes的默 ...

  3. 深入理解java虚拟机(二)HotSpot Java对象创建,内存布局以及访问方式

    内存中对象的创建.对象的结构以及访问方式. 一.对象的创建 在语言层面上,对象的创建只不过是一个new关键字而已,那么在虚拟机中又是一个怎样的过程呢? (一)判断类是否加载.虚拟机遇到一条new指令的 ...

  4. 后端技术杂谈11:十分钟理解Kubernetes核心概念

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 本文转自 https://github.com/h2pl/Java-Tutorial 喜欢的 ...

  5. 理解Kubernetes(1):手工搭建Kubernetes测试环境

    系列文章: 1. 手工搭建环境 1. 基础环境准备 准备 3个Ubuntu节点,操作系统版本为 16.04,并做好以下配置: 系统升级 设置 /etc/hosts 文件,保持一致 设置从 0 节点上无 ...

  6. 快速理解VirtualBox的四种网络连接方式

    VirtualBox中有4中网络连接方式: NAT Bridged Adapter Internal Host-only Adapter VMWare中有三种,其实他跟VMWare 的网络连接方式都是 ...

  7. Sql Server中的表访问方式Table Scan, Index Scan, Index Seek

    1.oracle中的表访问方式 在oracle中有表访问方式的说法,访问表中的数据主要通过三种方式进行访问: 全表扫描(full table scan),直接访问数据页,查找满足条件的数据 通过row ...

  8. 转:Sql Server中的表访问方式Table Scan, Index Scan, Index Seek

    0.参考文献 Table Scan, Index Scan, Index Seek SQL SERVER – Index Seek vs. Index Scan – Diffefence and Us ...

  9. 理解kubernetes环境的iptables

    node节点的iptables是由kube-proxy生成的,具体实现可以参见kube-proxy的代码 kube-proxy只修改了filter和nat表,它对iptables的链进行了扩充,自定义 ...

随机推荐

  1. 【HDOJ3018】【一笔画问题】【欧拉回路+并查集】

    http://acm.hdu.edu.cn/showproblem.php?pid=3018 Ant Trip Time Limit: 2000/1000 MS (Java/Others)    Me ...

  2. String的方法capitalize

    官方解释:Return a copy of the string with its first character capitalized and the rest lowercased.(返回字符串 ...

  3. day21-22Redis Mahout

    PS: Redis 在博客的 JavaEE PS:大数据实时执行3个特性,Storm,kafka,Redis PS:比如在系统中,1s中有大量的请求涌入的系统中,那么请求就存入数据库就挂了,这就需要到 ...

  4. MySQL5.6在线DDL不锁表(在线添加字段)

    解答你也看一下MySQL5.6在线DDL不锁表,现在我有一张1亿的表,需要增加一个字段,假如我让你去增加这个字段,你应该注意什么,具体怎么操作? 操作如下:1.注意磁盘空间(临时表目录 参数 tmpd ...

  5. vernemq 集群 docker-compose 搭建简单试用

    vernemq 是一款开源的mqtt broker, 支持cluster 模式部署,而且部署比较简单 以下是一个使用docker-compose 搭建环境的demo 环境准备 docker-compo ...

  6. js技巧专题篇: 页面跳转

    本篇主要介绍网页上常见的页面跳转技术.页面跳转有几种方式,比较常用的是window.location.href,window.location.replace,window.open,当然还有目前比较 ...

  7. quartz.net实现集群部署的笔记

    一..表信息 QRTZ_CALENDARS 以 Blob 类型存储 Quartz 的 Calendar 信息 QRTZ_CRON_TRIGGERS 存储 Cron Trigger,包括Cron表达式和 ...

  8. 如何利用 Chrome 来模拟移动网络来调试 FastAdmin 网站

    如何利用 Chrome 来模拟移动网络来高度 FastAdmin 网站 因为目前大多数都在开发移动类的网页,所以客户端的速度下载速度要也考虑. 虽然都已经 4G 了,但还是要看看在网络质量很差的情况 ...

  9. gevent原理

    未看 http://blog.csdn.net/yueguanghaidao/article/details/24281751

  10. MySQL5.6新特性之Multi-Range Read

    一 介绍    MySQL 5.6版本提供了很多性能优化的特性,其中之一就是 Multi-Range Read 多范围读(MRR) , 它的作用针对基于辅助/第二索引的查询,减少随机IO,并且将随机I ...