Service situé dans un autre espace de noms

108

J'ai essayé de trouver un moyen de définir un service dans un espace de noms lié à un pod fonctionnant dans un autre espace de noms. Je sais que les conteneurs d'un pod en cours d'exécution namespaceApeuvent accéder serviceXdéfinis dans namespaceBen le référençant dans le DNS du cluster comme serviceX.namespaceB.svc.cluster.local, mais je préfère ne pas avoir le code à l'intérieur du conteneur besoin de connaître l'emplacement de serviceX. Autrement dit, je veux que le code recherche simplement serviceXet puisse y accéder.

La documentation Kubernetes suggère que cela est possible. Il indique que l'une des raisons pour lesquelles vous définiriez un service sans sélecteur est que vous souhaitez pointer votre service vers un service dans un autre espace de noms ou sur un autre cluster .

Cela me suggère que je devrais:

  1. Définissez un serviceXservice dans namespaceA, sans sélecteur (puisque le POD que je souhaite sélectionner n'est pas dans namespaceA).
  2. Définissez un service (que j'ai également appelé serviceX) dans namespaceB, puis
  3. Définir un objet de points de terminaison namespaceApour pointer vers serviceXdans namespaceB.

C'est cette troisième étape que je n'ai pas pu accomplir.

Tout d'abord, j'ai essayé de définir l'objet Endpoints de cette façon:

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

Cela semblait l'approche logique, et évidemment à quoi cela targetRefservait. Mais cela a conduit à une erreur disant que le ipchamp dans le addressestableau était obligatoire. Donc, mon prochain essai a été d'attribuer une adresse ClusterIP fixe à serviceXin namespaceB, et de la mettre dans le champ IP (notez que le service_cluster_ip_rangeest configuré en tant que 192.168.0.0/16et a 192.168.1.1été attribué en tant que ClusterIP pour serviceXin namespaceB; serviceXin a namespaceAété automatiquement attribué un ClusterIP différent sur le 192.168.0.0/16sous - réseau) :

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

Cela a été accepté, mais les accès à serviceXin namespaceAn'ont pas été transmis au pod in namespaceB- ils ont expiré. En regardant la configuration d'iptables, il semble qu'il aurait fallu deux fois le pré-routage NAT pour y parvenir.

La seule chose que j'ai trouvé qui fonctionnait - mais pas une solution satisfaisante - est de rechercher l'adresse IP réelle du Pod fournissant serviceXdans namespaceBet de mettre cette adresse dans l'objet Endpoints dans namespaceA. Ce n'est pas satisfaisant, bien sûr, car l'adresse IP du pod peut changer avec le temps. C'est le problème que les adresses IP de service doivent résoudre.

Alors, y a-t-il un moyen de répondre à ce qui semble être la promesse de la documentation que je peux pointer un service dans un espace de noms vers un service fonctionnant dans un espace de noms différent?

Un commentateur a demandé pourquoi vous voudriez faire cela - voici un cas d'utilisation qui me semble logique, au moins:

Supposons que vous ayez un système multi-locataire, qui comprend également une fonction d'accès aux données commune qui peut être partagée entre les locataires. Imaginez maintenant qu'il existe différentes saveurs de cette fonction d'accès aux données avec des API communes, mais des caractéristiques de performances différentes. Certains locataires ont accès à l'un d'entre eux, d'autres locataires ont accès à un autre.

Les pods de chaque locataire s'exécutent dans leurs propres espaces de noms, mais chacun doit accéder à l'un de ces services d'accès aux données communs, qui sera nécessairement dans un autre espace de noms (car il est accédé par plusieurs locataires). Mais vous ne voudriez pas que le locataire doive changer son code si son abonnement change pour accéder au service plus performant.

Une solution potentielle (la plus propre à laquelle je puisse penser, si seulement cela fonctionnait) consiste à inclure une définition de service dans l'espace de noms de chaque locataire pour le service d'accès aux données, chacun étant configuré pour le point de terminaison approprié. Cette définition de service serait configurée pour pointer vers le service d'accès aux données approprié que chaque locataire est autorisé à utiliser.

David McKinley
la source
le but des espaces de noms est d'isoler, donc je pense que si vous avez besoin de traverser des espaces de noms, vous devez savoir au moins où ils se trouvent!
MrE
Alors, que signifie la documentation lorsqu'elle suggère que vous pouvez diriger un service défini dans un espace de noms pour accéder à un service dans un espace de noms différent en ne définissant pas de sélecteur - et par implication définissant un point de terminaison? Il y a certainement des cas d'utilisation valables pour cela - dont j'ai ajouté à la question. La documentation est-elle simplement trompeuse ou existe-t-il un moyen de le faire que je n'ai pas encore compris?
David McKinley
je ne suis pas sûr, désolé. ce que je sais, c'est que j'accède aux services dans plusieurs espaces de noms en utilisant leur fqdn. Je fais cela en particulier avec VPN, car j'ai 1 pod VPN et je me connecte via tous les services à partir de celui-ci. cependant, vous devez connaître l'espace de noms et fournir fqdn. Je vous suggère de demander sur le canal slack.
MrE
L'utilisation de fqdn est la solution que j'utilise actuellement. Mon cas d'utilisation serait mieux servi, cependant, (maintenant ajouté à la question) si ce n'était pas nécessaire.
David McKinley
Je me demande aussi à quoi fait référence la documentation, mais je peux utiliser fqdn comme une solution satisfaisante pour mon cas d'utilisation.
Vincent De Smet

Réponses:

224

Je suis tombé sur le même problème et j'ai trouvé une solution intéressante qui ne nécessite aucune configuration IP statique:

Vous pouvez accéder à un service via son nom DNS (comme vous l'avez mentionné): servicename.namespace.svc.cluster.local

Vous pouvez utiliser ce nom DNS pour le référencer dans un autre espace de noms via un service 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
Paul
la source
2
C'est une excellente solution! Je ne sais pas si le type "ExternalName" était disponible pour les services lorsque j'ai initialement posé la question, mais il est pris en charge maintenant et résout parfaitement le problème. Merci, Paul.
David McKinley
1
Est-ce que ça marche? je doute. Quelqu'un peut-il confirmer si cela a vraiment fonctionné, ne fonctionne pas pour moi.
debianmaster
2
Oui. Cela fonctionne pour un pod pour parler à un service dans un autre espace de noms, mais pas pour un équilibreur de charge d'entrée.
Paul le
en raison de la correction de la recherche CNAME dans le cluster de kubernetes , l'ancienne version peut ne pas fonctionner.
赵浩翔
1
Cela fonctionnerait-il / devrait-il également fonctionner pour les services dans l'espace de noms kube-system?
Nabheet
10

C'est si simple de le faire

si vous souhaitez l'utiliser comme hôte et souhaitez le résoudre

Si vous utilisez ambassador vers une autre passerelle API pour le service situé dans un autre espace de noms, il est toujours suggéré d'utiliser:

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

ce sera comme: servicename.namespacename.svc.cluster.local

cela enverra une demande à un service particulier dans l'espace de noms que vous avez mentionné.

exemple:

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

Remplacez ici <servicename>et <namespace>par la valeur appropriée.

Dans Kubernetes, les espaces de noms sont utilisés pour créer un environnement virtuel, mais tous sont connectés les uns aux autres.

Harsh Manvar
la source
6
Pourriez-vous expliquer en quoi cette réponse est différente de celle de Paul fournie près de 2 ans plus tôt?
Oliver
2
@Oliver, il n'y a pas de différence mais je viens de spécifier quoi remplacer le nom du service et l'espace de noms à quel endroit particulier. alors qu'il a utilisé un espace de noms, cela me semble déroutant.
Harsh Manvar
7
Une astuce pratique sur SO est d'ajouter un commentaire sur la réponse et d'apporter les éclaircissements nécessaires.
Oliver
4
J'appellerais cela la meilleure solution car elle .svc.cluster.localest prise en charge par défaut pour résoudre le service en interne.
DrKNa
1
réveillé pour moi aussi. thankyou
Vimal prakash
0

Vous pouvez y parvenir en déployant quelque chose à une couche plus élevée que les services à espace de noms, comme le service loadbalancer https://github.com/kubernetes/contrib/tree/master/service-loadbalancer . Si vous souhaitez le restreindre à un seul espace de noms, utilisez l'argument "--namespace = ns" (par défaut, tous les espaces de noms: https://github.com/kubernetes/contrib/blob/master/service-loadbalancer/service_loadbalancer.go # L715 ). Cela fonctionne bien pour L7, mais est un peu compliqué pour L4.

Prashanth B
la source
3
Ce projet est obsolète maintenant (août 2018)
Nicola Ben
1
@Prashanth B: Pourriez-vous mettre à jour votre réponse en conséquence!
chaosguru