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.
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.
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
parse
realpython-reader
Conteúdo do arquivo script.py
# script.py
import parse
from reader import feed
tutorial = feed.get_article(1)
headlines = [
r.named["header"]
for r in parse.findall("\n## {header}\n", tutorial)
]
print("\n".join(headlines))
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:
$ docker build -t python:sample .
Sending build context to Docker daemon 4.096kB
Step 1/6 : FROM python:3
3: Pulling from library/python
5492f66d2700: Pull complete
540ff8c0841d: Pull complete
a0bf850a0df0: Pull complete
d751dc38ae51: Pull complete
9720a112e886: Pull complete
f97b81fbdbd9: Pull complete
a70c58953c25: Pull complete
6f7b858c1584: Pull complete
74b4b07d81e4: Pull complete
Digest: sha256:6441e2f0bd2e566de0df6445cb8e7e395ea1a376dd702de908d70401d3700961
Status: Downloaded newer image for python:3
---> ee2a4300ffa2
Step 2/6 : WORKDIR /usr/src/app
---> Running in e7464a2483a6
Removing intermediate container e7464a2483a6
---> c311c48f19db
Step 3/6 : COPY requirements.txt ./
---> ea7e1c3c6991
Step 4/6 : RUN pip install --no-cache-dir -r requirements.txt
---> Running in bff3765cf691
Collecting parse
Downloading parse-1.19.0.tar.gz (30 kB)
Preparing metadata (setup.py): started
Preparing metadata (setup.py): finished with status 'done'
Collecting realpython-reader
Downloading realpython_reader-1.0.0-py3-none-any.whl (5.7 kB)
Collecting html2text
Downloading html2text-2020.1.16-py3-none-any.whl (32 kB)
Collecting feedparser
Downloading feedparser-6.0.8-py3-none-any.whl (81 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 81.0/81.0 KB 7.1 MB/s eta 0:00:00
Collecting typing
Downloading typing-3.7.4.3.tar.gz (78 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 78.6/78.6 KB 22.4 MB/s eta 0:00:00
Preparing metadata (setup.py): started
Preparing metadata (setup.py): finished with status 'done'
Collecting importlib-resources
Downloading importlib_resources-5.6.0-py3-none-any.whl (28 kB)
Collecting sgmllib3k
Downloading sgmllib3k-1.0.0.tar.gz (5.8 kB)
Preparing metadata (setup.py): started
Preparing metadata (setup.py): finished with status 'done'
Building wheels for collected packages: parse, typing, sgmllib3k
Building wheel for parse (setup.py): started
Building wheel for parse (setup.py): finished with status 'done'
Created wheel for parse: filename=parse-1.19.0-py3-none-any.whl size=24591 sha256=c5199f956a159e678dfaf936a03214269adf9265cb0aa964b95cd6b95e5ce632
Stored in directory: /tmp/pip-ephem-wheel-cache-banbtltw/wheels/70/4b/f0/eaf5a8de646d8676dc25caa01949b9f9d883b8fa2efb435bc3
Building wheel for typing (setup.py): started
Building wheel for typing (setup.py): finished with status 'done'
Created wheel for typing: filename=typing-3.7.4.3-py3-none-any.whl size=26325 sha256=f994d46721e8611affa5a7e7f862be68e13f4f1f583d4176a97a60b3cf22aa6d
Stored in directory: /tmp/pip-ephem-wheel-cache-banbtltw/wheels/7c/d0/9e/1f26ebb66d9e1732e4098bc5a6c2d91f6c9a529838f0284890
Building wheel for sgmllib3k (setup.py): started
Building wheel for sgmllib3k (setup.py): finished with status 'done'
Created wheel for sgmllib3k: filename=sgmllib3k-1.0.0-py3-none-any.whl size=6066 sha256=54cdac922cd615a2d5476da50fc3e81202548d9ff8d42e294c52ee52a680387d
Stored in directory: /tmp/pip-ephem-wheel-cache-banbtltw/wheels/f0/69/93/a47e9d621be168e9e33c7ce60524393c0b92ae83cf6c6e89c5
Successfully built parse typing sgmllib3k
Installing collected packages: sgmllib3k, parse, typing, importlib-resources, html2text, feedparser, realpython-reader
Successfully installed feedparser-6.0.8 html2text-2020.1.16 importlib-resources-5.6.0 parse-1.19.0 realpython-reader-1.0.0 sgmllib3k-1.0.0 typing-3.7.4.3
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
Removing intermediate container bff3765cf691
---> ca94e718b78b
Step 5/6 : COPY . .
---> 4fec572aaf81
Step 6/6 : CMD [ "python", "./script.py" ]
---> Running in ba2d27c38ae9
Removing intermediate container ba2d27c38ae9
---> 9862ce240bbe
Successfully built 9862ce240bbe
Successfully tagged python:sample
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:
$ docker images -a
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 4fec572aaf81 5 minutes ago 929MB
python sample 9862ce240bbe 5 minutes ago 929MB
<none> <none> ca94e718b78b 5 minutes ago 929MB
<none> <none> c311c48f19db 6 minutes ago 919MB
<none> <none> ea7e1c3c6991 6 minutes ago 919MB
python 3 ee2a4300ffa2 28 hours ago 919MB
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.
$ docker run --rm python:sample
Basic Image Operations With the Python Pillow Library
Read the full article at https://realpython.com/image-processing-with-the-
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.
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
529d2796888a python:sample "python ./script.py" 2 minutes ago Exited (0) 2 minutes ago interesting_wescoff
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.
$ docker start 529d2796888a; docker attach 529d2796888a
529d2796888a
Basic Image Operations With the Python Pillow Library
Read the full article at https://realpython.com/image-processing-with-the-
$ docker start interesting_wescoff; docker attach interesting_wescoff
interesting_wescoff
Basic Image Operations With the Python Pillow Library
Read the full article at https://realpython.com/image-processing-with-the-
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.