Compartilhar via


Tutorial: Criar aplicativos de vários contêineres com o MySQL e o Docker Compose

Este artigo descreve como criar aplicativos de vários contêineres com MySQL e do Docker Compose. Um aplicativo com vários contêineres permite que você dedique contêineres para tarefas especializadas, para que cada contêiner possa se concentrar em uma única tarefa. Há muitas vantagens em usar aplicativos de vários contêineres:

  • Contêineres separados permitem que você gerencie APIs e recursos de front-end de forma diferente dos bancos de dados.
  • Vários contêineres permitem que você controle a versão e atualize as versões isoladamente.
  • Os bancos de dados locais podem ser mantidos em contêineres e serviços gerenciados usados para bancos de dados em produção.
  • Aplicativos de vários contêineres são mais eficientes do que executar vários processos com um gerenciador de processos, o que adiciona complexidade à inicialização/desligamento do contêiner.

Neste tutorial, você:

  • Iniciar o MySQL
  • Executar seu aplicativo de vários contêineres com o MySQL
  • Criar um arquivo do Docker Compose para seu aplicativo
  • Executar o stack de aplicativos com o Docker Compose

Pré-requisitos

  • Este artigo faz parte de uma série de tutoriais. Os procedimentos se baseiam em um exemplo estabelecido que requer o Docker Desktop para contêineres do Linux.

    A abordagem recomendada é concluir o primeiro tutorial, Criar um Aplicativo de Contêiner, incluindo satisfazer os pré-requisitos, e também o tutorial, Persistir Dados em Seu Aplicativo. Depois de trabalhar nesses tutoriais, continue com os procedimentos descritos neste artigo.

  • O exemplo neste artigo usa Docker Compose.

    O Docker Desktop para Windows inclui o Docker Compose.

    Execute o seguinte comando para verificar a instalação do Docker:

    docker-compose version
    

Visual Studio Code

Esta série de tutoriais descreve os procedimentos do VS Code (Visual Studio Code). Examine as seguintes considerações para trabalhar nesse ambiente:

  • Use o menu à esquerda para alternar entre o EXPLORADOR DE CONTÊINER ou a visualização EXPLORER (arquivo e pasta):

    Captura de tela que mostra o Gerenciador de Contêineres e o modo de exibição explorador de arquivos/pastas no Visual Studio Code.

  • Abra uma janela de linha de comando no VS Code selecionando Terminal>Novo Terminal. Você também pode usar o atalho de teclado Ctrl+Shift+` (tique atrás).

  • A menos que especificado de outra forma, execute comandos em uma janela bash. A maioria dos comandos rotulados para Bash são executados em uma janela bash ou na janela de linha de comando do VS Code.

Iniciar o sistema de gerenciamento de banco de dados MySQL

Por padrão, os contêineres são executados isoladamente. Um contêiner não está ciente de outros processos ou outros contêineres no mesmo computador.

Para habilitar a comunicação entre contêineres, eles precisam ser anexados à mesma rede. Vários contêineres na mesma rede podem compartilhar dados e processar informações uns com os outros.

Há duas maneiras de anexar um contêiner a uma rede. Você pode anexar um contêiner a uma rede durante a criação ou anexar um contêiner existente a uma rede posteriormente.

Neste exemplo, você cria a rede e anexa o contêiner MySQL na inicialização.

  1. Criar uma rede chamada todo-app:

    docker network create todo-app
    
  2. Inicie um contêiner MySQL chamado todo-mysql-data e anexe-o à rede todo-app. O comando cria um alias de rede mysql para o banco de dados MySQL todos.

    Ao executar o comando, insira sua senha raiz do MySQL para o espaço reservado <your-password>.

    docker run -d --network todo-app --network-alias mysql -v todo-mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=<your-password> -e MYSQL_DATABASE=todos mysql:lts
    

    Esse comando também define as variáveis de ambiente MYSQL_ROOT_PASSWORD e MYSQL_DATABASE. Para obter mais informações, confira Listagem do Docker Hub do MySQL.

    Aviso

    Este tutorial ilustra as credenciais de senha para autenticar com um banco de dados MySQL, que não é o método mais seguro. Consulte a documentação do MySQL para saber mais sobre métodos mais seguros de autenticação.

  3. Obtenha a ID do contêiner para uso na próxima etapa.

    docker ps
    
  4. Confirme se você pode se conectar ao contêiner na rede mysql.

    Ao executar o comando, digite o ID do contêiner para o espaço reservado <mysql-container-id>.

    docker exec -it <mysql-container-id> mysql -p
    

    No prompt, insira a senha fornecida quando você criou o contêiner de todo-mysql-data.

  5. No shell do MySQL, liste os bancos de dados e verifique se você vê o banco de dados todos.

    SHOW DATABASES;
    

    Você deverá ver a seguinte saída:

    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    | sys                |
    | todos              |
    +--------------------+
    5 rows in set (0.00 sec)
    
  6. Para encerrar a conexão e retornar ao prompt de linha de comando, insira sair.

Executar seu aplicativo com o MySQL

O aplicativo todo dá suporte à definição de determinadas variáveis de ambiente para especificar as configurações de conexão do MySQL. A tabela a seguir lista as variáveis com suporte e os valores usados no exemplo apresentado nesta seção.

Nome da variável Valor de exemplo Descrição
MYSQL_HOST mysql O nome do host para o servidor MySQL.
MYSQL_USER root O nome de usuário a ser usado para a conexão.
MYSQL_PASSWORD <your-password> A senha a ser usada para a conexão. Neste exemplo, substitua sua senha raiz pelo espaço reservado <your-password>.
MYSQL_DATABASE todos O nome do banco de dados a ser usado após a conexão ser estabelecida.

Aviso

Usar variáveis de ambiente para definir as configurações de conexão é aceitável para desenvolvimento, mas essa prática não é recomendada para executar aplicativos em produção. Para mais informações, veja Por que você não deve usar variáveis de ambiente para dados secretos.

Um mecanismo mais seguro é usar o suporte secreto fornecido pela estrutura de orquestração de contêiner. Na maioria dos casos, esses segredos são montados como arquivos no contêiner em execução.

No exemplo a seguir, você inicia seu aplicativo e conecta o contêiner do aplicativo ao contêiner do MySQL.

  1. Execute o comando docker a seguir. Observe como o comando especifica as variáveis de ambiente descritas anteriormente.

    Ao executar o comando, lembre-se de inserir sua senha raiz do MySQL para o espaço reservado <your-password>.

    docker run -dp 3000:3000 -w /app -v ${PWD}:/app --network todo-app -e MYSQL_HOST=mysql -e MYSQL_USER=root -e MYSQL_PASSWORD=<your-password> -e MYSQL_DB=todos node:lts-alpine sh -c "yarn install && yarn run dev"
    
  2. No editor do VS Code, abra o Gerenciador de Contêineres, clique com o botão direito do mouse no contêiner do aplicativo e selecione Exibir Logs.

    Você também pode exibir os logs da linha de comando usando o comando docker logs.

  3. Examine a saída do log. Observe a linha que indica que o aplicativo está conectado ao banco de dados MySQL: Connected to mysql db at host mysql.

    # Previous log messages omitted
    $ nodemon src/index.js
    [nodemon] 1.19.2
    [nodemon] to restart at any time, enter `rs`
    [nodemon] watching dir(s): *.*
    [nodemon] starting `node src/index.js`
    Connected to mysql db at host mysql
    Listening on port 3000
    
  4. No navegador da Internet, acesse seu aplicativo em execução: http://localhost:3000.

  5. Em seu aplicativo em execução, adicione alguns itens à sua lista de tarefas pendentes.

  6. Conecte-se ao banco de dados de contêiner MySQL na rede mysql para que você possa verificar o banco de dados.

    Ao executar o comando, digite o ID do contêiner para o espaço reservado <mysql-container-id>.

    docker exec -ti <mysql-container-id> mysql -p todos
    

    No prompt, insira a senha fornecida quando você criou o contêiner de todo-mysql-data.

  7. No shell do MySQL, verifique se os todo_items adicionados foram gravados no banco de dados todos.

    use todos;
    select * from todo_items;
    

    Você deverá ver uma saída semelhante ao exemplo a seguir:

    +--------------------------------------+--------------------+-----------+
    | id                                   | name               | completed |
    +--------------------------------------+--------------------+-----------+
    | c906ff08-60e6-44e6-8f49-ed56a0853e85 | Do amazing things! |         0 |
    | 2912a79e-8486-4bc3-a4c5-460793a575ab | Be awesome!        |         0 |
    +--------------------------------------+--------------------+-----------+
    

Agora você tem um aplicativo que armazena dados em um banco de dados externo em execução em um contêiner separado. Este procedimento demonstra como você pode habilitar a comunicação entre contêineres usando a rede.

Criar arquivo do Docker Compose

O Docker Compose ajuda você a definir e compartilhar aplicativos de vários contêineres. Um arquivo do Docker Compose pode especificar todos os serviços necessários para que você possa iniciar ou encerrar todos os processos relacionados com um único comando. Você pode definir sua pilha de aplicativos em um arquivo Docker Compose na raiz do repositório de projeto e manter sua configuração sob controle de versão. Essa abordagem permite que outras pessoas contribuam para seu projeto quando clonam seu repositório.

No exemplo a seguir, você configura um arquivo do Docker Compose para seu aplicativo de vários contêineres todo.

  1. Na raiz do projeto de aplicativo todo, crie um arquivo do Docker Compose chamado docker-compose.yml.

    Nota

    Por padrão, a versão do esquema YAML é definida como a versão mais recente. Ao executar seu aplicativo, se a versão do esquema estiver obsoleta, você receberá uma mensagem de aviso. Para examinar as versões de esquema atuais e uma matriz de compatibilidade, confira Visão Geral (arquivo Compose).

  2. No arquivo docker-compose.yml, adicione os seguintes elementos. Especifique o aplicativo name e inicie a lista de services (ou contêineres) que você deseja executar como parte do aplicativo.

    name: todo
    
    services:
    

    A lista de serviços é exclusiva para seu aplicativo. Exemplos incluem app, web, db, proxye assim por diante. Você estende a definição para o elemento services em uma etapa posterior.

    Dica

    O recuo é significativo em arquivos .yml. Se você estiver editando no VS Code, o Intellisense indicará erros no formato ou sintaxe.

  3. Retorne à definição de services no arquivo docker-compose.yml. Estenda a definição adicionando uma entrada para definir o elemento de serviço app, que inclui a imagem do contêiner.

    services:
      app:
        image: node:lts-alpine
    

    Você pode escolher qualquer nome para o serviço. O nome se torna automaticamente um alias de rede, o que é útil quando você define o serviço MySQL.

  4. Estenda a definição do elemento app para especificar um command a ser executado.

      app:
        image: node:lts-alpine
        command: sh -c "yarn install && yarn run dev"
    
  5. Defina o ports a ser usado com o serviço app. Observe que essas portas correspondem ao argumento -p 3000:3000 para o comando usado para executar o aplicativo com o MySQL.

      app:
        image: node:lts-alpine
        command: sh -c "yarn install && yarn run dev"
        ports:
          - 3000:3000
    
  6. Identifique o diretório de trabalho working_dir para o serviço app e também o volumes mapeado.

      app:
        image: node:lts-alpine
        command: sh -c "yarn install && yarn run dev"
        ports:
          - 3000:3000
        working_dir: /app
        volumes:
          - ./:/app
    

    Ao definir volumes do Docker Compose, você pode usar caminhos relativos com base no diretório atual.

  7. Especifique as definições de variável environment a serem usadas ao executar comandos para o serviço app.

      app:
        image: node:lts-alpine
        command: sh -c "yarn install && yarn run dev"
        ports:
          - 3000:3000
        working_dir: /app
        volumes:
          - ./:/app
        environment:
          MYSQL_HOST: mysql
          MYSQL_USER: root
          MYSQL_PASSWORD: <your-password>
          MYSQL_DB: todos
    

    Lembre-se de inserir a senha raiz do MySQL do espaço reservado <your-password>.

  8. Adicione a definição para o serviço MySQL mysql após a definição do serviço app. Especifique os nomes e valores de elementos, conforme mostrado e com o mesmo recuo.

    services:
      app:
        ...
      mysql:
        image: mysql:lts
    

    A definição do serviço mysql corresponde ao comando usado anteriormente para iniciar o MySQL. Quando você define o serviço, ele recebe automaticamente o alias de rede.

  9. Identifique o volumes mapeado para o serviço mysql.

    services:
      app:
        ...
      mysql:
        image: mysql:lts
        volumes:
          - todo-mysql-data:/var/lib/mysql
    
  10. Especifique as definições de variável environment a serem usadas ao executar comandos para o serviço mysql.

    services:
      app:
        ...
      mysql:
        image: mysql:lts
        volumes:
          - todo-mysql-data:/var/lib/mysql
        environment: 
          MYSQL_ROOT_PASSWORD: <your-password>
          MYSQL_DATABASE: todos
    

    Lembre-se de inserir a senha raiz do MySQL do espaço reservado <your-password>.

  11. Defina o mapeamento de volume para todo o aplicativo. Adicione uma seção volumes: após a seção services: e com o mesmo recuo.

    services:
       ...
    
    volumes:
      todo-mysql-data:
    
  12. Confirme se o arquivo de docker-compose.yml concluído é semelhante ao exemplo a seguir. Você deve ver a senha raiz do MySQL do espaço reservado <your-password>.

    name: todo
    
    services:
      app:
        image: node:lts-alpine
        command: sh -c "yarn install && yarn run dev"
        ports:
          - 3000:3000
        working_dir: /app
        volumes:
          - ./:/app
        environment:
          MYSQL_HOST: mysql
          MYSQL_USER: root
          MYSQL_PASSWORD: <your-password>
          MYSQL_DB: todos
    
      mysql:
        image: mysql:lts
        volumes:
          - todo-mysql-data:/var/lib/mysql
        environment: 
          MYSQL_ROOT_PASSWORD: <your-password>
          MYSQL_DATABASE: todos
    
    volumes:
      todo-mysql-data:
    

Executar o stack de aplicativos com o Docker Compose

Agora você pode tentar executar o arquivo docker-compose.yml.

  1. Interrompa as instâncias em execução do seu aplicativo e do banco de dados.

    Siga essas etapas no VS Code:

    1. Abra o EXPLORADOR DE CONTEINERES (extensão Container Tools).

    2. Para cada contêiner em execução, clique com o botão direito do mouse no contêiner e selecione Remover.

  2. Inicie seu aplicativo de vários contêineres e todos os serviços.

    Siga essas etapas no VS Code:

    1. Abra a exibição EXPLORER (arquivo e pasta).

    2. Clique com o botão direito do mouse no arquivo docker-compose.yml e selecione Redigir.

    Você deverá ver uma saída semelhante ao exemplo a seguir:

    [+] Building 0.0s (0/0)
    [+] Running 2/2
    ✔ Container app-app-1    Started  0.9s 
    ✔ Container app-mysql-1  Running
    

    Essa operação cria o volume mapeado para o aplicativo e a rede. Por padrão, o Docker Compose cria uma rede especificamente para a pilha de aplicativos.

  3. Examine os logs do contêiner em execução.

    Siga essas etapas no VS Code:

    1. Abra o EXPLORADOR DE CONTEINERES (extensão Container Tools).

    2. Clique com o botão direito do mouse no contêiner do aplicativo e selecione Exibir Logs.

    Você deverá ver uma saída semelhante ao exemplo a seguir:

    mysql_1  | 2019-10-03T03:07:16.083639Z 0 [Note] mysqld: ready for connections.
    mysql_1  | Version: '5.7.27'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server (GPL)
    app_1    | Connected to mysql db at host mysql
    app_1    | Listening on port 3000
    

    Os logs mostram o nome do serviço e o número da instância, como app_1 no início de cada linha. Esse formato ajuda você a distinguir mensagens por serviço e instância. Os logs de cada serviço são intercalados em um único fluxo. Essa abordagem permite que você fique atento a problemas relacionados ao tempo.

  4. Agora você pode acessar seu aplicativo em execução no navegador da Internet: http://localhost:3000.

Parar o Docker Compose e os contêineres em execução

Quando terminar de usar o aplicativo e os contêineres, você poderá removê-los.

Siga essas etapas no VS Code:

  1. Abra a exibição EXPLORER (arquivo e pasta).

  2. Clique com o botão direito do mouse no arquivo docker-compose.yml e selecione Compose Inoperante.

Essa operação interrompe todos os contêineres em execução e remove a rede.

Por padrão, os volumes nomeados no arquivo de composição não são removidos. Se você quiser remover esses volumes, poderá usar o comando docker-compose down --volumes.

Limpar recursos

Se você aplicou os pré-requisitos componentes nesta série de tutoriais à sua instalação, poderá reutilizar a configuração para o desenvolvimento futuro do Docker. Não é essencial excluir ou desinstalar nenhum componente.