Como criar e manipular contêineres no Docker

Há várias formas de iniciar o uso do Docker e fazer uso dos containers. Neste texto, vou me concentrar nos comandos de execução — a começar por alguns comandos de verificação do estado da sua instalação.
Para saber se o Docker foi instalado corretamente, use o parâmetro ‘info’, na linha de comando:

docker info

O comando deve retornar algo semelhante ao que se vê abaixo:

Containers: 48
Images: 18
Storage Driver: aufs
 Root Dir: /var/lib/docker/aufs
 Dirs: 114
Execution Driver: native-0.2
Kernel Version: 3.13.0-63-generic
WARNING: No swap limit support

A saída do comando vai depender da configuração atual do seu sistema e do Docker.

O Docker trabalha sob a perspectiva cliente/servidor.
O mesmo binário Docker é usado tanto pelo servidor quanto pelos comandos do cliente.
Desta forma, quando executamos os comandos do lado do cliente, estes são repassados ao daemon Docker, em execução no seu sistema.

Para rodar um contêiner, use o comando ‘run’ (do próprio Docker).
Note que, nos exemplos deste artigo, o docker é usado pelo usuário normal — sem privilégios administrativos.
Na configuração padrão do aplicativo, é necessário rodá-lo precedido do sudo ou como root.
Leia mais sobre como configurar o docker para rodar com os privilégios de usuário comum, aqui.
O comando que segue, vai colocar a imagem do Ubuntu (ou a tag mais atual dele) para rodar como um contêiner, com uma shell bash dentro:

docker run -i -t ubuntu /bin/bash

Veja o que mais foi feito acima:

  • -i pede para que a entrada ou input permaneça aberta, para receber instruções
  • -t pede ao contêiner para atribuir-lhe um terminal
  • /bin/bash é a opção de programa terminal escolhida

Se vocẽ abrir uma nova janela do console (Ctrl + Alt + T, no Ubuntu), agora, vai poder verificar que o contêiner está rodando. Use o comando ‘ps’ do Docker, para isto:

docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
bdaaca495be7        ubuntu:latest       /bin/bash           10 seconds ago      Up 10 seconds                           jolly_meitner

O Docker é um excelente construtor de blocos para sistemas distribuídos e automatizados — o que inclui aplicações web de larga escala, clusters de bancos de dados, sistemas de distribuição/desenvolvimento continuado, PaaS privado, arquiteturas orientadas a serviço etc.
(Manual do Docker)

Os contêineres podem ser identificados e chamados pelos seus IDs. Tendo vários no seu sistema, cada contêiner terá sua própria identificação.
Se você acrescentar a opção ‘-a’, o Docker irá mostrar mais — o que inclui os contêineres que já estão parados no sistema.
dokcer-ps--a
Note as colunas das extremidades: à esquerda fica a ID de cada contêiner. À direita, o seu nome.
Você pode se referir a um contêiner, pela sua ID ou, se preferir, pelo seu nome.
O Docker “batiza” todos os novos contêineres criados sem nome. Ele cria/escolhe nomes aleatórios — jolly_meitner, goofy_hopper, stoic_torvalds etc. (Veja a figura, acima).

Como nomear contêineres Docker

Como já mencionei, é possível (e opcional) dar um nome a cada novo contêiner criado no Docker.
Caso o usuário não o faça, o Docker cria um nome aleatório e o atribui ao novo contêiner, no momento de sua criação.
Mas você pode (e deve) dar nomes que tenham mais significado para você.
Use o parâmetro ‘–name’ para escolher e atribuir um nome ao seu contêiner:

docker run --name primeiro_conteiner -i -t ubuntu /bin/bash

De dentro de um contêiner, use o comando ‘exit’ para terminá-lo e sair.

Opções para parar e iniciar um contêiner Docker

Você pode iniciar e parar um contêiner, com o uso dos comandos ‘start’ e ‘stop’, seguido da ID ou do nome do contêiner que você deseja atingir:

docker start 697f662350ab
697f662350ab
docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
697f662350ab        ubuntu:latest       /bin/bash           7 minutes ago       Up 6 seconds                            primeiro_conteiner   
bdaaca495be7        ubuntu:latest       /bin/bash           About an hour ago   Up About an hour                        jolly_meitner        
docker stop primeiro_conteiner
primeiro_conteiner
docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
bdaaca495be7        ubuntu:latest       /bin/bash           About an hour ago   Up About an hour                        jolly_meitner

docker-start-stop
Como você pode ver, nos exemplos acima (tanto no texto quanto na imagem), é possível se referir tanto ao ID quanto ao nome de um contêiner.
Ao aplicar os exemplos, você deve ter percebido que, embora o contêiner volte a rodar, você não está “dentro dele”.
Para poder assumir o controle da linha de comando (shell) dentro de um contêiner, use o comando ‘attach’ — seguido do seu ID ou do seu nome:

docker attach bdaaca495be7

Como rodar um contêiner em modo daemon

Além de usar estes contêineres interativos, que vimos até agora, podemos rodá-los nos bastidores do sistema ou daemonized.
Este modo é muito útil para executar tarefas (aplicações ou serviços) de longa duração em um contêiner.
Na verdade esta é a maneira mais comum de se executar Docker containers.
Veja um exemplo:

docker run --name primeiro_daemon -d ubuntu /bin/sh -c "while true; do echo ola mundo; sleep 1; done"
65f05aeced672283ba639aa240268d23fdaa7713ca0beb66da3f39155224502c

Aqui, usamos o comando ‘docker run’, em conjunto com o parâmetro ‘-d’ para enviar o contêiner pros bastidores ou background.
Dentro dele, escrevemos um pequeno script em loop, como comando.
O script envia a frase “ola mundo” uma vez a cada segundo, até ser interrompido — parando o contêiner ou o processo.
Com esta combinação de opções e parâmetros, é possível ver que o Docker não te coloca na shell de comandos. Ele apenas retorna a ID do contêiner o prompt linha de comando do seu terminal — enquanto o script continua a ser executado dentro do contêiner.
Como você já sabe, é possível acompanhar a execução dele, através do comando docker ps:

docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS               NAMES
65f05aeced67        debian:latest       /bin/sh -c 'while tr   29 minutes ago      Up 29 minutes                           primeiro_daemon     
bdaaca495be7        ubuntu:latest       /bin/bash              2 hours ago         Up 43 minutes                           jolly_meitner

Como ver o que acontece dentro de um contêiner

É possível, a qualquer momento, obter informações sobre processos que estejam em execução dentro de contêineres.
Neste momento, há um com um laço while em execução.
Você pode usar o comando ‘logs’ do Docker para obter informações sobre o andamento da execução dos processos:

docker logs primeiro_daemon
ola mundo
ola mundo
ola mundo

...

O comando ‘logs’ vai mostrar o resultado do script em execução no contêiner.
Se você deseja monitorar os resultados de alguma tarefa, acrescente a opção ‘-f’ — e observe os resultados como se estivesse executando o tails:

docker logs -f primeiro_daemon

Acrescente a opção ‘-t’ para exibir o timestamp ao lado de cada resultado:

docker logs -tf primeiro_daemon
[Sep 14 17:40:59.675] ola mundo
[Sep 14 17:41:00.676] ola mundo
[Sep 14 17:41:01.677] ola mundo
[Sep 14 17:41:02.678] ola mundo
[Sep 14 17:41:03.680] ola mundo
[Sep 14 17:41:04.681] ola mundo
[Sep 14 17:41:05.683] ola mundo
[Sep 14 17:41:06.684] ola mundo
[Sep 14 17:41:07.686] ola mundo
[Sep 14 17:41:08.688] ola mundo

Para concluir o monitoramento, pressione Ctrl + C.
Uma outra forma de observar o trabalho dentro do contêiner é rodando o comando ‘top’ com o Docker:

docker top primeiro_daemon
[/false]

UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                13434               2306                0                   14:37               ?                   00:00:00            /bin/sh -c while true; do echo ola mundo; sleep 1; done
root                16200               13434               0                   15:13               ?                   00:00:00            sleep 1

Também é possível ver estatísticas de funcionamento dos processos, através do comando ‘stats’:

sudo docker stats primeiro_daemon
CONTAINER           CPU %               MEM USAGE/LIMIT     MEM %               NET I/O
primeiro_daemon     0.12%               557.1 kB/8.059 GB   0.01%               10.47 kB/648 B

Para sair do painel de estatísticas, use a combinação Ctrl + C.

Como iniciar outro processo dentro de um contêiner existente

Um contêiner preexistente e com processos em andamento, pode aceitar novas tarefas e/ou novos processos, sem problemas — esta também é uma situação muito comum.
O comando ‘exec’ do Docker é que permite acrescentar tarefas aos contêineres.
Estas tarefas podem ser de 2 tipos: de background ou interativas.
As primeiras são inseridas para execução no contêiner e não tem interação depois disto.
As tarefas interativas são interessantes, pois permitem abrir uma shell dentro do contêiner.
Veja, no exemplo, como executar um comando em segundo plano dentro de um contêiner:

docker exec -d primeiro_daemon touch /etc/new_config_file

Aqui, o ‘-d’ sinaliza um processo rodando em segundo plano.
Em seguida, especificamos o nome do contêiner que queremos atingir e o comando que irá ser executado dentro dele.
Neste caso, o comando touch cria um arquivo vazio ‘new_config_file’ dentro do diretório ‘/etc’ dentro do contêiner ‘primeiro_daemon’.
Desta forma é que podemos usar o comando ‘exec’ do Docker para rodar comandos de manutenção, aplicativos de monitoramento, gerenciar tarefas etc. tudo dentro dos contêineres.
Com este método, é possível alterar a execução de um script on the fly.
Se você deseja obter acesso a uma shell dentro do contêiner, use as opções ‘-t’ e ‘-i’ (que já foram vistas anteriormente).
Com estas opções, é possível criar um terminal TTY e capturar o STDIN (standard input) dos processos em execução.
Além disto, é preciso indicar qual o contêiner e qual programa de shell a ser usado. Veja o exemplo:

docker exec -t -i primeiro_daemon /bin/bash

root@a3f74bdffacc:/# echo "Olha mae! Estou dentro do container!"

Olha mae! Estou dentro do container!

root@a3f74bdffacc:/# exit

Como você pode ver, o comando acima, criou uma nova sessão bash — dentro da qual é possível dar comandos dentro do contêiner.
No nosso exemplo, não esqueça, existe um processo rodando em background, ainda, dentro do ‘primeiro_daemon’.

Como reiniciar automaticamente um contêiner

Se um contêiner parar ou for finalizado em consequência de um erro, é possível configurar o Docker para pô-lo pra rodar de novo automaticamente — para o caso de você não “estar por perto”, isto pode ser útil.
Podemos sinalizar com ‘–restart’, quando queremos que haja um reinício e até quantas vezes tentar.
A flag ‘–restart’ aceita valores, como ‘always’ (sempre) e ‘on-failure’ (em caso de falhas).
Veja um exemplo:

docker run --restart=on-failure:3 --name segundo_daemon -d ubuntu /bin/sh -c "while true; do echo ola mundo; sleep 1; done"
4f505f038e885ef24f5b63474f28778f75d22098a4597d19dd92ff9cf1bb20d4

Neste exemplo, portanto, a configuração --restart=on-failure:3 pede para que ele tente retomar suas atividades, em caso de falha, (failure) até 3 vezes.

Como obter mais informações sobre um contêiner

O comando ‘inspect’ pode oferecer mais dados sobre um determinado contêiner.
Experimente:

docker inspect segundo_daemon

A saída deste comando pode ser muito extensa.
Para filtrar apenas a informação desejada, use o comando grep ou a opção ‘–format’ do docker:

docker inspect segundo_daemon | grep -A5 -i "state"
    "State": {
        "Running": true,
        "Paused": false,
        "Restarting": false,
        "OOMKilled": false,
        "Dead": false,

A opção ‘-A5’, do comando grep, diz para mostrar mais 5 linhas além daquela que contém a string ‘state’.
O que se vê é que o processo está rodando, não está pausado, não foi reiniciado, não foi alvo de um kill, não está morto…
Com a opção ‘–format’, é possível obter uma resposta mais objetiva para “o contêiner está em execução?”:

docker inspect --format='{{ .State.Running }}' segundo_daemon

true

Se quiser obter informações sobre as configurações de rede, use o template .NetworkSettings.IPAddress. No exemplo abaixo, mostro como obter informações de 2 contêineres (ou mais. Basta enfileirar os nomes):

docker inspect --format='{{ .NetworkSettings.IPAddress }}' segundo_daemon primeiro_daemon
172.17.0.2
172.17.0.3

Experimente explorar o diretório /var/lib/docker, onde se encontram imagens e configurações variadas de contêineres.
Já, os seus contêineres (que você criou) podem ser encontrados em /var/lib/docker/containers.

Como remover um contêiner

Ao terminar de usar um contêiner, é possível usar o Docker command ‘rm’ (remove).
É o mesmo comando que usamos para remover arquivos no UNIX ou no GNU/Linux.
Nas versões atuais do Docker, é possível remover um contêiner, ainda em execução, com o uso da opção ‘-f’ (force):

docker rm -f primeiro_daemon segundo_daemon
primeiro_daemon
segundo_daemon

Se quiser conferir a remoção, use o comando ‘ps’:

docker ps -a

No meu caso, não há mais nenhum contêiner rodando:

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

Este artigo abordou o uso básico do Docker, com comandos para iniciar instâncias do aplicativo e como manipular processos internamente. Vimos, ainda, como obter informações sobre os recipientes e, finalmente, como removê-los e onde encontrar mais imagens e configurações prontas, que podem ajudar a aprender mais sobre o assunto.
Há outros artigos sobre o uso do Docker neste site. Para encontrá-los, experimente usar a caixa de pesquisa.

Referências:
Google Books.
Slashroot.