Serviço localizado em outro namespace

108

Tenho tentado encontrar uma maneira de definir um serviço em um namespace que se vincule a um pod executado em outro namespace. Eu sei que os contêineres em um pod em execução namespaceApodem acessar serviceXdefinido em namespaceBreferenciando-o no DNS do cluster como serviceX.namespaceB.svc.cluster.local, mas prefiro não ter o código dentro do contêiner preciso saber sobre a localização de serviceX. Ou seja, quero que o código apenas procure serviceXe possa acessá-lo.

A documentação do Kubernetes sugere que isso é possível. Ele diz que um dos motivos pelos quais você definiria um serviço sem um seletor é que você deseja apontar seu serviço para um serviço em outro namespace ou em outro cluster .

Isso me sugere que eu deveria:

  1. Defina um serviceXserviço em namespaceA, sem um seletor (já que o POD que desejo selecionar não está em namespaceA).
  2. Defina um serviço (que também chamei serviceX) namespaceBe, em seguida,
  3. Definir um objecto Endpoints em namespaceAque ponto a serviceXem namespaceB.

É esta terceira etapa que não fui capaz de realizar.

Primeiro, tentei definir o objeto Endpoints desta maneira:

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

Essa parecia a abordagem lógica e, obviamente, para que serviatargetRef . Mas, isso levou a um erro dizendo que o ipcampo na addressesmatriz era obrigatório. Então, minha próxima tentativa foi atribuir um endereço IP fixo de Cluster a serviceXin namespaceBe colocá-lo no campo IP (observe que o service_cluster_ip_rangeestá configurado como 192.168.0.0/16e 192.168.1.1foi atribuído como ClusterIP para serviceXin namespaceB; serviceXem namespaceAfoi atribuído automaticamente um ClusterIP diferente na 192.168.0.0/16sub - rede) :

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

Isso foi aceito, mas os acessos ao serviceXin namespaceAnão foram encaminhados ao pod in namespaceB- eles expiraram. Olhando a configuração do iptables, parece que teria que fazer o pré-roteamento NAT duas vezes para conseguir isso.

A única coisa que eu achei que funcionou - mas não é uma solução satisfatória - é pesquisar o endereço IP real do Pod fornecendo serviceXem namespaceBe colocar esse endereço no objeto Endpoints em namespaceA. Isso não é satisfatório, é claro, porque o endereço IP do pod pode mudar com o tempo. Esse é o problema que os IPs de serviço estão aí para resolver.

Então, há uma maneira de cumprir o que parece ser a promessa da documentação de que posso apontar um serviço em um namespace para um serviço executado em um namespace diferente?

Um comentarista questionou por que você faria isso - aqui está um caso de uso que faz sentido para mim, pelo menos:

Digamos que você tenha um sistema multilocatário, que também inclui uma função comum de acesso a dados que pode ser compartilhada entre os locatários. Agora imagine que existem diferentes sabores dessa função de acesso a dados com APIs comuns, mas com características de desempenho diferentes. Alguns inquilinos têm acesso a um deles, outros inquilinos têm acesso a outro.

Os pods de cada locatário são executados em seus próprios namespaces, mas cada um precisa acessar um desses serviços comuns de acesso a dados, que estarão necessariamente em outro namespace (já que é acessado por vários locatários). Porém, você não gostaria que o locatário tivesse que alterar seu código se sua assinatura fosse alterada para acessar o serviço de alto desempenho.

Uma solução potencial (a mais limpa que posso imaginar, se ao menos funcionasse) é incluir uma definição de serviço no namespace de cada locatário para o serviço de acesso a dados, com cada um configurado para o endpoint apropriado. Essa definição de serviço seria configurada para apontar para o serviço de acesso a dados adequado que cada locatário tem direito de usar.

David McKinley
fonte
o objetivo dos namespaces é isolar, então eu acho que se você precisa passar por namespaces, você precisa saber pelo menos onde ele está localizado!
MrE
Então, o que a documentação significa quando sugere que você pode direcionar um serviço definido em um namespace para acessar um serviço em um namespace diferente, não definindo um seletor - e por implicação definindo um endpoint? Certamente há casos de uso válidos para isso - um dos quais acrescentei à pergunta. A documentação é apenas enganosa ou existe uma maneira de fazer isso que ainda não descobri?
David McKinley
não tenho certeza, desculpe. o que eu sei é que acesso serviços em vários namespaces usando seu fqdn. Faço isso especialmente com vpn, pois tenho 1 pod vpn e me conecto por meio de todos os serviços dele. no entanto, você precisa saber o namespace e fornecer fqdn. Eu sugiro que você pergunte no canal Slack.
MrE
Usar fqdn é a solução que estou usando atualmente. Porém, meu caso de uso seria melhor atendido (agora adicionado à pergunta) se isso não fosse necessário.
David McKinley
Também me pergunto a que a documentação se refere, no entanto, posso usar fqdn como uma solução satisfatória para o meu caso de uso.
Vincent De Smet

Respostas:

223

Eu tropecei no mesmo problema e encontrei uma boa solução que não precisa de nenhuma configuração de ip estático:

Você pode acessar um serviço por meio de seu nome DNS (conforme mencionado por você): servicename.namespace.svc.cluster.local

Você pode usar esse nome DNS para referenciá-lo em outro namespace por meio de um serviço 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
Paulo
fonte
2
Esta é uma otima soluçao! Não tenho certeza se o tipo "ExternalName" estava disponível para serviços quando eu fiz a pergunta originalmente, mas agora é compatível e resolve o problema de maneira organizada. Obrigado, Paul.
David McKinley
1
Isto funciona? eu duvido. Alguém pode confirmar se isso realmente funcionou, não funciona para mim.
debianmaster
2
Sim. Ele funciona para um pod para se comunicar com um serviço em outro namespace, mas não para um balanceador de carga de entrada.
Paul de
devido à correção da pesquisa CNAME do kubernetes no cluster , a versão antiga pode não funcionar.
赵浩翔
1
Isso funcionaria / deveria funcionar para serviços no namespace do sistema kube também?
Nabheet
10

É tão simples de fazer

se você quiser usá-lo como host e resolver isso

Se você estiver usando embaixador para qualquer outro gateway de API para serviço localizado em outro namespace, é sempre recomendável usar:

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

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

isso enviará uma solicitação a um serviço específico dentro do namespace que você mencionou.

exemplo:

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

Substitua aqui o <servicename>e <namespace>pelo valor apropriado.

No Kubernetes, os namespaces são usados ​​para criar um ambiente virtual, mas todos estão conectados uns aos outros.

Harsh Manvar
fonte
6
Você poderia explicar como essa resposta é diferente da dada por Paulo quase 2 anos antes?
Oliver
2
@Oliver não há diferença, mas acabei de especificar o que substituir o nome do serviço e o namespace em que local específico. enquanto ele usou o namespace-a parece confuso para mim.
Harsh Manvar
7
Um truque útil no SO é adicionar um comentário sobre a resposta e fazer o esclarecimento necessário.
Oliver
4
Eu chamaria isso de a melhor solução porque .svc.cluster.localé, por padrão, suportado para resolver o serviço internamente.
DrKNa
1
acordou para mim também. obrigado
vimal prakash
0

Você pode conseguir isso implantando algo em uma camada mais alta do que os serviços com namespace, como o loadbalancer de serviço https://github.com/kubernetes/contrib/tree/master/service-loadbalancer . Se você quiser restringi-lo a um único namespace, use o argumento "--namespace = ns" (o padrão é todos os namespaces: https://github.com/kubernetes/contrib/blob/master/service-loadbalancer/service_loadbalancer.go # L715 ). Isso funciona bem para L7, mas é um pouco confuso para L4.

Prashanth B
fonte
3
Este projeto está obsoleto agora (agosto de 2018)
Nicola Ben
1
@Prashanth B: Você poderia atualizar sua resposta de acordo!
chaosguru