Importante

Você está vendo a versão anterior da nova experiência da Alura que estamos preparando para você. Em breve, ela ganha uma identidade visual novinha totalmente pensada em potencializar seus estudos!

14
respostas

docker compose com mysql

Boa noite. Estou criando um projeto com spring boot e mysql. Estou tendo um problema pois o camando depends_on não está funcionando visto que os containers que eu crio no docker compose sempre startam no mesmo momento, assim quando a aplicação sobe o mysql ainda não terminou de inciar. Há alguma forma de contornar esse problema?

14 respostas

Oi Henrique, tudo bem? Você poderia disponibilizar seu compose pra gente dá uma olhada e entender melhor como ele está estruturado?

Bom dia Wanderson. Desculpe a demora. Então, esse problema eu consegui resolver. Agora estou com outro. Estou tentando fazer o load balance com uma aplicação angular + spring boot porém sem sucesso. Quando executo o docker compose os serviços iniciam corretamente, eu consigo acessar a plicação porém ele utiliza apenas o serviço node1. É como se a configuração

upstream node-upstream {
              least_conn;

              server node1:8080;
              server node2:8080;
              server node3:8080;

              keepalive 64;
        }

não funcionasse.

Seguem meus arquivos de configuração

nginx.conf

worker_processes 4;

events { worker_connections 1024; }

http {    

      proxy_cache_path          /var/cache/nginx levels=1:2 keys_zone=one:8m max_size=3000m inactive=600m;
        proxy_temp_path         /var/tmp;
        include                 mime.types;
        default_type            application/octet-stream;
        sendfile                on;
        keepalive_timeout       65;

        gzip                    on;
        gzip_comp_level         6;
        gzip_vary               on;
        gzip_min_length         1000;
        gzip_proxied            any;
        gzip_types              text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
        gzip_buffers            16 8k;

        upstream node-upstream {
              least_conn;

              server node1:8080;
              server node2:8080;
              server node3:8080;

              keepalive 64;
        }

        server {
              listen 4200; 

              server_name localhost;  
              root  /var/www/public/dist;  
              index index.html index.htm; 
              # Handle static files              

              location localhost:8080/ {
                  proxy_pass            http://node-upstream;

              }

              #return  301 https://$server_name$request_uri;
        }


}

docker-compose.yml

version: '3'

networks: 
  production-network:    
    #driver: bridge
    external:
      name: minha-rede

services: 
  batistagases_bd:
    container_name: batistagases_bd
    environment:       
      MYSQL_USER: root      
      MYSQL_ROOT_PASSWORD: admin      
    image: mysql
    ports: 
      - "3307:3307"
    networks: 
      - production-network    

  nginx:
    build:
      dockerfile: nginx.dockerfile
      context: .
    image: batistagases/nginx
    container_name: nginx
    ports: 
      - "4200:4200"
    networks: 
      - production-network    
    depends_on:   
      - batistagases_bd    
      - node1
      - node2
      - node3


  node1:
    build:
      dockerfile: /api.dockerfile
      context: /projetos-java/algaworks/batistagases-api
    image: batistagases-api
    container_name: node1
    ports:
      - "8080:8080"    
    networks: 
      - production-network    
    depends_on:   
      - batistagases_bd
    command: ./wait-for-it.sh a java -jar batistagases-1.0.0.jar

  node2:
    build:
      dockerfile: /api.dockerfile
      context: /projetos-java/algaworks/batistagases-api
    image: batistagases-api
    container_name: node2
    ports:
      - "8081:8080"    
    networks: 
      - production-network    
    depends_on:   
      - batistagases_bd
      - node1
    command: ./wait-for-it.sh a java -jar batistagases-1.0.0.jar

  node3:
    build:
      dockerfile: /api.dockerfile
      context: /projetos-java/algaworks/batistagases-api
    image: batistagases-api
    container_name: node3
    ports:
      - "8082:8080"    
    networks: 
      - production-network    
    depends_on:   
      - batistagases_bd
      - node2
    command: ./wait-for-it.sh a java -jar batistagases-1.0.0.jar



Não cara, não usa nginx usa o proprio docker para fazer o load balance só declarar no docker compose a quantidade de replicadas que ele faz isso sozinho.

Usando Swarm ou docker compose

só adicionar a sessão de replicas.

 backend:
    build:
      dockerfile: /api.dockerfile
      context: /projetos-java/algaworks/batistagases-api
    image: batistagases-api
    container_name: node1
    deploy:
        replicas: 3
    ports:
      - "8080:8080"    
    networks: 
      - production-network    
    depends_on:   
      - batistagases_bd
    command: ./wait-for-it.sh a java -jar batistagases-1.0.0.jar

Usando dessa forma o load balance é feito automaticamente sem necessidade de configuração e sem o problema do nginx onde você pode ter downtime se algum container cair.

E aí Vinicis, blz? Então, fiz o que vc recomendou mas ele só criou um container (o node 1).

Eu fiz o seguinte: exclui o node2 e node3 do arquivo docker-compose.yml e adicionei o deply: replicas:3.

No arquivo do nginx.conf eu deixei apenas o node1

upstream node-upstream {
              least_conn;

              server node1:8080;
              #server node2:8080;
              #server node3:8080;

              keepalive 64;
        }

Teria alguma outra configuração a fazer?

Certo, mas você não vai mais precisar do Nginx usando dessa forma, e estranho isso de ter criado apenas um container, você está subindo como uma Stack Swarm ou com Docker-Compose up -d ?

Vinicius, então, o deploy com replicas, só funciona com swarm ou outra stack de production, a documentação mesmo comenta sobre o comando ser ignorado pelo compose up e compose run.

https://docs.docker.com/compose/compose-file/#deploy

Henrique, olha o seguinte, no seu upstream todos os serviços estão configurados com a porta 8080:

upstream node-upstream {
              least_conn;

              server node1:8080;
              server node2:8080;
              server node3:8080;

              keepalive 64;
}

Mas no seu docker-compose, os serviços nodes estão com portas diferentes abertas: 8080, 8180, 8280 no Host.

Considerando isso, apenas um dos containers vai conseguir responder a requisição, que é o primeiro container.

Faz sentido?

Bom dia Wanderson. Então, eu já tentei de várias maneiras. Essas portas abertas já foi uma outra tentativa. O que acontece: considerando o meu docker-compose que publiquei, já coloquei as portas apenas assim

ports:
      - "8080"

para todos os nodes (node1, node2, node3) e no arquivo do nginx coloquei dessa forma

          server node1:8080;
              server node2:8080;
              server node3:8080;

pois como o nginx iria redirecionar as requisições, cada container estava apontando para a sua própria porta 8080 sendo que eles estão na mesma rede. Porém não funcionou. As requisições eram enviadas apenas para o node1. O que parece é que o arquivo nginx.conf não está executando o redirecionamento das requisições. Teria alguma idéia do que pode ser?

Oi Henrique, me aprofundando melhor na documentação, entendi que você está usando uma outra estratégia de load balance que a padrão do Nginx. A Least Connected

O que acontece nesse Least Connected? Ele só vai redirecionar a requisição para uma outra instância, quando a instância atual estiver demorando pra responder ou sobrecarregando.

Essa estratégia é habilitada quando você faz uso do least_conn;.

Nesse caso, se você estiver fazendo uma requisição por vez e essa requisição é respondida rapidamente, todas as requisições irão ser atendidas pelo node1.

Se você remover a configuração do least_conn, o Nginx, volta a trabalhar no modelo round-robin e assim, para cada requisição, ele deve mandar para um node diferente.

Testa isso pra gente e confirma se está correto por favor?

Boa noite Wanderson. Obrigado pela resposta mas continua como se só houvesse um servidor. O pior, acho que a configuração do nginx.conf não está sendo respeitada, ou seja, a configuração

server node1:8080; server node2:8080; server node3:8080;

não está surtindo efeito. Digo isso porque na aplicação angular, a url do servidor está localhost:8080 e se eu modificar o mapeamento dos nods para

server node1:8081; server node2:8082; server node3:8083;

continua chamando apenas o node1 pois foi ele que ficou com a porta 8080 no mapeamento feito no arquivo docker-compose.yml . Realmente não sei mais o que tentar. Tem alguma dica? Já passou por isso?

Como você está testando isso Henrique? Acho que você não pode disponibilizar o projeto para que eu teste, estou certo? Se puder, me disponibiliza no GitHub ou coisa assim para eu ver isso de perto por favor.

Outra coisa que não entendi é a dependência do node2 pro node 1 e do node3 para o node2, se os 3 são a mesma coisa, eles não deveriam ser dependentes entre si.

Olá Wanderson. Vou tentar colocar no git para vc poder ver. As dependências foi só para teste para saber se a diretiva depends_on funcionava. Mas não funciona corretamente, não da forma que eu esperava pois era para subir toda a aplicação node1 e depois a nod2 etc... mas não funciona pois para subir a aplicação eu primeiro tenho que subir o container do mysql e para isso eu tive que criar o script ./wait-for-it.sh a java -jar batistagases-1.0.0.jar

Wanderson, segue o link do projeto. Contem o jar, o api.dockfile para gerar a imagem dos nodes (node1, node2 e node3 ) , contem o arquivo wait-for-it.sh para aguardar o mysql subir para depois subir os nodes e contem o client em angular. Qualquer dúvida é só falar.

O login e senha para acessar a aplicação. login: admin@batistagases.com senha: admin

https://www.dropbox.com/s/s4a2qdwiqah8xzv/projeto.zip?dl=0

Então Wanderson, conseguiu acessar a aplicação?

Oi Henrique, tudo bem? Estou bem confuso sobre como o projeto foi arquitetado, você adicionar esse script wait-for-it.sh, mas ele não veio com o projeto e há várias referências absolutas que dizem respeito ao seu sistema operacional e usuário, o que torna tudo mais difícil de entender do meu lado.

Aqui, do jeito que está, não vai funcionar. Aqui precisei ajustar algumas coisas e no fim das contas, o que descobri é que na sua aplicação você usa o environment para pegar a URL correta para fazer a requisição. O que está 100% correto.

O problema é que o endereço configurado no environment é localhost:8080, ou seja, depois do Angular ser carregado pelo NGINX, ele vai fazer requisições sempre para o mesmo endereço configurado no código.

Esse deve ser o problema.

Outro ponto que observei é que o location também vai redirect para o localhost:8080.

Então o que tá acontecendo é: você faz requisição para o localhost:8080 (direto no código), essa requisição nem chega a passar pelo NGINX, indo direto para o node1.

E quando você faz requisição para o NGINX, pela porta 4200, você faz um redirect com o location para o localhost:8080, que ao meu ver, também chama o node1.

No fundo, o problema não é do compose, mas sim de arquitetura e configuração mesmo. No fim, não acho que o NGINX deveria informa a porta do redirect, o código do environment não deveria apontar para um node específico e pessoalmente, se fosse para usar o NGINX como load balancer, eu não colocaria os assets lá, por que o assets são gerados por um build próprio.