diff --git a/Diretorias/Diretoria Projetos/deploy/heroku/explicacao.md b/Diretorias/Diretoria Projetos/deploy/heroku/explicacao.md deleted file mode 100644 index 0cc4e242..00000000 --- a/Diretorias/Diretoria Projetos/deploy/heroku/explicacao.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -order: 3 -icon: rocket -label: "O que é Heroku ?" ---- - - - - -Heroku é uma plataforma de deployment de website, desenvolvidos em quase todos frameworks mais famosos utimamente, ela automaticamente analisa o repositório e verifica a linguagem que você está utilizando, e já faz o setup completo, facilitando uma das principais e mais demoradas atividades de um projeto de website. O Heroku roda um container docker com seus scripts de inicialização. Isso significa que é necessário que o seu projeto seja um servidor, ou seja, que ele tenha uma porta para ser acessado, e que ele seja capaz de responder a requisições. Sendo assim, é ideal para api's, mas não para servir _assets estáticos_ (como os gerados numa aplicação React comum). - -!!! -O Heroku, na ultima atualização dessa documentação, não possui plano gratuito, logo utilizamos self-hosting para o back-end na Struct. -!!! diff --git a/Diretorias/Diretoria Projetos/deploy/index.yml b/Diretorias/Diretoria Projetos/deploy/index.yml index 513e0bf8..e082631a 100644 --- a/Diretorias/Diretoria Projetos/deploy/index.yml +++ b/Diretorias/Diretoria Projetos/deploy/index.yml @@ -1,2 +1,2 @@ -icon: rocket -label: Deploy \ No newline at end of file +icon: share +label: Deploy diff --git a/Diretorias/Diretoria Projetos/deploy/netlify/index.yml b/Diretorias/Diretoria Projetos/deploy/netlify/index.yml deleted file mode 100644 index 10096fdd..00000000 --- a/Diretorias/Diretoria Projetos/deploy/netlify/index.yml +++ /dev/null @@ -1,5 +0,0 @@ -icon: rocket -label: Netlify - -# Ultima atualização: 23/09/2023 -# Autor(es): Artur Padovesi \ No newline at end of file diff --git a/Diretorias/Diretoria Projetos/deploy/self_hosting/explicacao.md b/Diretorias/Diretoria Projetos/deploy/self_hosting/explicacao.md new file mode 100644 index 00000000..45010905 --- /dev/null +++ b/Diretorias/Diretoria Projetos/deploy/self_hosting/explicacao.md @@ -0,0 +1,20 @@ +--- +order: 3 +icon: rocket +label: "Explicando nosso self hosting" +--- + + + + +## O que é self hosting? + +Self-hosting, também conhecido como auto-hospedagem, é um conceito em tecnologia que se refere à prática de hospedar e gerenciar seus próprios serviços, aplicativos ou plataformas em infraestrutura própria, em vez de utilizar serviços e plataformas de terceiros ou fornecedores externos. + +Em outras palavras, quando você opta por self-hosting, você é responsável por configurar, administrar e manter todos os aspectos do serviço ou aplicativo que está executando. + +## Nossa estrutura + +No momento, pagamos por um servidor no **DigitalOcean**, que é um serviço de cloud computing, ou seja, uma plataforma que usa a conectividade da internet para hospedar e prover recursos, programas e informações em nuvem, e usamos ssh para acessá-lo e fazê-lo rodar exatamente o que queremos. + +Além disso, usamos Docker para poder isolar e rodar vários servidores na mesma máquina. Para levar o tráfego que chega em nossa máquina para o container correto, usamos o [Traefik v2](https://doc.traefik.io/traefik/) como [proxy reverso](https://pt.wikipedia.org/wiki/Proxy_reverso). Isso é necessáro pois temos vários domínios apontando para o nosso servidor (structej.unb.br, marks.com.br). diff --git a/Diretorias/Diretoria Projetos/deploy/self_hosting/front/fazendo.md b/Diretorias/Diretoria Projetos/deploy/self_hosting/front/fazendo.md new file mode 100644 index 00000000..dce85586 --- /dev/null +++ b/Diretorias/Diretoria Projetos/deploy/self_hosting/front/fazendo.md @@ -0,0 +1,180 @@ +--- +order: 1 +icon: rocket +label: "Fazendo deploy de frontend" +--- + + + + +## Considerações + +Considerando que nenhum framework, e nem SSR, está sendo usado, a aplicação React não inclui servidor. No ambiente de **desenvolvimento** são usadas **ferramentas** (como vite, create-react-app, etc) para servir a aplicação na porta determinada (na Struct determinamos como 3000), mas no deploy utilizamos o Express, um servidor web que pode ser usado para servir arquivos estáticos, como imagens, css, js, etc. Sendo assim, após fazer o build da aplicação React, o Express é que estará servindo os _assets_ estáticos na porta definida. + +!!!danger Errado +Estamos usando Express para fazer o deploy! +!!! + +## Configurando o projeto + +!!! +Considere a [branch production do projeto jeira](https://github.com/StructCE/jeira-frontend/tree/production) como um exemplo. +!!! + +## Criando a branch production + +Crie a branch `production` a partir da `main` ou da `development`. **Esteja** localmente **na** branch **`production`** + +1. Criar um arquivo `.dockerignore` para garantir que o container gere certos arquivos, ao invés de usar as suas locais. É importante retirar possíveis fontes de problemas. Colocar o seguinte conteudo dentro do arquivo criado: + +```dockerignore +/node_modules +/dist +/build +``` + +2. Adicione o pacote `express` ao projeto. Crie um arquivo `sever.js` com o seguinte conteúdo: + +```js +const express = require("express"); +//chamamos o express para o arquivo + +const { resolve } = require("path"); +//para garantir que pegaremos o path exato + +const app = express(); +//criamos uma aplicação com o express + +app.use("/static", express.static(resolve(__dirname, "./build/static"))); + +app.use( + "/asset-manifest.json", + express.static(resolve(__dirname, "./build/asset-manifest.json")) +); + +app.use( + "/favicon.ico", + express.static(resolve(__dirname, "./build/favicon.ico")) +); + +app.use( + "/index.html", + express.static(resolve(__dirname, "./build/index.html")) +); + +app.use( + "/manifest.json", + express.static(resolve(__dirname, "./build/manifest.json")) +); + +app.use( + "/robots.txt", + express.static(resolve(__dirname, "./build/robots.txt")) +); + +app.use("*", express.static(resolve(__dirname, "./build"))); +//serve para pegarmos os itens de forma estática e servirmos o build + +app.listen(80, (err) => { + //usaremos a porta que o heroku definir ou a 300 + if (err) { + return console.log(err); + } + //caso tenha um erro vai retornar o erro na callback + console.log("Deu bom!"); + //no mais, esse console.log aparecerá na tela +}); +``` + +!!!warn +Eu sei que existe uma maneira melhor de fazer isso, mas desse jeito funciona, e como nossa aplicação é um SPA, então **não funciona** só fazer o seguinte: + +```js +app.use("*", express.static(resolve(__dirname, "./build"))); +``` + +Pois o `index.html` pede pelos arquivos `favicon.ico`, `static/*.js` e `static/*.css`. Nosso servidor serviria recursivamente o diretório inteiro da build para cada uma das requisições pedindo um único arquivo. + +Além disso, ter um rota _catch all_ (`*`) é necessário pois, como temos um SPA, queremos que `/` e `/users/profile/1` retornem os mesmo arquivos (todos os da build). + +!!! + +3. Adicione o arquivo `start.sh` com o comando que deve ser rodado ao inicializar o container: + +```bash +#!/bin/bash +bun server.js +``` + +4. Adicionar o Dockerfile de frontend: + +```dockerfile +# Imagem de Origem +FROM oven/bun as build + +RUN apt-get -y update + +# # if using Create React App, uncomment: +# RUN apt-get -y install nodejs +# # needed so build using react-scripts works + +WORKDIR /app + +COPY bun.lockb . +COPY package.json . +RUN bun install + +COPY . . +RUN bun run build + + +FROM oven/bun as start + +WORKDIR /app + +# copying only needed files to end image +COPY --from=build /app/build/. ./build +COPY --from=build /app/server.js ./server.js +COPY --from=build /app/start.sh ./start.sh + +RUN chmod +x ./start.sh +CMD ["./start.sh"] +``` + +!!! +Estamos usando bun pra instalar e rodar as coisas porque, no momento, bun é mais rápido que npm, e npm era lento que incomodava fazer a build do projeto. +!!! + +### Mudando as urls de localhost + +!!! +A aplicação React usa urls locais para acessar a API, por exemplo, `http://localhost:3333/api/v1`. Essas urls devem ser alteradas para as urls de produção, por exemplo, `https://api.struct.com.br/api/v1`.É possível fazer isso usando variáveis de ambiente, mas no momento deve ser trocado manualmente, como no nosso repositório de exemplo (talvez esse gitbook esteja desatualizado em relação ao repositório, verifique). +!!! + +### Mudando o `index.html` + +1. Alterar o arquivo `index.html` para conter informações corretas sobre a aplicação, bem como os metadados. +2. Criar um `robots.txt`, para ajudar os mecanismos de busca, além indexar o site conforme necessario. +3. Colocar o título correto, colocar descrição, mudar o favicon e a linguagem para pt-BR. + +## Criando a imagem + +[Cr] + +## Criando container + +1. Atualize o repositório de docker_compose da Struct com o seguinte comando: + +```bash Terminal +git pull +``` + +2. Crie uma pasta com o nome do projeto. +3. Modifique o template de `docker-compose.yml` do Traefik com os nomes que podem ser usados para identificar o projeto nos logs, caso ocorra algum erro. +4. Definir a imagem que será usada com o valor de `image`. +5. Alterar os valores de `environment`, `restart`, `volumes`, e `networks`. +6. Crie o container usando o comando: + +```bash Terminal +`docker-compose up -d` +``` diff --git a/Diretorias/Diretoria Projetos/deploy/self_hosting/front/index.yml b/Diretorias/Diretoria Projetos/deploy/self_hosting/front/index.yml new file mode 100644 index 00000000..8556a7fd --- /dev/null +++ b/Diretorias/Diretoria Projetos/deploy/self_hosting/front/index.yml @@ -0,0 +1,4 @@ +icon: rocket +label: Frontend (SPA) +# Ultima atualização: 23/09/2023 +# Autor(es): Artur Padovesi diff --git a/Diretorias/Diretoria Projetos/deploy/self_hosting/ideia.md b/Diretorias/Diretoria Projetos/deploy/self_hosting/ideia.md new file mode 100644 index 00000000..80c61928 --- /dev/null +++ b/Diretorias/Diretoria Projetos/deploy/self_hosting/ideia.md @@ -0,0 +1,198 @@ +--- +order: 1 +icon: rocket +label: "Qual a ideia de qualquer deploy?" +--- + + + + +## Passos + +1. Apontar o domínio para o IP do nosso servidor: + - Isso deve ser feito no site que configura o domínio; + - Caso o cliente já tenha um domínio para uso interno de sua empresa, provavelmente não teremos acesso. Para gerar o certificado SSL deve ser usado nosso proxy interno (traefik), podendo tomar como exemplo o deploy do Jeira; + - Caso o cliente não tenha um domínio, será necessário que o cliente compre o domínio, e é sugerido que ele seja configurado para usar Cloudflare como proxy reverso. Com o Cloudflare é mais fácil configurar o certificado SSL; +2. Configurar o projeto no github: + - Crie uma branch `production` e faça as alterações nessa branch. Essas alterações podem ser trocar URL's, adicionar um start.sh, etc.; +3. Criar uma imagem docker com o projeto dentro. + - Para isso, é feito um **Dockerfile** que faz a **_build_** do projeto, copia arquivos necessários, instala o mínimo necessário para depois o projeto poder rodar no servidor. + - Uma imagem Docker é como uma configuração inicial para **depois** uma máquina virtual inicializada com **Docker Compose**. Sendo assim, tem sistema operacional, pacotes instalados, filesystem, etc. separados. + - É comum gerar imagens a partir de outras imagens. Por exemplo, para rodar `NodeJS` é comum se basear na imagem oficial do Node ao invés de instalar tudo na mão (Sistema Operacional, dependências do Node, etc.). +4. Criar um `docker-compose.yml` para o projeto; + - Boa parte das seções de um `docker-compose.yml` são específicas do projeto, mas a seção de labels está sendo usada para configurar o container dentro do **traefik**; + - Esse arquivo pode ter mais de um `service`, por exemplo uma aplicação Next e um banco de dados MySQL. + +## Glossário + +### Dockerfile + +Dockerfile constrói uma imagem. Uma imagem é uma "foto" de uma computador em um estado. Ela inclui arquivos, sistema operacional (geralmente é usado Alpine ou um SO extremamente leve), dependências instaladas e, finalmente, o **comando de inicialização**. + +Ao construir imagens, geralmente são usadas imagens intermediárias. + +!!!warning +Cuidado para não copiar coisas demais para a Imagem Docker. Por exemplo, `node_modules/` não deve ser copiado do local para a imagem, mas sim o `package.json` para rodar o `pnpm install` ao construir a imagem (no Dockerfile). + +Como o sistema operacional rodando dentro dele é diferente do seu, copiar arquivos instalados para a sua máquina pode criar problemas. +!!! + +==- Exemplo de Dockerfile usando bun para buildar um projeto react, e rodar um servidor express para servi-lo + +```Dockerfile +# Imagem de Origem +FROM oven/bun as build + +RUN apt-get -y update + +# # needed so react-scripts build works +# # Se seu projeto estiver usando Create React App (for legado) descomente: +# RUN apt-get -y install nodejs + +# Separando a pasta com a aplicação do resto da imagem original +WORKDIR /app + +# RUN git clone ${PROJETO_GITHUB} --depth=1 --branch production /app/ +COPY bun.lockb . +COPY package.json . +RUN bun install + +# coloque o node_modules e outras pastas a serem ignoradas no .dockerignore +# senão pode ser copiada sem querer aqui +COPY . . +RUN bun run build + +# Iniciando construção da imagem final: +FROM oven/bun as start + +WORKDIR /app + +# Copiando somente os arquivos necessários, para diminuir ao máximo o tamanho final da imagem +# Pasta com o resultado da build: +COPY --from=build /app/build/. ./build +# Pasta com o servidor express +COPY --from=build /app/server.js ./server.js +COPY --from=build /app/start.sh ./start.sh + +# Tornando o start.sh executável +RUN chmod +x ./start.sh +# declarando o comando de inicialização da imagem: +CMD ["./start.sh"] +# Como só pode existir um comando de inicialização, se queremos ter mais de um comando +# ao iniciar o container precisamos usar o start.sh +``` + +=== + +### docker-compose.yml + +Esse arquivo pode ser usado com o comando `docker-compose up` ou `docker compose up`, e deve ser usada a flag `-d` quando no servidor. Ao fazer tal coisa, ele gera um **container com** o conteúdo da **imagem**, e roda o **comando de inicialização**. + +Ele tem várias partes de configuração: + +1. `networks`: + - Declara as conexões que os containers tem. No servidor, temos uma conexão chamada `proxy` que conecta todo mundo, mas às vezes é necessário ter uma conexão interna também, para, por exemplo, conectar um app Next com seu banco de dados; + - Caso queira rodar o container localmente, deve tirar o network proxy. +2. `services`: + - É aqui que a magia acontece. + - Declare um nome para os serviços que serão rodados, coloque o nome da imagem delas (a gerada anteriormente pelo Dockerfile, ou uma da internet); + - Declare `volumes` caso queira sincronizar arquivo/diretório do container com o do computador. Isso é útil ao ter um banco de dados, ao guardar arquivos no container, etc. + +Um exemplo do projeto Jeira: + +```yml +version: "3.3" + +# `dominio.qualquer.br`,`www.dominio.qualquer.br` +# my-react-app (uniq) +# my-react-app-certresolver (uniq) +# 80 + +networks: + proxy: + external: true + +services: + my-react-app: + image: structej/projetos:my-react-app-1.0.9 + environment: + - TZ=America/Sao_Paulo + labels: + - traefik.enable=true + - traefik.docker.network=proxy + + # # http access + - traefik.http.routers.my-react-app.rule=Host(`dominio.qualquer.br`,`www.dominio.qualquer.br`) + - traefik.http.routers.my-react-app.entrypoints=web + + # # https access + + - traefik.http.routers.my-react-app-websecure.rule=Host(`dominio.qualquer.br`,`www.dominio.qualquer.br`) + - traefik.http.routers.my-react-app-websecure.entrypoints=websecure + - traefik.http.routers.my-react-app-websecure.tls=true + + # # Specify to container port + - traefik.http.routers.my-react-app-websecure.service=my-react-app-service + - traefik.http.routers.my-react-app.service=my-react-app-service + - traefik.http.services.my-react-app-service.loadbalancer.server.port=80 + + # # redirect http to https + + - traefik.http.middlewares.my-react-app-redirect-to-websecure.redirectscheme.scheme=https + - traefik.http.middlewares.my-react-app-redirect-to-websecure.redirectscheme.permanent=true + - traefik.http.routers.my-react-app.middlewares=my-react-app-redirect-to-websecure + + # # certResolver pra quando precisar gerar certificado por aqui: + # # Exemplo do jeira. Ver traefik.yml para ver a configuracao do challenge: + + - traefik.http.routers.my-react-app-websecure.tls.certResolver=my-react-app-certresolver + + restart: always + volumes: + - project_data:/app/storage/ + networks: + - proxy + +volumes: + project_data: +``` + +### IP + +IP nada mais é do que o endereço da máquina. + +Em uma metáfora: se você quer ir pra casa (website) de alguém, precisa saber qual o endereço. + +### servidor + +É um computador que **serve** clientes. Você pode fazer do seu laptop um servidor. + +Nós pagamos por um computador da DigitalOcean, para que ele fique no ar 24/7. + +### domínio + +IP serve como endereço, mas é feio. Você, como usuário, não quer ir para http://104.131.141.67/, você quer ir para o https://struct.unb.br/. + +Sendo assim, geralmente se tem/compra um domínio (que.eh.tipo.isso.com) com uma autoridade de domínio, que ela redirecionará o usuário para o IP. Se configura com a autoridade de domínio para qual IP o domínio deve redirecionar. + +### reverse proxy + +Ele intermedia a internet e o servidor. Ao invés da requisição ir direto para quem vai servi-la, passa por um intermediário. + +Esse intermediário pode configurar certificados SSL/TLS, pode redirecionar para outros servidores de acordo com o domínio, pode lidar com cache, etc. + +Na Struct, tipicamente sugerimos pagar e colocar o domínio no **Cloudflare** para que ele lide com os certificados automaticamente. Então usamos o **Traefik** dentro do nosso servidor para que ele redirecione a requisição para o container correto. Ou seja, a request acaba passando por 2 _reverse proxies_ antes de chegar no container que está rodando o servidor Rails/Express/NextJS/etc. + +https://www.cloudflare.com/learning/cdn/glossary/reverse-proxy/ + +### Traefik + +É o que usamos no nosso servidor como reverse proxy. Ele redireciona a request para o container, dependendo das rules de [cada container](https://doc.traefik.io/traefik/routing/routers/). Por exemplo, podemos colocar para redirecionar requests vindo do domínio `www.structej.com` para um container, e vindo de `reminder.structej.com` para outro. + +Também podemos configurar o [certificado SSL/TLS de cada container](https://doc.traefik.io/traefik/https/acme/) pelo nosso proxy reverso. Caso tenha acesso ao nosso servidor, veja o `docker-compose.yml` do site struct como referência, além do nosso `traefik.yml`. + +### certificado SSL/TLS + +É a diferença do http para o https (http secure). Para garantir que a conexão com o site é criptografada (e então não pode ser interceptada), se coloca um certificado no servidor. Quando o usuário acessar seu site, caso esse certificado não seja encontrado, a conexão é http e os navegadores avisam o usuário que eles não estão seguros. + +Para ter um certificado no seu site, se faz uma configuração no container (quem está de fato servindo o website) ou nos reverse proxy que receberem a conexão antes dele. Sendo assim, isso pode ser feito usando o Cloudflare, o Traefik, ou dentro do container, instalando o certificado com alguma outra ferramenta. diff --git a/Diretorias/Diretoria Projetos/deploy/self_hosting/index.yml b/Diretorias/Diretoria Projetos/deploy/self_hosting/index.yml new file mode 100644 index 00000000..7b64213c --- /dev/null +++ b/Diretorias/Diretoria Projetos/deploy/self_hosting/index.yml @@ -0,0 +1,4 @@ +icon: server +label: Self-Hosting +# Ultima atualização: 22/09/2023 +# Autor(es): Artur Padovesi e Pedro Augusto Ramalho Duarte diff --git a/Diretorias/Diretoria Projetos/deploy/self_hosting_back/como_usar.md b/Diretorias/Diretoria Projetos/deploy/self_hosting/sempre.md similarity index 55% rename from Diretorias/Diretoria Projetos/deploy/self_hosting_back/como_usar.md rename to Diretorias/Diretoria Projetos/deploy/self_hosting/sempre.md index 889c17c3..26ad8837 100644 --- a/Diretorias/Diretoria Projetos/deploy/self_hosting_back/como_usar.md +++ b/Diretorias/Diretoria Projetos/deploy/self_hosting/sempre.md @@ -1,7 +1,7 @@ --- order: 1 icon: rocket -label: "Como fazer Self-Hosting (Back-End)?" +label: "O que fazer em qualquer deploy?" --- @@ -14,12 +14,11 @@ label: "Como fazer Self-Hosting (Back-End)?" !!! 1. Crie uma branch `production`; -2. Adicione `Dockerfile` ao `.gitignore` do projeto; ## Crie a imagem Docker !!! -Não coloque Dockerfiles no repositório do projeto, utilize o repositório do GitBucket para isso. Colocar esse arquivo no projeto pode causar problemas de segurança. Muitos dos nossos Dockerfiles usam credenciais que **não devem** ser expostas. +Muitos dos nossos Dockerfiles usam credenciais que **não devem** ser expostas. Se seu Dockerfile contém algo assim, dê commit apenas em um Dockerfile.example sem as credenciais. !!! 1. Pegue o template de `Dockerfile` no GitBucket @@ -27,14 +26,13 @@ Não coloque Dockerfiles no repositório do projeto, utilize o repositório do G 3. Para construir a imagem, use o comando: ```bash Terminal -docker build -t structej/projetos:{nome_do_projeto_versão} +docker build -t structej/projetos:nome-do-projeto-vers.subv ``` !!! Várias das nossas imagens são um pull do projeto, e para isso é necessário um token de acesso no github. Para gerar esse token, pode ser seguida a [Documentação do GitHub](https://docs.github.com/pt/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token#creating-a-personal-access-token-classic). !!! - ## Faça o Push da imagem Docker 1. Faça login no DockerHub, usando o comando: @@ -46,23 +44,30 @@ docker login 2. Faça o push da imagem para o DockerHub, usando o comando: ```bash Terminal -docker push structej/projetos:{nome_do_projeto_versão} +docker push structej/projetos:nome-do-projeto-vers.subv ``` !!! -O `structej/projetos` é o `usuário/projeto` que enviamos a imagem de tag `{nome_do_projeto_versão}`. É importante fazer assim, pois por padrão projetos no DockerHub são públicas, então enviamos ela para um repositório que sabemos ser privado. +O `structej/projetos` é o `usuário/projeto` que enviamos a imagem de tag `nome-do-projeto-vers.subv`. É importante fazer assim, pois por padrão projetos no DockerHub são públicas, então enviamos ela para um repositório que sabemos ser privado. !!! -## Faça o docker-compose no servidor +## Faça o docker-compose + +!!!warning Como assim **no servidor**? +Lembre que **no servidor** significa que é necessário acessar o servidor por _ssh_ e rodar os comando **pelo ssh**!! +!!! !!! Os templates de `docker-compose.yml` ficam na pasta `templates` do repositório armazenado no servidor. !!! -1. Fazer as atualizações localmente; +1. Fazer as atualizações **localmente**; 2. Fazer um push para o repositório; -3. Fazer um pull no servidor; -4. Faça o pull/clone do repositório do Docker Compose, usando o comando +3. Fazer um pull **no servidor**; + +Caso não tenha o repositório localmente, + +1. Faça o pull/clone do repositório do Docker Compose, usando o comando ```bash Terminal git pull/clone @@ -83,7 +88,13 @@ Procure por coisas que podem quebrar ou requerem passos adicionais no deploy, co 1. Faça o build da imagem docker, usando o comando: ```bash Terminal -docker build -t structej/projetos:{nome_do_projeto_versão} +docker build -t structej/projetos:nome-do-projeto-vers.subv +``` + +Por exemplo: + +```bash Terminal +docker build -t structej/projetos:nome-do-projeto-1.0 ``` !!! @@ -93,14 +104,13 @@ Agora a versão da imagem docker é `versão`. Sempre incrementamos a `versão` 2. Faça o push da imagem para o DockerHub, usando o comando: ```bash Terminal -docker push structej/projetos:{nome_do_projeto_versão} +docker push structej/projetos:nome-do-projeto-vers.subv ``` ## Atualize o docker-compose no servidor -1. Mudar a propriedade `image` do serviço do projeto no `docker-compose.yml` para a versão atual da imagem docker; -2. Faça o commit das alterações; -3. Faça o push do `docker-compose.yml`; +1. Esteja no repositório gitbucket do servidor; +2. Mude a propriedade `image` do serviço do projeto no `docker-compose.yml` para a versão atual da imagem docker; ```yml Exemplo version: '3.7' @@ -109,4 +119,17 @@ services: service-we-want-to-update: image: structej/projetos:nome-projeto-x.x ... -``` \ No newline at end of file +``` + +3. Faça o commit e push das alterações; +4. Entre no servidor com **ssh**; +5. Dê um `git pull` no diretório correto, com `docker-compose.yml` alterado, e depois rode `docker-compose up -d` +6. Verifique se deu certo e o serviço está funcionando normalmente; + +### Deu errado, e agora? + +1. Dê rollback de alguma maneira pra versão anterior. Pode usar git pra voltar pro último commit, reverter o commit anterior, alterar na mão a imagem pra versão anterior, etc. + +2. Continuou dando errado? Talvez alguém tenha alterado esse arquivo anteriormente e não deu `docker-compose up -d`, e agora o problema sobrou pra você. Verifique se as variáveis de ambiente estão configuradas corretamente. + +3. Tá difícil? Verifique os commits anterirores e as alterações feitas nesse `docker-compose.yml` e tente isolar a mudança que causou o problema. diff --git a/Diretorias/Diretoria Projetos/deploy/self_hosting_back/explicacao.md b/Diretorias/Diretoria Projetos/deploy/self_hosting_back/explicacao.md deleted file mode 100644 index 3bab7882..00000000 --- a/Diretorias/Diretoria Projetos/deploy/self_hosting_back/explicacao.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -order: 3 -icon: rocket -label: "O que é Self-Hosting (Back-End) ?" ---- - - - - -Self-hosting, também conhecido como auto-hospedagem, é um conceito em tecnologia que se refere à prática de hospedar e gerenciar seus próprios serviços, aplicativos ou plataformas em infraestrutura própria, em vez de utilizar serviços e plataformas de terceiros ou fornecedores externos. Em outras palavras, quando você opta por self-hosting, você é responsável por configurar, administrar e manter todos os aspectos do serviço ou aplicativo que está executando. No momento, pagamos por um servidor no DigitalOcean, que é um serviço de cloud computing, ou seja, uma plataforma que usa a conectividade da internet para hospedar e prover recursos, programas e informações em nuvem, e usamos ssh para acessá-lo e fazê-lo rodar exatamente o que queremos. Além disso, usamos Docker para poder isolar e rodar vários servidores na mesma máquina. Para levar o tráfego que chega em nossa máquina para o container correto, usamos o [Traefik v2](https://doc.traefik.io/traefik/) como [proxy reverso](https://pt.wikipedia.org/wiki/Proxy_reverso). diff --git a/Diretorias/Diretoria Projetos/deploy/self_hosting_back/index.yml b/Diretorias/Diretoria Projetos/deploy/self_hosting_back/index.yml deleted file mode 100644 index bc1a0a27..00000000 --- a/Diretorias/Diretoria Projetos/deploy/self_hosting_back/index.yml +++ /dev/null @@ -1,5 +0,0 @@ -icon: rocket -label: Self-Hosting (Back-End) - -# Ultima atualização: 22/09/2023 -# Autor(es): Artur Padovesi e Pedro Augusto Ramalho Duarte \ No newline at end of file diff --git a/Diretorias/Diretoria Projetos/deploy/self_hosting_front/como_usar.md b/Diretorias/Diretoria Projetos/deploy/self_hosting_front/como_usar.md deleted file mode 100644 index 9aa7634a..00000000 --- a/Diretorias/Diretoria Projetos/deploy/self_hosting_front/como_usar.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -order: 1 -icon: rocket -label: "Como faz Self-Hosting (Front-End)?" ---- - - - - -## Configurando o projeto - -!!! -Considere a [branch production do projeto front-end-template](https://github.com/StructCE/react-template/tree/production) e [suas alterações](https://github.com/StructCE/react-template/compare/main...production). -!!! - -## Configurando o NGinx - -1. Criar um arquivo `nginx.conf` para configuração do NGinx na raíz do projeto. -2. Colocar o seguinte conteudo dentro do arquivo criado: - -``` Conteudo -server { - listen 80 default_server; - listen [::]:80 default_server; - root /usr/share/nginx/html; - server_name dominio.exemplo.ex www.dominio.exemplo2; - location / { - root /usr/share/nginx/html; - index index.html index.htm; - try_files $uri $uri/ /index.html =404; - } -} -``` - -3. Trocar os valores de `dominio.exemplo.ex` e `www.dominio.exemplo2` pelos domínios que o aplicação que será feito o deploy.Se o app for servido em `www.struct.com.br`, o arquivo deve conter: - -``` Exemplo -server { - listen 80 default_server; - listen [::]:80 default_server; - root /usr/share/nginx/html; - server_name www.struct.com.br; - location / { - root /usr/share/nginx/html; - index index.html index.htm; - try_files $uri $uri/ /index.html =404; - } -} -``` - -## Mudando as urls de localhost - -!!! -A aplicação React usa urls locais para acessar a API, por exemplo, `http://localhost:3333/api/v1`. Essas urls devem ser alteradas para as urls de produção, por exemplo, `https://api.struct.com.br/api/v1`.É possível fazer isso usando variáveis de ambiente, mas no momento deve ser trocado manualmente, como no nosso repositório de exemplo (talvez esse gitbook esteja desatualizado em relação ao repositório, verifique). -!!! - -## Mudando o `index.html` - -1. Alterar o arquivo `index.html` para conter informações corretas sobre a aplicação, bem como os metadados. -2. Criar um `robots.txt`, para ajudar os mecanismos de busca, além indexar o site conforme necessario. -3. Colocar o título correto, colocar descrição, mudar o favicon e a linguagem para pt-BR. - -## Criando docker image - -1. Vá para a branch production localmente. -2. Crie um arquivo chamado `Dockerfile` na raíz do projeto. -3. Atualize o url do git presente no arquivo, mudando o nome do projeto e o token de autenticação do GitHub. - -## Criando container - -1. Atualize o repositório de docker_compose da Struct com o seguinte comando: - -```bash Terminal -git pull -``` - -2. Crie uma pasta com o nome do projeto. -3. Modifique o template de `docker-compose.yml` do Traefik com os nomes que podem ser usados para identificar o projeto nos logs, caso ocorra algum erro. -4. Definir a imagem que será usada com o valor de `image`. -5. Alterar os valores de `environment`, `restart`, `volumes`, e `networks`. -6. Crie o container usando o comando: - -```bash Terminal -`docker-compose up -d` -``` \ No newline at end of file diff --git a/Diretorias/Diretoria Projetos/deploy/self_hosting_front/explicacao.md b/Diretorias/Diretoria Projetos/deploy/self_hosting_front/explicacao.md deleted file mode 100644 index 3fd557a6..00000000 --- a/Diretorias/Diretoria Projetos/deploy/self_hosting_front/explicacao.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -order: 3 -icon: rocket -label: "O que é Self-Hosting (Front-End)?" ---- - - - - -Self-hosting, também conhecido como auto-hospedagem, é um conceito em tecnologia que se refere à prática de hospedar e gerenciar seus próprios serviços, aplicativos ou plataformas em infraestrutura própria, em vez de utilizar serviços e plataformas de terceiros ou fornecedores externos. Em outras palavras, quando você opta por self-hosting, você é responsável por configurar, administrar e manter todos os aspectos do serviço ou aplicativo que está executando.Considerando que nenhum framework, e nem SSR, está sendo usado, a aplicação react não inclui servidor. No ambiente de desenvolvimento são usadas ferramentas para servir a aplicação na porta determinada (na Struct determinamos como 3000), mas no deploy utilizamos o NGinx, um servidor web que pode ser usado para servir arquivos estáticos, como imagens, css, js, etc. Sendo assim, depois que nossa aplicação react é buildada, ela é mantida pelo NGinx. \ No newline at end of file diff --git a/Diretorias/Diretoria Projetos/deploy/self_hosting_front/index.yml b/Diretorias/Diretoria Projetos/deploy/self_hosting_front/index.yml deleted file mode 100644 index 13d559c4..00000000 --- a/Diretorias/Diretoria Projetos/deploy/self_hosting_front/index.yml +++ /dev/null @@ -1,5 +0,0 @@ -icon: rocket -label: Self-Hosting (Front-End) - -# Ultima atualização: 23/09/2023 -# Autor(es): Artur Padovesi \ No newline at end of file diff --git a/Diretorias/Diretoria Projetos/deploy/heroku/como_usar.md b/Diretorias/Diretoria Projetos/deploy/servicos/heroku/como_usar.md similarity index 79% rename from Diretorias/Diretoria Projetos/deploy/heroku/como_usar.md rename to Diretorias/Diretoria Projetos/deploy/servicos/heroku/como_usar.md index 514e2ebb..ccab72f5 100644 --- a/Diretorias/Diretoria Projetos/deploy/heroku/como_usar.md +++ b/Diretorias/Diretoria Projetos/deploy/servicos/heroku/como_usar.md @@ -1,7 +1,7 @@ --- order: 1 -icon: rocket -label: "Como usar Heroku ?" +icon: plug +label: "Fazendo deploy (Rails | assets estáticos)" --- @@ -16,8 +16,8 @@ Esse deploy esta sendo feito com base em um projeto Rails 1. Crie uma branch chamada `heroku`, caso ainda não tenha, e faça as seguintes mudanças; 2. Crie um arquivo chamado `start.sh` na raíz do projeto com o seguinte conteúdo: -``` Terminal Shell -!/bin/sh +```bash +#!/bin/sh rails db:migrate bundle exec puma -C config/puma.rb ``` @@ -28,7 +28,13 @@ bundle exec puma -C config/puma.rb - `bundle exec puma -C config/puma.rb`: esse código funciona como um rails s, ou seja, serve para executar o puma (servidor padrão do rails) com alguns recursos a mais que o rails s por si só, não oferece. -3. Caso seu projeto utilize Active Storage, ou guarda alguma imagem enviada por upload, é necessário mudar o path, no qual os arquivos ficam armazenados, escolhendo entre [cloudinary](https://cloudinary.com/documentation/ruby_rails_quickstart) e [amazon s3](https://devcenter.heroku.com/articles/active-storage-on-heroku). Execute o comando **Certo** para configurar os arquivos. +!!!danger Caso seu projeto tenha banco de dados +É necessário ter uma instância separada de banco de dados. Se não me engano, o Heroku possui memória volátil, ou seja, alterações e criações de arquivos após o deploy podem ser perdidas. +!!! + +!!!danger Caso seu projeto utilize Active Storage +Ou guarde alguma imagem enviada por upload, é necessário mudar o path no qual os arquivos ficam armazenados, escolhendo entre [cloudinary](https://cloudinary.com/documentation/ruby_rails_quickstart) e [amazon s3](https://devcenter.heroku.com/articles/active-storage-on-heroku). Execute o comando **Certo** para configurar os arquivos. +!!! !!! Não colocar as chaves de acesso no repositório, apenas no heroku. Na branch de produção, requisitar as variáveis de ambiente no heroku, e colocar no código com `ENV['NOME_DA_VARIAVEL']`. @@ -59,6 +65,7 @@ bundle ## Executando deploy do projeto ### Por CLI + !!! Tutorial para instalar o CLI do heroku https://devcenter.heroku.com/articles/heroku-cli#download-and-install !!! @@ -71,7 +78,7 @@ heroku git:remote -a {nome_da_aplicação} ``` 3. Configure o banco de dados para PostgreSQL; -4. E por fim execute o comando: +4. E por fim execute o comando: ```bash Terminal git push heroku {nome_da_aplicação} @@ -84,13 +91,12 @@ git push heroku {nome_da_aplicação} 3. Navegue até a aba Deploy e selecione a opção GitHub; 4. Selecione o repositório do projeto; 5. Selecione a branch `Heroku`; -6. Selecione a opção **Deploy Branch**. +6. Selecione a opção **Deploy Branch**. ### Deploy front-end com heroku É possível usar do Heroku para fazer deploy de front-end. Basta criar um único endpoint para enviar os assets estáticos do front. Exemplo: - ```js // /package.json @@ -110,17 +116,18 @@ git push heroku {nome_da_aplicação} const express = require("express"); //chamamos o express para o arquivo -const { resolve } = require('path') +const { resolve } = require("path"); //para garantir que pegaremos o path exato const app = express(); //criamos uma aplicação com o express -app.use("/", +app.use( + "*", express.static( resolve( __dirname, - './build' // Onde os assets estáticos do front-end estão depois de rodar yarn build + "./build" // Onde os assets estáticos do front-end estão depois de rodar build ) ) ); diff --git a/Diretorias/Diretoria Projetos/deploy/servicos/heroku/explicacao.md b/Diretorias/Diretoria Projetos/deploy/servicos/heroku/explicacao.md new file mode 100644 index 00000000..a3863602 --- /dev/null +++ b/Diretorias/Diretoria Projetos/deploy/servicos/heroku/explicacao.md @@ -0,0 +1,16 @@ +--- +order: 3 +icon: question +label: "O que é?" +--- + + + + +Heroku é uma **plataforma** de deployment de website, desenvolvidos em quase todos frameworks mais famosos utimamente, ela **automaticamente** analisa o repositório e verifica a **linguagem** que você está **utilizando**, e já **faz o setup completo**, facilitando uma das principais e mais demoradas atividades de um projeto de website. + +O Heroku **roda** um **container docker** com seus **scripts** de inicialização. Isso significa que é **necessário** que o seu **projeto seja** um **servidor**, **ou seja**, que ele tenha uma porta para ser acessado, e que ele seja **capaz de responder a requisições**. Sendo assim, é ideal para api's, mas não para servir _assets estáticos_ (como os gerados numa aplicação React comum). + +!!! +O Heroku, na ultima atualização dessa documentação, não possui plano gratuito, logo utilizamos self-hosting para o back-end na Struct. +!!! diff --git a/Diretorias/Diretoria Projetos/deploy/heroku/index.yml b/Diretorias/Diretoria Projetos/deploy/servicos/heroku/index.yml similarity index 72% rename from Diretorias/Diretoria Projetos/deploy/heroku/index.yml rename to Diretorias/Diretoria Projetos/deploy/servicos/heroku/index.yml index c1bfb6dc..6b16dc3f 100644 --- a/Diretorias/Diretoria Projetos/deploy/heroku/index.yml +++ b/Diretorias/Diretoria Projetos/deploy/servicos/heroku/index.yml @@ -1,4 +1,4 @@ -icon: rocket +icon: Imagens DocStruct/Logos/heroku.svg label: Heroku # Ultima atualização: 22/09/2023 diff --git a/Diretorias/Diretoria Projetos/deploy/servicos/index.yml b/Diretorias/Diretoria Projetos/deploy/servicos/index.yml new file mode 100644 index 00000000..b7aeb3f3 --- /dev/null +++ b/Diretorias/Diretoria Projetos/deploy/servicos/index.yml @@ -0,0 +1 @@ +icon: apps diff --git a/Diretorias/Diretoria Projetos/deploy/netlify/como_usar.md b/Diretorias/Diretoria Projetos/deploy/servicos/netlify/como_usar.md similarity index 70% rename from Diretorias/Diretoria Projetos/deploy/netlify/como_usar.md rename to Diretorias/Diretoria Projetos/deploy/servicos/netlify/como_usar.md index e374e053..637f428f 100644 --- a/Diretorias/Diretoria Projetos/deploy/netlify/como_usar.md +++ b/Diretorias/Diretoria Projetos/deploy/servicos/netlify/como_usar.md @@ -1,16 +1,20 @@ --- order: 1 -icon: rocket -label: "Como usar Netlify ?" +icon: plug +label: "Fazendo deploy de assets estáticos (talvez mais?)" --- +!!! +**Só foi testado** o deploy de assets estáticos gerados por build de apps **React**. Provavelmente é **possível** hospedar uma **API**, porém **sem o Banco de Dados**. Isso porque o armazenamento do Netlify é "volátil" (não garante permanência de alterações pós deploy, pode resetar pro estado inicial a qualquer momento) +!!! + ## Configurando o projeto -1. Na própria main, mude o `/public/favicon.ico` para o real ícone do projeto. -2. Mude o `index.html`, trocando os conteúdos das tags ``, `` e a `lang` da tag `<html>`. +1. Na própria main, mude o `/public/favicon.ico` para o real ícone do projeto. +2. Mude o `index.html`, trocando os conteúdos das tags `<meta>`, `<title>` e a `lang` da tag `<html>`. 3. Pense na possibilidade de adicionar um `/public/robots.txt`. 4. Crie uma branch chamada `netlify` 5. Mude todas as referências a localhost por suas respectivas urls de produção @@ -22,7 +26,7 @@ Se você tem uma instância axios com a url `http://localhost:3333/api/v1`, mude ## Roteamento Client Side !!! -Geralmente fazemos _deploy_ de React como [_single page app_](https://en.wikipedia.org/wiki/Single-page_application), com um roteador _client side_, como react-router-dom. Sendo assim, rotas não são [_endpoints_](https://www.cloudflare.com/pt-br/learning/security/api/what-is-api-endpoint/), e sempre devem ser retornados os mesmos arquivos pra requisições, independente da rota. +Geralmente fazemos _deploy_ de React como [_single page app_](https://en.wikipedia.org/wiki/Single-page_application), com um roteador _client side_, como react-router-dom. Sendo assim, rotas não são [_endpoints_](https://www.cloudflare.com/pt-br/learning/security/api/what-is-api-endpoint/), e sempre devem ser retornados os mesmos arquivos pra requisições, independente da rota. !!! 1. Adicione o arquivo `_redirects` no do projeto com o seguinte conteúdo: @@ -36,5 +40,5 @@ Geralmente fazemos _deploy_ de React como [_single page app_](https://en.wikiped 1. Vá para a branch `netlify`; 2. Rode o comando `yarn build` para gerar uma pasta `build` com os arquivos estáticos; 3. Faça login na conta de projetos da Struct; -4. Selecione a opção de _deploy_ manual (__deploy_ manually_); -5. Arraste e solte os arquivos da pasta `build` na área de upload; \ No newline at end of file +4. Selecione a opção de _deploy_ manual (\__deploy_ manually\_); +5. Arraste e solte os arquivos da pasta `build` na área de upload; diff --git a/Diretorias/Diretoria Projetos/deploy/netlify/explicacao.md b/Diretorias/Diretoria Projetos/deploy/servicos/netlify/explicacao.md similarity index 87% rename from Diretorias/Diretoria Projetos/deploy/netlify/explicacao.md rename to Diretorias/Diretoria Projetos/deploy/servicos/netlify/explicacao.md index bed00c83..d4a0dc68 100644 --- a/Diretorias/Diretoria Projetos/deploy/netlify/explicacao.md +++ b/Diretorias/Diretoria Projetos/deploy/servicos/netlify/explicacao.md @@ -1,10 +1,10 @@ --- order: 3 -icon: rocket -label: "O que é Netlify ?" +icon: question +label: "O que é?" --- <!-- Ultima atualização: 23/09/2023 --> <!-- Autor(es): Artur Padovesi --> -O Netlify é um serviço de hospedagem de sites estáticos, que também oferece serviços de _staging_ e _deploy_ automatizados. Isso significa que não é possível hospedar backend no Netlify, apenas frontend (com possibilidade de _AWS Lambda_).Para fazer _deploy_ no Netlify, a possiblidade atualmente gratuita é fazer _deploy_ manual, que consiste em gerar e colocar manualmente os arquivos que serão servidos no site. Sendo assim, o processo de _bundling_ deve ser feito na mão. \ No newline at end of file +O Netlify é um serviço de hospedagem de sites estáticos, que também oferece serviços de _staging_ e _deploy_ automatizados. Isso significa que não é possível hospedar backend no Netlify, apenas frontend (com possibilidade de _AWS Lambda_).Para fazer _deploy_ no Netlify, a possiblidade atualmente gratuita é fazer _deploy_ manual, que consiste em gerar e colocar manualmente os arquivos que serão servidos no site. Sendo assim, o processo de _bundling_ deve ser feito na mão. diff --git a/Diretorias/Diretoria Projetos/deploy/servicos/netlify/index.yml b/Diretorias/Diretoria Projetos/deploy/servicos/netlify/index.yml new file mode 100644 index 00000000..3b58897a --- /dev/null +++ b/Diretorias/Diretoria Projetos/deploy/servicos/netlify/index.yml @@ -0,0 +1,4 @@ +icon: Imagens DocStruct/Logos/netlify.png +label: Netlify +# Ultima atualização: 23/09/2023 +# Autor(es): Artur Padovesi diff --git a/Imagens DocStruct/Logos/heroku.svg b/Imagens DocStruct/Logos/heroku.svg new file mode 100644 index 00000000..a332e240 --- /dev/null +++ b/Imagens DocStruct/Logos/heroku.svg @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg width="800px" height="800px" viewBox="-72 0 400 400" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet"><path d="M28.083 398.289V363.51c0-2.452-1.798-3.51-3.917-3.51-4.248 0-9.554 1.058-14.37 3.181v35.108H0v-64.576h9.795v21.304c4.656-1.712 10.206-3.18 15.758-3.18 8.898 0 12.246 5.469 12.246 12.976v33.476h-9.716zm27.999-21.063c.326 11.674 2.613 13.961 9.794 13.961 5.634 0 12.002-1.879 16.902-3.757l1.632 7.346c-5.226 2.37-11.593 4.655-19.183 4.655-16.33 0-18.862-8.978-18.862-23.268 0-7.835.573-14.939 2.45-21.47 4.898-1.878 11.43-2.857 19.673-2.857 13.393 0 17.473 7.43 17.473 20.41v4.98H56.082zM68.488 360c-2.935 0-7.59.082-11.427.813-.406 1.96-.899 4.655-1.062 9.636h20.41c0-6.778-1.225-10.449-7.921-10.449zm35.837 3.181v35.108h-9.797v-39.515c8.246-4.489 16.981-5.877 22.698-6.285v8.164c-4 .326-9.064.816-12.9 2.528zm38.778 36.25c-14.616 0-21.228-7.183-21.228-23.594 0-17.389 8.735-24 21.228-24 14.612 0 21.226 7.182 21.226 23.592 0 17.39-8.737 24.002-21.226 24.002zm0-39.43c-7.512 0-11.675 4.325-11.675 15.836 0 12.574 3.51 15.35 11.675 15.35 7.51 0 11.674-4.247 11.674-15.758 0-12.574-3.51-15.429-11.674-15.429zm68.49 38.288H200.08c-2.692-7.184-6.45-14.532-12.246-20.9h-5.144v20.9h-9.796v-64.576h9.796v37.062h4.573c4.98-5.144 8.816-11.509 11.511-17.797h11.02c-3.754 7.593-8.57 14.287-13.959 19.757 6.45 8.164 11.511 16.818 15.757 25.554zm18.363 1.142c-8.897 0-12.244-5.468-12.244-12.98v-33.473h9.714v34.697c0 2.452 1.794 3.512 3.917 3.512 4.246 0 10.042-1.06 14.86-3.184v-35.025H256v39.35c-11.593 6.369-20.493 7.103-26.044 7.103zM225.628 317.253H30.258C13.545 317.253 0 303.708 0 286.998V30.256C0 13.546 13.546 0 30.257 0h195.37c16.71 0 30.26 13.546 30.26 30.256v256.742c0 16.71-13.55 30.255-30.26 30.255z" fill="#6762A6"/><path d="M160.36 273.6V147.61s8.195-30.15-100.943 12.334c-.2.539-.2-116.504-.2-116.504l35.66-.22v74.991s99.846-39.325 99.846 29.824V273.6h-34.362zm20.32-184.994h-37.824c13.615-16.646 25.94-45.167 25.94-45.167h39.11s-6.696 18.587-27.225 45.167zM59.865 273.382v-71.748l35.878 35.877-35.878 35.871z" fill="#FFF"/></svg> \ No newline at end of file diff --git a/Imagens DocStruct/Logos/netlify.png b/Imagens DocStruct/Logos/netlify.png new file mode 100644 index 00000000..888d9400 Binary files /dev/null and b/Imagens DocStruct/Logos/netlify.png differ