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

Concluído

Nesta unidade, você implanta uma imagem de contêiner no Serviço Kubernetes do Azure (AKS). Com o AKS, configura o seu cluster Kubernetes para funcionar num estado desejado por meio de uma implantação, que é o processo de realizar atualizações declarativas para pods e ReplicaSets. Essa declaração de estado é administrada no arquivo YAML manifesto e o controlador Kubernetes altera o estado atual para o estado declarado quando instruído. Você cria esse arquivo de manifesto deployment.yml e instrui sua instância do AKS a ser executada em um estado desejado com pods configurados para extrair e executar a flightbookingsystemsample imagem de contêiner contida no registro de contêiner do Azure que você enviou por push na unidade anterior. Este manifesto define declarativamente um Deployment e um Service. O Kubernetes utiliza o controlador de Deployment para gerir os pods da aplicação; também pode criar um Deployment imperativamente com kubectl create deployment.

Observação

Se sua sessão estiver ociosa ou se você estiver executando essa etapa em outro momento ou em outra CLI, talvez seja necessário reinicializar as variáveis de ambiente e autenticar novamente usando os seguintes comandos:

Restaurar os valores das variáveis de recursos usados na configuração inicial. Substitua <your-subscription-ID> abaixo pelo ID da subscrição que utilizou neste módulo. Se, ao iniciar sessão, for apresentado um seletor de subscrição, escolha essa mesma subscrição. Executa os comandos de autenticação um de cada vez. Após az account show, confirma se a subscrição 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"

Implantar uma imagem de contêiner

Agora você implanta a imagem do flightbookingsystemsample contêiner no cluster do AKS. Em containerize-and-deploy-Java-app-to-Azure/Project/Airlines, utilize um editor de texto instalado para criar um ficheiro chamado deployment.yml. Este caminho é relativo ao diretório pai onde clonou o repositório. Se já estiveres em Project/Airlines, fica lá em vez de voltares a mudar para o caminho absoluto completo. Crie o ficheiro e execute o comando seguinte kubectl apply -f deployment.yml a partir deste diretório.

Adicione o conteúdo seguinte a deployment.yml e depois guarde o ficheiro. Substitua o <AZ_CONTAINER_REGISTRY> marcador pelo valor da variável de ambiente AZ_CONTAINER_REGISTRY que definiu 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 usares o ficheiro deployment_solution.yml na pasta raiz do teu projeto como ponto de partida, atualiza a imagem para a mesma imagem do registo e :latest tag mostrada aqui. Adicione também o mesmo Linux AMD64 nodeSelector na secção spec.template.spec da Implantação, juntamente com containers. Não use a variante inalterada: a sua imagem e seletor de nós devem corresponder à plataforma de construção deste módulo.

No deployment.yml anterior, o ficheiro contém uma implantação e um serviço. A implantação é usada para administrar um conjunto de pods, e o serviço é usado para permitir o acesso de rede aos pods. Os pods são configurados para extrair uma única imagem, <AZ_CONTAINER_REGISTRY>.azurecr.io/flightbookingsystemsample:latest, do Registro de Contêiner do Azure. O serviço está configurado para permitir o tráfego de entrada do pod HTTP para a porta 8080, semelhante à maneira como se executou localmente a imagem do contêiner com o argumento -p port.

O seletor de nós restringe os pods a nós Linux AMD64, correspondendo à linux/amd64 imagem construída anteriormente. Pertence ao Deployment, não ao Serviço. Um seletor restringe o agendamento; não faz com que uma imagem incompatível seja executada noutra arquitetura.

Antes de configurar o acesso ao cluster, certifique-se de que a criação do cluster AKS na unidade de configuração foi concluída com sucesso. Verifique o seu 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 seguintes aplicam-se à sessão local de Linux, macOS ou WSL Bash estabelecida na configuração, não ao PowerShell nativo ou ao Prompt de Comandos. Se já tiveres instalações kubectl e kubelogin a funcionar nessa sessão, mantém-nas em vez de reinstalares. Verifique-os com kubectl version --client e kubelogin --version, e certifique-se de que kubectl cumpre a política de desajuste de versões suportada para o cluster.

Caso contrário, substitua <control-plane-version> pela currentKubernetesVersion devolvida. Instale essa versão correspondente kubectl e kubelogin em locais onde o utilizador possa escrever:

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 ficheiro executável. O PATH export aplica-se apenas à shell atual; repita-o numa nova sessão ou adicione-o à configuração de arranque do Bash apropriada. Resolva qualquer falha de instalação ou verificação de versões antes de continuar.

Depois de ambas as ferramentas estarem disponíveis e verificadas, configure kubectl para se ligar ao seu cluster AKS:

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

A seguinte saída é típica:

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

Verifique os sistemas operativos e arquiteturas reais dos nós antes de aplicar o manifest:

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

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

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

kubectl apply -f deployment.yml

A seguinte saída é típica:

deployment.apps/flightbookingsystemsample created
service/flightbookingsystemsample created

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

kubectl get all

A seguinte saída é 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 estado de um pod Running não confirma que o Tomcat terminou de implementar a aplicação ou que os pedidos HTTP são bem-sucedidos. Aguarde pela implementação faseada e siga os registos de arranque da aplicação:

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

Uma implementação bem-sucedida verifica a disponibilidade do Kubernetes. Como este manifesto não tem sonda de prontidão da aplicação, o rollout não é uma verificação de estado HTTP. Acompanhe os registos até que o Tomcat reporte que o arranque do servidor foi concluído e a implementação do AirlinesReservationSample.war foi concluída sem erros. Depois carrega em Ctrl+C para parar de seguir os logs. Isto para apenas o fluxo de registos, não o container. Se a implementação ou o arranque da aplicação falhar ou não terminar, inspecione os registos e os eventos do pod em vez de continuar para a verificação do navegador.

O resultado histórico seguinte ilustra mensagens de arranque a partir de uma imagem anterior do Tomcat 10.1.33. Não é resultado da imagem atualizada neste módulo; use os seus próprios registos para verificar o arranque em vez de esperar as mesmas versões, carimbos temporais 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

Monitorize o serviço pelo seu endereço externo:

kubectl get service flightbookingsystemsample --watch

O valor EXTERNAL-IP pode inicialmente ser <pending> enquanto o Azure aprovisiona o balanceador de carga. Isto pode demorar vários minutos e não é prova de uma implantação falhada por si só. Quando aparecer um endereço, pressione Ctrl+C para parar de monitorizar. Se o provisionamento não for concluído, pare o Watch e inspecione os eventos de serviço com kubectl describe service flightbookingsystemsample.

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

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> no seguinte URL pelo valor EXTERNAL-IP do comando que executou anteriormente.

Abra um navegador e visite a página inicial de exemplo do sistema de reserva de voos em http://<external-IP>:8080/AirlinesReservationSample/. Confirma que a página da aplicação responde; um Running pod ou um IP atribuído sozinho não prova a prontidão da aplicação. Seu navegador deve ser semelhante à seguinte captura de tela:

Captura de ecrã da landing page do Flight Booking System a correr no Azure Kubernetes Service num navegador.

Opcionalmente, pode iniciar sessão com qualquer utilizador a partir de tomcat-users.xml - por exemplo, someuser@azure.com: password.

Resolver uma incompatibilidade entre imagem e plataforma

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

Se confirmar que uma imagem já implantada tem a plataforma errada, repita primeiro a compilação, execução local, inspeção da imagem, etiquetagem do registo e passos de envio com as definições correspondentes da plataforma. Depois de a imagem corrigida ter sido reconstruída com sucesso, reetiquetada e publicada com a mesma tag :latest, substitua explicitamente os pods em execução:

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

Para este manifesto, :latest assume imagePullPolicy: Always por predefinição, por isso os pods de substituição resolvem a etiqueta de registo atual. Reaplicar sozinho um manifest inalterado não desencadeia uma implementação. Se personalizou a política de obtenção, utilize uma etiqueta de imagem atualizada ou um digest e atualize o Deployment em vez disso. Repita as verificações do registo de arranque e do URL da aplicação após a implementação.

Limpeza de recursos

Os recursos criados neste módulo podem incorrer em 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