> For the complete documentation index, see [llms.txt](https://aurimrv.gitbook.io/pratica-devops-com-docker-para-machine-learning/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://aurimrv.gitbook.io/pratica-devops-com-docker-para-machine-learning/id-1-introducao/1.5-dockerfile-imagem-e-conteiner-docker.md).

# 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)](https://docs.microsoft.com/pt-br/dotnet/architecture/microservices/container-docker-introduction/docker-containers-images-registries), 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).](/files/X9V5DNyy5SwV1E0LzRNT)

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](https://hub.docker.com), 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

```
FROM python:3

WORKDIR /usr/src/app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD [ "python", "./script.py" ]
```

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

```
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.

```
$ docker build -t python:sample .
Sending build context to Docker daemon  4.096kB
Step 1/6 : FROM python:3
 ---> ee2a4300ffa2
Step 2/6 : WORKDIR /usr/src/app
 ---> Using cache
 ---> 1f48c37c77f6
Step 3/6 : COPY requirements.txt ./
 ---> Using cache
 ---> 3dca482a4287
Step 4/6 : RUN pip install --no-cache-dir -r requirements.txt
 ---> Using cache
 ---> ad9b2c5f81ee
Step 5/6 : COPY . .
 ---> 7c01f2a4c087
Step 6/6 : CMD [ "python", "./script.py" ]
 ---> Running in ef40ba306c05
Removing intermediate container ef40ba306c05
 ---> 09b1b0e92fcb
Successfully built 09b1b0e92fcb
Successfully tagged python:sample
```

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.
