Aprimore Suas Habilidades com este Tutorial do Docker Compose

Se você está se perguntando como criar contêineres Docker reprodutíveis com o Docker Compose, você veio ao lugar certo. Neste tutorial passo a passo do Docker Compose, você vai aprender como criar contêineres simples, mapear portas com o Docker Compose até cenários multi-contêiner complexos.

Você está pronto? Vamos lá!

Pré-requisitos

Se você deseja acompanhar passo a passo neste tutorial, verifique se você tem o seguinte:

  1. A fresh install of Ubuntu Server LTS with SSH Enabled. This guide will use Ubuntu Server LTS 20.04.1 as the Docker host machine.
  2. A computer with VS Code installed (optional). This guide will use Visual Studio Code 1.52.1 to SSH to the Docker host and run commands.
  3. A extensão oficial SSH do VS Code instalada e conectada ao host Docker. (opcional)

O que é o Docker Compose?

Comandos únicos podem ficar longos, muito longos no Docker. Pegue o exemplo abaixo. Este exemplo cria um contêiner para um aplicativo de software chamado bookstack.

docker create \
   --name=bookstack \
   -e PUID # UID do usuário para assumir a propriedade do aplicativo/arquivos \
   -e PGID # GID do usuário para assumir a propriedade do aplicativo/arquivos \
   -e DB_USER # O usuário do banco de dados \
   -e DB_PASS # A senha do banco de dados \
   -e DB_HOST # O host do banco de dados \
   -e DB_DATABASE # O banco de dados a ser utilizado \
   -e APP_URL # A URL na qual seu aplicativo será acessado (necessário para a operação correta do proxy reverso) \
   -v /host/path/to/config:/config # Localização dos dados enviados \
   -p 80:80/tcp # Porta da interface do usuário da web \
   --restart unless-stopped \
   linuxserver/bookstack:version-v0.31.4

À medida que a complexidade de um ambiente Docker aumenta, também aumenta a quantidade de flags e condições necessárias para uma configuração de contêiner funcional. A linha de comando do Docker começa a se tornar complicada e difícil de solucionar problemas; especialmente quando configurações de vários contêineres começam a ser inseridas.

O Docker Compose é uma forma de criar contêineres Docker reproduzíveis usando um arquivo de configuração em vez de comandos Docker extremamente longos. Ao usar um arquivo de configuração estruturado, é mais fácil identificar erros e definir interações entre os contêineres.

O Docker Compose se torna rapidamente indispensável ao lidar com dependências de contêineres ou ambientes com vários contêineres.

O Docker Compose é uma maneira fantástica de entrar no Infrastructure as Code sem a complexidade de sistemas distribuídos como o Kubernetes.

O Docker Compose usa uma estrutura de arquivo de configuração chamada YAML. O YAML é semelhante ao JSON ou HTML, no sentido de que é uma linguagem estruturada e legível por máquina. O YAML se concentra especificamente em ser o mais legível possível para humanos, mantendo o poder estruturado.

O YAML possui uma desvantagem em que espaços em branco, como tabs, são significativos e devem ser formatados corretamente. O VS Code faz a maior parte desse trabalho difícil para você, e é por isso que você verá muitos exemplos sendo feitos no VS Code.

Instalando o Docker Compose

Agora vamos começar a colocar a mão na massa. Supondo que você esteja conectado ao seu host Docker, é hora de instalar o Docker Compose.

O Docker Compose é um pacote separado do tempo de execução do Docker. Mas ao instalar o Docker Compose, você também instalará o tempo de execução do Docker, matando dois coelhos com uma cajadada só!

Para instalar o Docker Compose e o tempo de execução do Docker, execute os dois comandos a seguir.

# atualize a lista de software (conhecida como repositório) e em seguida instale o docker compose
# com as dependências necessárias. a opção -y é usada para pular a confirmação
sudo apt update -y
sudo apt install docker-compose -y
The installation command for Docker Compose

Uma vez instalado, agora você deve criar uma estrutura de pastas para armazenar os containers.

Criando uma Estrutura de Pastas para o Docker Compose

Antes de criar um container com o Docker Compose, você deve primeiro criar uma pasta para armazenar os containers. Não apenas crie uma estrutura de pastas para armazenar os containers, mas também perceberá que vários comandos do Docker são sensíveis à localização de vários arquivos de configuração; o Docker Compose não é diferente.

O componente mais importante do Docker Compose é o seu arquivo de configuração chamado docker-compose.yaml. Este arquivo de configuração, como explicado acima, determina como o tempo de execução do Docker deve construir um container.

Ao executar o Docker Compose, o comando procurará pelo arquivo de configuração na mesma pasta em que o comando é executado. Devido a esse requisito, é sempre melhor criar uma pasta separada ao executar o Docker Compose.

Pode haver apenas um arquivo de configuração do Docker Compose por pasta.

Para demonstrar a criação de um container Docker com o Docker Compose, primeiro crie uma estrutura de pastas para armazenar o futuro container e seu arquivo de configuração usando um pequeno servidor de arquivos chamado Caddy.

Caddy é um servidor de arquivos, similar ao apache httpd ou ao nginx, mas escrito na linguagem Go. Caddy foi especificamente projetado para facilidade de uso (e irá gerar ou servir automaticamente um arquivo index.html) sem configuração. Essa combinação faz do caddy uma boa escolha para iniciantes.

Assumindo que você está logado no seu host Docker, crie a estrutura de pastas da seguinte forma:

  1. No diretório home, crie uma pasta chamada containers. Essa pasta será um bom local para esse e outros containers.
  2. Dentro da pasta containers, crie uma subpasta chamada caddy. Essa pasta irá conter o arquivo de configuração do Docker Compose e o próprio container do Caddy.
  3. Por fim, dentro da pasta do container, caddy, crie um arquivo de texto em branco chamado docker-compose.yaml que se tornará o arquivo de configuração do Docker Compose.

Com a estrutura de pastas e o arquivo de configuração do Docker Compose criados, você agora pode começar a preencher esse arquivo com a configuração do Docker Compose.

Criando um Arquivo de Configuração do Docker Compose

Em sua forma mais básica, um arquivo docker-compose.yaml para o container caddy se parece com o seguinte. Em seu editor de texto favorito do Linux ou com o VS Code, copie e cole o código abaixo no arquivo de configuração do Docker Compose criado anteriormente.

version: "3.7"
services:
  caddy:
    container_name: "caddy"
    image: "caddy:latest"
    ports:
      - "80:80"

Vamos passar por cada uma das opções mostradas:

  • version especifica a versão do arquivo docker-compose. Cada nova definição do Docker Compose inclui mudanças que podem quebrar a especificação. Portanto, a versão é importante para que o Docker Compose saiba quais recursos deve usar. A versão 3.7 é a versão mais recente suportada pelo Ubuntu 20.04.1 LTS.

A especificação completa para o Docker Compose 3.x pode ser encontrada aqui. A documentação vinculada menciona todas as opções que podem ser usadas no Docker Compose

  • services contém as especificações para os contêineres reais. Você pode definir vários contêineres nesta seção.
  • caddy é o nome do primeiro contêiner (apenas para referência).
  • container_name define o nome real dado ao contêiner pelo Docker e deve ser único.
  • image é o nome da imagem. Neste caso, é definido o caddy do Docker Hub. O nome ou número após a tag separados por dois pontos é a versão.

Mapeamento de Portas

Essa última opção em particular requer uma menção especial:

ports:
  - "80:80"

No Docker Compose, a diretiva ports permite definir um ou mais mapeamentos do host para o contêiner. Por exemplo, acima você mapeou a porta 80 do host para a porta 80 do contêiner. No entanto, não é necessário que as portas correspondam. O exemplo abaixo mapeia a porta 8800 do host para a porta 80 do contêiner.

ports:
  - "8800:80"

Também é possível definir várias portas, como no exemplo abaixo.

ports:
  - "80:80"
  - "443:443"

Ao fazer isso, as portas 80 e 443 serão mapeadas para o host (uma configuração comum para servidores web, para atender tanto HTTP quanto HTTPS).

O criador da imagem Docker define as portas disponíveis no momento da criação. Verifique a documentação da imagem com a qual você está trabalhando no Docker Hub ou no site do mantenedor para obter as portas mapeáveis. Não faz sentido mapear uma porta se ela não estiver em uso!

Com isso em mente, vamos ver como executar o contêiner.

Executando o Contêiner

Neste ponto, você deve ter o arquivo docker-compose.yaml dentro da pasta ~\containers\caddy. Agora é hora de criar e iniciar o contêiner do Caddy.

No seu terminal, execute o seguinte comando para iniciar os contêineres Docker definidos no arquivo docker-compose.yaml.

# Este comando deve ser executado na mesma pasta do arquivo. A opção -d executa
# o comando *detached*, que iniciará o contêiner em segundo plano
sudo docker-compose up -d

Você pode notar que não precisou especificar a localização do arquivo docker-compose.yaml ao executar sudo docker-compose up -d. O Docker Compose espera que você execute todos os comandos dentro da pasta que contém o arquivo docker-compose.yaml, pois muitos comandos são relativos a essa pasta.

Agora, verifique se o contêiner está funcionando navegando até http://<seu ip>. Este guia está usando http://homelab-docker como referência.

Você pode ver esse processamento acontecendo no VS Code enquanto está conectado ao host Docker na animação abaixo:

Demonstrating a container created with Docker Compose

Sucesso! Agora você usou com sucesso o Docker Compose para iniciar um contêiner a partir de um arquivo de configuração. Com esse primeiro passo importante concluído, vamos ver como você gerencia o estado do seu contêiner.

Comandos para Gerenciar Contêineres em Execução em Segundo Plano

Na seção anterior, você iniciou o contêiner caddy usando a opção -d. Fazendo isso, o contêiner foi executado em um estado desanexado. Quando um contêiner está em um estado desanexado, ele continuará sendo executado em segundo plano. No entanto, isso apresenta um problema: como você gerencia esse contêiner se não tiver mais controle direto sobre ele?

Para resolver esse problema, o Docker Compose possui uma série de comandos que gerenciarão os contêineres iniciados com um arquivo docker-compose.yaml:

  • docker-compose restart é usado para reiniciar um contêiner que está em execução. Fazê-lo é diferente de realmente executar novamente docker-compose up -d. O comando de reinicialização simplesmente reiniciará um contêiner existente, executará novamente o comando docker-compose up -d e recriará o contêiner do zero (se o arquivo de configuração tiver sido alterado).
  • docker-compose stop irá parar um contêiner em execução sem destruir o contêiner. Da mesma forma, docker-compose start iniciará o contêiner novamente.
  • docker-compose down irá parar os contêineres em execução e também destruí-los. É aqui que entram em jogo as ligações de volumes (leia mais abaixo).
  • docker-compose pull irá buscar a versão atual da imagem (ou imagens) do docker no repositório. Se estiver usando a marca latest, você pode seguir com docker-compose down && sudo docker-compose up -d para substituir o contêiner pela versão mais recente. Usar docker-compose pull é uma maneira conveniente de atualizar os contêineres rapidamente com um tempo de inatividade mínimo.
  • docker-compose logs mostrará os logs do contêiner em execução (ou parado). Você também pode especificar contêineres individuais (se houver vários contêineres definidos no arquivo de composição) com docker-compose logs <nome do contêiner>.

A full list of docker-compose commands can be seen by running docker-compose with no additional arguments or referenced here in the documentation.

Agora que você tem um contêiner em execução, vamos ver como usar conteúdo salvo localmente em sua máquina.

Criando Ligações de Volumes no Docker Compose

Bind Mounts são como o Docker mapeia dados importantes do usuário para armazenamento local no seu servidor. Para começar, gere algum conteúdo para o contêiner hospedar:

  1. No host do Docker, dentro da pasta ~/containers/caddy, crie uma nova pasta chamada files.

2. Crie um novo arquivo chamado index.html dentro da pasta ~/containers/caddy, que se parece com o exemplo abaixo. Esta será a página principal que o servidor web Caddy irá servir.

<body><h2>hello world!</h2></body>

3. Modifique o seu arquivo de configuração do Docker Compose para ficar como o exemplo abaixo. O arquivo de exemplo abaixo está adicionando a seção volumes e apontando um bind mount para a pasta files recém-criada para torná-la disponível para o contêiner.

version: "3.7" services: caddy: container_name: "caddy" image: "caddy:latest" ports: - "80:80" volumes: #o ./ refere-se a uma pasta relativa ao arquivo docker-compose - "./files:/usr/share/caddy"

4. Execute novamente o comando docker-compose up -d. O Docker Compose agora reconhecerá que o arquivo foi alterado e recriará o seu contêiner.

5. Acesse a página do contêiner com um navegador e você deverá ver que ela está servindo a página “Hello World!”.

Você pode ver o seguinte na animação abaixo:

Creating a bind mount using Docker Compose

Agora você está hospedando conteúdo armazenado localmente em sua máquina! No entanto, e se o seu conteúdo estiver em uma fonte externa, como uma rede compartilhada?

Usando o Docker Compose com Volumes do Docker

Uma vez que você cria um contêiner simples com o Docker Compose, provavelmente precisará que esse contêiner acesse arquivos em outro lugar, talvez em uma rede compartilhada. Se for o caso, você pode configurar o contêiner para usar volumes do Docker diretamente em seu arquivo de configuração do Docker Compose.

Para fins de demonstração, este guia irá criar um servidor de Compartilhamento de Arquivos de Rede (NFS) no host do Docker. Servir conteúdo local como um ponto de montagem NFS não tem nenhum propósito prático fora da demonstração. Se você for montar um volume NFS, geralmente será de uma fonte externa, como um NAS ou servidor remoto.

Configure um Compartilhamento NFS

Se você ainda não tem um compartilhamento NFS configurado, crie um agora no host do Docker para este tutorial. Para fazer isso:

  1. Instale o pacote do servidor NFS executando apt install nfs-kernel-server -y.

2. Adicione o contêiner como uma exportação NFS (similar a um compartilhamento CIFS do Windows) executando o seguinte.

# Adicione uma linha ao arquivo de configuração /etc/exports para criar um compartilhamento NFS para # /home/homelab/containers. Esse compartilhamento é exposto apenas para o localhost (para # impedir que outros computadores tenham acesso) echo '/home/homelab/containers localhost(rw,sync,no_root_squash,no_subtree_check)' | sudo tee -a /etc/exports # Reinicie o servidor NFS com a nova configuração sudo systemctl restart nfs-kernel-server

3. Agora verifique se o host expõe o compartilhamento NFS executando o comando showmount -e localhost. Este comando mostrará quaisquer compartilhamentos NFS atualmente expostos e quem tem acesso.

Na captura de tela abaixo, você pode ver que /home/homelab/containers está exposto, mas apenas para o computador localhost (que é o mesmo servidor que executa o host do Docker).

Creating a NFS share in Ubuntu 20.04

Se você ver a pasta /home/<username>/containers na saída, o compartilhamento NFS está configurado.

Definindo um Volume Nomeado do Docker

Depois de criar o compartilhamento NFS, agora você precisa informar ao Docker como acessar esse compartilhamento. Usando o Docker Compose, você pode fazer isso definindo um volume nomeado no arquivo de configuração do Docker Compose.

A named volume is a way for Docker to abstract network-based file shares. Network file sharing comes in all sorts of shapes and sizes these days: CIFS (windows) shares, NFS (Linux) shares, AWS S3 Buckets, and more. By creating a Named Volume, Docker does the hard part of figuring out how to talk to the network share and lets the container just treat the share as if it is local storage.

Para criar um volume nomeado:

  1. Abra o arquivo de configuração do Docker Compose (docker-compose.yaml). Se você estiver seguindo junto, o arquivo deve estar localizado na pasta ~/containers/caddy.

2. Dentro do arquivo de configuração do Docker Compose, adicione uma seção volumes após a seção services. Seu arquivo de configuração deve ficar como abaixo. A seção volumes cria um volume nomeado chamado MeuWebsite. Dentro desse volume nomeado, os parâmetros necessários (como IP, configurações NFS e caminho) são especificados. O parâmetro volumes dentro da seção services também é modificado para apontar para o volume nomeado em vez de uma pasta local.

version: "3.7"
 services:
   caddy:
     container_name: "caddy"
     image: "caddy:latest"
     ports:
       - "80:80"
     volumes:
       - "MyWebsite:/usr/share/caddy"
 volumes:
   MyWebsite:
     driver_opts:
       type: "nfs"
       o: "addr=localhost,nolock,soft,rw"
       device: ":/home/homelab/containers/caddy/files"

3. Depois de definir o volume nomeado apontando para o compartilhamento NFS no arquivo de configuração do Docker Compose, execute docker-compose up -d para criar e iniciar o contêiner. Se tudo correr bem, o contêiner e o site devem ser iniciados novamente.

Setting NFS client settings within Docker Compose in VS Code

4. Navegue novamente para a página do contêiner. O conteúdo do index.html deve aparecer como se o arquivo estivesse sendo montado localmente. No entanto, esse arquivo está sendo montado através do servidor NFS configurado na rede.

Demonstrating access to the index.html file through an NFS share in Docker

Agora que você pode montar volumes externos do Docker no Docker Compose, agora pode trazer todos os tipos de armazenamento de rede para seus contêineres. No entanto, o Docker Compose pode fazer mais do que apenas definir contêineres ou volumes individuais. Vamos mergulhar em cenários mais complexos com vários contêineres.

Este tutorial não usará mais o contêiner caddy, portanto, você pode remover o contêiner usando docker-compose down.

Definindo Múltiplos Contêineres no Docker Compose

A maioria dos contêineres do Docker não funciona isoladamente. Os contêineres do Docker geralmente têm dependências de serviços, como bancos de dados ou serviços da web separados que se comunicam através de uma API.

Usando o Docker Compose, você pode agrupar contêineres definidos em um único arquivo. Ao definir vários contêineres em um único arquivo, os contêineres podem se comunicar entre serviços dependentes e simplificar a organização de layouts de contêineres complexos.

Para demonstrar um cenário como esse, vamos configurar um aplicativo wiki popular chamado BookStack.

O BookStack é um software wiki popular conhecido por sua facilidade de uso e layout hierárquico (ao contrário de um layout plano, como o mediawiki).

O BookStack, assim como muitos aplicativos da web, requer um banco de dados separado para funcionar corretamente, bem como as informações necessárias para se comunicar com o banco de dados. Configurar essa situação é onde o Docker Compose se destaca.

Crie o arquivo de configuração do Docker Compose

O BookStack não possui uma imagem Docker mantida internamente, no entanto, o linuxserver.io mantém uma imagem confiável do BookStack em nome deles no Docker Hub. Embora a documentação no site do Docker Hub tenha um arquivo de configuração recomendado do Docker Compose, este tutorial criará um novo arquivo de configuração enquanto explica os conceitos.

No host Docker:

  1. Primeiro, crie uma pasta para o BookStack. Se você seguiu os tutoriais da seção anterior, você deve ter uma pasta ~/containers. Crie uma pasta chamada bookstack dentro dela.

2. Em seguida, crie um arquivo de configuração em branco do Docker Compose chamado docker-compose.yaml dentro da pasta bookstack.

Creating the folder structure for Bookstack in VS Code

3. Agora abra o arquivo de configuração do Docker Compose e defina dois containers: o container bookstack e o container bookstack_db (mariadb).

version: "3.7"
 services:
   bookstack:
     container_name: "bookstack"
     image: "ghcr.io/linuxserver/bookstack"
     ports:
       - "8080:80"
     volumes:
       - "./files:/usr/share/caddy"
     depends_on:
       - "bookstack_db"
   bookstack_db:
     container_name: "bookstack_db"
     image: "mariadb"
     volumes:
       - "./db:/var/lib/mysql"

Até agora, este arquivo docker-compose.yaml está usando principalmente conceitos já introduzidos: Você tem dois serviços (bookstack e bookstack_db), ambos com imagens e bind mounts. O contêiner bookstack tem um mapeamento de porta da porta do host 8080 para a porta interna 80.

Dado o baixo overhead extremamente baixo dos contêineres Docker, é prática comum definir um contêiner de banco de dados separado para cada aplicativo da web. Fazê-lo permite uma maior separação de responsabilidades. Isso é completamente diferente das configurações de banco de dados tradicionais, onde uma única instalação do banco de dados pode servir centenas de aplicativos da web.

Uma nova opção que você pode ver no arquivo acima é o comando depends_on. Esse comando informa ao Docker a ordem em que os contêineres devem ser iniciados. Definir o comando depends_on informa ao Docker que o contêiner bookstack_db deve ser iniciado primeiro.

Configurando a comunicação entre contêineres com variáveis de ambiente

Este arquivo de configuração construído na última seção ainda não está completo. Embora você tenha definido dois serviços (contêineres), eles não estão se comunicando! O contêiner bookstack não sabe como se comunicar com o contêiner bookstack_db. Vamos resolver isso usando variáveis de ambiente.

As variáveis de ambiente são a maneira mais comum de fornecer variáveis para os contêineres Docker. Essas variáveis são fornecidas em tempo de execução (ou definidas no arquivo de configuração docker-compose.yaml) para fornecer informações sobre o que o contêiner precisa fazer.

As variáveis de ambiente são definidas pela pessoa que cria a imagem do Docker. Elas serão diferentes dependendo da imagem do Docker que você está usando e você deve consultar a documentação do criador para saber quais variáveis de ambiente usar.

Há dois métodos para definir variáveis de ambiente: diretamente no arquivo docker-compose.yaml ou em um arquivo separado.

A separate file is, typically, the recommended method, especially if variables contain sensitive data such as passwords. A docker-compose.yaml file is designed to be shared or even uploaded to a public-facing GitHub repo. Having a separate file for sensitive data reduces the chance of an accidental security breach.

No host do Docker, crie duas variáveis de ambiente: uma para o container bookstack e outra para o container bookstack_db.

  1. Crie um novo arquivo na pasta ~/containers/bookstack chamado bookstack.env com o seguinte conteúdo:
APP_URL is the IP address or hostname of your server. This article is using homelab-docker
 APP_URL=http://homelab-docker:8080
 DB_HOST is the container name you gave your container
 DB_HOST=bookstack_db
 DB_USER is defined in the bookstack_DB environment file
 DB_USER=bookstack_user
 DB_PASS is also defined in the bookstack_DB environment file
 DB_PASS=MySecurePassword
 DB_DATABASE is the name of the database within mariadb
 DB_DATABASE=bookstack

2. Crie um novo arquivo na pasta ~/containers/bookstack chamado bookstack_db.env e inclua o seguinte conteúdo:

The root password for our database, keep it secret, keep it safe
 MYSQL_ROOT_PASSWORD=MySecureRootPassword
 The database bookstack will be using
 MYSQL_DATABASE=bookstack
 the user bookstack will be using
 MYSQL_USER=bookstack_user
 the password bookstack will be using
 MYSQL_PASSWORD=MySecurePassword

3. Como uma prática recomendada, agora garanta que ambos os arquivos env não sejam legíveis por outros usuários.

chmod 600 bookstack.env bookstack_db.env

Você deve alterar o acesso de leitura porque os arquivos bookstack.env e bookstack_db.env contêm dados sensíveis.

4. Atualize o arquivo ~/containers/bookstack/docker-compose.yaml do Docker Compose para fazer referência a esses dois arquivos de ambiente mostrados abaixo.

version: "3.7"
 services:
   bookstack:
     container_name: "bookstack"
     image: "ghcr.io/linuxserver/bookstack"
     ports:
       - "8080:80"
     volumes:
       - "./files:/usr/share/caddy"
     depends_on:
       - "bookstack_db"
     env_file:
       - "./bookstack.env"
   bookstack_db:
     container_name: "bookstack_db"
     image: "mariadb"
     volumes:
       - "./db:/var/lib/mysql"
     env_file:
       - "./bookstack_db.env"

5. Agora inicie os containers bookstack e bookstack_db usando o Docker Compose.

sudo docker-compose up -d

Você pode ver cada um dos passos mencionados nesta seção sendo realizados no VS Code abaixo.

Setting up environment variables and the Docker Compose file with VS Code

Monitorando os Logs do Docker Compose

O mecanismo Docker funciona com o Docker Compose para executar várias tarefas diferentes em segundo plano. Ser capaz de monitorar o que está acontecendo, especialmente ao trabalhar com vários containers ao mesmo tempo, é útil.

Para monitorar o container do bookstack, por exemplo, use o comando logs. Neste tutorial, assim que você ver os logs mostrarem [services.d] done, você pode acessar a URL do bookstack.

sudo docker-compose logs bookstack
Using the docker-compose logs command
The bookstack welcome screen. Default login is [email protected]/password

Nesta etapa, você deve ter um wiki totalmente funcional em execução em seu próprio container, com seu próprio banco de dados, completamente dentro do Docker!

Desde que você tenha as pastas bookstack e bookstack_db, você pode recriar seu ambiente bookstack do zero.

Docker Compose e Networking

Até este ponto, você não aprendeu muito sobre a comunicação e a aspecto de rede de como os containers trabalham juntos. Vamos mudar isso.

Quando você cria vários containers dentro de um único arquivo docker-compose.yaml, como fez nas seções anteriores, todos eles são atribuídos à mesma rede (geralmente chamada nome-da-pasta-pai_default).

Você pode ver a rede criada para os containers quando executa o comando docker-compose up -d como mostrado abaixo.

The default network created with docker-compose comes up

Quando todos os containers são atribuídos à mesma rede, o Docker cria entradas DNS para eles internamente. É por isso que, no exemplo anterior, você se referiu ao banco de dados como bookstack_db nas variáveis de ambiente. Esse nome bookstack_db é na verdade uma entrada DNS que aponta para o endereço IP do container do banco de dados.

Você também não precisa depender do Docker Compose para gerar automaticamente redes para você. Você pode definir manualmente redes internas ou externas. Definir manualmente redes é ótimo quando você tem um contêiner que precisa se comunicar com outro contêiner em um arquivo docker-compose.yaml separado. Você pode expor as portas ou criar uma rede na qual ambos podem se juntar!

Observe que quando você começa a definir redes explicitamente, também precisa definir explicitamente a rede padrão. O Docker Compose deixará de criar automaticamente essa rede assim que você começar a definir as redes

Agora modifique o docker-compose.yaml do bookstack para incluir uma rede criada externamente.

  1. Crie a rede externa com docker network create my_external_network.

2. Defina a rede externa no docker-compose.yaml:

version: "3.7"
 services:
   bookstack:
     container_name: "bookstack"
     image: "ghcr.io/linuxserver/bookstack"
     ports:
       - "8080:80"
     volumes:
       - "./files:/usr/share/caddy"
     depends_on:
       - "bookstack_db"
     env_file:
       - "./bookstack.env"
     networks:
       - "my_external_network"
       - "bookstack_default"
   bookstack_db:
     container_name: "bookstack_db"
     image: "mariadb"
     volumes:
       - "./db:/var/lib/mysql"
     env_file:
       - "./bookstack_db.env"
     networks:
       - "bookstack_default"
 networks:
   bookstack_default:
   my_external_network:
     external: true

3. Execute docker-compose up -d para recriar os contêineres. Agora seus dois contêineres estão conectados a duas redes, conforme mostrado abaixo.

A highlight of the networks defined within a docker-compose file

O contêiner bookstack agora também está conectado a uma rede definida externamente. Isso permite que você crie outro contêiner que converta o tráfego HTTP do bookstack em HTTPS antes de sair do Docker (referido como um proxy reverso).

Definindo um usuário específico para executar um contêiner.

Por padrão, todos os contêineres Docker são executados como um usuário root em sandbox. Isso é equivalente a executar uma máquina virtual conectada como o usuário Administrador padrão. Embora isso geralmente não seja um problema, existem preocupações de segurança se a sandbox for comprometida.

O outro problema de executar como root são as permissões de arquivo. Você pode notar que, se tentar excluir a pasta db dentro da pasta bookstack, na verdade não pode; o conteúdo pertence ao root.

Embora a maioria das imagens não aprecie ser executada como um usuário não-root, as imagens linuxserver.io em particular oferecem uma variável de ambiente para definir o usuário que é executado dentro do contêiner. Você pode fazer isso adicionando UID=1000 e GID=1000 na configuração bookstack.env.

1000:1000 é o ID de usuário e grupo padrão para o primeiro usuário no ubuntu (que pode não ser você). Você pode ler mais sobre IDs de usuário e IDs de grupo em Relacionado: Um cara do Windows em um mundo Linux: usuários e permissões de arquivo)

Você também pode forçar um UID e GID usando o parâmetro user no docker-compose, mas isso não é recomendado, pois a maioria dos contêineres não se comporta bem quando forçados a um usuário diferente

Definindo a Política de Reinicialização

Se você deseja que os contêineres construídos com o Docker Compose reiniciem em caso de falha, use a política de reinício adicionando o parâmetro restart: <opção> nas configurações do contêiner no arquivo docker-compose.yaml.

restart: "no"
restart: always
restart: on-failure
restart: unless-stopped

Ao adicionar esse parâmetro, os contêineres serão reiniciados automaticamente em caso de falha, ajudando a manter a disponibilidade em caso de problemas de energia inesperados.

Configurando manualmente as entradas de DNS para contêineres

Assim como no Windows e Linux, o Docker também possui um “arquivo de hosts”. Usando o parâmetro extra_hosts em um arquivo de configuração, você pode forçar um host a ser resolvido para um IP específico. Isso pode ser útil quando há restrições de DNS, como DNS dividido ou um servidor de teste com o qual você deseja interagir temporariamente.

extra_hosts:
  - "somehost:x.x.x.x"
  - "otherhost:x.x.x.x"

Executando comandos

Depois que o contêiner for iniciado, você poderá executar comandos dentro do contêiner usando o docker-compose run. Por exemplo, talvez você queira iniciar um terminal Bash dentro do seu contêiner bookstack. Para fazer isso, execute o seguinte comando.

docker-compose run web bash

Conclusão

Nesta etapa, você deve ter informações suficientes para acompanhar a maioria dos tutoriais de docker-compose disponíveis na web. Ter esse conhecimento pode expandir muito sua capacidade de entrar no mundo do Docker e na construção de aplicativos da web como Infraestrutura como Código.

Source:
https://adamtheautomator.com/docker-compose-tutorial/