跳转至

Kubernetes Service 服务


2020-04-10 by dongnan

开始之前

在前面的三篇文章中,至此我们已经准备好了K8S集群环境。

接下来我们将以在K8S集群运行一个真实的项目为目标,依次介绍项目所使用的K8S资源对象。

这个项目是一个典型的Web系统,使用 Java Spring Boot框架开发,需要使用 MySqlRedis数据库、NFS共享存储(多个Pod容器间共享文件)。

由于K8S环境部署在阿里云上,所以这里使用了阿里云提供的 RDS-MysqlRDS-Redis 数据库服务、NAS(NFS) 网络附加存储等中间件产品,对于K8S集群来说,我们需要将这些服务映射为K8S的资源对象。

项目使用的K8S的资源对象包括:

环境

测试的k8s集群由一个Master管理节点、两个Worker计算节点组成,详细请参考这里

目标

将阿里云的 RDS-MysqlRDS-Redis 产品映射为KubernetesService对象。

举个栗子

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对象底层使用了诸如iptablesipvs等技术。
  • 此外Service对象还有其它的形式,如Headless Service、不带标签选择器的外部服务Service、多端口Service 等等。

详细信息请参考 kubernetes 官方文档

参考

回到页面顶部