Kubernetes 的服务发现与负载均衡 (service)
Service 的作用
服务发现: 由于 Kubernetes 的调度机制, 在 Kubernetes 中, Pod 的 IP 不是固定的. 如果其它程序需要访问这个 Pod, 要怎么知道这个 Pod 的 IP 呢?
负载均衡: 由于 Deployment 管理着多个 Pod 的副本, 如果其它程序需要访问这些 Pod, 显然需要一个 proxy 为这些 Pod 做负载均衡.
外部路由: 如果应用程序运行在 Kubernetes 外部, 如何访问 Kubernetes 内部的 Pod 呢?
Kubernetes 提供了 Service 功能, 用来解决这些问题.
服务发现与负载均衡
Service 通常会和 Deployment 结合在一起使用, 首先通过 Deployment 部署应用程序, 然后再使用 Service 为应用程序提供服务发现, 负载均衡和外部路由的功能.
在 TKE 中通过应用创建服务, 默认也是一个 Deployment 和一个 Service
举例, 我通过应用从 ui 中导入服务, 确认后将生成以下 YAML 文件
- # 这个 YAML 文件不可直接引用
- apiVersion: extensions/v1beta1
- kind: Deployment
- metadata:
- creationTimestamp: null
- name: nginx-service
- namespace: '{{.NAMESPACE}}'
- spec:
- replicas: 2
- revisionHistoryLimit: 5
- selector: {}
- strategy:
- rollingUpdate:
- maxSurge: 1
- maxUnavailable: 0
- type: RollingUpdate
- template:
- metadata:
- creationTimestamp: null
- spec:
- containers:
- - image: nginx:latest
- imagePullPolicy: Always
- name: nginx-service
- resources:
- limits:
- CPU: 500m
- memory: 1Gi
- requests:
- CPU: 250m
- memory: 256Mi
- securityContext:
- privileged: false
- serviceAccountName: ""
- volumes: null
- status: {}
- ---
- apiVersion: v1
- kind: Service
- metadata:
- annotations:
- service.kubernetes.io/qcloud-loadbalancer-internet-charge-type: BANDWIDTH_POSTPAID_BY_HOUR
- service.kubernetes.io/qcloud-loadbalancer-internet-max-bandwidth-out: "1"
- creationTimestamp: null
- name: nginx-service
- namespace: '{{.NAMESPACE}}'
- spec:
- ports:
- - name: tcp-80-80-chjh2
- nodePort: 0
- port: 80
- protocol: TCP
- targetPort: 80
- selector: {}
- type: LoadBalancer
- status:
- loadBalancer: {}
这里我们创建了一个名为 nginx-service 的 Service, 它监听的端口是 80, 同时它会把全部的流量都转发给它代理的所有 Pod(这些 Pod 都必须拥有 nginx-server 这个标签).
Service 提供了两种服务发现的方式, 第一种是环境变量, 第二种是 DNS. 先说第一种, 上面我们创建了 nginx-service 这个 Service, 接着如果我们再创建另外一个 Pod, 那么在这个 Pod 中, 可以通过环境变量知道 nginx-service 的地址.
首先, 创建一个新的 Pod(这个 Pod 已经安装好了 curl 工具):
- # 可直接引用创建
- $ cat curl-pod.YAML
- apiVersion: v1
- kind: Pod
- metadata:
- name: curl
- spec:
- containers:
- - name: curl
- image: tutum/curl
- command:
- - sleep
- - "3600"
- ports:
- - containerPort: 80
- $ kubectl apply -f curl-pod.YAML
接着, 进入这个 Pod, 可以查看它的环境变量. 可以看到, 当 Kubernetes 创建这个 Pod 时, 会自动注入这些环境变量:
- # kubectl exec -it curl bash
- root@curl:/# env | grep NGINX
- NGINX_SERVICE_PORT_80_TCP_PORT=80
- NGINX_SERVICE_PORT_80_TCP_PROTO=tcp
- NGINX_SERVICE_SERVICE_PORT_TCP_80_80_CHJH2=80
- NGINX_SERVICE_SERVICE_HOST=192.168.255.152
- NGINX_SERVICE_PORT=tcp://192.168.255.152:80
- NGINX_SERVICE_PORT_80_TCP=tcp://192.168.255.152:80
- NGINX_SERVICE_SERVICE_PORT=80
- NGINX_SERVICE_PORT_80_TCP_ADDR=192.168.255.152
因此, 在 curl 这个 Pod 中, 可以通过访问这些环境变量, 从而访问 nginx-service.
另一种服务发现的方式是 DNS 解析. 例如, 我们进入 curl Pod 里面, 可以通过 DNS 解析, 访问 nginx-service:
root@curl:/# curl http://nginx-service.default:80
- <!DOCTYPE html>
- <HTML>
- <head>
- <title>Welcome to nginx!</title>
- <style>
- body {
- width: 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>
由于 nginx-service 的 namespace 是 default, 因此它的 DNS 域名是 nginx-service.default.
再说说负载均衡, 我们上面创建了 nginx-service, 这个 Service 会自动将接收到的流量转发给它代理的两个 Nginx Pod.
外部路由
默认情况下, 通过 TKE 创建的应用 Service 的类型是 LoadBalancer(提供公网访问) 如果选仅在集群内访问 TYPE 将为 ClusterIP
- # kubectl get services nginx-service
- NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
- nginx-service LoadBalancer 192.168.255.152 111.230.191.96 80:31437/TCP 19m
- nginx ClusterIP 192.168.255.193 <none> 80/TCP 31s
可以看到, nginx-service 的 Cluster-IP(集群 IP) 是 192.168.255.152, 这个 IP 只能从 Kubernetes 内部才能访问. 当然, 除了 ClusterIP 之外还有 Exteranl-IP(外部 IP)111.230.191.96, 这个就是公网 IP 提供访问的, Service 还可以是其它类型: NodePort,LoadBalancer 和 ExternalName.
参考资料
Docker-- 容器与容器云 (第 2 版)
Service
服务发现与负载均衡
知识点补充
Service 有三种类型:
ClusterIP: 默认类型, 自动分配一个仅 cluster 内部可以访问的虚拟 IP
NodePort: 在 ClusterIP 基础上为 Service 在每台机器上绑定一个端口, 这样就可以通过 <NodeIP>:NodePort 来访问该服务
LoadBalancer: 在 NodePort 的基础上, 借助 cloud provider 创建一个外部的负载均衡器, 并将请求转发到 <NodeIP>:NodePort
来源: https://www.qcloud.com/developer/article/1346992