Kubernetes 第九章 Service

Service

Kubernetes 在设计之初就充分考虑了针对容器的服务发现与负载均衡机制,提供了 Service 资源,对于内部容器资源提供负载均衡机制,对外提供统一访问入口。

Service 是对一组提供相同功能的 Pods 的抽象,并为它们提供一个统一的入口。借助 Service,应用可以方便的实现服务发现与负载均衡,并实现应用的零宕机升级。Service 通过标签来选取服务后端,一般配合 Replication Controller 或者 Deployment 来保证后端容器的正常运行。这些匹配标签的 Pod IP 和端口列表组成 endpoints,由 kube-proxy 负责将服务 IP 负载均衡到这些 endpoints 上。
#通过标签选择对应的pod
Service 有四种类型:

ClusterIP:默认类型,自动分配一个仅 cluster 内部可以访问的虚拟 IP
NodePort:在 ClusterIP 基础上为 Service 在每台机器上绑定一个端口,这样就可以通过 <NodeIP>:NodePort 来访问该服务。如果 kube-proxy 设置了 --nodeport-addresses=10.240.0.0/16(v1.10 支持),那么仅该 NodePort 仅对设置在范围内的 IP 有效。
LoadBalancer:在 NodePort 的基础上,借助 cloud provider 创建一个外部的负载均衡器,并将请求转发到 <NodeIP>:NodePort,依赖与云环境
ExternalName:将服务通过 DNS CNAME 记录方式转发到指定的域名(通过 spec.externlName 设定)。需要 kube-dns 版本在 1.7 以上。
另外,也可以将已有的服务以 Service 的形式加入到 Kubernetes 集群中来,只需要在创建 Service 的时候不指定 Label selector,而是在 Service 创建好后手动为其添加 endpoint。

Service 定义

ClusterIP
[root@kube test]# cat nginx-svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: default
spec:
#默认ClusterIP 类型 ports:
- port: 80 protocol: TCP targetPort: 80 selector: app: nginx type: ClusterIP [root@kube test]# kubectl apply -f nginx-svc.yaml [root@kube test]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 38d nginx-service ClusterIP 10.107.27.48 <none> 80/TCP 8s php-apache ClusterIP 10.97.196.195 <none> 80/TCP 86m [root@kube test]#

查看pods 标签

root@kube test]# kubectl get pods --show-labels
NAME                                READY   STATUS             RESTARTS   AGE     LABELS
liveness-exec                       0/1     CrashLoopBackOff   8923       24d     test=liveness
liveness-http                       1/1     Running            16         24d     test=liveness
nginx-deployment-5754944d6c-c797m   1/1     Running            0          3d22h   app=nginx,pod-templ
nginx-deployment-5754944d6c-jspst   1/1     Running            0          3d22h   app=nginx,pod-templ
nginx-deployment-5754944d6c-kkvx5   1/1     Running            0          3d22h   app=nginx,pod-templ
php-apache-d89b5f47b-dllcg          0/1     ImagePullBackOff   0          4h44m   pod-template-hash=d
pod-test                            1/1     Running            0          31d     app=myapp,tier=fron
[root@kube test]# 

  

NodePort:

[root@kube test]# cat nginx-svc-nodeport.yaml 
apiVersion: v1
kind: Service
metadata:
  name: nginx-service-nodeport
  namespace: default
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
    nodePort: 30080
//指定node 对外映射端口,确认没有被占用
selector: app: nginx type: NodePort [root@kube test]# kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 38d nginx-service ClusterIP 10.107.27.48 <none> 80/TCP 3h46m nginx-service-nodeport NodePort 10.109.241.119 <none> 80:30080/TCP 14m php-apache ClusterIP 10.97.196.195 <none> 80/TCP 5h12m [root@kube test]# curl http://10.2.61.22:30080 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> [root@kube test]#
[root@kube test]# kubectl describe service nginx-service-nodeport
Name:                     nginx-service-nodeport
Namespace:                default
Labels:                   <none>
Annotations:              kubectl.kubernetes.io/last-applied-configuration:
                            {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"nginx-service-nodeport","namespace":"default"},"spec":{"ports":[{...
Selector:                 app=nginx
Type:                     NodePort
IP:                       10.109.241.119
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30080/TCP
Endpoints:                10.244.1.7:80,10.244.2.28:80,10.244.2.29:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>
[root@kube test]# 

  

不指定 Selectors 的服务

在创建 Service 的时候,也可以不指定 Selectors,用来将 service 转发到 kubernetes 集群外部的服务(而不是 Pod)。目前支持两种方法

(1)自定义 endpoint,即创建同名的 service 和 endpoint,在 endpoint 中设置外部服务的 IP 和端口

[root@kube test]# cat endpoint_demo.yaml 
kind: Service
apiVersion: v1
metadata:
  name: my-service-end
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
---
kind: Endpoints
apiVersion: v1
metadata:
  name: my-service-end
subsets:
  - addresses:
      - ip: 10.1.255.156
    ports:
      - port: 8080
[root@kube test]# curl  -I http://10.100.60.230
HTTP/1.1 403 Forbidden
Server: nginx
Date: Tue, 20 Aug 2019 08:49:01 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
Vary: Accept-Encoding

[root@kube test]# 

  

    

Headless 服务

Headless 服务即不需要 Cluster IP 的服务,即在创建服务的时候指定 spec.clusterIP=None。包括两种类型

  • 不指定 Selectors,但设置 externalName,即上面的(2),通过 CNAME 记录处理
  • 指定 Selectors,通过 DNS A 记录设置后端 endpoint 列表

CNAME 方式

保留源 IP

各种类型的 Service 对源 IP 的处理方法不同:

  • ClusterIP Service:使用 iptables 模式,集群内部的源 IP 会保留(不做 SNAT)。如果 client 和 server pod 在同一个 Node 上,那源 IP 就是 client pod 的 IP 地址;如果在不同的 Node 上,源 IP 则取决于网络插件是如何处理的,比如使用 flannel 时,源 IP 是 node flannel IP 地址。
  • NodePort Service:默认情况下,源 IP 会做 SNAT,server pod 看到的源 IP 是 Node IP。为了避免这种情况,可以给 service 设置 spec.ExternalTrafficPolicy=Local (1.6-1.7 版本设置 Annotation service.beta.kubernetes.io/external-traffic=OnlyLocal),让 service 只代理本地 endpoint 的请求(如果没有本地 endpoint 则直接丢包),从而保留源 IP。
  • LoadBalancer Service:默认情况下,源 IP 会做 SNAT,server pod 看到的源 IP 是 Node IP。设置 service.spec.ExternalTrafficPolicy=Local 后可以自动从云平台负载均衡器中删除没有本地 endpoint 的 Node,从而保留源 IP。

工作原理

kube-proxy 负责将 service 负载均衡到后端 Pod 中,如下图所示

 

 

原文地址:https://www.cnblogs.com/zy09/p/11375624.html