Implementação de referência do balanceamento de carga da camada 7 do HAProxy

O Google Distributed Cloud (GDC) com isolamento físico oferece um balanceador de carga gerenciado da camada 4 (L4) integrado, mas muitos aplicativos empresariais exigem recursos avançados da camada 7 (L7), como roteamento com base em host, gerenciamento centralizado de TLS e divisão de tráfego complexa. Historicamente, isso é feito usando a API Entrada, que agora é considerada um recurso congelado na comunidade do Kubernetes.

Esta arquitetura de referência oferece uma solução de balanceamento de carga da camada 7 autogerenciada. Ao implantar o controlador de código aberto HAProxy popular em um cluster padrão do GDC, os clientes podem rotear o tráfego L7 para ambientes híbridos sem problemas. Essa arquitetura usa a terminação TLS (HTTPRoute) para rotear o tráfego com base na indicação de nome do servidor (SNI, na sigla em inglês) para pods e aplicativos em contêineres integrados hospedados em máquinas virtuais externas.

Arquitetura

Diagrama de arquitetura do balanceamento de carga da camada 7 do HAProxy no GDC com isolamento físico.

Os principais componentes da solução incluem:

  • Cliente:uma entidade que inicia solicitações HTTPS para interagir com os aplicativos.
  • Cluster padrão do GDC:o GDC oferece uma maneira integrada de criar clusters Vanilla do Kubernetes. Nessa solução, o cluster vai hospedar o LB L7 e os controladores dele, além das cargas de trabalho e do serviço headless para VMs externas.
  • Balanceador de carga L4 do GDC:o balanceador de carga L4 integrado que serve como ponto de entrada, distribuindo o tráfego TCP/443 diretamente para os pods do Kubernetes que executam os controladores.
  • Controladores de entrada:operadores HAProxy em execução no cluster padrão. Eles monitoram os recursos Ingress e atualizam dinamicamente os proxies subjacentes. O controlador de entrada do HAProxy será usado na implementação a seguir.
  • Entrada:recursos padronizados do Kubernetes que definem a porta de escuta física (443) e as regras de roteamento de host baseadas em SNI com terminação TLS.
  • Carga de trabalho em contêiner (pods) : uma implantação padrão do Kubernetes exposta internamente com um Service normal do Kubernetes.
  • Carga de trabalho baseada em VM (externa) : uma carga de trabalho hospedada em uma VM externa na rede do projeto, exposta ao proxy usando um Service headless do Kubernetes e um endpoint personalizado que contém o IP direto da VM.
  • Registro do Harbor:um registro de contêiner particular usado para armazenar e veicular as imagens de proxy e aplicativo no ambiente air-gapped.

No cluster padrão, crie três namespaces:

  • O namespace load-balancer hospeda o controlador de entrada do HAProxy e a carga de trabalho do balanceador de carga do HAProxy:

    Os recursos do namespace do balanceador de carga.

  • O namespace hello-app hospeda a Deployment, um Service e uma Ingress para a carga de trabalho do contêiner de demonstração:

    Os recursos do namespace hello-app.

  • O namespace vm-app hospeda um serviço headless que expõe o IP da VM externa, um EndpointSlice que aponta para o IP externo e uma Ingress:

    Os recursos do namespace vm-app.

Antes de começar

Antes de implantar essa solução, verifique se você tem os seguintes pré-requisitos:

  • Software necessário:helm, docker, kubectl
  • Login da CLI e configuração local:faça o download da CLI gdcloud no console do GDC e configure seu ambiente localmente:

    export USER_NAME="USER_NAME"
    export PROJECT_ID="PROJECT_ID"
    export ZONE="ZONE"
    export ORG_NAME="ORG_NAME"
    export GDC_URL="GDC_URL"
    
    gdcloud components install gdcloud-k8s-auth-plugin
    
    gdcloud config set core/organization_console_url \
      https://console.$ORG_NAME.$ZONE.$GDC_URL
    gdcloud config set core/zone $ZONE
    gdcloud config set core/project ${PROJECT_ID}
    
    gdcloud auth login # use --login-config-cert option in case of TLS error
    
  • Configuração do projeto:crie um projeto no ambiente GDC com isolamento físico para manter os recursos:

    gdcloud projects create $PROJECT_ID
    
  • Papéis do IAM:conceda ao usuário os papéis Administrador do cluster e Administrador do cluster padrão para gerenciar recursos do Kubernetes e o papel Administrador da instância do Harbor para enviar imagens:

    # Grant standard cluster and cluster admin roles
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member="user:${USER_NAME}" \
      --role=cluster-admin
    
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member="user:${USER_NAME}" \
      --role=standard-cluster-admin
    
    # Grant Harbor instance admin role
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member="user:${USER_NAME}" \
      --role=harbor-instance-admin
    

Criar um cluster padrão

Esta seção orienta você no processo de configuração de um cluster padrão do Kubernetes no ambiente GDC com isolamento físico. Um cluster padrão oferece uma base flexível e robusta para implantar várias cargas de trabalho, incluindo o controlador de entrada do HAProxy e seus aplicativos personalizados. As etapas a seguir garantem que o cluster esteja configurado e acessível para implantações subsequentes.

  1. Identifique os tipos de imagem de máquina virtual disponíveis executando:

    gdcloud compute machine-types list
    
  2. Selecione um tipo de máquina adequado para os nós de worker do cluster. Para este tutorial, recomendamos um tipo de máquina com pelo menos 4 vCPUs.

    export MACHINE_TYPE="MACHINE_TYPE"
    
  3. Receba o kubeconfig do servidor da API de gerenciamento e defina um alias:

    export CLUSTER_NAME="CLUSTER_NAME"
    
    KUBECONFIG=kubeconfig-admin.yaml gdcloud clusters \
      get-credentials ${ORG_NAME}-admin
    
    alias km="kubectl --kubeconfig kubeconfig-admin.yaml"
    
  4. Crie um cluster padrão com dois nós de worker:

    km create -f - <<EOF
    apiVersion: cluster.gdc.goog/v1
    kind: Cluster
    metadata:
      name: ${CLUSTER_NAME}
      namespace: ${PROJECT_ID}
    spec:
      nodePools:
      - machineTypeName: ${MACHINE_TYPE}
        nodeCount: 2
        name: ${CLUSTER_NAME}-node-pool
    EOF
    

    Para mais detalhes sobre as opções disponíveis, consulte a documentação.

    A criação de clusters padrão pode levar até 60 minutos. Para verificar o status, use o comando a seguir:

    km get clusters/${CLUSTER_NAME} \
      -n ${PROJECT_ID} \
      --watch
    

    Quando o cluster estiver pronto, a saída vai mostrar um estado de execução, como este:

    NAME         STATE     K8S VERSION
    my-cluster   Running   1.30.12-gke.300
    
  5. Quando o cluster estiver pronto, recupere as credenciais dele:

    KUBECONFIG=kubeconfig-${CLUSTER_NAME}.yaml gdcloud clusters \
      get-credentials ${CLUSTER_NAME} \
      --standard \
      --project ${PROJECT_ID} \
      --zone ${ZONE}
    
  6. Crie um alias para manter os comandos kubectl mais concisos no restante deste guia. Esse alias será usado para interagir com o cluster padrão:

    alias kk="kubectl --kubeconfig kubeconfig-${CLUSTER_NAME}.yaml"
    
  7. Crie namespaces para o controlador, o app em contêiner de demonstração "hello-app" e o app de demonstração baseado em VM:

    kk create namespace load-balancer
    kk create namespace hello-app
    kk create namespace vm-app
    

Criar e integrar o registro do Harbor

O Harbor é um registro de imagem do contêiner com suporte integrado no GDC com isolamento físico. Esta seção orienta você nas etapas para integrar um registro do Harbor ao cluster padrão, incluindo a configuração de credenciais e secrets para permitir o envio e recebimento seguros de imagens.

  1. Crie uma instância do Harbor no projeto.
  2. Crie um projeto do Harbor na instância do Harbor.
  3. Defina as variáveis de ambiente:

    export HARBOR_INSTANCE_NAME="HARBOR_INSTANCE_NAME"
    export HARBOR_INSTANCE_URL="HARBOR_INSTANCE_URL"
    export HARBOR_PROJECT="HARBOR_PROJECT"
    export IMAGE_PULL_SECRET_NAME="harbor-secret"
    
  4. Faça login na instância do Harbor usando uma conta de robô:

    docker --config=./docker login ${HARBOR_INSTANCE_URL}
    
  5. Crie os secrets no cluster padrão:

    kk create secret docker-registry ${IMAGE_PULL_SECRET_NAME} \
      --from-file=.dockerconfigjson=./docker/config.json \
      -n load-balancer
    
    kk create secret docker-registry ${IMAGE_PULL_SECRET_NAME} \
      --from-file=.dockerconfigjson=./docker/config.json \
      -n hello-app
    

Implantar o app em contêiner de demonstração

Esta seção detalha a implantação de um aplicativo em contêiner de demonstração (hello-app) no cluster do Kubernetes do GDC com isolamento físico. Você vai criar os recursos de implantação e serviço do Kubernetes necessários para executar o hello-app e expô-lo internamente no cluster, preparando-o para acesso usando o balanceador de carga L7.

  1. Faça o upload de uma imagem de amostra para o app em contêiner de demonstração no Harbor:

    docker pull gcr.io/google-samples/hello-app:1.0 \
      --platform linux/amd64
    docker tag gcr.io/google-samples/hello-app:1.0 \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/hello-app:1.0
    docker --config=./docker push \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/hello-app:1.0
    
  2. Implante o manifesto a seguir no cluster padrão:

    cat << EOF > hello-app.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: hello-app
      namespace: hello-app
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: hello-app
      template:
        metadata:
          labels:
            app: hello-app
        spec:
          containers:
          - name: hello-server
            image: ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/hello-app:1.0
            ports:
            - containerPort: 8080
          imagePullSecrets:
          - name: ${IMAGE_PULL_SECRET_NAME}
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: hello-app
      namespace: hello-app
    spec:
      type: ClusterIP
      selector:
        app: hello-app
      ports:
        - protocol: TCP
          port: 80
          targetPort: 8080
    EOF
    
    kk apply -f hello-app.yaml
    

Em seguida, verifique se a implantação e o serviço estão lá.

kk get svc,deploy -n hello-app

Implantar o app de demonstração em uma VM

Esta seção detalha a implantação de um aplicativo de demonstração em uma máquina virtual (VM) fora do cluster do Kubernetes. Ao configurar um servidor HTTP em uma VM, você vai simular um aplicativo externo que o balanceador de carga pode expor, demonstrando a capacidade de gerenciar o tráfego para recursos dentro e fora do cluster.

Primeiro, crie uma VM para o app de demonstração:

  1. Abra o console do GDC no navegador da Web.
  2. Selecione o mesmo projeto em que você criou o cluster padrão do Kubernetes.
  3. Abra o menu e clique em Máquinas virtuais.
  4. Clique em Criar instância.
  5. Dê à VM o nome vm-workload. Uma imagem de 2 vCPUs é suficiente para o exemplo.
  6. Para a imagem do disco de inicialização, selecione uma distribuição do Ubuntu 22.04, que vem com o Python pré-instalado.
  7. Clique em Criar.
  8. Aguarde alguns minutos até que a VM fique pronta.
  9. Estabeleça uma conexão SSH com a VM:
    1. No console do GDC, clique na VM.
    2. Clique em Conectar com SSH.

Depois de se conectar ao console SSH, execute o seguinte:

mkdir ~/simple-server
cd ~/simple-server
echo 'Welcome to my VM!' > index.html
python3 -m http.server --bind 0.0.0.0 8080 &

Para rotear o tráfego para uma VM, crie um serviço headless (sem seletores). Ele será mapeado manualmente para o endereço IP interno da VM usando um recurso EndpointSlice.

kk apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: vm-app-svc
  namespace: vm-app
spec:
  ports:
  - protocol: TCP
    port: 443
    targetPort: 443
EOF

Receba o endereço IP da VM vm-workload executando

gdcloud compute instances list --project ${PROJECT_ID} \
  | grep workload-vm | awk '{print $3}'

A saída será o endereço IP da VM necessário para configurar o recurso EndpointSlice.

Crie o recurso EndpointSlice que vai se conectar ao serviço sem seletor do app da VM e endereçar o IP da VM para a qual o tráfego precisa ser roteado.

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: vm-app-endpoints
  namespace: vm-app
  labels:
    kubernetes.io/service-name: vm-app-svc
addressType: IPv4
ports:
  - port: 8080
endpoints:
  - addresses:
    - "VM_IP"
    conditions:
      ready: true

Criar certificados autoassinados

Esta seção orienta você no processo de criação de certificados TLS e secrets do Kubernetes para proteger a comunicação dos aplicativos baseados em contêiner e VM. Este guia usa certificados autoassinados por conveniência, mas em ambientes de produção, é necessário usar certificados de nível de produção, conforme descrito em Opcional: usar certificados prontos para produção. Escolha nomes de domínio de amostra arbitrários para esses apps. Ao estabelecer conexões seguras, você garante a integridade de dados e a confidencialidade para clientes que acessam seu aplicativo pelo controlador de entrada do HAProxy.

Para o app em contêiner, criamos um certificado autoassinado e o salvamos como um secret no namespace do balanceador de carga. Ele será usado para o TLS ao solicitar k8s-app.example.com

openssl req -x509 -newkey rsa:2048 -nodes \
  -keyout tls-containerized.key \
  -out tls-containerized.crt \
  -subj "/CN=k8s-app.example.com" \
  -days 365

kk create secret tls tls-containerized \
  --namespace load-balancer \
  --key tls-containerized.key \
  --cert tls-containerized.crt

kk create secret tls tls-containerized \
  --namespace hello-app \
  --key tls-containerized.key \
  --cert tls-containerized.crt

Para o app da VM, um certificado autoassinado semelhante é emitido e salvo. Ele será usado para o TLS ao solicitar vm-app.example.com

openssl req -x509 -newkey rsa:2048 -nodes \
  -keyout tls-vm.key \
  -out tls-vm.crt \
  -subj "/CN=vm-app.example.com" \
  -days 365

kk create secret tls tls-vm \
  --namespace load-balancer \
  --key tls-vm.key \
  --cert tls-vm.crt

kk create secret tls tls-vm \
  --namespace vm-app \
  --key tls-vm.key \
  --cert tls-vm.crt

Implantar o HAProxy

Instalar o controlador de entrada do HAProxy e o LB L4

export HAPROXY_VERSION=3.1.14

# pull the HAProxy Ingress Controller image and push it to Harbor
docker pull haproxytech/kubernetes-ingress:${HAPROXY_VERSION} \
  --platform linux/amd64
docker tag haproxytech/kubernetes-ingress:${HAPROXY_VERSION} \
  ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/haproxy-ingress:${HAPROXY_VERSION}
docker --config=./docker push \
  ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/haproxy-ingress:${HAPROXY_VERSION}

# Get Helm repo
helm repo add haproxytech https://haproxytech.github.io/helm-charts
helm repo update

# Install the Ingress Controller with helm
helm upgrade --install haproxy-kubernetes-ingress \
  haproxytech/kubernetes-ingress \
  --kubeconfig kubeconfig-${CLUSTER_NAME}.yaml \
  --namespace load-balancer \
  --set controller.image.repository=${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/haproxy-ingress \
  --set controller.image.tag=${HAPROXY_VERSION} \
  --set controller.existingImagePullSecret=${IMAGE_PULL_SECRET_NAME} \
  --set controller.service.type=LoadBalancer \
  --set-json \
  controller.service.annotations='{"networking.gke.io/load-balancer-type": "internal"}'

O controlador de entrada do HAProxy ganha um endereço IP virtual exclusivo para acesso do cliente usando um serviço do tipo LoadBalancer. Esse serviço configura um balanceador de carga da camada 4 totalmente gerenciado. Para simplificar este guia, um balanceador de carga interno é criado definindo a anotação load-balancer-type como internal. A omissão dessa anotação resultaria em um balanceador de carga externo. A implantação do Kubernetes extrai imagens do Harbor com segurança usando o secret fornecido (${IMAGE_PULL_SECRET_NAME}), que contém as credenciais da conta de robô do Harbor.

Validar a instalação do controlador de entrada do HAProxy

Verifique se os pods do controlador de entrada do HAProxy estão em execução e prontos:

kk get pods -n load-balancer

A saída será semelhante a esta:

NAME                                          READY   STATUS      RESTARTS   AGE
haproxy-kubernetes-ingress-78dc9c8676-f8fcb   1/1     Running     0          35s
haproxy-kubernetes-ingress-78dc9c8676-lfnr2   1/1     Running     0          65s
haproxy-kubernetes-ingress-crdjob-3-tgj2h     0/1     Completed   0          65s

Verifique se o serviço do controlador de entrada do HAProxy foi criado e configurado:

kk get services -n load-balancer

A saída será assim:

NAME                         TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                                                                  AGE
haproxy-kubernetes-ingress   LoadBalancer   10.252.27.46   10.252.4.17   80:32023/TCP,443:31103/TCP,443:31103/UDP,1024:30146/TCP,6060:30718/TCP   10m

Definir recursos de entrada para os apps de demonstração

Crie o recurso de entrada que vai conectar o HAProxy ao serviço de app em contêiner

cat << EOF > hello-app-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-app-ingress
  namespace: hello-app
  annotations:
    haproxy.org/ssl-redirect: "true"
    haproxy.org/ssl-redirect-port: "443"
    haproxy.org/ssl-redirect-code: "308"
spec:
  ingressClassName: haproxy
  tls:
  - hosts:
    - "k8s-app.example.com"
    secretName: tls-containerized
  rules:
  - host: "k8s-app.example.com"
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: hello-app
            port:
              number: 80
EOF

kk apply -f hello-app-ingress.yaml

Crie o recurso de entrada que vai se conectar ao serviço sem seletor do app da VM e endereçar o IP da VM para a qual o tráfego precisa ser roteado.

cat << EOF > vm-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: vm-app-ingress
  namespace: vm-app
  annotations:
    haproxy.org/ssl-redirect: "true"
    haproxy.org/ssl-redirect-port: "443"
    haproxy.org/ssl-redirect-code: "308"
spec:
  ingressClassName: haproxy
  tls:
  - hosts:
    - "vm-app.example.com"
    secretName: tls-vm
  rules:
  - host: "vm-app.example.com"
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: vm-app-svc
            port:
              number: 443
EOF

kk apply -f vm-ingress.yaml

Recuperar o endereço IP do balanceador de carga

Execute o comando para receber o endereço IP do balanceador de carga.

kk get services/haproxy-kubernetes-ingress \
  -n load-balancer \
  -o jsonpath='{.status.loadBalancer.ingress[0].ip}'

Isso será necessário ao verificar o acesso aos apps. Ele será chamado de LOAD_BALANCER_IP.

Criar uma VM cliente

Siga as etapas para criar uma VM cliente:

  1. Abra o console do GDC no navegador da Web.
  2. Abra o menu e clique em Máquinas virtuais.
  3. Clique em Criar instância.
  4. Crie uma VM chamada client, selecione um tipo de máquina pequeno e selecione o Rocky Linux ou o Ubuntu, que vêm com o curl pré-instalado.
  5. Clique em Criar.
  6. Aguarde alguns minutos até que a VM fique pronta.
  7. Quando a VM estiver pronta, estabeleça uma conexão SSH com ela:
    1. No console do GDC, clique na VM.
    2. Clique em Conectar com SSH.

Verificar o acesso e o roteamento

Para testar o roteamento, execute comandos curl na VM do cliente. Você pode se conectar aos dois aplicativos usando os nomes de host definidos com o endereço IP do balanceador de carga.

Ao transmitir a flag --resolve no curl, você pode forçar os nomes de domínio a serem resolvidos para o IP do balanceador de carga L4 do GDC com isolamento físico. Transmitimos a flag -k para confiar nos certificados autoassinados.

Teste o app em contêiner do Kubernetes:

curl -k --resolve k8s-app.example.com:443:$LOAD_BALANCER_IP https://k8s-app.example.com -v

Teste o app da VM externa:

curl -k --resolve vm-app.example.com:443:$LOAD_BALANCER_IP https://vm-app.example.com -v

Se configurado corretamente, o controlador de entrada vai atuar como terminador de TLS e transmitir o tráfego para o destino.

Opcional: usar certificados prontos para produção

Esta seção aborda como aproveitar o serviço de CA air-gapped do GDC para criar uma autoridade de certificação (CA) raiz privada, emitir certificados assinados para suas cargas de trabalho e atualizar com segurança o cluster padrão e as VMs clientes air-gapped do GDC.

Esta seção descreve como usar o serviço de CA air-gapped do GDC para criar uma autoridade de certificação (CA) raiz privada e emitir certificados válidos para seus aplicativos. Ao instalar essa CA raiz na VM do cliente, você pode verificar se o término de TLS funciona perfeitamente com certificados confiáveis, sem precisar ignorar os avisos de SSL (por exemplo, usando curl -k).

Conceder as permissões necessárias e receber credenciais

Para gerenciar o serviço de CA e emitir certificados, o usuário precisa dos papéis do IAM adequados no projeto.

  1. Conceda os papéis certificate-authority-service-admin e certificate-requester:

    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member=user:${USER_NAME} \
      --role=certificate-authority-service-admin
    
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member=user:${USER_NAME} \
      --role=certificate-requester
    
  2. Receba as credenciais do servidor da API de gerenciamento:

    gdcloud clusters get-credentials ${ORG_NAME}-admin
    

Criar a CA raiz

Você vai criar uma autoridade de certificação no servidor da API de gerenciamento no namespace do projeto.

  1. Aplique o recurso CertificateAuthority:

    km apply -f - <<EOF
    apiVersion: pki.security.gdc.goog/v1
    kind: CertificateAuthority
    metadata:
      name: my-root-ca
      namespace: ${PROJECT_ID}
    spec:
      caProfile:
        commonName: "My Root CA"
        duration: 87600h # 10 years
        keyAlgorithm: RSA_2048
        maxChainLength: 1
      caType: ROOT
      keyLocation: HSM
      rotationPolicy:
        cronTime: 0 0 1 1 *
    EOF
    
    km -n ${PROJECT_ID} get \
    certificateauthority.pki.security.gdc.goog/my-root-ca -ojson \
    | jq -r '
    .status.conditions[] | select( .type as $id | "Ready" | index($id)) .status'
    

Emitir e implantar certificados

Quando a CA estiver pronta, você vai solicitar certificados para o app em contêiner e o app baseado em VM. Essas solicitações acontecem no servidor da API de gerenciamento, e as chaves resultantes precisam ser movidas para o cluster padrão.

Crie solicitações para os dois domínios:

km apply -f - <<EOF
apiVersion: pki.security.gdc.goog/v1
kind: CertificateRequest
metadata:
  name: tls-containerized-req
  namespace: ${PROJECT_ID}
spec:
  certificateAuthorityRef:
    name: my-root-ca
    namespace: ${PROJECT_ID}
  certificateConfig:
    subjectConfig:
      commonName: "k8s-app.example.com"
      dnsNames:
      - "k8s-app.example.com"
  signedCertificateSecret: tls-containerized-signed
---
apiVersion: pki.security.gdc.goog/v1
kind: CertificateRequest
metadata:
  name: tls-vm-req
  namespace: ${PROJECT_ID}
spec:
  certificateAuthorityRef:
    name: my-root-ca
    namespace: ${PROJECT_ID}
  certificateConfig:
    subjectConfig:
      commonName: "vm-app.example.com"
      dnsNames:
      - "vm-app.example.com"
  signedCertificateSecret: tls-vm-signed
EOF

Aguarde alguns instantes para que os certificados sejam emitidos. Você pode verificar se eles estão prontos quando a condição "Pronto" for "Verdadeira":

km get certificaterequests -n ${PROJECT_ID}

Atualizar o cluster padrão

Se você seguiu as seções anteriores deste guia, terá secrets autoassinados no cluster padrão. Exclua-os antes de criar as novas versões assinadas:

kk delete secret tls-containerized -n load-balancer
kk delete secret tls-vm -n load-balancer

kk delete secret tls-containerized -n hello-app
kk delete secret tls-vm -n vm-app

Agora, extraia os certificados assinados do servidor da API de gerenciamento e crie os novos secrets no cluster padrão.

km get secret -n ${PROJECT_ID} tls-containerized-signed \
  -o jsonpath='{.data.tls\.crt}' \
  | base64 -d > tls-containerized.crt

km get secret -n ${PROJECT_ID} tls-containerized-signed \
  -o jsonpath='{.data.tls\.key}' \
  | base64 -d > tls-containerized.key

kk create secret tls tls-containerized \
  --namespace load-balancer \
  --key tls-containerized.key \
  --cert tls-containerized.crt

kk create secret tls tls-containerized \
  --namespace hello-app \
  --key tls-containerized.key \
  --cert tls-containerized.crt

km get secret -n ${PROJECT_ID} tls-vm-signed \
  -o jsonpath='{.data.tls\.crt}' \
  | base64 -d > tls-vm.crt

km get secret -n ${PROJECT_ID} tls-vm-signed \
  -o jsonpath='{.data.tls\.key}' \
  | base64 -d > tls-vm.key

kk create secret tls tls-vm \
  --namespace load-balancer \
  --key tls-vm.key \
  --cert tls-vm.crt

kk create secret tls tls-vm \
  --namespace vm-app \
  --key tls-vm.key \
  --cert tls-vm.crt

Os novos secrets serão recebidos e atualizados automaticamente pelos balanceadores de carga.

Configurar a confiança do cliente

Para verificar a configuração, é necessário informar à VM do cliente para confiar na nova CA raiz.

Extraia o certificado de CA raiz para um arquivo:

km get secret -n ${PROJECT_ID} my-root-ca-secret \
  -o jsonpath='{.data.tls\.crt}' \
  | base64 -d > my-root-ca.crt

Transfira o certificado para a VM do cliente. Você pode copiar o conteúdo de my-root-ca.crt e colar em um arquivo na VM do cliente.

Na VM do cliente, atualize o repositório de confiança.

Se a VM client for do Ubuntu:

sudo cp my-root-ca.crt /usr/local/share/ca-certificates/
sudo chmod 644 /usr/local/share/ca-certificates/my-root-ca.crt
sudo update-ca-certificates

Se a VM client for do Rocky Linux:

sudo cp my-root-ca.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust

Verificar o acesso

Agora você pode acessar seus aplicativos usando o curl sem a flag -k. A conexão será totalmente confiável.

Teste o app em contêiner do k8s:

curl -v --resolve k8s-app.example.com:443:LOAD_BALANDER_IP https://k8s-app.example.com

Teste o app da VM:

curl -v --resolve vm.example.com:443:LOAD_BALANDER_IP https://vm-app.example.com

Se for bem-sucedido, a saída do aplicativo será exibida imediatamente, sem avisos de certificado SSL.

Exceto em caso de indicação contrária, o conteúdo desta página é licenciado de acordo com a Licença de atribuição 4.0 do Creative Commons, e as amostras de código são licenciadas de acordo com a Licença Apache 2.0. Para mais detalhes, consulte as políticas do site do Google Developers. Java é uma marca registrada da Oracle e/ou afiliadas.

Última atualização 2026-08-15 UTC.