概述
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: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp # service selector的label要和pod的label对应,才会生效
ports:
- protocol: TCP
port: 8080
targetPort: 80
# 还可以在yml文件里不用selector,用service和endpoint,写两个yml去使用service
apiVersion: v1
kind: Service
metadata:
name: my-service # service的名字要和endpoint的名字对应
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
------------------------
# 因为此Service没有选择器,则不会创建对应的Endpoints对象,可以手工将服务映射至指定的endpoints中:
apiVersion: v1
kind: Endpoints
metadata:
name: my-service
subsets:
- addresses:
- ip: 10.42.4.42 # 指定主机,分发流量,走iptable啥的
ports:
- port: 9376
[rancher@master1 test]$ kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 172.24.102.254:6443,172.24.102.255:6443,172.24.103. 1:6443 41h
my-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.yml
service/my-service created
[rancher@master1 test]$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 41h
my-service ClusterIP 10.43.12.238 <none> 8080/TCP 3s
# 命令行实现(最好不用)
[rancher@master1 ~]$ kubectl run --image=nginx test2
kubectl 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=80
service/test2 exposed
NodePort
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp # service selector的label要和pod的label对应,才会生效
ports:
- protocol: TCP
nodePort:
port: 8080
targetPort: 80
sessionAffinity: None
type: NodePort
status:
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: nginx
image: nginx
ports:
- containerPort: 80
name: web
2. 通过dns去解析statusful```yml
# 创建busybox
apiVersion: v1
kind: Pod
metadata:
name: busybox
spec:
containers:
- image: busybox:1.28
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
name: busybox
[rancher@master1 test]$ kubectl create -f dns.yml
# 查看无头service
[rancher@master1 test]$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 46h
nginx ClusterIP None <none> 80/TCP 21m
# 解析
[rancher@master1 test]$ kubectl exec -it busybox -- nslookup nginx
Server: 10.43.0.10
Address 1: 10.43.0.10 kube-dns.kube-system.svc.cluster.local
Name: nginx
Address 1: 10.42.4.44 web-2.nginx.default.svc.cluster.local
Address 2: 10.42.3.32 web-1.nginx.default.svc.cluster.local
Address 3: 10.42.4.43 web-0.nginx.default.svc.cluster.local
externalname
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: ExternalName
externalName: www.baidu.com
# 通过externalName可以对my-service在集群内部做一个解析
[rancher@master1 test]$ kubectl exec -it busybox nslookup my-service
Server: 10.43.0.10
Address 1: 10.43.0.10 kube-dns.kube-system.svc.cluster.local
Name: my-service
Address 1: 240e:83:205:58:0:ff:b09f:36bf
Address 2: 240e:83:205:59:0:ff:b09b:159e
Address 3: 220.181.38.149
Address 4: 220.181.38.150
[rancher@master1 test]$ kubectl exec -it busybox nslookup www.baidu.com
Server: 10.43.0.10
Address 1: 10.43.0.10 kube-dns.kube-system.svc.cluster.local
Name: www.baidu.com
Address 1: 240e:83:205:59:0:ff:b09b:159e
Address 2: 240e:83:205:58:0:ff:b09f:36bf
Address 3: 220.181.38.150
Address 4: 220.181.38.149
****
external ip
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: nginx
ports:
- name: http
protocol: TCP
port: 18080
targetPort: 80
externalIPs:
- 172.24.102.253
# 其实觉得可以理解为主机端口映射
[rancher@master1 test]$ curl 172.24.102.253:18080
[rancher@master1 test]$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 47h
my-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.localdomain6
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
172.24.102.255 master1
172.24.102.254 master2
172.24.103.1 master3
172.24.102.253 node1
172.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/foo
test # 可提前更改访问内容(略)