Lưu trữ một ứng dụng Ruby on Rails để phát triển với Docker Compose
Nếu bạn đang tích cực phát triển một ứng dụng, việc sử dụng Docker có thể đơn giản hóa quy trình làm việc và quy trình triển khai ứng dụng của bạn vào production . Làm việc với containers đang phát triển mang lại những lợi ích sau:- Các môi trường nhất quán, nghĩa là bạn có thể chọn ngôn ngữ và phụ thuộc bạn muốn cho dự án của bạn mà không cần lo lắng về xung đột hệ thống.
- Các môi trường được tách biệt, giúp khắc phục sự cố và giới thiệu thành viên group mới dễ dàng hơn.
- Môi trường có tính di động, cho phép bạn đóng gói và chia sẻ mã của bạn với người khác.
Hướng dẫn này sẽ chỉ cho bạn cách cài đặt môi trường phát triển cho ứng dụng Ruby on Rails bằng Docker. Bạn sẽ tạo nhiều containers - cho chính ứng dụng, database PostgreSQL , Redis và dịch vụ Sidekiq - với Docker Compose . Việc cài đặt sẽ thực hiện như sau:
- Đồng bộ hóa mã ứng dụng trên server với mã trong containers để tạo điều kiện thay đổi trong quá trình phát triển.
- Duy trì dữ liệu ứng dụng giữa các lần khởi động lại containers .
- Cấu hình công nhân Sidekiq để xử lý công việc như mong đợi.
Ở cuối hướng dẫn này, bạn sẽ có một ứng dụng thông tin cá mập đang hoạt động chạy trên containers Docker:
Yêu cầu
Để làm theo hướng dẫn này, bạn cần :
- Server hoặc máy phát triển local chạy Ubuntu 18.04, cùng với user không phải root có quyền
sudo
và firewall đang hoạt động. Để được hướng dẫn về cách cài đặt những điều này, vui lòng xem hướng dẫn Cài đặt Server Ban đầu này. - Docker được cài đặt trên máy local hoặc server của bạn, làm theo các Bước 1 và 2 của Cách cài đặt và sử dụng Docker trên Ubuntu 18.04 .
- Docker Compose được cài đặt trên máy local hoặc server của bạn, làm theo Bước 1 của Cách cài đặt Docker Compose trên Ubuntu 18.04 .
Bước 1 - Nhân bản Dự án và Thêm Phụ thuộc
Bước đầu tiên của ta sẽ là sao chép repository rails-sidekiq từ tài khoản GitHub của Cộng đồng DigitalOcean . Kho lưu trữ này bao gồm mã từ cài đặt được mô tả trong Cách thêm Sidekiq và Redis vào Ứng dụng Ruby on Rails , giải thích cách thêm Sidekiq vào dự án Rails 5 hiện có.
Sao chép repository vào một folder có tên là rails-docker
:
- git clone https://github.com/do-community/rails-sidekiq.git rails-docker
Điều hướng đến folder rails-docker
:
- cd rails-docker
Trong hướng dẫn này, ta sẽ sử dụng PostgreSQL làm database . Để làm việc với PostgreSQL thay vì SQLite 3, bạn cần thêm pg
gem vào các phụ thuộc của dự án, được liệt kê trong Gemfile của nó. Mở file đó để chỉnh sửa bằng nano
hoặc editor bạn quen dùng :
- nano Gemfile
Thêm đá quý vào bất kỳ đâu trong các phụ thuộc dự án chính (ở trên các phụ thuộc phát triển):
. . . # Reduces boot times through caching; required in config/boot.rb gem 'bootsnap', '>= 1.1.0', require: false gem 'sidekiq', '~>6.0.0' gem 'pg', '~>1.1.3' group :development, :test do . . .
Ta cũng có thể comment về gem sqlite
, vì ta sẽ không sử dụng nó nữa:
. . . # Use sqlite3 as the database for Active Record # gem 'sqlite3' . . .
Cuối cùng, hãy comment về viên ngọc spring-watcher-listen
đang được development
:
. . . gem 'spring' # gem 'spring-watcher-listen', '~> 2.0.0' . . .
Nếu ta không vô hiệu hóa gem này, ta sẽ thấy các thông báo lỗi liên tục khi truy cập console Rails. Các thông báo lỗi này xuất phát từ thực tế là gem này có Rails sử dụng listen
để theo dõi các thay đổi trong quá trình phát triển, thay vì thăm dò hệ thống file để tìm các thay đổi. Vì gem này theo dõi folder root của dự án , bao gồm cả folder node_modules
, nó sẽ đưa ra các thông báo lỗi về folder nào đang được theo dõi, làm lộn xộn console . Tuy nhiên, nếu bạn lo lắng về việc bảo tồn tài nguyên CPU, việc tắt gem này có thể không phù hợp với bạn. Trong trường hợp này, bạn nên nâng cấp ứng dụng Rails của bạn lên Rails 6.
Lưu file khi bạn hoàn tất chỉnh sửa.
Với repository dự án của bạn, viên ngọc pg
đã được thêm vào Gem file và viên ngọc spring-watcher-listen
listening đã comment , bạn đã sẵn sàng cấu hình ứng dụng của bạn để hoạt động với PostgreSQL.
Bước 2 - Cấu hình ứng dụng để hoạt động với PostgreSQL và Redis
Để làm việc với PostgreSQL và Redis trong quá trình phát triển, ta sẽ muốn thực hiện những việc sau:
- Cấu hình ứng dụng để hoạt động với PostgreSQL làm bộ điều hợp mặc định.
- Thêm file
.env
vào dự án với tên user và password database của ta và server Redis. - Tạo một tập lệnh
init.sql
để tạo một usersammy
cho database . - Thêm trình khởi tạo cho Sidekiq để nó có thể hoạt động với dịch vụ
redis
chứa trong vùng của ta . - Thêm
.env
file và các file khác có liên quan đến dự ángitignore
vàdockerignore
file . - Tạo hạt giống database để ứng dụng của ta có một số bản ghi để ta làm việc khi ta khởi động nó.
Đầu tiên, hãy mở file cấu hình database của bạn, có tại config/database.yml
:
- nano config/database.yml
Hiện tại, file bao gồm các cài đặt default
sau, được áp dụng trong trường hợp không có cài đặt khác:
default: &default adapter: sqlite3 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> timeout: 5000
Ta cần thay đổi những điều này để cho biết là ta sẽ sử dụng bộ điều hợp postgresql
, vì ta sẽ tạo một dịch vụ PostgreSQL với Docker Compose để duy trì dữ liệu ứng dụng của ta .
Xóa mã đặt SQLite làm bộ điều hợp và thay thế nó bằng các cài đặt sau, điều này sẽ đặt bộ điều hợp thích hợp và các biến khác cần thiết để kết nối:
default: &default adapter: postgresql encoding: unicode database: <%= ENV['DATABASE_NAME'] %> username: <%= ENV['DATABASE_USER'] %> password: <%= ENV['DATABASE_PASSWORD'] %> port: <%= ENV['DATABASE_PORT'] || '5432' %> host: <%= ENV['DATABASE_HOST'] %> pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> timeout: 5000 . . .
Tiếp theo, ta sẽ sửa đổi cài đặt cho môi trường development
, vì đây là môi trường ta đang sử dụng trong cài đặt này.
Xóa cấu hình database SQLite hiện có để phần đó trông giống như sau:
. . . development: <<: *default . . .
Cuối cùng, xóa cả cài đặt database
cho môi trường production
và test
:
. . . test: <<: *default production: <<: *default . . .
Những sửa đổi này đối với cài đặt database mặc định của ta sẽ cho phép ta đặt động thông tin database của bạn bằng cách sử dụng các biến môi trường được xác định trong file .env
, sẽ không được commit kiểm soát version .
Lưu file khi bạn hoàn tất chỉnh sửa.
Lưu ý nếu bạn đang tạo một dự án Rails từ đầu, bạn có thể đặt bộ điều hợp bằng lệnh rails new
, như được mô tả trong Bước 3 của Cách sử dụng PostgreSQL với Ứng dụng Ruby on Rails của bạn trên Ubuntu 18.04 . Điều này sẽ đặt bộ điều hợp của bạn trong config/database.yml
và tự động thêm đá quý pg
vào dự án.
Bây giờ ta đã tham chiếu đến các biến môi trường của bạn , ta có thể tạo file cho chúng với các cài đặt ưa thích của ta . Extract cài đặt cấu hình theo cách này là một phần của cách tiếp cận 12 Yếu tố để phát triển ứng dụng, xác định các phương pháp hay nhất để có khả năng phục hồi ứng dụng trong môi trường phân tán. Bây giờ, khi ta đang cài đặt môi trường production và thử nghiệm của bạn trong tương lai, việc cấu hình cài đặt database của ta sẽ liên quan đến việc tạo file .env
bổ sung và tham chiếu file thích hợp trong file Docker Compose của ta .
Mở file .env
:
- nano .env
Thêm các giá trị sau vào file :
DATABASE_NAME=rails_development DATABASE_USER=sammy DATABASE_PASSWORD=shark DATABASE_HOST=database REDIS_HOST=redis
Ngoài việc đặt tên database , user và password của ta , ta cũng đã đặt một giá trị cho DATABASE_HOST
. Giá trị, database
, đề cập đến dịch vụ PostgreSQL database
mà ta sẽ tạo bằng Docker Compose. Ta cũng đã đặt REDIS_HOST
để chỉ định dịch vụ redis
của ta .
Lưu file khi bạn hoàn tất chỉnh sửa.
Để tạo user database sammy
, ta có thể viết một tập lệnh init.sql
mà sau đó ta có thể mount vào containers database khi nó khởi động.
Mở file tập lệnh:
- nano init.sql
Thêm mã sau để tạo user sammy
có quyền quản trị:
CREATE USER sammy; ALTER USER sammy WITH SUPERUSER;
Tập lệnh này sẽ tạo user thích hợp trên database và cấp cho user này các quyền quản trị.
Đặt quyền thích hợp trên tập lệnh:
- chmod +x init.sql
Tiếp theo, ta sẽ cấu hình Sidekiq để hoạt động với dịch vụ redis
chứa trong containers của ta . Ta có thể thêm một trình khởi tạo vào folder config/initializers
, nơi Rails tìm kiếm các cài đặt cấu hình khi các khung và plugin được tải, điều này đặt giá trị cho server Redis.
Mở file sidekiq.rb
để chỉ định các cài đặt này:
- nano config/initializers/sidekiq.rb
Thêm mã sau vào file để chỉ định giá trị cho REDIS_HOST
và REDIS_PORT
:
Sidekiq.configure_server do |config| config.redis = { host: ENV['REDIS_HOST'], port: ENV['REDIS_PORT'] || '6379' } end Sidekiq.configure_client do |config| config.redis = { host: ENV['REDIS_HOST'], port: ENV['REDIS_PORT'] || '6379' } end
Giống như cài đặt cấu hình database của ta , những cài đặt này cho ta khả năng đặt động các thông số server và cổng, cho phép ta thay thế các giá trị thích hợp trong thời gian chạy mà không cần phải sửa đổi chính mã ứng dụng. Ngoài REDIS_HOST
, ta có một giá trị mặc định được đặt cho REDIS_PORT
trong trường hợp nó không được đặt ở nơi khác.
Lưu file khi bạn hoàn tất chỉnh sửa.
Tiếp theo, đảm bảo rằng dữ liệu nhạy cảm của ứng dụng của ta không bị sao chép sang kiểm soát version , ta có thể thêm .env
vào file .gitignore
của dự án, file này sẽ cho Git biết những file nào cần bỏ qua trong dự án của ta . Mở file để chỉnh sửa:
- nano .gitignore
Ở cuối file , hãy thêm một mục nhập cho .env
:
yarn-debug.log* .yarn-integrity .env
Lưu file khi bạn hoàn tất chỉnh sửa.
Tiếp theo, ta sẽ tạo một file .dockerignore
để đặt những gì không nên sao chép vào containers của ta . Mở file để chỉnh sửa:
- .dockerignore
Thêm mã sau vào file , mã này yêu cầu Docker bỏ qua một số thứ ta không cần sao chép vào containers của bạn :
.DS_Store .bin .git .gitignore .bundleignore .bundle .byebug_history .rspec tmp log test config/deploy public/packs public/packs-test node_modules yarn-error.log coverage/
Thêm .env
vào cuối file này:
. . . yarn-error.log coverage/ .env
Lưu file khi bạn hoàn tất chỉnh sửa.
Bước cuối cùng, ta sẽ tạo một số dữ liệu hạt giống để ứng dụng của ta có một vài bản ghi khi ta khởi động nó.
Mở file cho dữ liệu hạt giống trong folder db
:
- nano db/seeds.rb
Thêm mã sau vào file để tạo bốn con cá mập demo và một bài đăng mẫu:
# Adding demo sharks sharks = Shark.create([{ name: 'Great White', facts: 'Scary' }, { name: 'Megalodon', facts: 'Ancient' }, { name: 'Hammerhead', facts: 'Hammer-like' }, { name: 'Speartooth', facts: 'Endangered' }]) Post.create(body: 'These sharks are misunderstood', shark: sharks.first)
Dữ liệu hạt giống này sẽ tạo ra bốn con cá mập và một bài đăng được liên kết với con cá mập đầu tiên.
Lưu file khi bạn hoàn tất chỉnh sửa.
Với ứng dụng của bạn được cấu hình để hoạt động với PostgreSQL và các biến môi trường của bạn đã được tạo, bạn đã sẵn sàng để viết Dockerfile cho ứng dụng của bạn .
Bước 3 - Viết Tập lệnh Dockerfile và Entrypoint
Docker file chỉ định những gì sẽ được đưa vào containers ứng dụng của bạn khi nó được tạo. Sử dụng Dockerfile cho phép bạn xác định môi trường containers của bạn và tránh sự khác biệt với các version phụ thuộc hoặc thời gian chạy.
Tuân theo các nguyên tắc này về xây dựng các containers được tối ưu hóa , ta sẽ làm cho hình ảnh của bạn hiệu quả nhất có thể bằng cách sử dụng đế Alpine và cố gắng thu nhỏ các lớp hình ảnh của ta nói chung.
Mở file Dockerfile trong folder hiện tại của bạn:
- nano Dockerfile
Docker image được tạo bằng cách sử dụng liên tiếp các hình ảnh nhiều lớp xây dựng trên nhau. Bước đầu tiên của ta sẽ là thêm hình ảnh cơ sở cho ứng dụng của ta , hình ảnh này sẽ tạo thành điểm bắt đầu của việc xây dựng ứng dụng.
Thêm mã sau vào file để thêm hình ảnh núi cao Ruby làm cơ sở:
FROM ruby:2.5.1-alpine
Hình ảnh alpine
có nguồn root từ dự án Alpine Linux và sẽ giúp ta giảm kích thước hình ảnh. Để biết thêm thông tin về việc liệu hình ảnh alpine
có phải là sự lựa chọn phù hợp cho dự án của bạn hay không, vui lòng xem toàn bộ cuộc thảo luận trong phần Biến thể Hình ảnh của trang Docker image Hub Ruby .
Một số yếu tố cần xem xét khi sử dụng alpine
trong phát triển:
- Giảm kích thước hình ảnh sẽ làm giảm thời gian tải trang và tài nguyên, đặc biệt nếu bạn cũng giữ dung lượng ở mức tối thiểu. Điều này giúp giữ cho trải nghiệm user của bạn phát triển nhanh chóng và gần hơn với những gì sẽ xảy ra nếu bạn đang làm việc local trong môi trường không chứa đựng.
- Có sự tương đương giữa hình ảnh phát triển và production tạo điều kiện cho việc triển khai thành công. Vì các group thường chọn sử dụng hình ảnh Alpine trong quá trình production vì lợi ích về tốc độ, nên việc phát triển với đế Alpine giúp giải quyết các vấn đề khi chuyển sang production .
Tiếp theo, đặt một biến môi trường để chỉ định version Bundler :
. . . ENV BUNDLER_VERSION=2.0.2
Đây là một trong những bước ta sẽ thực hiện để tránh xung đột version giữa version bundler
mặc định có sẵn trong môi trường của ta và mã ứng dụng của ta , yêu cầu Bundler 2.0.2.
Tiếp theo, thêm các gói mà bạn cần để làm việc với ứng dụng vào Dockerfile:
. . . RUN apk add --update --no-cache \ binutils-gold \ build-base \ curl \ file \ g++ \ gcc \ git \ less \ libstdc++ \ libffi-dev \ libc-dev \ linux-headers \ libxml2-dev \ libxslt-dev \ libgcrypt-dev \ make \ netcat-openbsd \ nodejs \ openssl \ pkgconfig \ postgresql-dev \ python \ tzdata \ yarn
Các gói này bao gồm nodejs
và yarn
, trong số những gói khác. Vì ứng dụng của ta cung cấp nội dung với webpack , ta cần bao gồm Node.js và Yarn để ứng dụng hoạt động như mong đợi.
Lưu ý hình ảnh alpine
cực kỳ tối thiểu: các gói được liệt kê ở đây không đầy đủ những gì bạn có thể cần hoặc cần trong quá trình phát triển khi bạn đang chứa ứng dụng của riêng mình.
Tiếp theo, cài đặt version bundler
thích hợp:
. . . RUN gem install bundler -v 2.0.2
Bước này sẽ đảm bảo tính ngang bằng giữa môi trường được container của ta và các thông số kỹ thuật trong file Gemfile.lock
của dự án này.
Bây giờ đặt folder làm việc cho ứng dụng trên containers :
. . . WORKDIR /app
Sao chép của bạn Gemfile
và Gemfile.lock
:
. . . COPY Gemfile Gemfile.lock ./
Sao chép các file này như một bước độc lập, sau đó là bundle install
, nghĩa là các viên ngọc dự án không cần phải được xây dựng lại mỗi khi bạn thực hiện thay đổi đối với mã ứng dụng của bạn . Điều này sẽ hoạt động cùng với dung lượng đá quý mà ta sẽ đưa vào file Soạn của bạn , sẽ gắn đá quý vào containers ứng dụng của bạn trong trường hợp dịch vụ được tạo lại nhưng đá quý của dự án vẫn giữ nguyên.
Tiếp theo, đặt các tùy chọn cấu hình cho bản dựng đá quý nokogiri
:
. . . RUN bundle config build.nokogiri --use-system-libraries . . .
Bước này xây dựng nokigiri
với các version thư viện libxml2
và libxslt
mà ta đã thêm vào containers ứng dụng trong RUN apk add…
bước trên.
Tiếp theo, cài đặt các gem của dự án:
. . . RUN bundle check || bundle install
Hướng dẫn này kiểm tra xem đá quý chưa được cài đặt trước khi cài đặt chúng.
Tiếp theo, ta sẽ lặp lại quy trình tương tự mà ta đã sử dụng với đá quý với các gói và phụ thuộc JavaScript của ta . Đầu tiên, ta sẽ sao chép metadata gói, sau đó ta sẽ cài đặt các phần phụ thuộc và cuối cùng ta sẽ sao chép mã ứng dụng vào containers images .
Để bắt đầu với phần Javascript trong Dockerfile của ta , hãy sao chép package.json
và yarn.lock
từ folder dự án hiện tại của bạn trên server lưu trữ vào containers :
. . . COPY package.json yarn.lock ./
Sau đó, cài đặt các gói yêu cầu với yarn install
:
. . . RUN yarn install --check-files
Hướng dẫn này bao gồm --check-files
với lệnh yarn
, một tính năng đảm bảo mọi file đã cài đặt trước đó không bị xóa. Như trong trường hợp các node_modules
của ta , ta sẽ quản lý sự tồn tại của các gói trong folder node_modules
bằng một ổ đĩa khi ta viết file Soạn của bạn .
Cuối cùng, sao chép phần còn lại của mã ứng dụng và khởi động ứng dụng với một đoạn mã entrypoint:
. . . COPY . ./ ENTRYPOINT ["./entrypoints/docker-entrypoint.sh"]
Sử dụng một tập lệnh entrypoint cho phép ta chạy containers dưới dạng file thực thi .
Dockerfile cuối cùng sẽ giống như sau:
FROM ruby:2.5.1-alpine ENV BUNDLER_VERSION=2.0.2 RUN apk add --update --no-cache \ binutils-gold \ build-base \ curl \ file \ g++ \ gcc \ git \ less \ libstdc++ \ libffi-dev \ libc-dev \ linux-headers \ libxml2-dev \ libxslt-dev \ libgcrypt-dev \ make \ netcat-openbsd \ nodejs \ openssl \ pkgconfig \ postgresql-dev \ python \ tzdata \ yarn RUN gem install bundler -v 2.0.2 WORKDIR /app COPY Gemfile Gemfile.lock ./ RUN bundle config build.nokogiri --use-system-libraries RUN bundle check || bundle install COPY package.json yarn.lock ./ RUN yarn install --check-files COPY . ./ ENTRYPOINT ["./entrypoints/docker-entrypoint.sh"]
Lưu file khi bạn hoàn tất chỉnh sửa.
Tiếp theo, tạo một folder có tên là entrypoints
cho các tập lệnh entrypoint:
- mkdir entrypoints
Thư mục này sẽ bao gồm tập lệnh entrypoint chính của ta và một tập lệnh cho dịch vụ Sidekiq của ta .
Mở file cho tập lệnh điểm nhập ứng dụng:
- nano entrypoints/docker-entrypoint.sh
Thêm mã sau vào file :
#!/bin/sh set -e if [ -f tmp/pids/server.pid ]; then rm tmp/pids/server.pid fi bundle exec rails s -b 0.0.0.0
Dòng quan trọng đầu tiên là set -e
, cho biết shell /bin/sh
chạy tập lệnh bị lỗi nhanh nếu có sự cố nào sau này trong tập lệnh. Tiếp theo, tập lệnh kiểm tra xem tmp/pids/server.pid
không có mặt đảm bảo rằng sẽ không có xung đột server khi ta khởi động ứng dụng. Cuối cùng, tập lệnh khởi động server Rails bằng lệnh bundle exec rails s
. Ta sử dụng tùy chọn -b
với lệnh này để liên kết server với tất cả các địa chỉ IP thay vì với localhost
, mặc định. Lệnh gọi này làm cho server Rails định tuyến các yêu cầu đến IP containers thay vì đến localhost
mặc định.
Lưu file khi bạn hoàn tất chỉnh sửa.
Làm cho tập lệnh có thể thực thi:
- chmod +x entrypoints/docker-entrypoint.sh
Tiếp theo, ta sẽ tạo một tập lệnh để bắt đầu dịch vụ sidekiq
của ta , dịch vụ này sẽ xử lý các công việc Sidekiq của ta . Để biết thêm thông tin về cách ứng dụng này sử dụng Sidekiq, vui lòng xem Cách thêm Sidekiq và Redis vào Ứng dụng Ruby on Rails .
Mở file cho tập lệnh điểm nhập Sidekiq:
- nano entrypoints/sidekiq-entrypoint.sh
Thêm mã sau vào file để bắt đầu Sidekiq:
#!/bin/sh set -e if [ -f tmp/pids/server.pid ]; then rm tmp/pids/server.pid fi bundle exec sidekiq
Tập lệnh này khởi động Sidekiq trong bối cảnh gói ứng dụng của ta .
Lưu file khi bạn hoàn tất chỉnh sửa. Làm cho nó có thể thực thi:
- chmod +x entrypoints/sidekiq-entrypoint.sh
Với các tập lệnh entrypoint và Dockerfile tại chỗ, bạn đã sẵn sàng xác định các dịch vụ của bạn trong file Soạn của bạn .
Bước 4 - Xác định Dịch vụ với Docker Compose
Sử dụng Docker Compose, ta sẽ có thể chạy nhiều containers cần thiết cho cài đặt của ta . Ta sẽ xác định các dịch vụ Soạn thư của bạn trong file docker-compose.yml
chính của ta . Dịch vụ trong Soạn là một containers đang chạy và các định nghĩa dịch vụ - mà bạn sẽ đưa vào file docker-compose.yml
- chứa thông tin về cách mỗi containers images sẽ chạy. Công cụ Soạn thư cho phép bạn xác định nhiều dịch vụ để xây dựng các ứng dụng đa containers .
Cài đặt ứng dụng của ta sẽ bao gồm các dịch vụ sau:
- Bản thân ứng dụng
- Database PostgreSQL
- Redis
- Sidekiq
Ta cũng sẽ bao gồm một mount liên kết như một phần của cài đặt của ta , để bất kỳ thay đổi mã nào ta thực hiện trong quá trình phát triển sẽ được đồng bộ hóa ngay lập tức với các containers cần quyền truy cập vào mã này.
Lưu ý ta không xác định dịch vụ test
, vì thử nghiệm nằm ngoài phạm vi của hướng dẫn và loạt bài này , nhưng bạn có thể làm như vậy theo tiền lệ mà ta đang sử dụng ở đây cho dịch vụ sidekiq
.
Mở file docker-compose.yml
:
- nano docker-compose.yml
Đầu tiên, hãy thêm định nghĩa dịch vụ ứng dụng:
version: '3.4' services: app: build: context: . dockerfile: Dockerfile depends_on: - database - redis ports: - "3000:3000" volumes: - .:/app - gem_cache:/usr/local/bundle/gems - node_modules:/app/node_modules env_file: .env environment: RAILS_ENV: development
Định nghĩa dịch vụ app
bao gồm các tùy chọn sau:
-
build
: Tùy chọn này xác định các tùy chọn cấu hình, bao gồmcontext
vàdockerfile
, sẽ được áp dụng khi Compose xây dựng hình ảnh ứng dụng. Nếu bạn muốn sử dụng hình ảnh hiện có từ một nơi đăng ký như Docker Hub , bạn có thể sử dụng hướng dẫnimage
thay thế, với thông tin về tên user , repository và thẻ hình ảnh của bạn. -
context
: Điều này xác định bối cảnh xây dựng cho bản dựng hình ảnh - trong trường hợp này là folder dự án hiện tại. -
dockerfile
: Điều này chỉ địnhDockerfile
trong folder dự án hiện tại của bạn làm file Compose sẽ sử dụng để xây dựng hình ảnh ứng dụng. -
depends_on
: Điều này cài đặtdatabase
vàredis
container trước để chúng được cài đặt và chạy trướcapp
. -
ports
: Điều này ánh xạ cổng3000
trên server đến cổng3000
trên containers . -
volumes
: Ta bao gồm hai loại mount ở đây:- Đầu tiên là một liên kết ràng buộc gắn mã ứng dụng của ta trên server lưu trữ vào folder
/app
trên containers . Điều này sẽ tạo điều kiện phát triển nhanh chóng, vì bất kỳ thay đổi nào bạn thực hiện đối với mã server của bạn sẽ được điền ngay vào containers . - Thứ hai là một tên dung lượng ,
gem_cache
. Khi hướng dẫnbundle install
chạy trong containers , nó sẽ cài đặt các viên ngọc của dự án. Thêm dung lượng này nghĩa là nếu bạn tạo lại containers , các viên ngọc sẽ được gắn vào containers mới. Mount này giả định không có bất kỳ thay đổi nào đối với dự án, vì vậy nếu bạn thực hiện thay đổi đối với các viên ngọc dự án của bạn trong quá trình phát triển, bạn cần nhớ xóa tập này trước khi tạo lại dịch vụ ứng dụng của bạn . - Tập thứ ba là một tập được đặt tên cho folder
node_modules
. Thay vì cónode_modules
được gắn vào server , điều này có thể dẫn đến sự khác biệt về gói và xung đột quyền trong quá trình phát triển, tập này sẽ đảm bảo các gói trong folder này vẫn tồn tại và phản ánh trạng thái hiện tại của dự án. , nếu bạn sửa đổi các phụ thuộc Node của dự án, bạn cần phải xóa và tạo lại ổ đĩa này.
- Đầu tiên là một liên kết ràng buộc gắn mã ứng dụng của ta trên server lưu trữ vào folder
-
env_file
: Điều này cho Soạn biết rằng ta muốn thêm các biến môi trường từ một file có tên.env
nằm trong ngữ cảnh xây dựng. -
environment
: Sử dụng tùy chọn này cho phép ta cài đặt một biến môi trường không nhạy cảm, truyền thông tin về môi trường Rails vào containers .
Tiếp theo, bên dưới định nghĩa dịch vụ app
, hãy thêm mã sau để xác định dịch vụ database
của bạn:
. . . database: image: postgres:12.1 volumes: - db_data:/var/lib/postgresql/data - ./init.sql:/docker-entrypoint-initdb.d/init.sql
Không giống như dịch vụ app
, dịch vụ database
lấy một hình ảnh postgres
trực tiếp từ Docker Hub . Lưu ý ta cũng đang ghim version ở đây, thay vì đặt nó thành latest
hoặc không chỉ định nó (mặc định là latest
). Bằng cách này, ta có thể đảm bảo cài đặt này hoạt động với các version được chỉ định ở đây và tránh những bất ngờ không mong muốn với các thay đổi mã vi phạm đối với hình ảnh.
Ta cũng bao gồm một db_data
ở đây, ổ đĩa này sẽ duy trì dữ liệu ứng dụng của ta giữa các lần khởi động containers . Ngoài ra, ta đã gắn tập lệnh khởi động init.sql
của bạn vào folder thích hợp, docker-entrypoint-initdb.d/
trên containers , để tạo user database sammy
của ta . Sau khi điểm nhập hình ảnh tạo database và user postgres
mặc định, nó sẽ chạy bất kỳ tập lệnh nào được tìm thấy trong folder docker-entrypoint-initdb.d/
mà bạn có thể sử dụng cho các việc khởi tạo cần thiết. Để biết thêm chi tiết, hãy xem phần Tập lệnh khởi tạo của tài liệu hình ảnh PostgreSQL
Tiếp theo, thêm định nghĩa dịch vụ redis
:
. . . redis: image: redis:5.0.7
Giống như dịch vụ database
, dịch vụ redis
sử dụng hình ảnh từ Docker Hub. Trong trường hợp này, ta không duy trì bộ nhớ cache công việc Sidekiq.
Cuối cùng, thêm định nghĩa dịch vụ sidekiq
:
. . . sidekiq: build: context: . dockerfile: Dockerfile depends_on: - app - database - redis volumes: - .:/app - gem_cache:/usr/local/bundle/gems - node_modules:/app/node_modules env_file: .env environment: RAILS_ENV: development entrypoint: ./entrypoints/sidekiq-entrypoint.sh
Dịch vụ sidekiq
của ta giống với dịch vụ app
của ta ở một số khía cạnh: nó sử dụng cùng một bối cảnh và hình ảnh xây dựng, các biến môi trường và dung lượng . Tuy nhiên, nó phụ thuộc vào app
, redis
và các dịch vụ database
và vì vậy sẽ là lần cuối cùng bắt đầu. Ngoài ra, nó sử dụng một entrypoint
sẽ overrides điểm nhập được đặt trong Dockerfile. Cài đặt entrypoint
này trỏ tới entrypoints/sidekiq-entrypoint.sh
, bao gồm lệnh thích hợp để khởi động dịch vụ sidekiq
.
Bước cuối cùng, hãy thêm định nghĩa âm lượng bên dưới định nghĩa dịch vụ sidekiq
:
. . . volumes: gem_cache: db_data: node_modules:
Khóa dung lượng cấp cao nhất của ta xác định các dung lượng gem_cache
, db_data
và node_modules
. Khi Docker tạo tập, nội dung của tập được lưu trữ trong một phần của hệ thống file server , /var/lib/docker/volumes/
, được Docker quản lý. Nội dung của mỗi tập được lưu trữ trong một folder dưới /var/lib/docker/volumes/
và được gắn vào bất kỳ containers nào sử dụng tập. Bằng cách này, dữ liệu thông tin cá mập mà user của ta sẽ tạo sẽ tồn tại trong db_data
ngay cả khi ta xóa và tạo lại dịch vụ database
.
Tệp đã hoàn thành sẽ giống như sau:
version: '3.4' services: app: build: context: . dockerfile: Dockerfile depends_on: - database - redis ports: - "3000:3000" volumes: - .:/app - gem_cache:/usr/local/bundle/gems - node_modules:/app/node_modules env_file: .env environment: RAILS_ENV: development database: image: postgres:12.1 volumes: - db_data:/var/lib/postgresql/data - ./init.sql:/docker-entrypoint-initdb.d/init.sql redis: image: redis:5.0.7 sidekiq: build: context: . dockerfile: Dockerfile depends_on: - app - database - redis volumes: - .:/app - gem_cache:/usr/local/bundle/gems - node_modules:/app/node_modules env_file: .env environment: RAILS_ENV: development entrypoint: ./entrypoints/sidekiq-entrypoint.sh volumes: gem_cache: db_data: node_modules:
Lưu file khi bạn hoàn tất chỉnh sửa.
Với các định nghĩa dịch vụ của bạn đã được viết sẵn, bạn đã sẵn sàng khởi động ứng dụng.
Bước 5 - Kiểm tra ứng dụng
Với file docker-compose.yml
của bạn tại chỗ, bạn có thể tạo các dịch vụ của bạn bằng lệnh docker-compose up
database của bạn. Bạn cũng có thể kiểm tra xem dữ liệu của bạn có tồn tại hay không bằng cách dừng và xóa các containers của bạn bằng docker-compose down
chúng.
Đầu tiên, xây dựng các containers images và tạo các dịch vụ bằng cách chạy docker-compose up
với cờ -d
, sẽ chạy các containers trong nền:
- docker-compose up -d
Bạn sẽ thấy kết quả rằng các dịch vụ của bạn đã được tạo:
OutputCreating rails-docker_database_1 ... done Creating rails-docker_redis_1 ... done Creating rails-docker_app_1 ... done Creating rails-docker_sidekiq_1 ... done
Bạn cũng có thể nhận thêm thông tin chi tiết về các quy trình khởi động bằng cách hiển thị kết quả log từ các dịch vụ:
- docker-compose logs
Bạn sẽ thấy thông tin như thế này nếu mọi thứ đã bắt đầu đúng :
Outputsidekiq_1 | 2019-12-19T15:05:26.365Z pid=6 tid=grk7r6xly INFO: Booting Sidekiq 6.0.3 with redis options {:host=>"redis", :port=>"6379", :id=>"Sidekiq-server-PID-6", :url=>nil} sidekiq_1 | 2019-12-19T15:05:31.097Z pid=6 tid=grk7r6xly INFO: Running in ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux-musl] sidekiq_1 | 2019-12-19T15:05:31.097Z pid=6 tid=grk7r6xly INFO: See LICENSE and the LGPL-3.0 for licensing details. sidekiq_1 | 2019-12-19T15:05:31.097Z pid=6 tid=grk7r6xly INFO: Upgrade to Sidekiq Pro for more features and support: http://sidekiq.org app_1 | => Booting Puma app_1 | => Rails 5.2.3 application starting in development app_1 | => Run `rails server -h` for more startup options app_1 | Puma starting in single mode... app_1 | * Version 3.12.1 (ruby 2.5.1-p57), codename: Llamas in Pajamas app_1 | * Min threads: 5, max threads: 5 app_1 | * Environment: development app_1 | * Listening on tcp://0.0.0.0:3000 app_1 | Use Ctrl-C to stop . . . database_1 | PostgreSQL init process complete; ready for start up. database_1 | database_1 | 2019-12-19 15:05:20.160 UTC [1] LOG: starting PostgreSQL 12.1 (Debian 12.1-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit database_1 | 2019-12-19 15:05:20.160 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432 database_1 | 2019-12-19 15:05:20.160 UTC [1] LOG: listening on IPv6 address "::", port 5432 database_1 | 2019-12-19 15:05:20.163 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" database_1 | 2019-12-19 15:05:20.182 UTC [63] LOG: database system was shut down at 2019-12-19 15:05:20 UTC database_1 | 2019-12-19 15:05:20.187 UTC [1] LOG: database system is ready to accept connections . . . redis_1 | 1:M 19 Dec 2019 15:05:18.822 * Ready to accept connections
Bạn cũng có thể kiểm tra trạng thái của các containers của bạn bằng docker-compose ps
:
- docker-compose ps
Bạn sẽ thấy kết quả cho biết rằng các containers của bạn đang chạy:
Output Name Command State Ports ----------------------------------------------------------------------------------------- rails-docker_app_1 ./entrypoints/docker-resta ... Up 0.0.0.0:3000->3000/tcp rails-docker_database_1 docker-entrypoint.sh postgres Up 5432/tcp rails-docker_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp rails-docker_sidekiq_1 ./entrypoints/sidekiq-entr ... Up
Tiếp theo, tạo và khởi tạo database của bạn và chạy quá trình di chuyển trên đó bằng lệnh thực thi docker-compose exec
sau:
- docker-compose exec app bundle exec rake db:setup db:migrate
Lệnh thực thi docker-compose exec
cho phép bạn chạy các lệnh trong các dịch vụ của bạn ; ta đang sử dụng nó ở đây để chạy rake db:setup
và db:migrate
trong bối cảnh gói ứng dụng của ta để tạo và khởi tạo database và chạy di chuyển. Khi bạn làm việc trong quá trình phát triển, trình điều khiển docker-compose exec
sẽ tỏ ra hữu ích cho bạn khi bạn muốn chạy di chuyển đối với database phát triển của bạn .
Bạn sẽ thấy kết quả sau khi chạy lệnh này:
OutputCreated database 'rails_development' Database 'rails_development' already exists -- enable_extension("plpgsql") -> 0.0140s -- create_table("endangereds", {:force=>:cascade}) -> 0.0097s -- create_table("posts", {:force=>:cascade}) -> 0.0108s -- create_table("sharks", {:force=>:cascade}) -> 0.0050s -- enable_extension("plpgsql") -> 0.0173s -- create_table("endangereds", {:force=>:cascade}) -> 0.0088s -- create_table("posts", {:force=>:cascade}) -> 0.0128s -- create_table("sharks", {:force=>:cascade}) -> 0.0072s
Khi các dịch vụ của bạn đang chạy, bạn có thể truy cập localhost:3000
hoặc http://your_server_ip:3000
trong trình duyệt. Bạn sẽ thấy một trang đích giống như sau:
Bây giờ ta có thể kiểm tra độ bền của dữ liệu. Tạo một con cá mập mới bằng cách nhấp vào nút Nhận thông tin cá mập , nút này sẽ đưa bạn đến tuyến đường sharks/index
:
Để xác minh ứng dụng đang hoạt động, ta có thể thêm một số thông tin demo vào nó. Nhấp vào Cá mập mới . Bạn sẽ được yêu cầu nhập tên user ( sammy ) và password ( cá mập ), nhờ cài đặt xác thực của dự án.
Trên trang Cá mập mới , nhập “Mako” vào trường Tên và “Nhanh” vào trường Dữ kiện .
Nhấn vào nút Create Shark để tạo cá mập. Khi bạn đã tạo xong con cá mập, hãy nhấp vào Trang chủ trên thanh chuyển của trang web để quay lại trang đích của ứng dụng chính. Bây giờ ta có thể kiểm tra Sidekiq đang hoạt động.
Nhấp vào Cá mập nào đang gặp nguy hiểm? cái nút. Vì bạn chưa tải lên bất kỳ loài cá mập nguy cấp nào nên điều này sẽ đưa bạn đến chế độ xem index
endangered
:
Nhấp vào Nhập cá mập nguy cấp để nhập cá mập. Bạn sẽ thấy một thông báo trạng thái cho bạn biết rằng cá mập đã được nhập:
Bạn cũng sẽ thấy phần bắt đầu của quá trình nhập. Làm mới trang web để xem toàn bộ bảng:
Nhờ Sidekiq, quá trình tải lên hàng loạt lớn về cá mập có nguy cơ tuyệt chủng của ta đã thành công mà không cần khóa trình duyệt hoặc can thiệp vào chức năng ứng dụng khác.
Nhấp vào nút Trang chủ ở cuối trang, nút này sẽ đưa bạn trở lại trang chính của ứng dụng:
Từ đây, nhấp vào Cá mập nào đang gặp nguy hiểm? lần nữa. Bạn sẽ nhìn thấy những con cá mập được tải lên .
Bây giờ ta biết ứng dụng của bạn đang hoạt động bình thường, ta có thể kiểm tra tính bền bỉ của dữ liệu.
Quay lại terminal của bạn, nhập lệnh sau để dừng và xóa các containers của bạn:
- docker-compose down
Lưu ý ta không bao gồm tùy chọn --volumes
; do đó, dung lượng db_data
của ta không bị xóa.
Kết quả sau xác nhận containers và mạng của bạn đã bị xóa:
OutputStopping rails-docker_sidekiq_1 ... done Stopping rails-docker_app_1 ... done Stopping rails-docker_database_1 ... done Stopping rails-docker_redis_1 ... done Removing rails-docker_sidekiq_1 ... done Removing rails-docker_app_1 ... done Removing rails-docker_database_1 ... done Removing rails-docker_redis_1 ... done Removing network rails-docker_default
Tạo lại các containers :
- docker-compose up -d
Mở console Rails trên containers app
với console thực thi docker-compose exec
và bundle exec rails console
:
- docker-compose exec app bundle exec rails console
Khi được yêu cầu , hãy kiểm tra bản ghi Shark last
trong database :
- Shark.last.inspect
Bạn sẽ thấy bản ghi bạn vừa tạo:
IRB session Shark Load (1.0ms) SELECT "sharks".* FROM "sharks" ORDER BY "sharks"."id" DESC LIMIT $1 [["LIMIT", 1]] => "#<Shark id: 5, name: \"Mako\", facts: \"Fast\", created_at: \"2019-12-20 14:03:28\", updated_at: \"2019-12-20 14:03:28\">"
Sau đó, bạn có thể kiểm tra xem những con Cá mập Endangered
của bạn vẫn còn tồn tại bằng lệnh sau:
- Endangered.all.count
IRB session (0.8ms) SELECT COUNT(*) FROM "endangereds" => 73
db_data
của bạn đã được mount thành công vào dịch vụ database
tạo lại, giúp dịch vụ app
của bạn có thể truy cập vào dữ liệu đã lưu. Nếu bạn chuyển trực tiếp đến trang shark
index
bằng cách truy cập localhost:3000/sharks
shark
hoặc http://your_server_ip:3000/sharks
bạn cũng sẽ thấy bản ghi đó được hiển thị:
Những con cá mập có nguy cơ tuyệt chủng của bạn cũng sẽ có tại localhost:3000/endangered/data
http://your_server_ip:3000/endangered/data
localhost:3000/endangered/data
hoặc http://your_server_ip:3000/endangered/data
view:
Ứng dụng của bạn hiện đang chạy trên containers Docker với tính năng ổn định dữ liệu và đồng bộ hóa mã được bật. Bạn có thể tiếp tục và kiểm tra các thay đổi mã local trên server của bạn , các thay đổi này sẽ được đồng bộ hóa với containers của bạn nhờ mount liên kết mà ta đã xác định là một phần của dịch vụ app
.
Kết luận
Theo hướng dẫn này, bạn đã tạo một cài đặt phát triển cho ứng dụng Rails của bạn bằng cách sử dụng Docker container. Bạn đã làm cho dự án của bạn mang tính mô-đun và di động hơn bằng cách extract thông tin nhạy cảm và tách trạng thái ứng dụng khỏi mã của bạn. Bạn cũng đã cấu hình một file docker-compose.yml
mà bạn có thể sửa đổi khi nhu cầu phát triển và yêu cầu của bạn thay đổi.
Khi bạn phát triển, bạn có thể quan tâm đến việc tìm hiểu thêm về cách thiết kế các ứng dụng cho quy trình làm việc được chứa trong container và Cloud Native . Vui lòng xemỨng dụng kiến trúc cho Kubernetes và Ứng dụng hiện đại hóa cho Kubernetes để biết thêm thông tin về các chủ đề này. Hoặc, nếu bạn muốn đầu tư vào trình tự học Kubernetes, vui lòng xem qua giáo trình Kubernetes dành cho Nhà phát triển toàn ngăn xếp .
Để tìm hiểu thêm về mã ứng dụng, vui lòng xem các hướng dẫn khác trong loạt bài này:
- Cách tạo ứng dụng Ruby on Rails
- Cách tạo tài nguyên lồng nhau cho ứng dụng Ruby on Rails
- Cách thêm kích thích vào ứng dụng Ruby on Rails
- Cách thêm Bootstrap vào ứng dụng Ruby on Rails
- Cách thêm Sidekiq và Redis vào ứng dụng Ruby on Rails
Các tin liên quan
Làm việc với nhiều container bằng Docker Compose2019-12-20
Cách sử dụng Plugin Docker cho Visual Studio Code
2019-12-12
Cách sử dụng Ansible để cài đặt và thiết lập Docker trên Ubuntu 18.04
2019-12-05
Cách tạo ứng dụng Django và Gunicorn với Docker
2019-10-25
Cách thiết lập Flask với MongoDB và Docker
2019-10-11
Cách cài đặt và sử dụng Docker trên Debian 10
2019-07-08
Cách sử dụng server Docker từ xa để tăng tốc quy trình làm việc của bạn
2019-06-25
Cách cài đặt WordPress với Docker Compose
2019-05-24
Cách di chuyển Docker compose workflow sang Kubernetes
2019-04-03
Cách tối ưu hóa image Docker cho sản xuất
2019-03-25