K8S 之 Service

摘要

Service 介绍

  • Service是一个抽象层,它定义了一组Pod的逻辑集,并为这些Pod支持外部流量暴露、负载均衡和服务发现。

  • 尽管每个Pod 都有一个唯一的IP地址,但是如果没有Service,这些IP不会暴露在群集外部。

  • Service允许您的应用程序接收流量。

  • Service也可以用在ServiceSpec标记type的方式暴露,type类型如下:

    • ClusterIP(默认):在集群的内部IP上公开Service。这种类型使得Service只能从集群内访问。
    • NodePort:使用NAT在集群中每个选定Node的相同端口上公开Service。使用 : 从集群外部访问Service。是ClusterIP的超集。
    • LoadBalancer:在当前云中创建一个外部负载均衡器(如果支持的话),并为Service分配一个固定的外部IP。是NodePort的超集。
    • ExternalName:通过返回带有该名称的CNAME记录,使用任意名称(由spec中的externalName指定)公开Service。不使用代理。

创建Service

命令行方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 先创建deployment,此时会为每个pod添加一个label app=nginx
kubectl create deployment nginx --image=nginx --replicas=2

# 创建service,,将deployment的pod暴露出来,暴露类型为ClusterIP
kubectl expose deployment nginx --type=ClusterIP --port=80
$ kubectl get svc nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP 10.96.14.90 <none> 80/TCP 60s


# 创建service,将deployment的pod暴露出来,暴露类型为NodePort
kubectl expose deployment nginx --type=NodePort --port=80
# 查看service,此时可以看到service的端口和节点的端口,与 ClusterIP 的区别就是是否暴露在节点上的端口
$ kubectl get svc nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx NodePort 10.96.7.8 <none> 80:32691/TCP 31s

yaml文件创建service

  • yaml文件格式

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1      # api版本
kind: Service # 资源类型
metadata: # 元数据
name: nginx # service名称
spec: # 配置
ports: # 端口
- port: 80 # 集群内访问端口,service的端口,一般配置为与 targetPort 一致,但是非必须
protocol: TCP # 协议
targetPort: 80 # 容器端口, pod的端口,这个必须与实际容器端口一致
nodePort: 30080 # node暴露的端口,service类型为 NodePort 时使用,默认范围在 30000-32767 之间
selector: # 选择器
app: nginx # pod的标签,即匹配pod的标签 app=nginx
type: NodePort # service类型
  • 这里有个问题需要注意,service 默认是通过标签来匹配pod的,所以创建service的时候,一定要保证pod的标签是存在的,否则service无法匹配pod,另外虽然我们通过命令行创建service时是通过kubectl expose deployment nginx --type=NodePort --port=80创建的,但也并不表示service只会匹配这个deployment创建的pod,而是会匹配所有具有指定标签的pod(app=nginx)。

1
2
3
4
5
6
7
8
9
10
11
12
# 获取service的 selector
$ k get svc -owide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4d5h <none>
nginx NodePort 10.96.9.77 <none> 80:30080/TCP 8s app=nginx

# 这里有个名称为 kubernetes 的 service,其作用是为了方便集群内部的 Pod 调用 API Server 的统一入口
# 无论 API Server 实际运行在哪个节点哪个 IP,集群内部只要访问如下地址就能访问 API Server。
# https://kubernetes.default.svc
# 或者
# https://10.96.0.1
# 这个 Service 是 系统自带的,不建议删除或修改。

访问service,轮询pod

1
2
3
4
5
6
7
8
9
10
## 在集群内,通过 CLUSTER-IP 访问
curl 10.96.9.77
# 实际上在集群内部可以通过 <serviceName>.default.svc.cluster.local 访问,比如本示例为
curl nginx.default.svc.cluster.local
# 这是因为在创建 service前,我们是不知道 service 的 IP 地址的,所以在其它pod中就可以预先使用 serviceName.default.svc.cluster.local 访问,k8s会自动将 serviceName.default.svc.cluster.local 解析为 service 的 CLUSTER-IP
# 在相同的 namespace 中,可以通过 serviceName 直接访问
curl nginx

## 在集群外,通过 NODE-IP:NODE-PORT 访问
curl 10.211.55.16:30080

管理service

  • 查看service

1
2
3
4
5
6
7
8
9
10
11
12
# 查看service
kubectl get svc
# 查看指定namespace下的service
kubectl get svc -n kube-system
# 查看全部service
kubectl get svc -A
# 查看service详情
kubectl get svc nginx -o yaml
kubectl describe svc nginx

# 查看日志
k logs svc/nginx
  • 编辑service,保存(:wq)后生效,不需要额外 apply 或 restart

1
kubectl edit svc nginx
  • 删除service

1
kubectl delete svc nginx