chapter5-Service
Service
1.Service是什么
Kubemetes服务是一种为一组功能相同的pod提供单一不变的接入点的资源。当服务存在时,它的IP地址和端口不会改变。客户端通过IP地址和端口号建立连接,这些连接会被路由到提供该服务的任意一个pod上。通过这种方式,客户端不需要知道每个单独的提供服务的pod的地址,这样这些pod就可以在集群中随时被创建或移除。
1.1创建服务
服务的连接对所有的pod是负载均衡的,但是如何准确定义哪些pod属于服务哪些不属于呢?我们知道,ReplicaSet和其他pod控制器使用标签选择器来指定哪些pod属于同一组,服务也是使用相同的机制。
## 示例
apiVersion: v1
kind: Service
metadata:
name: kubia
spec:
ports:
- port: 80
targetPort: 8080 //服务将连接转发到容器端口
name: http
- port: 81
targetPort: 8081
name: https //pod内有两个容器,另一容器监听8081端口
selector:
app: kubia //具有app=kubia标签的pod都属于该服务
2.endpoint
2.1什么是endpoint
该书翻译的对endpoint的介绍不是很清楚,因此我在stackoverflow
上寻找到了对endpoint介绍更加清楚的解释:
An endpoint is an resource that gets IP addresses of one or more pods dynamically assigned to it, along with a port. An endpoint can be viewed using kubectl get endpoints
.
An endpoint resource is referenced by a kubernetes service, so that the service has a record of the internal IPs of pods in order to be able to communicate with them.
We need endpoints as an abstraction layer because the 'service' in kubernetes acts as part of the orchestration to ensure distribution of traffic to pods (including only sending traffic to healthy pods). For example if a pod dies, a replacement pod will be generated, with a new IP address. Conceptually, the dead pod IP will be removed from the endpoint object, and the IP of the newly created pod will be added, so that the service is updated and 'knows' which pods to connect to.
An easy way to investigate and see the relationship is:
kubectl describe pods
- and observe the IP addresses of your podskubectl get ep
- and observe the IP addresses assigned to your endpointkubectl describe service myServiceName
- and observe theEndpoints
associated with your service
pod selector的作用是构建IP+Port,并存储到endpoint中
2.2手动配置endpoint
如果创建了不包含pod selector的service,k8s便不会创建endpoint(毕竟缺少选择器,就不会知道service中包含哪些pod)。这样就需要手动创建endpoint来指定。
首先为一个service创建yaml文件:
apiVersion: v1
kind: Service
metadata:
name: external-service
spec:
ports:
- port: 80
创建endpoint
apiVersion: v1
kind: Endpoints
metadata:
name: external-service //endpoint name == service name
spec:
- addresses:
- ip: 11.11.11.11
- ip: 22.22.22.22
ports:
- port: 80
3.将服务暴露给集群外部
3.1NodePort
3.2LoadBalancer
A kubernetes LoadBalancer service is a service that points to external load balancers that are NOT in your kubernetes cluster, but exist elsewhere. They can work with your pods, assuming that your pods are externally routable.
$ kubect1 get svc kubia-loadbalancer
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubia-loadbalancer 10.111.241.153 130.211.53.173 80:32143/TCP 1m
curl 130.211.53.173:80
3.3Ingress
3.3.1为什么需要Ingress
一个重要原因是每个LoadBalancer都需要自己的负载均衡器以及独有的公网IP地址,而Ingress只需要一个公网IP就能为许多服务提供访问。当客户端向Ingress发送HTTP请求时,Ingress会根据请求的主机名和路径决定请求转发到的服务
3.3.2创建Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kubia
spec:
rules:
- host: kubia.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: mynginx
port:
number: 8000
通过kubectl get ingress
可以获取所创建ingress的公网IP地址192.168.246.1
,在本地虚拟机测试:echo "192.168.246.1 kubia.example.com" /etc/hosts
,通过http://kubia.example.com
访问
3.3.3Ingress工作原理
客户端首先对kubia.example.com
执行DNS查找,DNS服务器(或本地操作系统)返回Ingress控制器的IP地址。然后客户端向Ingress控制器发送HTTP请求,并在Host头中指定kubia.example.com
。控制器从该头部确定客户端尝试访问哪个Service,通过与该Service相关联的Endpoint对象查看Pod IP,并将客户端的请求转发给其中之一Pod。
Ingress控制器不会将请求转发给该Service,而是通过与Service关联的Endpoint选择一个Pod。
3.3.4通过同一Ingress暴露多个服务
通过kubectl explain Ingress.spec
可以看到rules和paths都是数组,因此可以包含多个条目。
将不同服务映射到相同主机的不同路径
...
- host: kubia.example.com
http:
paths:
- path: /kubia
pathType: Prefix
backend:
service:
name: bar
port:
number: 80
- path: /foo
pathType: Prefix
backend:
service:
name: bar
port:
number: 80
## 根据请求的URL中的路径将请求发送到两个不同服务
将不同的服务映射到不同的主机
spec:
rules:
- host: foo.example.com
http:
paths:
- path: /foo
pathType: Prefix
backend:
service:
name: foo
port:
number: 80
- host: bar.example.com
http:
paths:
- path: /bar
pathType: Prefix
backend:
service:
name: bar
port:
number: 80
3.3.5配置Ingress处理TLS传输
当客户端创建到Ingress控制器的TLS连接时,控制器将终止TLS连接,客户端和控制器之间通信是加密的,而控制器和Pod之间通信则不是。运行在Pod上的应用不需要支持TLS。例如,如果Pod运行web服务器,则它只能接收HTTP通信,并让Ingress控制器负责处理与TLS相关的所有内容。首先要将证书和私钥附加到Ingress,这两个资源存储在Secret中,关于Secret具体介绍放在后面,现在只创建Secret。
## 首先创建证书和私钥
openssl genrsa -out tls.key 2048
openssl rep -new -x509 -key tls.key -out tls.cert -days 360 -subj
## 创建Secret
kubectl create secret tls tls-secter --cert=tls.cert --key=tls.key
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kubia
spec:
tls:
- hosts:
- kubia.example.com
secretName: tls-secret
rules:
- host: kubia.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: mynginx
port:
number: 8000
## curl -k -v https://kubia.example.com
4.Pod就绪后发出信号
我们已经知道,如果pod标签与service选择器相匹配,该pod就将作为服务的后端,并且一部分请求会负载均衡的打入该pod,但是如果pod还没准备好,该如何处理请求呢?
该pod可能需要长时间来加载配置或数据,在这种情况下,不希望pod立即开始接收请求。不要将请求转到到正在启动的pod,直到pod完全准备就绪。
4.1就绪探针
就绪探针会定期调用,确定特定Pod是否准备好接收客户端请求。Kubernetes检查在容器中运行的程序是否相应一个简单的GET/请求,或者响应特定URL路径。
就绪探针类型
- Exec探针,在容器内执行指定的命令,Exit status of 0 is treated as live/healthy and non-zero is unhealthy
- HTTP GET探针,向容器发送HTTP GET请求,通过响应的HTTP状态码判断
- TCPsocket探针,它打开一个TCP连接到容器的指定端口,如果连接建立则表示容器就绪。
了解就绪探针的操作
启动容器时,可以为Kubernetes配置一个等待时间,经过等待时间后才可以执行第一次就绪检查,之后会周期性地调用就绪探针,并根据就绪探针的结果采取动作。如果某pod报告它尚未准备就绪,则会从该服务中删除该pod,如果pod再次准备就绪,就将该pod重新添加进服务。
与存活探针不同,如果容器未通过准备检查,则不会被终止或重新启动。存活探针通过杀死异常容器并启用新容器来保持pod正常工作,而就绪探针确保只有准备好处理请求的pod才可以接收请求。

4.2添加就绪探针
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: testnginx
spec:
replicas: 1
selector:
matchLabels:
app: mynginx
template:
metadata:
labels:
app: mynginx
spec:
containers:
- name: mynginx
image: nginx
readinessProbe:
exec:
command:
- ls
- /var/ready
kubectl apply -f test.yaml
新的pod将进行就绪检查会一直失败并且不会将其作为服务的端点,直到在每个pod中创建/var/ready文件kubectl exec kubia-2rlqb -- touch /var/ready
该文件的存在可以模拟就绪探针成功