Servicio ubicado en otro espacio de nombres

108

He estado tratando de encontrar una manera de definir un servicio en un espacio de nombres que se vincule a un Pod que se ejecuta en otro espacio de nombres. Sé que los contenedores en un Pod que se ejecutan namespaceApueden acceder serviceXdefinido en namespaceBal hacer referencia a él en el DNS del clúster como serviceX.namespaceB.svc.cluster.local, pero prefiero no tener el código dentro del contenedor que necesito saber sobre la ubicación de serviceX. Es decir, quiero que el código simplemente busque serviceXy luego pueda acceder a él.

La documentación de Kubernetes sugiere que esto es posible. Dice que una de las razones por las que definiría un servicio sin un selector es que desea apuntar su servicio a un servicio en otro espacio de nombres o en otro clúster .

Eso me sugiere que debería:

  1. Definir un serviceXservicio en namespaceA, sin un selector (ya que el POD que quiero seleccionar no está namespaceA).
  2. Definir un servicio (al que también llamé serviceX) namespaceBy luego
  3. Defina un objeto Endpoints en namespaceApara apuntar hacia serviceXadentro namespaceB.

Es este tercer paso el que no he podido realizar.

Primero, intenté definir el objeto Endpoints de esta manera:

kind: Endpoints
apiVersion: v1
metadata:
  name: serviceX
  namespace: namespaceA
subsets:
  - addresses:
      - targetRef:
          kind: Service
          namespace: namespaceB
          name: serviceX
          apiVersion: v1
    ports:
      - name: http
        port: 3000

Ese parecía el enfoque lógico, y obviamente para qué targetRefera. Pero, esto llevó a un error que decía que el ipcampo en la addressesmatriz era obligatorio. Entonces, mi siguiente intento fue asignar una dirección ClusterIP fija a serviceXin namespaceB, y ponerla en el campo IP (tenga en cuenta que service_cluster_ip_rangeestá configurado como 192.168.0.0/16y 192.168.1.1se asignó como ClusterIP para serviceXin namespaceB; serviceXen namespaceAse asignó automáticamente una ClusterIP diferente en la 192.168.0.0/16subred) :

kind: Endpoints
apiVersion: v1
metadata:
  name: serviceX
  namespace: namespaceA
subsets:
  - addresses:
        - ip: 192.168.1.1
          targetRef:
            kind: Service
            namespace: namespaceB
            name: serviceX
            apiVersion: v1
    ports:
      - name: http
        port: 3000

Eso fue aceptado, pero los accesos a serviceXin namespaceAno se reenviaron al Pod in namespaceB, se agotó el tiempo de espera. En cuanto a la configuración de iptables, parece que habría tenido que hacer un enrutamiento previo NAT dos veces para lograrlo.

Lo único que se encontró que funcionaba - pero no es una solución satisfactoria - es para buscar la dirección IP real de la vaina proporcionar serviceXen namespaceBy poner esa dirección en el objeto en puntos finales namespaceA. Eso no es satisfactorio, por supuesto, porque la dirección IP del Pod puede cambiar con el tiempo. Ese es el problema que las IP de servicio están ahí para resolver.

Entonces, ¿hay alguna manera de cumplir con lo que parece ser la promesa de la documentación de que puedo apuntar un servicio en un espacio de nombres a un servicio que se ejecuta en un espacio de nombres diferente?

Un comentarista preguntó por qué querría hacer esto; aquí hay un caso de uso que tiene sentido para mí, al menos:

Supongamos que tiene un sistema de múltiples inquilinos, que también incluye una función común de acceso a datos que se puede compartir entre inquilinos. Ahora imagine que hay diferentes sabores de esta función de acceso a datos con API comunes, pero diferentes características de rendimiento. Algunos inquilinos tienen acceso a uno de ellos, otros inquilinos tienen acceso a otro.

Los pods de cada inquilino se ejecutan en sus propios espacios de nombres, pero cada uno necesita acceder a uno de estos servicios comunes de acceso a datos, que necesariamente estará en otro espacio de nombres (ya que varios inquilinos acceden a él). Pero, no querrá que el inquilino tenga que cambiar su código si cambia su suscripción para acceder al servicio de mayor rendimiento.

Una posible solución (la más limpia que se me ocurre, si tan solo funcionara) es incluir una definición de servicio en el espacio de nombres de cada inquilino para el servicio de acceso a datos, con cada uno configurado para el punto final apropiado. Esta definición de servicio se configuraría para apuntar al servicio de acceso a datos adecuado que cada inquilino tiene derecho a usar.

David McKinley
fuente
el objetivo de los espacios de nombres es aislar, así que creo que si necesita cruzar espacios de nombres, debe saber al menos dónde se encuentra.
MrE
Entonces, ¿qué significa la documentación cuando sugiere que puede dirigir un servicio definido en un espacio de nombres para acceder a un servicio en un espacio de nombres diferente sin definir un selector y, por implicación, definir un punto final? Ciertamente, hay casos de uso válidos para esto, uno de los cuales agregué a la pregunta. ¿La documentación es engañosa o hay alguna manera de hacerlo que aún no he descubierto?
David McKinley
no estoy seguro, lo siento. Lo que sé es que accedo a servicios en múltiples espacios de nombres usando su fqdn. Hago esto especialmente con vpn, ya que tengo 1 vpn pod y me conecto a través de todos los servicios desde él. sin embargo, necesita conocer el espacio de nombres y proporcionar fqdn. Le sugiero que pregunte en el canal slack.
MrE
Usar fqdn es la solución que estoy usando actualmente. Sin embargo, mi caso de uso estaría mejor servido (ahora agregado a la pregunta) si eso no fuera necesario.
David McKinley
También me pregunto a qué se refiere la documentación, sin embargo, puedo usar fqdn como una solución satisfactoria para mi caso de uso.
Vincent De Smet

Respuestas:

222

Me encontré con el mismo problema y encontré una buena solución que no necesita ninguna configuración de IP estática:

Puede acceder a un servicio a través de su nombre DNS (como lo mencionó): servicename.namespace.svc.cluster.local

Puede usar ese nombre DNS para hacer referencia a él en otro espacio de nombres a través de un servicio local :

kind: Service
apiVersion: v1
metadata:
  name: service-y
  namespace: namespace-a
spec:
  type: ExternalName
  externalName: service-x.namespace-b.svc.cluster.local
  ports:
  - port: 80
Pablo
fuente
2
¡Esta es una gran solución! No estoy seguro de si el tipo "ExternalName" estaba disponible para los servicios cuando hice la pregunta originalmente, pero ahora es compatible y resuelve perfectamente el problema. Gracias, Paul.
David McKinley
1
¿Esto funciona? yo dudo. ¿Alguien puede confirmar si esto realmente funcionó, no funciona para mí?
debianmaster
2
Si lo hace. Funciona para que un pod hable con un servicio en otro espacio de nombres, pero no para un balanceador de carga de entrada.
Paul
Debido a la búsqueda de CNAME en el clúster de Kubernetes , la versión anterior tal vez no funcione.
赵浩翔
1
¿Funcionaría o debería funcionar esto también para los servicios en el espacio de nombres del sistema kube?
Nabheet
10

Es tan simple hacerlo

si quieres usarlo como host y quieres resolverlo

Si está utilizando embajador en cualquier otra puerta de enlace API para el servicio ubicado en otro espacio de nombres, siempre se sugiere usar:

            Use : <service name>
            Use : <service.name>.<namespace name>
            Not : <service.name>.<namespace name>.svc.cluster.local

será como: servicename.namespacename.svc.cluster.local

esto enviará una solicitud a un servicio en particular dentro del espacio de nombres que ha mencionado.

ejemplo:

kind: Service
apiVersion: v1
metadata:
  name: service
spec:
  type: ExternalName
  externalName: <servicename>.<namespace>.svc.cluster.local

Aquí reemplace <servicename>y <namespace>con el valor apropiado.

En Kubernetes, los espacios de nombres se utilizan para crear un entorno virtual, pero todos se conectan entre sí.

Áspero manvar
fuente
6
¿Podría explicar en qué se diferencia esta respuesta de la que dio Paul casi 2 años antes?
Oliver
2
@Oliver no hay diferencia, pero acabo de especificar qué reemplazar el nombre del servicio y el espacio de nombres en qué lugar en particular. aunque ha utilizado el espacio de nombres, me parece confuso.
Harsh Manvar
6
Un truco útil en SO es agregar un comentario sobre la respuesta y hacer las aclaraciones necesarias.
Oliver
4
Yo llamaría a esto como la mejor solución porque .svc.cluster.locales compatible de forma predeterminada para resolver el servicio internamente.
DrKNa
1
trabajado para mí también. gracias
vimal prakash
0

Puede lograr esto implementando algo en una capa más alta que los Servicios con espacio de nombres, como el equilibrador de carga del servicio https://github.com/kubernetes/contrib/tree/master/service-loadbalancer . Si desea restringirlo a un solo espacio de nombres, use el argumento "--namespace = ns" (predeterminado para todos los espacios de nombres: https://github.com/kubernetes/contrib/blob/master/service-loadbalancer/service_loadbalancer.go # L715 ). Esto funciona bien para L7, pero es un poco complicado para L4.

Prashanth B
fuente
3
Este proyecto está obsoleto ahora (agosto de 2018)
Nicola Ben
1
@Prashanth B: ¿Podrías actualizar tu respuesta en consecuencia?
chaosguru