Treinamento Docker

Treinamento em docker e sua utilização: conceitos básicos, comandos úteis, criando imagens docker e um exemplo de aplicação de blog (servidor web + banco de dados).

Conceitos

docker

O Docker é uma plataforma de código aberto que facilita a criação de ambientes isolados durante o desenvolvimento de software. Isso é importante para a gestão da infraestrutura da aplicação, desde a criação até a modificação dos serviços.

Na prática, o Docker age como uma máquina virtual que roda software dentro de outro sistema operacional. O conceito de container Linux é anterior à tecnologia do docker (Leia mais - O que é um container Linux).

Vantagens:

docker x virtualização

Os contêineres do Docker têm seu próprio sistema de arquivos, estrutura de dependências, processos e recursos de rede. A aplicação tem tudo o que precisa dentro do contêiner e pode ser executada em qualquer lugar. A tecnologia de contêiner do Docker usa diretamente os recursos subjacentes do kernel do sistema operacional host.

As máquinas virtuais (VMs) fornecem a virtualização de uma máquina inteira (servidor). Uma máquina virtual emula os componentes de hardware de uma máquina física, como CPU, memória, placa de interface de rede, controladores USB e placas de som. Você pode executar um sistema operacional convidado e várias aplicações no ambiente virtual.

Container-VM-Comparison.png

Comparação de docker e máquinas virtuais

container

O que é construído pelo Docker. É uma aplicação encapsulada, construída com as bibliotecas e dependências necessárias, e que pode ser executada em qualquer lugar que o Docker esteja instalado.

host

É a máquina que possui o Docker instalado e que executará os contêineres (no nosso caso, a máquina local).

porta

O mapeamento de portas é utilizado para acessar o serviço que roda dentro do contêiner. Nós abrimos uma porta no host para nos dar acesso à porta correspondente dentro do contêiner docker. Dessa forma, todas as requisições que são feitas no host podem ser direcionadas para dentro do contêiner docker.

volume

O sistema de arquivos do contêiner é volátil, quando o contêiner é destruído, todos os arquivos se perdem. O volume são diretórios externos ao contêiner, que são montados diretamente nele e, desse forma, não seguem esse padrão de volatilidade padrão dos demais arquivos, portanto os volumes são persistidos.

image

Uma imagem é como uma versão congelada de um contêiner. As imagens são criadas através de um arquivo chamado Dockerfile ou de um contêiner em execução.

tag

A tág é uma versão específica de uma imagem docker. Geralmente ela é associada da uma determinada versão do serviço principal que é oferecido em um determinado contêiner. Por convenção, a versão mais recente de uma imagem é disponibilizada na tag latest.

workdir

É a pasta padrão de trabalho do contêiner. Quando você entra dentro do contêiner, ou executa um comando nele, caso não seja fornecido o caminho completo, será executado por padrão a partir desta pasta.

docker compose

Uma ferramenta para definição e execução de múltiplos containers Docker. Com ela é possível configurar todos os parâmetros necessários para executar cada container a partir de um arquivo de definição.

hub

É um local (repositório docker) onde são armazenadas as imagens docker. Pode ter acesso público ou restrito.

Referências

Docker (software)

O que é Docker, principais vantagens e quando utilizá-lo no desenvolvimento de software?

Docker: tudo o que você precisa saber

O que é Docker: Um Guia Completo

Qual é a diferença entre o Docker e uma VM?

Instalação Debian/Ubuntu

Instalação em uma máquina Debian ou distribuição baseada em sistemas Debian.

Pré-requisito

Acesso de sudo na máquina em que será executada a instalação.

Repositório

Definindo o repositório docker do apt:

# Adicioando a chave GPG oficial do Docker:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Adicionando o repositório APT dos pacotes do Docker:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Atualizando a lista local de pacotes no sistema:
sudo apt-get update

Instalação

Instalando os pacotes:

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Permissão

Adicionando permissão para que o seu usuário no sistema não necessite de sudo para executar os comandos docker:

# adicionando o seu usuário ao grupo do docker:
sudo usermod -aG docker $USER

Importante: depois de adicionar o seu usuário ao grupo docker, é necessário recarregar a sessão (deslogar e logar novamente com o seu usuário ou reiniciar o sistema) para que essas alterações sejam aplicadas.

Teste se é possível acessar os comandos docker sem a necessidade de sudo:

docker ps

Testando

Testando se o pacote docker foi instalado corretamente:

docker run hello-world

Saída esperada:

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete 
Digest: sha256:94323f3e5e09a8b9515d74337010375a456c909543e1ff1538f5116d38ab3989
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

(...)

Referências

Instalar o Docker Engine no Debian

Principais comandos

docker run

Cria um novo contêiner, o inicia e executa o comando especificado (quando nada é especificado, executa o comando padrão).

docker run hello-world

Você verá uma saída como:

Hello from Docker!
This message shows that your installation appears to be working correctly.

(...)

No comando anterior o terminal é direcionado para dentro do contêiner. Para iniciá-lo no modo avulso (detached) utilizaremos o parâmetro -d:

docker run -d hello-world

O terminal exibirá o ID de criação do contêiner, algo como:

bdcaba00ed90289490331613191d1ec2010dbc94330b532b4da8f7714e417d8e

Quando um nome (parâmetro --name="nome") não é fornecido, o Docker criará o container com um nome aleatório, geralmente composto de 2 palavras (nome1_nome2).

Exemplo: inspiring_euclid

Dica: Todos os comandos de manipulação de contêiners docker poder ser utilizados se referenciando o nome do contêiner ou o seu respectivo ID.

docker ps

Lista os contêineres disponíveis na máquina. Por padrão, somente aqueles que estão atualmente executando serão exibidos. Para listar todos, utilize o parâmetro -a:

docker ps -a

No nosso exemplo, você verá algo como:

CONTAINER_ID IMAGE COMMAND CREATED STATUS PORTS NAMES
14a72c95d77b hello-world "/hello" 1 minute ago Exited (0) 1 minutes ago   unruffled_bartik

docker start

Inicia um contêiner que já tenha sido criado no host, seu acesso poderá ser realizado por nome ou por ID. Utilizando o exemplo anterior, vamos copiar o ID informado na coluna CONTAINER_ID para iniciá-lo novamente.

docker start 14a72c95d77b

Você verá como saída o ID do container indicando que ele foi iniciado.

14a72c95d77b

Dica: Um contêiner pode ser finalizado por ter terminado de executar a rotina para qual ele foi designado (Exemplo: processamento de um arquivo texto) ou por ter encontrado um erro no serviço (Exemplo: configuração incorreta, como um erro de sintaxe, no servidor web). Quando se cria um contêiner, pode-se definir qual o política padrão de reinicialização quando ele é encerrado: no, always, on-failure, unless-stopped.

docker stop

Encerra a execução de um contêiner. Mesma lógica do comando anterior. 

docker stop 14a72c95d77b

Dica: A execução do container é paralisada, no entanto o container não é removido do host.

docker restart

Reinicia a execução de um contêiner( stop e start). Mesma lógica dos comandos anteriores.

docker rm

Remove um contêiner do host. Você pode utilizar docker ps -a para listar a relação de contêineres disponíveis, e removê-lo por nome ou id.

docker rm 14a72c95d77b

O comando docker rm somente remove containers que não estão em execução. Para remover um container em execução, use docker rm -f

Para conferir a remoção, vamos checar novamente os containers criados no host:

docker ps -a

docker images

Conferir as imagens docker atualmente disponíveis no host:

docker images

Quando uma imagem docker não está disponível localmente, o docker tentará fazer o download da imagem docker em um repositório docker (Ex: hub.docker.com). Caso o repositório seja privado, será necessário efetuar o login neste repositório para ter acesso às imagens.

docker pull

Faz o download da imagem docker do repositório para o host:

docker pull alpine

Você verá uma saída como:

Using default tag: latest
latest: Pulling from library/alpine
ec99f8b99825: Pull complete 
Digest: sha256:b89d9c93e9ed3597455c90a0b88a8bbb5cb7188438f70953fede212a0c4394e0
Status: Downloaded newer image for alpine:latest
docker.io/library/alpine:latest

Quando você não especifica uma tag, o docker tomará como valor padrão a tag latest. O padrão de nomenclatura da imagem é nome-da-imagem:nome-da-tag.

Fazer o download de uma imagem docker em uma tag específica (tag: 3.20.1):

docker pull alpine:3.20.1

Você verá uma saída como:

3.20.1: Pulling from library/alpine
Digest: sha256:b89d9c93e9ed3597455c90a0b88a8bbb5cb7188438f70953fede212a0c4394e0
Status: Downloaded newer image for alpine:3.20.1
docker.io/library/alpine:3.20.1

Depois de baixarmos as imagens, vamos conferir novamente as imagens disponíveis:

docker images

Saída:

REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
alpine       3.20.1    a606584aa9aa   12 days ago   7.8MB
alpine       latest    a606584aa9aa   12 days ago   7.8MB

docker rmi

Remove a imagem do host. No entanto, só é possível remover as imagens que não está sendo utilizadas por nenhum contêiner no host.

docker rmi alpine

Para ver a lista de todas as imagens baixadas para o host utilize docker images

docker exec

Executa um comando dentro de um contêiner que está em execução.

docker run --name ubuntu_bash -d -it ubuntu
docker ps -a

Saída:

CONTAINER ID   IMAGE     COMMAND       CREATED         STATUS         PORTS     NAMES
759d52725ffe   ubuntu    "/bin/bash"   7 seconds ago   Up 6 seconds             ubuntu_bash
docker exec ubuntu_bash ls -la

Saída:

total 56
drwxr-xr-x   1 root root 4096 Jul  3 12:50 .
drwxr-xr-x   1 root root 4096 Jul  3 12:50 ..
-rwxr-xr-x   1 root root    0 Jul  3 12:50 .dockerenv
lrwxrwxrwx   1 root root    7 Apr 22 13:08 bin -> usr/bin
drwxr-xr-x   2 root root 4096 Apr 22 13:08 boot
drwxr-xr-x   5 root root  360 Jul  3 12:50 dev
drwxr-xr-x   1 root root 4096 Jul  3 12:50 etc
drwxr-xr-x   3 root root 4096 Jun  5 02:06 home
lrwxrwxrwx   1 root root    7 Apr 22 13:08 lib -> usr/lib
lrwxrwxrwx   1 root root    9 Apr 22 13:08 lib64 -> usr/lib64
drwxr-xr-x   2 root root 4096 Jun  5 02:02 media
drwxr-xr-x   2 root root 4096 Jun  5 02:02 mnt
drwxr-xr-x   2 root root 4096 Jun  5 02:02 opt
dr-xr-xr-x 399 root root    0 Jul  3 12:50 proc
drwx------   2 root root 4096 Jun  5 02:05 root
drwxr-xr-x   4 root root 4096 Jun  5 02:06 run
lrwxrwxrwx   1 root root    8 Apr 22 13:08 sbin -> usr/sbin
drwxr-xr-x   2 root root 4096 Jun  5 02:02 srv
dr-xr-xr-x  13 root root    0 Jul  3 12:50 sys
drwxrwxrwt   2 root root 4096 Jun  5 02:05 tmp
drwxr-xr-x  12 root root 4096 Jun  5 02:02 usr
drwxr-xr-x  11 root root 4096 Jun  5 02:05 var
docker exec -it ubuntu_bash bash

Saída:

root@759d52725ffe:/# 

Note que você está dentro do terminal do contêiner, com o usuário root.

Saia do contêiner:

root@759d52725ffe:/# exit
exit

docker stats

Exibe o consumo de recursos dos containers em execução no host:

docker stats

Saída (exemplo):

CONTAINER ID   NAME                 CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O         PIDS
e95bd53f6904   apache-ecampus       0.00%     98.92MiB / 512MiB     19.32%    22.6MB / 48.3MB   1.86MB / 12.3kB   8
77aa8c8f5d9b   pgadmin4             0.03%     202.9MiB / 31.18GiB   0.64%     53MB / 14MB       5.07MB / 22.3MB   20
c3f5ff58225d   lumen-pm             0.01%     52.88MiB / 31.18GiB   0.17%     318kB / 0B        5.41MB / 8.19kB   8
7659f7c19173   void-mail            6.08%     18.43MiB / 512MiB     3.60%     8.5MB / 9MB       6.45MB / 0B       2
4edcb809e7f8   apache-void          0.01%     11.64MiB / 512MiB     2.27%     13.1MB / 349kB    188kB / 8.19kB    7
39294708453c   apache-diploma       0.00%     2.672MiB / 512MiB     0.52%     348MB / 41.2MB    1.4MB / 9.72MB    2
c0187b82297c   apache-relatorio     0.00%     4.535MiB / 512MiB     0.89%     308MB / 7.45MB    3.44MB / 0B       2
ca7dd8afcbe3   laravel-mangaba      0.01%     124.9MiB / 31.18GiB   0.39%     318kB / 0B        10.9MB / 13.3MB   8
6e79d13253aa   laravel-assinador    0.00%     152.2MiB / 31.18GiB   0.48%     1.95MB / 1.71MB   3.42MB / 9.5MB    8
f782b4d255c6   rebrow-assinador     0.01%     22.86MiB / 31.18GiB   0.07%     318kB / 0B        4.89MB / 324kB    1
38aa0954d19c   web-ckan             0.01%     183.2MiB / 31.18GiB   0.57%     22.8MB / 22.6MB   36.9kB / 4.31MB   11
80e596827889   apache-moodlev3      0.01%     10.5MiB / 512MiB      2.05%     13.1MB / 352kB    12.3kB / 4.1kB    6
670a68bc71ff   postgres-ecampus     0.26%     168.2MiB / 31.18GiB   0.53%     50MB / 654MB      23.6MB / 505MB    7
e9265ae24b14   conector-ufvjm       0.25%     187.9MiB / 31.18GiB   0.59%     9.31MB / 8.72MB   16.4kB / 8.36MB   43
7aff38a1598f   phpmyadmin           0.01%     41.53MiB / 31.18GiB   0.13%     318kB / 0B        422kB / 1.98MB    7
fb98fc81448a   postgres-mangaba     0.01%     18.11MiB / 31.18GiB   0.06%     318kB / 0B        1.45MB / 14.4MB   7
27739272e682   apache-ldapadmin     0.01%     13.84MiB / 31.18GiB   0.04%     670kB / 289kB     8.19kB / 12.3kB   8
30bf52a8d11a   solr-ckan            0.11%     335.9MiB / 31.18GiB   1.05%     4.08MB / 3.75MB   45.1kB / 68.8MB   48
8481f13f87b7   postgres-pressiga    0.67%     43.35MiB / 31.18GiB   0.14%     4.14MB / 3.74MB   4.86MB / 71.7MB   7
6d1e7ba2556d   maria-pm             0.06%     97.93MiB / 31.18GiB   0.31%     319kB / 0B        11.1MB / 2.17MB   31
35aac4c5e8ca   redis-ckan           0.20%     3.551MiB / 31.18GiB   0.01%     340kB / 20.8kB    520kB / 0B        5
ade1ecfeb5e8   postgres-conector    0.01%     20.16MiB / 31.18GiB   0.06%     9.03MB / 8.98MB   4.83MB / 23MB     7
6e0fe48184b3   datapusher-ckan      0.02%     25.97MiB / 31.18GiB   0.08%     319kB / 0B        16.4kB / 111kB    1
15e396ca1835   postgres-ckan        0.00%     27.46MiB / 31.18GiB   0.09%     17.7MB / 17.3MB   8.09MB / 43.1MB   12
2fafc1c89a6c   redis-assinador      0.18%     7.848MiB / 31.18GiB   0.02%     319kB / 0B        4.1kB / 0B        5
5daf93ede22b   postgres-moodle      0.00%     21.84MiB / 31.18GiB   0.07%     318kB / 0B        5.52MB / 20.1MB   7
dc3216f22764   mailhog              0.00%     14.86MiB / 31.18GiB   0.05%     940kB / 574kB     2.86MB / 1.89MB   18
7237c9d8ab05   cache-ecampus        0.03%     8.301MiB / 31.18GiB   0.03%     2.37MB / 925kB    16.4kB / 0B       10
3819a952c8e6   ldap-ufvjm           0.03%     724.1MiB / 31.18GiB   2.27%     2.59MB / 1.19MB   586kB / 445MB     4
e05b811b58bc   postgres-assinador   0.01%     28.07MiB / 31.18GiB   0.09%     2.03MB / 1.63MB   12.3MB / 43.5MB   7

Para liberar a saída do terminal novamente use o atalho Ctrl + C.

docker logs

Exibe no terminal os logs do contêiner (parâmetro -f pode ser utilizado para travar a tela exibindo os logs, Ctrl + C para sair):

docker logs ubuntu_bash

Remover o container criado para realizar os testes:

docker rm -f ubuntu_bash

Saída:

ubuntu_bash

Referências

docker command CLI

List of Docker Commands with Examples

Criando imagens

O Docker pode construir automaticamente imagens lendo as instruções de um arquivo Dockerfile.

Dockerfile

O arquivo Dockerfile funciona como uma receita de bolo contendo as instruções de configuração para a configuração e execução do seu contêiner.

Neste exemplo, criaremos uma imagem de servidor web que exibirá uma página personalizada.

Servidor web

Crie uma pasta para armazenar os arquivos necessários para nossa imagem:

# acesando o home do usuário
cd ~

# criando a pasta
mkdir web

# entrando na pasta criada
cd web

Crie um arquivo chanado index.html com o seguinte conteúdo:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Página em manutenção</title>
</head>
<body>
<article>
    <h1>Página de Teste!</h1>
    <div>
        <p>Esta é uma página de teste.</p>
    </div>
</article>
</body>
</html>

Crie um arquivo chamado Dockerfile com o seguinte conteúdo:

# imagem base
FROM  ubuntu:oracular

# atualizando os pacotes e instalando o pacote nginx (servidor web)
RUN apt update && apt install -y nginx

# expondo a porta onde será executado o serviço no container
EXPOSE 80

# copiando o arquivo local para pasta dentro do container
COPY index.html /var/www/html

# comando que é executado, por padrao, quando o container se inicia
CMD ["nginx", "-g", "daemon off;"]

Criando a imagem

Dentro da pasta contendo o Dockerfile, execute o comando de build:

docker build -t nginx-treinamento .

Em caso de sucesso, você verá algo como:

(...)

 => => writing image sha256:4ba7dcc4bf31d3a97cee54016702f9565b5c203f62d624136b7cdc3e0cf9090d                                       0.0s 
 => => naming to docker.io/library/nginx-treinamento

A imagem docker foi criada com o nome docker.io/library/nginx-treinamento ou simplesmente nginx-treinamento:latest.

Mostrar as imagens locais disponíveis:

docker images

Saída:

REPOSITORY          TAG       IMAGE ID       CREATED              SIZE
nginx-treinamento   latest    4ba7dcc4bf31   About a minute ago   123MB

Quando listamos as imagens, o nome do repositório padrão docker.io/library/ é suprimido.

Executando a imagem

Execute o seguinte comando:

docker run \
    -it \
    -d \
    --name="web" \
    -p 9595:80 \
    --restart="always" \
    nginx-treinamento

A porta 9595 é onde o serviço ficará acessível no host, e a porta 80 é onde o serviço está disponível dentro do contêiner.

Opcional: se a porta utilizada no nosso exemplo já tiver sendo utilizado por outro serviço, você pode executar o contêiner com o mapeamento para outra porta (Exemplo: 9090) altere a linha -p para:

     -p 9090:80

Listando os contêiners ativos:

docker ps

Você verá algo como:

CONTAINER_ID IMAGE COMMAND CREATED STATUS PORTS
14a72c95d77b nginx-treinamento "nginx -g 'daemon ..." 1 minute ago Up 0.0.0.0:9595->80

Para testar, acesse pelo navegador o endereço: http://localhost:9595/.

Você deverá ver algo como:

Captura de tela de 2024-07-03 10-13-22.png

Página de teste acessada pelo navegador

Vamos remover este contêiner:

docker rm -f web

Saída:

web

Acessando os arquivos dentro do contêiner

Vamos recriar este mesmo contêiner do exemplo anterior, no entanto, desta vez vamos adicionar uma montagem de volume, para que possamos realizar a edição da página inicial que criamos e visualizar o reflexo destas alterações na página no navegador.

Criando novamente o contêiner:

docker run \
  -it \
  -d \
  --name="web" \
  -v ~/web:/var/www/html \
  -p 9595:80 \
  --restart="always" \
  nginx-treinamento

A pasta ~/web refere-se à localização da pasta dentro do host, a pasta /var/www/html refere-se à localização da pasta dentro do contêiner.

Acesse o navegador novamente.

Vamos editar o arquivo index.html localizado na pasta ~/web e conferir se as alterações se refletem no navegador web.

Alterar esse trecho de:

<p>Esta é uma página de teste.</p>

Para:

<p>Esta é uma página de teste, agora com alterações</p>
Acesse o navegador novamente e atualize (atalho F5).

Se tudo ocorreu como esperado, você irá visualizar:
Captura de tela de 2024-07-03 10-31-33.png
Página de teste com alterações

A partir de agora, você está pronto para realizar as alterações desejadas nos seus arquivos na sua área de desenvolvimento.

Removendo o contêiner

Após finalizar os testes, remova o contêiner:

docker rm -f web

Depois disso, caso deseje, remover os arquivos utilizados para nosso teste, apagar a pasta criada:

rm -rf ~/web

Referências

https://docs.docker.com/reference/dockerfile/

Docker Compose

Docker Compose é uma ferramenta escrita em Python para definir e rodar aplicações multi-contêineres Docker. Através do Docker Compose, você define a configuração dos serviços da sua aplicação. Em um arquivo yml, é descrita a configuração de cada um dos serviços, bem como o relacionamento entre eles. Através de um comando, você pode criar, atualizar ou remover todos os serviços.

Arquivo YML

Para este exemplo, criaremos uma aplicação blog composta de 2 serviços:

Dica: nos arquivos no formato yml a formatação é um aspecto importante da validação de sintaxe dele, formate-o de maneira padronizada (quantidade de espaços ou de tabs). Um espaço a mais antes de determinada definição irá causar erro de sintaxe no arquivo. Preste bastante atenção quanto copiar e colar os exemplos.

Crie um diretório chamado blog para armazenar a configuração:

# acessando o home do usuário
cd ~

# criando o diretório
mkdir blog

# entrando no diretório
cd blog

Crie um arquivo chamado docker-compose.yml com o seguinte conteúdo:

version: '3.0'
services:
  ghost:
    image: ghost:5.87.0
    ports:
      - 2368:2368
    restart: always
    environment:
      database__client: mysql
      database__connection__host: "ghost-db"
      database__connection__user: "ghostuser"
      database__connection__password: "pass"
      database__connection__database: "ghostdb"
    links:
      - ghost-db:ghost-db
    depends_on:
      - ghost-db
    volumes:
      - ~/blog/ghost:/var/lib/ghost/content
  ghost-db:
    image: mariadb:10.3
    ports:
      - 3306:3306
    restart: always
    environment:
      MYSQL_DATABASE: "ghostdb"
      MYSQL_PASSWORD: "pass"
      MYSQL_RANDOM_ROOT_PASSWORD: 'true'
      MYSQL_USER: "ghostuser"
    volumes:
      - ~/blog/ghost-db:/var/lib/mysql

Detalhando o arquivo docker-compose.yml

Note que nas configurações do tipo environment os mesmos valores passados no serviço de banco de dados são passados no serviço do blog. Você pode customizar esses valores, no entanto não se esqueça de atualizar nos dois serviços.

Quando subir um serviço em produção, não se esquecer de alterar os valores padrão das variáveis, especialmente as credenciais de acesso (nome de banco, nome do usuário, senha, etc). 

Comandos básicos

Para os exemplos abaixo, os comandos foram executados no diretório em que se encontra o arquivo docker-compose.yml:

Dica: em algumas instalações mais recentes o comando docker-compose pode ser acessado como docker compose (note o espaço entre as palavras). Os comandos a seguir deste treinamento serão efetuados sempre como docker-compose, se for o caso, faça a respectiva substituição pelo comando com espaço na sua área de desenvolvimento.

Criando a aplicação

Criar a aplicação descrita no arquivo docker-compose.yml, a tela exibirá o log:

docker-compose up

O serviço de banco iniciará, depois que ele estiver disponível a aplicação web irá se conectar no banco e fará a inicialização das tabelas padrão do sistema. Depois de alguns segundos você visualizará os logs cessarem com a rolagem e poderá ver algo como:

blog-ghost-1     | [2024-07-03 13:46:47] INFO Ghost booted in 9.523s
blog-ghost-1     | [2024-07-03 13:46:47] INFO Adding offloaded job to the queue
blog-ghost-1     | [2024-07-03 13:46:47] INFO Scheduling job update-check at 1 24 6 * * *. Next run on: Thu Jul 04 2024 06:24:01 GMT+0000 (Coordinated Universal Time)
blog-ghost-1     | [2024-07-03 13:46:47] INFO Running milestone emails job on Fri Jul 05 2024 13:46:47 GMT+0000 (Coordinated Universal Time)

Note que o terminal ficará travado neste execução. Os logs dos serviços da stack será exibidos no terminal. Para finalizar, utilize o atalho CONTROL + C. A execução da stack será finalizada.

Saída:

Gracefully stopping... (press Ctrl+C again to force)
Aborting on container exit...
[+] Stopping 2/2
 ✔ Container blog-ghost-1     Stopped                               0.5s 
 ✔ Container blog-ghost-db-1  Stopped                               2.5s 
canceled

Vamos criar a aplicação novamente, desta vez com a sua execução em background (-d Detached mode):

docker-compose up -d

Saída:

[+] Building 0.0s (0/0)                
[+] Running 2/2
 ✔ Container blog-ghost-db-1  Started                              0.4s 
 ✔ Container blog-ghost-1     Started

Conferir se a stack está rodando sem problemas:

docker-compose ps -a

Saída:

CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS          PORTS                                       NAMES
f67c51906df4   ghost:5.87.0   "docker-entrypoint.s…"   5 minutes ago   Up 54 seconds   0.0.0.0:2368->2368/tcp, :::2368->2368/tcp   blog-ghost-1
7c87994584ea   mariadb:10.3   "docker-entrypoint.s…"   5 minutes ago   Up 54 seconds   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp   blog-ghost-db-1

Captura de tela de 2024-07-03 10-54-49.png

Acessando o serviço de blog hospedado localmente via docker

Visualizar os logs:

docker-compose logs

Visualizar os logs e travar e tela na exibição neles:

docker-compose logs -f

Removendo a aplicação

Remover os contêiners da aplicação:

docker-compose down

Saída:

[+] Running 3/3
 ✔ Container blog-ghost-1     Removed              0.5s 
 ✔ Container blog-ghost-db-1  Removed              1.9s 
 ✔ Network blog_default       Removed 

Note que nós fizemos o mapeamento de volumes tanto do servidor de banco de dados como da aplicação web do blog ghost, portanto mesmo que você remova a aplicação, quando você criá-la novamente as alterações realizadas serão persistidas.

Conferir os arquivos persistidos no host:

ls -la ~/blog

Saída:

total 20
drwxr-xr-x  4 evertonpaiva evertonpaiva    4096 jul  3 10:46 .
drwxr-xr-x 80 evertonpaiva evertonpaiva    4096 jul  4 14:01 ..
-rw-r--r--  1 evertonpaiva evertonpaiva     750 jul  3 10:46 docker-compose.yml
drwxr-xr-x 11 evertonpaiva root            4096 jul  3 10:46 ghost
drwxr-xr-x  5          999 systemd-journal 4096 jul  3 11:08 ghost-db

Depois de realizarmos nossos teste, caso você deseja remover os arquivos utilizados:

sudo rm -rf ~/blog

Quando você acessa imagens docker no Docker Hub, geralmente você encontrará informações sobre os principais parâmetros para configuração do serviço, as portas padrão que o serviço é executa e dicamos de como realizar a persistência ou seja, quais pastas deverão ser mapeadas para volumes para não perder os dados quando o contêiner for encerrado.

Captura de tela de 2024-07-03 11-00-16.png

Página do serviço ghost no Docker Hub como informações de configuração do serviço.

Referências

https://docs.docker.com/compose/

Boas práticas

Imagem oficial

User imagens oficiais docker como imagens base para a criação dos serviços utilizados na sua aplicação.

Ao invés de pegar uma imagem base de um sistema operacional inteiro (Exemplo: ubuntu, alpine) e instalar os pacotes necessários para a execução do serviço desejado, procurar no repositório do Docker Hub imagens oficiais na versão desejada deste serviço.

Captura de tela de 2024-07-02 16-08-12.png

Exemplo: imagem docker oficial do PHP.

Versões específicas

Ao se escolher a imagem docker a ser utilizada para determinado serviço, definir uma versão específica para se utilizar desta imagem.

Por padrão, quando você não especifica a tag da imagem a ser utilizada em uma imagem docker, você utilizará a versão latest desta imagem. Conforme novas versões deste serviço são desenvolvidas, a imagem docker da tag denominada latest será substituída por estas novas versões.

Captura de tela de 2024-07-02 16-14-35.png

Imagem docker do PHP, tag latest.

Essa situação pode se transformar em um problema, porque você poderá perder o controle sobre qual a versão do serviço será utilizado. Por exemplo, quando o desenvolvimento e testes da aplicação for realizado, a tag latest pode conter o serviço PHP na versão 7.3. Num momento futuro, com o desenvolvimento de novas versões, a tag lastest poderá conter o serviço PHP na versão 8.0, que pode ter problema de compatibilidade com a versão anterior e causar um funcionamento imprevisível.

Tamanho pequeno

Dê preferência para imagens docker de tamanho pequeno. Além da economia de recursos, prefira imagens que tenham somente os serviços essenciais para o funcionamento da aplicação a ser desenvolvida.

Se for o caso, defina as imagens docker com os pacotes necessários para cada um dos ambientes de execução da aplicação. Por exemplo, a imagem do ambiente de desenvolvimento poderá ter pacotes instalados que não são necessários no ambiente de produção.

Além dos pacotes instalados na imagem, a distribuição que foi utilizada como imagem base também influenciará no tamanho total da imagem docker.

Captura de tela de 2024-07-02 16-30-53.png

Imagens docker PHP 8.3 - diferença de tamanho entre sistemas operacionais

Quanto mais pacotes, além dos recursos necessários para seu funcionamento, amplia-se potenciais problemas de segurança e maior frequência de necessidade de atualização.

.dockerignore

Quando se constrói uma imagem docker, podemos especificar quais os arquivos do repositório não serão incluídos dentro da imagem. O arquivo .dockerignore é utilizado na mesma lógica do funcionamento do arquivo .gitignore para um repositório git. Adicione neste arquivo o nome ou o padrão de arquivos para serem ignorados no momento da criação da imagem docker.

Referências

7 Práticas recomendadas para usar o Docker em produção

Comandos úteis

Exibir todos os containers

Exibindo todos os containers criados no host, inclusive aqueles que não estão atualmente em execução:

# exibir todos os containers, inclusive os parados
docker ps -a

Remover todos os containers

Para remover todos os containers em execução no seu computador execute o seguinte comando:

# força a remoção de todos os containers em execução
docker rm -f $(docker ps -a -q)

Limpeza total

O seguinte comando efetuará a limpeza total de todos os arquivos utilizados pelo docker.

IMPORTANTE: após execução desse comando, todos os dados não persistidos por volumes serão apagados do sistema.

# executa a limpeza total dos arquivos e configurações ocupados pelo docker
docker system prune -a


Treinamento em vídeo - YouTube

Gravação da reunião online realizada no dia 05/07/2024 deste mesmo treinamento.

Alguns comentários sobre o funcionamento do docker, docker-compose e dicas de utilização estão somente na versão em vídeo pois sugiram espontaneamente durante a utilização. A sequência de apresentação do vídeo segue a mesma da versão em texto. 

Seções

00:00 - Conceitos
10:47
- Principais comandos 
25:38
- Criando imagens
36:18
- Docker Compose
48:16
- Boas práticas
51:01 - Comandos úteis

A minutagem das seções também está disponível em um comentário no YouTube.

Contato

Esse conteúdo foi desenvolvido pela Divisão de Sistemas Institucionais - DSI/STI da UFVJM
Divisão de Sistemas Institucionais <sistemas.sti@ufvjm.edu.br>

Autoria

Em caso de dúvidas, sugestões de melhorias, informar algum problema com o conteúdo:
Contato: Éverton Paiva <everton.paiva@ufvjm.edu.br>