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 外部访问:
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
-
-