Implantação de Aplicações Frontend em Docker: Nginx, Balanceamento de Carga e Alta Disponibilidade

Este guia detalha o processo de empacotamento e implantação de uma aplicação frontend separada em um ambiente Docker, utilizando Nginx para servir os arquivos estáticos, configurando um balanceamento de carga e garantindo alta disponibilidade com Keepalived.

Empacotamento da Aplicação Frontend

O primeiro passo para implantar o projeto frontend é gerar os arquivos estáticos de produção. Em um projeto baseado em Node.js e ferramentas de build modernas (como Vue CLI, React Scripts ou Angular CLI), isso é tipicamente feito com um comando de build:

npm run build

Este comando criará uma pasta de saída (geralmente dist ou build) contendo os arquivos HTML, CSS, JavaScript e outros ativos compilados e otimizados para produção. Para este exemplo, assumiremos que a pasta de saída é dist.

Preparação dos Arquivos Estáticos no Host

Após a geração dos arquivos de produção, é necessário copiá-los para os diretórios no sistema host que serão montados dentro dos contêineres Docker. Para este exemplo, consideraremos três instâncias do servidor web. Você pode copiar os arquivos da seguinte forma:

# Crie e copie os arquivos para a primeira instância
sudo mkdir -p /srv/aplicacao/frontend/instancia-1
sudo cp -R dist/* /srv/aplicacao/frontend/instancia-1/

# Crie e copie os arquivos para a segunda instância
sudo mkdir -p /srv/aplicacao/frontend/instancia-2
sudo cp -R dist/* /srv/aplicacao/frontend/instancia-2/

# Crie e copie os arquivos para a terceira instância
sudo mkdir -p /srv/aplicacao/frontend/instancia-3
sudo cp -R dist/* /srv/aplicacao/frontend/instancia-3/

Garanta que esses diretórios no host contenham os arquivos estáticos completos da aplicação frontend.

Implantação dos Servidores Frontend com Nginx e Docker

Para hospedar os arquivos estáticos da aplicação frontend, serão configuradas três instâncias do Nginx, cada uma rodando em um contêiner Docker separado e expondo a aplicação em uma porta distinta. Primeiro, crie os arquivos de configuração do Nginx no seu host. Estes arquivos serão montados dentro dos contêineres.

Exemplo de Configuração Nginx para um Nó Front end (/srv/aplicacao/config/nginx-frontend-1.conf):

user  nginx;
worker_processes  auto; # Ajustado para usar todos os núcleos disponíveis

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    keepalive_timeout  65;
    gzip  on; # Habilitar compressão GZIP para melhor performance

    server {
        listen 6501; # Porta específica para esta instância
        server_name  192.168.99.104; # Ou o IP do seu host

        location  /  {
            root  /var/www/frontend-app; # Diretório onde os arquivos frontend serão montados
            index  index.html;
            try_files $uri $uri/ /index.html; # Configuração essencial para SPAs (Single Page Applications)
        }
    }
}

Crie arquivos de configuração semelhantes para as instâncias 2 e 3, ajustando a porta de escuta (listen) para 6502 e 6503, respectivamente, e os caminhos de montagem para os dados do frontend.

Comandos Docker para Iniciar os Nodos Frontend:

Os contêineres serão iniciados com volumes montados para as configurações do Nginx e os arquivos estáticos da aplicação. Usaremos --net=host para simplificar a rede, mas em ambientes de produção, redes bridge Docker personalizadas são mais recomendadas.

# Iniciar a primeira instância frontend (app-web-1)
docker run -d --name app-web-1 \
  -v /srv/aplicacao/config/nginx-frontend-1.conf:/etc/nginx/nginx.conf \
  -v /srv/aplicacao/frontend/instancia-1:/var/www/frontend-app \
  --net=host \
  --privileged \
  nginx

# Iniciar a segunda instância frontend (app-web-2)
docker run -d --name app-web-2 \
  -v /srv/aplicacao/config/nginx-frontend-2.conf:/etc/nginx/nginx.conf \
  -v /srv/aplicacao/frontend/instancia-2:/var/www/frontend-app \
  --net=host \
  --privileged \
  nginx

# Iniciar a terceira instância frontend (app-web-3)
docker run -d --name app-web-3 \
  -v /srv/aplicacao/config/nginx-frontend-3.conf:/etc/nginx/nginx.conf \
  -v /srv/aplicacao/frontend/instancia-3:/var/www/frontend-app \
  --net=host \
  --privileged \
  nginx

Certifique-se de que os arquivos nginx-frontend-2.conf e nginx-frontend-3.conf existam no host e estejam configurados com as portas e caminhos corretos, conforme mencionado anteriormente.

Configuração do Balanceamento de Carga com Nginx

Para distribuir o tráfego entre as três instâncias do servidor frontend, será configurado um balanceador de carga Nginx. Serão criadas duas instâncias de balanceamento de carga (para alta disponibilidade, que será configurada posteriormente), cada uma com sua própria configuração.

Exemplo de Configuração Nginx para o Balanceador de Carga (/srv/aplicacao/config/nginx-lb-1.conf):

user  nginx;
worker_processes  auto; # Ajustado para usar todos os núcleos disponíveis

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    keepalive_timeout  65;
    gzip  on;

    # Configurações de proxy são importantes para balanceadores de carga
    proxy_redirect          off;
    proxy_set_header        Host $host;
    proxy_set_header        X-Real-IP $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    client_max_body_size    10m;
    client_body_buffer_size   128k;
    proxy_connect_timeout   5s;
    proxy_send_timeout      5s;
    proxy_read_timeout      5s;
    proxy_buffer_size        4k;
    proxy_buffers           4 32k;
    proxy_busy_buffers_size  64k;
    proxy_temp_file_write_size 64k;

    # Bloco upstream define os servidores backend do frontend
    upstream frontend_pool {
        server 192.168.99.104:6501;
        server 192.168.99.104:6502;
        server 192.168.99.104:6503;
    }

    server {
        listen       6601; # Porta para o primeiro balanceador de carga
        server_name  192.168.99.104; # Ou o IP do seu host

        location / {
            proxy_pass   http://frontend_pool; # Encaminha para o pool de servidores frontend
            index  index.html index.htm;
        }
    }
}

Crie um segundo arquivo de configuração para o balanceador de carga 2 (ex: /srv/aplicacao/config/nginx-lb-2.conf), ajustando a porta de escuta para 6602.

Comandos Docker para Iniciar os Balanceadores de Carga Nginx:

# Iniciar a primeira instância do balanceador de carga (lb-node-1)
docker run -d --name lb-node-1 \
  -v /srv/aplicacao/config/nginx-lb-1.conf:/etc/nginx/nginx.conf \
  --net=host \
  --privileged \
  nginx

# Iniciar a segunda instância do balanceador de carga (lb-node-2)
docker run -d --name lb-node-2 \
  -v /srv/aplicacao/config/nginx-lb-2.conf:/etc/nginx/nginx.conf \
  --net=host \
  --privileged \
  nginx

Configuração de Alta Disponibilidade (HA) com Keepalived

Para garantir que o serviço de balanceamento de carga esteja sempre disponível, configuraremos o Keepalived em dois dos contêineres Nginx que atuam como balanceadores de carga (lb-node-1 e lb-node-2). O Keepalived usa o protocolo VRRP (Virtual Router Redundancy Protocol) para atribuir um IP virtual (VIP) a um dos servidores em um determinado momento, alternando para um servidor de backup em caso de falha do primário.

Instalação e Configuração do Keepalived nos Nodos de Balanceamento de Carga:

Primeiro, acesse cada um dos contêineres de balanceamento de carga (lb-node-1 e lb-node-2) para instalar o Keepalived e configurar seus respectivos arquivos. Uma abordagem mais robusta para produção seria montar os arquivos de configuração do Keepalived como volumes, mas para este guia, editaremos diretamente dentro dos contêineres conforme a prática original.

# Exemplo para 'lb-node-1':
docker exec -it lb-node-1 bash
apt-get update
apt-get install -y vim keepalived # '-y' para aceitar automaticamente a instalação
exit # Sair do contêiner

# Exemplo para 'lb-node-2':
docker exec -it lb-node-2 bash
apt-get update
apt-get install -y vim keepalived
exit # Sair do contêiner

Configuração do Keepalived para o Nó MASTER (/etc/keepalived/keepalived.conf dentro de lb-node-1):

Edite o arquivo /etc/keepalived/keepalived.conf dentro do contêiner lb-node-1:

vrrp_instance VI_FRONTEND_LB {
    state MASTER
    interface eth0 # Verifique a interface de rede do seu contêiner (pode ser ens33, eth0, etc.)
    virtual_router_id 101 # ID único para este grupo VRRP
    priority 100 # Prioridade mais alta para o MASTER
    advert_int 1 # Intervalo de anúncio em segundos

    authentication {
        auth_type PASS
        auth_pass senha_secreta_ha # Senha para autenticação entre os nodos Keepalived
    }

    virtual_ipaddress {
        192.168.99.150/24 # O IP Virtual que será atribuído ao MASTER
    }
}

virtual_server 192.168.99.150 6701 { # O IP virtual e a porta que os clientes acessarão
    delay_loop 3
    lb_algo rr # Round-robin para balanceamento entre os servidores reais
    lb_kind NAT # NAT para encaminhamento de pacotes
    persistence_timeout 50
    protocol TCP

    real_server 192.168.99.104 6601 { # Primeiro balanceador de carga Nginx
        weight 100 # Peso para este servidor
    }
}

Configuração do Keepalived para o Nó BACKUP (/etc/keepalived/keepalived.conf dentro de lb-node-2):

Edite o arquivo /etc/keepalived/keepalived.conf dentro do contêiner lb-node-2:

vrrp_instance VI_FRONTEND_LB {
    state BACKUP # Este nó será o BACKUP
    interface eth0 # Verifique a interface de rede do seu contêiner
    virtual_router_id 101 # Mesmo ID do MASTER
    priority 90 # Prioridade mais baixa para o BACKUP
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass senha_secreta_ha # Mesma senha do MASTER
    }

    virtual_ipaddress {
        192.168.99.150/24 # Mesmo IP Virtual do MASTER
    }
}

virtual_server 192.168.99.150 6701 { # O IP virtual e a porta que os clientes acessarão
    delay_loop 3
    lb_algo rr
    lb_kind NAT
    persistence_timeout 50
    protocol TCP

    real_server 192.168.99.104 6602 { # Segundo balanceador de carga Nginx
        weight 100
    }
}

Após salvar as configurações em ambos os contêineres, inicie o serviço Keepalived em cada um (acessando o contêiner via docker exec):

# Em 'lb-node-1' e 'lb-node-2' (após entrar nos contêineres):
service keepalived start

Agora, a aplicação frontend estará acessível através do IP virtual 192.168.99.150 na porta 6701. O Keepalived garantirá a alta disponibilidade do serviço de balanceamento de carga Nginx, alternando automaticamente para o nó de backup caso o primário falhe.

Tags: Docker nginx Keepalived frontend Deployment

Publicado em 6-8 21:30 por Thomas