概述
Service为一组功能相同的pod提供统一入口并为它们提供负载均衡和自动服务发现。Service所针对的一组Pod,通常是由Selector来确定。
为什么需要Service?
直接接通过pod的ip加端口去访问应用是不稳定的,因为pod的生命周期是不断变化的,每次触发了删除的动作后Pod会重新创建,那么Pod的IP地址就会产生变化。
service类型
Service的转发后端的三种方式
- Clusterip:通过集群的内部IP的创建,实现服务在集群内的访问。j这也是默认的 ServiceType。
- Nodeport:通过每个 Node 上的 IP 和静态端口(NodePort)暴露服务。通过请求
<NodeIP>:<NodePort>,可以从集群的外部访问一个 Kubernetes服务。 - Loadblance:使用云提供商的负载局衡器,可以向外部暴露服务。外部的负载均衡器可以路由到Service然后到应用。
- Externalname:依赖于DNS,用于将集群外部的服务通过域名的方式映射到Kubernetes集群内部,通过Service的name进行访问。
Service的三种端口类型:
- Port:Service对内暴露的端口
- Targetport:POD暴露的端口
- Nodeport:Service对外暴露的端口
集群外访问Service的方式:
- Nodeport
- Loadblance
- ExternalIP
clusterIP示例
apiVersion: v1kind: Servicemetadata:name: my-servicespec:selector:app: MyApp # service selector的label要和pod的label对应,才会生效ports:- protocol: TCPport: 8080targetPort: 80
# 还可以在yml文件里不用selector,用service和endpoint,写两个yml去使用serviceapiVersion: v1kind: Servicemetadata:name: my-service # service的名字要和endpoint的名字对应spec:ports:- protocol: TCPport: 80targetPort: 9376------------------------# 因为此Service没有选择器,则不会创建对应的Endpoints对象,可以手工将服务映射至指定的endpoints中:apiVersion: v1kind: Endpointsmetadata:name: my-servicesubsets:- addresses:- ip: 10.42.4.42 # 指定主机,分发流量,走iptable啥的ports:- port: 9376
[rancher@master1 test]$ kubectl get endpointsNAME ENDPOINTS AGEkubernetes 172.24.102.254:6443,172.24.102.255:6443,172.24.103. 1:6443 41hmy-service 10.42.3.28:80,10.42.4.39:80,10.42.4. 40:80 31s[rancher@master1 test]$ kubectl apply -f service_test.ymlservice/my-service created[rancher@master1 test]$ kubectl get serviceNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEkubernetes ClusterIP 10.43.0.1 <none> 443/TCP 41hmy-service ClusterIP 10.43.12.238 <none> 8080/TCP 3s# 命令行实现(最好不用)[rancher@master1 ~]$ kubectl run --image=nginx test2kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.deployment.apps/test2 created[rancher@master1 ~]$ kubectl expose deployment test2 --port=18080 --target-port=80service/test2 exposed
NodePort
apiVersion: v1kind: Servicemetadata:name: my-servicespec:selector:app: MyApp # service selector的label要和pod的label对应,才会生效ports:- protocol: TCPnodePort:port: 8080targetPort: 80sessionAffinity: Nonetype: NodePortstatus:loadBalancer: {}
# 直接用命令行[rancher@master1 test]$ kubectl expose deployment test --port=18080 --target-port=80 --type=NodePort
Headless Service
在有些场景下,服务可能不需要作为负载均衡代理,而仅仅需要一个单一的cluster ip。这时就可以通过设置“spec.clusterIP”的值为None,来创建一个”headless“类型的服务。此类型的服务允许开发者减少对Kubernetes系统的依赖,开发者可以通过自己的方式实现对服务的自动发现。应用也能够使用其他的服务发现系统,进行服务的自注册和适配器,实现服务的自动发现。对于这样的服务:
- Kubernetes未指派cluster IP;
- kube-proxy将不处理这些服务;
- 因此也就没有负载均衡和代理。
- 但会依赖服务是否拥有选择器进行DNS的配置。
- 创建statusful
- 典型的无头服务,而且这种通过dns解析服务,只能用于statulful,每个节点只要一个pod副本,ip不会变,所以可以这样理解,就是通过解析这个无头service找到对应的poo的IP ```yml apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports:
- port: 80 name: web clusterIP: None selector: app: nginx
apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: selector: matchLabels: app: nginx # has to match .spec.template.metadata.labels serviceName: “nginx” replicas: 3 # by default is 1 template: metadata: labels: app: nginx # has to match .spec.selector.matchLabels spec: terminationGracePeriodSeconds: 10 containers:
- name: nginximage: nginxports:- containerPort: 80name: web
2. 通过dns去解析statusful```yml# 创建busyboxapiVersion: v1kind: Podmetadata:name: busyboxspec:containers:- image: busybox:1.28command:- sleep- "3600"imagePullPolicy: IfNotPresentname: busybox
[rancher@master1 test]$ kubectl create -f dns.yml# 查看无头service[rancher@master1 test]$ kubectl get serviceNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEkubernetes ClusterIP 10.43.0.1 <none> 443/TCP 46hnginx ClusterIP None <none> 80/TCP 21m# 解析[rancher@master1 test]$ kubectl exec -it busybox -- nslookup nginxServer: 10.43.0.10Address 1: 10.43.0.10 kube-dns.kube-system.svc.cluster.localName: nginxAddress 1: 10.42.4.44 web-2.nginx.default.svc.cluster.localAddress 2: 10.42.3.32 web-1.nginx.default.svc.cluster.localAddress 3: 10.42.4.43 web-0.nginx.default.svc.cluster.local
externalname
apiVersion: v1kind: Servicemetadata:name: my-servicespec:type: ExternalNameexternalName: www.baidu.com
# 通过externalName可以对my-service在集群内部做一个解析[rancher@master1 test]$ kubectl exec -it busybox nslookup my-serviceServer: 10.43.0.10Address 1: 10.43.0.10 kube-dns.kube-system.svc.cluster.localName: my-serviceAddress 1: 240e:83:205:58:0:ff:b09f:36bfAddress 2: 240e:83:205:59:0:ff:b09b:159eAddress 3: 220.181.38.149Address 4: 220.181.38.150[rancher@master1 test]$ kubectl exec -it busybox nslookup www.baidu.comServer: 10.43.0.10Address 1: 10.43.0.10 kube-dns.kube-system.svc.cluster.localName: www.baidu.comAddress 1: 240e:83:205:59:0:ff:b09b:159eAddress 2: 240e:83:205:58:0:ff:b09f:36bfAddress 3: 220.181.38.150Address 4: 220.181.38.149****
external ip
apiVersion: v1kind: Servicemetadata:name: my-servicespec:selector:app: nginxports:- name: httpprotocol: TCPport: 18080targetPort: 80externalIPs:- 172.24.102.253
# 其实觉得可以理解为主机端口映射[rancher@master1 test]$ curl 172.24.102.253:18080[rancher@master1 test]$ kubectl get serviceNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEkubernetes ClusterIP 10.43.0.1 <none> 443/TCP 47hmy-service ClusterIP 10.43.91.49 172.24.102.253 18080/TCP 55s
ingress
ingress组成:

ingress-controller本身是一个是一个pod,这个pod里面的容器安装了反向代理软件,通过读取添加的Service,动态生成负载均衡器的反向代理配置,你添加对应的ingress服务后,里面规则包含了对应的规则,里面有域名和对应的Service-backend。
NGINX Ingress Controller是目前使用最多也是评分最高的Ingress控制器:
- 基于http-header 的路由
- 基于 path 的路由
- 单个ingress 的 timeout (不影响其他ingress 的 timeout 时间设置)
- 请求速率limit rewrite
- 规则 ssl
详细步骤(示例)
- 先创建两个服务,并暴露端口80```bash [rancher@master1 ~]$ kubectl run —image=nginx test [rancher@master1 ~]$ kubectl run —image=nginx demo
[rancher@master1 ~]$ kubectl expose deployment test —port=80 [rancher@master1 ~]$ kubectl expose deployment demo —port=80
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
demo ClusterIP 10.43.91.189
2. 在/etc/hosts文件里添加域名解析```bash[rancher@master1 ~]$ cat /etc/hosts::1 localhost localhost.localdomain localhost6 localhost6.localdomain6127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4172.24.102.255 master1172.24.102.254 master2172.24.103.1 master3172.24.102.253 node1172.24.103.0 node2 foo.bar.com
- 创建ingress文件```yml
第一种,使用foo.bar.com域名访问
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: test annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: rules:- host: foo.bar.com # 上面使用的域名解析
http:
paths:
- path: /foo # 访问路径前缀 backend: serviceName: test servicePort: 80 # cluster端口
- path: /bar backend: serviceName: demo servicePort: 80
- host: foo.bar.com # 上面使用的域名解析
http:
paths:
第二种,使用ip地址进行访问
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: test-ingress2 spec: backend: serviceName: test servicePort: 80
4. 访问```bash# 用域名[rancher@master1 ~]$ curl foo.bar.com/footest # 可提前更改访问内容(略)
