Aprimore suas habilidades com este Tutorial Docker Compose

Se estiver se perguntando como criar contêineres Docker reproduzí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 complexos com vários contêineres.

Está pronto? Vamos lá!

Pré-requisitos

Se você deseja seguir passo a passo neste tutorial, certifique-se de ter 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. O VS Code extensão SSH oficial instalada e conectada ao host Docker. (opcional)

O que é o Docker Compose?

Comandos únicos podem ficar longos, realmente longos no Docker. Veja o exemplo abaixo. Este exemplo cria um contêiner para uma aplicação de software chamada bookstack.

docker create \
   --name=bookstack \
   -e PUID # UID do usuário para assumir a propriedade da aplicação/arquivos \
   -e PGID # GID do usuário para assumir a propriedade da aplicação/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 usado \
   -e APP_URL # A URL na qual sua aplicação será acessada (necessária para o funcionamento correto do proxy reverso) \
   -v /host/path/to/config:/config # Localização de quaisquer dados enviados \
   -p 80:80/tcp # Porta da interface de 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 funcionando. A linha de comando do Docker começa a se tornar complicada e difícil de solucionar; especialmente quando configurações de múltiplos contêineres começam a entrar em jogo.

O Docker Compose é uma maneira 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, os erros são mais fáceis de identificar e as interações entre contêineres são mais fáceis de definir.

O Docker Compose rapidamente se torna inestimável ao lidar com dependências de contêiner ou ambientes de múltiplos contêineres.

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

O Docker Compose utiliza 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 foca especificamente em ser o mais legível possível para os humanos, mantendo o poder da estrutura.

O YAML tem uma desvantagem em que as guias e outros espaços em branco são significativos e devem ser formatados corretamente. O VS Code faz muito desse trabalho árduo para você, e é por isso que você verá muitos dos 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 a instalação do Docker Compose 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 depois instale o Docker Compose
# com quaisquer dependências necessárias. a bandeira -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 containers.

Criando uma Estrutura de Pastas para o Docker Compose

Antes de criar um contêiner com o Docker Compose, você deve primeiro criar uma pasta para armazenar contêineres. Você não deve apenas criar uma estrutura de pastas para armazenar contêineres, mas você verá 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 é seu arquivo de configuração chamado docker-compose.yaml. Este arquivo de configuração, como explicado acima, dita como o tempo de execução do Docker deve construir um contêiner.

Ao executar o Docker Compose, o comando procurará seu 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.

Só pode haver um arquivo de configuração do Docker Compose por pasta.

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

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

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

  1. Em seu diretório pessoal, crie uma pasta chamada containers. Essa pasta será um bom espaço reservado para este e outros contêineres.
  2. Dentro da pasta containers, crie uma subpasta chamada caddy. Esta pasta conterá o arquivo de configuração do Docker Compose e o próprio contêiner Caddy.
  3. Finalmente, dentro da pasta do contêiner, 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ê pode começar a preencher esse arquivo com uma 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 contêiner caddy se parece com o seguinte. Em seu editor de texto Linux favorito 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 percorrer 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 quebram a especificação. Portanto, a versão é importante para que o Docker Compose possa determinar quais recursos precisa usar. A versão 3.7 é a última versão 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 você pode usar dentro do 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 (isto é puramente 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, caddy do Docker Hub está definido. O nome ou número após a marca separado por dois pontos é a versão.

Mapeamento de Porta

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

ports:
  - "80:80"

Em Docker Compose, a diretiva ports permite configurar uma ou mais correspondências do host para o contêiner. Por exemplo, acima, você mapeou a porta 80 no host para a porta 80 no contêiner. No entanto, não é necessário que os números das portas correspondam. O exemplo abaixo mapeia a porta 8800 no host para a porta 80 no contêiner.

ports:
  - "8800:80"

Você também pode definir várias portas como mostrado abaixo.

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

Ao fazer isso, você mapearia tanto a porta 80 quanto a 443 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. Certifique-se de verificar a documentação da imagem com a qual está trabalhando no Docker Hub ou no site do mantenedor para portas mapeáveis. Não faz sentido mapear uma porta se ela não estiver em uso!

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

Executando o Contêiner

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

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

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

Você pode ter notado 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á ativo e funcionando navegando para 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 via SSH ao host do Docker na animação abaixo:

Demonstrating a container created with Docker Compose

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

Comandos para Gerenciar Contêineres Desanexados

Na seção anterior, você iniciou o contêiner caddy usando a bandeira -d. Fazendo isso, um contêiner foi executado em um estado desanexado. Quando um contêiner está em um estado desanexado, significa que o contêiner continuará a rodar em segundo plano. Mas, isso apresenta um problema: como você gerencia esse contêiner se não tem mais controle direto?

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

  • O comando docker-compose restart é usado para reiniciar um contêiner que está atualmente em execução. Fazê-lo é diferente de realmente executar novamente o comando docker-compose up -d. O comando de reinício 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).
  • O 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.
  • O docker-compose down irá parar os contêineres em execução e também os destruirá. Aqui é onde entram os bind mounts dos volumes (leia mais abaixo).
  • O docker-compose pull irá buscar a versão atual da imagem do docker (ou imagens) no repositório. Se estiver usando a tag 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 contêineres rapidamente com tempo de inatividade mínimo.
  • O docker-compose logs irá mostrar os logs do contêiner em execução (ou parado). Você também pode abordar 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 Bind Mounts no Docker Compose

Montagens de Vínculo 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 abaixo. Esta será a página principal que o servidor web Caddy servirá.

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

3. Modifique seu arquivo de configuração do Docker Compose para se parecer com abaixo. O arquivo de exemplo abaixo está adicionando a seção volumes e apontando uma montagem de vínculo 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 docker-compose up -d novamente. O Docker Compose agora reconhecerá que o arquivo foi alterado e recriará seu contêiner.

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

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

Creating a bind mount using Docker Compose

Você está agora hospedando conteúdo armazenado localmente na sua máquina! No entanto, e se o seu conteúdo estiver em uma fonte externa como um compartilhamento de rede?

Usando Docker Compose com Volumes do Docker

Depois de criar um contêiner simples com o Docker Compose, provavelmente você precisará que esse contêiner acesse arquivos em outro lugar, talvez em um compartilhamento de rede. Se for o caso, você pode configurar o contêiner para usar volumes do Docker diretamente no arquivo de configuração do Docker Compose.

Para fins de demonstração, este guia criará um servidor de compartilhamento de arquivos de rede (NFS) no host Docker. O uso de conteúdo local como um ponto de montagem NFS não tem objetivo prático além da demonstração. Normalmente, se você for montar um volume NFS, será de uma fonte externa, como um NAS ou servidor remoto.

Configurar um Compartilhamento NFS

Se você ainda não tiver um compartilhamento NFS configurado, configure um agora no host 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 (semelhante 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 # evitar 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 showmount -e localhost. Este comando mostrará qualquer compartilhamento NFS atualmente exposto e quem tem acesso.

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

Creating a NFS share in Ubuntu 20.04

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

Definindo um Volume Nomeado 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 ser semelhante ao abaixo. A seção volumes cria um volume nomeado chamado MyWebsite. 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 deverão 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 arquivo 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, pode trazer todos os tipos de armazenamento em rede para seus contêineres. No entanto, o Docker Compose pode fazer mais do que apenas definir contêineres ou volumes únicos. Vamos mergulhar em cenários mais complexos e multi-contêineres.

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

Definindo Múltiplos Contêineres no Docker Compose

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

Usando o Docker Compose, você pode agrupar contêineres definidos dentro de um único arquivo. Ao definir múltiplos 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 tal cenário, vamos configurar uma aplicação wiki popular chamada 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 muitas aplicações 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 tal 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, linuxserver.io mantém uma respeitável imagem Docker em nome do BookStack. Embora a documentação no site do Docker Hub tenha um arquivo de configuração recomendado para o Docker Compose, este tutorial criará um novo arquivo de configuração, explicando os conceitos.

No host Docker:

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

2. Em seguida, crie um arquivo de configuração em branco para o 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á principalmente utilizando conceitos já introduzidos: Você tem dois serviços (bookstack e bookstack_db), ambos com imagens e vinculações de montagem. O contêiner do bookstack possui um mapeamento de porta do host 8080 para a porta interna 80.

Dada a sobrecarga extremamente baixa dos contêineres do 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 é nitidamente diferente das configurações tradicionais de banco de dados, onde uma única instalação de banco de dados pode atender a centenas de aplicativos da web.

Uma nova opção que você pode ver no arquivo acima é o comando depends_on. Este comando informa ao Docker a ordem em que os contêineres devem iniciar. Definir o comando depends_on diz ao Docker que o contêiner bookstack_db deve iniciar 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 entre si! O contêiner bookstack não tem ideia de 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 contêineres do Docker. Essas são variáveis fornecidas durante a 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 Docker. Elas serão diferentes dependendo da imagem Docker que você está utilizando, e é necessário consultar a documentação do criador sobre quais variáveis de ambiente usar.

Existem dois métodos para definir variáveis de ambiente; diretamente no arquivo docker-compose.yaml ou como 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 Docker, crie agora duas variáveis de ambiente; uma para o contêiner bookstack e outra para o contêiner 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 prática recomendada, certifique-se agora de 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 ambos os arquivos bookstack.env e bookstack_db.env contêm dados sensíveis.

4. Atualize o arquivo Docker Compose ~/containers/bookstack/docker-compose.yaml para fazer referência a esses dois arquivos de ambiente conforme mostrado 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 contêineres bookstack e bookstack_db usando o Docker Compose.

sudo docker-compose up -d

Você pode ver cada um dos passos mencionados nesta seção 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 do Docker trabalha em conjunto com o Docker Compose para realizar diversas tarefas em segundo plano. Poder monitorar o que está acontecendo, especialmente ao trabalhar com vários containers ao mesmo tempo, é útil.

Para monitorar o container do bookstack, por exemplo, utilize o comando logs. Neste tutorial, assim que você visualizar os logs exibindo [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 dentro do seu próprio container, com seu próprio banco de dados, completamente dentro do Docker!

Enquanto você tiver as pastas bookstack e bookstack_db, poderá recriar seu ambiente do bookstack do zero.

Docker Compose e Networking

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

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

Você pode visualizar a rede criada para os containers quando executa o comando docker-compose up -d, conforme 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, no exemplo anterior, você se referiu ao seu 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 autogerar 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 pode criar uma rede à 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 essa rede automaticamente 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 em 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. Seus dois contêineres agora estão conectados a duas redes, como mostrado abaixo.

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

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

Configurando 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 um ambiente isolado. Isso é equivalente a rodar uma máquina virtual logada como o usuário Administrador padrão. Embora isso geralmente não seja um problema, existem preocupações de segurança se o isolamento for comprometido.

Outro problema de rodar como root são as permissões de arquivo. Você pode notar que se tentar deletar a pasta db dentro da pasta bookstack, você na verdade não conseguirá; o conteúdo é de propriedade do root.

Embora a maioria das imagens não aprecie ser executada como um usuário não-root, as imagens do linuxserver.io em particular oferecem uma variável de ambiente para definir o usuário que roda 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 (o que você pode não ser). Você pode ler mais sobre IDs de Usuários e Grupos em Relacionado: Um Cara do Windows em um Mundo Linux: Usuários e Permissões de Arquivos)

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çado a um usuário diferente

Configurando a Política de Reinício

Se você deseja que os contêineres construídos com o Docker Compose reiniciem em caso de falha, utilize a política de reinício adicionando a restart policy e incluindo o parâmetro restart: <option> 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 inesperados de energia.

Configurando manualmente entradas DNS para contêineres

Assim como no Windows e Linux, o Docker também possui um “arquivo hosts”. Usando o parâmetro extra_hosts em um arquivo de configuração, você pode forçar um host a resolver 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 é iniciado, você pode executar comandos dentro dele 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 comando abaixo.

docker-compose run web bash

Conclusão

Neste ponto, você deve ter informações suficientes para acompanhar a maioria dos tutoriais de docker-compose disponíveis na web. Ter esse conhecimento pode ampliar significativamente sua capacidade de ingressar no mundo do Docker e na construção de aplicativos web com Infrastructure as Code.

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