From cc4ce10f9b834d47fbccfa1e4e4898642372fc61 Mon Sep 17 00:00:00 2001 From: mvrp21 <mvrp21@inf.ufpr.br> Date: Tue, 16 Apr 2024 04:00:19 -0300 Subject: [PATCH] feat(docker-fundamentals): v0.9 done Signed-off-by: mvrp21 <mvrp21@inf.ufpr.br> --- source/index.md | 8 - source/pages/concepts/docker.md | 7 +- source/pages/guides/docker-fundamentals.md | 529 +++++++++++++++++++-- source/pages/guides/frontent-to-s3.md | 3 - source/pages/policies/documentation.md | 1 - 5 files changed, 488 insertions(+), 60 deletions(-) delete mode 100644 source/pages/guides/frontent-to-s3.md delete mode 100644 source/pages/policies/documentation.md diff --git a/source/index.md b/source/index.md index 282f532..eb39a4b 100644 --- a/source/index.md +++ b/source/index.md @@ -30,11 +30,3 @@ pages/policies/* pages/guides/* ``` - -```{toctree} -:caption: "Propostas de melhoria" -:glob: true -:maxdepth: 1 - -pages/proposals/* -``` diff --git a/source/pages/concepts/docker.md b/source/pages/concepts/docker.md index 850a3fa..21f368c 100644 --- a/source/pages/concepts/docker.md +++ b/source/pages/concepts/docker.md @@ -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). diff --git a/source/pages/guides/docker-fundamentals.md b/source/pages/guides/docker-fundamentals.md index aad5bf3..58828e2 100644 --- a/source/pages/guides/docker-fundamentals.md +++ b/source/pages/guides/docker-fundamentals.md @@ -1,29 +1,60 @@ # 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`: -2. `Sending build context to Docker daemon`: -3. Os `STEP`s: -4. `Successfully built` e `tagged`: -TODO: terminar aqui +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: 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 +``` -### Por que agora? -Por que ver toda a parte difícil antes de `compose`? +:::{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 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/). diff --git a/source/pages/guides/frontent-to-s3.md b/source/pages/guides/frontent-to-s3.md deleted file mode 100644 index e1d2ae6..0000000 --- a/source/pages/guides/frontent-to-s3.md +++ /dev/null @@ -1,3 +0,0 @@ -# Servindo frontend utilizando S3 - -## Integrando com GitLab CI diff --git a/source/pages/policies/documentation.md b/source/pages/policies/documentation.md deleted file mode 100644 index eaeb73c..0000000 --- a/source/pages/policies/documentation.md +++ /dev/null @@ -1 +0,0 @@ -# Como documentar um projeto -- GitLab