Migrar aplicativos Tomcat para contêineres no AKS (Serviço de Kubernetes do Azure)

Este guia descreve as informações das quais você deve estar ciente quando deseja migrar um aplicativo Tomcat existente para ser executado em um contêiner do AKS (Serviço de Kubernetes do Azure).

Pré-migração

Antes de tudo, para garantir uma migração bem-sucedida, conclua as etapas de avaliação e de inventário descritas nas seções a seguir.

Recursos externos de inventário

Recursos externos, como fontes de dados, agentes de mensagem JMS e outros, são injetados por meio de JNDI (Interface de Nomenclatura e Diretório do Java). Alguns desses recursos podem exigir migração ou reconfiguração.

Dentro de seu aplicativo

Inspecione o arquivo META-INF/context.xml. Procure elementos de <Resource> dentro do elemento <Context>.

Nos servidores de aplicativos

Inspecione os arquivos $CATALINA_BASE/conf/context.xml e $CATALINA_BASE/conf/server.xml, bem como os arquivos .xml encontrados nos diretórios $CATALINA_BASE/conf/[nome-do-mecanismo]/[nome-do-host].

Em arquivos context.xml, os recursos de JNDI serão descritos pelos elementos <Resource> dentro do elemento <Context> de nível superior.

Em arquivos server.xml, os recursos de JNDI serão descritos pelos elementos <Resource> dentro do elemento <GlobalNamingResources>.

Fontes de dados

Fontes de dados são recursos de JNDI com o atributo type definido como javax.sql.DataSource. Para cada fonte de dados, documente as seguintes informações:

  • Qual é o nome da fonte de dados?
  • Qual é a configuração do pool de conexões?
  • Onde posso encontrar o arquivo JAR do driver JDBC?

Para obter mais informações, consulte Instruções de fonte de dados JNDI na documentação do Tomcat.

Todos os outros recursos externos

Não é possível documentar todas as dependências externas possíveis neste guia. É responsabilidade da sua equipe verificar se você pode atender a todas as dependências externas de seu aplicativo após a migração.

Segredos de inventário

Senhas e cadeias de caracteres seguras

Verifique todas as propriedades e os arquivos de configuração nos servidores de produção para quaisquer senhas e cadeias de caracteres secretas. É necessário verificar server.xml e context.xml em $CATALINA_BASE/conf. Você também pode encontrar arquivos de configuração que contenham senhas ou credenciais dentro de seu aplicativo. Eles podem incluir META-INF/context.xml e, para aplicativos Spring boot, arquivos application.properties ou application.yml.

Determinar se e como o sistema de arquivos é usado

Qualquer uso do sistema de arquivos no servidor de aplicativos exigirá reconfiguração ou, em casos raros, alterações de arquitetura. Você pode identificar alguns ou todos os cenários a seguir.

Conteúdo estático somente leitura

Se seu aplicativo estiver servindo conteúdo estático no momento, você precisará de um local alternativo para ele. Talvez você queira considerar a migração de conteúdo estático para o Armazenamento de Blobs do Azure e a adição da CDN do Azure para downloads extremamente rápidos, globalmente. Para obter mais informações, confira Hospedagem de site estático no Armazenamento do Microsoft Azure e Início rápido: Integrar uma conta de armazenamento do Azure à CDN do Azure.

Conteúdo estático publicado dinamicamente

Se o aplicativo permitir conteúdo estático que é carregado/produzido pelo aplicativo, mas não puder ser alterado após sua criação, você poderá usar o Armazenamento de Blobs do Azure e a CDN do Azure, conforme descrito acima, com uma Função do Azure para lidar com uploads e atualização de CDN. Fornecemos uma implementação de exemplo para seu uso em Carregar conteúdo estático e fazer o pré-carregamento desse conteúdo pela CDN com o Azure Functions.

Conteúdo dinâmico ou interno

Para arquivos que são frequentemente escritos e lidos pelo aplicativo (como arquivos de dados temporários) ou arquivos estáticos que são visíveis somente para o aplicativo, você pode montar compartilhamentos do Armazenamento do Azure como volumes persistentes. Para obter mais informações, confira Criar e usar um volume com os Arquivos do Azure no AKS (Serviço de Kubernetes do Azure).

Identificar o mecanismo de persistência da sessão

Para identificar o gerenciador de persistência de sessão em uso, inspecione os arquivos context.xml em seu aplicativo e a configuração do Tomcat. Procure o elemento <Manager> e observe o valor do atributo className.

As implementações internas de PersistentManager do Tomcat, como StandardManager ou FileStore, não são projetadas para uso com uma plataforma distribuída e dimensionada como o Kubernetes. O AKS pode balancear a carga entre vários pods e reiniciar de forma transparente qualquer Pod a qualquer momento, então a persistência de um estado mutável para um sistema de arquivos não é recomendada.

Se a persistência da sessão for necessária, você precisará usar uma implementação alternativa de PersistentManager que será gravada em um armazenamento de dados externo, como o VMware Tanzu Session Manager com o Cache Redis. Para obter mais informações, confira Usar o Redis como um cache de sessão com o Tomcat.

Casos especiais

Determinados cenários de produção podem exigir alterações adicionais ou impor limitações adicionais. Embora esses cenários possam ser infrequentes, é importante garantir que eles não se apliquem ao seu aplicativo ou que sejam resolvidos corretamente.

Determinar se o aplicativo depende de trabalhos agendados

Trabalhos agendados, como tarefas do Agendador do Quartz ou trabalhos cron, não podem ser usados com implantações do Tomcat em contêineres. Se o aplicativo for escalado horizontalmente, um trabalho agendado poderá ser executado mais de uma vez por período agendado. Essa situação pode levar a consequências indesejadas.

Inventarie quaisquer trabalhos agendados, dentro ou fora do servidor de aplicativos.

Determinar se o aplicativo contém código específico do sistema operacional

Se seu aplicativo contiver qualquer código que esteja acomodando o sistema operacional no qual seu aplicativo estiver sendo executado, o aplicativo precisará ser refatorado para NÃO depender do sistema operacional subjacente. Por exemplo, qualquer uso de / ou \ em caminhos de sistema de arquivos podem precisar ser substituídos por File.Separator ou Path.get.

Determinar se MemoryRealm é usado

MemoryRealm requer um arquivo XML persistente. No Kubernetes, esse arquivo precisará ser adicionado à imagem de contêiner ou carregado no armazenamento compartilhado disponibilizado para os contêineres. O parâmetro pathName precisará ser modificado de acordo.

Para determinar se MemoryRealm está sendo usado no momento, inspecione os arquivos server.xml e context.xml e pesquise por elementos <Realm> em que o atributo className está definido como org.apache.catalina.realm.MemoryRealm.

Determinar se o acompanhamento de sessão SSL é usado

Em implantações em contêineres, as sessões SSL normalmente são descarregadas fora do contêiner do aplicativo, geralmente pelo controlador de entrada. Se o aplicativo exigir acompanhamento de sessão SSL, verifique se o tráfego SSL é passado diretamente para o contêiner do aplicativo.

Determine se AccessLogValve é ou não usado

Se AccessLogValve for usado, o parâmetro directory deverá ser definido para um compartilhamento dos Arquivos do Azure montado ou um dos respectivos subdiretórios.

Teste in-loco

Antes de criar imagens de contêiner, migre seu aplicativo para o JDK e o Tomcat que você pretende usar no AKS. Teste seu aplicativo cuidadosamente para garantir a compatibilidade e o desempenho.

Parametrizar a configuração

Na pré-migração, você provavelmente terá identificado segredos e dependências externas, como fontes de dados, nos arquivos server.xml e context.xml. Para cada item identificado assim, substitua qualquer nome de usuário, senha, cadeia de conexão ou URL por uma variável de ambiente.

Por exemplo, suponha que o arquivo context.xml contém o seguinte elemento:

<Resource
    name="jdbc/dbconnection"
    type="javax.sql.DataSource"
    url="jdbc:postgresql://postgresdb.contoso.com/wickedsecret?ssl=true"
    driverClassName="org.postgresql.Driver"
    username="postgres"
    password="t00secure2gue$$"
/>

Nesse caso, você poderia alterá-lo conforme mostrado no exemplo a seguir:

<Resource
    name="jdbc/dbconnection"
    type="javax.sql.DataSource"
    url="${postgresdb.connectionString}"
    driverClassName="org.postgresql.Driver"
    username="${postgresdb.username}"
    password="${postgresdb.password}"
/>

Migração

Com exceção da primeira etapa ("Provisionar registro de contêiner e AKS"), recomendamos que você siga as etapas abaixo individualmente para cada aplicativo (arquivo WAR) que deseje migrar.

Observação

Algumas implantações do Tomcat podem ter vários aplicativos em execução em um único servidor Tomcat. Se esse for o caso em sua implantação, será altamente recomendável executar cada aplicativo em um pod separado. Isso permite que você otimize a utilização de recursos para cada aplicativo, minimizando a complexidade e o acoplamento.

Provisionar registro de contêiner e AKS

Crie um registro de contêiner e um cluster do Kubernetes do Azure cuja entidade de serviço tenha a função de Leitor no registro. Verifique se você escolheu o modelo de rede apropriado para os requisitos de rede do seu cluster.

az group create \
    --resource-group $resourceGroup \
    --location eastus
az acr create \
    --resource-group $resourceGroup \
    --name $acrName \
    --sku Standard
az aks create \
    --resource-group $resourceGroup \
    --name $aksName \
    --attach-acr $acrName \
    --network-plugin azure

Preparar os artefatos de implantação

Clone o repositório GitHub do início rápido do Tomcat em contêineres. Ele contém um Dockerfile e arquivos de configuração do Tomcat com várias otimizações recomendadas. Nas etapas abaixo, descrevemos as modificações que você provavelmente precisará fazer nesses arquivos antes de criar a imagem de contêiner e implantá-la no AKS.

Abrir portas para clustering, se necessário

Se você pretende usar o clustering de Tomcat no AKS, verifique se os intervalos de portas necessários estão expostos no Dockerfile. Para especificar o endereço IP do servidor em server.xml, é necessário usar um valor de uma variável que é inicializada na inicialização do contêiner para o endereço IP do pod.

Como alternativa, o estado de sessão pode ser persistido em um local alternativo para estar disponível entre as réplicas.

Para determinar se seu aplicativo usa clustering, procure o elemento <Cluster> dentro dos elementos <Host> ou <Engine> no arquivo server.xml.

Adicionar recursos de JNDI

Edite server.xml para adicionar os recursos que você preparou nas etapas de pré-migração, como fontes de dados.

Por exemplo:

<!-- Global JNDI resources
      Documentation at /docs/jndi-resources-howto.html
-->
<GlobalNamingResources>
    <!-- Editable user database that can also be used by
         UserDatabaseRealm to authenticate users
    -->
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml"
               />

    <!-- Migrated datasources here: -->
    <Resource
        name="jdbc/dbconnection"
        type="javax.sql.DataSource"
        url="${postgresdb.connectionString}"
        driverClassName="org.postgresql.Driver"
        username="${postgresdb.username}"
        password="${postgresdb.password}"
    />
    <!-- End of migrated datasources -->
</GlobalNamingResources>

Para obter instruções adicionais da fonte de dados, consulte as seções a seguir das Instruções de fonte de dados JNDI na documentação do Tomcat:

Criar imagem e enviá-la por push

A maneira mais simples de criar a imagem e carregá-la no ACR (Registro de Contêiner do Azure) para uso pelo AKS é usar o comando az acr build. Este comando não requer que o Docker seja instalado no seu computador. Por exemplo, se você tiver o Dockerfile acima e o pacote de aplicativos petclinic.war no diretório atual, poderá criar a imagem de contêiner no ACR com uma etapa:

az acr build \
    --image "${acrName}.azurecr.io/petclinic:{{.Run.ID}}" \
    --registry $acrName \
    --build-arg APP_FILE=petclinic.war \
    --build-arg=prod.server.xml .

Você poderá omitir o parâmetro --build-arg APP_FILE... se o seu arquivo WAR for nomeado ROOT.war. Você poderá omitir o parâmetro --build-arg SERVER_XML... se o seu arquivo XML do servidor for nomeado server.xml. Ambos os arquivos precisam estar no mesmo diretório que o Dockerfile.

Como alternativa, você pode usar a CLI do Docker para criar a imagem localmente. Essa abordagem pode simplificar o teste e refinar a imagem antes da implantação inicial no ACR. No entanto, ela requer que a CLI do Docker seja instalada e que o daemon do Docker esteja em execução.

# Build the image locally
sudo docker build . --build-arg APP_FILE=petclinic.war -t "${acrName}.azurecr.io/petclinic:1"

# Run the image locally
sudo docker run -d -p 8080:8080 "${acrName}.azurecr.io/petclinic:1"

# Your application can now be accessed with a browser at http://localhost:8080.

# Log into ACR
sudo az acr login --name $acrName

# Push the image to ACR
sudo docker push "${acrName}.azurecr.io/petclinic:1"

Para obter mais informações, consulte o módulo do Learn para Criar e armazenar imagens de contêiner no Azure.

Provisionar um endereço IP público

Se quiser que seu aplicativo esteja acessível de fora de suas redes internas ou virtuais, você precisará de um endereço IP estático público. Esse endereço IP deve ser provisionado dentro do grupo de recursos do nó do cluster.

export nodeResourceGroup=$(az aks show \
    --resource-group $resourceGroup \
    --name $aksName \
    --query 'nodeResourceGroup' \
    --output tsv)
export publicIp=$(az network public-ip create \
    --resource-group $nodeResourceGroup \
    --name applicationIp \
    --sku Standard \
    --allocation-method Static \
    --query 'publicIp.ipAddress' \
    --output tsv)
echo "Your public IP address is ${publicIp}."

Implantar no AKS

Crie e aplique seus arquivos YAML do Kubernetes. Se você estiver criando um balanceador de carga externo (seja para seu aplicativo ou para um controlador de entrada), será necessário fornecer o endereço IP provisionado na seção anterior como o LoadBalancerIP.

Inclua parâmetros externos como variáveis de ambiente. Não inclua segredos (como senhas, chaves de API e cadeias de conexão JDBC). Os segredos são abordados na seção Configurar o FlexVolume do KeyVault.

Configurar um armazenamento persistente

Se seu aplicativo exigir armazenamento não volátil, configure um ou mais Volumes Persistentes.

Talvez você queira criar um volume persistente usando os Arquivos do Azure montados no diretório de logs do Tomcat (/tomcat_logs) para manter os logs centralmente. Para obter mais informações, confira Criar e usar dinamicamente um volume persistente com Arquivos do Azure no AKS (Serviço de Kubernetes do Azure).

Configurar FlexVolume do KeyVault

Crie um Azure KeyVault e preencha todos os segredos necessários. Em seguida, configure um FlexVolume do KeyVault para tornar esses segredos acessíveis para pods.

Você precisará modificar o script de inicialização (startup.sh no repositório GitHub Tomcat em Contêineres) para importar os certificados para o repositório de chaves local no contêiner.

Migrar os trabalhos agendados

Para executar trabalhos agendados em seu cluster do AKS, defina Trabalhos do Cron conforme necessário.

Após a migração

Agora que você migrou seu aplicativo para o AKS, você deve verificar se ele funciona conforme o esperado. Depois de fazer isso, temos algumas recomendações para você que podem tornar seu aplicativo mais nativo da nuvem.