云原生 从docker、Jenkins、Kubernetes从入门到精通系列
什么是Service
- 负载均衡服务。让一组Pod可以被别人进行服务发现。
- Service --- > 选择一组Pod
- 别人只需要访问这个Service。Service还会基于Pod的探针机制(ReadinessProbe:就绪探针)完成Pod的自动剔除和上线工作。
- Service即使是无头服务。别人(Pod)不能用ip访问,但是可以用service名当成域名访问。
- Service的名字还能当成域名被Pod解析
1、基础概念
将运行在一组 Pods 上的应用程序公开为网络服务的抽象方法。
ClusterIP:通过集群的内部 IP 暴露服务,选择该值时服务只能够在集群内部访问。 这也是默认的ServiceType。- NodePort:通过每个节点上的 IP 和静态端口(
NodePort)暴露服务。NodePort服务会路由到自动创建的ClusterIP服务。 通过请求<节点 IP>:<节点端口>,你可以从集群的外部访问一个NodePort服务。 - LoadBalancer:使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的
NodePort服务和ClusterIP服务上。 - ExternalName:通过返回
CNAME和对应值,可以将服务映射到externalName字段的内容(例如,foo.bar.example.com)。 无需创建任何类型代理。
1、创建简单Service
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp ## 使用选择器选择所有Pod
# type: ClusterIP ##type很重要,不写默认是ClusterIP
ports:
- protocol: TCP
port: 80
targetPort: 9376
- Service 创建完成后,会对应一组EndPoint。可以kubectl get ep 进行查看
- type有四种,每种对应不同服务发现机制
- Servvice可以利用Pod的就绪探针机制,只负载就绪了的Pod。自动剔除没有就绪的Pod
2、创建无Selector的Service
- 我们可以创建Service不指定Selector
- 然后手动创建EndPoint,指定一组Pod地址。
- 此场景用于我们负载均衡其他中间件场景。
原理:kube-proxy 在负责这个事情
# 无selector的svc
apiVersion: v1
kind: Service
metadata:
name: my-service-no-selector
spec:
ports:
- protocol: TCP
name: http ###一定注意,name可以不写,
###但是这里如果写了name,那么endpoint里面的ports必须有同名name才能绑定
port: 80 # service 80
targetPort: 80 #目标80
---
apiVersion: v1
kind: Endpoints
metadata:
name: my-service-no-selector ### ep和svc的绑定规则是:和svc同名同名称空间,port同名或同端口
namespace: default
subsets:
- addresses:
- ip: 220.181.38.148
- ip: 39.156.69.79
- ip: 192.168.169.165
ports:
- port: 80
name: http ## svc有name这里一定要有
protocol: TCP
e.g. Pod要访问 MySQL。 MySQL单独部署到很多机器,每次记ip麻烦.
集群内创建一个Service,实时的可以剔除EP信息。反向代理集群外的东西。
2、ClusterIP
type: ClusterIP
ClusterIP: 手动指定/None/""
- 手动指定的ClusterIP必须在合法范围内
- None会创建出没有ClusterIP的headless service(无头服务) ,Pod需要用服务的域名访问
3、NodePort
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: default
type: NodePort
ports:
- protocol: TCP
port: 80 # service 80
targetPort: 80 #目标80
nodePort: 32123 #自定义
- 如果将
type字段设置为NodePort,则 Kubernetes 将在--service-node-port-range标志指定的范围内分配端口(默认值:30000-32767) - k8s集群的所有机器都将打开监听这个端口的数据,访问任何一个机器,都可以访问这个service对应的Pod
- 使用 nodePort 自定义端口
4、ExternalName
apiVersion: v1
kind: Service
metadata:
name: my-service-05
namespace: default
spec:
type: ExternalName
externalName: baidu.com
- 其他的Pod可以通过访问这个service而访问其他的域名服务
- 但是需要注意目标服务的跨域问题
5、LoadBalancer
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app.kubernetes.io/name: load-balancer-example
name: my-service
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app.kubernetes.io/name: load-balancer-example
type: LoadBalancer
6、扩展 - externalIP
在 Service 的定义中, externalIPs 可以和任何类型的 .spec.type 一通使用。在下面的例子中,客户端可通过 80.11.12.10:80 (externalIP:port) 访问my-service
apiVersion: v1
kind: Service
metadata:
name: my-service-externalip
spec:
selector:
app: canary-nginx
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
externalIPs: ### 定义只有externalIPs指定的地址才可以访问这个service
- 10.170.0.111 ### 集群内的ip都不行?
其他机器的ip、黑名单????,这里需要再测试一下。
7、扩展 - Pod的DNS
apiVersion: v1
kind: Service
metadata:
name: default-subdomain
spec:
selector:
name: busybox
clusterIP: None
ports:
- name: foo # 实际上不需要指定端口号
port: 1234
targetPort: 1234
---
apiVersion: v1
kind: Pod
metadata:
name: busybox1
labels:
name: busybox
spec:
hostname: busybox-1
subdomain: default-subdomain
## 指定必须和svc名称一样,才可以 podName.subdomain.名称空间.svc.cluster.local访问。否则访问不同指定Pod
containers:
- image: busybox:1.28
command:
- sleep
- "3600"
name: busybox
---
apiVersion: v1
kind: Pod
metadata:
name: busybox2
labels:
name: busybox
spec:
hostname: busybox-2 ### 每个Pod指定主机名
subdomain: default-subdomain ## subdomain等于sevrice的名
containers:
- image: busybox:1.28
command:
- sleep
- "3600"
name: busybox
- 访问 busybox-1.default-subdomain.default.
svc.cluster.local可以访问到busybox-1。 - 访问Service
- 同名称空间
- ping service-name 即可
- 不同名称空间
- ping service-name.namespace 即可
- 同名称空间
- 访问Pod
- 同名称空间
- ping pod-host-name.service-name 即可
- 不同名称空间
- ping pod-host-name.service-name.namespace 即可
- 同名称空间
busybox-1.default-subdomain.default
Pod的hostName.service的名.名称空间的名
想要使用域名访问的模式,必须加Service网络的名字