Kubernetes 访问原理

4 分钟读完

Kubernetes 集群内外访问原理

1- 通过 Service 访问 Pod

集群中 Pod 是不稳定的,随着故障 Pod 被集群拉起的新 Pod 替换, 随之带来 IP 的变化,因此通过 Service 统一对外提供服务

通过 Deployment 创建一组 Pod,使用 ‘labels’ 将其和 Service 建立映射关系

创建 Deployment,设置 ‘labels’ 为 ‘run: httpd’

# vim httpd.yaml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: httpd
spec:
  replicas: 3
  template:
    metadata:
      labels:
        run: httpd
    spec:
      containers:
      - name: httpd
        image: httpd
        ports:
        - containerPort: 80

# kubectl apply -f httpd.yaml 
deployment "httpd" created

# kubectl get pods -o wide
NAME                    READY     STATUS    RESTARTS   AGE       IP            NODE
httpd-741508562-4h08z   1/1       Running   0          25s       10.244.1.28   f16-7-kubernetes02
httpd-741508562-j4lsm   1/1       Running   0          25s       10.244.1.29   f16-7-kubernetes02
httpd-741508562-jvgbg   1/1       Running   0          25s       10.244.2.22   f16-8-kubernetes03

每个 Pod 都有自己的 IP,但只能被集群中容器和节点访问

# curl 10.244.1.28
<html><body><h1>It works!</h1></body></html>

使用 ‘selector’ 选定 ‘labels’ 为 ‘run: httpd’ 的 Pod

将 Service 的 8080 端口映射到 Pod 的 80 端口,且指定 TCP 协议

# vim httpd-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: httpd-svc
spec:
  selector:
    run: httpd
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 80

# kubectl apply -f httpd-svc.yaml 
service "httpd-svc" created

# kubectl get services
NAME         CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
httpd-svc    10.96.203.6   <none>        8080/TCP   1m
kubernetes   10.96.0.1     <none>        443/TCP    88d

由 Service 管理的 CLUSTER-IP 是持久稳定的

# curl 10.96.203.6:8080
<html><body><h1>It works!</h1></body></html>

查看详细信息,可以看到三个后端 Pod

# 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,"protocol":"TC...
Selector:               run=httpd
Type:                   ClusterIP
IP:                     10.96.203.6
Port:                   <unset> 8080/TCP
Endpoints:              10.244.1.28:80,10.244.1.29:80,10.244.2.22:80
Session Affinity:       None
Events:                 <none>

2- Cluster IP

Service 的 Cluster IP 是通过 iptables 实现的虚拟 IP

# iptables-save | grep 10.96.203.6
-A KUBE-SERVICES ! -s 10.244.0.0/16 -d 10.96.203.6/32 -p tcp -m comment --comment "default/httpd-svc: cluster IP" -m tcp --dport 8080 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.96.203.6/32 -p tcp -m comment --comment "default/httpd-svc: cluster IP" -m tcp --dport 8080 -j KUBE-SVC-RL3JAE4GN7VOGDGP

第一条源自 10.244.0.0/16(集群内 Pod IP)要访问 httpd-svc 则允许

其他源访问 httpd-svc,跳转到 ‘KUBE-SVC-RL3JAE4GN7VOGDGP’ 规则

# iptables-save | grep KUBE-SVC-RL3JAE4GN7VOGDGP
:KUBE-SVC-RL3JAE4GN7VOGDGP - [0:0]
-A KUBE-SERVICES -d 10.96.203.6/32 -p tcp -m comment --comment "default/httpd-svc: cluster IP" -m tcp --dport 8080 -j KUBE-SVC-RL3JAE4GN7VOGDGP
-A KUBE-SVC-RL3JAE4GN7VOGDGP -m comment --comment "default/httpd-svc:" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-CR63JSDONEUBE2YK
-A KUBE-SVC-RL3JAE4GN7VOGDGP -m comment --comment "default/httpd-svc:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-Y5EOPQEI6R2HKSKZ
-A KUBE-SVC-RL3JAE4GN7VOGDGP -m comment --comment "default/httpd-svc:" -j KUBE-SEP-XY6KDITI4WWURGO2

所有 ‘KUBE-SVC-RL3JAE4GN7VOGDGP’ 规则中:

  • 0.33332999982(1/3)概率跳转到 ‘KUBE-SEP-CR63JSDONEUBE2YK’ 规则
  • 剩下的 2/3 中,0.5(1/3)概率跳转到 ‘KUBE-SEP-Y5EOPQEI6R2HKSKZ’ 规则
  • 其他的(1/3)跳转到 ‘KUBE-SEP-XY6KDITI4WWURGO2’ 规则

分别查看这三个规则对应后端

-A KUBE-SEP-CR63JSDONEUBE2YK -p tcp -m comment --comment "default/httpd-svc:" -m tcp -j DNAT --to-destination 10.244.1.28:80
-A KUBE-SEP-Y5EOPQEI6R2HKSKZ -p tcp -m comment --comment "default/httpd-svc:" -m tcp -j DNAT --to-destination 10.244.1.29:80
-A KUBE-SEP-XY6KDITI4WWURGO2 -p tcp -m comment --comment "default/httpd-svc:" -m tcp -j DNAT --to-destination 10.244.2.22:80

实现了从 Cluster IP 到 Pod IP 的均衡负载(轮询)

集群中每个节点都配置了相同 iptables 规则,保证集群内都可以正常访问 Service

3- 通过 DNS 访问 Service

查看 kube-dns 组件

# kubectl get svc -n kube-system -o wide | grep dns
kube-dns               10.96.0.10       <none>        53/UDP,53/TCP   89d       k8s-app=kube-dns

当新的 Service 创建后,kube-dns 会添加该 Service 的 DNS 记录,

可以通过 <Service_Name>.<Namespace_Name> 访问 Service,

相同 namespace 可以直接访问 <Service_name>

# kubectl run busybox --rm -it --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget httpd-svc.default:8080
Connecting to httpd-svc.default:8080 (10.96.203.6:8080)
index.html           100% |*****************************************************************************************|    45   0:00:00 ETA
/ # 
/ # nslookup httpd-svc
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      httpd-svc
Address 1: 10.96.203.6 httpd-svc.default.svc.cluster.local
/ # 

可见 httpd-svc 的完整域名为 ‘httpd-svc.default.svc.cluster.local’

4- 集群外部访问 Service

  • 通过 ‘ClusterIP’ - 集群内的节点和 Pod 可以访问,但集群外部无法联通

  • 通过 ‘NodePort’ - Service 使用集群节点的静态端口对外提供服务,外部访问 <NodeIP>:<NodePort>

在一个 Yaml 文件中创建 Deployment 和 Service,多种资源使用 ‘—’ 分隔

# vim myhttpd.yaml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: myhttpd
spec:
  replicas: 3
  template:
    metadata:
      labels:
        run: httpd
    spec:
      containers:
      - name: httpd
        image: httpd
        ports:
        - containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: myhttpd-svc
spec:
  type: NodePort
  selector:
    run: httpd
  ports:
  - protocol: TCP
    nodePort: 30000
    port: 8080
    targetPort: 80

文件中定义了三种端口

  • ‘nodePort’ - 节点上监听端口
  • ‘port’ - ClusterIP 监听端口
  • ‘targetPort’ - Pod 监听端口
# kubectl apply -f myhttpd.yaml 
deployment "myhttpd" created
service "myhttpd-svc" created

# kubectl get deployment -o wide
NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE       CONTAINER(S)   IMAGE(S)   SELECTOR
myhttpd   3         3         3            3           32s       httpd          httpd      run=httpd

# kubectl get pods -o wide
NAME                      READY     STATUS    RESTARTS   AGE       IP            NODE
myhttpd-741508562-lt4kr   1/1       Running   0          3h        10.244.1.32   f16-7-kubernetes02
myhttpd-741508562-p3h5w   1/1       Running   0          3h        10.244.1.33   f16-7-kubernetes02
myhttpd-741508562-sm9ft   1/1       Running   0          3h        10.244.2.26   f16-8-kubernetes03

# kubectl get svc myhttpd-svc
NAME          CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
myhttpd-svc   10.104.223.18   <nodes>       8080:30000/TCP   1m

# netstat -ntlp | grep 30000
tcp6       0      0 :::30000                :::*                    LISTEN      3390/kube-proxy

各节点均可访问

# curl F16-6-kubernetes01:30000
<html><body><h1>It works!</h1></body></html>

# curl F16-7-kubernetes02:30000
<html><body><h1>It works!</h1></body></html>

# curl F16-8-kubernetes03:30000
<html><body><h1>It works!</h1></body></html>

查看 iptalbes 规则

# iptables-save | grep 30000
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/myhttpd-svc:" -m tcp --dport 30000 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/myhttpd-svc:" -m tcp --dport 30000 -j KUBE-SVC-7P7YXYLZA3ZMJCMD

访问节点 30000 端口的请求应用规则 ‘KUBE-SVC-7P7YXYLZA3ZMJCMD’

# iptables-save | grep KUBE-SVC-7P7YXYLZA3ZMJCMD
:KUBE-SVC-7P7YXYLZA3ZMJCMD - [0:0]
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/myhttpd-svc:" -m tcp --dport 30000 -j KUBE-SVC-7P7YXYLZA3ZMJCMD
-A KUBE-SERVICES -d 10.104.223.18/32 -p tcp -m comment --comment "default/myhttpd-svc: cluster IP" -m tcp --dport 8080 -j KUBE-SVC-7P7YXYLZA3ZMJCMD
-A KUBE-SVC-7P7YXYLZA3ZMJCMD -m comment --comment "default/myhttpd-svc:" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-5JFNR2OVUEO7ADZR
-A KUBE-SVC-7P7YXYLZA3ZMJCMD -m comment --comment "default/myhttpd-svc:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-MXGVDRPRKF4FCFQ7
-A KUBE-SVC-7P7YXYLZA3ZMJCMD -m comment --comment "default/myhttpd-svc:" -j KUBE-SEP-3ZRQHJQFDZH6HPK7

规则 ‘KUBE-SVC-7P7YXYLZA3ZMJCMD’ 以各 1/3 比率分配到

‘KUBE-SEP-5JFNR2OVUEO7ADZR’;

‘KUBE-SEP-MXGVDRPRKF4FCFQ7’;

‘KUBE-SEP-3ZRQHJQFDZH6HPK7’

查看这三条规则

# iptables-save | grep KUBE-SEP-5JFNR2OVUEO7ADZR
:KUBE-SEP-5JFNR2OVUEO7ADZR - [0:0]
-A KUBE-SEP-5JFNR2OVUEO7ADZR -s 10.244.1.32/32 -m comment --comment "default/myhttpd-svc:" -j KUBE-MARK-MASQ
-A KUBE-SEP-5JFNR2OVUEO7ADZR -p tcp -m comment --comment "default/myhttpd-svc:" -m tcp -j DNAT --to-destination 10.244.1.32:80

# iptables-save | grep KUBE-SEP-MXGVDRPRKF4FCFQ7
:KUBE-SEP-MXGVDRPRKF4FCFQ7 - [0:0]
-A KUBE-SEP-MXGVDRPRKF4FCFQ7 -s 10.244.1.33/32 -m comment --comment "default/myhttpd-svc:" -j KUBE-MARK-MASQ
-A KUBE-SEP-MXGVDRPRKF4FCFQ7 -p tcp -m comment --comment "default/myhttpd-svc:" -m tcp -j DNAT --to-destination 10.244.1.33:80

# iptables-save | grep KUBE-SEP-3ZRQHJQFDZH6HPK7
:KUBE-SEP-3ZRQHJQFDZH6HPK7 - [0:0]
-A KUBE-SEP-3ZRQHJQFDZH6HPK7 -s 10.244.2.26/32 -m comment --comment "default/myhttpd-svc:" -j KUBE-MARK-MASQ
-A KUBE-SEP-3ZRQHJQFDZH6HPK7 -p tcp -m comment --comment "default/myhttpd-svc:" -m tcp -j DNAT --to-destination 10.244.2.26:80

最终请求落到了 Pod 上

更新时间: