Phần mềm chứa phần mềm đóng gói nó thành các đơn vị tiêu chuẩn hóa để dễ phát triển và triển khai. Các vùng chứa gói mã từ ứng dụng của bạn lại với nhau, cùng với tất cả các phần phụ thuộc của nó. Một thùng chứa có thể đứng độc lập hoàn toàn; nó chứa một gói với phần mềm của bạn, môi trường thời gian chạy và các thư viện hệ thống. Vùng chứa giúp các nhà phát triển và nhóm vận hành đảm bảo rằng phần mềm chạy giống nhau, bất kể môi trường của nó là gì. Bằng cách tách mã khỏi cơ sở hạ tầng, các ứng dụng được "container hóa" sẽ chạy giống nhau trong môi trường cục bộ, môi trường thử nghiệm và sản xuất.
Docker là một trong những nền tảng phổ biến nhất để phát triển và triển khai phần mềm. Docker đóng gói phần mềm dưới dạng "hình ảnh", phần mềm này được biến thành một vùng chứa trong thời gian chạy khi được thực thi trên Hình ảnh Docker. Sự cô lập cho phép các nhà phát triển chạy nhiều vùng chứa trên một máy chủ lưu trữ cùng một lúc.
Các nhà phát triển đường ray phải đối mặt với một loạt thách thức duy nhất khi chứa một ứng dụng hiện có. Bài viết này sẽ cung cấp hướng dẫn về cách chứa một ứng dụng Rails chức năng và giải thích các khái niệm và cạm bẫy quan trọng trong quá trình thực hiện. Bài viết này không phải là mô tả cơ bản về vùng chứa hoặc Docker; thay vào đó, nó là lời giải thích về các vấn đề mà các nhà phát triển gặp phải khi chứa các ứng dụng sản xuất.
Điều kiện tiên quyết
Nếu bạn đang theo dõi, thì rõ ràng bạn sẽ cần một ứng dụng Rails chưa được làm dày (đó là thuật ngữ dành riêng cho docker dành cho 'container'). Tôi sẽ sử dụng RailsWork, một dự án phụ đầy đủ tính năng mà tôi chỉ ra mắt. Đó là một bảng công việc được viết bằng Rails và được triển khai cho Heroku, nhưng nó không được chứa trong hộp đựng.
Ngoài ra, bạn cũng sẽ cần phải cài đặt Docker. Một cách phổ biến để cài đặt nó là với Docker Desktop, có thể tải xuống qua trang web chính thức.
Sau khi ứng dụng được tải xuống, hãy chạy trình cài đặt. Sau khi chạy, nó sẽ nhắc bạn kéo ứng dụng vào thư mục ứng dụng của bạn. Sau đó, bạn sẽ phải khởi chạy ứng dụng từ thư mục ứng dụng của mình và cấp cho nó các quyền đặc quyền mà nó yêu cầu. Là lần kiểm tra cuối cùng để đảm bảo Docker được cài đặt đúng cách, hãy thử liệt kê các vùng chứa đang chạy trên máy của bạn từ thiết bị đầu cuối của bạn bằng cách chạy như sau:
docker ps
Nếu Docker được cài đặt (và bạn không chạy bất kỳ vùng chứa nào), bạn sẽ nhận được một danh sách trống chỉ với các tiêu đề giống như sau:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Dockerfile
Điều quan trọng là phải bắt đầu với thuật ngữ rõ ràng trước khi chúng ta đi sâu vào quá sâu.
Sau khi ứng dụng Rails của bạn được "Tài liệu hóa", nó sẽ chạy trong vùng chứa . Một vùng chứa đứng riêng, có thể thay thế và thường được xây dựng lại.
Vùng chứa được tạo từ hình ảnh . Hình ảnh là một ảnh chụp nhanh ảo của hệ thống tệp được ghép nối với siêu dữ liệu.
A Dockerfile là mã nguồn mô tả cách tạo hình ảnh. Dockerfiles thường được bao gồm trong kho lưu trữ của ứng dụng Dockerized và được theo dõi trong kiểm soát phiên bản cùng với phần còn lại của ứng dụng.
Tạo một Dockerfile dễ dàng hơn âm thanh! Docker cung cấp cho chúng ta cú pháp đặc biệt giúp loại bỏ công việc khó khăn trong việc chứa đựng một thứ gì đó. Trước tiên, hãy truy cập vào thư mục gốc của ứng dụng bạn muốn chứa. Bây giờ bạn đã sẵn sàng bắt đầu làm việc, bạn nên tạo một nhánh mới nếu bạn đang sử dụng git. Bạn có thể dễ dàng tạo một nhánh mới với tên dockerize-this-app
bằng cách chạy như sau:
git checkout -b dockerize-this-app
Tiếp theo, tạo một Dockerfile và hướng nó xây dựng một hình ảnh dựa trên ứng dụng Ruby. Điều này có thể được thực hiện từ dòng lệnh bằng cách chạy như sau:
echo "FROM ruby:3.0.0" > Dockerfile
Ở đây, chúng ta chỉ tạo Dockerfile và thêm một dòng chỉ định nơi tìm hình ảnh vùng chứa Ruby. Dự án của tôi sử dụng Ruby 3.0.0, vì vậy tôi đã sử dụng hình ảnh thích hợp. Nếu bạn đang sử dụng phiên bản Ruby khác, không có vấn đề gì. Docker có một danh sách tất cả các hình ảnh được hỗ trợ.
Tiếp theo, hướng dẫn Docker tạo hình ảnh Docker theo cách thủ công:
docker build -t rails_work .
Tại đây, bạn có thể thay thế rails_work
với bất kỳ tên nào bạn muốn cho hình ảnh. Ngoài ra, hãy nhớ bao gồm dấu chấm ở cuối!
Nếu bạn muốn thấy rằng hình ảnh đã được tạo, bạn có thể liệt kê các hình ảnh trên hệ thống của mình như sau:
docker image list
Mặc dù vậy, hình ảnh này hầu như trống rỗng; nó hiện không chứa ứng dụng của chúng tôi. Chúng tôi có thể hướng dẫn nó thêm mã từ ứng dụng của chúng tôi bằng cách thêm phần sau vào Dockerfile vào cuối:
ADD . /rails_work
WORKDIR /rails_work
RUN bundle install
Thao tác này sao chép các tệp từ ứng dụng của bạn và cài đặt các phần phụ thuộc của ứng dụng. (Tại đây, bạn sẽ thay thế rails_work
với tên ứng dụng của bạn.)
Tại thời điểm này, bạn nên chạy lại lệnh để tạo hình ảnh:
docker image list
Có một khả năng xảy ra sự cố ở đây , đặc biệt nếu bạn đang làm điều này với một ứng dụng sản xuất hiện có. Bundler có thể phàn nàn rằng phiên bản Bundler mà hình ảnh đang cố gắng sử dụng khác với phiên bản đã tạo Gemfile.lock
tập tin. Nếu điều này xảy ra, bạn có hai lựa chọn rõ ràng:
- Thay đổi phiên bản hình ảnh đang sử dụng.
- Xóa
Gemfile.lock
toàn bộ. ** Nếu bạn làm điều này, hãy nhớ ghim bất kỳ phiên bản Đá quý nào bạn cần ở các phiên bản cụ thể, vì tệp khóa sẽ được tạo lại hoàn toàn.
Nếu cài đặt gói của bạn vẫn không thành công, thì bạn có thể cần một số cài đặt bổ sung trong Dockerfile :
RUN apt-get update && apt-get install -y shared-mime-info
Nếu bạn vẫn gặp sự cố, có thể bạn đã chọn nhầm hình ảnh Ruby để làm cơ sở cho , vì vậy bạn nên bắt đầu điều tra ở đó.
Đây là cơ hội tốt để đặt các biến môi trường :
ENV RAILS_ENV production
ENV RAILS_SERVE_STATIC_FILES true
Tiếp theo, thêm một dòng để hiển thị cổng 3000, đó là nơi Rails chạy theo mặc định:
EXPOSE 3000
Cuối cùng, hướng dẫn vùng chứa mở bash shell khi nó khởi động:
CMD ["bash"]
Nhìn chung, Dockerfile của bạn sẽ trông như thế này (với tên rails_work được thay thế):
FROM ruby:3.0.0
ADD . /rails_work
WORKDIR /rails_work
RUN bundle install
ENV RAILS_ENV production
ENV RAILS_SERVE_STATIC_FILES true
EXPOSE 3000
CMD ["bash"]
Giải thích các lệnh Docker
Chắc chắn sẽ hữu ích khi hiểu đầy đủ về một số lệnh Dockerfile phổ biến nhất.
- FROM -> Điều này xác định hình ảnh nào sẽ dựa trên.
- RUN -> Thao tác này thực thi các lệnh bên trong thùng chứa.
- ENV -> Điều này xác định các biến môi trường.
- WORKDIR -> Điều này thay đổi thư mục mà vùng chứa đang sử dụng.
- CMD -> Chỉ định chương trình nào sẽ chạy khi vùng chứa bắt đầu.
Docker Compose
Theo tài liệu của Docker, "Compose" là công cụ của họ để tạo (và khởi động) các ứng dụng có nhiều vùng chứa Docker. Mọi thứ cần thiết để tạo ra các vùng chứa cần thiết của ứng dụng được phác thảo trong YAML. Khi ai đó chạy docker-compose up
, các thùng chứa được tạo ra! Docker-compos cho phép chúng tôi mô tả một cách khai báo cấu hình vùng chứa của mình.
Trước khi tạo tệp Docker Compose của bạn, điều quan trọng là phải chỉ ra cho Docker những tệp nào nên được loại trừ khỏi hình ảnh được tạo. Tạo một tệp có tên .dockerignore
. (Lưu ý dấu chấm!) Trong tệp này, hãy dán như sau:
.git
.dockerignore
.env
Nếu Gemfile của bạn được duy trì bởi quá trình xây dựng, hãy đảm bảo thêm Gemfile.lock
bỏ qua ở trên.
Tiếp theo, tạo một tệp có tên là docker-compose.yml
. Đây là nơi chúng tôi sẽ mô tả cấu hình vùng chứa của chúng tôi. Chúng tôi sẽ bắt đầu với điều này cho nội dung của tệp:
version: '3.8'
services:
db:
image: postgres
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
volumes:
- postgres:/var/lib/postgresql/data
web:
build: .
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/Rails-Docker
ports:
- "3000:3000"
depends_on:
- db
volumes:
postgres:
Tệp này tạo ra hai dịch vụ:một dịch vụ được gọi là db
và cái còn lại được gọi là web
. Vùng chứa db sẽ được tạo từ một hình ảnh tạo sẵn dành cho bưu điện và bạn nên thay thế các giá trị có liên quan cho POSTGRES_USER
và POSTGRES_PASSWORD
. Bạn nên cẩn thận không đưa bí mật sản xuất trong tệp này - hãy xem phần "Bí mật quản lý" bên dưới để biết thêm thông tin về điều đó.
Vùng chứa web được xây dựng từ Dockerfile của chúng tôi và sau đó khởi động máy chủ Rails trên cổng 3000 tại địa chỉ IP 0.0.0.0. Cổng nội bộ 3000 sau đó được ánh xạ tới cổng thực tế 3000.
Và cuối cùng, chúng tôi có một khối lượng Postgres để duy trì dữ liệu cho chúng tôi.
Quản lý bí mật
Xác thực tại thời điểm xây dựng có thể là một vấn đề đối với các ứng dụng sản xuất. Có lẽ ứng dụng của bạn tìm kiếm Đá quý từ một kho lưu trữ riêng hoặc bạn chỉ cần lưu trữ thông tin đăng nhập cơ sở dữ liệu.
Mọi thông tin trực tiếp trong Dockerfile sẽ vĩnh viễn được đưa vào hình ảnh vùng chứa, và đây là một lỗi bảo mật phổ biến.
Nếu bạn đang sử dụng trình quản lý thông tin đăng nhập của Rails, thì việc cấp cho Docker (hoặc bất kỳ máy chủ nào cho vấn đề đó) quyền truy cập là tương đối nhỏ. Trong tệp Docker Compose, bạn chỉ cần cung cấp RAILS_MASTER_KEY
biến môi trường. Đối với mục tiêu soạn thư nhất định, bạn chỉ định khóa trong environment
tiêu đề mà bạn cần tạo nếu chưa có. Sau đó, tập tin docker-compile từ bên trên sẽ trở thành như sau:
version: '3.8'
services:
db:
image: postgres
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
volumes:
- postgres:/var/lib/postgresql/data
web:
build: .
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/Rails-Docker
ports:
- "3000:3000"
depends_on:
- db
environment:
- RAILS_MASTER_KEY=this_would_be_the_key
volumes:
postgres:
Bây giờ, điều này khiến bạn ở ngã ba đường. Bạn có thể muốn có tệp này được cam kết với quyền kiểm soát nguồn, nhưng bạn chắc chắn không muốn khóa chính hoặc thậm chí mật khẩu cơ sở dữ liệu của bạn bị kiểm soát nguồn theo dõi , vì đây sẽ là một vấn đề bảo mật nguy hiểm khác. Giải pháp tốt nhất cho đến nay sẽ là sử dụng đá quý dotenv để bạn có thể truy cập các thông tin đăng nhập này bằng proxy, lưu trữ chúng trong một tệp khác không được kiểm soát nguồn theo dõi.
Chạy Ứng dụng Tài liệu hóa
Cuối cùng, bạn có thể chạy ứng dụng được quét vôi hóa bằng lệnh sau:
docker compose up
Tin hay không tùy bạn, đó là nó! Docker-comp giúp dễ dàng xoay vòng một vùng chứa, đặc biệt là khi nói đến các đối số dòng lệnh.
Nếu bạn muốn có một danh sách các vùng chứa đang chạy, chỉ cần chạy như sau:
docker ps
Nếu tên vùng chứa Rails của bạn là web
, bạn có thể thực hiện các lệnh trên nó một cách khá đơn giản. Ví dụ:nếu bạn muốn chạy bảng điều khiển Rails, tất cả những gì bạn cần làm là chạy như sau:
docker exec -it web rails console
Nếu bạn chỉ muốn có một bash shell bên trong vùng chứa, thay vào đó bạn nên chạy như sau:
docker exec -it web bash
Một số cạm bẫy khác giống như những cạm bẫy được liệt kê ở đây
Một vấn đề phổ biến với các ứng dụng Rails được pha trộn trong sản xuất là xử lý các bản ghi. Chúng không nên ở trong hệ thống container lâu dài. Docker gợi ý rằng các bản ghi chỉ cần được chuyển hướng đến STDOUT. Điều này có thể được định cấu hình rõ ràng trong config/application.rb
.
Một vấn đề phổ biến khác là của người gửi thư. Nếu ứng dụng của bạn sử dụng thư, bạn phải xác định rõ ràng cài đặt kết nối . SMTP là một phương thức phân phối hoàn toàn tốt và thường hoạt động tốt với các giá trị mặc định, nhưng chúng tôi phải cẩn thận đặt vị trí máy chủ và các cài đặt khác để phù hợp với cấu hình vùng chứa của chúng tôi.
Nếu bạn có công nhân hoặc công việc cơ bản, chẳng hạn như sidekiq , thì bạn phải chạy nó trong vùng chứa của chính nó.
Kết luận
Việc chứa một ứng dụng Rails sản xuất đi kèm với một loạt thách thức, như bạn đã thấy. Khi ứng dụng của bạn đã phát triển, nó có thể đã tích lũy một số phụ thuộc khiến việc di chuyển như thế này trở nên khó khăn. Cho dù đó là nhân viên nền tảng, người đưa thư hay bí mật, có những khuôn mẫu đã được thiết lập để xử lý hầu hết các cạm bẫy. Khi công việc ban đầu của việc tạo ứng dụng sản xuất hoạt động với Docker hoàn tất, việc dễ dàng thay đổi và triển khai trong tương lai sẽ khiến khoản đầu tư trở nên đáng giá.