1.5 Dockerfile, Imagem e Contêiner Docker

Esta seção apresenta conceitos básicos relacionados com a terminologia Docker. A figura a seguir, extraída de Anil et al. (2022), ilustra de forma simplificada a relação entre os termos (taxonomia básica do Docker.

Taxonomia básica do Docker (extraído de Anil et al. (2022).

Uma maneira simplificada de compreender a figura acima é associar os conceitos de imagem e contêiner com Orientação a Objetos. Nessa comparação, as imagens Docker seria as classes, ou seja, o molde a partir do qual objetos (contêineres) são criados. Ou seja, uma imagem Docker nada mais é do que uma representação estática que viabiliza a construção de contêineres. Um contêiner é uma instância de uma imagem em execução. Uma imagem pode dar origem a vários contêineres e um contêiner é uma instância de uma imagem.

Para facilitar o armazenamento e busca por imagens Docker existem os registradores de imagens (Registry). Esses registradores são serviços disponíveis em núvens públicas ou privadas. O próprio Docker oferece um serviço público, denominado Docker Hub, que será descrito em mais detalhes na Seção 1.6, e também serviços de registry privado. Outras empresas, como Azure, Google e AWS também oferecem serviços de registry públicos.

Crindo Imagem Docker: Dockerfile

O processo de criação de uma imagem Docker passa pela edição de um arquivo denominado de Dockerfile. O exemplo a seguir, extraído de https://hub.docker.com/_/python, ilustra um Dockerfile para configuração de uma aplicação Python. Como pode ser observado, um Dockerfile nada mais é do que uma receita de como uma imagem deve ser construída.

Conteúdo do arquivo Dockerfile

No exemplo acima, a "receita" diz o seguinte:

A partir da imagem do "python:3" (FROM python:3), defina como diretório de trabalho na imagem a pasta /usr/src/app (WORKDIR /usr/src/app). Em seguida, copie o arquivo requirements.txt, localizado na pasta local, junto com este arquivo Dockerfile, para a pasta /usr/src/app da imagem (COPY requirements.txt ./).

Na sequência, execute o comando pip para instalar a lista de bibliotecas Python presentes em requirements.txt (RUN pip install --no-cache-dir -r requirements.txt).

Finalmente, copie todo o restante dos arquivos da pasta local para a pasta /usr/src/app da imagem (COPY . .) e execute o comando python passando como parâmetro o arquivo ./your-daemon-or-script.py (CMD [ "python", "./script.py" ]).

Conteúdo do arquivo requirements.txt

Conteúdo do arquivo script.py

Considerando que esses três arquivos estão juntos em um diretório, o processo de construção de uma imagem é realizado por meio do comando docker build. No comando a seguir, o parâmetro -t (--tag) permite atribuir um nome para a imagem sendo criada e o "." indica que o Dockerfile para a construção da imagem deve ser procurado no diretório corrente.

O resultado da primeira execução do comando de build faz com que as várias camadas que irão compor a imagem solicitada sejam baixadas e combinadas. O resultado abaixo ilustra esse processo:

Numa segunda execução do mesmo comando em sequência, como as partes que compõem a imagem já estão disponíveis localmente, não há a necessidade de buscá-las no registry e, desse modo, o processo de construção é acelerado. Com esse recurso de construção de imagens por camadas ganha-se em desempenho e se permite um melhor reaproveitamento das camadas já disponíveis.

O comando docker images -a permite consultar as camadas disponíveis localmente, inclusive as camadas intermediárias que compõem a imagem:

De forma genérica pode se dizer que cada linha do Dockerfile contendo alguma instrução que irá agregar recursos na imagem fará com que uma nova camada seja sobreposta a anterior compondo a imagem desejada.

Dado que exista a imagem de um contêiner para realizar a tarefa que se deseja, basta solicitar a execução de um contêiner a partir da imagem desejada. Para se criar um contêiner a partir da imagem criada basta utilizar o comando docker run. No exemplo a seguir, o parâmetro --rm indica que o contêiner deve ser removido ao final de sua execução.

Opcionalmente, executado o comando acima sem o --rm fará com que o contêiner, após finalizar sua execução, continue disponível para execução futura e pode ser consultado por meio do comando docker ps -a.

Observa-se que, caso não seja nomeado no comando docker run, o Docker atribui um nome genérico para cada contêiner executado que pode ser utilizado para referenciá-lo no futuro (coluna NAMES). Cada contêiner também recebe um ID único (coluna CONTAINER ID).

Por exemplo, os comandos a seguir, são equivalentes: os dois primeiros reexecutam o contêiner com base no seu ID e os dois últimos utilizando o nome.

O comando docker start reinicia o contêiner em segundo plano e o comando docker attach anexa o terminal à saída padrão stdin, permitindo visualizar o resultado da execução.

Last updated