Como usar o comando docker debug para depurar contêineres e imagens

DockerBeginner
Pratique Agora

Introdução

Neste laboratório, exploraremos como depurar efetivamente contêineres e imagens Docker usando o comando docker debug e outras técnicas relacionadas. Começaremos abordando o desafio de depurar contêineres slim (leves) que não possuem um shell, demonstrando como executar comandos diretamente em seu ambiente.

Em seguida, aprenderemos como depurar uma imagem slim diretamente antes mesmo de ser executada como um contêiner. Também abordaremos como modificar arquivos dentro de um contêiner em execução para fins de depuração e como gerenciar a caixa de ferramentas de depuração usando os comandos install e uninstall. Por fim, obteremos uma compreensão mais profunda dos pontos de entrada (entry points) do contêiner, utilizando o comando entrypoint.

Depurando um contêiner slim sem shell

Nesta etapa, aprenderemos como depurar um contêiner slim que não possui um shell instalado. Contêineres slim são frequentemente usados para reduzir o tamanho da imagem e a superfície de ataque, mas podem ser desafiadores de depurar quando algo dá errado.

Primeiro, vamos executar um contêiner slim simples que imprime uma mensagem e depois sai. Usaremos a imagem alpine, que é uma distribuição Linux muito pequena.

docker run alpine echo "Hello from Alpine!"

Você deve ver a saída Hello from Alpine! no seu terminal. Isso confirma que o contêiner foi executado com sucesso.

Agora, vamos tentar executar um comando dentro deste contêiner usando docker exec. Tentaremos executar /bin/sh, que é um shell comum.

docker run -d --name slim-container alpine sleep 3600
docker exec -it slim-container /bin/sh

Você provavelmente verá uma mensagem de erro indicando que /bin/sh não foi encontrado. Isso ocorre porque a imagem alpine, em sua configuração padrão, não inclui um shell como bash ou sh. Esta é uma característica comum de contêineres slim.

Para depurar um contêiner sem um shell, podemos usar o comando docker exec para executar um comando específico dentro do ambiente do contêiner. No entanto, como não há shell, precisamos executar o comando diretamente.

Vamos tentar listar os arquivos no diretório raiz do contêiner. Sabemos que o comando ls geralmente está disponível mesmo em ambientes mínimos.

docker exec -it slim-container ls /

Você deve ver uma lista de diretórios e arquivos na raiz do sistema de arquivos do contêiner, como bin, etc, lib, etc. Isso demonstra que ainda podemos executar comandos diretamente dentro do contêiner, mesmo sem um shell.

Finalmente, vamos limpar o contêiner que criamos.

docker stop slim-container
docker rm slim-container

Esta etapa nos mostrou como interagir com um contêiner slim que não possui um shell, executando comandos diretamente usando docker exec. Nas próximas etapas, exploraremos outras técnicas de depuração.

Depurando uma imagem slim diretamente

Na etapa anterior, aprendemos como interagir com um contêiner slim em execução. No entanto, às vezes você pode precisar inspecionar o conteúdo de uma imagem slim antes de executá-la como um contêiner, ou se o contêiner falhar ao iniciar. Nesta etapa, exploraremos como depurar uma imagem slim diretamente.

O Docker fornece o comando docker run com a capacidade de substituir o ponto de entrada (entrypoint) e o comando padrão de uma imagem. Isso nos permite executar um comando diferente dentro de um contêiner temporário criado a partir da imagem, dando-nos uma maneira de inspecionar seu conteúdo.

Vamos usar a imagem alpine novamente. Sabemos que é uma imagem slim e não possui um shell por padrão. Podemos usar docker run para executar um comando como ls / diretamente na imagem.

docker run --rm alpine ls /

A flag --rm garante que o contêiner temporário seja removido automaticamente após a conclusão do comando. Você deve ver a mesma saída que quando executamos ls / no contêiner em execução na etapa anterior. Isso confirma que podemos inspecionar o sistema de arquivos da imagem diretamente.

Agora, vamos tentar ver se um comando específico existe dentro da imagem. Por exemplo, vamos verificar a presença do comando ping.

docker run --rm alpine which ping

Você provavelmente verá uma mensagem de erro como which: not found. Isso indica que o comando ping não está presente na imagem alpine padrão. Esta é outra característica das imagens slim – elas geralmente incluem apenas as ferramentas mínimas absolutamente necessárias.

Vamos tentar um comando que sabemos que existe, como cat.

docker run --rm alpine which cat

Desta vez, você deve ver a saída /bin/cat, confirmando que o comando cat está disponível na imagem.

Esta técnica de usar docker run --rm <image> <command> é muito útil para verificar rapidamente o conteúdo de uma imagem, verificar a presença de arquivos ou comandos específicos e entender a estrutura da imagem sem precisar executar um contêiner de longa duração ou construir uma nova imagem.

Modificando arquivos em um contêiner em execução

Nesta etapa, aprenderemos como modificar arquivos dentro de um contêiner em execução. Isso pode ser útil para fins de depuração, como alterar arquivos de configuração ou adicionar scripts temporários a um contêiner que já está em execução.

Começaremos executando um contêiner simples baseado na imagem ubuntu, que é mais rica em recursos do que alpine e inclui um shell e utilitários comuns.

docker run -d --name my-ubuntu ubuntu sleep 3600

Este comando executa um contêiner Ubuntu em modo detached (-d) e o mantém em execução por uma hora usando o comando sleep 3600. Nomeamos o contêiner my-ubuntu para facilitar a referência.

Agora, vamos usar docker exec para obter um shell dentro do contêiner em execução.

docker exec -it my-ubuntu /bin/bash

Você deve estar agora dentro do shell bash do contêiner my-ubuntu. O prompt mudará para refletir que você está dentro do contêiner.

Dentro do contêiner, vamos criar um novo arquivo no diretório /tmp.

echo "This is a test file." > /tmp/test_file.txt

Agora, vamos verificar se o arquivo foi criado e contém o conteúdo correto.

cat /tmp/test_file.txt

Você deve ver a saída This is a test file.. Isso confirma que fomos capazes de criar e escrever em um arquivo dentro do contêiner em execução.

Para sair do shell do contêiner, basta digitar exit.

exit

Você está agora de volta ao seu terminal da VM LabEx.

Também podemos copiar arquivos para dentro e para fora de um contêiner em execução usando o comando docker cp. Vamos criar um arquivo em nossa VM LabEx e copiá-lo para o contêiner.

Primeiro, crie um arquivo chamado local_file.txt em seu diretório ~/project.

echo "This file is from the host." > ~/project/local_file.txt

Agora, copie este arquivo para o diretório /tmp do contêiner my-ubuntu.

docker cp ~/project/local_file.txt my-ubuntu:/tmp/

O formato para docker cp é docker cp <source_path> <container_name>:<destination_path> ou docker cp <container_name>:<source_path> <destination_path>.

Vamos verificar se o arquivo foi copiado para o contêiner. Volte para o shell do contêiner.

docker exec -it my-ubuntu /bin/bash

Dentro do contêiner, verifique a presença de local_file.txt em /tmp.

ls /tmp/

Você deve ver local_file.txt listado junto com test_file.txt.

Agora, vamos visualizar o conteúdo de local_file.txt dentro do contêiner.

cat /tmp/local_file.txt

Você deve ver a saída This file is from the host..

Saia do shell do contêiner novamente.

exit

Finalmente, vamos limpar o contêiner.

docker stop my-ubuntu
docker rm my-ubuntu

Esta etapa demonstrou como modificar arquivos dentro de um contêiner em execução usando docker exec para obter um shell e comandos Linux padrão, e como copiar arquivos entre o host e o contêiner usando docker cp.

Gerenciando a caixa de ferramentas de depuração com install e uninstall

Nesta etapa, exploraremos como adicionar e remover ferramentas de depuração dentro de um contêiner em execução. Embora geralmente seja recomendado manter as imagens de contêiner de produção mínimas, às vezes você precisa instalar ferramentas temporárias para fins de depuração.

Usaremos a imagem ubuntu novamente, pois ela possui um gerenciador de pacotes (apt) que facilita a instalação de software.

Primeiro, vamos executar um novo contêiner Ubuntu em modo detached.

docker run -d --name debug-ubuntu ubuntu sleep 3600

Agora, vamos obter um shell dentro do contêiner.

docker exec -it debug-ubuntu /bin/bash

Dentro do contêiner, vamos tentar usar um comando que não é instalado por padrão, como ping.

ping google.com

Você provavelmente verá um erro "command not found".

Para instalar ping e outros utilitários de rede, podemos usar o gerenciador de pacotes apt. Primeiro, é uma boa prática atualizar a lista de pacotes.

apt update

Este comando busca as informações mais recentes sobre os pacotes disponíveis nos repositórios.

Agora, vamos instalar o pacote iputils-ping, que fornece o comando ping.

apt install -y iputils-ping

A flag -y confirma automaticamente a instalação sem solicitar.

Após a conclusão da instalação, você deve ser capaz de usar o comando ping.

ping -c 4 google.com

Você deve ver a saída do comando ping, indicando que ele agora está disponível e funcionando dentro do contêiner.

Depois de terminar a depuração, é uma boa ideia remover todas as ferramentas que você instalou para manter o contêiner limpo e reduzir seu tamanho se você for confirmá-lo como uma nova imagem (embora modificar contêineres em execução para produção seja geralmente desencorajado).

Para remover o pacote iputils-ping, use apt remove.

apt remove -y iputils-ping

Você pode verificar se ping não está mais disponível.

ping google.com

Você deve ver o erro "command not found" novamente.

Saia do shell do contêiner.

exit

Finalmente, limpe o contêiner.

docker stop debug-ubuntu
docker rm debug-ubuntu

Esta etapa demonstrou como instalar e desinstalar temporariamente ferramentas de depuração dentro de um contêiner em execução usando seu gerenciador de pacotes. Esta é uma técnica poderosa para solucionar problemas em contêineres onde as ferramentas necessárias não estão incluídas na imagem base.

Entendendo os pontos de entrada do contêiner com o comando entrypoint

Nesta etapa, aprenderemos sobre a instrução ENTRYPOINT em um Dockerfile e como ela afeta a execução de um contêiner. O ENTRYPOINT define o comando que será executado quando um contêiner iniciar. Ele é frequentemente usado para definir o executável principal do contêiner.

Vamos criar um Dockerfile simples que usa ENTRYPOINT. Em seu diretório ~/project, crie um arquivo chamado Dockerfile com o seguinte conteúdo:

FROM alpine
ENTRYPOINT ["echo", "Hello from the entrypoint!"]
CMD ["default", "command"]

Este Dockerfile usa a imagem alpine como base. O ENTRYPOINT é definido como ["echo", "Hello from the entrypoint!"]. O CMD é definido como ["default", "command"]. Quando ENTRYPOINT e CMD são especificados, os argumentos CMD são passados ​​como argumentos para o comando ENTRYPOINT.

Agora, vamos construir uma imagem a partir deste Dockerfile.

docker build -t my-entrypoint-image ~/project

Este comando constrói uma imagem chamada my-entrypoint-image a partir do Dockerfile no diretório ~/project.

Agora, vamos executar um contêiner a partir desta imagem sem fornecer nenhum comando adicional.

docker run my-entrypoint-image

Você deve ver a saída Hello from the entrypoint! default command. Isso mostra que o comando ENTRYPOINT (echo) foi executado e os argumentos CMD (default command) foram passados ​​para ele.

Agora, vamos executar o contêiner e fornecer um comando diferente na linha docker run. Quando você fornece um comando na linha docker run, ele substitui a instrução CMD no Dockerfile, mas o ENTRYPOINT ainda é executado com o comando fornecido como argumentos.

docker run my-entrypoint-image "override command"

Você deve ver a saída Hello from the entrypoint! override command. Isso demonstra que o ENTRYPOINT ainda foi executado, mas os argumentos do comando docker run (override command) substituíram os argumentos CMD.

E se você quiser ignorar completamente o ENTRYPOINT e executar um comando diferente? Você pode usar a flag --entrypoint com docker run.

docker run --entrypoint /bin/echo my-entrypoint-image "Running a different command"

Você deve ver a saída Running a different command. Neste caso, a flag --entrypoint substituiu o ENTRYPOINT especificado no Dockerfile, e o comando fornecido (/bin/echo) foi executado com os argumentos (Running a different command).

Compreender ENTRYPOINT e CMD é crucial para construir e depurar imagens Docker. ENTRYPOINT define o executável principal, enquanto CMD fornece argumentos padrão para esse executável ou um comando padrão se nenhum ENTRYPOINT for definido.

Resumo

Neste laboratório, aprendemos como depurar contêineres e imagens Docker usando o comando docker debug e técnicas relacionadas. Começamos explorando como depurar um contêiner slim que não possui um shell, demonstrando que ainda podemos executar comandos diretamente no ambiente do contêiner usando docker exec, mesmo sem um shell tradicional como bash ou sh. Esta é uma técnica crucial para solucionar problemas em imagens de contêineres mínimas.

Embora o conteúdo fornecido cubra apenas a primeira etapa, a estrutura geral do laboratório indica que as etapas subsequentes se aprofundariam na depuração direta de imagens slim, na modificação de arquivos dentro de contêineres em execução, no gerenciamento da caixa de ferramentas de depuração com comandos de instalação e desinstalação e na compreensão dos pontos de entrada do contêiner usando o comando entrypoint. Essas etapas aprimorariam ainda mais nossa capacidade de diagnosticar e resolver problemas em aplicações e imagens Dockerizadas.