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