kubernetes Service:让客户端发现pod并与之通信
目录
5.1.Service介绍
5.1.1.Serice简介
5.1.1.1什么是Service
5.1.1.2.Service的创建
5.1.1.3.检测服务
5.1.1.4.在运行的容器中远程执行命令
5.2.连接集群外部的服务
5.2.1.介绍服务endpoint
5.2.2.手动配置服务的endpoint
5.2.3.为外部服务创建别名
5.3.将服务暴露给外部客户端
5.3.1.使用nodeport类型的服务
5.3.2.通过Loadbalance将服务暴露出来
5.4.通过Ingress暴露服务
5.4.1.创建Ingress资源
5.4.2.通过Ingress访问服务
5.4.3.通过相同的Ingress暴露多少服务
5.4.4.配置Ingress处理TLS传输
5.5.pod就绪后发出信号
5.5.1.介绍就绪探针
5.5.2.向pod添加就绪探针
5.6.使用headless服务发现独立的pod
5.6.1.创建headless服务
正文
回到顶部
5.1.Service介绍
回到顶部
5.1.1.Serice简介
5.1.1.1什么是Service
service是k8s中的一个重要概念,主要是提供负载均衡和服务自动发现。
Service 是由 kube-proxy 组件,加上 iptables 来共同实现的。
5.1.1.2.Service的创建
创建Service的方法有两种:
1.通过kubectl expose创建
1
2
3
4
5
6
7
#kubectl expose deployment nginx --port=88 --type=NodePort --target-port=80 --name=nginx-service
这一步说是将服务暴露出去,实际上是在服务前面加一个负载均衡,因为pod可能分布在不同的结点上。
–port:暴露出去的端口
–type=NodePort:使用结点+端口方式访问服务
–target-port:容器的端口
–name:创建service指定的名称
2.通过yaml文件创建
创建一个名为hostnames-yaohong的服务,将在端口80接收请求并将链接路由到具有标签选择器是app=hostnames的pod的9376端口上。
使用kubectl creat来创建serivice
1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Service
metadata:
name: hostnames-yaohong
spec:
selector:
app: hostnames
ports:
- name: default
protocol: TCP
port: 80 //该服务的可用端口
targetPort: 9376 //具有app=hostnames标签的pod都属于该服务
5.1.1.3.检测服务
使用如下命令来检查服务:
1
2
3
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.187.0.1 443/TCP 18d
5.1.1.4.在运行的容器中远程执行命令
使用kubectl exec 命令来远程执行容器中命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ kubectl -n kube-system exec coredns-7b8dbb87dd-pb9hk -- ls /
bin
coredns
dev
etc
home
lib
media
mnt
proc
root
run
sbin
srv
sys
tmp
usr
var
双横杠(--)代表kubectl命令项的结束,在双横杠后面的内容是指pod内部需要执行的命令。 回到顶部 5.2.连接集群外部的服务 5.2.1.介绍服务endpoint 服务并不是和pod直接相连的,介于他们之间的就是Endpoint资源。 Endpoint资源就是暴露一个服务的IP地址和端口列表。 通过service查看endpoint方法如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 $ kubectl -n kube-system get svc kube-dns NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kube-dns ClusterI P 10.187.0.2 53/UDP,53/TCP 19d
$ kubectl -n kube-system describe svc kube-dns
Name: kube-dns
Namespace: kube-system
Labels: addonmanager.kubernetes.io/mode=Reconcile
k8s-app=kube-dns
kubernetes.io/cluster-service=true
kubernetes.io/name=CoreDNS
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{"prometheus.io/scrape":"true"},"labels":{"addonmanager.kubernetes.io/mode":...
prometheus.io/scrape: true
Selector: k8s-app=kube-dns
Type: ClusterIP
IP: 10.187.0.2
Port: dns 53/UDP
TargetPort: 53/UDP
Endpoints: 10.186.0.2:53,10.186.0.3:53 //代表服务endpoint的pod的ip和端口列表
Port: dns-tcp 53/TCP
TargetPort: 53/TCP
Endpoints: 10.186.0.2:53,10.186.0.3:53
Session Affinity: None
Events:
直接查看endpoint信息方法如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#kubectl -n kube-system get endpoints kube-dns
NAME ENDPOINTS AGE
kube-dns 10.186.0.2:53,10.186.0.3:53,10.186.0.2:53 + 1 more... 19d
#kubectl -n kube-system describe endpoints kube-dns
Name: kube-dns
Namespace: kube-system
Labels: addonmanager.kubernetes.io/mode=Reconcile
k8s-app=kube-dns
kubernetes.io/cluster-service=true
kubernetes.io/name=CoreDNS
Annotations:
Subsets:
Addresses: 10.186.0.2,10.186.0.3
NotReadyAddresses:
Ports:
Name Port Protocol
---- ---- --------
dns 53 UDP
dns-tcp 53 TCP
Events:
5.2.2.手动配置服务的endpoint
如果创建pod时不包含选择器,则k8s将不会创建endpoint资源。这样就需要创建endpoint来指的服务的对应的endpoint列表。
service中创建endpoint资源,其中一个作用就是用于service知道包含哪些pod。
5.2.3.为外部服务创建别名
除了手动配置来访问外部服务外,还可以使用完全限定域名(FQDN)访问外部服务。
1
2
3
4
5
6
apiVersion: v1
kind: Service
metadata:
name: Service-yaohong
spec:
type: ExternalName //代码的type被设置成了ExternalName
1
externalName: someapi.somecompany.com // 实际服务的完全限定域名(FQDN)
port: - port: 80 服务创建完成后,pod可以通过external-service.default.svc.cluster.local域名(甚至是external-service)连接外部服务。 回到顶部 5.3.将服务暴露给外部客户端 有3种方式在外部访问服务: 1.将服务的类型设置成NodePort; 2.将服务的类型设置成LoadBalance; 3.创建一个Ingress资源。 5.3.1.使用nodeport类型的服务 NodePort 服务是引导外部流量到你的服务的最原始方式。NodePort,正如这个名字所示,在所有节点(虚拟机)上开放一个特定端口,任何发送到该端口的流量都被转发到对应服务。 YAML 文件类似如下: 1 2 3 4 5 6 7 8 9 10 11 12 apiVersion: v1 kind: Service metadata: name: Service-yaohong spec: type: NodePort //为NodePort设置服务类型 ports: - port: 80 targetPort: 8080 nodeport: 30123 //通过集群节点的30123端口可以访问服务 selector: app: yh 这种方法有许多缺点: 1.每个端口只能是一种服务 2.端口范围只能是 30000-32767 如果节点/VM 的 IP 地址发生变化,你需要能处理这种情况 基于以上原因,我不建议在生产环境上用这种方式暴露服务。如果你运行的服务不要求一直可用,或者对成本比较敏感,你可以使用这种方法。这样的应用的最佳例子是 demo 应用,或者某些临时应用。 5.3.2.通过Loadbalance将服务暴露出来 LoadBalancer 服务是暴露服务到 internet 的标准方式。在 GKE 上,这种方式会启动一个 Network Load Balancer[2],它将给你一个单独的 IP 地址,转发所有流量到你的服务。 通过如下方法来定义服务使用负载均衡 1 2 3 4 5 6 7 8 9 10 11 apiVersion: v1 kind: Service metadata: name: loadBalancer-yaohong spec: type: LoadBalancer //该服务从k8s集群的基础架构获取负载均衡器 ports: - port: 80 targetPort: 8080 selector: app: yh 何时使用这种方式? 如果你想要直接暴露服务,这就是默认方式。所有通往你指定的端口的流量都会被转发到对应的服务。它没有过滤条件,没有路由等。这意味着你几乎可以发送任何种类的流量到该服务,像 HTTP,TCP,UDP,Websocket,gRPC 或其它任意种类。 这个方式的最大缺点是每一个用 LoadBalancer 暴露的服务都会有它自己的 IP 地址,每个用到的 LoadBalancer 都需要付费,这将是非常昂贵的。 回到顶部 5.4.通过Ingress暴露服务 为什么使用Ingress,一个重要的原因是LoadBalancer服务都需要创建自己的负载均衡器,以及独有的公有Ip地址,而Ingress只需要一个公网Ip就能为许多服务提供访问。 5.4.1.创建Ingress资源 Ingress 事实上不是一种服务类型。相反,它处于多个服务的前端,扮演着“智能路由”或者集群入口的角色。 你可以用 Ingress 来做许多不同的事情,各种不同类型的 Ingress 控制器也有不同的能力。 编写如下ingress.yml文件 1 2 3 4 5 6 7 8 9 10 11 12 kind: Ingress metadata: name: ingressyaohong spec: rules: - host: kubia.example.com http: paths: - path: / backend: serviceName: kubia-nodeport servicePort: 80 通过如下命令进行查看ingress 1 # kubectl create -f ingress.yml 5.4.2.通过Ingress访问服务 通过kubectl get ing命令进行查看ingress 1 2 3 # kubectl get ing NAME HOSTS ADDRESS PORTS AGE ingressyaohong kubia.example.com 80 2m 了解Ingress的工作原理 何时使用这种方式? Ingress 可能是暴露服务的最强大方式,但同时也是最复杂的。Ingress 控制器有各种类型,包括 Google Cloud Load Balancer, Nginx,Contour,Istio,等等。它还有各种插件,比如 cert-manager[5],它可以为你的服务自动提供 SSL 证书。 如果你想要使用同一个 IP 暴露多个服务,这些服务都是使用相同的七层协议(典型如 HTTP),那么Ingress 就是最有用的。如果你使用本地的 GCP 集成,你只需要为一个负载均衡器付费,且由于 Ingress是“智能”的,你还可以获取各种开箱即用的特性(比如 SSL、认证、路由等等)。 5.4.3.通过相同的Ingress暴露多少服务 1.将不同的服务映射到相同的主机不同的路径 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 apiVersion: v1 kind: Ingress metadata: name: Ingress-yaohong spec: rules: - host: kubia.example.com http: paths: - path: /yh //对kubia.example.com/yh请求转发至kubai服务 backend: serviceName: kubia servicePort:80 - path: /foo //对kubia.example.com/foo请求转发至bar服务 backend: serviceName: bar servicePort:80 2.将不同的服务映射到不同的主机上 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 apiVersion: v1 kind: Ingress metadata: name: Ingress-yaohong spec: rules: - host: yh.example.com http: paths: - path: / //对yh.example.com请求转发至kubai服务 backend: serviceName: kubia servicePort:80 - host: bar.example.com http: paths: - path: / //对bar.example.com请求转发至bar服务 backend: serviceName: bar servicePort:80 5.4.4.配置Ingress处理TLS传输 客户端和控制器之间的通信是加密的,而控制器和后端pod之间的通信则不是。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 apiVersion: v1 kind: Ingress metadata: name: Ingress-yaohong spec: tls: //在这个属性中包含所有的TLS配置 - hosts: - yh.example.com //将接收来自yh.example.com的TLS连接 serviceName: tls-secret //从tls-secret中获得之前创立的私钥和证书 rules: - host: yh.example.com http: paths: - path: / //对yh.example.com请求转发至kubai服务 backend: serviceName: kubia servicePort:80 回到顶部 5.5.pod就绪后发出信号 5.5.1.介绍就绪探针 就绪探针有三种类型: 1.Exec探针,执行进程的地方。容器的状态由进程的退出状态代码确定。 2.HTTP GET探针,向容器发送HTTP GET请求,通过响应http状态码判断容器是否准备好。 3.TCP socket探针,它打开一个TCP连接到容器的指定端口,如果连接建立,则认为容器已经准备就绪。 启动容器时,k8s设置了一个等待时间,等待时间后才会执行一次准备就绪检查。之后就会周期性的进行调用探针,并根据就绪探针的结果采取行动。 如果某个pod未就绪成功,则会从该服务中删除该pod,如果pod再次就绪成功,则从新添加pod。 与存活探针区别: 就绪探针如果容器未准备就绪,则不会终止或者重启启动。 存活探针通过杀死异常容器,并用新的正常的容器来替代他保证pod正常工作。 就绪探针只有准备好处理请求pod才会接收他的请求。 重要性; 确保客户端只与正常的pod进行交互,并且永远不会知道系统存在问题。 5.5.2.向pod添加就绪探针 添加的yml文件如下 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 apiVersion: v1 kind: deployment ... spec: ... port: containers: - name: kubia-yh imgress: luksa/kubia readinessProbe: failureThreshold: 2 httpGet: path: /ping port: 80 scheme: HTTP initialDelaySeconds: 30 periodSeconds: 5 successThreshold: 1 timeoutSeconds: 3 相关参数解释如下: initialDelaySeconds:容器启动和探针启动之间的秒数。 periodSeconds:检查的频率(以秒为单位)。默认为10秒。最小值为1。 timeoutSeconds:检查超时的秒数。默认为1秒。最小值为1。 successThreshold:失败后检查成功的最小连续成功次数。默认为1.活跃度必须为1。最小值为1。 failureThreshold:当Pod成功启动且检查失败时,Kubernetes将在放弃之前尝试failureThreshold次。放弃生存检查意味着重新启动Pod。而放弃就绪检查,Pod将被标记为未就绪。默认为3.最小值为1。 HTTP探针在httpGet上的配置项: host:主机名,默认为pod的IP。 scheme:用于连接主机的方案(HTTP或HTTPS)。默认为HTTP。 path:探针的路径。 httpHeaders:在HTTP请求中设置的自定义标头。 HTTP允许重复的请求头。 port:端口的名称或编号。数字必须在1到65535的范围内 模拟就绪探针 1 2 3 4 # kubectl exec -- curl http://10.187.0.139:80/ping
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
回到顶部
5.6.使用headless服务发现独立的pod
5.6.1.创建headless服务
Headless Service也是一种Service,但不同的是会定义spec:clusterIP: None,也就是不需要Cluster IP的Service。
顾名思义,Headless Service就是没头的Service。有什么使用场景呢?
第一种:自主选择权,有时候client想自己来决定使用哪个Real Server,可以通过查询DNS来获取Real Server的信息。
第二种:Headless Services还有一个用处(PS:也就是我们需要的那个特性)。Headless Service的对应的每一个Endpoints,即每一个Pod,都会有对应的DNS域名;这样Pod之间就可以互相访问。https://www.cnblogs.com/yaohong/p/11478749.html
双横杠(--)代表kubectl命令项的结束,在双横杠后面的内容是指pod内部需要执行的命令。 回到顶部 5.2.连接集群外部的服务 5.2.1.介绍服务endpoint 服务并不是和pod直接相连的,介于他们之间的就是Endpoint资源。 Endpoint资源就是暴露一个服务的IP地址和端口列表。 通过service查看endpoint方法如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 $ kubectl -n kube-system get svc kube-dns NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kube-dns ClusterI P 10.187.0.2
port: - port: 80 服务创建完成后,pod可以通过external-service.default.svc.cluster.local域名(甚至是external-service)连接外部服务。 回到顶部 5.3.将服务暴露给外部客户端 有3种方式在外部访问服务: 1.将服务的类型设置成NodePort; 2.将服务的类型设置成LoadBalance; 3.创建一个Ingress资源。 5.3.1.使用nodeport类型的服务 NodePort 服务是引导外部流量到你的服务的最原始方式。NodePort,正如这个名字所示,在所有节点(虚拟机)上开放一个特定端口,任何发送到该端口的流量都被转发到对应服务。 YAML 文件类似如下: 1 2 3 4 5 6 7 8 9 10 11 12 apiVersion: v1 kind: Service metadata: name: Service-yaohong spec: type: NodePort //为NodePort设置服务类型 ports: - port: 80 targetPort: 8080 nodeport: 30123 //通过集群节点的30123端口可以访问服务 selector: app: yh 这种方法有许多缺点: 1.每个端口只能是一种服务 2.端口范围只能是 30000-32767 如果节点/VM 的 IP 地址发生变化,你需要能处理这种情况 基于以上原因,我不建议在生产环境上用这种方式暴露服务。如果你运行的服务不要求一直可用,或者对成本比较敏感,你可以使用这种方法。这样的应用的最佳例子是 demo 应用,或者某些临时应用。 5.3.2.通过Loadbalance将服务暴露出来 LoadBalancer 服务是暴露服务到 internet 的标准方式。在 GKE 上,这种方式会启动一个 Network Load Balancer[2],它将给你一个单独的 IP 地址,转发所有流量到你的服务。 通过如下方法来定义服务使用负载均衡 1 2 3 4 5 6 7 8 9 10 11 apiVersion: v1 kind: Service metadata: name: loadBalancer-yaohong spec: type: LoadBalancer //该服务从k8s集群的基础架构获取负载均衡器 ports: - port: 80 targetPort: 8080 selector: app: yh 何时使用这种方式? 如果你想要直接暴露服务,这就是默认方式。所有通往你指定的端口的流量都会被转发到对应的服务。它没有过滤条件,没有路由等。这意味着你几乎可以发送任何种类的流量到该服务,像 HTTP,TCP,UDP,Websocket,gRPC 或其它任意种类。 这个方式的最大缺点是每一个用 LoadBalancer 暴露的服务都会有它自己的 IP 地址,每个用到的 LoadBalancer 都需要付费,这将是非常昂贵的。 回到顶部 5.4.通过Ingress暴露服务 为什么使用Ingress,一个重要的原因是LoadBalancer服务都需要创建自己的负载均衡器,以及独有的公有Ip地址,而Ingress只需要一个公网Ip就能为许多服务提供访问。 5.4.1.创建Ingress资源 Ingress 事实上不是一种服务类型。相反,它处于多个服务的前端,扮演着“智能路由”或者集群入口的角色。 你可以用 Ingress 来做许多不同的事情,各种不同类型的 Ingress 控制器也有不同的能力。 编写如下ingress.yml文件 1 2 3 4 5 6 7 8 9 10 11 12 kind: Ingress metadata: name: ingressyaohong spec: rules: - host: kubia.example.com http: paths: - path: / backend: serviceName: kubia-nodeport servicePort: 80 通过如下命令进行查看ingress 1 # kubectl create -f ingress.yml 5.4.2.通过Ingress访问服务 通过kubectl get ing命令进行查看ingress 1 2 3 # kubectl get ing NAME HOSTS ADDRESS PORTS AGE ingressyaohong kubia.example.com 80 2m 了解Ingress的工作原理 何时使用这种方式? Ingress 可能是暴露服务的最强大方式,但同时也是最复杂的。Ingress 控制器有各种类型,包括 Google Cloud Load Balancer, Nginx,Contour,Istio,等等。它还有各种插件,比如 cert-manager[5],它可以为你的服务自动提供 SSL 证书。 如果你想要使用同一个 IP 暴露多个服务,这些服务都是使用相同的七层协议(典型如 HTTP),那么Ingress 就是最有用的。如果你使用本地的 GCP 集成,你只需要为一个负载均衡器付费,且由于 Ingress是“智能”的,你还可以获取各种开箱即用的特性(比如 SSL、认证、路由等等)。 5.4.3.通过相同的Ingress暴露多少服务 1.将不同的服务映射到相同的主机不同的路径 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 apiVersion: v1 kind: Ingress metadata: name: Ingress-yaohong spec: rules: - host: kubia.example.com http: paths: - path: /yh //对kubia.example.com/yh请求转发至kubai服务 backend: serviceName: kubia servicePort:80 - path: /foo //对kubia.example.com/foo请求转发至bar服务 backend: serviceName: bar servicePort:80 2.将不同的服务映射到不同的主机上 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 apiVersion: v1 kind: Ingress metadata: name: Ingress-yaohong spec: rules: - host: yh.example.com http: paths: - path: / //对yh.example.com请求转发至kubai服务 backend: serviceName: kubia servicePort:80 - host: bar.example.com http: paths: - path: / //对bar.example.com请求转发至bar服务 backend: serviceName: bar servicePort:80 5.4.4.配置Ingress处理TLS传输 客户端和控制器之间的通信是加密的,而控制器和后端pod之间的通信则不是。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 apiVersion: v1 kind: Ingress metadata: name: Ingress-yaohong spec: tls: //在这个属性中包含所有的TLS配置 - hosts: - yh.example.com //将接收来自yh.example.com的TLS连接 serviceName: tls-secret //从tls-secret中获得之前创立的私钥和证书 rules: - host: yh.example.com http: paths: - path: / //对yh.example.com请求转发至kubai服务 backend: serviceName: kubia servicePort:80 回到顶部 5.5.pod就绪后发出信号 5.5.1.介绍就绪探针 就绪探针有三种类型: 1.Exec探针,执行进程的地方。容器的状态由进程的退出状态代码确定。 2.HTTP GET探针,向容器发送HTTP GET请求,通过响应http状态码判断容器是否准备好。 3.TCP socket探针,它打开一个TCP连接到容器的指定端口,如果连接建立,则认为容器已经准备就绪。 启动容器时,k8s设置了一个等待时间,等待时间后才会执行一次准备就绪检查。之后就会周期性的进行调用探针,并根据就绪探针的结果采取行动。 如果某个pod未就绪成功,则会从该服务中删除该pod,如果pod再次就绪成功,则从新添加pod。 与存活探针区别: 就绪探针如果容器未准备就绪,则不会终止或者重启启动。 存活探针通过杀死异常容器,并用新的正常的容器来替代他保证pod正常工作。 就绪探针只有准备好处理请求pod才会接收他的请求。 重要性; 确保客户端只与正常的pod进行交互,并且永远不会知道系统存在问题。 5.5.2.向pod添加就绪探针 添加的yml文件如下 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 apiVersion: v1 kind: deployment ... spec: ... port: containers: - name: kubia-yh imgress: luksa/kubia readinessProbe: failureThreshold: 2 httpGet: path: /ping port: 80 scheme: HTTP initialDelaySeconds: 30 periodSeconds: 5 successThreshold: 1 timeoutSeconds: 3 相关参数解释如下: initialDelaySeconds:容器启动和探针启动之间的秒数。 periodSeconds:检查的频率(以秒为单位)。默认为10秒。最小值为1。 timeoutSeconds:检查超时的秒数。默认为1秒。最小值为1。 successThreshold:失败后检查成功的最小连续成功次数。默认为1.活跃度必须为1。最小值为1。 failureThreshold:当Pod成功启动且检查失败时,Kubernetes将在放弃之前尝试failureThreshold次。放弃生存检查意味着重新启动Pod。而放弃就绪检查,Pod将被标记为未就绪。默认为3.最小值为1。 HTTP探针在httpGet上的配置项: host:主机名,默认为pod的IP。 scheme:用于连接主机的方案(HTTP或HTTPS)。默认为HTTP。 path:探针的路径。 httpHeaders:在HTTP请求中设置的自定义标头。 HTTP允许重复的请求头。 port:端口的名称或编号。数字必须在1到65535的范围内 模拟就绪探针 1 2 3 4 # kubectl exec