From 97412cffdcfcd9691ce2ea49495ab4fb2079c71d Mon Sep 17 00:00:00 2001 From: "Marcus V." <mvrp21@inf.ufpr.br> Date: Tue, 12 Mar 2024 17:46:23 -0300 Subject: [PATCH] feat(docker-fundamentals): progress Signed-off-by: Marcus V. <mvrp21@inf.ufpr.br> --- source/conf.py | 2 +- source/index.md | 8 +- .../guides/containerize-an-application.md | 1 - source/pages/guides/docker-fundamentals.md | 160 ++++++++++++++++-- 4 files changed, 151 insertions(+), 20 deletions(-) delete mode 100644 source/pages/guides/containerize-an-application.md diff --git a/source/conf.py b/source/conf.py index a8697da..ba50010 100644 --- a/source/conf.py +++ b/source/conf.py @@ -56,7 +56,7 @@ html_theme = "furo" html_static_path = ["_static", "_static/fonts/iosevka-fixed/"] html_css_files = ["fonts/iosevka-fixed/iosevka-fixed.css", "svgbob.css"] -html_logo = "_static/root-logo.png" +html_logo = "_static/c3sl.png" html_theme_options = { "sidebar_hide_name": True, "source_edit_link": "https://gitlab.c3sl.ufpr.br/c3sl/c3docs/devops/-/blob/main/source/{filename}", diff --git a/source/index.md b/source/index.md index f6f61e2..282f532 100644 --- a/source/index.md +++ b/source/index.md @@ -1,16 +1,10 @@ # DevOps do C3SL -```{image} _static/root-logo.png -:align: center -:alt: Root -:width: 200px -``` - ```{image} _static/c3sl.png :align: center :alt: C3SL UFPR :target: https://www.c3sl.ufpr.br -:width: 150px +:width: 500px ``` ```{toctree} diff --git a/source/pages/guides/containerize-an-application.md b/source/pages/guides/containerize-an-application.md deleted file mode 100644 index eba0ae2..0000000 --- a/source/pages/guides/containerize-an-application.md +++ /dev/null @@ -1 +0,0 @@ -# Dockarizando uma aplicação diff --git a/source/pages/guides/docker-fundamentals.md b/source/pages/guides/docker-fundamentals.md index 9bff006..6845dd7 100644 --- a/source/pages/guides/docker-fundamentals.md +++ b/source/pages/guides/docker-fundamentals.md @@ -6,7 +6,7 @@ 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. -## Trabalhando com contêineres +## Trabalhando com **contêineres** ### 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 @@ -104,7 +104,7 @@ Vamos analisar esse output: de *entrypoint*, que veremos mais à frente. Por enquanto veja esse comando apenas como um script que incia tudo o que o contêiner precisa. -:::{note} +:::{hint} Para mais opções do comando `docker ps` basta executar `docker ps --help`. ::: @@ -130,7 +130,7 @@ undefined Para sair da *shell* interativa do Node basta teclar `Ctrl+D`. -:::{note} +:::{hint} Para mais opções do comando `docker run` basta executar `docker run --help`. ::: @@ -160,7 +160,7 @@ Note que tanto o identificador do nome quando do id do contêiner servem. #### Removendo contêineres automaticamente Para remover automaticamente um contêiner que você executou é só passar a -flag `--rm` para o comando `docker run <imagem>`. +flag `--rm` para o comando `docker run`. ``` root@devops:~# docker ps -a @@ -171,7 +171,7 @@ CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES root@devops:~# ``` -## Lidando com imagens +## Lidando com **imagens** Como comentado anteriormente, imagens Docker são construídas por camadas. Essencialmente 'cada camada é uma linha de um script'. O que ocorre sempre que @@ -212,20 +212,154 @@ node latest ba29744b7cd0 3 days ago 1.1GB root@devops:~# ``` -### Criando uma imagem com um Dockerfile -TODO: exemplo com backend Node +:::{hint} +Caso você queira baixar uma imagem sem necessariamente criar um contêiner para +ela naquele momento basta executar `docker pull` (versão curta de `docker image +pull`). +::: + +### Criando imagens: o arquivo **Dockerfile** + +#### Pré-requisitos +Para acompanhar os próximos passos utilizaremos um código simples em NodeJS. +Não é necessário conhecer Node, mas deixa a experiência mais tranquila. + +Crie um diretório, nele colocaremos dois arquivos. O primeiro: + +```javascript +const express = require('express'); +const fs = require('fs'); +const app = express(); +const FILENAME = 'texto.txt'; +let counter = 0; +// Retorna o contador +app.use('/ler', (req, res) => { + console.log(`[LEITURA] contador eh ${counter}`); + const text = fs.readFileSync(FILENAME); + res.status(200).json({ texto: text, contador: counter }); +}); +// Escreve um texto no arquivo +app.use('/escrever', (req, res) => { + console.log(`[ESCRITA] contador foi de ${counter} para ${++counter}`); + const text = `O contador eh ${counter}`; + fs.writeFileSync(FILENAME, text); + res.status(200).json({ texto: text, contador: counter }); +}); +// Servidor escuta na porta 3000 +app.listen(3000, () => { + fs.writeFileSync(FILENAME, 'O arquivo nao foi modificado!'); + console.log('Escutando na porta 3000') +}); +``` + +Em suma, o código acima cria um servidor que escuta na porta 3000, e possui +duas operações: ler e escrever um arquivo específico no sistema de arquivos. + +Esse código deve ser salvo em um arquivo chamado `app.js`. + +Além do código, o seguinte texto deve estar em outro arquivo chamado +`package.json`: + +```json +{ + "name": "docker-tutorial", + "version": "1.0.0", + "description": "Backend simples para brincar com docker.", + "main": "app.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [ + "nodejs", + "express", + "docker" + ], + "author": "mvrp21@inf.ufpr.br", + "license": "GPL-3.0" +} +``` + +Pronto! Já podemos iniciar essa seção. + +#### Criando um Dockerfile +Quem já conhece Node sabe que para executar o código será preciso primeiro +instalar as dependências do projeto com `npm install` e depois basta +executar o servidor com `npm start`. + +Para isso é necessário que o `npm` esteja instalado no sistema. + +```Dockerfile + +FROM node:lts +``` + +:::{caution} +A imagem escolhida é `node:lts`. Para usos além de testes locais é sempre bom +mudar a tag `lts` para uma versão específica da imagem. + +Isso pois `lts` é uma **tag dinâmica**. Hoje essa tag aponta para uma versão +específica (20.11.1 no momento) da escrita desse parágrafo, mas conforme o +tempo passa a versão LTS (Long Term Support[^cite_lts]) mudará; e não é +impossível que essa mudança quebre a aplicação. + +Isso é particularmente ruim para aplicações que ficaram paradas por um tempo, +pois quando o contêiner for executado de novo ele procurará a versão `lts` da +imagem, que pode não ser mais compatível com a versão da época em que o projeto +era ativo. -#### EXPOSE <PORT> +(Claro, o ideal é manter um projeto atualizado, sempre que a versão LTS de +suas dependências mudar ele **deveria** acompanhar essa mudança. Infelizmente +o mundo da teoria é muito mais bonito e previsível que o da prática.) +::: + +#### Camadas +##### Ordenando as camadas + +#### Mapeando portas + +:::{attention} +A instrução `EXPOSE <PORTA>`[^cite_expose] **não expõe** de verdade as portas, +isso pois por mais que uma porta seja utilizada no contêiner o host pode querer +mapeá-la para outra. -### *Attatched* e *detatched* +A verdadeira razão para usar essa instrução é para **informar** quem estiver +utilizando a imagem quais portas devem ser "publicadas". Ela serve como uma +espécie de **documentação**. +::: + +### *Attached* e *detached* +#### Vendo Logs -## Persistindo mudanças no disco com volumes +## Disco persistente com **volumes** -## Uma introdução às redes +### Tipos de volumes + +## Uma introdução às **redes** ## Docker Compose Como orquestrar múltiplos contêineres elegantemente? +Vamos supor que desejamos executar aquele mesmo contêiner com base na imagem do +Dockerfile que foi criado logo acima. Seria necessária a seguinte sequência de +comandos longos: + +``` +.................................... +``` + +Um bom programador teria preguiça de executar esses comandos todos, e dado que +a configuração para os contêineres será sempre a mesma ele provavelmente +acabaria criando um script que lê um arquivo de configuração para ele e os +executa corretamente. + +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 +::: + ### `docker-compose.yml` ... @@ -249,6 +383,8 @@ ferramentas como GitLabCI[^cite_gitlab_ci] para realizar esse deploy com qualquer *merge* na branch `main`, por exemplo. ::: +## TODO: Fernando comentou sobre docker debian12 em host debian9 -> estudar + ## TODO: Colinha de Docker - `docker run <nome-da-imagem>:<tag>`: Cria e executa um contêiner com base na imagem com versão especificada pela *tag*. @@ -266,3 +402,5 @@ qualquer *merge* na branch `main`, por exemplo. [^cite_docker_install]: [Instalando Docker](https://docs.docker.com/engine/install/). [^cite_nodejs]: [NodeJS](https://nodejs.org/). [^cite_docker_hub]: [DockerHub](https://hub.docker.com/). +[^cite_expose]: [Instrução EXPOSE](https://docs.docker.com/reference/dockerfile/#expose). +[^cite_lts]: [Long Term Support](https://en.wikipedia.org/wiki/Long-term_support). -- GitLab