Loading

k8s - Service ExternalName

类型ExternalName

类型为 ExternalName 的服务将服务映射到 DNS 名称,而不是典型的选择器,例如 my-service 或者 cassandra。 您可以使用 spec.externalName 参数指定这些服务。

例如,以下 Service 定义将 prod 名称空间中的 my-service 服务映射到 my.database.example.com

apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: my.database.example.com
说明: ExternalName 接受 IPv4 地址字符串,但作为包含数字的 DNS 名称,而不是 IP 地址。 类似于 IPv4 地址的外部名称不能由 CoreDNS 或 ingress-nginx 解析,因为外部名称旨在指定规范的 DNS 名称。 要对 IP 地址进行硬编码,请考虑使用 [headless Services](#headless-services)。

当查找主机 my-service.prod.svc.cluster.local 时,群集DNS服务返回 CNAME 记录,其值为 my.database.example.com。 访问 my-service 的方式与其他服务的方式相同,但主要区别在于重定向发生在 DNS 级别,而不是通过代理或转发。 如果以后您决定将数据库移到群集中,则可以启动其 Pod,添加适当的选择器或端点以及更改服务的类型

 

以下文章引用: https://www.qedev.com/cloud/244937.html

ExternalName 介绍

记得很多年前大陆流行音乐刚开始流行,李春波的一首《小芳》风靡大街小巷,正处于青春懵懂期的少男,顷刻间就被它的旋律捕获了,于是小芳就是初恋,初恋就是小芳.

后来上了大学,读了计算机系,学到了很多基于控制台的命令,但是不知道为什么,每当我敲打 ln 命令的时候,都会想起小芳,那时我天真地认为,只要找到了小芳,我就可以找到幸福,于是我向一个情场老手讨教全年级最好记的女生姓名叫什么?他想都没想,脱口而出——“殷静”、“史珍香”。

        后来学了 k8s,知道了常用的 k8s service 类型—— ClusterIP、NodePort、LoadBalancer,唯独对 externalName 置若罔闻,直到有一天在学习 Istio Sidecar 这种 API 资源的时候,才突然领悟了 ExternalName 这种 k8s service 类型是使用场景。

 ExternalName 这种 service 类型的作用类似软链或者快捷方式。下面举一个具体的例子。

 

 该样例目的是让处于 default 命名空间下的 httpd-pod 访问到处于 nginx-ns 命名空间下的 nginx-svc,不像以往 svc-name.ns-name.svc.cluster.local 方式跨命名空间访问的方式,这里我们使用 ExternalName 方式。

 jiuxi-client.yaml

 

 

 jiuxi-client-svc.yaml

 

 关键点就在这个文件,该文件中指定了到 nginx-svc 的软链,这么做的好处是对使用者做到了透明,让使用者感觉就好像调用自己命名空间的服务一样。

 

jiuxi-nginx.yaml

 

 

 

jiuxi-nginx-svc.yaml

 

 

jiuxi-ns.yaml

 

 

自此整个样例代码编写完毕。

首先创建 jiuxi-ns.yaml 命名空间,然后再应用其他资源文件,如下命令所示:

kubectl apply -f jiuxi-ns.yaml

kubectl apply -f jiuxi-client.yaml

kubectl apply -f jiuxi-client-svc.yaml

kubectl apply -f jiuxi-nginx.yaml

kubectl apply -f jiuxi-nginx-svc.yaml

     

验证样例

所有 pod 都争取运行之后,登录 client,然后执行如下语句:

wget -q -O - http://jiuxi-client-svc

wget -q -O - http://jiuxi-nginx-svc.nginx-ns.svc.cluster.local

        发现两种方式都可以正常访问。

 

扩展阅读 

K8S 最佳实践-映射外部服务

场景 1:具有 IP 地址的集群外数据库

其中一个常见场景是在集群外部托管自己的数据库,例如在 Google 计算引擎实例中。如果您在 Kubernetes 内部和外部分别运行一些服务,或者需要在 Kubernetes 允许的基础上获得更多定制或控制,通常可采用上述这种方式。

希望未来某个时候您可以将所有服务都移入集群内,但在此之前将是“内外混用”的状态。幸运的是,您可以使用静态 Kubernetes 服务来缓解上述痛点。

在本例中,我使用 Cloud Launcher 创建了一个 MongoDB 服务器。由于此服务器在与 Kubernetes 集群相同的网络(或 VPC)中创建,因此可以使用高性能的内部 IP 地址访问。在 Google Cloud 中,这是默认设置,因此无需进行任何特殊配置。

现在我们有了 IP 地址,那么第一步就是创建服务:

kind: Service

apiVersion: v1

metadata:

name: mongo

Spec:

type: ClusterIP

ports:

– port: 27017

targetPort: 27017

您可能会注意到此服务没有 Pod 选择器。此操作将创建一个服务,但它不知道往哪里发送流量。这样一来,您可以手动创建一个将从此服务接收流量的 Endpoints 对象。

kind: Endpoints

apiVersion: v1

metadata:

name: mongo

subsets:

– addresses:

– ip: 10.240.0.4

ports:

– port: 27017

您可以看到 Endpoints 手动定义了数据库的 IP 地址,并且使用的名称与服务名称相同。Kubernetes 将 Endpoints 中定义的所有 IP 地址视为与常规 Kubernetes Pod 一样。现在您可以用一个简单的连接字符串访问数据库:

mongodb://mongo

> 根本不需要在代码中使用 IP 地址!如果以后 IP 地址发生变化,您可以为端点更新 IP 地址,而应用无需进行任何更改。

场景 2:具有 URI 的远程托管数据库

如果您使用的是来自第三方的托管数据库服务,它们可能会为您提供可用于连接的统一资源标识符 (URI)。如果它们为您提供 IP 地址,则可以使用场景 1 中的方法。

在本例中,我在 mLab 上托管了两个 MongoDB 数据库。一个是我的开发数据库,另一个是生产数据库。

这些数据库的连接字符串如下所示:

mongodb://<dbuser>:<dbpassword>@ds149763.mlab.com:49763/devmongodb://<dbuser>:<dbpassword>@ds145868.mlab.com:45868/prodmLab

为您提供了动态 URI 和动态端口,您可以看到两者都不同。我们来使用 Kubernetes 基于这些差异创建一个抽象层。在本例中,我们将连接开发数据库。

您可以创建一个 “ExternalName” Kubernetes 服务,此服务为您提供将流量重定向到外部服务的静态 Kubernetes 服务。此服务在内核级别执行简单的 CNAME 重定向,因此对性能的影响非常小。

服务的 YAML 如下所示:

kind: Service

apiVersion: v1

metadata:

name: mongo

spec:

type: ExternalName

externalName: ds149763.mlab.com

现在,您可以使用更简化的连接字符串:

mongodb://<dbuser>:<dbpassword>@mongo:<port>/dev

由于 “ExternalName” 使用 CNAME 重定向,因此无法执行端口重映射。对于使用静态端口的服务来说,这可能不成问题,然而本例中使用的是动态端口。mLab 免费版为您提供了动态端口号,并且不允许更改。这意味着您需要对开发和生产数据库使用其他连接字符串。

但如果您可以获取 IP 地址,就可以执行端口重映射,关于此内容,我将在下一部分进行介绍。

场景 3:具有 URI 和端口重映射功能的远程托管数据库

CNAME 重定向对于每个环境均使用相同端口的服务非常有效,但如果每个环境的不同端点使用不同的端口,CNAME 重定向就略显不足。幸运的是我们可以使用一些基本工具来解决这个问题。

第一步是从 URI 获取 IP 地址。

对 URI 运行 nslookup、hostname 或 ping 命令即可获取数据库的 IP 地址。

您现在可以创建一个重新映射 mLab 端口的服务,并为此 IP 地址创建端点。

kind: Service

apiVersion: v1

metadata:

name: mongo

spec:

ports:

– port: 27017

targetPort: 49763

kind: Endpoints

apiVersion: v1

metadata:

name: mongo

subsets:

– addresses:

– ip: 35.188.8.12

ports:

– port: 49763

注:URI 可以使用 DNS 在多个 IP 地址之间进行负载平衡,因此,如果 IP 地址发生变化,这个方法可能会有风险!如果您通过上述命令获取多个 IP 地址,则可以将所有这些地址都包含在 Endpoints YAML 中,并且 Kubernetes 会在所有 IP 地址之间进行流量的负载平衡。

通过这种方式,您无需指定端口即可连接到远程数据库。Kubernetes 服务重映射端口的过程完全透明!

mongodb://<dbuser>:<dbpassword>@mongo/dev

结论

将外部服务映射到内部服务可让您未来灵活地将这些服务纳入集群,同时最大限度地减少重构工作。即使您今天不打算将服务加入集群,以后可能也会这样做!而且,这样一来,您可以更轻松地管理和了解组织所使用的外部服务。

如果外部服务具有有效域名,并且您不需要重新映射端口,那么使用 “ExternalName” 服务类型将外部服务映射到内部服务十分简便、快捷。如果您没有域名或需要执行端口重映射,只需将 IP 地址添加到端点并使用即可。

实例 

ExternalName
apiVersion: v1
kind: Service
metadata:
  name: "baiducom" # 设置 IP 14.215.177.39和www.baidu.com 错误,不允许'.'
spec:
  type: ExternalName
  externalName: "www.baidu.com" # 设置 IP 14.215.177.39 无效

# 所以 externalName 的意义就是为域名设置一个别名,如上 为 www.baidu.com 设置别名 baiducom,以便 pod 内容器使用
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  replicas: 1
  selector:
    matchLabels:
      app: busybox
  template:
    metadata:
      labels:
        app: busybox
    spec:
      containers:
        - name: busybox
          image: busybox
          command: ["/bin/sh", "-c", "sleep 3600"]

- 外部 IP 链接

ip.yaml 外部访问:

182.254.186.198:81
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    run: nginx
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
      name: http
      nodePort: 81
  selector:
    run: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      run: nginx
  replicas: 1
  template:
    metadata:
      labels:
        run: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
          ports:
            - containerPort: 80

kubectl apply -f ip.yaml

创建服务 ips.yaml

apiVersion: v1
kind: Service
metadata:
  name: nginx-ip
spec:
  ports:
    - protocol: TCP
      port: 88
      targetPort: 81
---
apiVersion: v1
kind: Endpoints
metadata:
  name: nginx-ip
subsets:
  - addresses:
      - ip: 182.254.186.198
    ports:
      - port: 81 # IP相关的端口,可以是外部连接端口,也可以是内部容器连接端口

kubectl apply -f ips.yaml

 

 -

 

 

posted @ 2020-07-06 15:34  microestc  阅读(10838)  评论(0编辑  收藏  举报