Service概念
当谈到容器编排和管理时,Kubernetes(简称K8s)无疑是当今最热门的选择之一。而在K8s中,Service(服务)是一个至关重要的概念,它为应用程序提供了稳定的网络终结点,使得微服务能够相互通信,无论它们在集群中的位置如何。
K8s Service的魅力在于它为应用程序提供了一个虚拟的IP地址,通过该地址,其他应用程序可以轻松地访问到服务提供的功能。这为开发者提供了更高层次的抽象,使得他们无需关心底层的网络细节,而专注于应用程序的逻辑。
使用K8s Service,我们可以轻松实现负载均衡,确保应用程序的高可用性。而且,Service的选择不仅仅局限于单一的负载均衡算法,K8s支持多种不同的Service类型,如ClusterIP
、NodePort
、和LoadBalancer
,开发者可以根据应用程序的需求选择最适合的类型。
此外,通过Service的标签选择器,我们可以方便地进行服务发现,无论是内部服务还是外部服务。这为构建复杂的微服务架构提供了便利,使得各个微服务可以松散耦合,更好地实现了容器编排的目标。
Service的三种类型
Cluster IP(默认类型)
ClusterIP是默认的Service类型。它为集群内部的Pod提供了一个虚拟的IP地址,使得同一集群内的其他服务可以通过该虚拟IP与该Service通信。
适用于那些只需要在集群内部进行通信的服务。对于集群外的请求,需要通过其他手段,比如Ingress来实现访问。
apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: my-app ports: - name: http protocol: TCP port: 80 targetPort: 9376
上述 YAML 文件可用来创建一个 Service:
- 名字为 my-service
- 目标端口为 TCP 9376
- 选取所有包含标签 app=my-app 的 Pod
NodePort
NodePort类型的Service会为每个Node分配一个静态端口,并通过该端口将流量路由到Service。这使得外部可以通过Node的IP地址和分配的静态端口访问该Service。
适用于需要从集群外部访问Service的场景,但不适用于生产环境的高负载服务,因为NodePort会暴露端口到整个集群,可能会引起端口冲突和安全隐患。
apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: my-app ports: - name: http protocol: TCP port: 80 targetPort: 9376 type: NodePort
LoadBlancer
LoadBalancer类型的Service通过云服务提供商的负载均衡器(如AWS ELB、GCP LoadBalancer)为Service分配一个外部可访问的IP,并将流量均衡分配到集群中的Pod。
适用于需要在集群外提供稳定访问入口的场景,且云服务提供商支持该类型。
apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: my-app ports: - name: http protocol: TCP port: 80 targetPort: 9376 type: LoadBalancer
这三种Service类型满足了不同场景下的需求,开发者可以根据应用程序的特性和部署环境选择适合的类型。详细关于Service的知识点查阅官方文档。
代理模式
Kubernetes 支持三种 proxy mode(代理模式),他们的版本兼容性如下:
代理模式 |
Kubernetes 版本 |
是否默认 |
User space proxy mode |
v1.0 + |
|
Iptables proxy mode |
v1.1 + |
默认 |
Ipvs proxy mode |
v1.8 + |
User space 代理模式
在user space proxy mode
下:
kube-proxy
监听kubernetes master
以获得添加和移除Service / Endpoint
的事件kube-proxy
在其所在的节点(每个节点都有kube-proxy
)上为每一个Service
打开一个随机端口kube-proxy
安装iptables
规则,将发送到该Service
的ClusterIP
(虚拟 IP)/ Port 的请求重定向到该随机端口- 任何发送到该随机端口的请求将被代理转发到该
Service
的后端Pod
上(kube-proxy 从 Endpoint 信息中获得可用 Pod) kube-proxy
在决定将请求转发到后端哪一个Pod
时,默认使用round-robin
(轮询)算法,并会考虑到Service
中的SessionAffinity
的设定。
Iptables 代理模式
在 iptables proxy mode
下:
kube-proxy
监听kubernetes master
以获得添加和移除Service / Endpoint
的事件kube-proxy
在其所在的节点(每个节点都有 kube-proxy)上为每一个Service
安装iptable
规则iptables
将发送到Service
的ClusterIP / Port
的请求重定向到Service
的后端Pod
上
- 对于
Service
中的每一个Endpoint
,kube-proxy
安装一个iptable
规则 - 默认情况下,
kube-proxy
随机选择一个Service
的后端Pod
iptables proxy mode
的优点:
- 更低的系统开销:在
linux netfilter
处理请求,无需在userspace
和kernel space
之间切换 - 更稳定
与 user space mode
的差异:
- 使用
iptables mode
时,如果第一个 Pod 没有响应,则创建连接失败 - 使用
user space mode
时,如果第一个 Pod 没有响应,kube-proxy 会自动尝试连接另外一个后端 Pod
IPVS 代理模式
在 IPVS proxy mode
下:
kube-proxy
监听kubernetes master
以获得添加和移除Service / Endpoin
t 的事件kube-proxy
根据监听到的事件,调用netlink
接口,创建IPVS
规则;并且将Service/Endpoint
的变化同步到IPVS
规则中- 当访问一个
Service
时,IPVS
将请求重定向到后端Pod
IPVS 模式的优点
IPVS proxy mode
基于 netfilter
的 hook
功能,与 iptables
代理模式相似,但是 IPVS
代理模式使用 hash table
作为底层的数据结构,并在 kernel space
运作。这就意味着
IPVS
代理模式可以比iptables
代理模式有更低的网络延迟,在同步代理规则时,也有更高的效率- 与
user space
代理模式 /iptables
代理模式相比,IPVS
模式可以支持更大的网络流量。
CKA真题
以下这题是关于service四层代理CKA真题,相对也是非常简单的。
中文解析
切换 k8s 集群环境:kubectl config use-context k8s
Task
重新配置一个已经存在的front-end
的 deployment
,在名字为 nginx
的容器里面添加一个端口配置,名字为 http
,暴露端口号为 80
,然后创建一个 service
,名字为 front-end-svc
,暴露该deployment
的 http
端,并且 service
的类型为 NodePort
。
参考官方文档
做题解答
- 先按照题目的要求切换集群环境
kubectl config use-context k8s
- 检查集群上是否存在
front-end
的deployment
。
controlplane $ kubectl get deployments.apps NAME READY UP-TO-DATE AVAILABLE AGE front-end 2/3 3 2 8s controlplane $ kubectl get pod NAME READY STATUS RESTARTS AGE front-end-65b66568d4-4hgww 1/1 Running 0 15s front-end-65b66568d4-dsxnx 1/1 Running 0 15s front-end-65b66568d4-vql52 1/1 Running 0 15s controlplane $
- 创建名字为
front-end-svc
的service。
- 资源清单方法,新建一个
front-end-svc.yaml
文件,内容如下:
apiVersion: v1 kind: Service metadata: name: front-end-svc spec: selector: app: nginx ports: - name: http protocol: TCP port: 80 targetPort: 80 type: NodePort
然后,执行如下命令创建
controlplane $ kubectl create -f front-end-svc.yaml service/front-end-svc created
- 通过命令行方式创建(考试时首选这种方式)
controlplane $ kubectl expose deployment front-end --type=NodePort --port=80 --target-port=80 --name=front-end-svc service/front-end-svc exposed
--port
是 service 的端口号,--target-port
是 deployment里容器的端口号。
- 检测Service状态
controlplane $ kubectl describe svc front-end-svc Name: front-end-svc Namespace: default Labels: app=nginx Annotations: <none> Selector: app=nginx Type: NodePort IP Family Policy: SingleStack IP Families: IPv4 IP: 10.108.182.66 IPs: 10.108.182.66 Port: <unset> 80/TCP TargetPort: 80/TCP NodePort: <unset> 31323/TCP Endpoints: 192.168.0.4:80,192.168.1.4:80,192.168.1.5:80 Session Affinity: None External Traffic Policy: Cluster Events: <none>