K8s Service对外暴露端口与代理方式

  • Service概述
  • Service服务类型
  • userspace代理模式
  • iptables 代理模式
  • IPVS 代理模式
  • 实例

Service概述

Kubernetes Service定义了这样一种抽象:逻辑上的一组 Pod,一种可以访问它们的策略 —— 通常被称为微服务。这一组 Pod 能够被 Service 访问到,通常是通过 selector实现的。

Service可以提供负载均衡的能力,但是使用上存在如下限制:
只能提供4层负载均衡能力,而没有7层功能。有时我们可能需要更多的匹配规则来转发请求,这点上4层负载均衡是不支持的

Service服务类型

Kubernetes 中Service有以下类型:

  • ClusterIP:默认类型,自动分配一个仅Cluster内部可以访问的虚拟IP
  • NodePort:通过每个 Node 上的 IP 和静态端口(NodePort)暴露服务。以ClusterIP为基础,NodePort 服务会路由到 ClusterIP 服务。通过请求 :,可以从集群的外部访问一个集群内部的 NodePort 服务。
  • LoadBalancer:使用云提供商的负载均衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务。
  • ExternalName:通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容(例如,foo.bar.example.com)。没有任何类型代理被创建。

userspace代理模式

这种模式,kube-proxy 会监视 Kubernetes master 对 Service 对象和 Endpoints 对象的添加和移除。 对每个 Service,它会在本地 Node 上打开一个端口(随机选择)。 任何连接到“代理端口”的请求,都会被代理到 Service 的backend Pods 中的某个上面(如 Endpoints 所报告的一样)。 使用哪个 backend Pod,是 kube-proxy 基于 SessionAffinity 来确定的。

最后,它配置 iptables 规则,捕获到达该 Service 的 clusterIP(是虚拟 IP)和 Port 的请求,并重定向到代理端口,代理端口再代理请求到 backend Pod。

默认情况下,userspace模式下的kube-proxy通过循环算法选择后端。

默认的策略是,通过 round-robin 算法来选择 backend Pod。

iptables 代理模式

这种模式,kube-proxy 会监视 Kubernetes 控制节点对 Service 对象和 Endpoints 对象的添加和移除。 对每个 Service,它会配置 iptables 规则,从而捕获到达该 Service 的 clusterIP 和端口的请求,进而将请求重定向到 Service 的一组 backend 中的某个上面。对于每个 Endpoints 对象,它也会配置 iptables 规则,这个规则会选择一个 backend 组合。

默认的策略是,kube-proxy 在 iptables 模式下随机选择一个 backend。

使用 iptables 处理流量具有较低的系统开销,因为流量由 Linux netfilter 处理,而无需在用户空间和内核空间之间切换。 这种方法也可能更可靠。

如果 kube-proxy 在 iptables模式下运行,并且所选的第一个 Pod 没有响应,则连接失败。 这与userspace模式不同:在这种情况下,kube-proxy 将检测到与第一个 Pod 的连接已失败,并会自动使用其他后端 Pod 重试。

我们可以使用 Pod readiness 探测器 验证后端 Pod 是否可以正常工作,以便 iptables 模式下的 kube-proxy 仅看到测试正常的后端。这样做意味着可以避免将流量通过 kube-proxy 发送到已知已失败的Pod。

IPVS 代理模式

在 ipvs 模式下,kube-proxy监视Kubernetes服务(Service)和端点(Endpoints),调用 netlink 接口相应地创建 IPVS 规则, 并定期将 IPVS 规则与 Kubernetes服务(Service)和端点(Endpoints)同步。该控制循环可确保 IPVS 状态与所需状态匹配。访问服务(Service)时,IPVS 将流量定向到后端Pod之一。

IPVS代理模式基于类似于 iptables 模式的 netfilter 挂钩函数,但是使用哈希表作为基础数据结构,并且在内核空间中工作。 这意味着,与 iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通信的延迟要短,并且在同步代理规则时具有更好的性能。与其他代理模式相比,IPVS 模式还支持更高的网络流量吞吐量。

IPVS提供了更多选项来平衡后端Pod的流量。这些是:

rr: round-robin //循环
 lc: least connection (smallest number of open connections) //最少连接(最少打开连接数)
 dh: destination hashing //目标地址哈希
 sh: source hashing //源地址哈希
 sed: shortest expected delay //最短预期延迟
 nq: never queue //从不排队

实例

创建一个deployment副本数3,然后滚动更新镜像版本,并记录这个更新记录,最后再回滚到上一个版本

[root@master ~]# vi deploy.yml
[root@master ~]# cat deploy.yml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
   matchLabels:
     app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80

[root@master ~]# kubectl apply -f deploy.yml
deployment.apps/nginx-deployment created

[root@master ~]# kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-66dd47b7cd-mxpdt   1/1     Running   0          2m11s
nginx-deployment-66dd47b7cd-rvz4v   1/1     Running   0          2m11s
nginx-deployment-66dd47b7cd-wz5t6   1/1     Running   0          2m11s

#使用 nginx:1.9.1 的镜像来代替原来的 nginx的镜像
[root@master ~]# kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
deployment.apps/nginx-deployment image updated


nginx-deployment-9b8f648df-8xlt9   1/1     Running   0          6m36s
nginx-deployment-9b8f648df-bqbqg   1/1     Running   0          6m36s
nginx-deployment-9b8f648df-dprm6   1/1     Running   0          6m36s

//回滚
[root@master ]# kubectl rollout undo deployment/nginx-deployment --to-revision=1 
deployment.apps/test rolled back

给一个应用扩容副本数为3

[root@master ~]# kubectl  apply -f cluster.yml 
deployment.apps/apache created

[root@master ~]# kubectl  get pods
NAME                          READY   STATUS    RESTARTS   AGE
pod/apache-599bc546b8-6tctl   1/1     Running   0          28s


[root@master ~]# kubectl scale  deployment apache --replicas 4
deployment.apps/apache scaled
[root@master ~]# kubectl  get pods
NAME                          READY   STATUS              RESTARTS   AGE
pod/apache-599bc546b8-6gx4p   0/1     ContainerCreating   0          2s
pod/apache-599bc546b8-6tctl   1/1     Running             0          2m3s
pod/apache-599bc546b8-8qzr4   0/1     ContainerCreating   0          2s
pod/apache-599bc546b8-j48v5   0/1     ContainerCreating   0          2s

创建一个pod,其中运行着nginx、redis、memcached 3个容器

[root@master ~]# vim pod.yml 
---
apiVersion: v1
kind: Pod
metadata:
  name: hellok8s
  namespace: default
  labels:
    app: myapp
spec:
  containers:
  - name: mynginx
    image: nginx 
    ports:
    - containerPort: 80
  - name: myredis
    image: redis
    ports:
    - containerPort: 6379
  - name: memcached
    image: memcached 

[root@master ~]# kubectl apply -f pod.yml 
pod/hellok8s created


[root@master ~]# kubectl  get pods
NAME       READY   STATUS    RESTARTS   AGE
hellok8s   3/3     Running   0          2m49s

给一个pod创建service,并可以通过ClusterlP/NodePort访问

[root@master ~]# vi nodeport.yml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: apache
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: apache
  template: 
    metadata:
      labels:
        app: apache 
    spec:
      containers:
      - image: 1968046xux/apache:v1
        imagePullPolicy: IfNotPresent
        name: apache

---
apiVersion: v1
kind: Service
metadata:
  name: apache
  namespace: default
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
    nodePort: 30000   //指定对外端口
  selector:
    app: apache
  type: NodePort  

[root@master ~]# kubectl  apply -f nodeport.yml 
deployment.apps/apache created
service/apache created
[root@master ~]# kubectl get pods,svc
NAME                          READY   STATUS    RESTARTS   AGE
pod/apache-599bc546b8-w6xnd   1/1     Running   0          10s

NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
service/apache       NodePort    10.96.90.92   <none>        80:30000/TCP   10s
service/kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP        4d12h
[root@master ~]# curl 192.168.172.142:30000
this is a test page 1

创建deployment和service,使用busybox容器nslookup解析service

[root@master manifest]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        3d22h
web          NodePort    10.102.175.55   <none>        80:30000/TCP   7m10s

[root@master manifest]# kubectl run -it b1 --image busybox -- /bin/sh
If you don't see a command prompt, try pressing enter.
/ # nslookup web.default.svc.cluster.local
Server:		10.96.0.10
Address:	10.96.0.10:53