paint-brush
Um guia simplificado para o "Dockerazition" de Ruby e Rails com o aplicativo React Front-End por@forison
198 leituras

Um guia simplificado para o "Dockerazition" de Ruby e Rails com o aplicativo React Front-End

por Addo Boakye Forison13m2024/08/04
Read on Terminal Reader

Muito longo; Para ler

Dockerização envolve dois conceitos principais: imagens e contêineres. As imagens servem como modelos para contêineres, contendo todas as informações necessárias para criar um contêiner. Um contêiner é uma instância de tempo de execução de uma imagem, compreendendo a própria imagem, um ambiente de execução e instruções de tempo de execução. Neste artigo, forneceremos um guia prático para dockerizar suas aplicações Rails e React em detalhes.
featured image - Um guia simplificado para o "Dockerazition" de Ruby e Rails com o aplicativo React Front-End
Addo Boakye Forison HackerNoon profile picture
0-item
1-item

Dockerizar seu Ruby on Rails com um aplicativo front-end React pode melhorar drasticamente seu fluxo de trabalho de desenvolvimento e processo de implantação. Ao criar um ambiente padronizado para seu aplicativo, você garante um comportamento consistente em diferentes estágios de desenvolvimento, teste, produção e até mesmo em diferentes sistemas. Na verdade, ele foi projetado para minimizar problemas relacionados às diferenças do sistema. Este guia orientará você nas etapas essenciais para que seu aplicativo Rails e React funcione perfeitamente em contêineres Docker.

Docker para o resgate

Por que Dockerizar um aplicativo?

  • Consistência entre ambientes :
    • O Docker garante que o aplicativo seja executado da mesma maneira, independentemente de onde for implantado, seja na máquina de um desenvolvedor, em um ambiente de teste ou em um servidor de produção. Essa consistência é alcançada pela conteinerização de todas as dependências e configurações.


  • Gerenciamento de Dependências :
    • Os contêineres Docker incluem todas as dependências necessárias para a execução do aplicativo. Isso significa que variações nas bibliotecas do sistema ou falta de dependências em sistemas diferentes não afetam a funcionalidade do aplicativo.


  • Isolamento :
    • Os contêineres Docker são executados isoladamente uns dos outros e do sistema host. Este isolamento evita conflitos entre diferentes aplicações e suas dependências no mesmo sistema.


  • Portabilidade :
    • Os contêineres Docker podem ser facilmente movidos e executados em qualquer sistema que suporte Docker, seja uma máquina local, um serviço em nuvem ou um servidor dedicado. Isso torna o aplicativo altamente portátil e flexível em termos de implantação.


NB: É necessário conhecimento da sintaxe do Docker


Dockerização envolve dois conceitos principais: imagens e contêineres. As imagens servem como modelos para contêineres, contendo todas as informações necessárias para criar um contêiner, incluindo dependências e configurações de implantação. Um contêiner é uma instância de tempo de execução de uma imagem, compreendendo a própria imagem, um ambiente de execução e instruções de tempo de execução. O Docker em geral estabelece um padrão para envio de software.


Para explicar o Docker com uma analogia simples: pense nos contêineres como os contêineres de transporte em um pátio, nas imagens como os itens colocados dentro desses contêineres e no navio de transporte como o sistema no qual os contêineres funcionam.


Sempre que você configura e cria seu aplicativo, determinadas configurações de ambiente são necessárias. Por exemplo, você não pode executar uma aplicação Rails sem um ambiente Ruby instalado em seu sistema. Da mesma forma, você não pode executar um aplicativo React sem Node.js e não pode instalar pacotes React sem um gerenciador de pacotes Node como npm ou Yarn etc.


Como o contêiner roda de forma isolada do sistema do usuário, vamos disponibilizar todos esses pacotes em nosso contêiner, assim como faríamos caso o construíssemos diretamente em nosso sistema, assim, o contêiner atuará como um sistema nele próprio, como uma máquina virtual. Existem diferenças entre o docker e a máquina virtual, mas este exemplo é apenas para explicar melhor.


Agora, vamos dockerizar a aplicação Rails. Para fazer isso, precisaremos de três arquivos em nossa aplicação Rails: um Dockerfile , um docker-compose.yml e um bin/docker-entrypoint . Vamos examinar cada um desses arquivos detalhadamente.


NB: É necessário conhecimento da sintaxe do Docker

Dockerfile

O Dockerfile é um modelo para criar um contêiner Docker. Ele contém uma série de instruções que o Docker usa para construir uma imagem, que pode então ser usada para executar contêineres. Vamos detalhar um Dockerfile para um aplicativo Ruby on Rails e React:

. Imagem base

 ARG RUBY_VERSION=3.1.4 FROM ruby:$RUBY_VERSION
  • ARG RUBY_VERSION=3.1.4 : Define um argumento de construção denominado RUBY_VERSION com um valor padrão de 3.1.4 . Isso pode ser substituído no momento da construção.


  • FROM ruby:$RUBY_VERSION : Usa a imagem base ruby com a versão especificada por RUBY_VERSION . Isso configura o contêiner com o tempo de execução Ruby. Assim como mencionei anteriormente, para executar uma aplicação Rails, você precisa ter o Ruby instalado.

2. Instale dependências

 RUN apt-get update -qq && \ apt-get install -y build-essential libvips bash bash-completion libffi-dev tzdata postgresql curl && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* /usr/share/doc /usr/share/man
  • apt-get update -qq : Atualiza a lista de pacotes dos repositórios, com -qq para saída silenciosa.


  • apt-get install -y ... : Instala vários pacotes:
    • build-essential : Pacotes essenciais para construção de software (como GCC).

    • libvips : Biblioteca para processamento de imagens.

    • bash , bash-completion : shell Bash e seu preenchimento automático.

    • libffi-dev : biblioteca de interface de funções estrangeiras.

    • tzdata : dados de fuso horário.

    • postgresql : cliente de banco de dados PostgreSQL.

    • curl : Ferramenta para transferir dados de URLs.


  • apt-get clean : Limpa o repositório local de arquivos de pacotes recuperados.


  • rm -rf /var/lib/apt/lists/ /usr/share/doc /usr/share/man : Remove listas de pacotes e documentação para reduzir o tamanho da imagem.

3. Instale Node.js e Yarn

 RUN curl -fsSL https://deb.nodesource.com/setup_current.x | bash - && \ apt-get install -y nodejs && \ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ apt-get update && \ apt-get install -y yarn
  • curl -fsSL https://deb.nodesource.com/setup_current.x | bash - : baixa e executa o script de configuração do NodeSource para instalar o Node.js.


  • apt-get install -y nodejs : instala o Node.js.


  • curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - : Adiciona a chave Yarn GPG para verificar seus pacotes.


  • echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list : Adiciona o repositório do Yarn à lista de fontes.


  • apt-get update && apt-get install -y yarn : Atualiza a lista de pacotes e instala o Yarn.

4. Variáveis de ambiente

 ENV NODE_OPTIONS=--openssl-legacy-provider
  • ENV NODE_OPTIONS=--openssl-legacy-provider : Define uma variável de ambiente para ativar o suporte OpenSSL legado para Node.js.

5. Definir diretório de trabalho

 WORKDIR /rails
  • WORKDIR /rails : Define o diretório de trabalho para instruções subsequentes para /rails .

6. Construa argumentos e variáveis de ambiente

 ARG RAILS_ENV ENV RAILS_ENV=$RAILS_ENV
  • ARG RAILS_ENV : Define um argumento de construção chamado RAILS_ENV para especificar o ambiente Rails (como development , test , production ).


  • ENV RAILS_ENV=$RAILS_ENV : Define a variável de ambiente RAILS_ENV para o valor do argumento de construção.

7. Instale gemas de aplicativos

 COPY Gemfile Gemfile.lock ./ RUN bundle install
  • COPY Gemfile Gemfile.lock ./ : Copia o Gemfile e Gemfile.lock para o diretório de trabalho.


  • RUN bundle install : Instala gems Ruby especificadas no Gemfile .

8. Instale dependências de front-end

 COPY package.json yarn.lock ./ RUN yarn install --frozen-lockfile
  • COPY package.json yarn.lock ./ : Copia package.json e yarn.lock para o diretório de trabalho.


  • RUN yarn install --frozen-lockfile : Instala dependências de front-end usando Yarn, garantindo que ele use as versões exatas em yarn.lock .

9. Copie o código do aplicativo

 COPY . .
  • COPY . . : Copia todo o código do aplicativo para o diretório de trabalho.

10. Pré-compilar código Bootsnap

 RUN bundle exec bootsnap precompile --gemfile app/ lib/
  • RUN bundle exec bootsnap precompile --gemfile app/ lib/ : pré-compila o cache do Bootsnap para tempos de inicialização mais rápidos do aplicativo Rails. Bootsnap é uma joia que acelera o tempo de inicialização do Ruby e do Rails armazenando em cache cálculos caros.

11. Pré-compilar ativos para produção

 RUN if [ "$RAILS_ENV" = "production" ]; then \ SECRET_KEY_BASE=1 bin/rails assets:precompile; \ fi
  • RUN if [ "$RAILS_ENV" = "production" ]; then ... : executa condicionalmente a pré-compilação do ativo somente se RAILS_ENV estiver definido como production . Esta etapa é crucial para preparar ativos para um ambiente de produção.

12. Script de ponto de entrada

 COPY bin/docker-entrypoint /rails/bin/ RUN chmod +x /rails/bin/docker-entrypoint
  • COPY bin/docker-entrypoint /rails/bin/ : copia um script de ponto de entrada personalizado para o contêiner.


  • RUN chmod +x /rails/bin/docker-entrypoint : Torna o script do ponto de entrada executável.

13. Defina ponto de entrada e comando

 ENTRYPOINT ["/rails/bin/docker-entrypoint"] EXPOSE 5000 // you can use any port of your choice CMD ["./bin/rails", "server"]
  • ENTRYPOINT ["/rails/bin/docker-entrypoint"] : Define o script do ponto de entrada que será executado quando o contêiner for iniciado. Esse script normalmente configura o ambiente, prepara o banco de dados e inicia o aplicativo.


  • EXPOSE 5000 : Indica que o contêiner escuta na porta 5000. Este é um recurso de documentação e não publica a porta.


  • CMD ["./bin/rails", "server"] : Especifica o comando padrão a ser executado quando o contêiner for iniciado, que é iniciar o servidor Rails.

docker-compose.yml

O arquivo docker-compose.yml é usado para definir e executar aplicativos Docker com vários contêineres. Ele permite que você configure os serviços, redes e volumes do seu aplicativo em um único arquivo. Neste caso, usaremos dois serviços. Aqui está o arquivo docker-compose.yml para o aplicativo Rails:

1. Serviço de banco de dados ( db )

 codedb: image: postgres:14.2-alpine container_name: demo-postgres-14.2 volumes: - postgres_data:/var/lib/postgresql/data command: "postgres -c 'max_connections=500'" environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} ports: - "5432:5432"
  • image: postgres:14.2-alpine : especifica a imagem do Docker a ser usada para este serviço. Neste caso, é a imagem PostgreSQL 14.2 baseada na distribuição Alpine Linux. As imagens alpinas são conhecidas por seu tamanho pequeno, o que pode ajudar a manter o tamanho geral da imagem baixo.


  • container_name: demo-postgres-14.2 : Nomeia o contêiner demo-postgres-14.2 . Este nome é usado para fazer referência ao contêiner em comandos e logs.


  • volumes :
    • postgres_data:/var/lib/postgresql/data: Monta um volume nomeado postgres_data em /var/lib/postgresql/data dentro do contêiner. Este diretório é onde o PostgreSQL armazena seus dados, garantindo que os dados do banco de dados persistam entre as reinicializações do contêiner.


  • command: "postgres -c 'max_connections=500'" : Substitui o comando padrão da imagem PostgreSQL. Inicia o PostgreSQL com uma opção de configuração para aumentar o número máximo de conexões para 500.


  • environment :
    • POSTGRES_DB: ${POSTGRES_DB} : Define o nome do banco de dados padrão a ser criado, usando uma variável de ambiente POSTGRES_DB .

    • POSTGRES_USER: ${POSTGRES_USER} : Define o nome de usuário padrão para acessar o banco de dados PostgreSQL, usando a variável de ambiente POSTGRES_USER .

    • POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} : Define a senha para o usuário padrão, usando a variável de ambiente POSTGRES_PASSWORD .


  • ports :
    • "5432:5432" : mapeia a porta 5432 no host para a porta 5432 no contêiner. Isto permite o acesso ao PostgreSQL na máquina host através da porta 5432.

2. Serviço de aplicação web ( demo-web )

 codedemo-web: build: context: . args: - RAILS_ENV=${RAILS_ENV} command: "./bin/rails server -b 0.0.0.0" environment: - RAILS_ENV=${RAILS_ENV} - POSTGRES_HOST=${POSTGRES_HOST} - POSTGRES_DB=${POSTGRES_DB} - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - RAILS_MASTER_KEY=${RAILS_MASTER_KEY} volumes: - .:/rails - app-storage:/rails/storage depends_on: - db ports: - "3000:3000"
  • build:

    • context: . : especifica o contexto de construção da imagem Docker. Nesse caso, . refere-se ao diretório atual. Isso significa que o Docker usará o Dockerfile no diretório atual para construir a imagem.
    • args :
      • RAILS_ENV=${RAILS_ENV} : passa o argumento de construção RAILS_ENV para o processo de construção do Docker, permitindo que você especifique o ambiente Rails (como development , test ou production ).


  • command: "./bin/rails server -b 0.0.0.0" : substitui o comando padrão da imagem Docker. Inicia o servidor Rails e vincula-o a todas as interfaces de rede ( 0.0.0.0 ), o que é necessário para que o serviço seja acessível de fora do contêiner.


  • environment:

    • RAILS_ENV=${RAILS_ENV} : Define o ambiente Rails dentro do contêiner usando a variável de ambiente RAILS_ENV .

    • POSTGRES_HOST=${POSTGRES_HOST} : Define o endereço do host PostgreSQL.

    • POSTGRES_DB=${POSTGRES_DB} : Define o nome do banco de dados.

    • POSTGRES_USER=${POSTGRES_USER} : Define o usuário do PostgreSQL.

    • POSTGRES_PASSWORD=${POSTGRES_PASSWORD} : Define a senha do usuário PostgreSQL.

    • RAILS_MASTER_KEY=${RAILS_MASTER_KEY} : Define a chave mestra Rails, que é usada para criptografar credenciais e outros segredos.


  • volumes :

    • .:/rails : monta o diretório atual (onde o arquivo docker-compose.yml está localizado) em /rails dentro do contêiner. Isso permite que você edite arquivos em seu host e tenha essas alterações refletidas dentro do contêiner.

    • app-storage:/rails/storage : monta um volume nomeado app-storage em /rails/storage dentro do contêiner. Isso normalmente é usado para armazenar arquivos específicos do Rails, como logs, uploads e arquivos em cache.


  • depends_on :

    • db : garante que o serviço demo-web aguarde até que o serviço db esteja pronto antes de iniciar. Docker Compose lida com a ordem de início dos serviços com base nesta configuração.
  • ports:

    • "3000:3000" : mapeia a porta 3000 no host para a porta 3000 no contêiner. Isso permite que você acesse o aplicativo Rails na máquina host através da porta 3000.

    Volumes

     codevolumes: postgres_data: app-storage:
    • postgres_data : define um volume nomeado postgres_data usado pelo serviço db para persistir dados do PostgreSQL.
    • app-storage : define um volume nomeado app-storage usado pelo serviço demo-web para persistir dados específicos do aplicativo, como uploads e logs.

bin/docker-ponto de entrada

O script bin/docker-entrypoint é uma parte crucial da configuração do Docker. Ele é executado quando o contêiner é iniciado e normalmente lida com a configuração do ambiente, a preparação do banco de dados e outras tarefas de inicialização necessárias antes de iniciar o aplicativo principal. Aqui está um exemplo de script bin/docker-entrypoint e uma explicação detalhada de cada parte:

Shebang e saída em caso de erro

 bashCopy code#!/bin/bash set -e
  • #!/bin/bash : Esta linha especifica que o script deve ser executado usando o shell Bash.


  • set -e : instrui o script a sair imediatamente se algum comando retornar um código de saída diferente de zero. Isso ajuda a garantir que, se alguma etapa falhar, o script interromperá a execução, o que pode impedir que etapas subsequentes sejam executadas em um estado inválido.


Criação ou migração condicional de banco de dados

 # If running the rails server then create or migrate existing database if [ "${*}" == "./bin/rails server" ]; then ./bin/rails db:create ./bin/rails db:prepare fi


  • if [ "${*}" == "./bin/rails servidor"]; then ... fi : Esta instrução condicional verifica se o comando passado para o script ( "${*}" ) é ./bin/rails server . O * é um parâmetro especial que contém todos os parâmetros posicionais passados ao script.


  • ./bin/rails banco de dados

    : Se a condição for atendida, este comando tentará criar o banco de dados. É equivalente a executar rails db:create que configura o banco de dados conforme definido no arquivo de configuração do banco de dados ( config/database.yml ).


  • ./bin/rails banco de dados

    : Este comando executará rails db:prepare , o que garante que o banco de dados seja configurado e migrado. Ele criará o banco de dados se ele não existir e executará migrações se o banco de dados já estiver criado. Esta é uma combinação de rails db:create e rails db:migrate .

    Executando o Processo Principal

     bashCopy codeexec "${@}"
    • exec "${@}" : substitui o processo shell atual pelo comando passado como argumentos para o script. O símbolo @ contém todos os parâmetros posicionais passados para o script. Por exemplo, se o script for chamado com ./bin/rails server , esta linha efetivamente executa ./bin/rails server como o processo principal do contêiner.

Conclusão

Um Dockerfile bem elaborado é essencial para criar um ambiente confiável e consistente para sua aplicação Ruby on Rails e React. Ao definir a imagem base, definir variáveis de ambiente e instalar dependências, você garante que seu aplicativo seja executado sem problemas em vários ambientes.


O Docker não apenas agiliza seu processo de desenvolvimento, mas também aumenta a confiabilidade de seu aplicativo em produção. Existem áreas de otimizações, mas esta é apenas uma visão geral de como dockerizar a aplicação Rails.

Script completo para o Dockerfile resultante, docker-compose.yml e bin/docker-entrypoint

 ARG RUBY_VERSION=3.1.4 FROM ruby:$RUBY_VERSION # Install dependencies RUN apt-get update -qq && \ apt-get install -y build-essential libvips bash bash-completion libffi-dev tzdata postgresql curl && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* /usr/share/doc /usr/share/man # Install Node.js and Yarn RUN curl -fsSL https://deb.nodesource.com/setup_current.x | bash - && \ apt-get install -y nodejs && \ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ apt-get update && \ apt-get install -y yarn # Set environment variable to enable legacy OpenSSL support ENV NODE_OPTIONS=--openssl-legacy-provider # Rails app lives here WORKDIR /rails # Set environment variable for the build ARG RAILS_ENV ENV RAILS_ENV=$RAILS_ENV # Install application gems COPY Gemfile Gemfile.lock ./ RUN bundle install # Install frontend dependencies COPY package.json yarn.lock ./ RUN yarn install --frozen-lockfile # Copy application code COPY . . # Precompile bootsnap code for faster boot times RUN bundle exec bootsnap precompile --gemfile app/ lib/ # Precompiling assets for production without requiring secret RAILS_MASTER_KEY RUN if [ "$RAILS_ENV" = "production" ]; then \ SECRET_KEY_BASE=1 bin/rails assets:precompile; \ fi # Entrypoint prepares the database. COPY bin/docker-entrypoint /rails/bin/ RUN chmod +x /rails/bin/docker-entrypoint # Use an absolute path for the entry point script ENTRYPOINT ["/rails/bin/docker-entrypoint"] # Start the server by default, this can be overwritten at runtime EXPOSE 5000 CMD ["./bin/rails", "server"]


 services: db: image: postgres:14.2-alpine container_name: demo-postgres-14.2 volumes: - postgres_data:/var/lib/postgresql/data command: "postgres -c 'max_connections=500'" environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} ports: - "5432:5432" demo-web: build: context: . args: - RAILS_ENV=${RAILS_ENV} command: "./bin/rails server -b 0.0.0.0" environment: - RAILS_ENV=${RAILS_ENV} - POSTGRES_HOST=${POSTGRES_HOST} - POSTGRES_DB=${POSTGRES_DB} - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - RAILS_MASTER_KEY=${RAILS_MASTER_KEY} volumes: - .:/rails - app-storage:/rails/storage depends_on: - db ports: - "3000:3000" volumes: postgres_data: app-storage:



 #!/bin/bash set -e # If running the rails server then create or migrate existing database if [ "${*}" == "./bin/rails server" ]; then ./bin/rails db:create ./bin/rails db:prepare fi exec "${@}"