K8s暴露端口与代理方式

K8s暴露端口与代理方式

kubernetes暴露端口的方式

方式1:clusterIP
此类型会提供一个集群内部的虚拟IP(与pod不在同一网段),以供集群内部的pod之间通信使用。clusterIP也是kubernetes service的默认类型
主要需要以下几个组件的协同工作
apiservice:在创建service时,apiserver接收到请求以后将数据存储到etcd中。
kube-proxy:k8s的每个节点中都有该进程,负责实现service功能,这个进程负责感知service,pod的变化,并将变化的信息写入本地的iptables中
iptables:使用NAT等技术奖virtuallp的流量转至endpoint中

方式2:NodePort
NodePort模式除了使用cluster ip外,也将service的port映射到每个node的一个指定内部的port上,映射的每个node的内部port都一样。为每个节点暴露一个端口,通过nodeIP+nodeport可以访问你这个服务,同时服务依然会有cluster类型的ip+port。内部通过clusterip方式访问,外部通过nodeport方式访问

方式3:loadbalancer
loadbalancer在nodeport基础上,k8s可以请求底层云平台创建一个负载均衡器,将每个node作为后端,进行服务分发,该模式需要底层云平台(例如GCE)支持

方式4:lngress
lngress,是一种http方式的路由转发机制由lngress controller和http代理服务器组合而成,lngress controller实例监控kubernetes api,实时更新http代理服务器的转发规则。http代理服务器有GCE load-balancer、haproxy、nginx等开源方案

​ service是一个抽象概念,定义了一个服务的多个pod逻辑合集和访问pod的策略,一般把service称为微服务.举个例子一个a服务运行3个pod,b服务怎么访问a服务的pod,pod的ip都不是持久化的重启之后就会有变化。这时候b服务可以访问跟a服务绑定的service,service信息是固定的提前告诉b就行了,service通过Label Selector跟a服务的pod绑定,无论a的pod如何变化对b来说都是透明的.

kubernetes代理方式

​ k8s群集中的每个节点都运行一个kube-proxy的组件,kube-proxy其实是一个代理层负责实现service.kube-proxy代理模式有两种:

代理模式:userspace

​ 客户端访问ServiceIP(clusterIP)请求会先从用户空间到内核中的iptables,然后回到用户空间kube-proxy,kube-proxy负责代理工作。具体细节:
​ 每个service都会由kube-proxy在node节点上起一个随机的代理端口,iptables会捕捉clusterIP上的端口(targetPort)流量重定向代理端口,访问代理端口的任何连接都会被代理到service后端的某一个pod,默认情况下对

在这里插入图片描述

代理模式:iptables

​ 客户端访问ServiceIP(clusterIP)请求会由iptables直接重定向到后端,具体细节:每个service都会由kube-proxy生成一组iptables规则,iptables会捕捉clusterIP上的端口(targetPort)流量重定向后端某一个pod,默认对pod的选择是随机的

在这里插入图片描述
Kubernetes v1.2之前默认是userspace之后是iptables模式,iptables模式性能和可靠性更好,但是iptables模式依赖健康检查,在没有健康检查的情况下如果一个pod不响应,iptables模式不会切换另一个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
    注意:要在 IPVS 模式下运行 kube-proxy,必须在启动 kube-proxy 以前使 IPVS Linux 在节点上可用。 当 kube-proxy 以 IPVS 代理模式启动时,它将验证 IPVS 内核模块是否可用。 若是未检测到 IPVS 内核模块,则 kube-proxy 将退回到以 iptables 代理模式运行。
    在这里插入图片描述

Service

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

举例:考虑一个图片处理 backend,它运行了3个副本。这些副本是可互换的 —— frontend 不需要关心它们调用了哪一个 backend 副本。 然而组成这一组 backend 程序的 Pod 实际上可能会发生变化,frontend 客户端不必知道,并且也不需要跟踪这一组 backend 的状态。Service 定义的抽象可以解耦这种关联。

Service能够提供负载均衡的能力,可是使用上存在以下限制:

只能提供4层负载均衡能力,而没有7层功能。有时咱们可能须要更多的匹配规则来转发请求,这点上4层负载均衡是不支持的、
如web访问的service服务示例图:
在这里插入图片描述
VIP和Service代理
在 Kubernetes 集群中,每一个 Node 运行一个 kube-proxy 进程。kube-proxy 负责为 Service 实现了一种 VIP(虚拟 IP)的形式,而不是 ExternalName 的形式。后端

从Kubernetes v1.0开始,已经可使用 userspace代理模式。Kubernetes v1.1添加了 iptables 代理模式,在 Kubernetes v1.2 中kube-proxy 的 iptables 模式成为默认设置。Kubernetes v1.8添加了 ipvs 代理模式。

为何不使用 DNS 轮询?
缘由以下:

DNS 实现的历史由来已久,它不遵照记录 TTL,而且在名称查找到结果后会对其进行缓存。

有些应用程序仅执行一次 DNS 查找,并没有限期地缓存结果。

即便应用和库进行了适当的从新解析,DNS 记录上的 TTL 值低或为零也可能会给 DNS 带来高负载,从而使管理变得困难。

由于有缓存,所以不合适。

Service服务类型

Kubernetes 中Service有如下4中类型:

ClusterIP:默认类型,自动分配一个仅Cluster内部能够访问的虚拟IP

NodePort:经过每一个 Node 上的 IP 和静态端口(NodePort)暴露服务。以ClusterIP为基础,NodePort 服务会路由到 ClusterIP 服务。经过请求 :,能够从集群的外部访问一个集群内部的 NodePort 服务。

LoadBalancer:使用云提供商的负载均衡器,能够向外部暴露服务。外部的负载均衡器能够路由到 NodePort 服务和 ClusterIP 服务。

ExternalName:经过返回 CNAME 和它的值,能够将服务映射到 externalName 字段的内容(例如,foo.bar.example.com)。没有任何类型代理被建立。
须要注意的是:Service 可以将一个接收 port 映射到任意的 targetPort。默认状况下,targetPort 将被设置为与 port 字段相同的值。

Service域名格式: ( s e r v i c e n a m e ) . (service name). (servicename).(namespace).svc.cluster.local,其中 cluster.local 为指定的集群的域名

ClusterIP:

默认类型,自动分配一个仅Cluster内部能够访问的虚拟IP

# 编写network.yaml资源清单文件

[root@master ~]# vi network.yaml 
apiVersion: apps/v1 
kind: Deployment 
metadata: 
  name: myapp-deploy 
  namespace: default 
spec: 
  replicas: 2 
  selector: 
    matchLabels: 
      app: myapp 
      release: v1
  template:
    metadata: 
      labels: 
        app: myapp 
        release: v1 
    spec: 
      containers: 
      - name: myapp
        image: syblyw0806/httpd:v1.0
        imagePullPolicy: IfNotPresent
---
apiVersion: v1 
kind: Service 
metadata: 
  name: myapp-nodeport
  namespace: default
spec: 
  type: ClusterIP
  selector: 
    app: myapp
    release: v1
  ports: 
  - name: httpd
    port: 80
    targetPort: 80

# 应用资源清单文件,创建资源
[root@master ~]# kubectl apply -f network.yaml   
deployment.apps/myapp-deploy created
service/myapp-nodeport created

# 查看pod,service运行情况
[root@master ~]# kubectl get pods,svc
NAME                                READY   STATUS    RESTARTS   AGE
pod/myapp-deploy-667bd747b6-6mkmq   1/1     Running   0          6m30s
pod/myapp-deploy-667bd747b6-wp65f   1/1     Running   0          6m30s

NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/kubernetes       ClusterIP   10.96.0.1       <none>        443/TCP   5d22h
service/myapp-nodeport   ClusterIP   10.98.209.123   <none>        80/TCP    6m30s

# 查看iptables,规则

[root@master ~]# iptables -t nat -nvL | grep 'myapp-nodeport'
    0     0 KUBE-MARK-MASQ  all  --  *      *       10.244.2.173         0.0.0.0/0            /* default/myapp-nodeport:httpd */
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/myapp-nodeport:httpd */ tcp to:10.244.2.173:80
    0     0 KUBE-MARK-MASQ  all  --  *      *       10.244.1.126         0.0.0.0/0            /* default/myapp-nodeport:httpd */
    2   120 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/myapp-nodeport:httpd */ tcp to:10.244.1.126:80
    2   120 KUBE-SVC-UJB7KAYNZVW7NK6H  tcp  --  *      *       0.0.0.0/0            10.98.209.123        /* default/myapp-nodeport:httpd cluster IP */ tcp dpt:80
    2   120 KUBE-MARK-MASQ  tcp  --  *      *      !10.244.0.0/16        10.98.209.123        /* default/myapp-nodeport:httpd cluster IP */ tcp dpt:80
    2   120 KUBE-SEP-WXLK2WHO6A3V7JDH  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/myapp-nodeport:httpd */ statistic mode random probability 0.50000000000
    0     0 KUBE-SEP-BXPFXJRGQ62K7TWT  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/myapp-nodeport:httpd */


# 访问测试
[root@master ~]# curl 10.98.209.123
This is test!
NodePort

nodePort的原理在于在node上开了一个端口,将向该端口的流量导入到kube-proxy,然后由 kube-proxy进一步到给对应的pod

# 修改资源定义文件

[root@master ~]# vi network.yaml 
apiVersion: apps/v1 
kind: Deployment 
metadata: 
  name: myapp-deploy 
  namespace: default 
spec: 
  replicas: 2 
  selector: 
    matchLabels: 
      app: myapp 
      release: v1
  template:
    metadata: 
      labels: 
        app: myapp 
        release: v1 
    spec: 
      containers: 
      - name: myapp
        image: syblyw0806/httpd:v1.0
        imagePullPolicy: IfNotPresent
---
apiVersion: v1 
kind: Service 
metadata: 
  name: myapp-nodeport
  namespace: default
spec: 
  type: NodePort  // 指定NodePort类型
  selector: 
    app: myapp
    release: v1
  ports: 
  - name: httpd
    port: 80
    targetPort: 80
    nodePort: 30002   //指定对外端口

# 应用修改后的资源定义文件,重启pods
[root@master ~]# kubectl apply -f network.yaml 
deployment.apps/myapp-deploy unchanged
service/myapp-nodeport configured

# 查看pods,service状态
[root@master ~]# kubectl get pod,svc
NAME                                READY   STATUS    RESTARTS   AGE
pod/myapp-deploy-667bd747b6-6mkmq   1/1     Running   0          30m
pod/myapp-deploy-667bd747b6-wp65f   1/1     Running   0          30m

NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/kubernetes       ClusterIP   10.96.0.1       <none>        443/TCP        5d23h
service/myapp-nodeport   NodePort    10.98.209.123   <none>        80:30002/TCP   30m

# 查看iptables 规则
[root@master ~]# iptables -t nat -nvL | grep 'myapp-nodeport'
    1    60 KUBE-SVC-UJB7KAYNZVW7NK6H  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/myapp-nodeport:httpd */ tcp dpt:30002
    0     0 KUBE-MARK-MASQ  all  --  *      *       10.244.2.173         0.0.0.0/0            /* default/myapp-nodeport:httpd */
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/myapp-nodeport:httpd */ tcp to:10.244.2.173:80
    0     0 KUBE-MARK-MASQ  all  --  *      *       10.244.1.126         0.0.0.0/0            /* default/myapp-nodeport:httpd */
    1    60 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/myapp-nodeport:httpd */ tcp to:10.244.1.126:80
    0     0 KUBE-SVC-UJB7KAYNZVW7NK6H  tcp  --  *      *       0.0.0.0/0            10.98.209.123        /* default/myapp-nodeport:httpd cluster IP */ tcp dpt:80
    0     0 KUBE-MARK-MASQ  tcp  --  *      *      !10.244.0.0/16        10.98.209.123        /* default/myapp-nodeport:httpd cluster IP */ tcp dpt:80
    1    60 KUBE-MARK-MASQ  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/myapp-nodeport:httpd */ tcp dpt:30002
    1    60 KUBE-SEP-WXLK2WHO6A3V7JDH  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/myapp-nodeport:httpd */ statistic mode random probability 0.50000000000
    0     0 KUBE-SEP-BXPFXJRGQ62K7TWT  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/myapp-nodeport:httpd */

# 访问测试
[root@master ~]# curl 192.168.58.110:30002
This is test!
ExternalName类型示例

这种类型的Service经过返回CNAME和它的值,能够将服务映射到externalName字段的内容(例如:my.k8s.example.com;能够实现跨namespace名称空间访问)。ExternalName Service是Service的特例,它没有selector,也没有定义任何的端口和Endpoint。相反的,对于运行在集群外部的服务,它经过返回该外部服务的别名这种方式提供服务。

# 修改netwoek.yanl资源定义文件

[root@master ~]# vi network.yaml 
apiVersion: apps/v1 
kind: Deployment 
metadata: 
  name: myapp-deploy 
  namespace: default 
spec: 
  replicas: 2 
  selector: 
    matchLabels: 
      app: myapp 
      release: v1
  template:
    metadata: 
      labels: 
        app: myapp 
        release: v1 
    spec: 
      containers: 
      - name: httpd
        image: syblyw0806/httpd:v2.0  //此处将镜像,更换为基于contos编译的httpd镜像
        imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata: 
  name: myapp-externalname
  namespace: default
spec: 
  type: ExternalName  //指定类型
  externalName: my.k8s.example.com

# 使用修改过后的资源定义文件,重启pods
[root@master ~]# kubectl apply -f network.yaml 
deployment.apps/myapp-deploy configured
service/myapp-externalname unchanged


# 查看pod,service状态
[root@master ~]# kubectl get pod,svc
NAME                               READY   STATUS    RESTARTS   AGE
pod/myapp-deploy-6768948cc-4tp9j   1/1     Running   0          9m8s
pod/myapp-deploy-6768948cc-x5ncr   1/1     Running   0          9m6s

NAME                         TYPE           CLUSTER-IP   EXTERNAL-IP          PORT(S)   AGE
service/kubernetes           ClusterIP      10.96.0.1    <none>               443/TCP   6d
service/myapp-externalname   ExternalName   <none>       my.k8s.example.com   <none>    32m

# 此处Type,改为 ExternalName模式了

宿主机dig命令安装

# 进入pods中的某个容器中

[root@master ~]# kubectl exec -it myapp-deploy-6768948cc-4tp9j /bin/sh  
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
sh-4.4# /bin/bash

[root@myapp-deploy-6768948cc-4tp9j src]# ls
apr-1.7.0  apr-util-1.6.1  debug  httpd-2.4.48  kernels
[root@myapp-deploy-6768948cc-4tp9j src]# cd
[root@myapp-deploy-6768948cc-4tp9j ~]# yum install -y bind-utils    // 安装包组

coredns记录信息如下

# 经过 nslookup 访问

[root@myapp-deploy-6768948cc-4tp9j ~]# nslookup myapp-externalname.default.svc.cluster.local
Server:         10.96.0.10
Address:        10.96.0.10#53

myapp-externalname.default.svc.cluster.local    canonical name = my.k8s.example.com.
** server can't find my.k8s.example.com: NXDOMAIN

# 其中  10.96.0.10 为 coredns IP
# myapp-externalname.default.svc.cluster.local 为Service域名。格式为:$(service name).$(namespace).svc.cluster.local,其中 cluster.local 指定的集群的域名

# 经过 dig 访问
[root@myapp-deploy-6768948cc-4tp9j ~]# dig -t A myapp-externalname.default.svc.cluster.local.@10.96.0.10

; <<>> DiG 9.11.26-RedHat-9.11.26-6.el8 <<>> -t A myapp-externalname.default.svc.cluster.local.@10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 24780
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 1293df4bb1831323 (echoed)
;; QUESTION SECTION:
;myapp-externalname.default.svc.cluster.local.\@10.96.0.10. IN A

;; Query time: 1012 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Sat Dec 25 04:08:21 UTC 2021
;; MSG SIZE  rcvd: 97
ExternalIP示例

若是外部的 IP 路由到集群中一个或多个 Node 上,Kubernetes Service 会被暴露给这些 externalIPs。经过外部 IP(做为目的 IP 地址)进入到集群,打到 Service 端口上的流量,将会被路由到 Service 的 Endpoint 上。

externalIPs 不会被 Kubernetes 管理,它属于集群管理员的职责范畴。
根据 Service 的规定,externalIPs 能够同任意的 ServiceType 来一块儿指定。在下面的例子中,my-service 能够在模拟外网IP(“10.0.0.240”)(externalIP:port) 上被客户端访问。

# 编写 network.yaml资源定义文件

[root@master ~]# vi network.yaml 
apiVersion: apps/v1 
kind: Deployment 
metadata: 
  name: myapp-deploy 
  namespace: default 
spec: 
  replicas: 2 
  selector: 
    matchLabels: 
      app: myapp 
      release: v1
  template:
    metadata: 
      labels: 
        app: myapp 
        release: v1 
    spec: 
      containers: 
      - name: httpd
        image: syblyw0806/httpd:v2.0
        imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata: 
  name: myapp-externalip
  namespace: default
spec: 
  selector: 
    app: myapp
    release: v1
  ports: 
  - name: httpd
    port: 80
    targetPort: 80
  externalIPs: 
    - 10.0.0.240


# 应用资源定义文件,部署资源
[root@master ~]# kubectl apply -f network.yaml 
deployment.apps/myapp-deploy unchanged
service/myapp-externalip created

# 查看pods,service状态
[root@master ~]# kubectl get svc -o wide
NAME                 TYPE           CLUSTER-IP      EXTERNAL-IP          PORT(S)   AGE     SELECTOR
kubernetes           ClusterIP      10.96.0.1       <none>               443/TCP   6d3h    <none>
myapp-externalip     ClusterIP      10.99.109.176   10.0.0.240           80/TCP    13s     app=myapp,release=v1
myapp-externalname   ExternalName   <none>          my.k8s.example.com   <none>    3h45m   <none>

# curl访问,经过ClusterIP
[root@master ~]# curl 10.99.109.176
<html><body><h1>It works!</h1></body></html>


# curl访问,经过ExternalIP
[root@master ~]# curl 10.0.0.240
<html><body><h1>It works!</h1></body></html>
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值