Kubernetes Service 服务
2020-04-10 by dongnan
开始之前
在前面的三篇文章中,至此我们已经准备好了K8S集群环境。
接下来我们将以在K8S集群运行一个真实的项目为目标,依次介绍项目所使用的K8S资源对象。
这个项目是一个典型的Web系统,使用 Java Spring Boot框架开发,需要使用 MySql、Redis数据库、NFS共享存储(多个Pod容器间共享文件)。
由于K8S环境部署在阿里云上,所以这里使用了阿里云提供的 RDS-Mysql 、RDS-Redis 数据库服务、NAS(NFS)
网络附加存储等中间件产品,对于K8S集群来说,我们需要将这些服务映射为K8S的资源对象。
项目使用的K8S的资源对象包括:
- PV&PVC,用于Pod数据卷(NFS)。
- Pod (volumeMounts、readinessProbe),挂载数据卷、健康检查。
- Secret,存储机密数据。
- Service,服务-外部域名(ExternalName)。
- NetworkPolicy,网络策略。
- LimitRange,限制资源。
- Ingress
环境
测试的k8s集群由一个Master管理节点、两个Worker计算节点组成,详细请参考这里。
目标
将阿里云的 RDS-Mysql 、RDS-Redis 产品映射为Kubernetes的Service对象。
举个栗子
Yaml文档
这里定义两个Service服务,yyi-db为Mysql数据库,yyi-rds为Redis数据库:
apiVersion: v1
kind: Service
metadata:
  namespace: yyi-prod
  name: yyi-db
spec:
  type: ExternalName    # 注意这里
  externalName: rm-8vxxxxxxxxxx7.mysql.zxxxxx.rds.aliyuncs.com
---
apiVersion: v1
kind: Service
metadata:
  namespace: yyi-prod
  name: yyi-rds
spec:
  type: ExternalName    # 注意这里
  externalName: r-8vxxxxxxxxxxro.redis.zxxxxx.rds.aliyuncs.com
创建Service
kubectl apply -f yii-dbs.yaml
验证
查看 Service 详细信息:
# Mysql
kubectl -n yyi-prod describe svc yyi-db
Name:              bulk-db
Namespace:         yyi-prod
Labels:            <none>
                   #...省略
Selector:          <none>
Type:              ExternalName
IP:                
External Name:     rm-8vxxxxxxxxxx7.mysql.zxxxxx.rds.aliyuncs.com
Session Affinity:  None
Events:            <none>
# Reids
kubectl -n yyi-prod describe svc yyi-rds 
Name:              bulk-rds
Namespace:         yyi-prod
Labels:            <none>
                   #...省略
Selector:          <none>
Type:              ExternalName
IP:                
External Name:     r-8vxxxxxxxxxxro.redis.zxxxxx.rds.aliyuncs.com
Session Affinity:  None
Events:            <none>
尝试使用yyi-serverPod容器访问创建的Service对象:
# 登录Pod控制台
kubectl -n yyi-prod exec -ti yyi-server-7xxxx94d-gxt6r /bin/bash
# 访问Mysql数据库
telnet yyi-db 3306
Trying 10.0.xx.215...
Connected to rm-8vxxxxxxxxxx7.mysql.zxxxxx.rds.aliyuncs.com.
Escape character is '^]'.
N
5.7.26-log�DP+Ag/#!D3\rUR.-rmysql_native_passworduqit
ot packets out of orderConnection closed by foreign host.
# 访问Redis数据库    
telnet yyi-rds 6379
Trying 10.0.xx.227...
Connected to r-8vxxxxxxxxxxro.redis.zxxxxx.rds.aliyuncs.com.
Escape character is '^]'.
quit
+OK
Connection closed by foreign host.
Pod容器成功访问到两个Service对象。
Service
Kubernetes 中 Service 是一个 API 对象,可以将符合Service指定条件的Pod作为可通过网络访问的服务,提供给服务调用者。
Service 具有服务发现机制:
- Pod拥有自己的- IP地址。
- Service被赋予一个唯一的- DNS名称。
- Service通过- label selector选定一组- Pod。
- Service实现负载均衡,可将请求均衡分发到选定这一组- Pod中。
Service类型
Service 服务类型如下:
- ClusterIP:通过集群的内部- IP暴露服务,选择该类型服务只能够在集群内部访问,这是默认的选项。
- NodePort:通过每个节点上的- IP和静态端口(- NodePort)暴露服务。通过请求- 节点IP:端口可以从集群的外部访问这个- NodePort服务。
- LoadBalancer:使用云提供商的负载均衡器向外部暴露服务。外部负载均衡器可以将流量路由到自动创建的- NodePort服务和- ClusterIP服务上。
- ExternalName:通过返回- CNAME和对应值,可以将服务映射到- externalName字段的内容,无需创建任何类型代理。
ClusterIP 示例
再来看一个Service例子:
---
apiVersion: v1
kind: Service
metadata:
  namespace: yyi-prod
  name: yyi-server-svc
  labels:
    app: yyi-server-svc
spec:
  selector:
    app: yyi-server
  ports:
  - name: yyi-server-svc
    protocol: TCP
    port: 80
    targetPort: 8080
  type: ClusterIP # ClusterIP/NodePort/LoaderBalancer
  # sessionAffinity: ClientIP  # ClientIP/None
这个Service类型为ClusterIP用于K8S集群内部的Pod访问,
可以通过 yyi-server-svc:8080 这个地址进行访问的,这个 yaml 指定后端Pod必须带有 app:yyi-server 这个标签。
这与 Kubernetes Pod 数据卷与健康检查 Deployment 定义的 spec.template.metadata.labels 相对应:
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: yii-prod
  name: yii-server
  #...省略 
spec:
  replicas: 1
  selector:
    matchLabels:
      app: yii-server
  template:
    metadata:
      labels:
        app: yii-server     # 这里
    spec:
#...省略
创建Service
kubectl apply -f yii-svc.yaml
验证
新创建了 yyi-asset-sv 服务,至此拥有3个Service对象:
kubectl -n yyi-prod get svc
NAME              TYPE           CLUSTER-IP       EXTERNAL-IP                                      PORT(S)   AGE
yyi-db            ExternalName   <none>           rm-8vxxxxxxxxxx7.mysql.zxxxxx.rds.aliyuncs.com   <none>    159d
yyi-rds           ExternalName   <none>           r-8vxxxxxxxxxxro.redis.zxxxxx.rds.aliyuncs.com   <none>    159d
yyi-server-svc    ClusterIP      172.19.xxx.231   <none>                                           80/TCP    159d
NodePort 实例
之前我们部署 Ingress控制器时,所使用的 Service类型就是 NodePort:
kubectl -n ingress-nginx get svc
NAME            TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx   NodePort   172.19.xxx.223   <none>        80:32001/TCP,443:32002/TCP   613d
选择NodePort类型就是希望暴露ECS的端口给上游的SLB负载均衡器使用,也就是从集群的外部访问这个服务。
验证
通过请求节点IP:端口的方式,访问到了Ingress控制器:
# 节点 host1
curl -IL host1:32001
HTTP/1.1 404 Not Found
Server: nginx/1.17.8
Date: Wed, 08 Dec 2021 05:47:16 GMT
Content-Type: text/html
Content-Length: 153
Connection: keep-alive
小结
- Kubernetes 的 Service对象底层使用了诸如iptables、ipvs等技术。
- 此外Service对象还有其它的形式,如Headless Service、不带标签选择器的外部服务Service、多端口Service等等。
详细信息请参考 kubernetes 官方文档 。