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
RUNvocê pode utilizar basicamente qualquer comando bash; nesse caso, estamos instalando o pacotetree(basicamente umlsque verifica as subpastas).
RUN mkdir -p test/nested && \
cd test && \
touch nested/a.txt b.txt
Para verificar o comando
treeem 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
cdna linha passada, ao utilizarmos os comandospwdelsverificamos que retornamos ao endereço base; isso porque cada comandoRUNé executado a partir doWORKDIRatual.
CMD ["echo", "Hello World!"]
O comando
CMDdistingue-se doRUNpor 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
-tserve 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
WORKDIRfunciona como ummkdir(se necessário) +cd(modificando o contexto ao longo de toda a imagem)
Entao, o comandotreepoderia ser utilizado no contexto atual., já que oWORKDIRdessa imagem não é mais o caminho base/, e, sim, o caminho/test/