
Dockerizando uma aplicação ruby on rails com postgresql, redis e vue.js
Criei uma aplicação Ruby on Rails diretamente pelo docker e docker-compose com PostgreSQL, Redis e Vue.js.
Criaremos uma aplicação Ruby on Rails a partir do docker e docker-compose com PostgreSQL, Redis e Vue.js.
O que é Docker?
De forma resumida, o Docker é uma plataforma de código aberto, desenvolvido na linguagem Go e criada pelo próprio Docker.Inc. Por ser de alto desempenho, o software garante maior facilidade na criação e administração de ambientes isolados, garantindo a rápida disponibilização de programas para o usuário final.
O que é Docker Compose?
Docker Compose é o orquestrador de containers da Docker. E como funciona um orquestrador em uma orquestra? Ele rege como uma banda deve se comportar/tocar durante uma determinada apresentação ou música.
Veja como instalar os dois nesses links:
https://docs.docker.com/engine/install/
https://docs.docker.com/compose/install/
Com tudo instalado vamos criar dois arquivos Dockerfile e docker-compose.yml
Crie um arquivo Dockerfile
O primeiro passo é criar um Dockerfile em algum diretório. Para esta construção, estarei usando ruby:2.7.2-alpine imagem. Alpine é uma imagem docker do Linux muito mais limpa e reduzirá nossos tamanhos gerais de imagens.
mkdir code-docker
cd code-docker
touch Dockerfile
Adicione em Dockerfile o seguinte conteúdo:
FROM ruby:2.7.2-alpine
LABEL maintainer="[email protected]"
ENV RAILS_ENV development
ENV RAILS_SERVE_STATIC_FILES true
ENV RAILS_LOG_TO_STDOUT true
ENV APP_HOME /app
ENV BUNDLE_APP_CONFIG="$APP_HOME/.bundle"
RUN apk add --update --no-cache \
binutils-gold \
bash \
build-base \
busybox \
ca-certificates \
curl \
file \
g++ \
gcc \
git \
gnupg1 \
graphicsmagick \
less \
libstdc++ \
libffi-dev \
libc-dev \
linux-headers \
libxml2-dev \
libxslt-dev \
libgcrypt-dev \
libffi-dev \
libsodium-dev \
make \
netcat-openbsd \
nodejs \
openssl \
pkgconfig \
postgresql-dev \
tzdata \
openssh-client \
rsync \
yaml-dev \
sqlite-dev \
ruby-dev \
zlib-dev \
yarn
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
COPY Gemfile Gemfile.lock ./
RUN gem install bundler -v 2.0.2
RUN bundle config
RUN bundle config frozen false
RUN echo 'gem: --no-ri --no-rdoc' > ~/.gemrc
#RUN bundle config --local build.sassc --disable-march-tune-native
#RUN bundle config build.nokogiri --use-system-libraries
#RUN bundle check || bundle install
RUN gem install rails
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
COPY Gemfile Gemfile.lock ./
RUN bundle config build.nokogiri --use-system-libraries
RUN bundle check || bundle install
#COPY package.json yarn.lock ./
#RUN yarn install --check-files
COPY . $APP_HOME
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["bash","entrypoint.sh"]
EXPOSE 3000
# Start the main process.
CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]
Crie um arquivo docker-compose.yml
Em seguida, crie um docker-compose.yml arquivo no diretório raiz do seu projeto. Para descobrir qual versão você pode definir na parte superior de seu arquivo, verifique docker -v e compare com a referência de versão aqui.
touch docker-compose.yml
Adicione ao arquivo docker-compose.yml recém criado o seguinte conteúdo:
version: "3.7"
services:
app:
build:
context: .
env_file:
- rails.env
volumes:
- .:/app
- gem_cache:/usr/local/bundle/gems
- node_modules:/app/node_modules
environment:
DB_HOST: db
RAILS_MAX_THREADS: 5
PORT: 3000
ports:
- 3000:3000
restart: always
depends_on:
- "db"
db:
image: postgres:13-alpine
env_file:
- db.env
environment:
POSTGRES_HOST_AUTH_METHOD: trust
POSTGRES_PASSWORD: your_db_password
PGDATA: /var/lib/postgresql/data/pgdata
restart: always
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:6.0.8-alpine
volumes:
pgdata:
gem_cache:
node_modules:
Eu configurei app (Ruby on Rails) aplicativo e o db (PostgreSQL) para sempre reiniciar com restart: always. Se o contêiner travar ou você reiniciar o servidor, esses serviços serão iniciados automaticamente.
O aplicativo Rails depende do banco de dados estar funcionando, nós definimos isso com a depends on: - db linha.Também estamos criando um pgdata volume para que os dados do banco de dados sejam persistentes.
Observe que estamos usando um env_file: para definir algumas variáveis de ambiente, bem como environment: para outras variáveis. Você pode escolher quais variáveis deseja confirmar em seu sistema de controle de versão e quais não deseja confirmar.
Crie os arquivos .env
Agora vamos criar rails.enve db.env você pode nomear os arquivos com qualquer coisa, desde que eles correspondam à configuração em seu docker-compose.yml arquivo.
O rails.env arquivo:
DB_PASSWORD=my_password
SECRET_KEY_BASE=rails_secret_key # generate this with 'rails secret' # docker-compose run --rm app bundle exec rails secret
O db.env arquivo:
POSTGRES_PASSWORD=my_password
Adicione os arquivos .env ao seu .gitignore
Não queremos confirmar nossas chaves secretas para um sistema de controle de versão, portanto, adicione o seguinte ao seu .gitignore arquivo:
# Ignore environment files
*.env
Crie um arquivo .dockerignore
Ao copiar nossos arquivos para o docker contêiner, não queremos pastas como node_modules a serem copiadas. Além disso, não queremos que nenhum arquivo com informações confidenciais, como .env ou nosso, master.key seja copiado para o contêiner.
Você pode usar o arquivo abaixo como exemplo:
# Ignore bundler config.
.bundle
# Ignore all logfiles and tempfiles.
log/
tmp/
# Ignore uploaded files in development.
storage/
public/assets
# Byebug history
.byebug_history
# Ignore master key for decrypting credentials and more.
config/master.key
# Node modules, yarn etc.
public/packs
public/packs-test
node_modules
yarn-error.log
yarn-debug.log*
.yarn-integrity
# Ignore environment files
*.env
# Ignore database dumps
*.dump
# Misc files
.dockerignore
.git
.cache
Crie um arquivo de ponto de entrada
Crie um entrypoint.sh arquivo no diretório raiz do projeto:
#!/bin/bash
# Note: !/bin/sh must be at the top of the line,
# Alpine doesn't have bash so we need to use shell.
# Docker entrypoint script.
# Don't forget to give this file execution rights via `chmod +x entrypoint.sh`
# which I've added to the Dockerfile but you could do this manually instead.
# Wait until Postgres is ready before running the next step.
while ! pg_isready -q -h $DB_HOST -p $DB_PORT -U $DB_USERNAME
do
echo "$(date) - waiting for database to start."
sleep 2
done
# If the database exists, migrate. Otherwise setup (create and migrate)
echo "Running database migrations..."
bundle exec rails db:migrate 2>/dev/null || bundle exec rails db:create db:migrate
echo "Finished running database migrations."
# Remove a potentially pre-existing server.pid for Rails.
echo "Deleting server.pid file..."
set -e
# Remove a potentially pre-existing server.pid for Rails.
if [ -f /app/tmp/pids/server.pid ]; then
rm /app/tmp/pids/server.pid
fi
# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
Embora tenhamos definido depends_on: - db em nosso docker-compose.yml arquivo, isso só espera que o contêiner PostgreSQL seja executado, no entanto, o banco de dados ainda estará inicializando e não queremos tentar executar nenhuma migração etc. até que esteja pronto para aceitar conexões daí a while ! pg_isready linha.
Criando a aplicação Ruby on Rails com Docker
Até agora só configuramos arquivos do docker mais a aplicação ROR ainda não existe.
Iremos criar agora depois da montagem das imagens.
No terminal execute o comando, isso vai baixar todas as images que definimos nos dois arquivos.
docker-compose build
Apos a execução do comando temos Ruby 2.7.2, PostgreSQL 13, Redis, Nodejs e Yarn tudo que precisamos para cria uma aplicação rails.
Então vamos lar:
docker-compose run --rm app rails new ./ -d postgresql --webpack=vue
Agora o docker irá criar nosso app rails sem tem ruby e nem rails instalado na maquina local. Se você já estive ruby instalado anteriormente não haverá nenhum conflito.
Caso prefira definir um nome ao app rails, isso pode ser feito alterando o comando acima.
docker-compose run --rm app rails new rails-docker -d postgresql --webpack=vue
Para evitar problema de permissão no projeto execute o comando o terminal.
sudo chown -R $USER:$USER .
Depois de aguardar o fim do processo criaremos o banco de dados do app e inicializaremos a aplicação:
Altere o arquivo config/database.yml recém criado pelo docker por algo assim:
# PostgreSQL. Versions 9.3 and up are supported.
#
# Install the pg driver:
# gem install pg
# On macOS with Homebrew:
# gem install pg -- --with-pg-config=/usr/local/bin/pg_config
# On macOS with MacPorts:
# gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config
# On Windows:
# gem install pg
# Choose the win32 build.
# Install PostgreSQL and put its /bin directory on your path.
#
# Configure Using Gemfile
# gem 'pg'
#
default: &default
adapter: postgresql
encoding: unicode
username: <%= ENV.fetch("DB_USERNAME") { "postgres" } %>
password: <%= ENV.fetch('DB_PASSWORD') %>
host: <%= ENV.fetch('DB_HOST') || 'localhost'%>
port: <%= ENV.fetch('DB_PORT') || '5432'%>
# For details on connection pooling, see Rails configuration guide
# https://guides.rubyonrails.org/configuring.html#database-pooling
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
development:
<<: *default
database: app_development
# The specified database role being used to connect to postgres.
# To create additional roles in postgres see `$ createuser --help`.
# When left blank, postgres will use the default role. This is
# the same name as the operating system user that initialized the database.
#username: app
# The password associated with the postgres role (username).
#password:
# Connect on a TCP socket. Omitted by default since the client uses a
# domain socket that doesn't need configuration. Windows does not have
# domain sockets, so uncomment these lines.
#host: localhost
# The TCP port the server listens on. Defaults to 5432.
# If your server runs on a different port number, change accordingly.
#port: 5432
# Schema search path. The server defaults to $user,public
#schema_search_path: myapp,sharedapp,public
# Minimum log levels, in increasing order:
# debug5, debug4, debug3, debug2, debug1,
# log, notice, warning, error, fatal, and panic
# Defaults to warning.
#min_messages: notice
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
<<: *default
database: app_test
# As with config/credentials.yml, you never want to store sensitive information,
# like your database password, in your source code. If your source code is
# ever seen by anyone, they now have access to your database.
#
# Instead, provide the password as a unix environment variable when you boot
# the app. Read https://guides.rubyonrails.org/configuring.html#configuring-a-database
# for a full rundown on how to provide these environment variables in a
# production deployment.
#
# On Heroku and other platform providers, you may have a full connection URL
# available as an environment variable. For example:
#
# DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase"
#
# You can use this database configuration with:
#
# production:
# url: <%= ENV['DATABASE_URL'] %>
#
production:
<<: *default
# database: app_production
database: <%= ENV['DB_DATABASE'] %>
username: <%= ENV['DB_USERNAME'] %>
password: <%= ENV['DB_PASSWORD'] %>
host: <%= ENV['DB_HOST'] %>
Agora podemos criar o banco de dados e executar as migrations.
docker-compose run --rm app bundle exec rails db:create db:migrate
Inicializando a aplicação com docker e docker-compose:
docker-compose up
Pronto tudo funcionando.
http://localhost:3000
Outros comando docker e docker-compose
docker-compose ps
docker-compose stop
docker-compose down
docker-compose up --build
docker-compose run --rm app rails db:create
docker-compose run --rm app rails db:setup db:migrate
docker-compose run --rm app rails db:migrate
docker-compose run --rm app rails console
docker-compose run --rm app bash
docker-compose run --rm app bundle install
docker-compose run --rm app yarn install --check-files
Espero ter ajudado alguém.
Github do projeto:
https://github.com/gilcierweb/rails-docker
Fontes:
https://danielwachtel.com/rails/dockerizing-ruby-on-rails-app-with-postgresql-database
https://lipanski.com/posts/dockerfile-ruby-best-practices
https://firehydrant.io/blog/developing-a-ruby-on-rails-app-with-docker-compose/