Implantar a imagem de contêiner no Serviço de Kubernetes do Azure

Concluído(a)

Nesta unidade, você implantará uma imagem de contêiner no AKS (Serviço de Kubernetes do Azure). Com o AKS, você configura o cluster kubernetes para ser executado em um estado desejado por meio de um Deployment, que é o processo de fornecer atualizações declarativas para pods e ReplicaSets. Essa declaração de estado é administrada no arquivo YAML do manifesto e o controlador kubernetes altera o estado atual para o estado declarado quando instruído. Você cria este arquivo de manifesto deployment.yml e instrui sua instância do AKS a operar em um estado desejado, com pods configurados para buscar e executar a imagem de contêiner flightbookingsystemsample — armazenada no Registro de Contêiner do Azure — que você enviou na unidade anterior. Esse manifesto define declarativamente um Deployment e um serviço. O Kubernetes usa o controlador de implantação para gerenciar os pods do aplicativo; você também pode criar uma implantação imperativamente com kubectl create deployment.

Observação

Se a sua sessão tiver expirado por inatividade ou você estiver fazendo essa etapa em outro momento ou em outra CLI, talvez seja necessário reinicializar as variáveis de ambiente e se reautenticar usando os seguintes comandos:

Restaure os valores das variáveis ​​de recurso usados na configuração. Substitua <your-subscription-ID> abaixo pela ID da assinatura que você usou para este módulo. Se o login apresentar um seletor de assinatura, escolha a mesma assinatura. Execute os comandos de autenticação um de cada vez. Depois de az account show, confirme se a assinatura ativa corresponde à configuração antes de continuar. Se um comando falhar, pare e resolva o erro.

export AZ_RESOURCE_GROUP=java-containerization-demo-rg
export AZ_CONTAINER_REGISTRY=<your-container-registry>
export AZ_KUBERNETES_CLUSTER=java-containerization-demo-aks
export AZ_LOCATION=<your-Azure-region>
export AZ_KUBERNETES_CLUSTER_DNS_PREFIX=<your-unique-DNS-prefix-to-access-your-AKS-cluster>
az login
az account set --subscription "<your-subscription-ID>"
az account show --output table
az acr login --name "$AZ_CONTAINER_REGISTRY"

Fazer deploy de uma imagem de contêiner

Agora você implanta a imagem de flightbookingsystemsample contêiner no cluster do AKS. Em containerize-and-deploy-Java-app-to-Azure/Project/Airlines, use um editor de texto instalado para criar um arquivo chamado deployment.yml. Esse caminho é relativo ao diretório pai em que você clonou o repositório. Se você já estiver em Project/Airlines, permaneça lá, em vez de navegar novamente pelo caminho relativo completo. Crie o arquivo e execute o comando kubectl apply -f deployment.yml (mencionado posteriormente) a partir deste diretório.

Adicione o conteúdo a seguir para deployment.yml e salve o arquivo. Substitua o <AZ_CONTAINER_REGISTRY> placeholder pelo valor da variável de ambiente AZ_CONTAINER_REGISTRY definida anteriormente.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: flightbookingsystemsample
spec:
  replicas: 1
  selector:
    matchLabels:
      app: flightbookingsystemsample
  template:
    metadata:
      labels:
        app: flightbookingsystemsample
    spec:
      nodeSelector:
        kubernetes.io/os: linux
        kubernetes.io/arch: amd64
      containers:
      - name: flightbookingsystemsample
        image: <AZ_CONTAINER_REGISTRY>.azurecr.io/flightbookingsystemsample:latest
        resources:
          requests:
            cpu: "1"
            memory: "1Gi"
          limits:
            cpu: "2"
            memory: "2Gi"
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: flightbookingsystemsample
spec:
  type: LoadBalancer
  ports:
  - port: 8080
    targetPort: 8080
  selector:
    app: flightbookingsystemsample

Observação

Se você usar o arquivo deployment_solution.yml na pasta raiz do projeto como ponto de partida, atualize sua imagem para a mesma imagem do registro e a tag :latest mostrada aqui. Adicione também a mesma configuração para Linux AMD64 nodeSelector na seção spec.template.spec, do Deployment, ao lado de containers. Não utilize a alternativa original sem alterações: a imagem e o seletor de nós (node selector) devem corresponder à plataforma de compilação deste módulo.

No deployment.yml anterior, o arquivo contém um Deployment e um serviço. A implantação é usada para administrar um conjunto de pods e o serviço é usado para permitir o acesso à rede aos pods. Os pods são configurados para efetuar pull de uma única imagem, <AZ_CONTAINER_REGISTRY>.azurecr.io/flightbookingsystemsample:latestdo Registro de Contêiner do Azure. O serviço está configurado para permitir tráfego HTTP de entrada para os pods na porta 8080, de forma semelhante a como você executou a imagem de contêiner localmente usando o argumento de porta -p.

O seletor de nó restringe os pods a nós AMD64 do Linux, correspondendo à linux/amd64 imagem criada anteriormente. Isso pertence ao Deployment, não ao Service. Um seletor restringe o agendamento; não faz com que uma imagem incompatível seja executada em outra arquitetura.

Antes de configurar o acesso ao cluster, verifique se a criação do cluster do AKS na unidade de instalação foi concluída com êxito. Verifique o estado de provisionamento e a versão atual do Kubernetes:

az aks show \
    --resource-group "$AZ_RESOURCE_GROUP" \
    --name "$AZ_KUBERNETES_CLUSTER" \
    --query '{provisioningState:provisioningState,currentKubernetesVersion:currentKubernetesVersion}' \
    --output table

Não continue se o comando falhar, provisioningState não for currentKubernetesVersion ou major.minor.patch não for uma versão não vazia no formato Succeeded.

As instruções da ferramenta a seguir se aplicam à sessão local de Bash no Linux, macOS ou WSL estabelecida na configuração, não ao PowerShell nativo nem ao Prompt de Comando. Se você já tiver instalações funcionais de kubectl e kubelogin nessa sessão, mantenha-as em vez de reinstalá-las. Verifique-as usando kubectl version --client e kubelogin --version e certifique-se de que kubectl atenda à política de discrepância de versão compatível para o cluster.

Caso contrário, substitua <control-plane-version> pelo retornado currentKubernetesVersion. Instale essa versão correspondente kubectl e kubelogin em locais com permissão de gravação para o usuário:

KUBECTL_VERSION="<control-plane-version>"
if [[ "$KUBECTL_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
    mkdir -p "$HOME/.local/bin" &&
    az aks install-cli \
        --client-version "$KUBECTL_VERSION" \
        --install-location "$HOME/.local/bin/kubectl" \
        --kubelogin-install-location "$HOME/.local/bin/kubelogin" &&
    export PATH="$HOME/.local/bin:$PATH" &&
    kubectl version --client &&
    kubelogin --version
else
    printf 'Stop: set KUBECTL_VERSION to the returned major.minor.patch version.\n' >&2
    false
fi

Ambos os caminhos de instalação incluem o nome do arquivo executável. O comando PATH export aplica-se somente ao shell atual; repita-o em uma nova sessão ou adicione-o à configuração de inicialização do Bash apropriada. Resolva qualquer falha de instalação ou verificação de versão antes de continuar.

Depois que ambas as ferramentas estiverem disponíveis e verificadas, configure kubectl para se conectar ao cluster do AKS:

az aks get-credentials \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_KUBERNETES_CLUSTER

A saída a seguir é típica:

Merged AZ_KUBERNETES_CLUSTER as current context in ~/.kube/config

Verifique os sistemas operacionais e as arquiteturas reais do nó antes de aplicar o manifesto:

kubectl get nodes \
    -o custom-columns='NAME:.metadata.name,OS:.status.nodeInfo.operatingSystem,ARCH:.status.nodeInfo.architecture'

O caminho de build deste linux/amd64 módulo requer nós AMD64 do Linux. Se não houver nós correspondentes, pare e resolva a incompatibilidade antes de continuar. Use um pool de nós AMD64 com suporte ou recompile, execute e envie por push a imagem para outra arquitetura de nó do Linux com suporte e atualize o seletor de arquitetura do Deployment para corresponder. A opção Docker --platform não cria ou altera um pool de nós do AKS.

De containerize-and-deploy-Java-app-to-Azure/Project/Airlines, aplique deployment.yml ao cluster:

kubectl apply -f deployment.yml

A saída a seguir é típica:

deployment.apps/flightbookingsystemsample created
service/flightbookingsystemsample created

Monitore o status da implantação usando o seguinte comando:

kubectl get all

A saída a seguir é típica:

kubectl get all
NAME                                            READY   STATUS    RESTARTS   AGE
pod/flightbookingsystemsample-b7fd6684f-4j8vf   1/1     Running   0          37s

NAME                                TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)          AGE
service/flightbookingsystemsample   LoadBalancer   10.0.62.153   <external-IP>   8080:30534/TCP   37s
service/kubernetes                  ClusterIP      10.0.0.1      <none>          443/TCP          11h

NAME                                        READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/flightbookingsystemsample   1/1     1            1           37s

NAME                                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/flightbookingsystemsample-b7fd6684f   1         1         1       37s

O status de Running um pod não confirma se o Tomcat terminou de implantar o aplicativo ou se as solicitações HTTP são bem-sucedidas. Aguarde o rollout da implantação e siga os logs de inicialização do aplicativo:

kubectl rollout status deployment/flightbookingsystemsample --timeout=300s &&
kubectl logs deployment/flightbookingsystemsample --tail=100 --follow

Um rollout bem-sucedido verifica a disponibilidade do Kubernetes. Como este manifesto não inclui uma investigação de preparação da aplicação, o processo de implantação (rollout) não envolve um teste de integridade HTTP. Siga os logs até que o Tomcat reporte a inicialização do servidor concluída e que a implantação de AirlinesReservationSample.war tenha sido concluída sem erros. Em seguida, pressione Ctrl+C para parar de seguir os logs. Isso interrompe apenas o fluxo de log, não o contêiner. Se a implantação ou a inicialização do aplicativo falhar ou não for concluída, inspecione os logs e os eventos de pod em vez de continuar para a verificação do navegador.

A saída histórica a seguir ilustra as mensagens de inicialização de uma imagem anterior do Tomcat 10.1.33. Isto não é a saída da imagem atualizada neste módulo; use seus próprios logs para verificar a inicialização em vez de esperar as mesmas versões, carimbos de data/hora ou detalhes do ambiente:

kubectl logs pod/flightbookingsystemsample-b7fd6684f-4j8vf
15-Nov-2024 12:31:51.208 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name:   Apache Tomcat/10.1.33
15-Nov-2024 12:31:51.211 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built:          Nov 7 2024 22:28:55 UTC
15-Nov-2024 12:31:51.212 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 10.1.33.0
15-Nov-2024 12:31:51.212 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name:               Linux
15-Nov-2024 12:31:51.212 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version:            5.15.0-1074-azure
15-Nov-2024 12:31:51.212 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture:          amd64
15-Nov-2024 12:31:51.216 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home:             /usr/lib/jvm/msopenjdk-17
15-Nov-2024 12:31:51.216 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version:           17.0.13+11-LTS
15-Nov-2024 12:31:51.216 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor:            Microsoft
15-Nov-2024 12:31:51.216 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE:         /usr/local/tomcat
15-Nov-2024 12:31:51.216 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME:         /usr/local/tomcat
15-Nov-2024 12:31:51.226 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties
15-Nov-2024 12:31:51.226 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
15-Nov-2024 12:31:51.227 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048
15-Nov-2024 12:31:51.227 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
15-Nov-2024 12:31:51.227 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dorg.apache.catalina.security.SecurityListener.UMASK=0027
15-Nov-2024 12:31:51.227 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang=ALL-UNNAMED
15-Nov-2024 12:31:51.228 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.io=ALL-UNNAMED
15-Nov-2024 12:31:51.228 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util=ALL-UNNAMED
15-Nov-2024 12:31:51.228 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
15-Nov-2024 12:31:51.229 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
15-Nov-2024 12:31:51.229 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=/usr/local/tomcat
15-Nov-2024 12:31:51.229 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=/usr/local/tomcat
15-Nov-2024 12:31:51.229 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=/usr/local/tomcat/temp
15-Nov-2024 12:31:51.231 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent The Apache Tomcat Native library which allows using OpenSSL was not found on the java.library.path: [/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib]
15-Nov-2024 12:31:51.565 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
15-Nov-2024 12:31:51.602 INFO [main] org.apache.catalina.startup.Catalina.load Server initialization in [616] milliseconds
15-Nov-2024 12:31:51.658 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
15-Nov-2024 12:31:51.659 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/10.1.33]
15-Nov-2024 12:31:51.689 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/usr/local/tomcat/webapps/AirlinesReservationSample.war]
15-Nov-2024 12:31:53.264 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
15-Nov-2024 12:31:55.155 INFO [main] com.sun.xml.ws.server.MonitorBase.createRoot Metro monitoring rootname successfully set to: com.sun.metro:pp=/,type=WSEndpoint,name=/AirlinesReservationSample-PriceAndSeats-PriceAndSeatsPort
15-Nov-2024 12:31:55.347 INFO [main] com.sun.xml.ws.transport.http.servlet.WSServletDelegate.<init> WSSERVLET14: XML-WS servlet initializing
WARNING:Error in the metadata of the table SEATS: table's row count in the metadata is 5 but 6 records have been found and loaded by UCanAccess. All will work fine, but it's better to repair your database.
15-Nov-2024 12:31:56.248 INFO [main] com.sun.xml.ws.transport.http.servlet.WSServletContextListener.contextInitialized WSSERVLET12: XML-WS context listener initializing
15-Nov-2024 12:31:56.249 INFO [main] com.sun.xml.ws.transport.http.servlet.WSServletContextListener.contextInitialized WSSERVLET12: XML-WS context listener initializing
15-Nov-2024 12:31:56.284 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/usr/local/tomcat/webapps/AirlinesReservationSample.war] has finished in [4,595] ms
15-Nov-2024 12:31:56.285 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/docs]
15-Nov-2024 12:31:56.315 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/docs] has finished in [30] ms
15-Nov-2024 12:31:56.316 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/examples]
15-Nov-2024 12:31:56.439 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/examples] has finished in [123] ms
15-Nov-2024 12:31:56.440 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/manager]
15-Nov-2024 12:31:56.456 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/manager] has finished in [16] ms
15-Nov-2024 12:31:56.457 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/ROOT]
15-Nov-2024 12:31:56.468 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/ROOT] has finished in [11] ms
15-Nov-2024 12:31:56.468 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/host-manager]
15-Nov-2024 12:31:56.481 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/host-manager] has finished in [13] ms
15-Nov-2024 12:31:56.484 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
15-Nov-2024 12:31:56.501 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [4897] milliseconds

Monitore o serviço para obter seu endereço externo:

kubectl get service flightbookingsystemsample --watch

O EXTERNAL-IP valor pode ser <pending> inicialmente enquanto Azure provisiona o balanceador de carga. Isso pode levar vários minutos e não é evidência de uma implantação com falha por si só. Quando um endereço aparecer, pressione Ctrl+C para interromper o monitoramento. Se o provisionamento não for concluído, interrompa o monitoramento e inspecione os eventos do serviço usando kubectl describe service flightbookingsystemsample.

A seguinte saída ilustrativa mostra onde o endereço atribuído é exibido:

NAME                        TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)          AGE
flightbookingsystemsample   LoadBalancer   10.0.62.153   <external-IP>   8080:30534/TCP   3m28s

Observação

Substitua o endereço IP <external-IP> na seguinte URL pelo valor EXTERNAL-IP do comando executado anteriormente:

Abra um navegador e visite a página inicial do exemplo Sistema de Reservas de Voo em http://<external-IP>:8080/AirlinesReservationSample/. Confirme se a página do aplicativo responde; um Running pod ou um IP atribuído sozinho não prova a preparação do aplicativo. Seu navegador deve ser semelhante à seguinte captura de tela:

Captura de tela da página inicial do Sistema de Reservas de Voo em execução no Serviço de Kubernetes do Azure em um navegador.

Opcionalmente, você pode fazer login com qualquer usuário de tomcat-users.xml – por exemplo, someuser@azure.com: password.

Solução de problemas: incompatibilidade de plataforma da imagem

Para falhas de inicialização de pod, inspecione kubectl describe pods -l app=flightbookingsystemsamplee kubectl logs deployment/flightbookingsystemsample --tail=100kubectl get events --sort-by=.metadata.creationTimestamp. Um CrashLoopBackOff estado pode ter várias causas, incluindo erros de aplicativo; não suponha que cada falha seja uma incompatibilidade de arquitetura.

Se você confirmar que uma imagem já implantada tem a plataforma errada, primeiro repita o build, a execução local, a inspeção de imagem, a marcação do Registro e as etapas de push com as configurações de plataforma correspondentes. Após a imagem corrigida ser reconstruída, renomeada e enviada com a mesma marcação :latest, substitua explicitamente os pods em execução:

kubectl rollout restart deployment/flightbookingsystemsample &&
kubectl rollout status deployment/flightbookingsystemsample --timeout=300s

Para esse manifesto, :latest é definido por padrão como imagePullPolicy: Always, portanto, os pods de substituição resolvem a tag atual do registro. Reaplicar um manifesto inalterado por si só não dispara um rollout. Se você personalizou a política de busca, utilize uma marcação ou um digest de imagem atualizado e, em vez disso, atualize o Deployment. Repita as verificações de URL do aplicativo e do log de inicialização após a implantação.

Limpar os recursos

Os recursos criados neste módulo podem gerar custos contínuos. Para limpar os recursos, exclua o grupo de recursos que os contém usando o seguinte comando:

az group delete --name $AZ_RESOURCE_GROUP