diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..6d75dcc --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ + +tests/ +.github/ +terraform/ \ No newline at end of file diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml new file mode 100644 index 0000000..4bd88ca --- /dev/null +++ b/.github/workflows/docker-build.yml @@ -0,0 +1,191 @@ +# Definição do nome da pipeline CI/CD +name: CI/CD Pipeline + +# Configura os eventos que disparam o pipeline, sendo um push ou pull request na branch "main" +on: + push: + branches: ["main"] # Dispara no push para a branch main + paths-ignore: + - README.md # Ignora alterações no arquivo README.md + pull_request: + branches: ["main"] # Dispara quando um pull request é aberto para a branch main + paths-ignore: + - README.md # Ignora alterações no arquivo README.md + +jobs: + # Job de testes + test: + runs-on: ubuntu-latest # Roda em uma máquina virtual com Ubuntu mais recente + steps: + # Passo 1: Faz o checkout do repositório + - name: Checkout repository + uses: actions/checkout@v3 # Usa a ação de checkout do repositório + + # Passo 2: Configura o Python 3.11 no ambiente + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' # Define a versão do Python a ser utilizada + + # Passo 3: Instala as dependências do projeto usando o pip + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt # Instala as dependências do arquivo requirements.txt + + # Passo 4: Define o PYTHONPATH para o diretório atual + - name: Set PYTHONPATH + run: echo "PYTHONPATH=$(pwd)" >> $GITHUB_ENV # Define a variável de ambiente PYTHONPATH + + # Passo 5: Executa os testes com cobertura de código + - name: Run tests with coverage + env: + DATABASE_URL: ${{ secrets.DATABASE_URL }} # Passa a variável DATABASE_URL como segredo + run: | + pytest --cov=api --cov-report=xml # Executa os testes com cobertura e gera relatório XML + + # Passo 6: Faz o upload do relatório de cobertura + - name: Upload coverage report + uses: actions/upload-artifact@v4 # Usa a ação para enviar o relatório de cobertura como artefato + with: + name: coverage-report + path: coverage.xml # O caminho do arquivo de cobertura + + # Job de análise do SonarQube + sonar: + runs-on: ubuntu-latest # Roda em uma máquina Ubuntu + needs: test # Esse job depende do job "test" para ser executado + steps: + # Passo 1: Faz o checkout do repositório + - name: Checkout repository + uses: actions/checkout@v3 + + # Passo 2: Baixa o relatório de cobertura + - name: Download coverage report + uses: actions/download-artifact@v4 + with: + name: coverage-report # Baixa o artefato de cobertura gerado no job anterior + + # Passo 3: Baixa e instala o SonarScanner + - name: Download and Install SonarScanner + run: | + curl -sSLo sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-7.0.2.4839-linux-x64.zip + unzip sonar-scanner.zip -d $HOME # Baixa e descompacta o scanner + echo "$HOME/sonar-scanner-7.0.2.4839-linux-x64/bin" >> $GITHUB_PATH # Adiciona o sonar-scanner ao PATH + + # Passo 4: Executa a análise no SonarQube + - name: SonarQube Scan + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} # Passa o token de autenticação como segredo + run: | + sonar-scanner \ + -Dsonar.organization=filipesuhett \ + -Dsonar.projectKey=filipesuhett_ledschallenge \ + -Dsonar.sources=api \ + -Dsonar.python.coverage.reportPaths=coverage.xml \ + -Dsonar.host.url=https://sonarcloud.io # Configura o SonarQube e envia os dados de cobertura + + # Job de infraestrutura usando Terraform + terraform: + runs-on: ubuntu-latest # Roda em uma máquina Ubuntu + needs: sonar # Esse job depende do job "sonar" + steps: + # Passo 1: Faz o checkout do repositório + - name: Checkout repository + uses: actions/checkout@v3 + + # Passo 2: Configura as credenciais da AWS + - name: Configure AWS CLI + uses: aws-actions/configure-aws-credentials@v2 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} # Usando a chave de acesso da AWS como segredo + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # Usando a chave secreta da AWS como segredo + aws-region: ${{ secrets.AWS_REGION }} # Região da AWS + + # Passo 3: Instala o Terraform + - name: Instalar Terraform + uses: hashicorp/setup-terraform@v2 # Instala o Terraform no ambiente + + # Passo 4: Navega até o diretório Terraform e executa comandos + - name: Navegar até a pasta terraform e inicializar + run: | + cd terraform + terraform init # Inicializa o diretório com o Terraform + terraform plan -out=tfplan # Planeja a execução + terraform show -no-color tfplan # Exibe o plano sem cores + + # Passo 5: Aplica o plano do Terraform + - name: Aplicar Terraform + run: | + cd terraform + terraform apply -auto-approve # Aplica as mudanças sem confirmação manual + + # Job de construção do Docker + build: + runs-on: ubuntu-latest # Roda em uma máquina Ubuntu + needs: terraform # Esse job depende do job "terraform" + steps: + # Passo 1: Faz o checkout do repositório + - name: Checkout repository + uses: actions/checkout@v3 + + # Passo 2: Constrói a imagem Docker com o segredo DATABASE_URL + - name: Build Docker image with secret DATABASE_URL + run: | + docker build --build-arg DATABASE_URL=${{ secrets.DATABASE_URL }} -t ledschallenge:latest . # Constrói a imagem Docker com o argumento de banco de dados + + # Passo 3: Salva a imagem Docker em um arquivo tar + - name: Save Docker image as tar file + run: | + docker save -o ledschallenge.tar ledschallenge:latest # Salva a imagem em formato .tar + + # Passo 4: Faz o upload do arquivo tar como artefato + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: ledschallenge-image + path: ledschallenge.tar # Envia a imagem como artefato + + # Job de deployment + deploy: + runs-on: ubuntu-latest # Roda em uma máquina Ubuntu + needs: build # Esse job depende do job "build" + steps: + # Passo 1: Faz o checkout do repositório + - name: Checkout repository + uses: actions/checkout@v3 + + # Passo 2: Configura as credenciais da AWS para o deployment (caso precise de algum recurso da AWS) + - name: Configure AWS CLI + uses: aws-actions/configure-aws-credentials@v2 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} # Chave de acesso da AWS + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # Chave secreta da AWS + aws-region: ${{ secrets.AWS_REGION }} # Região da AWS + + # Passo 3: Faz login no Docker Hub usando o token pessoal + - name: Docker Hub Login + run: | + docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_TOKEN }} # Login com o token + + # Passo 4: Baixa a imagem Docker criada no job anterior + - name: Baixar imagem do build + uses: actions/download-artifact@v4 + with: + name: ledschallenge-image + path: ./ # Baixa o artefato contendo a imagem Docker + + # Passo 5: Carrega a imagem Docker no ambiente + - name: Load Docker image + run: docker load -i ledschallenge.tar # Carrega a imagem Docker + + # Passo 6: Marca e faz push da imagem para o Docker Hub + - name: Tag e Push para Docker Hub + run: | + IMAGE_TAG=latest + REPO_URI=docker.io/${{ secrets.DOCKER_USERNAME }}/ledschallenge # Substitua pelo seu repositório no Docker Hub + + docker tag ledschallenge:latest $REPO_URI:$IMAGE_TAG # Marca a imagem com a tag "latest" + docker push $REPO_URI:$IMAGE_TAG # Envia a imagem para o Docker Hub + + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8a13706 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +# Usando a imagem base do Python 3.11 com uma versão slim para reduzir o tamanho da imagem +FROM python:3.11-slim + +# Definindo uma variável de ambiente para a URL do banco de dados +ARG DATABASE_URL +ENV DATABASE_URL=$DATABASE_URL + +# Definindo o diretório de trabalho dentro do container para /app +WORKDIR /app + +# Copiando o arquivo de dependências para dentro do container +COPY requirements.txt . + +# Instalando as dependências a partir do requirements.txt +RUN pip install --no-cache-dir -r requirements.txt + +# Copiando todo o conteúdo do diretório atual para o diretório de trabalho dentro do container +COPY . . + +# Expondo a porta 8000 para a aplicação web (FastAPI) +EXPOSE 8000 + +# Definindo o comando padrão para rodar a aplicação com o Uvicorn, que é um servidor ASGI +CMD ["uvicorn", "api.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"] diff --git a/README.md b/README.md index 05fdafe..73def1f 100644 --- a/README.md +++ b/README.md @@ -1,104 +1,315 @@ -# Desafio DevOps - LEDS -*Bem-vindo!* 👋 +# LedsChallenge - Documentação Completa -Neste desafio, você terá a oportunidade de demonstrar que possui as habilidades necessárias para atuar no time de DevOps do laboratório. +Este repositório é uma solução DevOps completa, abrangendo a configuração do **Dockerfile**, **Terraform**, **GitHub Actions** e a **Infraestrutura na AWS** para uma aplicação FastAPI. A seguir, você encontrará todos os detalhes das configurações, decisões tomadas e passos necessários para replicar e entender o processo. -# Contextualização +## Índice -O desafio é implementar uma automação de CI/CD usando Github Actions para um programa que permita realizar as seguintes buscas: -1. Listar os **órgãos, códigos e editais dos concursos públicos** que se encaixam no perfil do candidato, tomando como base o seu **CPF**; -2. Listar o **nome, data de nascimento e o CPF** dos candidatos que se encaixam no perfil do concurso tomando com base o **Código do Concurso** do concurso público; +1. [Pré-requisitos](#pré-requisitos) +2. [Estrutura do Repositório](#estrutura-do-repositório) +3. [Dockerfile](#dockerfile) +4. [GitHub Actions](#github-actions) +5. [Terraform](#terraform) + - [Provedor AWS](#provedor-aws) + - [Instância EC2](#instância-ec2) + - [IAM e Políticas](#iam-e-políticas) +6. [Como funciona a API](#como-funciona-a-api) +7. [Infraestrutura AWS](#infraestrutura-aws) +8. [Passos para Rodar Localmente](#passos-para-rodar-localmente) +9. [Notas Finais](#notas-finais) -A automação deve realizar as seguintes automações: -1. Executar os testes automatizados -2. Verificar a qualidade do código -3. Quebrar o CI quando os testes falharem ou quando a qualidade for menor de 80% -4. Registrar o docker do software no Github Package +--- -O arquivo **candidatos.txt** contém as informações dos candidatos: +## 1. Pré-requisitos -| Nome | Data de Nascimento | CPF | Profissões| -|---|---|---|---| -| Lindsey Craft | 19/05/1976 | 182.845.084-34 | [carpinteiro] | -| Jackie Dawson | 14/08/1970 | 311.667.973-47 | [marceneiro, assistente administrativo] | -| Cory Mendoza | 11/02/1957 | 565.512.353-92 | [carpinteiro, marceneiro] | +Antes de começar, verifique se você tem as ferramentas e configurações necessárias em seu ambiente: -O arquivo **concursos.txt** contém as informações dos concursos públicos: +- **Docker**: Para construir e rodar containers. +- **Terraform**: Para provisionamento de infraestrutura na AWS. +- **AWS CLI**: Para gerenciar e configurar recursos AWS diretamente do seu terminal. +- **GitHub Actions**: Para automação do CI/CD. +- **Conta AWS**: Com permissões apropriadas para criar e gerenciar recursos como EC2, IAM, etc. -| Órgão | Edital | Código do Concurso | Lista de vagas| -|---|---|---|---| -| SEDU | 9/2016 | 61828450843 | [analista de sistemas, marceneiro] | -| SEJUS | 15/2017 | 61828450843 | [carpinteiro,professor de matemática,assistente administrativo] | -| SEJUS | 17/2017 | 95655123539 | [professor de matemática] | +--- -🤩 **As tecnologias a serem utilizadas na implementação da solução ficam a seu critério!** +## 2. Estrutura do Repositório -# Como entregar? -1. Faça um **fork** do repositório. Nesse fork esperamos encontrar uma documentação completa da solução e a listagem dos diferenciais implementados. -2. Abra um **pull request (PR)** do seu fork para o nome repositório com o seu nome como título. Assim conseguimos te localizar melhor e ver que você já finalizou o desafio! +O repositório segue uma estrutura simples, porém organizada, para facilitar a navegação e execução de todos os componentes necessários: -🚨 **Atenção**: você deve enviar apenas o código fonte. Não serão aceitos códigos compilados. +``` +. +├── Dockerfile # Configuração da imagem Docker +├── requirements.txt # Dependências Python +├── api/ # Código da aplicação FastAPI +│ ├── main.py # Arquivo principal da aplicação +│ ├── schemas.py # Definições dos schemas Pydantic +│ ├── models.py # Modelos de dados +│ └── database.py # Conexão com o banco de dados +├── tests/ # Testes da aplicação +│ ├── conftest.py # Configurações de testes +│ ├── test_candidatos.py # Testes dos candidatos +│ └── test_concursos.py # Testes dos concursos +├── terraform/ # Infraestrutura com Terraform +│ ├── main.tf # Definições principais do Terraform +│ ├── variables.tf # Variáveis do Terraform +│ └── outputs.tf # Saídas do Terraform +├── .github/ # Configurações do GitHub Actions +│ └── workflows/ +│ └── deploy.yml # Workflow de deploy +└── README.md # Documentação do projeto +``` -## Avaliação +--- -O programa será avaliado levando em conta os seguintes critérios: +## 3. Dockerfile -| Critério | Valor | -|---|---| -| Legibilidade do Código | 10 | -| Documentação do código | 10 | -| Documentação da solução | 10 | -| Tratamento de Erros | 10 | -| Implementar testes unitários | 15 | -| Implementar integração com [Github Action](https://github.com/features/actions) | 10 | -| Implementar integração com Github Action + SonarQube | 10 | -| Implementar usando Docker | 5 | -| Total | 90 | +O `Dockerfile` define a imagem Docker necessária para rodar a aplicação FastAPI dentro de um container. -A sua pontuação será a soma dos valores obtidos nos critérios acima. +```dockerfile +# Usando a imagem base do Python 3.11 com uma versão slim para reduzir o tamanho da imagem +FROM python:3.11-slim -## Diferenciais -Você pode **aumentar sua pontuação** implementando os seguintes diferenciais: +# Definindo uma variável de ambiente para a URL do banco de dados +ARG DATABASE_URL +ENV DATABASE_URL=$DATABASE_URL -| Item | Pontos Ganhos | -|---|---| -| Criar um [serviço](https://martinfowler.com/articles/microservices.html) com o problema | 30 | -| Utilizar banco de dados | 30 | -| Implementar Clean Code | 20 | -| Implementar o padrão de programação da tecnologia escolhida | 20 | -| Implementar testes comportamentais | 15 | -| Usar tecnologias de IaC (Terraform, ansible, HelmChart, etc)|15| -| Total| 130 | +# Definindo o diretório de trabalho dentro do container +WORKDIR /app -A pontuação final será calculada somando os critérios obrigatórios e os diferenciais implementados corretamente. +# Copiando o arquivo de dependências para dentro do container +COPY requirements.txt . -# Penalizações +# Instalando as dependências do requirements.txt +RUN pip install --no-cache-dir -r requirements.txt -Você será desclassificado se: +# Copiando todos os arquivos do diretório atual para dentro do container +COPY . . -1. Enviar uma solução que não funcione. -2. Não cumprir os critérios da seção **Avaliação**. -3. For identificado plágio. - -***Que a força esteja com você. Boa sorte!*** +# Expondo a porta 8000 para a aplicação FastAPI +EXPOSE 8000 -