12/08/2018, 15:45

Xây dựng môi trường cho ứng dụng Ruby on Rails với Docker, Docker-Compose

Tất nhiên để dùng Docker và Docker-Compose trước tiên chúng ta phải cài đặt chúng rồi. Thông tin cách thức chi tiết bạn có thể xem tại đây cho Docker , Docker-compose Nếu bạn mới làm quen hoặc chưa biết về docker bạn có thể ghé qua đây Tạo file docker: touch Dockerfile Nội dung hoàn ...

Tất nhiên để dùng Docker và Docker-Compose trước tiên chúng ta phải cài đặt chúng rồi. Thông tin cách thức chi tiết bạn có thể xem tại đây cho Docker , Docker-compose

Nếu bạn mới làm quen hoặc chưa biết về docker bạn có thể ghé qua đây

Tạo file docker:

touch Dockerfile Nội dung hoàn chỉnh của file (mình sẽ chỉ rõ ý nghĩa của từng line phía dưới):

FROM ruby
RUN apt-get update -qq && apt-get install -y build-essential nodejs
RUN mkdir /rails-app
WORKDIR /rails-app
ADD Gemfile /rails-app/Gemfile
ADD Gemfile.lock /rails-app/Gemfile.lock
RUN bundle install
ADD . /rails-app

FROM để chỉ định image mà chúng ta sẽ sử dụng, tất nhiên bạn có thể bắt đầu từ image ubuntu và tự mình install những gì bạn cần nhưng thường thì tất cả những gì chúng ta cần đều đã có sẵng nên, cứ lười biến dùng lại là ok rồi. Ở đây mình sử dụng image cho ruby là latest version bạn có thể quyết định version sử dụng image có version nào bằng cách

// thay
FROM ruby
// thành
FROM ruby:2.x.x

Vì mình chỉ chọn dùng image ruby only mà không dùng image bao gồm rails vì để có thể thỏa mái lựa chọn rails version vào ruby version nên trong Dockerfile mình phải install nodejs qua line:

RUN apt-get update -qq && apt-get install -y build-essential nodejs

Tạo vài chỉ định thư mục làm việc của dự án trong docker container, với tên là rails-app thực sự thì bạn cũng sẽ không cần quan tâm lắm đến tên này,

RUN mkdir /rails-app
WORKDIR /rails-app

add 2 file cơ bản để init cho 1 ứng dụng rails tử thư mục chức src của dự án vào container:

ADD Gemfile /rails-app/Gemfile
ADD Gemfile.lock /rails-app/Gemfile.lock

Mình mới chỉ ADD 2 file này mà không hề tạo như folder rails-app nên chúng ta cần tạo 2 file này:

touch Gemfile Gemfile.lock Ở đây tại sao mình lại tạo 2 file này tại máy mà không dùng 1 line tương tự như :

RUN touch /rails-app/Gemfile  /rails-app/Gemfile.lock

hoặc

RUN touch Gemfile  Gemfile.lock

Nếu bạn tạo 2 file này trong container thì nó sẽ bị ẩn đi và thứ 2 là nó sẽ được tạo với quyền root dẫn đến khó khăn trong việc change 2 file này. init rails Giờ thì init rails nào: ./Gemfile

source 'https://rubygems.org'
gem 'rails', '5.0.0.1'

Làm việc với Gemfile có lẽ đã quá quen thuộc nên mình sẽ để đây và không nói gì thêm.

Bây h thì hoàng thành việc init cho rails với command:

rails new . --force --database=mysql --skip-bundle

Mình chỉ mới tạo file docker cho ruby và init cho rails vậy thì h chúng ta cần khởi tạo các container khác như mysql. Để giới thiệu 1 cách dài dòng hơn mình sẽ tạo container cho cả redis và sidekiq, và nếu bạn cần dùng sidekiq với redis thì thêm vào Gemfile:

gem 'sidekiq'
gem 'sinatra', require: false

Tạo file docker-compose.yml Như đã nói, tất cả những image chúng ta cần đều đã được tạo sẵng rồi nên chỉ việc dùng lại thôi, nội dung docker-compose.yml:

version: '2'
services:
  db:
    image: mysql
    ports:
      - "3307:3307"
    environment:
      MYSQL_ROOT_PASSWORD: 123123
      MYSQL_USER: root
      MYSQL_PASSWORD: 123123
      MYSQL_DATABASE: 123123
  redis:
    image: redis
    environment:
      - REDIS_URL=redis://redis:6379
  sidekiq:
    build: .
    volumes:
      - .:/rails-app
    links:
      - db
      - redis
    command: bundle exec sidekiq
    environment:
      - REDIS_URL=redis://redis:6379

  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/rails-app
    ports:
      - "3000:3000"
    depends_on:
      - db
    stdin_open: true
    tty: true

Để có thể debug thì bạn cần 2 line:

    stdin_open: true
    tty: true

Config cho database

config/database.yml

default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: root
  password: 123123
  host: db

development:
  <<: *default
  database: my_app

Bây h đề pull các image mà chúng ta xử dụng và hoàn thành việc init với command:

docker-compose build

Run

docker-compose up

Tạo database:

docker-compose run web rails db:create

Ứng dụng của bạn đã sẵng sàng để phát triển.

TIP Nếu bạn là người phát triển ứng dụng, bạn bên bundle ứng dụng ngay tại thư mục thực tế:

bundle install

và chạy các lệnh greanate ngay tại đây để không mắc các vấn đề về khả năng truy cập của file được tạo. ví dụ: tạo 1model User thì nên:

rails g model User name:string

thay vì:

docker-compose run web rails g model User name:string

Còn nếu bạn là chỉ muốn run ứng dụng mà không quan tâm việc greanate thêm 1 thành phần nào của nó thì bundle là việc không cần thiết.

Việc sử dụng lâu dài đôi khi sẽ phát sinh lỗi khi đang chạy hay vì vấn đề nào đó mà bạn cần rebuild lại các container, để xóa nhanh tất cả các container hiện tại:

docker rm -f $$docker ps -a -q)

Khi bạn thực hiện việc rebuild thì thường sẽ bắt gặp lỗi không thể start rails server, đây là vì bạn thay đổi container và các file temp tạo với quyền root của container trước đó không cho phép bạn access. Bạn cần remove nó đi, cụ thể là 2 folder tmp và log

sudo chmod -R 777 tmp log rm -rf tmp log

Để debug thì bạn có thể dùng lệnh

docker attach [container-name/container-id]

nếu console có log tương tự như

Started GET "/assets/home-fcec5b5a277ac7c20cc9f45a209a3bcd.js?body=1" for 10.0.2.2 at 2015-04-02 15:48:31 +0000
Cannot render console from 10.0.2.2! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255

cùng với đó bạn cần thêm vào config:

config.web_console.whitelisted_ips = '10.0.2.2' Đẹp hơn thì bạn đên đặt cho nó 1 env để mọi người trong team có thể config lại theo ip từng người config.web_console.whitelisted_ips = ENV["CONSOLE_IP"]

Kiểm tra các images hiện tại:

docker images

Xem các container:

  • Đang chạy

docker ps

  • Tất cả;

docker ps -a

0