Quay lại
11/04/2026 7 phút

Dockerize dự án Rails legacy

🤖 Mình có dùng AI (Google Gemini) trợ giúp triển khai docker nhưng nội dung bài viết này tự tay mình viết 100%.

Mệt mỏi vì mỗi lần đổi máy mới hay có thêm thành viên vào chung dự án đều phải cài Rails app từ đầu lỗi lên lỗi xuống vì dùng phiên bản quá cũ nên mình quyết định dockerize nó để khi vào dự án chỉ cần build và compose là chạy được.

Các di sản đời trước để lại lạ là Ruby 2.4.2, Rails 5.1.6, Nodejs 14.17, Webpacker 4 và vô vàn thư viện xưa cũ. Có thể bạn sẽ tự hỏi tại sao không nâng lên bản mới nhất. Mình cũng từng đề xuất nhưng leader không cho, bảo nó vẫn chạy được thì để nó chạy. Okay!

Dưới đây là cách mình áp dụng cho Macbook với các chip ARM nhà trồng của Apple từ M1→M5.

Dockerfile

Trước hết ta cần tạo một file tên Dockerfile là bản hướng dẫn docker build image dự án. Mình gửi luôn nội dung hoàn chỉnh.

FROM --platform=linux/amd64 ruby:2.4.2

RUN echo "deb http://archive.debian.org/debian jessie main" > /etc/apt/sources.list && \
    echo "Acquire::Check-Valid-Until false;" > /etc/apt/apt.conf.d/10-nocheckvalid

RUN apt-get update -qq && apt-get install -y --force-yes \
    build-essential \
    pkg-config \
    libpq-dev \
    python \
    curl \
    imagemagick \
    libglib2.0-dev \
    libexpat1-dev \
    libjpeg-dev \
    libpng-dev \
    libwebp-dev \
    libtiff5-dev \
    libexif-dev \
    fontconfig \
    libfontconfig1 \
    libxrender1 \
    libxext6 \
    xfonts-75dpi \
    xfonts-base

RUN curl -fsSLO https://github.com/libvips/libvips/releases/download/v8.7.4/vips-8.7.4.tar.gz && \
    tar xzf vips-8.7.4.tar.gz && \
    cd vips-8.7.4 && \
    ./configure && \
    make -j4 && \
    make install && \
    ldconfig && \
    cd .. && rm -rf vips-8.7.4 vips-8.7.4.tar.gz

RUN curl -fsSLO https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.5/wkhtmltox_0.12.5-1.jessie_amd64.deb && \
    dpkg -i wkhtmltox_0.12.5-1.jessie_amd64.deb || apt-get install -y --force-yes -f && \
    rm wkhtmltox_0.12.5-1.jessie_amd64.deb

RUN curl -fsSLO https://nodejs.org/dist/v14.17.0/node-v14.17.0-linux-x64.tar.xz && \
    tar -xJf node-v14.17.0-linux-x64.tar.xz -C /usr/local --strip-components=1 && \
    rm node-v14.17.0-linux-x64.tar.xz

RUN npm install -g yarn@1.22.19

WORKDIR /app

ENV BUNDLER_VERSION=2.3.23

RUN gem install bundler -v $BUNDLER_VERSION

COPY Gemfile Gemfile.lock ./
RUN bundle install --jobs 4 --retry 3

COPY package.json yarn.lock ./
RUN yarn install

COPY . .

EXPOSE 3000
CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]

Vì Ruby 2.4.2 đã bị ngừng hỗ trợ từ rất lâu rồi và cũng không có image cho kiến trúc arm nên buộc phải dùng amd64 (Intel/AMD 64 bit) --platform=linux/amd64. Docker dùng trình giả lập QEMU để hỗ trợ chạy amd64 trên ARM của Apple.

Vì Ruby 2.4.2 xây dựng trên hệ điều hành Debian 8 (Jessie) đã bị khai tử. Mặc định apt-get sẽ không tìm thấy nó để tải nên phải ghi đè link archive vào sources.list để chỉ chỗ tải bằng echo "deb http://archive.debian.org/debian jessie main" > /etc/apt/sources.list.

echo "Acquire::Check-Valid-Until false;" > /etc/apt/apt.conf.d/10-nocheckvalid bảo docker bỏ qua không kiểm tra hạn dùng của phần mềm vì lúc cài phần mềm cũ quá sẽ báo lỗi hết "đát".

Các dòng RUN tiếp theo để tiến hành cài đặt các phần mềm cần thiết vì có nhiều gem dựa trên các thư viện native đã lỗi thời khiến việc chạy lệnh bundle install (ở bước sau) gặp rất nhiều lỗi. Ví dụ như các gem: pg, wicked_pdf, wkhtmltopdf-binary, ruby-vips, mini_magick,... Node.js 14.17, yarn 1.22.19.

WORKDIR thiết lập thư mục làm việc bên trong container.

ENV BUNDLER_VERSION=2.3.23 đè biến môi trường nhằm ép bundler chạy đúng phiên bản. Sau đó cài bundler bằng lệnh RUN  gem install bundler -v $BUNDLER_VERSION.

COPY Gemfile Gemfile.lock ./
RUN bundle install --jobs 4 --retry 3

COPY package.json yarn.lock ./
RUN yarn install

COPY . .

Phần này tận dụng cache layer của Docker để không phải build lại nhiều lần so với khi viết:

COPY . .           # 1. Copy TOÀN BỘ code dự án vào (bao gồm cả Gemfile, package.json, src, app, config...)
RUN bundle install # 2. Cài gem
RUN yarn install   # 3. Cài node modules

Nếu bạn sửa một file source code bất kì sẽ invalidate cache của layer COPY làm cho tất cả các lớp tiếp theo phải build lại (bundle, yarn install) trong khi với code ban đầu 2 lệnh trên không phải build lại lần nữa.

Sau cùng expose và cmd để cho phép truy cập vào localhost:3000.

⚠️ Lưu ý: nên copy file yarn.lock từ máy tính đã chạy được dự án vào để cài thư viện cho lẹ và không bị lỗi phiên bản.

docker-compose.yml

Dockerfile build image còn docker-compose định nghĩa container cho từng service cần để dev cho dự án là: web, db, redis, sidekiq và webpack-dev-server. Đây là nội dung file:

version: "3.8"

x-app: &app
  build:
    context: .
    dockerfile: Dockerfile
  platform: linux/amd64
  volumes:
    - .:/app
    - node_modules:/app/node_modules
    - bundle:/usr/local/bundle
  env_file:
    - .env.development
  environment:
    - RAILS_ENV=development
    - DATABASE_HOST=db
    - DATABASE_USER=postgres
    - DATABASE_PASSWORD=postgres
    - REDIS_HOST=redis

services:
  web:
    <<: *app
    environment:
      - WEBPACKER_DEV_SERVER_HOST=webpacker
    ports:
      - "3000:3000"
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -b '0.0.0.0'"
    depends_on:
      - db
      - redis
      - webpacker

  webpacker:
    <<: *app
    environment:
      - WEBPACKER_DEV_SERVER_HOST=0.0.0.0
    ports:
      - "3035:3035"
    command: bash -c "yarn install && ./bin/webpack-dev-server"
    depends_on:
      - db
      - redis

  sidekiq:
    <<: *app
    command: bundle exec sidekiq -C config/sidekiq.yml
    depends_on:
      - db
      - redis

  db:
    image: postgres:15-alpine
    platform: linux/amd64
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_DB=vamos_development
      - POSTGRES_HOST_AUTH_METHOD=trust
    ports:
      - "5432:5432"
    volumes:
      - pg_data:/var/lib/postgresql/data

  redis:
    image: redis:4.0-alpine
    platform: linux/amd64
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data

volumes:
  pg_data:
  redis_data:
  node_modules:
  bundle:

Trên là những cấu hình cơ bản cho dự án Rails, vài điểm cần chú ý là biến POSTGRES_HOST_AUTH_METHOD=trust cho postgresql nếu có báo lỗi phương thức xác thực. Ở đây mình dùng postgresql 15 cùng phiên bản với production và gặp lỗi đó.

Trong quá trình compose nếu có lỗi hãy thử kiểm tra các biến môi trường khai báo đã đúng chưa.

Ngoài ra, nhớ thêm platform: linux/amd64 tương tự như ở Dockerfile vào các service nhé.

Những thay đổi khác

Nhớ thêm require 'uri' vào boot.rb vì ruby gọi thư viện này lúc trước lúc sau không biết đâu mà lần và gây ra lỗi, nếu bạn không gặp thì có thể bỏ qua.

Ở các file cấu hình database.yml, cable.ymlwebpacker.yml nhớ đổi lại host theo host của container nội bộ. Đa phần cấu hình khi dev trên máy thường là localhost nhưng khi chuyển sang docker tất cả đều là container và giao tiếp thông qua network giữa chúng. Tên host trong network thường cùng tên với service là db, redis,... nên có thể dùng luôn tên này hoặc cài đặt trong biến môi trường trong file docker-compose.yml.

Sau khi chạy docker compose build xong hãy chạy docker compose up -d. Rails cần tạo db và migrate trước khi dùng được. Chạy lệnh

docker compose run --rm web bundle exec rails db:create db:migrate db:seed

Nếu migrate bị lỗi giống mình (vì dự án quá cũ đi) thì nhanh nhất là lên staging dump database vào một file .dump và dùng pg_restore restore lại vào database dưới local là xong.

docker compose exec -T db pg_restore -U postgres -d vamos_development -O -x --clean < path/to/dump

Lệnh phòng thân

Không thể nào tránh khỏi những lỗi kì quặc khác trong quá trình build và compose. Khi đó nếu tuyệt vọng bạn hãy thử dọn dẹp file cache và node_modules:

docker compose run --rm web bash -c "rm -rf tmp/cache/* public/packs node_modules/*"

Cài lại yarn:

docker compose run --rm web yarn install

Biên dịch lại webpack:

docker compose run --rm web bundle exec rails webpacker:compile

Và khởi động lại toàn bộ:

docker compose down
docker compose up -d --build

Trên là quá trình tốn kém thời gian và đau đầu (nhưng đau một lần rồi thôi) để dockerize dự án Rails cũ kĩ không còn hỗ trợ. Từ rày về sau máy mới nhảy vào cứ cài docker và chạy là xong. Docker hay thật! Mình dự định sẽ viết một bài cơ bản về docker. Cùng chờ xem nhé!
Cảm ơn bạn đã đọc bài.
0

Thảo luận trên Bluesky

Đi

Đang tải bình luận...

Powered by Bluesky AT Protocol