![Search icon](https://hackernoon.imgix.net/search-new.png?w=19&h=19)
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.
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.
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.
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.
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
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:
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. 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. 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. 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. WORKDIR /rails
WORKDIR /rails
: Define o diretório de trabalho para instruções subsequentes para /rails
. 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. 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
. 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
. COPY . .
COPY . .
: Copia todo o código do aplicativo para o diretório de trabalho. 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. 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. 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. 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. 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:
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.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. 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. 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:
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
"${*}"
) é ./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
.
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. 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.
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 "${@}"