←
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.
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
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
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
Ở các file cấu hình
Sau khi chạy
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.yml và webpacker.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ệnhdocker 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é!