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  sudovà 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  .envvà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 usersammycho database .
-  Thêm trình khởi tạo cho Sidekiq để nó có thể hoạt động với dịch vụ redischứa trong vùng của ta .
-  Thêm .envfile và các file khác có liên quan đến dự ángitignorevàdockerignorefile .
- 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ồmcontextvà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ẫnimagethay 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ỉ địnhDockerfiletrong 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 đặtdatabasevàrediscontainer trước để chúng được cài đặt và chạy trướcapp.
-  ports: Điều này ánh xạ cổng3000trên server đến cổng3000trê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  /apptrê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 installchạ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.envnằ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
 

