Criar um serviço e uma entrada

Este documento mostra como criar um objeto de Entrada do Kubernetes em um cluster de usuário, híbrido ou independente para clusters do Anthos em bare metal. Uma Entrada é associada a um ou mais Serviços, e cada um deles está associado a um conjunto de pods.

Antes de começar

Consiga uma conexão SSH do cluster com a estação de trabalho de administrador.

Criar uma implantação

Veja o manifesto de uma implantação:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-deployment
spec:
  selector:
    matchLabels:
      greeting: hello
  replicas: 3
  template:
    metadata:
      labels:
        greeting: hello
    spec:
      containers:
      - name: hello-world
        image: "gcr.io/google-samples/hello-app:2.0"
        env:
        - name: "PORT"
          value: "50000"
      - name: hello-kubernetes
        image: "gcr.io/google-samples/node-hello:1.0"
        env:
        - name: "PORT"
          value: "8080"

Para este exercício, é importante entender os pontos a seguir sobre o manifesto de implantação:

  • Cada pod que pertence à implantação tem o rótulo greeting: hello.

  • Cada pod tem dois contêineres.

  • Os campos env especificam que os contêineres hello-app detectam atividade na porta TCP 50000 e os contêineres node-hello detectam atividade na porta TCP 8080. Para hello-app, é possível ver o efeito da variável de ambiente PORT observando o código-fonte.

Copie o manifesto em um arquivo denominado hello-deployment.yaml e crie a implantação:

kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f hello-deployment.yaml

Substitua CLUSTER_KUBECONFIG pelo nome do arquivo kubeconfig do cluster.

Expor a implantação com um Serviço

Se quiser oferecer uma forma estável para os clientes enviarem solicitações aos pods da implantação, crie um Serviço.

Veja aqui um manifesto para um Serviço que expõe a implantação a clientes dentro do cluster:

apiVersion: v1
kind: Service
metadata:
  name: hello-service
spec:
  type: ClusterIP
  selector:
    greeting: hello
  ports:
  - name: world-port
    protocol: TCP
    port: 60000
    targetPort: 50000
  - name: kubernetes-port
    protocol: TCP
    port: 60001
    targetPort: 8080

Copie o manifesto para um arquivo chamado hello-service.yaml e crie o Service:

kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f hello-service.yaml

Substitua CLUSTER_KUBECONFIG pelo nome do arquivo kubeconfig do cluster.

Veja o Serviço:

kubectl --kubeconfig CLUSTER_KUBECONFIG get service hello-service --output yaml

A saída mostra o valor de clusterIP que foi fornecido ao serviço. Exemplo:

apiVersion: v1
kind: Service
metadata:
  annotations:
    ...
spec:
  clusterIP: 10.96.14.249
  clusterIPs:
  - 10.96.14.249
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - name: world-port
    port: 60000
    protocol: TCP
    targetPort: 50000
  - name: kubernetes-port
    port: 60001
    protocol: TCP
    targetPort: 8080
  selector:
    greeting: hello
  sessionAffinity: None
  type: ClusterIP
status:
  loadBalancer: {}

Na saída anterior, o campo ports é uma matriz de objetos ServicePort: um chamado world-port e outro chamado kubernetes-port. Para mais informações sobre os campos de serviço, consulte ServiceSpec na documentação do Kubernetes.

Veja como um cliente pode chamar o Serviço:

  • Usando world-port: um cliente que executa um dos nós do cluster envia uma solicitação para clusterIP em port. Neste exemplo, 10.96.14.249:60000. A solicitação é encaminhada a um pod membro em targetPort. Neste exemplo, POD_IP_ADDRESS:50000.

  • Usando kubernetes-port: um cliente que executa um dos nós do cluster envia uma solicitação para clusterIP em port. Neste exemplo, 10.96.14.249:60001. A solicitação é encaminhada a um pod membro em targetPort. Neste exemplo, POD_IP_ADDRESS:8080.

Componentes da Entrada

Estes são alguns dos componentes do cluster relacionados à Entrada:

  • A implantação istio-ingress. Esse é o proxy de entrada. O proxy de entrada encaminha o tráfego para os Serviços internos de acordo com as regras especificadas em um objeto de Entrada.

  • O serviço istio-ingress. Este serviço expõe a implantação istio-ingress.

  • A implantação istiod. Este é o controlador de Entrada. O controlador de Entrada observa a criação de objetos de Entrada e configura o proxy de Entrada de acordo.

Todos esses componentes do Istio no cluster estão instalados no namespace gke-system. Esse namespace não entra em conflito com uma instalação completa do Istio/Anthos Service Mesh.

Criar uma Entrada

Veja aqui um manifesto de uma Entrada:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
  - http:
      paths:
      - path: /greet-the-world
        pathType: Exact
        backend:
          service:
            name: hello-service
            port:
              number: 60000
      - path: /greet-kubernetes
        pathType: Exact
        backend:
          service:
            name: hello-service
            port:
              number: 60001

Copie o manifesto em um arquivo chamado my-ingress.yaml e crie a Entrada:

kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f my-ingress.yaml

Ao criar um cluster de usuário, especifique um valor para loadbalancer.ingressVIP no arquivo de configuração do cluster. Esse endereço IP é configurado no balanceador de carga do cluster. Quando você cria uma Entrada, ela recebe esse mesmo VIP como o endereço IP externo dela.

Quando um cliente envia uma solicitação ao VIP de Entrada do cluster de usuário, a solicitação é roteada para o balanceador de carga. O balanceador de carga usa o Serviço istio-ingress para encaminhar a solicitação ao proxy de Entrada, que é executada no cluster de usuário. O Serviço de entrada está configurado para encaminhar a solicitação a back-ends diferentes, dependendo do caminho no URL da solicitação.

Caminho /greet-the-world

No manifesto de Entrada, há uma regra que diz que o caminho /greet-the-world está associado a serviceName: hello-service e servicePort: 60000. Lembre-se de que 60000 é o valor da port na seção world-port do Serviço hello-service.

- name: world-port
    port: 60000
    protocol: TCP
    targetPort: 50000

O Serviço de Entrada encaminha a solicitação para clusterIP:50.000. Em seguida, a solicitação vai para um dos pods membros do serviço hello-service. O contêiner, nesse pod, que detecta a porta 50000 exibe uma mensagem Hello World!.

Caminho /greet-kubernetes

No manifesto de Entrada, há uma regra que diz que o caminho /greet-kubernetes está associado a serviceName: hello-service e servicePort: 60001. Lembre-se de que 60001 é o valor da port na seção kubernetes-port do Serviço hello-service.

- name: kubernetes-port
    port: 60001
    protocol: TCP
    targetPort: 8080

O Serviço de Entrada encaminha a solicitação para clusterIP: 8080. Em seguida, a solicitação vai para um dos pods membros do serviço hello-service. O contêiner, nesse pod, que detecta a porta 8080 exibe uma mensagem Hello Kubernetes!.

Testar a Entrada

Teste o Entrada usando o caminho /greet-the-world:

curl CLUSTER_INGRESS_VIP/greet-the-world

Substitua CLUSTER_INGRESS_VIP pelo endereço IP externo da Entrada.

A saída mostra uma mensagem Hello, world!:

Hello, world!
Version: 2.0.0
Hostname: ...

Teste o Entrada usando o caminho /greet-kubernetes:

curl CLUSTER_INGRESS_VIP/greet-kubernetes

A saída mostra uma mensagem Hello, Kubernetes!:

Hello Kubernetes!

Desativar a entrada em pacote

O recurso de entrada agrupado com clusters do Anthos em bare metal é compatível apenas com a funcionalidade de entrada. É possível fazer a integração com o Istio ou o Anthos Service Mesh. Esses produtos oferecem outros benefícios de uma malha de serviço totalmente funcional, como TLS mútuo (mTLS), capacidade de gerenciar autenticação entre serviços e observabilidade da carga de trabalho. Se você fizer a integração ao Istio ou ao Anthos Service Mesh, recomendamos que desative o recurso de entrada no pacote.

É possível ativar ou desativar a Entrada agrupada com o campo spec.clusterNetwork.bundledIngress no arquivo de configuração do cluster. Este campo está disponível apenas nos clusters da versão 1.13.0 e mais recentes. O campo bundledIngress assume como padrão true e não está presente no arquivo de configuração do cluster gerado. Esse campo é mutável e pode ser alterado quando você cria ou atualiza um cluster da versão 1.13.0 ou mais recente. Também é possível especificar esse campo ao fazer upgrade de um cluster para a versão 1.13.0 ou mais recente.

No arquivo de configuração de cluster de amostra a seguir, mostramos como configurar o cluster para desativar o recurso de entrada em pacote:

apiVersion: v1
kind: Namespace
metadata:
  name: cluster-hybrid-basic
---
apiVersion: baremetal.cluster.gke.io/v1
kind: Cluster
metadata:
  name: hybrid-basic
  namespace: cluster-hybrid-basic
spec:
  type: hybrid
  profile: default
  anthosBareMetalVersion: 1.13.0
  gkeConnect:
    projectID: project-fleet
  controlPlane:
    nodePoolSpec:
      nodes:
      - address: 10.200.0.2
  clusterNetwork:
    bundledIngress: false
    pods:
      cidrBlocks:
      - 192.168.0.0/16
    services:
      cidrBlocks:
      - 172.26.232.0/24
...

Configurar HTTPS para a Entrada

Se você quiser aceitar solicitações HTTPS dos clientes, o proxy de Entrada precisará ter um certificado para provar a identidade dele aos clientes. Esse proxy também precisa ter uma chave privada para concluir o handshake HTTPS.

O exemplo a seguir usa essas entidades:

  • Proxy de entrada: participa do handshake HTTPS e, em seguida, encaminha os pacotes para os pods membros do serviço hello-service.

  • Domínio do serviço hello-service: altostrat.com na organização de exemplo

Siga estas etapas:

  1. Crie um certificado raiz e uma chave privada. Este exemplo usa uma autoridade certificadora raiz de root.ca.example.com na organização de exemplo da CA raiz.

    openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj \
        '/O=Root CA Example Inc./CN=root.ca.example.com' -keyout root-ca.key \
        -out root-ca.crt
  2. Crie uma solicitação de assinatura de certificado:

     openssl req -out server.csr -newkey rsa:2048 -nodes -keyout server.key -subj \
         "/CN=altostrat.com/O=Example Org"
  3. Crie um certificado de exibição para o proxy de entrada.

    openssl x509 -req -days 365 -CA root-ca.crt -CAkey root-ca.key -set_serial 0 \
        -in server.csr -out server.crt

    Você criou estes seguintes certificados e chaves:

    • root-ca.crt: certificado da CA raiz;
    • root-ca.key: chave privada da CA raiz;
    • server.crt: certificado de exibição do proxy de entrada;
    • server.key: chave privada do proxy de entrada;
  4. Crie um secret do Kubernetes que contenha o certificado e a chave de exibição.

    kubectl create secret tls example-server-creds --key=server.key --cert=server.crt \
        --namespace gke-system

    O secret resultante é denominado example-server-creds.

Criar uma implantação e um serviço

Se você criou uma implantação e um Serviço na parte HTTP deste guia, deixe-os no lugar. Se você não fez isso, crie-os agora seguindo as etapas descritas para HTTP.

Criar uma Entrada

Se você já tiver criado uma Entrada na parte HTTP, exclua-a antes de continuar.

Exclua a Entrada:

kubectl --kubeconfig CLUSTER_KUBECONFIG delete ingress my-ingress

Para lidar com o tráfego do serviço que você criou anteriormente, crie uma nova Entrada que tenha uma seção tls. Isso ativará o HTTPS entre os clientes e o proxy de entrada.

Veja aqui um manifesto de uma Entrada:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress-2
spec:
  tls:
  - hosts:
    - altostrat.com
    secretName: example-server-creds
  rules:
  - host: altostrat.com
    http:
      paths:
      - path: /greet-the-world
        pathType: Exact
        backend:
          service:
            name: hello-service
            port:
              number: 60000
      - path: /greet-kubernetes
        pathType: Exact
        backend:
          service:
            name: hello-service
            port:
              number: 60001

Salve o manifesto em um arquivo chamado my-ingress-2.yaml e crie a Entrada:

kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f my-ingress-2.yaml

Confirme por teste.

  • Teste o caminho /greet-the-world:

    curl -v --resolve altostrat.com:443:CLUSTER_INGRESS_VIP\
        https://altostrat.com/greet-the-world \
        --cacert root-ca.crt

    Saída:

    Hello, world!
    Version: 2.0.0
    Hostname: hello-deployment-5ff7f68854-wqzp7
    
  • Teste o caminho /greet-kubernetes:

    curl -v --resolve altostrat.com:443:CLUSTER_INGRESS_VIP \
        https://altostrat.com/greet-kubernetes --cacert root-ca.crt

    Saída:

    Hello Kubernetes!
    

Criar um serviço LoadBalancer

O tipo LoadBalancer é uma extensão do tipo NodePort. Portanto, um Service do tipo LoadBalancer tem um endereço IP de cluster e um ou mais valores nodePort. Por padrão, o Kubernetes aloca portas de nó para serviços LoadBalancer. Essas alocações podem esgotar rapidamente as portas de nó disponíveis das 2.768 alocadas para o cluster. Para salvar portas de nó, desative a alocação de porta de nó do balanceador de carga definindo o campo allocateLoadBalancerNodePorts como false na especificação do serviço LoadBalancer. Essa configuração impede que o Kubernetes aloque portas de nó para serviços LoadBalancer. Para mais informações, consulte Como desativar a alocação de NodePort do balanceador de carga na documentação do Kubernetes.

Confira aqui um manifesto para criar um Serviço que não usa nenhuma porta de nó:

apiVersion: v1
kind: Service
metadata:
  name: service-does-not-use-nodeports
spec:
  selector:
    app: my-app
  type: LoadBalancer
  ports:
  - port: 8000
  # Set allocateLoadBalancerNodePorts to false
  allocateLoadBalancerNodePorts: false

Limpar

Exclua o Entrada:

kubectl --kubeconfig CLUSTER_KUBECONFIG delete ingress INGRESS_NAME

Substitua INGRESS_NAME pelo nome da Entrada, como my-ingress ou my-ingress-2.

Exclua o Serviço:

kubectl --kubeconfig CLUSTER_KUBECONFIG delete service hello-service

Exclua a implantação:

kubectl --kubeconfig CLUSTER_KUBECONFIG delete deployment hello-deployment

Exclua o serviço LoadBalancer:

kubectl --kubeconfig CLUSTER_KUBECONFIG delete service service-does-not-use-nodeports