Thứ ba, 05/03/2019 | 00:00 GMT+7

Giữ lại một ứng dụng Node.js để 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ố dễ dàng hơn và giới thiệu các thành viên mới trong group .
  • 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 Node.js bằng Docker. Bạn sẽ tạo hai containers - một cho ứng dụng Node và một cho database MongoDB - với Docker Compose . Vì ứng dụng này hoạt động với Node và MongoDB, cài đặt của ta 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.
  • Đảm bảo rằng các thay đổi đối với mã ứng dụng hoạt động mà không cần khởi động lại.
  • Tạo database được bảo vệ bằng password và user cho dữ liệu của ứng dụng.
  • Kiên trì dữ liệu này.

Ở 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:

Bộ sưu tập cá mập hoàn chỉnh

Yêu cầu

Để làm theo hướng dẫn này, bạn cần :

Bước 1 - Nhân bản dự án và sửa đổi dependencies

Bước đầu tiên trong việc xây dựng cài đặt này sẽ là sao chép mã dự án và sửa đổi file package.json của nó, bao gồm các phụ thuộc của dự án. Ta sẽ bổ sung thêm nodemon tới của dự án devDependencies , chỉ rõ rằng ta sẽ sử dụng nó trong quá trình phát triển. Chạy ứng dụng với nodemon đảm bảo nó sẽ được tự động khởi động lại khi nào bạn áp dụng các thay đổi đối với mã của bạn .

Đầu tiên, sao chép kho lưu trữ nodejs-mongo-mongoose từ tài khoản GitHub Cộng đồng DigitalOcean . Kho lưu trữ này bao gồm mã từ cài đặt được mô tả trong Cách tích hợp MongoDB với ứng dụng Node của bạn , phần này giải thích cách tích hợp database MongoDB với ứng dụng Node hiện có bằng Mongoose .

Sao node_project repository vào một folder có tên là node_project :

  • git clone https://github.com/do-community/nodejs-mongo-mongoose.git node_project

Điều hướng đến folder node_project :

  • cd node_project

Mở file package.json của dự án bằng nano hoặc editor bạn quen dùng :

  • nano package.json

Bên dưới các phần phụ thuộc của dự án và phía trên dấu ngoặc nhọn đóng, hãy tạo một đối tượng devDependencies mới bao gồm các nodemon :

~ / node_project / package.json
... "dependencies": {     "ejs": "^2.6.1",     "express": "^4.16.4",     "mongoose": "^5.4.10"   },   "devDependencies": {     "nodemon": "^1.18.10"   }     } 

Lưu file khi bạn hoàn tất chỉnh sửa.

Với mã dự án tại chỗ và các phụ thuộc của nó đã được sửa đổi, bạn có thể chuyển sang cấu trúc lại mã cho một quy trình làm việc được tích hợp.

Bước 2 - Cấu hình ứng dụng của bạn để hoạt động với containers

Sửa đổi ứng dụng của ta cho một quy trình làm việc được chứa nghĩa là làm cho mã của ta trở nên module hơn. Các containers cung cấp khả năng di động giữa các môi trường và mã của ta phải phản ánh điều đó bằng cách được tách rời khỏi hệ điều hành cơ bản nhất có thể. Để làm điều này, ta sẽ cấu trúc lại mã của bạn để sử dụng nhiều hơn thuộc tính process.env của Node, thuộc tính này sẽ trả về một đối tượng với thông tin về môi trường user của bạn trong thời gian chạy. Ta có thể sử dụng đối tượng này trong mã của bạn để gán động thông tin cấu hình trong thời gian chạy với các biến môi trường.

Hãy bắt đầu với app.js , điểm nhập ứng dụng chính của ta . Mở tập tin:

  • nano app.js

Bên trong, bạn sẽ thấy định nghĩa cho hằng số port , cũng như hàm listen sử dụng hằng số này để chỉ định cổng mà ứng dụng sẽ lắng nghe:

~ / home / node_project / app.js
... const port = 8080; ... app.listen(port, function () {   console.log('Example app listening on port 8080!'); }); 

Hãy xác định lại hằng số port để cho phép gán động trong thời gian chạy bằng cách sử dụng đối tượng process.env . áp dụng các thay đổi sau đối với định nghĩa không đổi và hàm listen :

~ / home / node_project / app.js
... const port = process.env.PORT || 8080; ... app.listen(port, function () {   console.log(`Example app listening on ${port}!`); }); 

Định nghĩa hằng số mới của ta chỉ định port động bằng cách sử dụng giá trị được truyền vào lúc chạy hoặc 8080 . Tương tự như vậy, ta đã viết lại hàm listen để sử dụng một ký tự mẫu , sẽ nội suy giá trị cổng khi lắng nghe các kết nối. Bởi vì ta sẽ ánh xạ các cổng của bạn ở nơi khác, những bản sửa đổi này sẽ ngăn ta phải liên tục sửa đổi file này khi môi trường của ta thay đổi.

Khi bạn hoàn tất chỉnh sửa, hãy lưu file .

Tiếp theo, ta sẽ sửa đổi thông tin kết nối database của bạn để xóa bất kỳ thông tin đăng nhập cấu hình nào. Mở file db.js , chứa thông tin sau:

  • nano db.js

Hiện tại, file thực hiện những việc sau:

  • Nhập Mongoose, Trình lập bản đồ tài liệu đối tượng (ODM) mà ta đang sử dụng để tạo schemas và mô hình cho dữ liệu ứng dụng của ta .
  • Đặt thông tin xác thực database làm hằng số, bao gồm tên user và password .
  • Kết nối với database bằng phương thức mongoose.connect .

Để biết thêm thông tin về file , vui lòng xem Bước 3 của Cách tích hợp MongoDB với Ứng dụng Node của bạn .

Bước đầu tiên của ta khi sửa đổi file sẽ là xác định lại các hằng số bao gồm thông tin nhạy cảm. Hiện tại, các hằng số này trông giống như sau:

~ / node_project / db.js
... const MONGO_USERNAME = 'sammy'; const MONGO_PASSWORD = 'your_password'; const MONGO_HOSTNAME = '127.0.0.1'; const MONGO_PORT = '27017'; const MONGO_DB = 'sharkinfo'; ... 

Thay vì mã hóa cứng thông tin này, bạn có thể sử dụng đối tượng process.env để nắm bắt các giá trị thời gian chạy cho các hằng số này. Sửa đổi khối để trông như thế này:

~ / node_project / db.js
... const {   MONGO_USERNAME,   MONGO_PASSWORD,   MONGO_HOSTNAME,   MONGO_PORT,   MONGO_DB } = process.env; ... 

Lưu file khi bạn hoàn tất chỉnh sửa.

Đến đây, bạn đã sửa đổi db.js để hoạt động với các biến môi trường của ứng dụng, nhưng bạn vẫn cần một cách để chuyển các biến này vào ứng dụng của bạn . Hãy tạo một file .env với các giá trị mà bạn có thể chuyển vào ứng dụng của bạn trong thời gian chạy.

Mở tập tin:

  • nano .env

Tệp này sẽ bao gồm thông tin mà bạn đã xóa khỏi db.js : tên user và password cho database ứng dụng của bạn, cũng như cài đặt cổng và tên database . Hãy nhớ cập nhật tên user , password và tên database được liệt kê ở đây với thông tin của bạn :

~ / node_project / .env
MONGO_USERNAME=sammy MONGO_PASSWORD=your_password MONGO_PORT=27017 MONGO_DB=sharkinfo 

Lưu ý ta đã xóa cài đặt server lưu trữ ban đầu xuất hiện trong db.js Bây giờ ta sẽ xác định server của bạn ở cấp file Docker Compose, cùng với thông tin khác về các dịch vụ và containers của ta .

Lưu file này khi bạn hoàn tất chỉnh sửa.

Vì file .env của bạn có chứa thông tin nhạy cảm, bạn cần đảm bảo nó có trong các .dockerignore.gitignore của dự án để nó không sao chép vào containers hoặc điều khiển version của bạn.

Mở file .dockerignore của bạn:

  • nano .dockerignore

Thêm dòng sau vào cuối file :

~ / node_project / .dockerignore
... .gitignore .env 

Lưu file khi bạn hoàn tất chỉnh sửa.

Tệp .gitignore trong repository lưu trữ này đã bao gồm .env , nhưng hãy kiểm tra xem nó có ở đó không:

  • nano .gitignore
~~ / node_project / .gitignore
... .env ... 

Đến đây, bạn đã extract thành công thông tin nhạy cảm từ mã dự án của bạn và thực hiện các biện pháp để kiểm soát cách thức và vị trí thông tin này được sao chép. Như vậy, bạn có thể tăng cường độ mạnh mẽ hơn cho mã kết nối database của bạn để tối ưu hóa nó cho quy trình làm việc được tích hợp.

Bước 3 - Sửa đổi Cài đặt Kết nối Database

Bước tiếp theo của ta sẽ là làm cho phương thức kết nối database của ta mạnh mẽ hơn bằng cách thêm mã xử lý các trường hợp ứng dụng của ta không kết nối được với database của ta . Giới thiệu mức độ phục hồi này cho mã ứng dụng của bạn là một phương pháp được khuyến khích khi làm việc với containers bằng Soạn thư.

Mở db.js để chỉnh sửa:

  • nano db.js

Bạn sẽ thấy mã mà ta đã thêm trước đó, cùng với hằng số url cho URI kết nối của Mongo và phương thức connect Mongoose :

~ / node_project / db.js
... const {   MONGO_USERNAME,   MONGO_PASSWORD,   MONGO_HOSTNAME,   MONGO_PORT,   MONGO_DB } = process.env;  const url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=admin`;  mongoose.connect(url, {useNewUrlParser: true}); 

Hiện tại, phương thức connect của ta chấp nhận một tùy chọn yêu cầu Mongoose sử dụng trình phân tích cú pháp URL mới của Mongo. Hãy thêm một vài tùy chọn khác vào phương thức này để xác định các tham số cho các nỗ lực kết nối lại. Ta có thể làm điều này bằng cách tạo một hằng số options bao gồm thông tin liên quan, ngoài tùy chọn phân tích cú pháp URL mới. Bên dưới hằng số Mongo của bạn, hãy thêm định nghĩa sau cho hằng số options :

~ / node_project / db.js
... const {   MONGO_USERNAME,   MONGO_PASSWORD,   MONGO_HOSTNAME,   MONGO_PORT,   MONGO_DB } = process.env;  const options = {   useNewUrlParser: true,   reconnectTries: Number.MAX_VALUE,   reconnectInterval: 500,    connectTimeoutMS: 10000, }; ... 

Các reconnectTries tùy chọn bảo Mongoose để tiếp tục cố gắng để kết nối vô thời hạn, trong khi reconnectInterval xác định khoảng thời gian giữa những nỗ lực kết nối trong mili giây. connectTimeoutMS xác định 10 giây là khoảng thời gian mà trình điều khiển Mongo sẽ đợi trước khi kết nối thất bại.

Bây giờ ta có thể sử dụng hằng số options mới trong phương thức connect Mongoose để tinh chỉnh cài đặt kết nối Mongoose của bạn . Ta cũng sẽ thêm một lời hứa để xử lý các lỗi kết nối tiềm ẩn.

Hiện tại, phương thức connect Mongoose trông giống như sau:

~ / node_project / db.js
... mongoose.connect(url, {useNewUrlParser: true}); 

Xóa phương thức connect hiện có và thay thế nó bằng mã sau, bao gồm hằng số options và một lời hứa:

~ / node_project / db.js
... mongoose.connect(url, options).then( function() {   console.log('MongoDB is connected'); })   .catch( function(err) {   console.log(err); }); 

Trong trường hợp kết nối thành công, chức năng của ta ghi lại một thông báo thích hợp; nếu không nó sẽ catch và ghi lại lỗi, cho phép ta khắc phục sự cố.

Tệp đã hoàn thành sẽ giống như sau:

~ / node_project / db.js
const mongoose = require('mongoose');  const {   MONGO_USERNAME,   MONGO_PASSWORD,   MONGO_HOSTNAME,   MONGO_PORT,   MONGO_DB } = process.env;  const options = {   useNewUrlParser: true,   reconnectTries: Number.MAX_VALUE,   reconnectInterval: 500,   connectTimeoutMS: 10000, };  const url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=admin`;  mongoose.connect(url, options).then( function() {   console.log('MongoDB is connected'); })   .catch( function(err) {   console.log(err); }); 

Lưu file khi bạn đã chỉnh sửa xong.

Bây giờ, bạn đã thêm khả năng phục hồi vào mã ứng dụng của bạn để xử lý các trường hợp ứng dụng của bạn có thể không kết nối được với database của bạn. Với mã này, bạn có thể chuyển sang xác định các dịch vụ của bạn với Soạn thư.

Bước 4 - Xác định Dịch vụ với Docker Compose

Với mã của bạn đã được cấu trúc lại, bạn đã sẵn sàng để ghi file docker-compose.yml với các định nghĩa dịch vụ của bạn . 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 .

Tuy nhiên, trước khi xác định các dịch vụ của bạn , ta sẽ thêm một công cụ vào dự án của bạn có tên là wait-for đảm bảo rằng ứng dụng của ta chỉ cố gắng kết nối với database của ta khi các việc khởi động database hoàn tất. Tập lệnh shell bọc này sử dụng netcat để thăm dò xem server và cổng cụ thể có chấp nhận kết nối TCP hay không. Sử dụng nó cho phép bạn kiểm soát nỗ lực của ứng dụng để kết nối với database của bạn bằng cách kiểm tra xem database đã sẵn sàng chấp nhận kết nối hay chưa.

Mặc dù tính năng Soạn thư cho phép bạn chỉ định dependencies giữa các dịch vụ bằng cách sử dụng tùy chọn depends_on , thứ tự này dựa trên việc containers có đang chạy hay không chứ không phải là tính sẵn sàng của nó. Việc sử dụng depends_on sẽ không tối ưu cho cài đặt của ta , vì ta muốn ứng dụng của bạn chỉ kết nối khi các việc khởi động database , bao gồm thêm user và password vào database xác thực admin , hoàn tất. Để biết thêm thông tin về cách sử dụng wait-for và các công cụ khác để kiểm soát thứ tự khởi động, vui lòng xem các khuyến nghị liên quan trong tài liệu Soạn .

Mở một file có tên là wait-for.sh :

  • nano wait-for.sh

Dán mã sau vào file để tạo chức năng bỏ phiếu:

~ / node_project / app / wait-for.sh
#!/bin/sh  # original script: https://github.com/eficode/wait-for/blob/master/wait-for  TIMEOUT=15 QUIET=0  echoerr() {   if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi }  usage() {   exitcode="$1"   cat << USAGE >&2 Usage:   $cmdname host:port [-t timeout] [-- command args]   -q | --quiet                        Do not output any status messages   -t TIMEOUT | --timeout=timeout      Timeout in seconds, zero for no timeout   -- COMMAND ARGS                     Execute command with args after the test finishes USAGE   exit "$exitcode" }  wait_for() {   for i in `seq $TIMEOUT` ; do     nc -z "$HOST" "$PORT" > /dev/null 2>&1      result=$?     if [ $result -eq 0 ] ; then       if [ $# -gt 0 ] ; then         exec "$@"       fi       exit 0     fi     sleep 1   done   echo "Operation timed out" >&2   exit 1 }  while [ $# -gt 0 ] do   case "$1" in     *:* )     HOST=$(printf "%s\n" "$1"| cut -d : -f 1)     PORT=$(printf "%s\n" "$1"| cut -d : -f 2)     shift 1     ;;     -q | --quiet)     QUIET=1     shift 1     ;;     -t)     TIMEOUT="$2"     if [ "$TIMEOUT" = "" ]; then break; fi     shift 2     ;;     --timeout=*)     TIMEOUT="${1#*=}"     shift 1     ;;     --)     shift     break     ;;     --help)     usage 0     ;;     *)     echoerr "Unknown argument: $1"     usage 1     ;;   esac done  if [ "$HOST" = "" -o "$PORT" = "" ]; then   echoerr "Error: you need to provide a host and port to test."   usage 2 fi  wait_for "$@" 

Lưu file khi bạn hoàn tất việc thêm mã.

Làm cho tập lệnh có thể thực thi:

  • chmod +x wait-for.sh

Tiếp theo, mở file docker-compose.yml :

  • nano docker-compose.yml

Đầu tiên, xác định dịch vụ ứng dụng nodejs bằng cách thêm mã sau vào file :

~ / node_project / docker-compo.yml
version: '3'  services:   nodejs:     build:       context: .       dockerfile: Dockerfile     image: nodejs     container_name: nodejs     restart: unless-stopped     env_file: .env     environment:       - MONGO_USERNAME=$MONGO_USERNAME       - MONGO_PASSWORD=$MONGO_PASSWORD       - MONGO_HOSTNAME=db       - MONGO_PORT=$MONGO_PORT       - MONGO_DB=$MONGO_DB      ports:       - "80:8080"     volumes:       - .:/home/node/app       - node_modules:/home/node/app/node_modules     networks:       - app-network     command: ./wait-for.sh db:27017 -- /home/node/app/node_modules/.bin/nodemon app.js 

Định nghĩa dịch vụ nodejs 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ồm contextdockerfile , 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ẫn image 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ỉ định Dockerfile 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. Để biết thêm thông tin về file này, vui lòng xem Cách tạo ứng dụng Node.js bằng Docker .
  • image , container_name : Các tên này áp dụng cho hình ảnh và containers .
  • restart : Điều này xác định policy khởi động lại. Mặc định là no , nhưng ta đã đặt containers khởi động lại trừ khi nó bị dừng.
  • 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 là .env , nằm trong ngữ cảnh xây dựng của ta .
  • environment : Sử dụng tùy chọn này cho phép bạn thêm cài đặt kết nối Mongo mà bạn đã xác định trong file .env . Lưu ý ta không đặt NODE_ENV để development , vì đây là hành vi mặc định của Express nếu NODE_ENV không được đặt. Khi chuyển sang production , bạn có thể đặt cài đặt này thành production để bật chế độ xem bộ nhớ đệm và ít thông báo lỗi dài dòng hơn . Cũng lưu ý ta đã chỉ định containers database db làm server lưu trữ, như đã thảo luận trong Bước 2 .
  • ports : Điều này ánh xạ cổng 80 trên server đến cổng 8080 trên container .
  • volumes : Ta bao gồm hai loại mount ở đây:

    • Đầu tiên là một liên kết mount gắn mã ứng dụng của ta trên server lưu trữ vào folder /home/node/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 khối được đặt tên, node_modules . Khi Docker chạy npm install hướng dẫn liệt kê trong đơn Dockerfile , npm sẽ tạo ra một mới node_modules folder trên thùng bao gồm các gói cần thiết để chạy các ứng dụng. Tuy nhiên, mount mount mà ta vừa tạo sẽ ẩn folder node_modules mới được tạo này. Vì node_modules trên server trống, liên kết sẽ ánh xạ một folder trống đến containers , overrides folder node_modules mới và ngăn ứng dụng của ta khởi động. Dung lượng node_modules được đặt tên giải quyết vấn đề này bằng cách duy trì nội dung của folder /home/node/app/node_modules và gắn nó vào containers , ẩn ràng buộc.

    Hãy ghi nhớ những điểm sau khi sử dụng phương pháp này :

    • Liên kết của bạn sẽ mount nội dung của folder node_modules trên containers vào server lưu trữ và folder này sẽ thuộc quyền sở hữu của root , vì ổ đĩa được đặt tên được tạo bởi Docker.
    • Nếu bạn có folder node_modules từ trước trên server , nó sẽ overrides folder node_modules được tạo trên containers . Cài đặt mà ta đang xây dựng trong hướng dẫn này giả định bạn không có folder node_modules từ trước và bạn sẽ không làm việc với npm trên server của bạn .Điều này phù hợp với cách tiếp cận mười hai yếu tố để phát triển ứng dụng , giúp giảm thiểu dependencies giữa các môi trường thực thi.
  • networks : Điều này chỉ định rằng dịch vụ ứng dụng của ta sẽ tham gia app-network mạng, mà ta sẽ xác định ở cuối file .

  • command : Tùy chọn này cho phép bạn đặt lệnh sẽ được thực hiện khi Compose chạy hình ảnh. Lưu ý điều này sẽ overrides hướng dẫn CMD mà ta đặt trong Dockerfile ứng dụng của ta . Ở đây, ta đang chạy ứng dụng bằng tập lệnh wait-for tập lệnh này sẽ thăm dò dịch vụ db trên cổng 27017 để kiểm tra xem dịch vụ database đã sẵn sàng hay chưa. Sau khi kiểm tra mức độ sẵn sàng thành công, tập lệnh sẽ thực thi lệnh mà ta đã đặt, /home/node/app/node_modules/.bin/nodemon app.js , để khởi động ứng dụng với nodemon . Điều này sẽ đảm bảo bất kỳ thay đổi nào trong tương lai mà ta thực hiện đối với mã của bạn đều được reload mà ta không phải khởi động lại ứng dụng.

Tiếp theo, tạo dịch vụ db bằng cách thêm mã sau vào bên dưới định nghĩa dịch vụ ứng dụng:

~ / node_project / docker-compo.yml
...   db:     image: mongo:4.1.8-xenial     container_name: db     restart: unless-stopped     env_file: .env     environment:       - MONGO_INITDB_ROOT_USERNAME=$MONGO_USERNAME       - MONGO_INITDB_ROOT_PASSWORD=$MONGO_PASSWORD     volumes:         - dbdata:/data/db        networks:       - app-network   

Một số cài đặt ta đã xác định cho dịch vụ nodejs vẫn giữ nguyên, nhưng ta cũng đã áp dụng các thay đổi sau đối với định nghĩa image , environmentvolumes :

  • image : Để tạo dịch vụ này, Compose sẽ lấy hình ảnh 4.1.8-xenial Mongo từ Docker Hub. Ta đang ghim một version cụ thể để tránh xung đột có thể xảy ra trong tương lai khi hình ảnh Mongo thay đổi. Để biết thêm thông tin về ghim version , vui lòng xem tài liệu Docker về các phương pháp hay nhất của Dockerfile .
  • MONGO_INITDB_ROOT_USERNAME , MONGO_INITDB_ROOT_PASSWORD : Hình ảnh mongo cung cấp các biến môi trường này để bạn có thể sửa đổi quá trình khởi tạo version database của bạn . MONGO_INITDB_ROOT_USERNAMEMONGO_INITDB_ROOT_PASSWORD cùng nhau tạo user root trong database xác thực admin và đảm bảo xác thực được bật khi containers khởi động. Ta đã đặt MONGO_INITDB_ROOT_USERNAMEMONGO_INITDB_ROOT_PASSWORD bằng cách sử dụng các giá trị từ file .env của ta , ta chuyển sang dịch vụ db bằng tùy chọn env_file . Làm điều này nghĩa là user ứng dụng sammy của ta sẽ là user root trên cá thể database , có quyền truy cập vào tất cả các quyền quản trị và hoạt động của role đó. Khi làm việc trong production , bạn cần tạo một user ứng dụng chuyên dụng với các quyền trong phạm vi phù hợp. Lưu ý: Lưu ý các biến này sẽ không có hiệu lực nếu bạn khởi động containers với một folder dữ liệu hiện có tại chỗ.
  • dbdata:/data/db : dbdata ổ đĩa được đặt tên sẽ giữ nguyên dữ liệu được lưu trữ trong thư mục dữ liệu mặc định của Mongo, /data/db . Điều này sẽ đảm bảo bạn không bị mất dữ liệu trong trường hợp bạn dừng hoặc xóa containers .

Ta cũng đã thêm dịch vụ db vào app-network mạng với tùy chọn networks .

Bước cuối cùng, hãy thêm định nghĩa dung lượng và mạng vào cuối file :

~ / node_project / docker-compo.yml
... networks:   app-network:     driver: bridge  volumes:   dbdata:   node_modules:   

Mạng app-network mạng cầu nối do user xác định cho phép giao tiếp giữa các containers của ta vì chúng nằm trên cùng một server Docker daemon. Điều này hợp lý hóa lưu lượng truy cập và giao tiếp trong ứng dụng, vì nó mở tất cả các cổng giữa các container trên cùng một mạng cầu, đồng thời không để lộ cổng nào ra thế giới bên ngoài. Do đó, các containers dbnodejs của ta có thể giao tiếp với nhau và ta chỉ cần để lộ cổng 80 để truy cập front-end vào ứng dụng.

Cấp cao nhất của ta volumes định nghĩa then chốt dung lượng dbdatanode_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 ổ đĩa dbdata ngay cả khi ta xóa và tạo lại containers db .

Tệp docker-compose.yml đã hoàn thành sẽ giống như sau:

~ / node_project / docker-compo.yml
version: '3'  services:   nodejs:     build:       context: .       dockerfile: Dockerfile     image: nodejs     container_name: nodejs     restart: unless-stopped     env_file: .env     environment:       - MONGO_USERNAME=$MONGO_USERNAME       - MONGO_PASSWORD=$MONGO_PASSWORD       - MONGO_HOSTNAME=db       - MONGO_PORT=$MONGO_PORT       - MONGO_DB=$MONGO_DB     ports:       - "80:8080"     volumes:       - .:/home/node/app       - node_modules:/home/node/app/node_modules     networks:       - app-network     command: ./wait-for.sh db:27017 -- /home/node/app/node_modules/.bin/nodemon app.js     db:     image: mongo:4.1.8-xenial     container_name: db     restart: unless-stopped     env_file: .env     environment:       - MONGO_INITDB_ROOT_USERNAME=$MONGO_USERNAME       - MONGO_INITDB_ROOT_PASSWORD=$MONGO_PASSWORD     volumes:            - dbdata:/data/db     networks:       - app-network    networks:   app-network:     driver: bridge  volumes:   dbdata:   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, bạn đã sẵn sàng để bắt đầu ứ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 . 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 containers bằng docker-compose down .

Đầ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 , sau đó sẽ chạy các containers nodejsdb trong nền:

  • docker-compose up -d

Bạn sẽ thấy kết quả xác nhận các dịch vụ của bạn đã được tạo:

Output
... Creating db ... done Creating nodejs ... done

Bạn cũng có thể nhận được thông tin chi tiết hơn 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 :

Output
... nodejs | [nodemon] starting `node app.js` nodejs | Example app listening on 8080! nodejs | MongoDB is connected ... db | 2019-02-22T17:26:27.329+0000 I ACCESS [conn2] Successfully authenticated as principal sammy on admin

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 ---------------------------------------------------------------------- db docker-entrypoint.sh mongod Up 27017/tcp nodejs ./wait-for.sh db:27017 -- ... Up 0.0.0.0:80->8080/tcp

Khi các dịch vụ của bạn đang chạy, bạn có thể truy cập http:// your_server_ip trong trình duyệt. Bạn sẽ thấy một trang đích giống như sau:

Trang đích ứng dụng

Nhấp vào nút Nhận thông tin cá mập . Bạn sẽ thấy một trang có mẫu mục nhập, nơi bạn có thể nhập tên cá mập và mô tả về đặc điểm chung của con cá mập đó:

Biểu mẫu thông tin cá mập

Trong biểu mẫu, hãy thêm một con cá mập mà bạn chọn. Với mục đích của phần trình diễn này, ta sẽ thêm Megalodon Shark vào trường Shark NameAncient vào trường Shark Character :

Hình thức cá mập đầy

Bấm vào nút Gửi . Bạn sẽ thấy một trang với thông tin cá mập này được hiển thị lại cho bạn:

Đầu ra cá mập

Bước cuối cùng, ta có thể kiểm tra xem dữ liệu bạn vừa nhập sẽ tồn tại nếu bạn xóa containers database của bạn .

Quay lại terminal của bạn, nhập lệnh sau để dừng và xóa containers và mạng của bạn:

  • docker-compose down

Lưu ý ta không bao gồm tùy chọn --volumes ; do đó, dung lượng dbdata 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:

Output
Stopping nodejs ... done Stopping db ... done Removing nodejs ... done Removing db ... done Removing network node_project_app-network

Tạo lại các containers :

  • docker-compose up -d

Bây giờ quay trở lại biểu mẫu thông tin cá mập:

Biểu mẫu thông tin cá mập

Nhập một con cá mập mới mà bạn chọn. Ta sẽ đi với Whale SharkLarge :

Tham gia Shark mới

Khi bạn nhấp vào Gửi , bạn sẽ thấy rằng con cá mập mới đã được thêm vào bộ sưu tập cá mập trong database của bạn mà không làm mất dữ liệu bạn đã nhập:

Bộ sưu tập cá mập hoàn chỉnh

Ứ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.

Kết luận

Theo hướng dẫn này, bạn đã tạo cài đặt phát triển cho ứng dụng Node của bạn bằng cách sử dụng containers Docker. Bạn đã làm cho dự án của bạn có tính module và di động hơn bằng cách extract thông tin nhạy cảm và tách trạng thái của ứng dụng khỏi mã ứng dụng của bạn. Bạn cũng đã cấu hình 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Ứng dụng hiện đại hóa cho Kubernetes để biết thêm thông tin về các chủ đề này.

Để tìm hiểu thêm về mã được sử dụng trong hướng dẫn này, vui lòng xem Cách tạo ứng dụng Node.js với DockerCách tích hợp MongoDB với ứng dụng Node của bạn . Để biết thông tin về cách triển khai ứng dụng Node với Reverse Proxy Nginx bằng cách sử dụng containers , vui lòng xem Cách bảo mật ứng dụng Node.js bị chứa bằng Nginx, Let's Encrypt và Docker Compose .


Tags:

Các tin liên quan

Cách cài đặt và sử dụng Docker Compose trên CentOS 7
2019-01-23
Cách sử dụng Traefik làm reverse-proxy cho container Docker trên Debian 9
2019-01-08
Cách thiết lập registry Docker riêng trên Ubuntu 18.04
2019-01-07
Cách thiết lập triển khai nhiều node với Rancher 2.1, Kubernetes và Docker Machine trên Ubuntu 18.04
2019-01-03
Cách tạo ứng dụng Node.js với Docker
2018-11-29
Cách quản lý triển khai nhiều node với Máy Rancher và Docker trên Ubuntu 16.04
2018-10-30
Cách cài đặt và sử dụng Docker trên Ubuntu 16.04
2018-10-19
Cách cung cấp và quản lý server Docker từ xa bằng Máy Docker trên Ubuntu 18.04
2018-10-02
Cách cài đặt và bảo mật OpenFaaS bằng Docker Swarm trên Ubuntu 16.04
2018-09-19
Cách cài đặt Docker Compose trên Debian 9
2018-09-06