Um histórico sobre containers
Embora exista a palavra contêiner, (plural: contêineres) nos dicionários de português do Brasil, manterei nesse texto a terminologia container (plural: containers) para me referir aos objetos de software tratado neste texto.
Uma máquina virtual, ou uma VM (Virtual Machine) é uma simulação em software de um computador, incluindo CPU, memória, área de armazenamento de arquivos e conexão com à internet. Um aplicativo como o VMware, VirtualBox ou Gnome Boxes cria um arquivo no computador (a imagem) que se comporta como sendo outro computador, no sistema operacional escolhido. Essa imagem se torna um novo ambiente que pode ser isolado ou ter suas interações bem definidas com o computador hospedeiro. Máquinas virtuais foram a primeira resposta dada para o problema de executar diversos aplicativos simultaneamente e em isolamento nos servidores.
Containers são pacotes de software que contém um ambiente completo para a execução de um aplicativo. Isso inclui suas dependências, bibliotecas de sistemas, configurações e outros binários, além dos arquivos de configuração necessários para essa operação. Eles estão disponíveis no Linux e Windows e são extremamente úteis para executar da mesma forma os aplicativos, independentemente do ambiente usado. Eles são especialmente usados na fase de desenvolvimento, reduzindo os conflitos entre as equipes de TI por favorecerem a montagem de ambiente idêntico para todos os envolvidos no projeto. Elem disso facilitam a portabilidade de um para outro sistema operacional, ou mesmo entre diferentes modelos de arquitetura de hardware.
Nas máquinas virtuais um pacote de software inclui, além do aplicativo que se quer executar, um sistema operacional inteiro. No caso dos containers o kernel (o núcleo) do sistema operacional é compartilhado com outros containers que, por isso, usam menos recursos do que as máquinas virtuais. Um servidor físico executando três máquinas virtuais, por exemplo, teria que rodar três sistemas operacionais separados. O mesmo servidor executando três aplicativos em containers roda em um único sistema operacional, sendo que cada container tem acesso ao núcleo do sistema operacional hospedeiro. Dessa forma a máquina pode rodar um número muito superior de containers. Além disso aplicativos de container são iniciados mais rápido, porque não precisam inicializar todo o sistema operacional, e podem liberar recursos que não estão em uso.
Outro problema que os containers buscam resolver é questão dos diversos aplicativos instalados em uma máquina que partilham bibliotecas comuns. Não é raro que um dos aplicativos necessite de versão diferente da biblioteca, o que pode fazer com que partes do software instalado deixe de funcionar. Containers são, portanto, úteis para o desenvolvimento, a distribuição e instalação, e uso em produção de softwares.
Finalmente, containers introduzem um nível adicional de segurança aos computadores. Sabemos que existem programas deliberadamente projetados para atacar, invadir, roubar dados e tempo de máquina no computador hospedeiro. Mesmo programas bem-intencionados podem conter bugs perigosos para o sistema e usuário. Um programa rodando em um container só tem acesso ao seu próprio ambiente, a menos que tenha sido projetado de outra forma.
Todas essas caraterísticas tornam os containers especialmente úteis para a implementação de aplicativos e serviços na nuvem, usando ambientes tais como o Azure, AWS, Google Cloud, etc.
Docker
Docker é o formato de implementação de container mais conhecido. Ele foi desenvolvido primeiro para o uso no Linux, depois levado até plataformas com MacOS e Windows. Associado ao uso de docker temos o Kubernetes, um projeto de código aberto do Google que serve como orquestrador de aplicativos em container. Ele é um dos gerenciadores de containers e imagens do docker disponíveis.
O projeto é open-source e mantido pela empresa Docker Inc., EUA. Empresas e indivíduos contribuem para o projeto que é construído sobre uma arquitetura de plug-ins, onde componentes podem ser acrescentados ou removidos. A Open Container Iniciative, OCI, é um conselho fundado para zelar pela manutenção e observância de padrões, e é mantida pela Linux Foundation com a colaboração de Docker Inc. e outras.
Atualmente (em 2022) o docker roda nativamente no Linux. Para MacOs e Windows ele instala uma única máquina virtual que pode executar todos os containers. Em sistemas modernos é possível rodar dentro de containers aplicativos do Windows e macOS. Docker não é uma linguagem de programação nem um ambiente de desenvolvimento mas sim uma ferramenta de comando de linha que ajuda na solução de diversos problemas comuns ao processo de desenvolvimento, tais como a construção de projetos, sua distribuição, instalação, remoção, atualização e execução. Existem hoje diversos aplicativos GUI (com interfaces gráficas) para o gerenciamento do Docker.
Resumindo
Podemos pensar um container como uma caixa que contém aplicações. Dentro dela existe tudo o que é necessário para a execução das aplicações e o container se assemelha a um computador, com seu próprio nome de máquina, endereço de IP address e até seus próprios discos, todos eles virtuais e criados pelo docker.
O aplicativo dentro do container não tem contato com nada fora dele, exceto o que for explicitamente indicado. Um exemplo disso seriam os casos de interação com o usuário via teclado, ou o acesso do aplicativo a um banco de dados externo.
Terminologia
Images (imagens do Docker) contêm o código-fonte do aplicativo executável, junto com as ferramentas, bibliotecas e dependências que o código precisa para ser executado. Elas podem ser construídas pelo desenvolvedor ou baixadas prontas de repositórios como o Docker Hub. Geralmente uma imagem é composta de várias outras imagens base que são empilhadas em camadas. Vários containers podem ser criados a partir de uma imagem.
Containers são as instâncias ativas e em execução das imagens. Enquanto imagens são arquivos de leitura somente (read-only) os containers são processos ativos que podem interagir com outros processos. Administradores podem ajustar suas configurações e condições usando comandos do Docker.
Dockerfiles (arquivos Docker) são arquivos de texto com as instruções sobre como criar imagens. Um Dockerfile automatiza o processo de criação de containers, contendo todos os passos na sequência que devem ser executados para a construção da imagem. Ele é similar a um script, declarando qual é a imagem base inicial a usar e com instruções para instalar os demais programas necessários, em camadas posteriores.
Build é a ação de criar de uma imagem usando as informações fornecidas pelo Dockerfile, desde que os arquivos adicionais estejam disponíveis no diretório onde a imagem é criada.
Tag (marcação) é uma marca ou rótulo aplicado em imagens para diferenciar versões. As tags podem ser usadas para, por exemplo, baixar uma imagem em versão específica.
Layers (camadas) são modificações aplicadas à uma imagem por meio de instruções do dockerfile. Por exemplo, dentro de uma imagem do ubuntu, que está na primeira camada, pode-se instalar outro aplicativo qualquer que será construído em uma segunda camada. Layers são identificadas por ids (hashes) que são usados para identificá-las.
Repository (repositório) é uma coleção de imagens do Docker rotuladas com marcação (tags) que indicam a versão da imagem. Podem conter imagem de versões diversas diferenciadas por tags, e variantes para as diversas plataformas.
Docker Hub é o repositório público padrão de imagens do Docker considerado a “maior biblioteca para imagens de containers”. Ele contém mais de 100.000 imagens de containers provenientes de fornecedores de software comercial ou de código aberto, e desenvolvedores individuais. Usuários do Docker Hub podem compartilhar suas imagens livremente ou baixar imagens base para usar no desenvolvimento de outros projetos. Existem outros repositórios, como o GitHub. Acesse o site Docker Hub.
Registro do Docker é um sistema de armazenamento e distribuição de imagens do Docker. Ele permite rastrear versões de imagens em repositórios usando o git, uma ferramenta de controle de versão. O registro padrão para imagens mais frequentemente usado é o Docker Hub (propriedade da Docker como uma organização).
Daemon Docker é um serviço que cria e gerencia imagens Docker usando os comandos do cliente. Ele serve como central de controle da implementação do Docker. O servidor onde o daemon é executado é chamado de host do Docker, que pode ser o computador local ou um serviço em nuvem.
Docker Desktop é um aplicativo que facilita a criação e compartilhamento de aplicativos e microsserviços em containers. Junto com o Desktop são instaladas ferramentas como Kubernetes, Docker Compose, BuildKit e verificação de vulnerabilidades. Inicialmente disponível apenas para Windows e MacOS, foi disponibilizado para desenvolvedores no Linux em Maio de 2022. Docker Desktop também inclui extensões do Docker para facilitar a integração com ferramentas de outros desenvolvedores da equipe ou de terceiros.
Docker Dashboard é um aplicativo GUI para gerenciamento de imagens, containers e volumes do Docker. Ele é um aplicativo WEB que roda em Node, abrindo uma página no navegador e pode ser usado para gerenciar visualmente os recursos de container.
Docker Compose é uma ferramenta utilizada na definição e compartilhamento de aplicações multi-container. Com Compose podemos criar um arquivo YAML para definir os serviços usados. Dessa forma um aplicativo pode ser iniciado ou finalizado com um único comando. Ele também facilita a colaboração entre desenvolvedores.
Instalando o Docker
Existem duas versões disponíveis para instalação:
- Community Edition (CE), edição da comunidade,
- Enterprise Edition (EE), edição comercial.
Docker CE é gratuita. Docker EE é o mesmo pacote de software, mas com suporte técnico e acesso à outros produtos da empresa.
Instalação: Fedora Linux, Ubuntu Linux, Archlinux, Mac, Windows.
Como exemplo, listamos o procedimento de instalação no Fedora Linux:
# Primeiro habilitamos o repositório
$ sudo dnf -y install dnf-plugins-core
$ sudo dnf config-manager \
--add-repo \
https://download.docker.com/linux/fedora/docker-ce.repo
# instalamos o docker engine
$ sudo dnf install docker-ce docker-ce-cli containerd.io docker-compose-plugin
Para iniciar o serviço do docker via systemctl usamos start docker
. Depois podemos testar se a instalação foi bem sucedida verificando a versão instalada e o status do serviço.
# para iniciar o Docker
sudo systemctl start docker
# para verificar a versão instalada
$ docker --version
Docker version 20.10.17, build 100c701
# verificando o status do serviço
$ sudo service docker status
Redirecting to /bin/systemctl status docker.service
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
Active: active (running) since Fri 2022-08-12 18:52:19 -03; 1min 10s ago
TriggeredBy: ● docker.socket
Docs: https://docs.docker.com
Main PID: 32787 (dockerd)
Tasks: 13
Memory: 111.8M
CPU: 344ms # (saída truncada)
Nessa instalação é criado um grupo de usuários que podem rodar o Docker. Por default o Docker exige privilégios de root para rodar containers, o que pode ser problemático para a segurança do sistema. Para rodar o Docker sem necessidade de emitir comandos como superuser adicionamos um usuário ao grupo do Docker.
$ sudo usermod -aG docker <nome_usuario>
# verificando
$ cat /etc/group | grep docker
docker:x:973:nome_usuario
Temos dois componentes principais com a instalação do docker: o cliente e o docker daemon (também chamado de docker engine). Uma versão alternativa de docker version
(sem os hífens) fornece mais dados sobre a instalação:
$ docker version
Client: Docker Engine - Community
Version: 20.10.17
API version: 1.41
Go version: go1.17.11
Git commit: 100c701
Built: Mon Jun 6 23:03:59 2022
OS/Arch: linux/amd64
Context: default
Experimental: true
Server: Docker Engine - Community (saída truncada)
Para instalar e verificar o docker-compose
usamos:
# instalar o docker
$ sudo dnf install docker-compose # (no fedora) ou
$ sudo apt install docker-compose # (no ubuntu)
# Para verificar a instalação
$ docker-compose version
docker-compose version 1.29.2, build unknown
docker-py version: 5.0.3
CPython version: 3.10.5
OpenSSL version: OpenSSL 3.0.5 5 Jul 2022
Desinstalação e atualização: Para atualizar o docker é necessário remover os pacotes antigos e realizar uma nova instalação.
As desinstalações podem ser feitas da seguinte maneira:
# para desinstalar o docker
$ sudo dnf remove docker-desktop
# para desinstalar Docker Engine, CLI, containerd, e Docker Compose
$ sudo dnf remove docker-ce docker-ce-cli containerd.io docker-compose-plugin
Docker Desktop
Docker Desktop é um aplicativo (disponível para Mac, Linux ou Windows) que permite criar, compartilhar e executar aplicativos e microsserviços em containers. Ele fornece uma GUI (interface gráfica do usuário) simples que permite gerenciar seus containers, aplicativos e imagens diretamente de sua máquina.
Para instalar o Docker desktop faça o download do pacote mais recente: Docker desktop e o instale, por exemplo com o comando dnf
. Isso criará um ícone no desktop que pode ser clicado para iniciar o aplicativo.
$ sudo dnf install ./docker-desktop--.rpm
# para iniciar o docker-desktop clique no ícone no desktop ou
# alternativamente use, para iniciar e finalizar o docker-desktop
$ systemctl --user start docker-desktop
$ systemctl --user stop docker-desktop
O Docker-desktop é iniciado dando as alternativas de criação de uma conta no Docker, de login em contas já criadas, ou de prosseguir sem esse login.
Docker Dashboard (GUI)
Um aplicativo web pode ser usado com Docker Dashboard. O Dashboard roda com Node.js que, portanto, precisa estar instalado em seu sistema. Depois você deve clonar um repositório do Github.
# clone repositório
$ git clone git@github.com:rakibtg/docker-web-gui.git
# mude para o novo directório criado
$ cd ./docker-web-gui
# execute o app app.js usando o node. Essa ação instalará os módulos necessários ainda não instalados.
$ node app.js
# agora você pode abrir no navegador a página http://localhost:3230/
O navegador abrirá uma página exibindo as imagens instaladas, containers em execução ou parados, visualização dos logs, criação e vizualização de grupos de containers.
Para baixar o código do aplicativo usando git clone git@github.com:rakibtg/docker-web-gui.git
, você deve ter uma conta do GitHub com chaves certificadas de ssh. Instruções em Connecting to GitHub with ssh. Alternativamente você pode entrar no site do GitHub para esse aplicativo, baixar e instalar o código.
Imagens do Docker
Uma imagem do docker é um objeto que contém um aplicativo e arquivos de sistema, suficientes para rodar esse aplicativo. Essas imagens podem ser construídas pelo desenvolvedor ou baixadas pela internet de algum repositório, onde outros desenvolvedores as disponibilizaram. Por default as imagens são procuradas no GitHub. Um exemplo simples pode ser dado com a imagem de hello_world. Digitamos no prompt de comando do terminal:
# o primeiro passo é baixar uma imagem†
$ docker pull hello-world
# o container pode ser agora executado
$ docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
(saída truncada)
† O uso de docker pull <imagem>
não é estritamente necessário. O comando docker run procura primeiro a imagem na máquina local e, se ela não foi previamente baixada, ele a procura em Docker Hub. Se a imagem for encontrada ele a baixa e constroi um container à partir dela. No caso desse exemplo a imagem contém um aplicativo simples de demonstração que imprime a mensagem listada (que foi aqui truncada) no console. A cada execução de run um novo container é criado e seu aplicativo subjacente é rodado. Imagens baixadas são previamente compiladas (built).
Se você está com o Docker-Desktop aberto a imagem baixada aparecerá no painel do aplicativo.
O comando docker image ls
permite ver quais são as imagens já baixadas:
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 9 months ago 13.3kB
A tag latest indica que a última versão disponível foi baixada. Em outros casos, a tag é a versão da imagem. A imagem hello-world foi preparada para teste dos iniciantes e contém instruções interessantes. Para apagar um imagem baixada usamos docker rm imagem
ou cicando no painels do Docker-Desktop. Mesmo sem a imagem baixada podemos rodar o container. O output da execução será em inglês (para essa imagem) mas a exibiremos aqui com partes traduzidas.
# para apagar a imagem
$ docker rm hello-world
# para rodar novamente essa imagem
$ docker container run hello-world
Hello from Docker!
Essa messagem mostra que sua instalação parece estar funcionando corretamente.
Para gerar essa mensagem Docker seguiu os seguintes passos:
1. O cliente Docker fez contato com o Docker daemon.
2. O Docker daemon baixou (pulled) a imagem "hello-world" do Docker Hub. (amd64)
3. O Docker daemon criou um novo container à partir dessa imagem. O container
executou código que produziu o presente output.
4. O Docker daemon transmitiu esse output para o Docker client, que o enviou para
o terminal.
Você pode tentar algo mais ambicioso, por ex. rodando o container do Ubuntu usando:
$ docker run -it ubuntu bash
Partilhe imagens, fluxos de trabalho automatizados e mais coisas usando um Docker ID gratuito:
https://hub.docker.com/
Para ver mais exemplos e ideias visite:
https://docs.docker.com/get-started/
Aproveite a oportunidade para entrar no Docker Hub e criar uma conta.
Comandos do Docker
Recapitulando, podemos baixar uma imagem do docker usando pull
.
$ docker pull <nome_imagem>:latest
Como vimos latest significa que baixamos a última e mais atualizada versão da imagem. Outra versão pode ser especificada se necessário como, por exemplo, fazendo $ docker pull <nome_imagem>:8.0
. Para executar essa imagem usamos:
$ docker run -d --name=<nome_alternativo> -p m:n -<nome_imagem>
Além do comando run para criar e rodar um container usamos os parâmetros:
--name
: para dar um nome alternativo para o container criado,
-p
: para tornar a porta do docker visível fora do container,
<nome_imagem>
: especifica a imagem a ser executada,
m:n
: mapeia portas do container em portas do host. (porta_host:porta_container
)
Podemos ver quais são os containers em execução:
docker ps
container ID IMAGE COMMAND CREATED STATUS
642881d63879 mysql/mysql-server "/entrypoint.sh mysq…" 16 minutes ago Up 16 minutes (healthy)
PORTS NAMES
0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060-33061/tcp mysql1
Para encerrar a execução, e remover o container usamos, respectivamente:
# encerrar
$ docker stop <nome_imagem>
# remover container
$ docker rm <nome_imagem>
No linux, os arquivos de configuração do docker e as imagens baixadas ficam no diretório /var/lib/docker
. No Windows o endereço desses arquivos varia, de acordo com o modo de instalação. Esses arquivos nunca devem ser manipulados diretamente pelo usuário.
Uma página de ajuda é exibida com docker help
, sobre a sintaxe de docker. Uma lista completa da saída do help pode ser vista na seção Docker Help.
# ajuda geral
$ docker help
# ajuda sobre um comando específico
$ docker <comando> help
# por exemplo, para o comando cp (copy)
$ docker cp help
Podemos ver todas as imagens baixadas no computador e apagá-las, se assim for desejado.
# para listar as imagens
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql/mysql-server latest 5a9594052aec 3 months ago 438MB
hello-world latest feb5d9fea6a5 10 months ago 13.3kB
# para apagar as imagens usamos os primeiros caracteres do id para identificá-las
$ docker image rm -f 5a
$ docker image rm -f fe
#alternativamente, o seguinte comando lista todos os containers
$ docker container ls --all --quiet
# podemos apagar todos os containers usando (veja descrição abaixo)
$ docker container rm --force $(docker container ls --all --quiet)
A sintaxe $(), usada no último comando, faz com que a saída de um comando seja enviada para o comando externo. Nesse caso o comando interno gera uma lista de containers instalado, que é enviada para o comando de apagamento forçado. A chave –force (ou -f) força o apagamento mesmo que exista uma imagem desse container em execução. Esse comando deve ser usado com cautela pois a remoção é feita sem nenhuma confirmação.
Várias dessas operações, como inicializar o docker, apagar imagens, visualizar status e rodar uma imagem, podem ser executadas através do aplicativo gui, Docker Desktop. Você encontra mais ajuda no site do docker.
Imagem do MySQL
Como um exemplo mais completo e útil vamos carregar e executar uma imagem contendo o mysql. Começamos por baixar (pull) a imagem.
# baixar a imagem
$ docker pull mysql/mysql-server:latest
# um outpup é exibido:
What's Next?
1. Sign in to your Docker account → docker login
2. View a summary of image vulnerabilities and recommendations → docker scout quickview mysql/mysql-server:latest
A mensagem (aqui truncada) sugere o login na conta do docker ou a visualização de recomendações. O login também pode ser feito na janela do Docker Desktop.
Como vimos, latest significa que baixamos a última e mais atualizada versão do mysql. Outra versão pode ser especificada se necessário, como em $ docker pull mysql/mysql-server:8.0
. Para executar essa imagem usamos:
# executar a imagem do mysql
$ docker run --name=mysql1 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=meupassword -d mysql/mysql-server
# um id é exibido
Pode ocorrer que a porta designada esteja ocupada por outro serviço do computador host, o que provoca a emissão de uma mensagem de erro. Nesse caso podemos usar outra porta, tal como docker run --name=mysql1 -p 8080:3306...
.
Além do comando run para criar e rodar um container usamos os parâmetros:
--name
: para dar um nome alternativo para o container criado,
-p
: para tornar a porta do docker visível fora do container,
-e
: para inserir um password de gerenciamento do mysql,
mysql/mysql-server
: especifica a imagem a ser executada,
3306:3306
: mapeia portas do container em portas do host, (porta_host:porta_container
).
Podemos ver quais são os containers em execução:
docker ps
container ID IMAGE COMMAND CREATED STATUS
642881d63879 mysql/mysql-server "/entrypoint.sh mysq…" 16 minutes ago Up 16 minutes (healthy)
PORTS NAMES
0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060-33061/tcp mysql1
A linha foi quebrada para facilitar a visualização. Para conectar com o servidor do mysql executamos:
$ docker exec -it mysql1 mysql -uroot -p
Enter password: meupassword
Welcome to the MySQL monitor. ... (saída truncada)
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
Um prompt de comandos fica aberto para receber comandos do mysql. Operações usuais sobre o banco de dados ficam disponíveis. Você pode encontrar mais informações sobre a sintaxe básica do SQL no artigo Linguagem de Consulta SQL.
Por exemplo, no caso abaixo criamos um banco de dados, uma tabela, inserimos valores, fazemos uma consulta, finalizando depois o uso do MySQL.
# cria um banco de dados
mysql> CREATE DATABASE teste;
# use esse BD
mysql> USE teste;
# cria uma tabela
mysql> CREATE TABLE cidades(nome varchar(60),id varchar(4));
# insere valores na tabela
mysql> INSERT INTO cidades SET nome='Belo Horizonte', id='1';
mysql> INSERT INTO cidades SET nome='Salvador', id='2';
mysql> INSERT INTO cidades SET nome='Curitiba', id='3';
mysql> SELECT * FROM cidades;
+----------------+------+
| nome | id |
+----------------+------+
| Belo Horizonte | 1 |
| Salvador | 2 |
| Curitiba | 3 |
+----------------+------+
3 rows in set (0.00 sec)
# para abandonar o programa
mysql> exit
Para encerrar a execução, e remover o container usamos, respectivamente:
# encerrar
$ docker stop mysql1
# remover container
$ docker rm mysql1
Conectando com o container
A interação com um container se dá de modo similar à execução de comandos em um computador remoto. Para mostrar isso executaremos uma imagem do docker chamada diamol/base, criada e disponibilizada no Dockerhub por E. Stoneman para exemplificar um trecho de seu livro (veja bibliografia). Para interagir com o aplicativo em execução usamos as flags –interactive e –tty (ou simplesmente -i e -t) para fazer essa interação através do terminal. O primeiro comando abaixo baixa a imagem e a executa, criando um container que expõe um prompt de terminal para o usuário. Os comandos aceitos no prompt dependem do sistema operacional. Por exemplo, no linux usamos ls para listar os arquivos do diretório atual; no Windows usamos dir.
# para baixar e rodar a imagem
$ docker container run --interactive --tty diamol/base
Unable to find image 'diamol/base:latest' locally
latest: Pulling from diamol/base
31603596830f: Pull complete
792f5419a843: Pull complete
Digest: sha256:787fe221a14f46b55e224ea0436aca77d345c3ded400aaf6cd40125e247f35c7
Status: Downloaded newer image for diamol/base:latest
# O aplicativo expõe o prompt do terminal (usando os sinais / ⧣ para indicar o prompt)
/ ⧣
# no linux podemos listar os arquivos na pasta ativa
/ ⧣ ls
bin etc lib mnt proc run srv tmp var
dev home media opt root sbin sys usr
# o nome da máquina em execução é o mesmo que o id da imagem
/ ⧣ hostname
2c33c99fcaf7
# para ver a data
/ ⧣ date
Sat Aug 6 15:38:21 UTC 2022
# uma lista de comandos disponíveis pode ser vista com help
/ # help
Built-in commands:
------------------
. : [ [[ alias bg break cd chdir command continue echo eval exec
exit export false fg getopts hash help history jobs kill let
local printf pwd read readonly return set shift source test times
trap true type ulimit umask unalias unset wait
# para terminar a execução
/ ⧣ exit
Mantendo esse terminal aberto, podemos abrir outro terminal e listar detalhes dos containers em execução:
$ docker container ls
container ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2c33c99fcaf7 diamol/base "/bin/sh" 3 minutes ago Up 3 minutes strange_lehmann
# para listar os processos dentro desse container (notando que 2c são os primeiros dígitos do container ID)
$ docker container top 2c
UID PID PPID C STIME TTY TIME CMD
root 13436 13410 0 12:36 pts/0 00:00:00 /bin/sh
# para listar as ações (log) executadas nesse container
$ docker container logs 2c
# ls
bin etc lib mnt proc run srv tmp var
dev home media opt root sbin sys usr
(retorna uma lista de comandos já utilizados no container, aqui truncada)
# inspect retorna uma descrição detalhada do container
$ docker container inspect 2c
[
{
"Id": "2c33c99fcaf7fb94393ce1e7e31ce05ab6f5bcc914fc5eac8c90e600cf711995",
"Created": "2022-08-06T15:36:14.327115583Z",
"Path": "/bin/sh",
"Args": [],
"State": {
"Status": "running",
"Running": true,
"Paused": false, ... (saída truncada)
},
}
]
Os comandos usam o atalho 2c para se referir ao ID do container 2c33c99fcaf7. inspect retorna dados no formato JSON, aqui truncados, incluindo informações sobre caminhos usados pelo filesystem virtual e muitos outros.
Podemos ver uma lista de imagens instaladas usando docker image list
ou docker image ls
, e apagar uma imagem que não será mais necessária com docker image rm <id>
, onde <id>
é o id listado no passo anterior. No nosso caso, se usamos:
# para listar imagens baixadas
$ docker image list
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql/mysql-server latest 5a9594052aec 3 months ago 438MB
hello-world latest feb5d9fea6a5 10 months ago 13.3kB
diamol/base latest 9fc3f74c8b53 17 months ago 7.13MB
# para apagar a imagem referente à diamol/base (a imagem está em uso no container 5f73d74675a7)
$ docker image rm 9fc3f74c8b53
Error response from daemon: conflict: unable to delete 9fc3f74c8b53 (must be forced)
- image is being used by stopped container 5f73d74675a7
# para forçar a interrupção desse container e apagar a imagem
$ docker image rm -f 9fc3f74c8b53
Deleted: sha256:9fc3f74c8b533bed2ac40ccfc6a5235ebb626a26a230dc3731fcdf926d984106
# lista todos os containers (em execução ou não)
$ docker container ls --all
container ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5f73d74675a7 9fc3f74c8b53 "/bin/sh" 3 hours ago Exited (0) 2 hours ago intelligent_wescoff
2c33c99fcaf7 9fc3f74c8b53 "/bin/sh" 6 hours ago Exited (0) 3 hours ago strange_lehmann
e0ca567900b9 nginx "/docker-entrypoint.…" 25 hours ago Created webserver
5ccc8d7d5ff3 hello-world "/hello" 32 hours ago Exited (0) 32 hours ago hopeful_banach
fb9dc473c7f5 hello-world "/hello" 32 hours ago Exited (0) 32 hours ago loving_swartz
5e5c65bb00c4 hello-world "/hello" 32 hours ago Exited (0) 32 hours ago cool_cannon
(... saída truncada)
Como nenhum container está ativo (no meu caso) eles têm o status Exited
. Quando um container está em execução o mesmo ocorre com o aplicativo que ele contém. Quando o processo é terminado o container entra no estado de encerrado (Exited). Containers encerrados não usam recursos de memória nem tempo de CPU do computador mas são mantidos em disco e ocupam espaço. Containers não desaparecem quando são terminados mas continuam a existir e podem ser executados novamente. Nesse estado eles retêm logs e arquivos no sistema de arquivos. Para remover containers encerrados você deve emitir o controle específico para tal.
Outros comandos associados:
$ docker ps -a # Lista containers, informando a imagem que os gerou
$ docker images # Lista imagens
$ docker rm <container_id> # Remove um container interrompido (não em execução)
$ docker rm -f <container_id> # Força a remoção de um container mesmo que em execução
$ docker rmi <image_id> # Remove uma imagem que não esteja
# associada um container em execução
$ docker rmi -f <image_id> # Força a remoção da imagem mesmo que esteja em uso
$ docker system prune -a # remove: todos os containers parados,
# todas as redes não utilizadas
# todas as imagens não ativas
# todo o cache de docker
Claro que o comando docker system prune -a
deve ser usada com bastante cuidado.
Uma lista de comandos está listada na seção Docker Help.
Rodando um webserver
Outro bom exemplo de funcionamento do docker consiste em rodar um container preparado para fins educacioanis pelo DockerHub, que roda um tutorial interativo para iniciantes. Outras instruções podem ser encontradas em Docker Docs: Getting started.
$ docker run -d -p 8080:80 docker/getting-started
# as flags podem ser unidas
docker run -dp 8080:80 docker/getting-started
# para acessar o tutorial abra o navegador em http://localhost:8080.
As flags ou chaves significam o seguinte:
-d
: execute o container em mode destacado (detached ou em background).
-p 8080:80
: associa a porta 8080 do host à porta 80 do container. Se a porta 8080 já estiver em uso especifica outra porta, como 80 ou 3000.
docker/getting-started
especifica o nome da imagem a ser usada.
Como já vimos, a imagem é baixada (se não estiver no computador) e rodada. Ela cria uma seção de um servidor que pode ser acessado em http://localhost:8080, contendo um tutorial de uso do docker com instruções iniciais para seu uso, preparada por seus desenvolvedores.
Se iniciarmos uma imagem em segundo plano e quisermos um terminal interativo podemos executar
$ docker exec -it <container> bash
Rodando Oracle Linux
Mostraremos outro exemplo rodando um container com Oracle Linux.
Verificamos primeiro o status do docker:
$ service docker status
Redirecting to /bin/systemctl status docker.service
○ docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
Active: inactive (dead)
TriggeredBy: ○ docker.socket
Docs: https://docs.docker.com
Vemos que o docker está inativo, como exibido em Active: inactive (dead)
. Então reiniciamos o serviço:
$ sudo service docker start
[sudo] password for guilherme:
Redirecting to /bin/systemctl start docker.service
$ service docker status
Redirecting to /bin/systemctl status docker.service
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
Active: active (running) since Mon 2022-08-15 16:32:32 -03; 2s ago
(saída truncada)
Podemos terminar um comando no prompt do bash usamos CTRL-C
.
Para baixar a imagem do Oracle Linux usamos pull oraclelinux:9
, sendo 9 a versão mais atual, na data em que esse texto foi escrito. Caso seja necessária uma versão anterior usamos pull oraclelinux:8
(ou a versão necessária). No caso do Oracle Linux a tag latest foi removida, como se pode ver na página docker: oraclelinux.
$ sudo docker pull oraclelinux:9
9: Pulling from library/oraclelinux
16c5055e8b97: Pull complete
Digest: sha256:93514816e192d51fbb34c008a479c789c43fb1fe0c2f91bd5be1ba7919dafa77
Status: Downloaded newer image for oraclelinux:9
docker.io/library/oraclelinux:9
# para visualizar as imagens baixadas
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker/getting-started latest cb90f98fd791 4 months ago 28.8MB
oraclelinux 9 61a922496eee 16 hours ago 236MB
Podemos rodar essa imagem, gerando um container, com o comando docker run <nome_imagem>
. Por default a imagem é criada, se já não existe, e roda em primeiro plano (attached mode). Para rodá-la no segundo plano (em background ou dettached mode) usamos o marcador (flag) -d
. Para usar o terminal de modo interativo use as opções –i, –t
. As flags podem ser juntas, como em –dit
. A flag –rm
serve para apagar o container quando ele for encerrado. A opção --name
é usada para dar um nome para a imagem sendo rodada. Esse nome deve ser único (não pode ter o mesmo nome de um que já está rodando).
# para rodar a imagem em primeiro plano (attached mode)
$ sudo docker run <nome_imagem>
# para rodar a imagem em segundo plano ou background (dettached mode)
$ sudo docker run -d <nome_imagem>
No caso de nossa imagem para o oracle linux usaremos run
com as flags já descritas. Um terminal é apresentado, onde podem ser digitados comandos apropriados.
$ docker run -i -t --rm --name oraclelinux oraclelinux:9
[root@723e7c1a71ea /]#
# se executado em outro terminal (para não fechar o terminal do oraclelinux)
# podemos ver que temos uma imagem rodando.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
oraclelinux 9 a0ad236ea4f0 6 days ago 218MB
# no prompt do Oracle digitamos comandos. Por exemplo:
[root@723e7c1a71ea /]# cat /etc/oracle-release
Oracle Linux Server release 9.0
[root@03d35e4c35b1 teste_oracle]# cat /etc/os-release
NAME="Oracle Linux Server"
VERSION="9.0"
<saída truncada>
O comando cat é usado para ler, concatenar e escrever em arquivos, para o output padrão. Outros comandos usuais do linux podem ser executados no prompt:
[root@723e7c1a71ea /]# mkdir teste_oracle # cria um novo diretório
[root@723e7c1a71ea /]# cd teste_oracle # move cursor para o novo diretório
# envia texto para arquivo.txt
[root@723e7c1a71ea teste_oracle]# echo "teste de docker no oraclelinux" > arquivo.txt
# exibe conteúdo do arquivo.txt
[root@723e7c1a71ea teste_oracle]# cat arquivo.txt
teste de docker no oraclelinux
# para interromper a execução usamos exit
[root@723e7c1a71ea teste_oracle]# exit # retornamos ao prompt do sistema hospedeiro $
Uma vez rodando o Oracle Linux todas as operações válidas no sistema podem ser executadas. Mais detalhes sobre o Oracle Linux 9 pode ser lido no site da Oracle.
O Docker é normalmente usado para rodar aplicativos em segundo plano e programas CLI (command-line interface). Mas ele também pode ser usado para executar programas com interface gráfico, desde que você faça o setup necessário. Informações podem ser vistas por exemplo em Baeldung.com: Running GUI Applications in a Linux Docker Container.
Docker Help
A execução de docker help
resulta em uma lista de comandos e parâmetros, mostrados na tabela.
Para ajuda sobre comando específico digite docker COMMAND --help
. Para mais informações visite Docker Guides.
O Docker é executado como a seguinte sintaxe:
docker [OPÇÕES] COMANDO
Comandos comuns: |
run |
Cria e executa um novo container de uma imagem |
exec |
Executa comando em container em execução |
ps |
Lista containers |
build |
Cria imagem de um Dockerfile |
pull |
Download imagem de um repositório† |
push |
Upload imagem para repositório† |
images |
Lista imagens |
login |
Login no repositório† |
logout |
Logout do repositório† |
search |
Pesquisa imagens no Docker Hub |
version |
Exibe informações de versão do Docker |
info |
Exibe informações gerais de sistema |
Comandos de gerenciamento: |
builder |
Gerencia builds |
buildx* |
Docker Buildx |
compose* |
Docker Compose |
container |
Gerencia containers |
context |
Gerencia contexts |
debug* |
Abre uma shell dentro de qualquer imagem ou container |
dev* |
Ambiente de Docker Dev |
extension* |
Gerencia extensões do Docker |
feedback* |
Fornece feedback direto no terminal |
imagem |
Gerencia imagens |
init* |
Cria arquivos de inicialização do Docker para o projeto |
manifest |
Gerencia manifestos de imagem e lists do Docker |
network |
Gerencia networks |
plugin |
Gerencia plugins |
sbom* |
Visualiza Software Bill Of Materials (SBOM) de uma imagem |
scout* |
Docker Scout |
system |
Gerencia Docker |
trust |
Gerencia confiança sobre imagens do Docker |
volume |
Gerencia volumes |
Comandos de grupo: |
attach |
Anexa entrada, saída e mensagens de erro padrões local a container em execução |
commit |
Cria nova imagem após alteração em container |
cp |
Copia arquivos/pastas entre um container e sistema local |
create |
Cria novo container |
diff |
Inspeciona alterações em arquivos e pastas no container |
events |
Recebe eventos no servidor em tempo real |
export |
Exporta aqruivos de sistema em um container para arquivo tar |
history |
Exibe o histórico de uma imagem |
import |
Importa conteúdo de tarball para criat sistema na imagem |
inspect |
Retorna informação de baixo nível sobre objetos do Docker |
kill |
Extingue um ou mais containersem execução |
load |
Carrega uma imagem de arquivo tar ou STDIN |
logs |
Captura os logs de um container |
pause |
Pausa todos os processos dentro de um ou mais containers |
port |
Lista mapeamento de portas para o container |
rename |
Renomeia um container |
restart |
Reinicia um ou mais containers |
rm |
Remove um ou mais containers |
rmi |
Remove uma ou mais imagems |
save |
Grava uma ou mais imagems para arquivo tar (para STDOUT, por default) |
start |
Inicializa um ou mais containers parados |
stats |
Exibe estísticas de containers em tempo real |
stop |
Para um ou mais containers em execução |
tag |
Cria uma tag TARGET_IMAGE em referência à SOURCE_IMAGE |
top |
Exibe os processos ativos de um container |
unpause |
Recomeça todos os processos dentro de um ou mais containers |
update |
Atualiza a configuração de um ou mais containers |
wait |
Paraliza a execução até que um ou mais containers são interrompidos, depois exibe códigos de saída |
Opções globais: |
–config string |
Local dos arquivos de configuração do cliente (default “/home/usuario/.docker”) |
-c, –context string |
Nome do contexto a ser usado para conectar com o daemon (sobrescreve DOCKER_HOST e ajusta default para “docker context use”) |
-D, –debug |
Liga modo de debug |
-H, –host list |
Daemon socket a conectar |
-l, –log-level string |
Ajusta nível de logging (“debug”, “info”, “warn”, “error”, “fatal”) (default é “info”) |
–tls |
Usa TLS; implícito por –tlsverify |
–tlscacert string |
Aceita apenas certificados assinado por esse CA (default “/home/usuario/.docker/ca.pem”) |
–tlscert string |
Caminho para arquivo de certificado (default “/home/usuario/.docker/cert.pem”) |
–tlskey string |
Caminho para arquivo de chave (default “/home/guilherme/.docker/key.pem”) |
–tlsverify |
Use TLS e verifique o remoto |
-v, –version |
Exibe informação de versão e termina |
†: Na tabela usamos a expressão repositório no lugar de registry
. O Registry é a implementação de código aberto para armazenamento e distribuição de imagens de containers e outros conteúdos. A implementação do registro Docker Hub é baseada em Distribuição. Docker Hub implementa especificação de distribuição OCI versão 1.0.1. Mais informações em Docker Hub Registry.
Bibliografia
Livros:
- Ashley, David: Foundation Dynamic Web Pages with Python, Apress, 2020,
- Miel, Ian: Sayers, Aidan H.: Docker in Practice, 2 Ed., Manning, 2019,
- Nickoloff, Jeff; Kuenzli, Stephen: Docker in Action, 2 Ed., Manning, 2019,
- Poulton, Nigel: Docker Deep Dive, disponível em Leanpub.com, 2018,
- Stoneman, Elton: Learn Docker in a Month of Lunches, Manning, 2020,
- Vohra, Deepak: Pro Docker, Apress, 2016.
Sites: