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
- Instalação Debian/Ubuntu
- Principais comandos
- Criando imagens
- Docker Compose
- Boas práticas
- Comandos úteis
- Treinamento em vídeo - YouTube
- Contato
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:
- rodar seus contêineres com menor gasto de recursos;
- funcionalidades de segurança que tornaram a tecnologia bem popular nos dias atuais;
- evitar o problema do inferno das dependências;
- garantir que as mesmas versões e dependências utilizadas no ambiente de desenvolvimento e testes seja utilizada no ambiente de produção.
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.
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
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.
- Primeiro executaremos um contêiner criado a partir de uma imagem do Ubuntu, em modo
detached
:
docker run --name ubuntu_bash -d -it ubuntu
- Vamos conferir se o contêiner está em execução sem problemas:
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
- Agora executaremos o comando
ls -la
dentro do contêiner:
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
- Para logar dentro do contêiner e executar comandos diretamente de lá (
exit
para sair):
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
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
nginx-treinamento
: nome da imagemlatest
: tag da imagem
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:
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.
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>
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:
- Servidor web:
ghost
(Ghost) - Banco de dados: mariadb (MariaDB Foundation)
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
- version: versão do docker-compose
- services: descrição dos serviços
- ghost
- ghost-db
- image: imagem utilizada pelo serviço
- ports: porta em que o serviço executará (lado esquerdo: host, lado direito: contêiner)
- restart: configuração de reinicialização do serviço
- environment: variáveis de ambiente dentro do contêiner
- links: link um contêiner em um outro serviço através do apelido fornecido
- depends_on: monta uma lista de dependências, para que o docker organize qual a ordem desejada de criação dos serviços (Exemplo: cria o banco de dados primeiro, depois cria o servidor web que precisará se conectar no banco)
- volumes: o mapeamento da pasta no host e a respectiva pasta dentro do contêiner (lado esquerdo: host, lado direito: contêiner)
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
- O servidor web pode ser acessado no navegador no seguinte endereço: http://localhost:2368
- O servidor de banco de dados está acessível na porta
3306
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
- ghost: pasta local para os arquivos do servidor web ghost
- ghost-db: pasta local para os arquivos do servidor de banco maria-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.
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.
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.
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.
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>