Na primeira parte nós montamos um Dockerfile com as dependências do nosso projeto para criar uma imagem que nos forneça o suficiente para rodar essa aplicação Rails.
FROM ruby:2.7.0
ENV NODE_VERSION 12
ENV INSTALL_PATH /opt/app
RUN curl -sL https://deb.nodesource.com/setup_$NODE_VERSION.x | bash -
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update -qq
RUN apt-get install -y --no-install-recommends nodejs postgresql-client \
locales yarn
RUN echo "en_US.UTF-8 UTF-8" > /etc/locale.gen
RUN locale-gen
RUN export LC_ALL="en_US.utf8"
RUN mkdir -p $INSTALL_PATH
WORKDIR $INSTALL_PATH
COPY Gemfile Gemfile
COPY Gemfile.lock Gemfile.lock
RUN gem install bundler
RUN bundle install
COPY . $INSTALL_PATH
Com essa imagem montada, podemos começar a pensar na estrutura do projeto. Até aqui o nosso banco de dados não está funcionando simplesmente porque não está instalado nesse contêiner. Levando em consideração a estrutura de aplicações Web modernas, é bastante comum que aplicação e banco de dados sejam hospedados em máquinas diferentes.
Então vamos montar uma estrutura parecida por meio de contêineres. Isso também dá a liberdade de estender essa estrutura para facilmente colocar um Redis ou outras opções de ferramentas no seu projeto. Pensando nisso, o pessoal da Docker criou o docker-compose
, que facilita a integração de contêineres. Onde antes iríamos subir dois contêineres, criar uma conexão entre os dois, exportar portas, etc. agora é uma questão de criar um único arquivo de configuração.
No diretório raiz do nosso projeto, vamos criar o arquivo docker-compose.yml
, que faz a ponte entre o banco de dados e a aplicação pra gente.
Se você usa Mac ou Windows, a instalação do Docker Desktop já vem com o compose. Em sistemas Linux ele é instalado separadamente, você pode ler mais aqui.
version: '3'
services:
rails:
build: .
command: rails s -b 0.0.0.0
container_name: meu_projeto_rails
ports:
- 3000:3000
volumes:
- .:/opt/app
Com esse arquivo criado, podemos executar o comando docker-compose run --service-ports rails bash
para subir um contêiner com o nosso projeto. Se você já teve que passar pelo processo de subir duas máquinas e conectá-las, percebeu como o docker-compose
tornou tudo muito mais fácil.
O arquivo de configuração define o local onde o contêiner irá buscar a imagem para ser construída (build
), nesse caso é a pasta corrente definida pelo .
. O Docker busca o arquivo Dockerfile
na mesma pasta em que se encontra o docker-compose
. A opção --service-ports
garante a comunicação da porta 3000 da nossa máquina com a porta 3000 do contêiner. Além disso, como o volume já foi definido nesse arquivo não precisamos mais nos preocupar com isso. Então basta rodar o serviço com o nome que declaramos (no caso, rails
) executando o bash
.
Feito isso e garantindo que tudo está funcionando, podemos sair do nosso contêiner com o comando exit
e começar a configurar o banco de dados.
No docker-compose.yml
nós podemos declarar um segundo serviço que será responsável pelo banco de dados. Neste caso chamamos de db
.
version: '3'
services:
rails:
build: .
command: rails s -b 0.0.0.0
container_name: meu_projeto_rails
ports:
- 3000:3000
volumes:
- .:/opt/app
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_HOST=db
depends_on:
- db
db:
image: postgres:12-alpine
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
volumes:
- meu_projeto_rails_data:/var/lib/postgresql/data
volumes:
meu_projeto_rails_data:
Declaramos o serviço de banco de dados (db
) com algumas variáveis de ambiente importantes (você pode ler mais sobre outras opções para fazer isto aqui). Além disso, fizemos um link, de forma que ao criarmos um contêiner com o serviço rails
, um contêiner com o serviço db
deve ser criado automaticamente. Configuramos também as mesmas variáveis nesse serviço com um adicional, que é o nome do serviço que está hospedando o banco de dados, nesse caso, db
.
Caso você faça modificações no
Dockerfile
é importante atualizar o cache com umdocker-compose build
.
Quando executarmos docker-compose run --service-ports rails bash
, o script irá reconhecer que deve subir um segundo contêiner com um banco de dados usando a imagem do postgres disponível no Docker Hub.
Mas para fazer tudo funcionar temos que usar o arquivo config/database.yml
da nossa aplicação Rails para usar as variáveis de ambiente que declaramos com a senha e host do banco.
O arquivo tem muitas linhas, mas parte importante é troca do default
incluindo o usuário, senha e host do banco.
default: &default
adapter: postgresql
encoding: unicode
# For details on connection pooling, see Rails configuration guide
# https://guides.rubyonrails.org/configuring.html#database-pooling
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: <%= ENV.fetch("POSTGRES_USER") %>
password: <%= ENV.fetch("POSTGRES_PASSWORD") %>
host: <%= ENV.fetch("POSTGRES_HOST") %>
Assim, temos o nosso banco funcionando num outro contêiner e de forma extensível para inclusão de um Redis, camada de cache, entre outras coisas necessárias ao nosso ambiente de desenvolvimento.
Projeto rodando com docker-compose run --service-ports rails bash
, fazer um bin/setup
, e rails server --binding 0.0.0.0
, bora codar!?