Docker 101: fundamentos e prática
Se você está cansado de ouvir seus colegas de trabalho elogiarem o Docker e seus benefícios a cada chance que eles têm, ou está cansado de balançar a cabeça e ir embora toda vez que se encontra em uma dessas conversas, você veio para a direita Lugar, colocar.
Além disso, se você está procurando uma nova desculpa para vagar sem ser demitido, continue lendo e você me agradecerá mais tarde.

Docker
Esta é a definição de Docker, de acordo com a Wikipedia:
Docker é um programa de computador que realiza virtualização em nível de sistema operacional.Muito simples, certo? Bem, não exatamente. Tudo bem, aqui está minha definição do que é docker:
Docker é uma plataforma para criar e executar contêineres a partir de imagens .Ainda perdido? Não se preocupe, porque provavelmente você não sabe o que são contêineres ou imagens .
As imagens são arquivos únicos contendo todas as dependências e configurações necessárias para executar um programa, enquanto os contêineres são as instâncias dessas imagens. Vamos ver um exemplo disso na prática para deixar as coisas mais claras.
Observação importante: antes de continuar, certifique-se de instalar o docker usando as etapas recomendadas para o seu sistema operacional.Parte 1. "Olá, mundo!" de uma imagem Python
Digamos que você não tenha o Python instalado em sua máquina - ou pelo menos não a versão mais recente - e precise do python para imprimir "Hello, World!" em seu terminal. O que você faz? Você usa o docker!
Vá em frente e execute o seguinte comando:
docker run --rm -it python:3 python
Não se preocupe, explicarei esse comando em um segundo, mas agora você provavelmente está vendo algo assim:

Isso significa que estamos dentro de um contêiner do docker criado a partir de uma imagem do docker do Python 3 , executando o python
comando. Para finalizar o exemplo, digite print("Hello, World!")
e observe a mágica acontecer.

Tudo bem, você conseguiu, mas antes de começar a dar tapinhas nas próprias costas, vamos dar um passo para trás e entender como isso funcionou.
Quebrando isso
Vamos começar do começo. O docker run
comando é a ferramenta padrão do docker para ajudá-lo a iniciar e executar seus contêineres.
O --rm
sinalizador está lá para dizer ao Docker Daemon para limpar o contêiner e remover o sistema de arquivos após a saída do contêiner. Isso ajuda a economizar espaço em disco depois de executar containers de curta duração como este, que apenas começamos a imprimir "Hello, World!".
O -t (or --tty)
sinalizador diz ao Docker para alocar uma sessão de terminal virtual dentro do contêiner. Isso é comumente usado com a -i (or --interactive)
opção, que mantém o STDIN aberto, mesmo se executando no modo separado (mais sobre isso mais tarde).
-it
sinalizador sempre que quiser digitar alguns comandos no seu contêiner.
Por último, python:3
é a imagem base que usamos para este contêiner. No momento, esta imagem vem com o python versão 3.7.3 instalado, entre outras coisas. Agora, você deve estar se perguntando de onde veio essa imagem e o que há dentro dela. Você pode encontrar as respostas para essas duas perguntas aqui, junto com todas as outras imagens python que poderíamos ter usado neste exemplo.
Por último, mas não menos importante, python
foi o comando que pedimos ao Docker para executar dentro de nossa python:3
imagem, que iniciou um shell Python e permitiu que nossa print("Hello, World!")
chamada funcionasse.
Mais uma coisa
Para sair do python e encerrar nosso contêiner, você pode usar CTRL / CMD + D ou exit()
. Vá em frente e faça isso agora. Depois disso, tente executar nosso docker run
comando novamente e você verá algo um pouco diferente e muito mais rápido.

Isso porque já baixamos a python:3
imagem, então nosso contêiner inicia muito mais rápido agora.
Parte 2. Automatizado "Hello World!" de uma imagem Python
O que é melhor do que escrever "Hello, World!" no seu terminal uma vez? Você entendeu, escrevendo duas vezes!
Já que não podemos esperar para ver "Hello, World!" impresso em nosso terminal novamente, e não queremos passar pela confusão de abrir o python e digitar print
novamente, vamos prosseguir e automatizar um pouco esse processo. Comece criando um hello.py
arquivo onde desejar.
# hello.py
print("Hello, World!")
Em seguida, vá em frente e execute o seguinte comando dessa mesma pasta.
docker run --rm -it -v $(pwd):/src python:3 python /src/hello.py
Este é o resultado que procuramos:

ls
antes do comando para mostrar que estava na mesma pasta em que criei o
hello.py
arquivo.
Como fizemos antes, vamos dar um passo atrás e entender como isso funcionou.
Quebrando isso
Estamos executando praticamente o mesmo comando que executamos na última seção, exceto por duas coisas.
A -v $(pwd):/src
opção diz ao Docker Daemon para iniciar um volume em nosso contêiner . Os volumes são a melhor maneira de persistir os dados no Docker. Neste exemplo, estamos dizendo ao Docker que queremos que o diretório atual - recuperado de $(pwd)
- seja adicionado ao nosso contêiner na pasta /src
.
/src
Se você quiser verificar se /src/hello.py
realmente existe dentro do nosso contêiner, você pode alterar o final do nosso comando de python hello.py
para bash
. Isso abrirá um shell interativo dentro de nosso contêiner, e você pode usá-lo como esperava.

bash
aqui porque vem pré-instalado na
python:3
imagem. Algumas imagens são tão simples que nem têm
bash
. Isso não significa que você não pode usá-lo, mas você mesmo terá que instalá-lo, se quiser.
A última parte do nosso comando é a python /src/hello.py
instrução. Ao executá-lo, estamos dizendo ao nosso contêiner para olhar dentro de sua /src
pasta e executar o hello.py
arquivo usando python
.
Talvez você já possa ver as maravilhas que pode fazer com este poder, mas vou destacá-lo de qualquer maneira. Usando o que acabamos de aprender, podemos executar praticamente qualquer código de qualquer linguagem dentro de qualquer computador sem precisar instalar nenhuma dependência na máquina host - exceto para Docker, é claro.É muito texto em negrito para uma frase, então certifique-se de lê-lo duas vezes!
Parte 3. Mais fácil "Olá, mundo!" possível a partir de uma imagem Python usando Dockerfile
Você já está cansado de dizer olá ao nosso lindo planeta? É uma pena, porque vamos fazer de novo!
O último comando que aprendemos foi um pouco prolixo, e já posso me ver ficando cansado de digitar todo aquele código toda vez que quero dizer "Olá, mundo!" Vamos automatizar um pouco mais as coisas agora. Crie um arquivo chamado Dockerfile
e adicione o seguinte conteúdo a ele:
# Dockerfile
FROM python:3
WORKDIR /src/app
COPY . .
CMD [ "python", "./hello.py" ]
Agora execute este comando na mesma pasta em que criou Dockerfile
:
docker build -t hello .
Tudo o que resta a fazer agora é enlouquecer usando este código:
docker run hello

Você já sabe como é. Vamos entender como um Dockerfile funciona agora.
Quebrando isso
Começando com nosso Dockerfile, a primeira linha FROM python:3
diz ao Docker para iniciar tudo com a imagem base com a qual já estamos familiarizados python:3
,.
A segunda linha WORKDIR /src/app
,, define o diretório de trabalho dentro de nosso contêiner. Isso é para algumas instruções que executaremos posteriormente, como CMD
ou COPY
. Você pode ver o resto das instruções com suporte para WORKDIR
aqui.
A terceira linha COPY . .
basicamente diz ao Docker para copiar tudo de nossa pasta atual (primeiro .
) e colá-lo /src/app
(segundo .
). O local da colagem foi definido com o WORKDIR
comando logo acima.
WORKDIR
instrução e substituindo-a
COPY . .
por
COPY . /src/app
. Nesse caso, também precisaríamos alterar a última instrução
CMD ["python", "./hello.py"]
para
CMD ["python", "/src/app/hello.py"]
.
Finalmente, a última linha CMD ["python", "./hello.py"]
fornece o comando padrão para nosso contêiner. Basicamente, está dizendo que toda vez que run
um contêiner a partir dessa configuração, ele deve ser executado python ./hello.py
. Lembre-se de que estamos executando implicitamente em /src/app/hello.py
vez de apenas hello.py
, uma vez que é para onde apontamos WORKDIR
.
CMD
comando pode ser substituído em tempo de execução. Por exemplo, se você quiser executar em
bash
vez disso, faça
docker run hello bash
depois de construir o contêiner.
Com nosso Dockerfile concluído, vamos em frente e iniciamos nosso build
processo. O docker build -t hello .
comando lê toda a configuração que adicionamos ao nosso Dockerfile e cria uma imagem docker a partir dela. Isso mesmo, assim como a python:3
imagem que usamos para todo este artigo. O .
no final informa ao Docker que queremos executar um Dockerfile em nosso local atual e a -t hello
opção dá o nome a essa imagem hello
, para que possamos referenciá-la facilmente no tempo de execução.
Depois de tudo isso, tudo o que precisamos fazer é executar a docker run
instrução usual , mas desta vez com o hello
nome da imagem no final da linha. Isso iniciará um contêiner a partir da imagem que construímos recentemente e, finalmente, imprimirá o bom e velho "Hello, World!" em nosso terminal.
Ampliando nossa imagem de base
O que faremos se precisarmos de alguma dependência para executar nosso código que não vem pré-instalado com nossa imagem base? Para resolver esse problema, docker tem as RUN
instruções.
Seguindo nosso exemplo python, se precisássemos da numpy
biblioteca para executar nosso código, poderíamos adicionar a RUN
instrução logo após nosso FROM
comando.
# Dockerfile
FROM python:3
# NEW LINERUN pip3 install numpy
WORKDIR /src/app
COPY . .
CMD [ "python", "./hello.py" ]
A RUN
instrução basicamente dá um comando a ser executado pelo terminal do contêiner. Assim, como nossa imagem base já vem com pip3
instalada, podemos usar pip3 install numpy
.
requirements.txt
arquivo, copie-o para o recipiente, em seguida, atualizar a
RUN
instrução para
RUN pip3 install -r requirements.txt
.
Parte 4. "Olá, mundo!" de uma imagem Nginx usando um contêiner desanexado de longa duração
Sei que você provavelmente está cansado de me ouvir dizer isso, mas tenho mais um "olá" para dizer antes de ir. Vamos seguir em frente e usar nosso docker power recém-adquirido para criar um contêiner simples de longa duração, em vez dos de curta duração que usamos até agora.
Crie um index.html
arquivo em uma nova pasta com o seguinte conteúdo.
# index.html
Hello, World!
Agora, vamos criar um novo Dockerfile na mesma pasta.
# Dockerfile
FROM nginx:alpine
WORKDIR /usr/share/nginx/html
COPY . .
Construa a imagem e dê um nome a ela simple_nginx
, como fizemos anteriormente.
docker build -t simple_nginx .
Por último, vamos executar nossa imagem recém-criada com o seguinte comando:
docker run --rm -d -p 8080:80 simple_nginx
Você pode estar pensando que nada aconteceu porque você voltou ao seu terminal, mas vamos dar uma olhada mais de perto com o docker ps
comando.

O docker ps
comando mostra todos os contêineres em execução em sua máquina. Como você pode ver na imagem acima, tenho um contêiner chamado simple_nginx
em execução na minha máquina agora. Vamos abrir um navegador da web e ver se nginx
funciona acessando localhost:8080
.

Tudo parece estar funcionando conforme o esperado e estamos servindo uma página estática por meio da nginx
execução em nosso contêiner. Vamos dedicar um momento para entender como conseguimos isso.
Quebrando isso
Vou pular a explicação do Dockerfile porque já aprendemos esses comandos na última seção. A única coisa "nova" nessa configuração é a nginx:alpine
imagem, sobre a qual você pode ler mais aqui.
Além do que é novo, essa configuração funciona porque nginx
usa a usr/share/nginx/html
pasta para procurar um index.html
arquivo e começar a exibi-lo, portanto, como nomeamos nosso arquivo index.html
e configuramos o WORKDIR
para ser usr/share/nginx/html
, essa configuração funcionará imediatamente.
O build
comando é exatamente igual ao que usamos na última seção, estamos usando apenas a configuração do Dockerfile para construir uma imagem com um determinado nome.
Agora, a parte divertida, a docker run --rm -d -p 8080:80 simple_nginx
instrução. Aqui temos duas novas bandeiras. O primeiro é o -d
sinalizador detached ( ), o que significa que queremos executar este contêiner em segundo plano, e é por isso que estamos de volta ao nosso terminal logo após usar o docker run
comando, embora nosso contêiner ainda esteja em execução.
A segunda nova bandeira é a -p 8080:80
opção. Como você deve ter adivinhado, este é o port
sinalizador e basicamente está mapeando a porta 8080
de nossa máquina local para a porta 80
dentro de nosso contêiner. Você poderia ter usado qualquer outra porta em vez de 8080
, mas não pode alterar a porta 80
sem adicionar uma configuração adicional à nginx
imagem, uma vez que 80
é a porta padrão que a nginx
imagem expõe.
docker ps
comando para obter o
nome do contêiner (não imagem) e, em seguida, usar a
docker stop
instrução com o nome do contêiner desejado no final da linha.
Parte 5. O fim
É isso aí! Se você ainda está lendo isso, você tem todos os fundamentos para começar a usar o Docker hoje em seus projetos pessoais ou no trabalho diário.
Deixe-me saber o que você achou deste artigo nos comentários, e eu irei escrever um artigo de acompanhamento cobrindo tópicos mais avançados, como docker-compose
em algum lugar no futuro próximo.
Se você tiver alguma dúvida, por favor me avise.
Felicidades!