一、service简介
在kubernetes中,pod是应用程序的载体,我们可以通过pod的ip来访问应用程序,但是pod的ip地址不是固定的,这也就意味着不方便直接采用pod的ip对服务进行访问。
为了解决这个问题,kubernetes提供了Service资源,Service会对提供同一个服务的多个pod进行聚合,并且提供一个统一的入口地址。通过访问Service的入口地址就能访问到后面的pod服务。
Service在很多情况下只是一个概念,真正起作用的其实是kube-proxy服务进程,每个Node节点上都运行着一个kube-proxy服务进程。当创建Service的时候会通过api-server向etcd写入创建的service的信息,而kube-proxy会基于监听的机制发现这种Service的变动,然后它会将最新的Service信息转换成对应的访问规则。
二、service资源清单
kind: Service # 资源类型
apiVersion: v1 # 资源版本
metadata: # 元数据
name: service # 资源名称
namespace: dev # 命名空间
spec: # 描述
selector: # 标签选择器,用于确定当前service代理哪些pod
app: nginx
type: # Service类型,指定service的访问方式
clusterIP: # 虚拟服务的ip地址
sessionAffinity: # session亲和性,支持ClientIP、None两个选项
ports: # 端口信息
- protocol: TCP
port: 3017 # service端口
targetPort: 5003 # pod端口
nodePort: 31122 # 主机端口
ClusterIP:默认值,它是Kubernetes系统自动分配的虚拟IP,只能在集群内部访问
NodePort:将Service通过指定的Node上的端口暴露给外部,通过此方法,就可以在集群外部访问服务
LoadBalancer:使用外接负载均衡器完成到服务的负载分发,注意此模式需要外部云环境支持ExternalName: 把集群外部的服务引入集群内部,直接使用
三、环境准备
在使用service之前,首先利用Deployment创建出3个pod
[root@t3-tkhijbs-jcsszy-app09 yaml]# cat nginx-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: pc-deployment
namespace: dev
spec:
replicas: 3
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
查看详情
[root@t3-tkhijbs-jcsszy-app09 yaml]# kubectl apply -f nginx-pod.yaml
deployment.apps/pc-deployment created
[root@t3-tkhijbs-jcsszy-app09 yaml]# kubectl get pod -n dev --show-labels
NAME READY STATUS RESTARTS AGE LABELS
pc-deployment-7d7dd5499b-l5r7v 1/1 Running 0 28s app=nginx-pod,pod-template-hash=7d7dd5499b
pc-deployment-7d7dd5499b-lx64t 1/1 Running 0 28s app=nginx-pod,pod-template-hash=7d7dd5499b
pc-deployment-7d7dd5499b-tmdg9 1/1 Running 0 28s app=nginx-pod,pod-template-hash=7d7dd5499b
为了方便后面的测试,修改下三台nginx的index.html页面(三台修改的IP地址不一致)
1.进入POD
修改pod1
kubectl exec -it pc-deployment-7d7dd5499b-l5r7v -n dev -- /bin/bash
root@pc-deployment-7d7dd5499b-l5r7v:/# cd /usr/share/nginx/html/
root@pc-deployment-7d7dd5499b-l5r7v:/usr/share/nginx/html# echo "pod01" > index.html
修改pod2
kubectl exec -it pc-deployment-7d7dd5499b-lx64t -n dev -- /bin/bash
root@pc-deployment-7d7dd5499b-lx64t:/# cd /usr/share/nginx/html/
root@pc-deployment-7d7dd5499b-lx64t:/usr/share/nginx/html# echo "pod2" > index.html
修改pod3
kubectl exec -it pc-deployment-7d7dd5499b-tmdg9 -n dev -- /bin/bash
root@pc-deployment-7d7dd5499b-tmdg9:/# cd usr/share/nginx/html/
root@pc-deployment-7d7dd5499b-tmdg9:/usr/share/nginx/html# echo "pod3" > index.html
2.访问pod
[root@t3-tkhijbs-jcsszy-app09 yaml]# kubectl get pod -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pc-deployment-7d7dd5499b-l5r7v 1/1 Running 0 53m 10.244.2.154
pc-deployment-7d7dd5499b-lx64t 1/1 Running 0 53m 10.244.2.156
pc-deployment-7d7dd5499b-tmdg9 1/1 Running 0 53m 10.244.2.155
[root@t3-tkhijbs-jcsszy-app09 yaml]# curl 10.244.2.154
pod01
[root@t3-tkhijbs-jcsszy-app09 yaml]# curl 10.244.2.155
pod3
[root@t3-tkhijbs-jcsszy-app09 yaml]# curl 10.244.2.156
pod2
四、ClusterIP类型的Service
基于上边的环境开始
1.创建service
[root@t3-tkhijbs-jcsszy-app09 yaml]# cat nginx-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: service-clusterip
namespace: dev
spec:
selector:
app: nginx-pod #为标签为这个标签的pod创建svc
#clusterIP: 10.97.97.97 service的ip地址,如果不写,默认会生成一个
type: ClusterIP
ports:
- port: 80 # Service端口 可以自定义端口
targetPort: 80 # pod端口
2.查看service
[root@t3-tkhijbs-jcsszy-app09 yaml]# kubectl get svc -n dev
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service-clusterip ClusterIP 10.0.0.63 <none> 80/TCP 4m57s
3.通过service访问pod
[root@t3-tkhijbs-jcsszy-app09 yaml]# curl 10.0.0.63
pod2
[root@t3-tkhijbs-jcsszy-app09 yaml]# curl 10.0.0.63
pod3
[root@t3-tkhijbs-jcsszy-app09 yaml]# curl 10.0.0.63
pod01
[root@t3-tkhijbs-jcsszy-app09 yaml]# curl 10.0.0.63
pod2
[root@t3-tkhijbs-jcsszy-app09 yaml]# curl 10.0.0.63
pod3
[root@t3-tkhijbs-jcsszy-app09 yaml]# curl 10.0.0.63
pod01
4.缺点
此类型的service只能用于集群内部
五、NodePort类型的service
在之前的样例中,创建的Service的ip地址只有集群内部才可以访问,如果希望将Service暴露给集群外部使用,那么就要使用到另外一种类型的Service,称为NodePort类型。NodePort的工作原理其实就是将service的端口映射到Node的一个端口上,然后就可以通过NodeIp:NodePort
来访问service了。
1.创建service
apiVersion: v1
kind: Service
metadata:
name: service-nodeport
namespace: dev
spec:
selector:
app: nginx-pod
type: NodePort # service类型
ports:
- port: 80 # Service端口 可以自定义端口
nodePort: 30002 # 指定绑定的node的端口(默认的取值范围是:30000-32767), 如果不指定,会默认分配
targetPort: 80 #pod的端口
2.查看svc
[root@t3-tkhijbs-jcsszy-app09 yaml]# kubectl apply -f nginx-svc.yaml
service/service-clusterip created
[root@t3-tkhijbs-jcsszy-app09 yaml]# kubectl get svc -n dev
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service-clusterip NodePort 10.0.0.86 <none> 80:30002/TCP 29s
[root@t3-tkhijbs-jcsszy-app09 yaml]# kubectl get nodes -o wide |awk '{print $6}'
INTERNAL-IP
10.154.140.64
10.154.140.65
10.154.140.66
10.154.140.67
3.通过service访问pod
[root@t3-tkhijbs-jcsszy-app09 yaml]# curl 10.154.140.64:30002
pod3
[root@t3-tkhijbs-jcsszy-app09 yaml]# curl 10.154.140.64:30002
pod01
[root@t3-tkhijbs-jcsszy-app09 yaml]# curl 10.154.140.64:30002
pod2
[root@t3-tkhijbs-jcsszy-app09 yaml]# curl 10.154.140.67:30002
pod2
[root@t3-tkhijbs-jcsszy-app09 yaml]# curl 10.154.140.67:30002
pod3
[root@t3-tkhijbs-jcsszy-app09 yaml]# curl 10.154.140.67:30002
pod01
这说明通过任何一个node的30002端口都可以访问到pod的内容
六、ingress
NodePort方式的缺点是会占用很多集群机器的端口,那么当集群服务变多的时候,这个缺点就愈发明显
基于这种现状,kubernetes提供了Ingress资源对象,Ingress只需要一个NodePort或者一个LB就可以满足暴露多个Service的需求。工作机制大致如下图表示:
- ingress:kubernetes中的一个对象,作用是定义请求如何转发到service的规则
- ingress controller:具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,根据配置的规则来实现请求转发,实现方式有很多,比如Nginx, Contour, Haproxy等等
Ingress(以Nginx为例)的工作原理如下:
- 用户编写Ingress规则,说明哪个域名对应kubernetes集群中的哪个Service
- Ingress控制器动态感知Ingress服务规则的变化,然后生成一段对应的Nginx反向代理配置
- Ingress控制器会将生成的Nginx配置写入到一个运行着的Nginx服务中,并动态更新
- 到此为止,其实真正在工作的就是一个Nginx了,内部配置了用户定义的请求转发规则
要使用Ingress 需要要有ingress pod。安装过程百度就好。
[root@t3-tkhijbs-jcsszy-app09 yaml]# kubectl get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
nginx-ingress-controller-6b8fd66c-4x5rq 1/1 Running 0 69d
环境准备service和pod
[root@t3-tkhijbs-jcsszy-app09 yaml]# cat tomcat-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: dev
spec:
replicas: 3
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deployment
namespace: dev
spec:
replicas: 3
selector:
matchLabels:
app: tomcat-pod
template:
metadata:
labels:
app: tomcat-pod
spec:
containers:
- name: tomcat
image: tomcat:8.5-jre10-slim
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: dev
spec:
selector:
app: nginx-pod
clusterIP: None
type: ClusterIP
ports:
- port: 80
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: tomcat-service
namespace: dev
spec:
selector:
app: tomcat-pod
clusterIP: None
type: ClusterIP
ports:
- port: 8080
targetPort: 8080
[root@t3-tkhijbs-jcsszy-app09 yaml]# kubectl apply -f tomcat-nginx.yaml
deployment.apps/nginx-deployment created
deployment.apps/tomcat-deployment created
service/nginx-service created
service/tomcat-service created
[root@t3-tkhijbs-jcsszy-app09 yaml]# kubectl get pod -n dev
NAME READY STATUS RESTARTS AGE
nginx-deployment-6fff47d65b-27tb2 1/1 Running 0 2m6s
nginx-deployment-6fff47d65b-btpzk 1/1 Running 0 2m6s
nginx-deployment-6fff47d65b-pxdd4 1/1 Running 0 2m6s
tomcat-deployment-7d5fcd4756-5nvfz 1/1 Running 0 2m6s
tomcat-deployment-7d5fcd4756-8mjkt 1/1 Running 0 2m6s
tomcat-deployment-7d5fcd4756-pfwmx 1/1 Running 0 2m6s
[root@t3-tkhijbs-jcsszy-app09 yaml]# kubectl get svc -n dev
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service ClusterIP None <none> 80/TCP 2m33s
tomcat-service ClusterIP None <none> 8080/TCP 2m33s
1.http代理
创建ingress-http.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-http
namespace: dev
spec:
rules:
- host: nginx.test.com
http: #使用的http协议
paths:
- path: /
backend:
serviceName: nginx-service #对应得kubectl get svc -n dev里得service名称
servicePort: 80 #对应service暴露得端口
- host: tomcat.test.com
http:
paths:
- path: /
backend:
serviceName: tomcat-service
servicePort: 8080
[root@t3-tkhijbs-jcsszy-app09 yaml]# kubectl apply -f ingress-http.yaml
ingress.extensions/ingress-http created
[root@t3-tkhijbs-jcsszy-app09 yaml]# kubectl get ing -n dev
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-http <none> nginx.test.com,tomcat.test.com 80 57s
也可以查看详细规则
[root@t3-tkhijbs-jcsszy-app09 yaml]# kubectl describe ing ingress-http -n dev
......
Rules:
Host Path Backends
---- ---- --------
nginx.test.com
/ nginx-service:80 (10.244.2.157:80,10.244.2.160:80,10.244.2.162:80)
tomcat.test.com
/ tomcat-service:8080 (10.244.2.158:8080,10.244.2.159:8080,10.244.2.161:8080)
......
更改hosts
[root@t3-tkhijbs-jcsszy-app09 yaml]# cat /etc/hosts
10.154.140.64 nginx.test.com tomcat.test.com
[root@t3-tkhijbs-jcsszy-app09 yaml]# curl -I nginx.test.com
HTTP/1.1 200 OK
Server: nginx/1.17.8
Date: Sun, 06 Feb 2022 14:59:11 GMT
Content-Type: text/html
Content-Length: 615
Connection: keep-alive
Vary: Accept-Encoding
Last-Modified: Tue, 25 Jan 2022 15:03:52 GMT
ETag: "61f01158-267"
Accept-Ranges: bytes
[root@t3-tkhijbs-jcsszy-app09 yaml]# curl -I tomcat.test.com
HTTP/1.1 200
Server: nginx/1.17.8
Date: Sun, 06 Feb 2022 14:59:17 GMT
Content-Type: text/html;charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
2.https代理
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-https
namespace: dev
spec:
tls:
- hosts:
- nginx.itheima.com
- tomcat.itheima.com
secretName: xxxxxxxxx # 指定秘钥
rules:
- host: nginx.itheima.com
http:
paths:
- path: /
backend:
serviceName: nginx-service
servicePort: 80
- host: tomcat.itheima.com
http:
paths:
- path: /
backend:
serviceName: tomcat-service
servicePort: 8080