Skip to content
Snippets Groups Projects
Commit cc4ce10f authored by mvrp21's avatar mvrp21
Browse files

feat(docker-fundamentals): v0.9 done


Signed-off-by: default avatarmvrp21 <mvrp21@inf.ufpr.br>
parent 256f9636
No related branches found
No related tags found
No related merge requests found
......@@ -30,11 +30,3 @@ pages/policies/*
pages/guides/*
```
```{toctree}
:caption: "Propostas de melhoria"
:glob: true
:maxdepth: 1
pages/proposals/*
```
......@@ -108,10 +108,10 @@ ter uma imagem da aplicação para *deploy* facilitado.
Assumindo que tudo foi configurado corretamente. Uma vez que uma aplicação tem uma imagem
:::{admonition} Um projeto *dockarizado* ficou parado por dois anos e voltou do nada?
:class:{question}
:class: question
Sem problemas! É só fazer o *deploy* da última imagem de produção! Agora para
continuar o desenvolvimento basta que a documentação[^cite_documentation] do
projeto esteja em ordem (esse é um problema que sempre caberá ao projeto em si).
continuar o desenvolvimento basta que a documentação do projeto esteja em ordem
(esse é um problema que sempre caberá ao projeto em si).
:::
### Testes de integração
......@@ -128,4 +128,3 @@ Um perfeito exemplo disso é um *website*. Caso
[^cite_docker_docs]: [Primeiros passos com Docker](https://docs.docker.com/get-started/overview/).
[^cite_docker_hub]: [Docker Hub](https://hub.docker.com/).
[^cite_docker_networks]: [*Overview* de redes Docker](https://docs.docker.com/network/#drivers).
[^cite_documentation]: [Guia básico de documentação](../policies/documentation.md).
# Fundamentos do Docker
TODO: rever tudo com calma, acho que usei um monte de terminologias que não são
as 'oficiais' e que tirei da cabeça.
TODO: em algum lugar (idealmente lá pro final kkkkkkkk) colocar sobre pesquisar
*samples* de Dockerfile e docker-compose.yml.
Assume-se que quem ler essa documentação é familiarizado com os conceitos
básicos de Docker[^cite_docker_concepts].
Antes de começar a executar comandos é preciso ter Docker instalado no sistema.
Há documentação oficial[^cite_docker_install] sobre instalação.
:::{note}
Esse guia/tutorial é um tipo de 'comece a mexer com docker rápido'. Ele **não
substitui** e nem tenta substituir pesquisa mais aprofundada sobre Docker para
quem tem interesse em aprender essa tecnologia.
A motivação para criar esse guia foi o fato de alguns projetos do C3SL
utilizarem Docker mas quem realmente tinha algum conhecimento era uma única
pessoa, e por conta disso já ocorreram algumas instâncias de precisar mexer
no `Dockerfile` 'pra ontem' mas ninguém ter o conhecimento básico para fazer
isso, pois quem sabia saiu do projeto (por exemplo). Esse guia visa no mínimo
atenuar esse problema.
:::
## Pré-requisitos
A ideia para esse guia era ter o mínimo de pré-requisitos possível, para que
quem precisar aprender a mexer com Docker no próprio projeto pudesse começar
rapidamente. Entretanto é impossível negar que alguns conhecimentos específicos
facilitariam o acompanhamento desse guia.
Segue a lista de conhecimentos que são interessantes ter:
- Sistemas Operacionais: Em particular virtualização e sistemas de arquivos,
facilitam a compreensão do que é Docker e volumes, respectivamente. Entender
processos pode ajudar também.
- Redes de Computadores: O guia assume que o leitor sabe o que é 'porta', e tem
uma ideia básica de comunicação em rede. Compreensão do modelo TCP/IP é ideal.
- *Shell*: Em certos momentos variáveis de ambiente são mencionadas, além disso
o `Dockerfile` se assemelha muito a um *script* `.sh`.
- NodeJS: Esse não é necessário, mas não faz mal. Como é comum utilizarem
NodeJS nos projetos do C3SL um exemplo abaixo utiliza essa tecnologia com
Docker. Não é necessário saber Node, mas saber exatamente o que o código
faz apenas olhando para ele pode facilitar a compreensão do que está
acontecendo.
- Git: Em alguns momentos é feita analogia entre GitHub e DockerHub, não é
necessário conhecer Git, apenas a analogia que não será compreendida.
### Terminologia básica
Algumas palavras vão se repetir frequentemente nesse guia:
- '*host*': É a máquina que **vai executar o contêiner Docker**.
- 'porta': Definição de porta TCP/UDP.
- '*output*': Saída padrão da execução de algum programa (neste caso de
contêineres Docker).
## Trabalhando com **contêineres**
TODO: rootless-docker e sobre como ele é executado (tem a ver com instalação,
que não foi comentado ainda)
### Utilizando imagens pré-construídas
Vamos iniciar com prática: pegar uma imagem que já foi construída por alguém e
executar um contêiner baseado nela. Para este guia foi escolhida a imagem do
NodeJS[^cite_nodejs].
TODO: `docker stop` e `docker run` ficariam melhores na seção 'Trabalhando com
contêineres'
Execute o comando `docker run node`. A saída deve ser similar à seguinte:
```
......@@ -252,6 +283,10 @@ pull`).
:::
### Criando imagens: o arquivo **Dockerfile**
Colocando em termos extremamente simples: É possível descrever o `Dockerfile`
como **um *script* que configura a máquina que vai executar a aplicação** para
você do zero, o que garante um ambiente consistente, pois ela terá sempre o
mesmo estado inicial e passará pelos mesmos comandos de configuração.
#### Pré-requisitos
Para acompanhar os próximos passos utilizaremos um código simples em NodeJS.
......@@ -400,9 +435,22 @@ RUN npm install
CMD [ "npm", "start" ]
```
Sumarizando (veremos cada comando em detalhes à frente),
TODO: terminar aqui
Sumarizando (veremos cada comando em detalhes à frente):
- `FROM node:lts`: Estamos criando nossa imagem baseada em uma que já existe, a
imagem `node` com tag `lts`.
- `WORKDIR /app`: Define que o diretório onde a aplicação vai ficar dentro do
contêiner é o `/app`.
- `COPY package.json /app/package.json`: Copia o arquivo `package.json` **do
host para o contêiner**, e o coloca em `/app/package.json`.
- `EXPOSE 3000`: Informa o leitor do `Dockerfile` que essa aplicação utiliza
a porta 3000, e que ela provavelmente deve ser mapeada para o *host*.
- `COPY . /app/`: Copia os demais arquivos do *host* para o contêiner, e os
coloca em `/app/`.
- `RUN npm install`: Instala as dependências do projeto (esse comando roda
**dentro do contêiner**).
- `CMD [ "npm", "start" ]`: Informa que quando um contêiner for criado com base
na imagem ele deve executar `npm start` para iniciar a aplicação.
:::{caution}
A imagem escolhida é `node:lts`. Para usos além de testes locais é sempre bom
......@@ -482,16 +530,18 @@ Perceba que há um aviso 'DEPRECATED'. No momento da escrita desse guia docker
ainda suporta usar build ao invés do buildx. Eventualmente esse guia será atualizado
para incluir ambas as opções (caso ambas ainda sejam válidas).
Um pouco sobre o buildx será comentado na seção [Docker Compose](docker-compose).
Um pouco sobre o `buildx` será comentado na seção de [plugins](buildx).
:::
Vamos analisar esse output:
1. A mensagem `DEPRECATED`:
1. A mensagem `DEPRECATED`: No momento da escrita desse guia Docker está em
processo de migrar seu *builder* padrão, não há problema com a mensagem.
2. `Sending build context to Docker daemon`:
3. Os `STEP`s:
4. `Successfully built` e `tagged`:
TODO: terminar aqui
3. Os `STEP`s: São as camadas do `Dockerfile` sendo executadas, e gravadas para
a imagem.
4. `Successfully built` e `tagged`: *Build* finalizou, a imagem foi criada e
seu nome/tag foi atribuído normalmente.
Com isso devemos ter uma imagem local chamada `teste-node`. Podemos verificar isso
com `docker image ls`:
......@@ -675,6 +725,12 @@ Para ver em detalhes como é feito o cache de camadas do Docker na hora do
TODO: :)
#### COPY e RUN
O comando `COPY` copia arquivos do *host* para o contêiner. Seu uso avançado
permite copiar arquivos entre contêineres, que é feito geralmente em
*multi-stage builds*.
O comando `RUN` executa algum comando na *shell* do contêiner. Geralmente a
*shell* do contêiner será *Bash*.
:::{tip}
Vamos supor que você só precisa de um pequeno conjunto de seus arquivos
......@@ -687,12 +743,13 @@ cada um dos arquivos necessários, ou diretórios se tudo neles for necessário.
Se você já tem familiaridade com o Git provavelmente conhece o arquivo
`.gitignore`. Com docker existe o arquivo `.dockerignore` para arquivos
não serem copiados com a instrução `COPY`
não serem copiados com a instrução `COPY`.
Veja mais sobre `.dockerignore` na documentação oficial[^cite_dockerignore].
:::
#### CMD vs ENTRYPOINT
TODO: explicar isso aq
:::{seealso}
A documentação oficial de Docker tem todas as instruções aceitas pelo
......@@ -703,22 +760,263 @@ Vale a pena estudar a fundo como são feitas imagens para seus fins específicos
:::
### Interagindo com contêineres
Antes de vermos 'volumes' é ideal saber interagir com contêineres de forma mais
eficiente e conveniente. A seguir estão algumas considerações sobre isso.
#### *Attached* vs *detached*
Você já deve ter se incomodado com o fato de que após rodar `docker run` o
terminal fica preso ao output do contêiner. Isso acontece pois por padrão os
contêineres são executados em modo `attached`.
:::{note}
Isso é particularmente inconveniente se o contêiner deve ser executado em um
servidor, a partir de uma *shell* ssh.
O que fazer com o terminal aberto? Se ele for fechado o processo do contêiner
será morto também!
:::
No modo `attached` o terminal ficará preso, logo precisamos apenas executar o
contêiner em modo `detached`. Para isso basta passar a flag `--detach`/`-d`
para o comando `docker run`. Veja um exemplo:
```
root@devops: ~/node-test# docker run --detach --rm --name teste teste-node
07f74b3feb9ed7025179139bd62422970c21f127ea0a62791de0c78e716330d8
root@devops: ~/node-test# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
07f74b3feb9e teste-node "docker-entrypoint.s…" 45 seconds ago Up 11 seconds 3000/tcp teste
root@devops: ~/node-test#
```
Perceba que não vimos o output do contêiner, e no mesmo terminal pudemos
executar `docker ps` para ver que o contêiner estava sim em execução.
#### Vendo Logs
Mas e se quisermos ver o output do contêiner? Para isso existe o comando
`docker logs <identificador>`, cujo funcionamento é similar ao comando `tail`,
muito utilizado em *scripts shell* de Linux. Vejamos um exemplo:
```
root@devops: ~/node-test# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
07f74b3feb9e teste-node "docker-entrypoint.s…" 9 minutes ago Up 8 minutes 3000/tcp teste
root@devops: ~/node-test# docker logs teste
> docker-tutorial@1.0.0 start
> node app.js
Escutando na porta 3000
root@devops: ~/node-test#
```
E da mesma maneira que o `tail`, se quisermos que o terminal fique preso ao
output basta passar a flag `--follow`/`-f`. É possível liberar o terminal com
`Ctrl+C` sem que o contêiner pare, como pode ser visto abaixo:
```
root@devops ~/node-test# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
07f74b3feb9e teste-node "docker-entrypoint.s…" 11 minutes ago Up 10 minutes 3000/tcp teste
root@devops ~/node-test# docker logs -f 07
> docker-tutorial@1.0.0 start
> node app.js
Escutando na porta 3000
^CInterrupt
root@devops ~/node-test# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
07f74b3feb9e teste-node "docker-entrypoint.s…" 11 minutes ago Up 11 minutes 3000/tcp teste
root@devops ~/node-test#
```
:::{note}
O `^CInterrupt` do output é o `Ctrl+C` que liberou o terminal.
:::
#### Utilizando `docker exec`
Um último comando interessante é o `docker exec` com o qual, como o nome
indica, é possível executar comandos diretamente no contêiner. Três flags
em particular são bem relevantes para o uso com esse comando:
- `--detach`/`-d`: Executa o comando 'no *background*', similar ao `-d` de
`docker run`.
- `--interactive`/`-i`: Mantém a entrada padrão aberta mesmo que o comando não
seja executado em modo `attached`.
- `--tty`/`-t`: Aloca um pseudo-TTY.
:::{seealso}
TODO: explicar TTY?
:::
## Disco persistente com **volumes**
Caso ainda não tenha reparado, sempre que executamos um contêiner ele tem seus
próprios arquivos, muito similar a uma máquina virtual. Entretanto, toda vez que
o contêiner é parado todas as alterações que foram feitas no sistema de
arquivos dele são perdidas.
### Tipos de volumes
#### Bind Mounts
:::{note}
No exemplo utilizado até agora, com o projeto em NodeJS, é possível ver o
sistema de arquivos do contêiner com `docker exec -it <id> bash`, que te dará
uma *shell* no contêiner.
:::
Essa seção apenas introduz os conceitos de *volumes* e de *bind mounts*. Para
ver seu uso detalhado recomenda-se dar uma olhada na documentação oficial para
*volumes*[^cite_docker_volumes] e para *bind mounts*[^cite_bind_mounts].
:::{note}
Tanto volumes quanto bind mounts podem ser utilizados em modo *read-only* ou
*read-write*.
:::
### Volumes
O jeito recomendado de lidar com dados persistentes utilizando docker é por
meio de volumes, isso pois volumes são completamente gerenciados pelo Docker,
enquanto *bind mounts* que são descritos mais à frente são dependentes do
*host* executando o contêiner.
Para ver os volumes do sistema basta executar `docker volume ls`.
:::{note}
Você já deve ter percebido o padrão da CLI de docker. Antes vimos várias vezes
`docker container ls`, depois `docker image ls`, `docker volume ls` e à frente
veremos também `docker network ls`.
:::
Volumes podem ser criados manualmente pela CLI com `docker volume create`, e
podem ser utilizados no comando `docker run` por meio da flag `--volume`/`-v`.
Uma grande utilidade de volumes é que eles podem ser pré-populados por um
contêiner. Em um projeto em NodeJS por exemplo, é possível utilizar essa
*feature* para acelerar o processo de *build* na parte de instalação de
dependências com `npm install` ao ter o volume com os `node_modules` pré-feitos
por um contêiner intermediário de *build* (isso se torna particularmente
importante para projetos que possuem **muitas** dependências, pois o *build* é
acelerado consideravelmente).
:::{seealso}
Se o parágrafo acima interessou o leitor então pesquisar as seguintes
palavras-chave é essencial para aprofundar o conhecimento nesse tópico:
- docker multi-stage build;
- docker volume caching;
- docker node modules cache;
- docker reduce build time;
Um exemplo de *multi-stage build* está no `Dockerfile` oficial do
NextJS[^cite_nextjs].
:::
### Bind Mounts
*Bind mounts* podem ser compreendidos como 'volumes mais simples'. Comparados a
volumes *bind mounts* têm funcionalidade bem mais limitada, mas por sua simplicidade
são frequentemente utilizados também.
Os *bind mounts* nada mais fazem do que montar uma árvore de diretórios do
*host* diretamente no contêiner, enquanto os *volumes* são gerenciados
diretamente pelo Docker.
Uma implicação do fato acima é que em sistemas Mac ou Windows o desempenho de
*bind mounts* é um pouco pior do que o de *volumes* (lembre-se que Docker
utiliza o kernel do host, baseado em Linux, e que em Mac e Windows uma Máquina
Virtual Linux é executada para prover esse kernel), um dos fatores da
preferência de *volumes* a *bind mounts* para gerenciar dados persistentes.
:::{note}
Não é possível gerenciar *bind mounts* pela CLI, dada a sua natureza dinâmica
de existir apenas com o contêiner em execução, e seus dados não passarem de algum
diretório que já exista no *host*.
:::
### tmpfs mounts
Se um contêiner gerar dados não persistentes então é possível utilizar um
*tmpfs mount*, que armazena os arquivos diretamente em memória RAM, o que
proporciona duas coisas:
- Garante que os dados não sejam armazenados permanentemente;
- Aumenta a performance de IO do que estiver nesse *tmpfs mount*, pois acessar
a memória RAM é mais rápido que acessar o disco;
## Uma introdução às **redes**
6 tipos de rede lesgoooooo (ou 7, a default tem gente que diz que eh diferente)
Redes em Docker é um conteúdo relativamente avançado, pois para compreensão
total dos seus conceitos é necessário ter uma base sobre Redes de Computadores
que não cabe a esse guia explicar.
:::{admonition} TLDR: Too Long Didn't Read
:class: hint
Redes Docker permitem que contêineres se comuniquem diretamente.
90% das vezes será utilizada a rede padrão *bridge*, que permite que N
contêineres nela se comuniquem utilizando seus nomes.
Por exemplo, suponha que há dois contêineres 'API-A' e 'API-B'. O contêiner
'API-A' pode mandar uma requisição HTTP para 'API-B', e esse segundo receberá
a requisição e retornará normalmente, do mesmo jeito que se faz uma requisição
HTTP para um website, por exemplo.
:::
Redes Docker permitem que contêineres se comuniquem diretamente. Por exemplo um
contêiner de *backend* pode se comunicar diretamente com o contêiner de banco de
dados no mesmo *host*, ao invés de fazer uma requisição que saia do *host* e
volte depois e etc.
Docker permite isso pois gerencia suas próprias interfaces de rede. Se você
verificar o output de `ip a` com um contêiner rodando irá se deparar com
interfaces com nomes como `docker0` ou `vethcee46c9@if17`. Além disso Docker
também usa `iptables` no Linux para filtrar pacotes e gerência de
*firewall*[^cite_iptables].
Além disso há dezenas de outras funcionalidades que podem ser obtidas
utilizando os diversos tipos de *drivers* de redes, como eliminar o isolamento
entre o *host* e o contêiner, isolar completamente a rede de um contêiner, dar
um endereço MAC a um contêiner, controlar por completo os endereços IPv{4,6}
dele, dentre outras ações interessantes.
### Tipos de redes
Contêineres têm *networking* habilitado por padrão, e eles podem fazer
requisições 'para fora' do *host*. Um contêiner não tem informações sobre que
tipo de rede ele está utilizando, nem se quem recebe suas requisições é outro
contêiner Docker ou não. Isso **é transparente** para o contêiner.
É possível ver as redes presentes no sistema com `docker network ls`:
```
root@devops ~/node-test# docker network ls
NETWORK ID NAME DRIVER SCOPE
aa4e1b063bfe bridge bridge local
696da25ad0fa host host local
cb3bee259cd9 none null local
root@devops ~/node-test#
```
Há 6 *drivers* de rede distintos, cada um descrito na documentação
oficial[^cite_networking]. É interessante pesquisar seus usos, já que esta
seção meramente introduz o conceito das redes Docker.
## Docker plugins
TODO: compose e buildx entram aqui
Para estender as funcionalidades do Docker existem plugins, os quais são
instalados separadamente e permitem fazer algo a mais com Docker ou facilitam
algo que já é possível.
Há inúmeros *plugins* para inúmeros casos de uso, vale a pena pesquisar mas é
inviável descrevê-los todos neste guia.
### Buildx
Anteriormente vimos um aviso de depreciação do *builder* padrão. Isso pois no
momento em que esse guia estava sendo escrito a ferramenta para *build* do Docker
estava em fase de transição. Em versões mais novas do Docker o comando `docker
build` já irá utilizar automaticamente o novo `buildx`, de modo transparente.
O `buildx` estende as habilidades de criar imagens utilizando o *builder*
**BuildKit**.
:::{admonition} Por que um plugin?
:class: important
> Por que não simplesmente substituíram o *builder* padrão do Docker pelo
> `buildx` ao invés de transformá-lo em um plugin que deve ser instalado
> separadamente?
Por que ainda estavam em fase de transição, e não era possível simplesmente
trocar de uma vez o *build* sem afetar incontáveis projetos. Entretanto no
futuro o plano é sim substituir o `docker build` padrão pelo novo.
:::
## Docker Compose
Como orquestrar múltiplos contêineres elegantemente?
......@@ -728,7 +1026,7 @@ Dockerfile que foi criado logo acima. Seria necessára a seguinte sequência de
comandos longos:
```
....................................
TODO: até eu to com preguiça de escrever todos
```
Um bom programador teria preguiça de executar esses comandos todos, e dado que
......@@ -740,48 +1038,184 @@ Felizmente, já existe uma ferramenta nativa para orquestrar múltiples
contêineres com um único arquivo de configuração, com comandos curtos: `docker
compose`.
:::{attention}
docker-compose vs. docker compose
:::{admonition} `docker-compose` vs. `docker compose`
:class: attention
O comando `docker-compose` é o jeito antigo de utilizar `compose`, o modo ideal
é instalando o *plugin* e utilizar o comando `docker compose` (com espaço ao
invés do traço).
A versão com traço é a V1, enquanto a mais nova é a V2, e chamá-las assim é
menos confuso do que procurar pelo traço.
O *plugin* é a versão mais nova do `compose`, que foi migrada para a linguagem
Go, e com isso a versão antiga foi depreciada e seu uso é fortemente
desencorajado. (A partir de Julho de 2023 V1 parou de receber *updates*)
:::
Na verdade, mesmo com um único contêiner, para o caso de uso para os projetos do
C3SL ainda é melhor usar `compose`. Isso pois ele é mais simples de executar, tem
um arquivo de configuração descritivo e no geral facilita a vida de quem usa.
C3SL, por exemplo, ainda é melhor usar `compose`. Isso pois ele é mais simples
de executar, tem um arquivo de configuração descritivo e no geral facilita a
vida de quem usa. Não há por que executar 6 ou 7 comandos quando basta executar
1 (fora o fato de que o arquivo `docker-compose.yml` é bem descritivo, serve
**parcialmente** de 'documentação' sobre o contêiner sendo utilizado).
:::{attention}
O problema com isso é que geralmente uma única pessoa aprende o suficiente de
O problema com isso é que geralmente **uma única pessoa** aprende o suficiente de
Docker para fazer essa configuração inicial, e depois todos aceitam que funciona
e usam, mas eventualmente quem fez e conhece Docker sai.
Um dia algum problema surge, com ele a necessidade de mexer no Dockerfile ou no
docker-compose.yml, e muito tempo é perdido tentando arrumar algo que deveria
facilitaria o trabalho caso todos conhecessem.
facilitaria o trabalho caso todos conhecessem o básico.
Isso não é problema com Docker em si, mas sim com não conhecer uma tecnologia
essencial para o projeto. O que é relativamente compreensível, se funciona e
não há por que mexer ninguém irá mexer.
essencial para o projeto (o que é relativamente compreensível, se funciona e
não há por que mexer ninguém irá mexer).
:::
### O arquivo `docker-compose.yml`
TODO: Aqui vamos longe.
Com `compose` ao invés de executar diversos comandos você descreve os seus
contêineres dentro de um arquivo YAML. O comando `docker compose` vai ler
esse arquivo e executar os comandos adequados para o usuário, que precisará
executar **apenas um comando**, ao invés de vários.
Um exemplo de arquivo `docker-compose.yml` que foi utilizado no projeto do
ensalamento do C3SL:
```yaml
version: '3'
services:
ensalamento-postgres:
container_name: ensalamento-postgres
image: postgres:13.8
env_file:
- .env
volumes:
- ~/.local/docker-volumes/ensalamento/db:/var/lib/postgresql/data
networks:
- backend
backend:
container_name: ensalamento-backend
build: ./ensalamento-back-v2
env_file:
- .env
volumes:
- ./ensalamento-back-v2/bin/:/app/bin/:ro
- ./ensalamento-back-v2/src/:/app/src/:ro
- ./ensalamento-back-v2/volumes/:/app/volumes
ports:
- '8000:8000'
depends_on:
- ensalamento-postgres
networks:
- backend
restart: on-failure
frontend:
container_name: ensalamento-frontend
build: ./ensalamento-front-v2
env_file:
- .env
volumes:
- ./ensalamento-front-v2/src/:/app/src/:ro
- ./ensalamento-front-v2/public/:/app/public/:ro
- ./ensalamento-front-v2/swap/:/app/swap/
ports:
- '3000:3000'
links:
- backend:backend
networks:
- backend
restart: on-failure
networks:
backend:
name: ensalamento-network
```
:::{note}
Essa é uma versão um pouco mais antiga do `docker-compose.yml`, essa é a versão
3, mas já há a versão 3.8, por exemplo.
Há pequenas diferenças quanto às versões, em especial sobre as versões 3.x há a
documentação oficial[^cite_compose_3] que descreve brevemente as diferenças, mas
a essência dos arquivos será sempre a mesma.
:::
A maioria dos elementos do arquivo acima são reconhecíveis, então vamos
analisar apenas algumas partes do arquivo:
- `services`: Dentro disso fica a lista de contêineres a serem executados. No
caso do arquivo acima são 3 (ensalamento-backend, ensalamento-frontend e
ensalamento-postgres).
- `build`: Indica o diretório que contém o `Dockerfile` para o contêiner.
- `env_file`: Arquivo que define as variáveis de ambiente, ao invés de
especificarmos uma por uma como anteriormente.
- `restart: on-failure`: Caso o `CMD` do contêiner retorne um erro em algum
momento ele será reiniciado automaticamente, ao invés de falhar e não
retornar.
- `depends_on`: Isso define que o contêiner **depende** da lista de contêineres
passadas aqui, e **não será iniciado** até que **todos** dessa lista já
tenham iniciado.
Ressaltando, de novo: **esse guia é introdutório**, para uma descrição melhor do
`docker-compose.yml` é recomendado ver a documentação oficial, assim como
**pesquisar** *samples* de projetos reais para compreender como ele é utilizado.
### Utilizando `docker compose`
> O projeto tem um arquivo `docker-compose.yml`, e agora?
Para **iniciar todos** os contêineres com todas as informações descritas no arquivo
`docker-compose.yml` basta executar `docker compose up` no mesmo diretório
desse arquivo.
Ainda, há duas flags importantes para `docker compose up`:
- `--build`: Executa o `docker build` antes de iniciar os contêineres,
reconstruindo a imagem.
- `--detach`/`-d`: Funciona do mesmo modo que com o comando `docker run` visto
anteriormente.
Para **parar todos** os contêineres descritos no arquivo basta executar `docker
compose down` no mesmo diretório do `docker-compose.yml`.
:::{note}
Perceba que o `docker compose` é essencialmente uma interface. Ele utiliza um
arquivo de configuração e nada mais do que executa os diversos comandos
necessários para você enquanto você apenas digita um único comando.
:::
### Por que agora?
Por que ver toda a parte difícil antes de `compose`?
### Por que só agora?
> Por que ver toda a parte difícil antes de `compose` sendo que ele que é
> realmente utilizado?
Para entender como ele funciona, por que ele existe e o que acontece por
debaixo dos panos. Além disso saber `compose` não exclui a necessidade de saber
o 'docker puro'.
o 'docker puro' (às vezes deseja-se um contêiner rapidamente, para testar uma
imagem nova, para executar algum comando, para aprender, etc.).
Por exemplo, se você tem uma aplicação com vários contêineres e precisa atualizar
algo dentro de um deles, você (idealmente) não vai parar todos os outros com
`docker compose down`, mas vai parar apenas o necessário com `docker stop`.
## TODO: Utilizando um registry
Falar de `pull`, `login`, `push` e etc.
:::{note}
Isso é parcialmente uma mentira. Há como executar `docker compose` para apenas
parte dos contêineres, mas **a essência do comando é a mesma**.
:::
## Utilizando um registry
Frequentemente é feita a comparação de *registry* como o DockerHub com
plataformas *git* como GitHub, mas faltam alguns pedaços dessa analogia, por
exemplo: como fazer o equivalente de `git push`?
Para isso existem os comandos `docker login`, `docker pull` e `docker push`,
vale a pena pesquisar mais sobre eles.
Como não é comum utilizarem o *registry* do C3SL essa parte do guia ficará
pendente por enquanto. Idealmente no futuro ele será mais utilizado.
## Exemplo de *deploy* manual
TODO: fazer o exemplo (quadro de avisos????)
TODO: fazer o exemplo (provavelmente com o quadro de avisos digital)
:::{admonition} Esse não é necessariamente o melhor método.
:class: note
......@@ -798,11 +1232,12 @@ qualquer *merge* na branch `main`, por exemplo.
:::
### Ciclo de desenvolvimento
TODO: aproveitar e utilizar o mesmo exemplo daqui de cima
## TODO: Fernando comentou sobre docker debian12 em host debian9 -> estudar
## TODO: Considerações finais
## TODO: Pesquisando por conta
...
## TODO: *cheatsheet*
Não queria fazer isso, mas acredito que vai facilitar a vida de alguns.
[^cite_docker_concepts]: [Conceitos básicos de Docker](../concepts/docker.md).
......@@ -815,3 +1250,9 @@ qualquer *merge* na branch `main`, por exemplo.
[^cite_docker_cache]: [Docker build cache](https://docs.docker.com/build/cache/).
[^cite_dockerignore]: [Arquivos `.dockerignore`](https://docs.docker.com/build/building/context/#dockerignore-files).
[^cite_dockerfile]: [Referência Dockerfile](https://docs.docker.com/reference/dockerfile/).
[^cite_docker_volumes]: [Volumes](https://docs.docker.com/storage/volumes/).
[^cite_bind_mounts]: [Bind Mounts](https://docs.docker.com/storage/bind-mounts/).
[^cite_nextjs]: [Dockerfile oficial NextJS](https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile).
[^cite_iptables]: [Packet filtering and firewalls](https://docs.docker.com/network/packet-filtering-firewalls/).
[^cite_networking]: [Docker Networking](https://docs.docker.com/network/).
[^cite_compose_3]: [Docker compose 3.x](https://docs.docker.com/compose/compose-file/compose-file-v3/).
# Servindo frontend utilizando S3
## Integrando com GitLab CI
# Como documentar um projeto
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment