Xây dựng hệ thống Ruby on Rails trên môi trường Docker

Docker có lẽ chính là từ khóa hot nhất trong thời gian gần đây. Nó là một môi trường mở, cung cấp cho lập trình viên những công cụ, service để đóng gói và chạy chương trình của mình trên các môi trường khác nhau một cách nhanh nhất. Hôm nay tôi và các bạn sẽ cùng tìm hiểu cách triển khai ứng dụng rails app trên môi trường này nhé.

Để bắt đầu tìm hiểu việc config Docker, trước tiên bạn hãy tạo cho mình một ứng dụng rails đơn giản. VD:

$ rails new demo_docker

Nào bây giờ chúng ta sẽ cùng tìm hiểu cách xây dựng môi trường Docker nhé.

Installing Docker

Nếu trên máy bạn đã cài đặt Docker bạn có thể chuyển qua bước tiếp theo để triển khai docker trên rails app. Nếu chưa, bạn có thể làm theo hướng dẫn sau đây:

Cài đặt Docker

update apt package index

$ sudo apt-get update

install packages cho phép apt sử dụng một repo thông qua HTPS

$ sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common

Thêm Docker’s official GPG key

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

Hãy kiểm tra lại để chắc chắn rằng bạn vừa có key với fingureprint 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88 bằng cách tìm kiếm 8 ký tự cuối của fingureprint này với câu lệnh như sau:

$ sudo apt-key fingerprint 0EBFCD88

/etc/apt/trusted.gpg
--------------------
pub   4096R/0EBFCD88 2017-02-22
      Key fingerprint = 9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid                  Docker Release (CE deb) <[email protected]>
sub   4096R/F273FCD8 2017-02-22

Sử dụng câu lệnh sau để thiết lập stable repository. Bạn sẽ luôn cần một kho lưu trữ ổn định ngay cả khi bạn cài đặt cản bản được built từ các kho lưu trữ thử nghiệm. amd64

$ sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

cài đặt docker-ce bản mới nhất hoặc bạn cũng có thể cài docker-ce với version nào đó bạn mong muốn. Bản Docker được cài đặt trước đó sẽ bị thay thế

$ sudo apt-get install docker-ce

hoặc

$ sudo apt-get install docker-ce=<VERSION>

Và để chắc chắn bạn đã cài đặt Docker thành công, hãy chạy thử hello-world image

$ sudo docker run hello-world

command này sẽ download một test image và chạy nó trên một container.

Cài đặt docker-compose

Vẫn chưa xong đâu nhé. Bạn vẫn cần phải cài đặt docker-compose đó là một công cụ dùng để định nghĩa và chạy multi-container Docker app. Việc config các thông số thiết lập cho app của bạn trong compose file sẽ giúp bạn đơn giản hóa việc chạy chúng bằng cách chỉ dùng một câu lệnh 😉

chạy câu lệnh sau để download lastest version của docker-compose

$ sudo curl -L https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

apply permission

$ sudo chmod +x /usr/local/bin/docker-compose

Kiểm tra version docker-compose đã cài đặt

$ docker-compose --version

Vậy là đã xong

Dockerizing a Rails Application

Bây giờ chúng ta đã cài đặt xong Docker và chạy được nó trên máy tính, việc tiếp theo chúng ta cần làm là làm sao để rails app có thể hoạt động trên môi trường này. Docker được configure thông qua Dockerfile - Nơi bạn sẽ cần viết các định nghĩa cách build các container. Dockerfile bắt đầu bằng một dòng đơn, định nghĩa base image sẽ được sử dụng. Có rất nhiều base image, bạn có thể search những image phù hợp trên Docker Hub. Trong ví dú dưới đây, tôi sẽ sử dụng base image là ruby:2.4.0-alpine

FROM ruby:2.4.0-alpine

ENV APP_ROOT /app 

# Configure the main working directory. This is the base 
# directory used in any further RUN, COPY, and ENTRYPOINT 
# commands.

RUN mkdir -p $APP_ROOT
WORKDIR $APP_ROOT

# Expose port 3000 to the Docker host, so we can access it 
# from the outside.
EXPOSE 3000

# Install apt based dependencies required to run Rails as 
# well as RubyGems. As the Ruby image itself is based on a 
# Debian image, we use apt-get to install those.
RUN apk update && \
    apk upgrade && \
    apk add --update --virtual build-dependencies \
    git \
    bash curl-dev ruby-dev build-base\
    zlib-dev libxml2-dev libxslt-dev tzdata yaml-dev mysql-dev \
    ruby-json yaml nodejs \
    linux-headers && \
    rm -rf /var/cache/apk/*
  
# Copy the Gemfile as well as the Gemfile.lock and install 
# the RubyGems. This is a separate step so the dependencies 
# will be cached unless changes to one of those two files 
# are made.
COPY Gemfile Gemfile.lock ./ 
RUN gem install bundler && \
    bundle config build.nokogiri --use-system-libraries && \
    QMAKE=/usr/lib/qt5/bin/qmake bundle install && \
    bundle clean

# Copy the main application.
COPY . ./
CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]

Sau khi thêm nội dung trên vào Dockerfile, bây giờ chúng ta có thể xây dựng container và chạy các lệnh với nó. Chúng ta có thể sử dụng một thẻ thông qua tùy chọn -t, nó cho phép chúng ta có thể tham chiếu đến các container sau này.

$ docker build -t demo_docker .
$ docker run -itP demo_docker

Nào cùng xem các câu lệnh trên có ý nghĩa gì nhé.

  • docker run: chạy các tác vụ chạy trong một container. Điều này thường được sử dụng cho các one-off tasks nhưng cũng rất hữu ích trong môi trường phát triển.
  • Tùy chọn -P làm cho tất cả các cổng được định nghĩa trong Dockerfile được tiếp xúc với các cổng không có đặc quyền trên máy chủ và do đó có thể truy cập từ bên ngoài.
  • Nếu chúng ta không chỉ định một lệnh chạy trên command line thì command được định nghĩa bởi CMD sẽ được chạy.

Giờ chúng ta đã có ứng dụng Rails của chúng ta chạy bên trong một Docker container, nhưng làm thế nào để thực sự truy cập nó từ máy tính của chúng ta? Bạn sẽ cần sử dụng docker ps, một công cụ tiện dụng để liệt kê các tiến trình Docker đang chạy cũng như các thông tin bổ sung về chúng.

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES
a20e454d8bb3        demo_docker         "bundle exec rails..."   49 seconds ago      Up 47 seconds       0.0.0.0:32769->3000/tcp   gracious_rosalind

Bạn có thể thấy Container ID của image đang sử dụng. Với những thông tin bên trên, chúng ta có thể mở ứng dụng trong trình duyệt tại địa chỉ http://0.0.0.0:32769

Moving your Development Environment to MySQL

Mặc dù SQLite có thể khá tốt cho một ứng dụng đơn giản, nhưng bạn sẽ không sử dụng nó trong môi trường production. Vậy hãy di chuyển môi trường phát triển của chúng ta sang MySQL. Bạn có thể thêm cơ sở dữ liệu vào container, nhưng có một cách khác tốt hơn để thực hiện việc này, đó là sử dụng Docker Compose để cung cấp cơ sở dữ liệu trong container và liên kết hai chúng với nhau. Thêm file docker-compose.yml vào thư mục của ứng dụng. Đồng thời thêm vào các configure sau

app:
  build: .
  command: rails server -p 3000 -b '0.0.0.0'
  environment:
    DATABASE_HOST: 'db'
    DATABASE_USER: 'root'
    DATABASE_PASSWORD: ''
  volumes:
    - .:/app
  ports:
    - "3000:3000"
  links:
    - db
  tty: true
  stdin_open: true
db:
  image: mysql:5.7.18
  environment:
    MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'

Bạn có thể tìm thấy các MySQL Docker image phù hợp. Trong ví dụ này, tôi sử dụng image mysql:5.7.18 và thông báo cho app container của bạn đường dẫn tới database.

Một phần rất quan trọng nữa là setting database.yml để có thể truy cập vào database server.

default: &default
  adapter: mysql2
  encoding: utf8
  collation: utf8_general_ci
  pool: 5
  timeout: 5000
  username: <%= ENV['DATABASE_USER'] %>
  password: <%= ENV['DATABASE_PASSWORD'] %>
  socket: /var/run/mysqld/mysqld.sock

development: &development
  <<: *default
  host: <%= ENV['DATABASE_HOST'] %>
  database: demo_docker_development

test:
  <<: *default
  host: <%= ENV['DATABASE_HOST'] %>
  database: demo_docker_test

và trong Gemfile hãy thay thế sqlite3 bằng mysql2

Vậy đã đã xong việc config docker-compose. Bây giờ chúng ta cần rebuilt lại container sử dụng các lệnh sau:

$ docker-compose build
$ docker-compose up -d
$ docker-compose run app bundle exec rake db:create
$ docker-compose run app bundle exec rake db:migrate

Vậy là xong rồi. Bây giờ bạn có thể thưởng thức thành quả của mình tại đường dẫn http://0.0.0.0:3000

Conclusion

Việc xây dựng hệ thống rails app trên môi trường docker quả thật là rất dễ dàng phải không? Mặc dù chuyển đổi môi trường phát triển của bạn sang Docker sẽ mất một số công việc nhất định, nhưng những lợi ích nó đem lại rất đáng giá. Bạn có được một môi trường dễ dàng chia sẻ với các thành viên trong nhóm, bạn có thể mô hình hóa nó gần giống với môi trường production và mở rộng nó một cách đơn giản. Từ giờ chúng ta đã có thể áp dụng cho các project sắp tới rồi nhé. 😉

Bạn có thể tham khảo tại github: Demo Docker