Introdução ao Docker Compose

Introdução ao Docker Compose

1. Visão geral

Ao usar o Docker extensivamente, o gerenciamento de vários contêineres diferentes rapidamente se torna complicado.

Docker Compose é uma ferramenta que nos ajuda a superar esse problema eeasily handle multiple containers at once.

Neste tutorial, daremos uma olhada em seus principais recursos e mecanismos poderosos.

2. A configuração YAML explicada

Resumindo, o Docker Compose funciona aplicando muitas regras declaradas ema single docker-compose.yml configuration file.

Essas regrasYAML, tanto legíveis por humanos quanto otimizadas por máquina, nos fornecem uma maneira eficaz de fazer um instantâneo de todo o projeto de dez mil pés em algumas linhas.

Quase todas as regras substituem um comando específico do Docker, de modo que, no final, precisamos apenas executar:

docker-compose up

Podemos obter dezenas de configurações aplicadas pelo Compose sob o capô. Isso nos poupará o trabalho de escrevê-los com Bash ou qualquer outra coisa.

Neste arquivo, precisamos especificar oversion do formato de arquivo Compose, pelo menos umservice e, opcionalmente,volumesenetworks:

version: "3.7"
services:
  ...
volumes:
  ...
networks:
  ...

Vamos ver o que esses elementos realmente são.

2.1. Serviços

Em primeiro lugar,services refer to containers' configuration.

Por exemplo, vamos pegar um aplicativo da web dockerizado que consiste em um front end, um back end e um banco de dados: provavelmente dividiríamos esses componentes em três imagens e os definiríamos como três serviços diferentes na configuração:

services:
  frontend:
    image: my-vue-app
    ...
  backend:
    image: my-springboot-app
    ...
  db:
    image: postgres
    ...

Existem várias configurações que podemos aplicar aos serviços, e vamos explorá-los profundamente mais tarde.

2.2. Volumes e redes

Volumes, por outro lado, são áreas físicas de espaço em disco compartilhadas entre o host e um contêiner, ou mesmo entre contêineres. Em outras palavras,a volume is a shared directory in the host, visível de alguns ou todos os contêineres.

Da mesma forma,networks define the communication rules between containers, and between a container and the host. As zonas de rede comuns tornarão os serviços dos contêineres detectáveis ​​um pelo outro, enquanto as zonas privadas os separarão em caixas de proteção virtuais.

Mais uma vez, aprenderemos mais sobre eles na próxima seção.

3. Dissecando um serviço

Vamos agora começar a inspecionar as configurações principais de um serviço.

3.1. Puxando uma imagem

Às vezes, a imagem de que precisamos para nosso serviço já foi publicada (por nós ou por outros) emDocker Hub, ou outro Docker Registry.

Se for esse o caso, então nos referimos a ele com o atributoimage, especificando o nome da imagem e tag:

services:
  my-service:
    image: ubuntu:latest
    ...

3.2. Construindo uma imagem

Em vez disso, podemos precisarbuild uma imagem do código-fonte lendo seuDockerfile.

Desta vez, usaremos a palavra-chavebuild, passando o caminho para o Dockerfile como o valor:

services:
  my-custom-app:
    build: /path/to/dockerfile/
    ...

Também podemosuse a URL em vez de um caminho:

services:
  my-custom-app:
    build: https://github.com/my-company/my-project.git
    ...

Além disso, podemos especificar um nomeimage em conjunto com o atributobuild, que nomeará a imagem uma vez criada,making it available to be used by other services:

services:
  my-custom-app:
    build: https://github.com/my-company/my-project.git
    image: my-project-image
    ...

3.3. Configurando a rede

Docker containers communicate between themselves in networks created, implicitly or through configuration, by Docker Compose. Um serviço pode se comunicar com outro serviço na mesma rede simplesmente referenciando-o pelo nome do contêiner e porta (por exemplonetwork-example-service:80), desde que tenhamos tornado a porta acessível por meio da palavra-chaveexpose:

services:
  network-example-service:
    image: karthequian/helloworld:latest
    expose:
      - "80"

Nesse caso, aliás, também funcionaria sem expô-lo, porque a diretivaexpose já está emthe image Dockerfile.

To reach a container from the host,the ports must be exposed declaratively through the ports keyword, o que também nos permite escolher se expor a porta de forma diferente no host:

services:
  network-example-service:
    image: karthequian/helloworld:latest
    ports:
      - "80:80"
    ...
  my-custom-app:
    image: myapp:latest
    ports:
      - "8080:3000"
    ...
  my-custom-app-replica:
    image: myapp:latest
    ports:
      - "8081:3000"
    ...

A porta 80 agora estará visível no host, enquanto a porta 3000 dos outros dois contêineres estará disponível nas portas 8080 e 8081 no host. This powerful mechanism allows us to run different containers exposing the same ports without collisions.

Por fim, podemos definir redes virtuais adicionais para segregar nossos contêineres:

services:
  network-example-service:
    image: karthequian/helloworld:latest
    networks:
      - my-shared-network
    ...
  another-service-in-the-same-network:
    image: alpine:latest
    networks:
      - my-shared-network
    ...
  another-service-in-its-own-network:
    image: alpine:latest
    networks:
      - my-private-network
    ...
networks:
  my-shared-network: {}
  my-private-network: {}

Neste último exemplo, podemos ver queanother-service-in-the-same-network será capaz de fazer ping e alcançar a porta 80 denetwork-example-service, enquantoanother-service-in-its-own-network não.

3.4. Configurando os Volumes

Existem três tipos de volumes:anonymous, named, and host.

Docker manages both anonymous and named volumes, montando-os automaticamente em diretórios autogerados no host. Embora os volumes anônimos sejam úteis nas versões mais antigas do Docker (anteriores à 1.9), os nomeados são o caminho sugerido atualmente. Host volumes also allow us to specify an existing folder in the host.

Podemos configurar volumes de host no nível de serviço e volumes nomeados no nível externo da configuração, a fim de torná-lo visível para outros contêineres e não apenas para o que eles pertencem:

services:
  volumes-example-service:
    image: alpine:latest
    volumes:
      - my-named-global-volume:/my-volumes/named-global-volume
      - /tmp:/my-volumes/host-volume
      - /home:/my-volumes/readonly-host-volume:ro
    ...
  another-volumes-example-service:
    image: alpine:latest
    volumes:
      - my-named-global-volume:/another-path/the-same-named-global-volume
    ...
volumes:
  my-named-global-volume:

Aqui, os dois contêineres terão acesso de leitura / gravação à pasta compartilhadamy-named-global-volume, não importando os caminhos diferentes para os quais a mapearam. Os dois volumes de host, em vez disso, estarão disponíveis apenas paravolumes-example-service.

A pasta/tmp do sistema de arquivos do host é mapeada para a pasta/my-volumes/host-volume do contêiner. Esta parte do sistema de arquivos é gravável, o que significa que o contêiner pode não apenas ler, mas também gravar (e excluir) arquivos na máquina host.

We can mount a volume in read-only mode by appending :ro para a regra, como para a pasta/home (não queremos um contêiner do Docker apagando nossos usuários por engano).

3.5. Declarando as dependências

Freqüentemente, precisamos criar uma cadeia de dependência entre nossos serviços, para que alguns serviços sejam carregados antes (e descarregados depois) de outros. Podemos alcançar esse resultado por meio da palavra-chavedepends_on:

services:
  kafka:
    image: wurstmeister/kafka:2.11-0.11.0.3
    depends_on:
      - zookeeper
    ...
  zookeeper:
    image: wurstmeister/zookeeper
    ...

Devemos estar cientes, entretanto, que o Compose não irá esperar que o serviçozookeeper termine de carregar antes de iniciar o serviçokafka: ele simplesmente esperará que ele inicie. Se precisarmos que um serviço seja totalmente carregado antes de iniciar outro serviço, precisamos obterdeeper control of startup and shutdown order in Compose.

4. Gerenciando Variáveis ​​de Ambiente

Trabalhar com variáveis ​​de ambiente é fácil no Compose. Podemos definir variáveis ​​de ambiente estáticas e também definir variáveis ​​dinâmicas com a notação$\{}:

services:
  database:
    image: "postgres:${POSTGRES_VERSION}"
    environment:
      DB: mydb
      USER: "${USER}"

Existem métodos diferentes para fornecer esses valores para Compor.

Por exemplo, eles estão configurados em um arquivo.env no mesmo diretório, estruturado como um arquivo.properties,key=value:

POSTGRES_VERSION=alpine
USER=foo

Caso contrário, podemos configurá-los no sistema operacional antes de chamar o comando:

export POSTGRES_VERSION=alpine
export USER=foo
docker-compose up

Finalmente, podemos achar útil usar uma linha simples no shell:

POSTGRES_VERSION=alpine USER=foo docker-compose up

Podemos misturar as abordagens, mas vamos ter em mente que o Compose usa a seguinte ordem de prioridade, substituindo as menos importantes pelas mais altas:

  1. Redigir arquivo

  2. Variáveis ​​de ambiente do shell

  3. Arquivo de ambiente

  4. Dockerfile

  5. Variável não definida

5. Dimensionamento e réplicas

Em versões anteriores do Compose, tínhamos permissão para dimensionar as instâncias de um contêiner por meio do comandodocker-compose scale. Versões mais recentes o tornaram obsoleto e o substituíram pela opção––scale.

Por outro lado, podemos explorarDocker Swarm - um cluster de Docker Engines - e escalonar automaticamente nossos contêineres declarativamente por meio do atributoreplicas da seçãodeploy:

services:
  worker:
    image: dockersamples/examplevotingapp_worker
    networks:
      - frontend
      - backend
    deploy:
      mode: replicated
      replicas: 6
      resources:
        limits:
          cpus: '0.50'
          memory: 50M
        reservations:
          cpus: '0.25'
          memory: 20M
      ...

Emdeploy,, também podemos especificar muitas outras opções, como os limites de recursos. Componha, no entanto,considers the whole deploy section only when deploying to Swarm e ignora o contrário.

6. Um exemplo do mundo real: Spring Cloud Data Flow

Embora pequenas experiências nos ajudem a entender as mudanças individuais, ver o código do mundo real em ação definitivamente revelará o cenário geral.

O Spring Cloud Data Flow é um projeto complexo, mas simples o suficiente para ser compreensível. Vamosdownload its YAML filee executar:

DATAFLOW_VERSION=2.1.0.RELEASE SKIPPER_VERSION=2.0.2.RELEASE docker-compose up

O Compose baixará, configurará e iniciará todos os componentes e, em seguida,intersect the container’s logs into a single flow in the current terminal.

Ele também aplicará cores exclusivas a cada um deles para uma ótima experiência do usuário:

image

Podemos receber o seguinte erro ao executar uma nova instalação do Docker Compose:

lookup registry-1.docker.io: no such host

Emborathere are different solutions para essa armadilha comum, usar8.8.8.8 como DNS é provavelmente o mais simples.

7. Gerenciamento do ciclo de vida

Vamos finalmente dar uma olhada na sintaxe do Docker Compose:

docker-compose [-f ...] [options] [COMMAND] [ARGS...]

Embora existammany options and commands available, precisamos pelo menos saber aqueles para ativar e desativar todo o sistema corretamente.

7.1. Comece

Vimos que podemos criar e iniciar os contêineres, as redes e os volumes definidos na configuração comup:

docker-compose up

Após a primeira vez, no entanto, podemos simplesmente usarstart para iniciar os serviços:

docker-compose start

Caso nosso arquivo tenha um nome diferente do padrão (docker-compose.yml), podemos explorar os sinalizadores-fe––file para especificar um nome de arquivo alternativo:

docker-compose -f custom-compose-file.yml start

O Compose também pode ser executado em segundo plano como um daemon quando iniciado com a opção-d:

docker-compose up -d

7.2. Desligar

Para interromper com segurança os serviços ativos, podemos usarstop, que preservará contêineres, volumes e redes, junto com todas as modificações feitas neles:

docker-compose stop

Para redefinir o status do nosso projeto, em vez disso, simplesmente executamosdown,which will destroy everything with only the exception of external volumes:

docker-compose down

8. Conclusão

Neste tutorial, aprendemos sobre o Docker Compose e como ele funciona.

Como de costume, podemos encontrar o arquivo de origemdocker-compose.ymlon GitHub, junto com uma bateria útil de testes imediatamente disponível na seguinte imagem:

image