Trabalhando com Imagens Docker

DockerBeginner
Pratique Agora

Introdução

Neste laboratório, exploraremos as imagens Docker, que são a base para a criação e execução de containers. Aprenderemos como baixar imagens do Docker Hub, executar containers usando diferentes versões de imagem, listar e remover imagens, entender as camadas de imagem, pesquisar por imagens e realizar a marcação básica de tags. Esta experiência prática fornecerá as habilidades essenciais para trabalhar com imagens Docker de forma eficaz. Não se preocupe se você for novo no Docker — guiaremos você por cada etapa com explicações detalhadas.

Baixando Imagens do Docker Hub

O Docker Hub é um repositório público de imagens Docker, semelhante ao que o GitHub representa para o código-fonte. É onde você pode encontrar imagens pré-configuradas para muitos aplicativos de software e sistemas operacionais populares. Vamos começar baixando (fazendo o pull) da imagem oficial do Nginx.

Abra um terminal em seu sistema. Você deverá ver um prompt parecido com este:

labex:project/ $

Agora, vamos baixar a imagem do Nginx. Digite o seguinte comando e pressione Enter:

docker pull nginx

Este comando instrui o Docker a baixar a versão mais recente da imagem do Nginx diretamente do Docker Hub. Você verá uma saída semelhante a esta:

Using default tag: latest
latest: Pulling from library/nginx
5040bd298390: Pull complete
d7a91cdb22f0: Pull complete
9cac4850e5df: Pull complete
Digest: sha256:33ff28a2763feccc1e1071a97960b7fef714d6e17e2d0ff573b74825d0049303
Status: Downloaded newer image for nginx:latest

Vamos analisar o que está acontecendo aqui:

  1. "Using default tag: latest" - Quando você não especifica uma versão, o Docker assume que você deseja a versão mais recente (latest).
  2. As linhas seguintes mostram o Docker baixando diferentes "camadas" da imagem. Cada camada representa um conjunto de alterações no sistema de arquivos.
  3. O "Digest" é um identificador exclusivo para esta versão exata da imagem.
  4. A última linha confirma que a imagem foi baixada com sucesso.

Agora que baixamos a imagem, vamos verificar se ela está em nosso sistema. Podemos fazer isso listando todas as imagens que o Docker possui localmente:

docker images

Você verá uma saída semelhante a esta:

REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
nginx         latest    605c77e624dd   2 weeks ago    141MB

Isso nos informa:

  • REPOSITORY: O nome da imagem (nginx)
  • TAG: A versão da imagem (latest)
  • IMAGE ID: Um identificador exclusivo para esta imagem
  • CREATED: Quando esta versão da imagem foi criada
  • SIZE: Quanto espaço em disco a imagem ocupa

Não se preocupe se os números exatos forem diferentes — o importante é que você veja uma entrada para o nginx.

Se você estiver curioso sobre quais outras imagens estão no seu sistema, poderá ver entradas para "jenkins/jenkins" e "gcr.io/k8s-minikube/kicbase". Estas são imagens pré-instaladas que não utilizaremos neste laboratório.

Executando Diferentes Versões de uma Imagem

O Docker permite que você execute versões específicas de uma imagem usando tags. As tags funcionam como apelidos para versões específicas. Vamos explorar esse conceito com a imagem do Python.

Primeiro, vamos baixar a imagem mais recente do Python:

docker pull python

Você verá uma saída semelhante a quando baixamos a imagem do Nginx. Isso está baixando a versão mais atual do Python.

Agora, vamos baixar uma versão específica do Python, por exemplo, a versão 3.7:

docker pull python:3.7

Observe como adicionamos :3.7 após python. Isso instrui o Docker a baixar especificamente a versão 3.7, em vez da mais recente.

Vamos listar nossas imagens Python para ver as diferentes versões:

docker images python

Você verá uma saída semelhante a esta:

REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
python       3.7       1f1a7b570fbd   2 weeks ago    907MB
python       latest    98ccd1643c71   2 weeks ago    920MB

Agora temos duas imagens Python: uma com a tag latest (que na verdade é o Python 3.9 ou 3.10, dependendo de quando você está realizando este laboratório) e outra com a tag 3.7.

Vamos executar containers usando essas versões diferentes para ver a diferença:

docker run --rm python:latest python --version

Este comando realiza várias ações:

  1. docker run cria e inicia um novo container.
  2. --rm instrui o Docker a remover o container automaticamente após ele ser encerrado.
  3. python:latest especifica qual imagem usar.
  4. python --version é o comando a ser executado dentro do container.

Você deverá ver a versão mais recente do Python na saída.

Agora vamos fazer o mesmo com o Python 3.7:

docker run python:3.7 python --version

Desta vez, você deverá ver Python 3.7.x na saída, onde x é a versão de correção mais recente do Python 3.7.

Esses comandos demonstram como você pode utilizar diferentes versões do mesmo software usando tags de imagem distintas. Isso é incrivelmente útil quando você precisa executar aplicações que exigem versões específicas do Python (ou de qualquer outro software).

Listando e Removendo Imagens

À medida que você trabalha com o Docker, acumulará imagens ao longo do tempo. É importante saber como gerenciar essas imagens, incluindo como listá-las e remover aquelas que não são mais necessárias.

Vamos começar listando todas as imagens no seu sistema:

docker images

Você verá uma lista de todas as imagens que baixou até agora, incluindo o Nginx e as imagens do Python.

Agora, suponha que queiramos remover a imagem do Python 3.7 para liberar espaço. Podemos fazer isso usando o comando docker rmi (rmi significa "remove image"):

docker rmi python:3.7

Se o comando for bem-sucedido, você verá uma saída como esta:

Untagged: python:3.7
Untagged: python@sha256:1f93c63...
Deleted: sha256:1f1a7b57...
Deleted: sha256:8c75ecde...
...

No entanto, você pode encontrar uma mensagem de erro como esta:

Error response from daemon: conflict: unable to remove repository reference "python:3.7" (must force) - container <container_id> is using its referenced image <image_id>

Esse erro ocorre se houver um container (em execução ou parado) que foi criado a partir desta imagem. O Docker impede a remoção de imagens que estão em uso para manter a integridade do sistema.

Para resolver isso, precisamos remover primeiro quaisquer containers que utilizem esta imagem. Vamos listar todos os containers (incluindo os parados):

docker ps -a

Procure por quaisquer containers que foram criados a partir da imagem python:3.7. Se encontrar algum, remova-o usando o comando docker rm:

docker rm <container_id>

Substitua <container_id> pelo ID real do container que você deseja remover.

Agora tente remover a imagem novamente:

docker rmi python:3.7

Desta vez, a operação deve ser bem-sucedida.

Vamos verificar se a imagem foi removida listando as imagens Python novamente:

docker images python

Você não deve mais ver a imagem do Python 3.7 na lista.

Entendendo as Camadas de Imagem

As imagens Docker são construídas usando um sistema de arquivos em camadas. Cada camada representa um conjunto de alterações no sistema de arquivos. Essa abordagem em camadas permite que o Docker seja eficiente em termos de armazenamento e uso de rede. Vamos explorar esse conceito.

Primeiro, vamos inspecionar as camadas da imagem Nginx que baixamos anteriormente:

docker inspect --format='{{.RootFS.Layers}}' nginx

Você verá uma saída semelhante a esta:

[sha256:2edcec3590a4ec7f40cf0743c15d78fb39d8326bc029073b41ef9727da6c851f sha256:e379e8aedd4d72bb4c529a4ca07a4e4d230b5a1d3f7a61bc80179e8f02421ad8 sha256:b5357ce95c68acd9c9672ec76e3b2a2ff3f8f62a2bcc1866b8811572f4d409af]

Cada uma dessas longas strings (chamadas de hashes SHA256) representa uma camada na imagem. Cada camada corresponde a um comando no Dockerfile usado para construir a imagem.

Para entender melhor as camadas, vamos criar uma imagem personalizada simples. Primeiro, crie um novo arquivo chamado Dockerfile no seu diretório atual:

nano Dockerfile

Neste arquivo, adicione o seguinte conteúdo:

FROM nginx
RUN echo "Hello from custom layer" > /usr/share/nginx/html/hello.html

Este Dockerfile faz duas coisas:

  1. Começa com a imagem Nginx que baixamos anteriormente (FROM nginx).
  2. Adiciona um novo arquivo à imagem (RUN echo...).

Salve e saia do arquivo (no nano, você faz isso pressionando Ctrl+X, depois Y e Enter).

Agora vamos construir esta imagem:

docker build -t custom-nginx .

Exemplo de saída:

Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM nginx
 ---> 5ef79149e0ec
Step 2/2 : RUN echo "Hello from custom layer" > /usr/share/nginx/html/hello.html
 ---> Running in 2fa43e649234
Removing intermediate container 2fa43e649234
 ---> 73b62663b5c3
Successfully built 73b62663b5c3
Successfully tagged custom-nginx:latest

Este comando constrói uma nova imagem baseada no nosso Dockerfile e a etiqueta como custom-nginx. O ponto . ao final instrui o Docker a procurar o Dockerfile no diretório atual.

Agora, vamos inspecionar as camadas da nossa imagem personalizada:

docker inspect --format='{{.RootFS.Layers}}' custom-nginx

Você notará que esta imagem possui uma camada a mais do que a imagem original do Nginx. Esta camada adicional representa as alterações feitas pelo nosso comando RUN.

Entender as camadas é crucial porque:

  1. As camadas são armazenadas em cache, acelerando a construção de imagens semelhantes.
  2. As camadas são compartilhadas entre imagens, economizando espaço em disco.
  3. Ao enviar (push) ou baixar (pull) imagens, apenas as camadas alteradas precisam ser transferidas.

Pesquisando Imagens no Docker Hub

O Docker Hub hospeda uma vasta coleção de imagens. Embora você possa pesquisar imagens no site do Docker Hub, o Docker também fornece uma ferramenta de linha de comando para pesquisar imagens diretamente do seu terminal.

Vamos começar pesquisando por imagens do Nginx:

docker search nginx

Isso retornará uma lista de imagens relacionadas ao Nginx. A saída inclui várias colunas:

  • NAME: O nome da imagem.
  • DESCRIPTION: Uma breve descrição da imagem.
  • STARS: O número de estrelas que a imagem possui no Docker Hub (indicando popularidade).
  • OFFICIAL: Se esta é uma imagem oficial mantida pelo Docker.
  • AUTOMATED: Se esta imagem é construída automaticamente a partir de um repositório GitHub.

Por exemplo, você pode ver algo assim:

NAME                              DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
nginx                             Official build of Nginx.                        15763     [OK]
jwilder/nginx-proxy               Automated Nginx reverse proxy for docker c...   2088                 [OK]
...

A imagem oficial do Nginx geralmente está no topo desta lista.

Agora, vamos tentar pesquisar por uma versão específica do Python:

docker search python:3.8

Você notará que esta pesquisa não funciona exatamente como esperado. O comando docker search não suporta a busca por tags específicas (como 3.8). Em vez disso, ele procurará por imagens que tenham "python:3.8" em seu nome ou descrição.

Para encontrar versões específicas de uma imagem, geralmente é melhor:

  1. Pesquisar pelo nome geral da imagem (ex: docker search python).
  2. Visitar o site do Docker Hub para informações mais detalhadas.
  3. Usar docker pull para baixar a imagem e então inspecioná-la localmente.

Lembre-se, o docker search é uma maneira rápida de encontrar imagens, mas para detalhes minuciosos, o site do Docker Hub costuma ser mais útil.

Salvando e Carregando Imagens

O Docker permite que você salve imagens como arquivos tar e as carregue posteriormente. Isso é útil para transferir imagens entre sistemas sem usar um registro (registry) ou para fazer backup de imagens.

Vamos começar salvando a imagem do Nginx em um arquivo:

docker save nginx > nginx.tar

Este comando salva a imagem do Nginx em um arquivo chamado nginx.tar no seu diretório atual. O símbolo > é usado para redirecionar a saída do comando docker save para um arquivo.

Você pode verificar se o arquivo foi criado listando o conteúdo do seu diretório atual:

ls -lh nginx.tar

Você deverá ver o arquivo nginx.tar listado, junto com seu tamanho (que deve ser superior a 100MB).

Agora, vamos remover a imagem do Nginx do nosso sistema para simular a transferência da imagem para um sistema que não a possui:

docker rmi nginx

Verifique se a imagem desapareceu:

docker images nginx

Você não deve ver resultados, indicando que a imagem do Nginx foi removida do seu sistema.

Agora, vamos carregar a imagem de volta a partir do arquivo tar:

docker load < nginx.tar

O símbolo < é usado para redirecionar o conteúdo do arquivo nginx.tar como entrada para o comando docker load.

Após a conclusão do carregamento, verifique se a imagem do Nginx está de volta:

docker images nginx

Você deverá ver a imagem do Nginx na lista novamente, exatamente como estava antes de a removermos.

Este processo de salvar e carregar imagens pode ser muito útil quando você precisa:

  • Transferir imagens para um sistema sem acesso à internet.
  • Fazer backup de versões específicas de imagens.
  • Compartilhar imagens personalizadas com outras pessoas sem usar um registro.

Conceitos Básicos de Marcação de Tags

A marcação de tags (tagging) é uma forma de criar apelidos para suas imagens Docker. É comumente usada para versionamento e organização de imagens. Vamos explorar como marcar imagens.

Primeiro, vamos criar uma nova tag para nossa imagem Nginx:

docker tag nginx:latest my-nginx:v1

Este comando cria uma nova tag my-nginx:v1 que aponta para a mesma imagem que nginx:latest. Aqui está o que cada parte significa:

  • nginx:latest é a imagem de origem e sua tag.
  • my-nginx é o novo nome da imagem que estamos criando.
  • v1 é a nova tag que estamos atribuindo.

Agora, liste suas imagens para ver a nova tag:

docker images

Você deverá ver tanto nginx:latest quanto my-nginx:v1 na lista. Observe que elas possuem o mesmo Image ID — isso ocorre porque são, na verdade, a mesma imagem, apenas com nomes diferentes.

Você pode usar esta nova tag para executar um container:

docker run -d --name my-nginx-container my-nginx:v1

Este comando faz o seguinte:

  • -d executa o container em modo destacado (detached), ou seja, em segundo plano.
  • --name my-nginx-container atribui um nome ao nosso novo container.
  • my-nginx:v1 é a imagem e a tag que estamos usando para criar o container.

Verifique se o container está em execução:

docker ps

Você deverá ver seu container na lista de containers ativos.

A marcação de tags é útil por vários motivos:

  1. Controle de versão: Você pode marcar imagens com números de versão (v1, v2, etc.).
  2. Separação de ambientes: Você pode marcar imagens para diferentes ambientes (dev, staging, prod).
  3. Legibilidade: Tags personalizadas podem tornar mais claro para que serve uma imagem.

Lembre-se, as tags são apenas apelidos — elas não criam novas imagens, apenas criam novos nomes que apontam para imagens existentes.

Resumo

Neste laboratório, exploramos vários aspectos do trabalho com imagens Docker. Aprendemos como:

  1. Baixar imagens do Docker Hub.
  2. Executar containers usando diferentes versões de imagem.
  3. Listar e remover imagens.
  4. Entender as camadas de imagem.
  5. Pesquisar imagens no Docker Hub.
  6. Salvar e carregar imagens.
  7. Realizar a marcação básica de tags em imagens.

Essas habilidades formam a base para gerenciar efetivamente as imagens Docker em seus projetos. À medida que você continua sua jornada com o Docker, descobrirá que essas operações são essenciais para construir e implantar aplicações conteinerizadas.

Lembre-se de que as imagens Docker estão no cerne do funcionamento do Docker. Elas fornecem uma maneira consistente, portátil e eficiente de empacotar e distribuir aplicações. Ao dominar essas operações de imagem, você está no caminho certo para se tornar proficiente em Docker.

Continue praticando esses comandos e explorando diferentes imagens. Quanto mais você trabalhar com o Docker, mais confortável e habilidoso você se tornará. Bom trabalho com o Docker!