Recomendações para usar Docker

Docker mudou nossa forma de desenvolver software. Ele permite simplificar os ambientes de desenvolvimento e as implantações, mas é fácil cair em armadilhas ao escrever seus primeiros Dockerfiles. Estas práticas nos ajudaram a amenizar problemas comuns quando começamos a usar Docker.
Não crie várias imagens para o mesmo software.
Uma grande vantagem de usar Docker para construir, executar e implantar aplicações é ter um ambiente de execução consistente. Assim, você garante que o software de produção seja o mesmo do servidor de staging, por exemplo, simplificando a implantação e os testes.
Um erro comum ao começar a criar contêineres Docker é empacotar arquivos de configuração ou parâmetros de execução junto com o software. Você provavelmente precisará de uma imagem diferente para cada ambiente, anulando parte dos benefícios de conteinerizar a aplicação.
Argumentos de linha de comando
Se você precisa passar argumentos diferentes ao programa conforme o ambiente, pode usar a diretiva ENTRYPOINT para executá-lo e fornecer os argumentos necessários, por exemplo:
# Dockerfile
FROM ubuntu:18.04
ENTRYPOINT ["ls"]
CMD ["-shl", "/"]
Agora você pode construir e executar assim:
$ docker build --tag myls .
$ docker run myls
$ docker run myls -la /bin
Como você vê, podemos usar o contêiner como se fosse o utilitário ls. Também podemos fornecer parâmetros padrão pela diretiva CMD.
Arquivos de configuração e variáveis de ambiente
Variáveis de ambiente costumam ser a solução habitual para configurações. Você pode defini-las uma a uma pela CLI do Docker ou usar um arquivo de variáveis de ambiente, por exemplo:
# Dockerfile
FROM ubuntu:18.04
CMD ["sh", "-c", "echo ${SOME_TEXT} ${SOME_OTHER_TEXT}"]
Construa e execute:
$ docker build --tag myecho .
$ docker run -e SOME_TEXT=Hello -e SOME_OTHER_TEXT=World myecho
Hello World
Você também pode usar um arquivo de variáveis de ambiente em vez de passá-las uma a uma:
# file.env
SOME_TEXT=Hello,
SOME_OTHER_TEXT=Bob
$ docker run --env-file file.env myecho
Hello, Bob
Às vezes, o software precisa de um arquivo de configuração dentro do contêiner. Você pode fazer isso sem empacotá-lo junto com o programa, por exemplo:
# Dockerfile
FROM ubuntu:18.04
CMD ["sh", "-c", "cat /config.txt"]
# config-pro.txt
Production config file :D
$ docker build --tag myconfig .
$ docker run -v /full/path/to/config-pro.txt:/config.txt myconfig
Production config file :D
Talvez você queira usar um diretório de configuração em vez de um arquivo, por exemplo:
# Dockerfile
FROM ubuntu:18.04
CMD ["sh", "-c", "cat /config/*.txt"]
Agora crie uma pasta chamada my-config e escreva dois arquivos nela.
# a.txt
This is file A
# b.txt
This is file B
$ docker build --tag mydir .
$ docker run -v /full/path/to/my-config:/config mydir
This is file A
This is file B
Ambiente local
O ambiente local costuma ser uma exceção a essa regra. Ao desenvolver software, você precisa passar rapidamente da escrita do código à execução do programa. Isso geralmente exige versões de desenvolvimento das dependências, compilar em modo Debug e possivelmente executar os programas em modos diferentes.
Você consegue isso com compilações de múltiplos estágios. Um único Dockerfile permite construir, executar e testar a versão de desenvolvimento, além de criar a imagem final de produção.
Escreva seus logs em stdout e/ou stderr.
A aplicação deve escrever seus logs em stdout sempre que possível. Isso facilita inspecionar a saída e coletar logs no banco de dados que você escolher. Docker coleta automaticamente o que é escrito em stdout ou stderr em um arquivo JSON específico do contêiner, que você pode inspecionar com o comando docker logs <container-id>.
Evite logs com várias linhas: são difíceis de agrupar e complicam a busca por valores importantes.
Modifique como sua linguagem ou framework exibe exceções, erros e rastreamentos de pilha, algo para o qual a maioria oferece um mecanismo, para mostrar todas as informações necessárias em uma única linha. Considere exibi-los como strings JSON.
Use compilações de múltiplos estágios.
Compilações de múltiplos estágios permitem usar um único Dockerfile para compilar o software e criar a imagem final do Docker. Isso ajuda a reduzir o tamanho dos contêineres e simplifica a compilação. A documentação do Docker explica muito bem esse recurso: compilações de múltiplos estágios.
Com esses conselhos simples, você poderá criar contêineres fáceis de gerenciar e usar em vários ambientes, desde uma arquitetura implantada sob medida até clusters Kubernetes com grande capacidade de escalar.