Trabalho Individual 2021.2

Os conhecimentos de Gestão de Configuração de Software são fundamentais no ciclo de vida de um produto de software. As técnicas para a gestão vão desde o controle de versão, automação de build e de configuração de ambiente, testes automatizados, isolamento do ambiente até o deploy do sistema. Todo este ciclo nos dias de hoje são integrados em um pipeline de DevOps com as etapas de Integração Contínua (CI) e Deploy Contínuo (CD) implementadas e automatizada.

Para exercitar estes conhecimentos, neste trabalho, você deverá aplicar os conceitos estudados ao longo da disciplina no produto de software contido neste repositório.

O sistema se trata de uma aplicação em Ruby on Rails composta por:

  • Aplicação de Gerência de Biblioteca;
  • Banco de Dados Postgres;

Para executar a aplicação em sua máquina, basta seguir o passo-a-passo descrito no arquivo README da pasta.

Resumo da aplicação

A aplicação é um simples sistema de cadastro de livros. Porém, o foco do trabalho é na automação da build, testes, conteinerização e configuração dos pipelines de CI/CD. Está escrita em Ruby on Rails, utiliza o banco de dados Postgres e inclui testes.

Etapas de trabalho

O trabalho deve ser elaborado através de etapas. Cada uma das etapas deve ser realizada em um commit separado com o resultado funcional desta etapa.

As etapas de 1 a 3 são relacionadas ao isolamento do ambiente utilizando a ferramenta Docker e Docker Compose. Neste sentido o tutorial abaixo cobre os conceitos fundamentais para o uso destas tecnologias.

Tutorial de Docker

As etapas de 4 e 5 são relacionadas à configuração do pipeline de CI e CD.

Tutorial CI - Gitlab

1. Containerização do Banco

A versão inicial do sistema é uma aplicação Ruby on Rails cujo funcionamento requer uma instalação de um banco de dados Postgres. A primeira etapa do trabalho é de configurar um container somente para o banco de dados com as credenciais especificadas na descrição da aplicação e testar o funcionamento do mesmo.

Nesta estapa, o banco de dados foi containerizado a partir de um arquivo Dockerfile, de forma bem simples. Para a sua utilização é necessária a realização do build para que a imagem possa ser gerada. Esse passo é realizado através do comando (dentro da pasta aplicacao):
sudo docker build -t postgres-db ./
A criação do container e a sua execução são realizadas com o comando (também na pasta aplicacao):
sudo docker run --name postgresdb-container -p 5432:5432 postgres-db
Após a realização destes dois passos, a aplicação pode ser configurada e executada normalmente.

Commits:
atualizando gitignore
criando Dockerfile do banco de dados
1. Containerização do Banco

2. Containerização da Aplicação + Banco

Nesta segunda etapa, tanto a aplicação quanto o banco de dados deverão estar funcionando em containers individuais.

Deverá ser utilizado um orquestrador (Docker Compose) para gerenciar comunicação entre os containers além do uso de credenciais, networks, volumes, entre outras configurações necessárias para a correta execução da aplicação.

Nesta etapa tanto o banco de dados quanto a aplicação foram conteinerizados. Para o gerenciamento entre os containers foi criado um arquivo docker-compose. O Dockerfile do banco de dados, por se tratar de um serviço simples, foi removido. Assim, o container do banco se baseia em uma imagem já pronta do Postgre. Para o Ruby, por ser um serviço mais complexo, foi criado um Dockerfile.
Os servicos foram nomeados como app (Ruby) e db (Postgre).
Tanto o Dockerfile quando o docker-compose ainda estão localizados na raíz da aplicacao.

Para a execução do container, utiliza-se o comando:
sudo docker-compose up --build
na pasta aplicacao. Após a inicialização dos serviços, é necessário configurar o banco de dados com o comando:
sudo docker exec -it aplicacao_app_1 rails db:setup

Commits:
removendo postgree e criando ruby Dockerfile
criando docker-compose
configurando host da BD na aplicacao
corrigindo senha do banco de dados
renomeando servico da aplicacao
2. Containerização da Aplicação + Banco

3. Adição de um container do Nginx

A aplicação originalmente está configurada para rodar com um servidor web simples interno na porta 3000. Nesta etapa será necessário adicionar o servidor Nginx para servir a aplicação através da porta 80. O resultado final também estará expresso utilizando o Docker Compose.

Nesta etapa foi criado um diretório para armazenar os Dockerfiles tanto do container app (Ruby) quanto do web (nginx). Além disso, foi criado também um arquivo .dockerignore, para que arquivos desnecessários não sejam copiados para o container da aplicação.
Assim como na etapa anterior, para o build e execução dos containers, é utilizado o comando:
sudo docker-compose up --build
Entretanto, como foi criado um servidor nginx para a aplicação, basta digitar localhost no seu navegador para ter acesso à Biblioteca Pessoal.
O resultado desta etapa é uma aplicação completamente containerizada, mais organizada que as anteriores (possuindo um diretório direcionado para o docker e um arquivo .dockerignore) e pronta para seguir para a integração contínua.

Commits:
criando diretório de docker
tornando o dockerfile da aplicação mais robusto
criando dockerignore
criando Dockerfile do nginx
adicionando arquivo de configuração do nginx
alterando o docker compose
3. Adição de um container do Nginx

4. Integração Contínua (CI)

Para a realização desta etapa, a aplicação já deverá ter seu ambiente completamente containerizado.

Deverá ser utilizada uma ferramenta de Integração Contínua para garantir o build, os testes e os deploy para o Docker Hub dos serviços principais.

Esta etapa do trabalho poderá ser realizada utilizado os ambientes de CI do GitLab-CI. ou Github Actions.

Requisitos da configuração da Integração Contínua (Gitlab ou Github) incluem:

  • Build
  • Test
  • Lint

Nesta etapa foi criado o diretório de workflows do github. Foram criados três jobs:

  1. Build, onde são executadas as ações para setup da base de dados.
  2. Test, onse são executadas os comandos de teste indicados no README da aplicação.
  3. Lint, onde são realizadas inspeções com as Gems bundler-audit, brakeman e rubocop.

Sendo que tanto o job Lint quanto o Test dependem do Build. Na primeira execução da action, o Job de Lint falhou por encontrar uma vulnerabilidade nas versões de algumas Gems. Essa vulnerabilidade foi corrigida e todos os jobs foram executados com sucesso.

Commits:
criando arquivo de workflow
adicionando job de build
adicionando job de teste
adicionando job de lint
movendo pasta de workflow
corrigindo vulnerabilidades
4. Integração Contínua (CI)

5. Deploy Contínuo (CD)

A etapa final do trabalho deverá ser realizada à partir do deploy automático da aplicação que deve ser realizado à partir após passar sem erros em todas as etapas de CI.

Nesta etapa foi criado o job push_to_registry para que se possa executar o push das imagens para o DockerHub. Esse job depende dos jobs de Test e Lint, que, por sua vez, dependem do job de Build.
As imagens estão hospedadas em:

Desta forma o trabalho está, enfim, finalizado.

Commits:
adicionando o job para puh no dockerhub
alterando o nome do workflow
5. Deploy Contínuo (CD)

Avaliação

A avaliação do trabalho será feita à partir da correta implementação de cada etapa 1 a 5. A avaliação será feita de maneira quantitativa (se foi realizado a implementação + documentação), e qualitativa (como foi implementado, entendimento dos conceitos na prática, complexidade da solução). Para isso, faça os commits atômicos, bem documentados, completos a fim de facilitar o entendimento e avaliação do seu trabalho. Lembrando o trabalho é individual.

Item Peso
Containerização do Banco 1.0
Containerização da Aplicação + Banco 2.0
Containerização da Aplicação + Banco + Nginx 2.0
Integração Contínua (Build, Test, Lint) 3.0
Deploy Contínuo 2.0

Exemplo de Trabalhos Anteriores

Alguns trabalhos de trabalhos anteriores: