Resumão Docker
Tempo estimado de leitura: 4min
Disclaimer: esse capítulo (de introdução) é 100% baseado nesse vídeo ->
Problema
Suponha que voce está desenvolvendo um app em Cobol, que roda numa plataforma Linux aleatória (ex: archlinux), e você deseja compartilhar esse app com seu amigo; entretanto, ele utiliza um sistema totalmente diferente (ex: debian, windows 7, etc)...
Então, surge a questão:
Como replicar esse ambiente que meu app precisa em qualquer computador?
Máquinas Virtuais
Uma das soluções possíveis é utilizar uma Virtual Machine (e existem varias opções para isso, como: VirtualBox, Vmware, GnomeBoxes, Qemu, dentre outros)
O que são máquinas virtuais? São computadores completos: possuem CPU, memória RAM, disco rigido, sistema operacional, arquivos, aplicativos... tudo. Mas, tudo isso é virtual/simulado, utilizando recursos do computador físico/servidor "real" -- também conhecido como Host.
Então, a idéia seria: um simulador de computador que será configurado de forma igual (idealmente) pelos devs do projeto, utilizando um mesmo sistema operacional e instalando as dependencias necessárias pro projeto.
exemplo: todos instalam uma VM usando Manjaro, instalam os pacotes g++, libncurses etc (qualquer app/dependencia necessária pra rodar aquele projeto)
Mas... isso não é muito escalável quando se considera uma organização com múltiplos apps sendo desenvolvidos simultaneamente, por exemplo. Como as VMs tendem a ser pesadas (tanto em consumo de recursos computacionais do computador [real], como na performance individual), essa opção se torna meio inviável
Docker ao resgate
obs: existem outras opções surgindo atualmente, como o Podman (da Redhat); mas, no geral, container = Docker
Um Container de Docker é conceitualmente muito similar a uma VM, com uma distinção chave: em vez de virtualizar o Hardware (um computador inteiro), os Containers virtualizam apenas o S.O.; ou seja, todos os apps (ou, Containers) são executados por um único Kernel
É isso que torna a utilização de Docker tão mais rápida, flúida e eficiente.
Estrutura básica do Docker
Existem 3 pilares que constituem o universo de Docker:
Dockerfile
Este arquivo é como o DNA: um código que especifica ao Docker como ele deve buildar uma imagem
.
Imagem
A imagem é um snapshot da sua aplicação: contém desde as dependencias do seu projeto (ex: pacotes npm etc) até o "sistema operacional". Vale ressaltar que essa imagem é imutavel, e pode ser utilizada para construir múltiplos containers
.
Container
É a instancia em execução, criada a partir da imagem.
fazendo um paralelo com OO: img = classe; container = objeto [instancia da classe]
Exemplo Mínimo
Não é necessário reproduzir esses comandos, já que praticaremos isso junto no segundo sub-capítulo.
A partir desse Dockerfile
de exemplo:
FROM ubuntu:20.04
Como um "import"; é uma imagem pré-definida que será utilizada como base nesse arquivo. Essa imagem é "puxada" do docker hub; essa imagem em específico se refere a este Dockerfile.
Existem N imagens pré-definidas, que podem ser utilizadas de acordo com a necessidade do seu projeto. Por exemplo: Python, Ruby, Node, dentre outras infinitas possibilidades.
Normalmente, quando há de se partir de uma imagem de um S.O. mais básico (como esse caso do exemplo), há uma certa preferência para a distribuição Alpine em vez de Ubuntu, por exemplo, por se tratar de uma distribuição mais minimalista.
RUN apt-get update -y && apt-get install -y tree
Com o comando
RUN
você pode utilizar basicamente qualquer comando bash; nesse caso, estamos instalando o pacotetree
(basicamente umls
que verifica as subpastas).
RUN mkdir -p test/nested && \
cd test && \
touch nested/a.txt b.txt
Para verificar o comando
tree
em ação, dentro dessa imagem, a partir do endereço base/
, criamos uma pasta aleatoria e outra subpasta; entramos* na pasta criada, e criamos dois arquivos.
RUN echo "current path: `pwd`"
RUN ls --format=across
RUN tree test/
Mesmo utilizando o comando
cd
na linha passada, ao utilizarmos os comandospwd
els
verificamos que retornamos ao endereço base; isso porque cada comandoRUN
é executado a partir doWORKDIR
atual.
CMD ["echo", "Hello World!"]
O comando
CMD
distingue-se doRUN
por se tratar de um comando que sera rodado ao executarmos um container; ou seja, no processo de build da imagem, este comando não é executado.
Então, ao executarmos o comando de build:
$ docker build -t exemplo_minimo .
A flag
-t
serve pra especificar o nome da imagem que será construída
Após isso, podemos finalmente executar essa imagem (iniciando um container):
Observação:
A linha de criação de pastas etc poderia ser reescrita da seguinte forma:
WORKDIR test
RUN mkdir nested
RUN touch nested/a.txt b.txt
O comando
WORKDIR
funciona como ummkdir
(se necessário) +cd
(modificando o contexto ao longo de toda a imagem)
Entao, o comandotree
poderia ser utilizado no contexto atual.
, já que oWORKDIR
dessa imagem não é mais o caminho base/
, e, sim, o caminho/test/