Compartilhar via


Visão geral do JavaScript nos Aplicativos de Contêiner do Azure

Os Aplicativos de Contêiner do Azure podem executar qualquer aplicativo JavaScript em contêineres na nuvem, oferecendo opções flexíveis de como implantar seus aplicativos.

Configuração

Os Aplicativos de Contêiner do Azure permitem simplificar a implantação de seus aplicativos JavaScript por meio de contêineres eficazes, incluindo a configuração de variáveis de ambiente, a criação de dockerfiles eficientes e a organização do processo de build do aplicativo.

Variáveis de ambiente

As variáveis de ambiente são cruciais para configurar seu aplicativo. Use um .env arquivo para gerenciar essas variáveis localmente e garantir que elas sejam gerenciadas com segurança em produção com um serviço como o Azure Key Vault.

O exemplo a seguir mostra como criar variáveis para seu aplicativo.

# .env
NODE_ENV=production
PORT=3000
AZURE_COSMOS_DB_ENDPOINT=https://<YOUR_COSMOSDB_RESOURCE_NAME>.documents.azure.com:443/

Contêineres

Um Dockerfile bem configurado é essencial para contêinerizar seu aplicativo:

  • Use um Dockerfile como base: Se vários projetos compartilham uma configuração comum, você pode criar um Dockerfile base que inclua essas etapas comuns. O Dockerfile de cada projeto pode começar com FROM essa imagem base e adicionar configurações específicas do projeto.

  • Parametrização de argumentos de build: você pode usar argumentos de build (ARG) em seu Dockerfile para torná-lo mais flexível. Dessa forma, você pode transmitir valores diferentes para esses argumentos na criação para desenvolvimento, preparo ou produção.

  • Imagem base de Node.js otimizada: verifique se você está usando uma imagem baseNode.js apropriada. Considere usar imagens menores e otimizadas, como as variantes alpinas, para reduzir a sobrecarga.

  • Arquivos Mínimos – Copiar Somente Essenciais: concentre-se em copiar apenas os arquivos necessários para o contêiner. Crie um .dockerignore arquivo para garantir que os arquivos de desenvolvimento não sejam copiados como .env e node_modules. Esse arquivo ajuda a acelerar as compilações em casos em que desenvolvedores copiaram arquivos desnecessários.

  • Separe construção e tempo de execução com construções de múltiplos estágios: Utilize construções de múltiplos estágios para criar uma imagem final enxuta, separando o ambiente de construção do ambiente de tempo de execução.

  • Pré-construir artefatos através de compilação e agrupamento: Pré-construir os artefatos do seu aplicativo (como compilar TypeScript ou agrupar JavaScript) antes de copiá-los para a fase de execução pode minimizar o tamanho da imagem, acelerar a implantação do contêiner e melhorar o desempenho de inicialização a frio. A ordenação cuidadosa de instruções em seu Dockerfile também otimiza os tempos de cache e recompilação.

  • Docker Compose para ambientes de desenvolvimento: o Docker Compose permite que você defina e execute aplicativos Docker de vários contêineres. Essa abordagem de vários contêineres é útil para configurar ambientes de desenvolvimento. Você pode incluir o contexto de construção e o Dockerfile no arquivo de composição. Esse nível de encapsulamento permite que você use dockerfiles diferentes para serviços diferentes quando necessário.

Dockerfile base

Esse arquivo serve como um ponto de partida comum para suas imagens de Node.js. Você pode usá-la com uma FROM diretiva no Dockerfiles que referencia essa imagem base. Use um número de versão ou uma confirmação para dar suporte à versão recente e segura da imagem.

# Dockerfile.base

FROM node:22-alpine

# Set the working directory
WORKDIR /usr/src/app

# Define build arguments with default values
ARG PORT_DEFAULT=3000
ARG ENABLE_DEBUG_DEFAULT=false

# Set environment variables using the build arguments
ENV PORT=${PORT_DEFAULT}
ENV ENABLE_DEBUG=${ENABLE_DEBUG_DEFAULT}

# Copy package manifests and install dependencies
COPY package*.json ./
RUN npm install

# Expose the application and debugging ports
EXPOSE $PORT
EXPOSE 9229

# This image focuses on common steps; project-specific Dockerfiles can extend this.

Quando você passa valores usando o --build-arg sinalizador durante o processo de build, os valores passados substituem os valores padrão codificados em seu Dockerfile.

Por exemplo:

docker build \
  --build-arg PORT_DEFAULT=4000 \
  --build-arg ENABLE_DEBUG_DEFAULT=true \
  --tag <IMAGE>:<TAG> \
  --file Dockerfile.base .

Neste exemplo, as variáveis de ambiente PORT e ENABLE_DEBUG são definidas com valores explícitos, em vez de seus valores padrão.

Convenções de marcação de imagem de contêiner, como o uso de latest, são uma convenção. Saiba mais sobre recomendações para marcação e controle de versão de imagens de contêiner.

Configurar o ambiente de desenvolvimento com o Docker Compose

A configuração de exemplo a seguir usa um Dockerfile de desenvolvimento dedicado (Dockerfile.dev) juntamente com montagens de volume para recarregamento dinâmico e sincronização de origem local.

version: "3.8"
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.base
      args:
        PORT_DEFAULT: ${PORT:-3000}
        ENABLE_DEBUG_DEFAULT: ${ENABLE_DEBUG:-false}
    ports:
      - "${PORT:-3000}:3000"
      - "9229:9229"  # Expose debug port if needed
    volumes:
      - .:/usr/src/app
      - /usr/src/app/node_modules
    environment:
      - NODE_ENV=development
      - PORT=${PORT:-3000}
      - ENABLE_DEBUG=${ENABLE_DEBUG:-false}

Para iniciar o Docker Compose com valores personalizados, você pode exportar as variáveis de ambiente na linha de comando. Por exemplo:

PORT=4000 ENABLE_DEBUG=true docker compose up

Dockerfile de produção

Esse Dockerfile de várias fases compila seu aplicativo e produz uma imagem de runtime lean. Verifique se o arquivo .dockerignore já está no seu código-fonte para que o comando COPY . . não copie arquivos específicos do ambiente de desenvolvimento desnecessários para produção.

# Stage 1: Builder
FROM node:22 AS build

WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .

# Build your project (e.g., compile TypeScript or bundle JavaScript)
RUN npm run build

# Stage 2: Runtime
FROM my-base-image:latest AS runtime

WORKDIR /usr/src/app

# Copy only the compiled output and essential files from the build stage
COPY --from=build /usr/src/app/dist ./dist
COPY --from=build /usr/src/app/package*.json ./

# Install only production dependencies
RUN npm ci --omit=dev

# Copy the entrypoint script for remote debugging
COPY entrypoint.sh /usr/src/app/entrypoint.sh
RUN chmod +x /usr/src/app/entrypoint.sh

# Expose the application port (using the PORT environment variable) and the debug port (9229)
EXPOSE $PORT
EXPOSE 9229

# Use the entrypoint script to conditionally enable debugging
ENTRYPOINT ["sh", "/usr/src/app/entrypoint.sh"]

O script do ponto de entrada permite que você se conecte ao seu aplicativo de contêiner para depuração remota.

Para executar um contêiner da imagem de produção criada com variáveis de ambiente personalizadas, execute:

docker run \
  --env PORT=4000 \
  --env ENABLE_DEBUG=true \
  --publish 4000:4000 \
  --publish 9229:9229 \
  <IMAGE>:<TAG>

Para builds de produção, certifique-se de usar a tag de versão correta, que talvez não seja latest. Convenções de marcação de imagem de contêiner, como o uso de latest, são uma convenção. Saiba mais sobre recomendações para marcação e controle de versão de imagens de contêiner.

Implantação

Para dar suporte à CI/CD (integração contínua/implantação contínua), configure um pipeline de CI/CD usando o GitHub Actions, o Azure DevOps ou outra ferramenta de CI/CD para automatizar o processo de implantação.

# .github/workflows/deploy.yml
name: Deploy to Azure

on:
push:
    branches:
    - main

jobs:
build-and-deploy:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4

    - name: Set up Node.js
      uses: actions/setup-node@v4
      with:
          node-version: '22'

    - name: Install dependencies
      run: npm ci

    - name: Build the app
      run: npm run build

    - name: Log in to Azure
      uses: azure/login@v2
      with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}

    - name: Deploy to Azure Container Apps
      run: |
          az containerapp up \
          --name my-container-app \
          --resource-group my-resource-group \
          --image my-image:my_tag \
          --environment my-environment \
          --cpu 1 --memory 2Gi \
          --env-vars NODE_ENV=production PORT=3000

Ao usar o Registro do Docker, entre no registro e envie suas imagens do Docker por push para um registro de contêiner, como o ACR (Registro de Contêiner do Azure) ou o Hub do Docker.

# Tag the image
docker tag \
  <IMAGE>:<TAG> \
  <AZURE_REGISTRY>.azurecr.io/<IMAGE>:<TAG>

# Push the image
docker push <AZURE_REGISTRY>.azurecr.io/<IMAGE>:<TAG>

Inicializações a frio

Otimize o build de produção incluindo apenas o código e as dependências essenciais. Para garantir que a carga útil seja a mais enxuta possível, use uma das seguintes abordagens:

  • Construções ou empacotadores Docker de várias etapas: Utilize ferramentas de compilação e empacotamento como Webpack ou Rollup para criar o menor payload possível para seu contêiner. Ao compilar e agrupar apenas o que é necessário para a produção, você ajuda a minimizar o tamanho do contêiner e a melhorar os tempos de inicialização a frio.

  • Gerencie as dependências cuidadosamente: Mantenha sua node_modules pasta enxuta, incluindo apenas os pacotes necessários para executar o código de produção. Não liste dependências de desenvolvimento ou teste na seção dependencies do seu package.json. Remova as dependências não utilizados e verifique se o package.json arquivo e o arquivo de bloqueio permanecem consistentes.

Segurança

Considerações de segurança para desenvolvedores JavaScript usando Aplicativos de Contêiner do Azure incluem proteger variáveis de ambiente (como usar o Azure Key Vault), garantir o uso de HTTPS com gerenciamento adequado de certificados, atualizar dependências com auditorias regulares e implementar registro em log e monitoramento robustos para detectar e responder rapidamente às ameaças.

Variáveis de ambiente seguras

Verifique se informações confidenciais, como cadeias de conexão de banco de dados e chaves de API, são armazenadas com segurança. Use o Azure Key Vault para gerenciar segredos e variáveis de ambiente com segurança.

Antes de executar esse comando, substitua os espaços reservados cercados por <> por seus valores.

az keyvault secret set \
  --vault-name <KEY_VAULT_APP> \
  --name "<SECRET_NAME>" \
  --value "<CONNECTION_STRING>"

HTTPS e certificados

Verifique se o aplicativo é fornecido por HTTPS. Os Aplicativos de Contêiner do Azure podem gerenciar certificados para você. Configure seu domínio e certificado personalizados no portal do Azure.

Gerenciamento de Dependências

Atualize regularmente suas dependências para evitar vulnerabilidades de segurança. Use ferramentas como npm audit para verificar se há vulnerabilidades.

npm audit

Tratamento de erros

Implemente um tratamento de erro robusto em seu aplicativo Node.js. Use o middleware no Express ou no Fastify para lidar com erros normalmente.

// src/middleware/errorHandler.ts
import { Request, Response, NextFunction } from 'express';

export function errorHandler(err: any, req: Request, res: Response, next: NextFunction) {
  console.error(err.stack);
  res.status(500).send('Something broke!');
}

Desligamentos normais

Desligar corretamente seu aplicativo é crucial para garantir que as solicitações in-flight sejam concluídas e que os recursos sejam liberados corretamente. Isso ajuda a evitar a perda de dados e mantém uma experiência tranquila do usuário durante implantações ou eventos de escala. O exemplo a seguir demonstra uma abordagem usando Node.js e Express para lidar com sinais de desligamento normalmente.

import express from 'express';
import healthRouter from './health.js';

const app = express();

app.use(healthRouter);

const server = app.listen(process.env.PORT || 3000);

// Graceful shutdown
process.on('SIGTERM', () => {
  console.log('SIGTERM received, shutting down...');
  server.close(() => {
    console.log('Server closed');
    process.exit(0);
  });

  // Force close after 30s
  setTimeout(() => {
    console.error('Could not close connections in time, forcing shutdown');
    process.exit(1);
  }, 30000);
});

Registro em log

Nos Aplicativos de Contêiner do Azure, tanto as chamadas console.log quanto as chamadas console.error são capturadas e registradas automaticamente. Os Aplicativos de Contêiner do Azure capturam os fluxos de saída padrão (stdout) e de erro padrão (stderr) do aplicativo e os disponibilizam no Azure Monitor e no Log Analytics.

Como configurar o registro em log nos Aplicativos de Contêiner do Azure

Para garantir que seus logs sejam capturados e acessíveis corretamente, você precisa definir as configurações de diagnóstico para seu Aplicativo de Contêiner do Azure. A instalação é um processo de duas etapas.

  1. Habilitar configurações de diagnóstico: use a CLI do Azure para habilitar as configurações de diagnóstico para seu Aplicativo de Contêiner do Azure.

    Antes de executar esse comando, substitua os espaços reservados cercados por <> por seus valores.

    az monitor diagnostic-settings create \
    --resource /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP>/providers/Microsoft.Web/containerApps/<CONTAINER_APP_NAME> \
    --name "containerapp-logs" \
    --workspace <LOG_ANALYTICS_WORKSPACE_ID> \
    --logs '[{"category": "ContainerAppConsoleLogs","enabled": true}]'
    
  2. Acesse os logs no portal acessando seu workspace do Log Analytics e consultando os logs.

Como usar as bibliotecas de log

Embora console.log e console.error sejam capturados automaticamente, o uso de uma biblioteca de registro como o Winston fornece mais flexibilidade e controle sobre o log. Essa flexibilidade permite formatar logs, definir níveis de log e emitir logs para vários destinos, como arquivos ou serviços externos de registro de logs.

O exemplo a seguir demonstra como configurar o Winston para armazenar logs de alta fidelidade.

// src/logger.ts
import { createLogger, transports, format } from 'winston';

const logger = createLogger({
  level: 'info',
  format: format.combine(
    format.timestamp(),
    format.json()
  ),
  transports: [
    new transports.Console(),
    new transports.File({ filename: 'app.log' })
  ]
});

export default logger;

Para usar o registrador, use a seguinte sintaxe em seu aplicativo:

import logger from './logger';

logger.info('This is an info message');
logger.error('This is an error message');

Depuração remota

Para habilitar a depuração remota, você pode usar o inspetor interno do Node. Em vez de codificar configurações de depuração em seu Dockerfile CMD, você pode habilitar dinamicamente a depuração remota usando um script de shell como o ponto de entrada do contêiner.

O script a seguir verifica uma variável de ambiente (por exemplo, ENABLE_DEBUG) quando o contêiner é iniciado. Se a variável estiver definida como true, o script será iniciado Node.js no modo de depuração (usando --inspect ou --inspect-brk). Caso contrário, o contêiner iniciará o aplicativo normalmente.

Você pode implementar a depuração remota seguindo estas etapas:

  1. Crie um script de ponto de entrada em um arquivo nomeado entrypoint.sh na raiz do projeto com o seguinte conteúdo:

    #!/bin/sh
    # If ENABLE_DEBUG is set to "true", start Node with debugging enabled
    if [ "$ENABLE_DEBUG" = "true" ]; then
      echo "Debug mode enabled: starting Node with inspector"
      exec node --inspect=0.0.0.0:9229 dist/index.js
    else
      echo "Starting Node without debug mode"
      exec node dist/index.js
    fi
    
  2. Modifique o Dockerfile para copiar o entrypoint.sh script para o contêiner e defina-o como o ponto de entrada. Além disso, exponha a porta de depuração, se necessário:

    # Copy the entrypoint script to the container
    COPY entrypoint.sh /usr/src/app/entrypoint.sh
    
    # Ensure the script is executable
    RUN chmod +x /usr/src/app/entrypoint.sh
    
    # Expose the debugging port (if using debug mode)
    EXPOSE 9229
    
    # Set the shell script as the container’s entrypoint
    ENTRYPOINT ["sh", "/usr/src/app/entrypoint.sh"]
    
  3. Acione o modo de depuração definindo a variável de ambiente ENABLE_DEBUG para true. Por exemplo, usando a CLI do Azure:

    az containerapp update \
      --name <CONTAINER_APP> \
      --env-vars ENABLE_DEBUG=true
    

Antes de executar esse comando, substitua os espaços reservados cercados por <> por seus valores.

Essa abordagem oferece uma solução flexível que permite reiniciar o contêiner no modo de depuração atualizando uma variável de ambiente na inicialização. Ele evita a necessidade de criar uma nova revisão com configurações diferentes CMD sempre que você precisar depurar seu aplicativo.

Considerações sobre manutenção e desempenho

Para manter e otimizar o desempenho do aplicativo ao longo do tempo, certifique-se de gerenciar com eficiência as alterações de variável de ambiente, monitorar seus recursos, manter suas dependências up-to-date, configurar o dimensionamento corretamente e configurar alertas de monitoramento.

Alterações de variável de ambiente

Como cada alteração nas variáveis de ambiente requer uma nova revisão implantada, faça todas as alterações nos segredos do aplicativo de uma só vez. Quando as alterações forem concluídas, vincule os segredos às variáveis de ambiente da revisão. Essa abordagem minimiza o número de revisões e ajuda a manter um histórico de implantação limpo.

Alocação de recursos

Monitore e ajuste a alocação de CPU e memória para seus contêineres com base nos padrões de desempenho e uso do aplicativo. O excesso de provisionamento pode levar a custos desnecessários, enquanto o subprovisionamento pode causar problemas de desempenho.

Atualizações de dependência

Atualize regularmente suas dependências para se beneficiar de melhorias de desempenho e patches de segurança. Use ferramentas como npm-check-updates para automatizar esse processo.

npm install -g npm-check-updates
ncu -u
npm install

Scaling

Configure o dimensionamento automático com base na carga do aplicativo. Os Aplicativos de Contêiner do Azure dão suporte ao dimensionamento horizontal, que ajusta automaticamente o número de instâncias de contêiner com base no uso de CPU ou memória.

O exemplo a seguir demonstra como definir uma regra de escala baseada em CPU. Antes de executar esse comando, substitua os espaços reservados cercados por <> por seus valores.

az containerapp revision set-scale \
  --name <CONTAINER_APP> \
  --resource-group <RESOURCE_GROUP> \
  --min-replicas 1 \
  --max-replicas 10 \
  --cpu 80

Alertas de monitorização

Configure o monitoramento e os alertas para acompanhar o desempenho e a integridade do aplicativo. Use o Azure Monitor para criar alertas para métricas específicas, como uso da CPU, uso de memória e tempos de resposta.

Antes de executar esse comando, substitua os espaços reservados cercados por <> por seus valores.

az monitor metrics alert create \
  --name "HighCPUUsage" \
  --resource-group <RESOURCE_GROUP> \
  --scopes /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP>/providers/Microsoft.ContainerInstance/containerGroups/<CONTAINER_GROUP> \
  --condition "avg Percentage CPU > 80" \
  --description "Alert when CPU usage is above 80%"

Gestão de recursos

Use a extensão aplicativos de contêiner do Azure para Visual Studio Code para criar, editar e implantar aplicativos em contêineres rapidamente diretamente do Visual Studio Code.

Resolução de problemas

Quando seu aplicativo encontra problemas de tempo de execução nos Aplicativos de Contêiner do Azure, você pode usar log, depuração remota e alertas de verificação de integridade para localizar e resolver o problema.

Registro em log

Habilite e configure o registro para capturar logs de aplicação. Use o Azure Monitor e o Log Analytics para coletar e analisar logs. Antes de executar esses comandos, substitua os espaços reservados cercados por <> com seus valores.

  1. Crie um novo espaço de trabalho.

    az monitor log-analytics workspace create \
        --resource-group <RESOURCE_GROUP> \
        --workspace-name <WORKSPACE_NAME>
    
  2. Em seguida, crie uma nova configuração de workspace.

    az monitor diagnostic-settings create \
        --resource <CONTAINER_APP> \
        --workspace <WORKSPACE_NAME> \
        --logs '[{"category": "ContainerAppConsoleLogs","enabled": true}]'
    

Resolução de Erros

Você usa ferramentas de depuração remota para se conectar ao contêiner em execução. Verifique se o Dockerfile expõe as portas necessárias para depuração.

# Expose the debugging port
EXPOSE 9229

Exames de saúde

Configure verificações de integridade para monitorar a integridade do aplicativo. Esse recurso garante que os Aplicativos de Contêiner do Azure possam reiniciar o contêiner se ele não responder.

# Azure Container Apps YAML configuration
properties:
configuration:
    livenessProbe:
    httpGet:
        path: /health
        port: 3000
    initialDelaySeconds: 30
    periodSeconds: 10