Shipit là một công cụ hữu ích giúp tự động hóa quy trình triển khai ứng dụng Node.js từ môi trường làm việc sang môi trường production. Để có thể hiểu rõ hơn, hãy cùng tìm hiểu bài viết về cách tự động hóa triển khai Node js với Shipit trên CentOS 7 dưới đây của Vietnix nhé.
Yêu cầu để có thể tự động hóa triển khai Node js với Shipit trên CentOS 7
- Hai server CentOS 7 (gọi là là app và web) được cấu hình với private networking.
- Nginx (ở web server của bạn) được bảo mật bởi TLS / SSL.
- Cài đặt Node.js và npm vào môi trường làm việc của bạn. Ở bài viết này sẽ sử dụng Node.js phiên bản 10.17.0. Sau khi cài đặt Node.js, bạn cũng đã cài đặt được npm và phiên bản sử dụng sẽ là 6.11.3.
- Cài đặt
rsync
vàgit
vào thiết bị của bạn, lưu ý: - Một tài khoản Github hoặc bất kỳ nhà cung cấp dịch vụ
git
khác. Ở bài viết này, sẽ sử dụng GitHub.
Lưu ý: Đối với người dùng Windows sẽ cần phải cài đặt Windows Subsystem for Linux để thực hiện các lệnh trong bài hướng dẫn này.
Nếu bạn đang có nhu cầu triển khai ứng dụng Node.js với Shipit trên CentOS 7 nhưng chưa có máy chủ, hãy tham khảo các gói dịch vụ VPS của Vietnix. Hiện tại, Vietnix đang cung cấp các gói dịch vụ thuê máy ảo (VPS) hỗ trợ hệ điều hành CentOS 7, cấu hình đa dạng, chi phí hợp lý, giúp bạn dễ dàng lựa chọn được gói dịch vụ phù hợp với nhu cầu.
Ngoài ra, với sự hỗ trợ của đội ngũ Vietnix, việc triển khai và quản lý máy chủ của bạn sẽ trở nên dễ dàng và dễ dàng hơn. Liên hệ tư vấn và đăng ký ngay để trải nghiệm sự ổn định và tốc độ cao của các gói dịch vụ VPS tại Vietnix.
Xem thêm: Hướng dẫn cài đặt NodeJS trên CentOS 7
Bước 1: Thiết lập remote repository (kho lưu trữ từ xa)
Shipit cần có Git repository để đồng bộ hóa giữa máy tính của bạn và remote server. Ở bước này, bạn sẽ tạo một remote repository tại Github.com
. Mỗi nhà cung cấp sẽ có phần khác biệt về cách sử dụng dịch vụ git, tuy nhiên các lệnh dùng để tạo kho lưu trữ và các thao tác trên đó, giữa các nhà cung cấp, cơ bản là giống nhau.
Để tạo repository, bạn hãy mở Github.com
trong trình duyệt web và đăng nhập hoặc đăng ký nếu bạn chưa có tài khoản. Click chuột vào dấu + ở góc trên bên phải của giao diện. Sau đó chọn New repository.
Hãy nhập tên một cách ngắn gọn, dễ nhớ cho repository của bạn, ví dụ: hello-world
. Lưu ý rằng tên của repository mà bạn vừa nhập, sẽ được sử dụng để đặt tên cho thư mục chứa project, và thư mục này sẽ được lưu trữ ở máy tính của bạn.
Bạn có thể nhập một số thông tin để mô tả về repository của mình.
Sau đó, hãy thiết lập chế độ hiển thị của repository, chọn public (công khai) hoặc private (riêng tư) tùy theo nhu cầu sử dụng của bản thân.
Để file .gitignore
được khởi tạo trong repository của bạn, hãy chọn Node
trong mục Add .gitignore
. Điều này rất quan trọng vì bạn sẽ tránh được việc thêm các file không cần thiết (như thư mục node_modules
) vào repository của mình.
Tiếp theo, nhấp vào nút Create repository để hoàn tất.
Bạn clone repository từ Github.com
sang máy tính.
Tiến hành mở terminal và điều hướng đến vị trí của thư mục mà bạn muốn lưu trữ toàn bộ các file project Node.js của mình. Lưu ý rằng quá trình này sẽ tạo ra một thư mục con trong thư mục mà bạn vừa chọn để lưu trữ. Để clone repository vào máy tính, hãy thực thi lệnh sau:
git clone https://github.com/your-github-username/your-github-repository-name.git
Bạn hãy thay thế your-github-username
và your-github-repository-name
bằng username của mình trên Github và tên repository mà bạn vừa tạo trước đó.
Lưu ý: Nếu bạn đã bật two-factor authentication (2FA) ( xác thực 2 yếu tố ) trên Github.com
, bạn phải sử dụng mã personal access token hoặc SSH key thay vì sử dụng mật khẩu khi truy cập Github bằng dòng lệnh.
Bạn sẽ nhận được output như sau:
Output
Cloning into 'your-github-repository-name'...
remote: Enumerating objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 3
Unpacking objects: 100% (3/3), done.
Điều hướng đến repository bằng cách chạy lệnh sau:
cd your-github-repository-name
Bên trong repository sẽ chứa một tệp và thư mục, cả hai đều được Git sử dụng để quản lý repository. Bạn có thể xác minh việc này bằng cách chạy câu lệnh sau:
ls -la
Output sẽ hiển thị như sau:
Output
total 8
0 drwxr-xr-x 4 asciant staff 128 22 Apr 07:16 .
0 drwxr-xr-x 5 asciant staff 160 22 Apr 07:16 ..
0 drwxr-xr-x 13 asciant staff 416 22 Apr 07:16 .git
8 -rw-r--r-- 1 asciant staff 914 22 Apr 07:16 .gitignore
Xem thêm: Hướng dẫn cách thiết lập ứng dụng Node.js trên CentOS 7 cho môi trường production
Bước 2: Tích hợp Shipit vào Node.js Project
Ở bước này, bạn sẽ tạo một Node.js project. sau đó thêm các Shipit package. Sau đây, sẽ là một ví dụ cho bạn như sau: Node.js web server chấp nhận các yêu cầu HTTP và phản hồi với Hello World
bằng văn bản. Để tạo ứng dụng (đặt tên là hello.js), hãy thực thi lệnh sau:
nano hello.js
Thêm đoạn code sau vào hello.js
(cập nhật biến APP_PRIVATE_IP_ADDRESS
thành địa chỉ private network IP của app server):
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(8080, 'APP_PRIVATE_IP_ADDRESS');
console.log('Server running at http://APP_PRIVATE_IP_ADDRESS:8080/');
Tạo tệp package.json
cho project của bạn bằng lệnh sau:
npm init -y
Lệnh này sẽ tạo ra một tệp package.json
mà bạn sẽ sử dụng để cấu hình ứng dụng Node.js. Tiếp theo, bạn sẽ thêm dependencies vào tệp này bằng npm
command line interface (giao diện dòng lệnh npm).
Output
Wrote to ~/hello-world/package.json:
{
"name": "hello-world",
"version": "1.0.0",
"description": "",
"main": index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Cài đặt các npm
package cần thiết bằng lệnh sau:
npm install --save-dev shipit-cli shipit-deploy shipit-shared
Do các Shipit package chỉ cần thiết trên máy tính của bạn khi phát triển ứng dụng. Vì vậy mà bạn phải sử dụng –save-dev trong lệnh cài đặt npm, sau đó bạn sẽ nhận được output như sau:
Output
+ shipit-shared@4.4.2
+ shipit-cli@4.2.0
+ shipit-deploy@4.1.4
updated 4 packages and audited 21356 packages in 11.671s
found 62 low severity vulnerabilities run `npm audit fix` to fix them, or `npm audit` for details
Việc cài đặt này sẽ tự động thêm ba package vào file package.json
của bạn dưới dạng development dependencies như sau:
. . .
"devDependencies": {
"shipit-cli": "^4.2.0",
"shipit-deploy": "^4.1.4",
"shipit-shared": "^4.4.2"
},
. . .
Bước 3: Chuẩn bị remote app server
Bạn sử dụng ssh
để kết nối với app server và cài đặt một remote dependency là rsync
. Rsync là một tiện ích cho phép chuyển đổi và đồng bộ hóa các tệp một cách hiệu quả, giữa ổ đĩa của máy tính cục bộ với các máy tính kết nối mạng, bằng cách so sánh các thay đổi về thời gian và kích thước của các file.
Shipit sử dụng rsync
để truyền và đồng bộ hóa các file giữa máy tính của bạn và remote app server. Do đó, Shipit sẽ tự động xử lý mà không cần bạn cấu hình trực tiếp.
Lưu ý: Những lệnh này chỉ nên được thực thi trên app.
Kết nối với remote app server thông qua ssh
bằng lệnh sau:
ssh deployer@your_app_server_ip
Sau đó, cài đặt rsync
trên server bằng cách thực thi lệnh dưới đây:
sudo yum install rsync
Bạn sẽ xác nhận việc cài đặt này bằng cách:
rsync --version
Một output sẽ xuất hiện như sau:
Output
rsync version 3.1.2 protocol version 31
. . .
Bạn có thể kết thúc ssh
bằng cách nhập exit
.
Sau khi cài đặt rsync
và đã được có sẵn trên command line, bạn hãy triển khai các task và tìm hiểu mối quan hệ giữa task với các event ở bước tiếp theo.
Bước 4: Cấu hình và thực thi Deployment Tasks
Cả event (sự kiện) và task (tác vụ) đều là các thành phần chính của việc triển khai bằng Shipit, và quan trọng là bạn cần hiểu rõ cách chúng bổ sung cho việc phát triển ứng dụng của mình. Các event được kích hoạt bởi Shipit, đại diện cho các điểm cụ thể trong vòng đời của quá trình triển khai. Các task sẽ thực thi theo trình tự dựa trên vòng đời của Shipit, để đáp ứng cho những event này.
Một ví dụ thường gặp về sự hữu ích của hệ thống task/event trong ứng dụng Node.js là cài đặt dependencies của ứng dụng (node_modules
) trên remote server. Tại bước này, về sau bạn sẽ cho Shipit lắng nghe event đã được update
(được thực hiện sau khi các tệp của ứng dụng được truyền đi) và chạy một task để cài đặt dependencies của ứng dụng (npm install
) trên remote server.
Để có thể lắng nghe các event và thực thi các task, Shipit cần một file cấu hình chứa thông tin về remote server (app server) của bạn và đăng ký trình lắng nghe events cùng với lệnh được thực thi bởi các task. File này sẽ được lưu trữ trong thư mục ứng dụng Node.js trên máy tính của bạn.
Bạn tạo file chứa thông tin về remote server của mình, trình lắng nghe events mà bạn muốn đăng ký và một số định nghĩa về task, ở đây, sẽ đặt tên là shipitfile.js
và lưu trữ trong root directory của ứng dụng trên máy tính. Thực thi lệnh dưới đây để tạo tệp:
nano shipitfile.js
Hiện tại, bạn đã tạo được tệp shipitfile.js
, tuy nhiên tệp này phải lưu trữ thông tin mà Shipit cần đó là initial environment (môi trường ban đầu). Chủ yếu là vị trí lưu trữ của remote Git
repository và quan trọng là địa chỉ public IP của app server và tài khoản người dùng SSH của bạn.
Bạn hãy thêm đoạn cấu hình sau đây và cập nhật một số thông tin ở dòng deployTo, repositoryUrl, servers, để phù hợp với môi trường làm việc của mình:
module.exports = shipit => {
require('shipit-deploy')(shipit);
require('shipit-shared')(shipit);
const appName = 'hello';
shipit.initConfig({
default: {
deployTo: '/home/vietnix/your-domain',
repositoryUrl: 'https://git-provider.tld/YOUR_GIT_USERNAME/YOUR_GIT_REPO_NAME.git',
keepReleases: 5,
shared: {
overwrite: true,
dirs: ['node_modules']
}
},
production: {
servers: 'vietnix@YOUR_APP_SERVER_PUBLIC_IP'
}
});
const path = require('path');
const ecosystemFilePath = path.join(
shipit.config.deployTo,
'shared',
'ecosystem.config.js'
);
// Our listeners and tasks will go here
};
Việc cập nhật variables
trong phương thức shipit.initConfig
sẽ cung cấp cho Shipit các cấu hình cụ thể cho việc triển khai của bạn. Đối với Shipit thì ý nghĩa của các variables
như sau:
deployTo
: Là thư mục mà Shipit sẽ deploy code của ứng dụng lên remote server. Ở đây, bạn sẽ sử dụng thư mục/home/
cho người dùng non-root với quyềnsudo
(/home/vietnix
) để đảm bảo an toàn và tránh được các vấn đề về quyền truy cập./your-domain
là một quy ước về đặt tên thư mục để phân biệt với các thư mục khác.repositoryUrl
: Biến này sẽ lưu URL dẫn đến Git repository trên trình duyệt, Shipit sẽ sử dụng URL này để đảm bảo các tệp project được đồng bộ hóa trước khi triển khai.keepReleases
: Là số lượng phiên bản cần lưu trên remote server. Mộtrelease
là một thư mục dạng date-stamped (đánh dấu thời gian cụ thể ) chứa các file ứng dụng của bạn vào thời điểm phát hành. Việc này sẽ hữu ích cho việcrollback
(khôi phục ) lại quá trình triển khai của ứng dụng.shared
: Tương tự nhưkeepReleases
cho phép các thư mục đượcshared
giữa các phiên bản. Trong trường hợp này, bạn có duy nhất một thư mụcnode_module
s được chia sẻ cho tất cả các phiên bản hiện có.prodution
: Đại diện cho một remote server để triển khai ứng dụng. Ở đây, bạn có duy nhất một server (app server) mà bạn đặt tên choproduction
, vớiserver
: cấu hình phù hợp với SSHuser
vàpublic ip address
. Tênprodution
, tương ứng với câu lệnh triển khai Shipit, sẽ được sử dụng ở cuối hướng dẫn này (npx shipit server name deploy
hoặc trong trường hợp của bạn sẽ lànpx shipit production deploy
).
Trước khi tiếp tục việc cập nhật trên tệp shipitfile.js
, bạn hãy xem qua đoạn code mẫu dưới đây để hiểu thêm về cách thức hoạt động của các task trong Shipit:
Example event listener
shipit.on('deploy', () => {
shipit.start('say-hello');
});
shipit.blTask('say-hello', async () => {
shipit.local('echo "hello from your local computer"')
});
Đây là một ví dụ cụ thể về task được sử dụng trong phương thức shipit.on
để khởi tạo một sự kiện deploy
. Task này sẽ đợi cho đến khi Shipit phát ra sự kiện deploy trong vòng đời của Shipit, sau khi bắt được sự kiện deploy, task sẽ thực thi phương thức shipit.start
yêu cầu Shipit tiến hành start
tác vụ say-hello
.
Phương thức shipit.on
có hai tham số, một là tên của sự kiện cần lắng nghe và hai là hàm callback để thực thi khi bắt được sự kiện.
Sau phần khai báo phương thức shipit.on
, thì một task khác cũng được được khởi tạo bằng phương thức shipit.blTask
. Việc này sẽ tạo ra một task mới, mà trong quá trình thực thi, các task khác sẽ bị chặn lại (đây là một tác vụ đồng bộ). Phương thức shipit.blTask
cũng có hai tham số đó là tên của task đang được xác định và hàm callback để thực thi khi task được kích hoạt bởi phương thức shipit.start
.
Trong hàm callback của task ở ví dụ này (say-hello
), phương thức shipit.local
sẽ thực thi lệnh trên máy tính của bạn. Output của lệnh này sẽ hiển thị dòng "hello from your local computer"
ở terminal.
Nếu bạn muốn thực thi một lệnh trên remote server, bạn sẽ sử dụng phương thức shipit.remote
. Hai phương thức là shipit.local
và shipit.remote
đều cung cấp một API, để thực thi các lệnh tương ứng trên máy tính của bạn hoặc từ xa, như một phần của quá trình triển khai.
Sau khi tìm hiểu qua về ví dụ trên, bạn cập nhật file shipitfile.js
bằng cách thêm các event listener để đăng ký vòng đời của Shipit bằng phương thức shipit.on
. Chèn các event listener vào sau cụm // Our tasks will go here
để cập nhật tệp shipitfile.js
như sau:
. . .
shipit.on('updated', () => {
shipit.start('npm-install', 'copy-config');
});
shipit.on('published', () => {
shipit.start('pm2-server');
});
Hai phương thức này sẽ lắng nghe các event được updated
và được published
như một phần của vòng đời triển khai Shipit. Khi bắt được event, các task sẽ được thực thi bằng phương thức shipit.start
, tương tự như ở ví dụ về task mà bạn vừa được tìm hiểu.
Đến đây, bạn đã khởi tạo được các listeners, tiếp theo hãy thêm các task tương ứng bằng cách chèn vào sau các event listener của tệp shipitfile.js
:
. . .
shipit.blTask('copy-config', async () => {
const fs = require('fs');
const ecosystem = `
module.exports = {
apps: [
{
name: '${appName}',
script: '${shipit.releasePath}/hello.js',
watch: true,
autorestart: true,
restart_delay: 1000,
env: {
NODE_ENV: 'development'
},
env_production: {
NODE_ENV: 'production'
}
}
]
};`;
fs.writeFileSync('ecosystem.config.js', ecosystem, function(err) {
if (err) throw err;
console.log('File created successfully.');
});
await shipit.copyToRemote('ecosystem.config.js', ecosystemFilePath);
});
Bạn cần khai báo một task gọi là copy-config
. Task này tạo một local file có tên là ecosystem.config.js
, sau đó bạn hãy sao chép tệp này vào remote app server của bạn. PM2
sử dụng ecosystem.config.js
để quản lý ứng dụng Node.js, đồng thời file này sẽ cung cấp thông tin cần thiết về đường dẫn đến PM2
, để đảm bảo rằng ứng dụng của bạn đang chạy các file được triển khai mới nhất. Trong quá trình phát triển về sau, bạn sẽ tạo một task chạy PM2
cùng với ecosystem.config.js
, và tệp này sẽ được coi là một file cấu hình.
Nếu ứng dụng của bạn cần các biến môi trường (như database connection string), bạn có thể khai báo một cách cục bộ trong env:
hoặc ở remote server trong env_production:
bằng cách tương tự mà bạn đặt biến NODE_ENV
trong các đối tượng này.
Sau đó, bạn hãy thêm task dưới đây vào sau task copy-config
, thuộc file shipitfile.js
:
. . .
shipit.blTask('npm-install', async () => {
shipit.remote(`cd ${shipit.releasePath} && npm install --production`);
});
Tiếp theo, bạn khai báo một task có tên là npm-install
. Task này sẽ sử dụng remote bash terminal (thông qua shipit.remote
) để cài đặt dependencies của ứng dụng (npm
packages).
Thêm task cuối cùng vào sau npm-install
trong file shipitfile.js
:
. . .
shipit.blTask('pm2-server', async () => {
await shipit.remote(`pm2 delete -s ${appName} || :`);
await shipit.remote(
`pm2 start ${ecosystemFilePath} --env production --watch true`
);
});
Cuối cùng, bạn khai báo một task có tên là pm2-server
. Task này cũng sẽ sử dụng remote bash terminal, trước tiên để ngăn PM2
quản lý việc triển khai trước đó thông qua lệnh delete
, và sau đó bắt đầu một phiên bản mới của Node.js server bằng cách cung cấp tệp ecosystem.config.js
như là một biến.
Bạn cho PM2
biết rằng PM2 nên sử dụng các biến môi trường từ khối production
trong cấu hình ban đầu và yêu cầu PM2
theo dõi và khởi động lại ứng dụng nếu gặp phải sự cố.
Sau đây là file shipitfile.js
được cài đặt một cách hoàn chỉnh:
module.exports = shipit => {
require('shipit-deploy')(shipit);
require('shipit-shared')(shipit);
const appName = 'hello';
shipit.initConfig({
default: {
deployTo: '/home/deployer/example.com',
repositoryUrl: 'https://git-provider.tld/YOUR_GIT_USERNAME/YOUR_GIT_REPO_NAME.git',
keepReleases: 5,
shared: {
overwrite: true,
dirs: ['node_modules']
}
},
production: {
servers: 'deployer@YOUR_APP_SERVER_PUBLIC_IP'
}
});
const path = require('path');
const ecosystemFilePath = path.join(
shipit.config.deployTo,
'shared',
'ecosystem.config.js'
);
// Our listeners and tasks will go here
shipit.on('updated', async () => {
shipit.start('npm-install', 'copy-config');
});
shipit.on('published', async () => {
shipit.start('pm2-server');
});
shipit.blTask('copy-config', async () => {
const fs = require('fs');
const ecosystem = `
module.exports = {
apps: [
{
name: '${appName}',
script: '${shipit.releasePath}/hello.js',
watch: true,
autorestart: true,
restart_delay: 1000,
env: {
NODE_ENV: 'development'
},
env_production: {
NODE_ENV: 'production'
}
}
]
};`;
fs.writeFileSync('ecosystem.config.js', ecosystem, function(err) {
if (err) throw err;
console.log('File created successfully.');
});
await shipit.copyToRemote('ecosystem.config.js', ecosystemFilePath);
});
shipit.blTask('npm-install', async () => {
shipit.remote(`cd ${shipit.releasePath} && npm install --production`);
});
shipit.blTask('pm2-server', async () => {
await shipit.remote(`pm2 delete -s ${appName} || :`);
await shipit.remote(
`pm2 start ${ecosystemFilePath} --env production --watch true`
);
});
};
Lưu và thoát file.
Bước 5: Triển khai ứng dụng của bạn
Trong bước này, bạn sẽ triển khai ứng dụng của mình từ xa và kiểm tra xem việc triển khai này có đảm bảo được ứng dụng của bạn có thể truy cập trên internet hay không.
Do Shipit sẽ clone các tệp project từ remote Git repository của bạn, nên bạn cần push các file ứng dụng Node.js từ máy tính của mình lên Github. Vì vậy, bây giờ hãy điều hướng đến vị trí thư mục ứng dụng của Node.js project (nơi lưu trữ hello.js
và shiptitfile.js
) và thực thi lệnh sau:
git status
Lệnh git status
hiển thị trạng thái của thư mục đang hoạt động và khu vực staging. Cho phép bạn xem những thay đổi nào đã được đưa vào staging, những thay đổi nào chưa được đưa vào staging và các tệp nào không được theo dõi bởi Git. Các tệp mà không được theo dõi sẽ xuất hiện với màu chữ đỏ trong output:
Output
On branch master
Your branch is up to date with 'origin/master'.
Untracked files:
(use "git add <file>..." to include in what will be committed)
hello.js
package-lock.json
package.json
shipitfile.js
nothing added to commit but untracked files present (use "git add" to track)
Bạn có thể thêm các tệp này vào repository của mình bằng lệnh sau:
git add --all
Lệnh này không tạo ra bất kỳ output nào, cho dù bạn có thực thi lại lệnh git status
đi chăng nữa, thì các tệp này vẫn sẽ được hiển thị bằng màu chữ xanh lá cây với lưu ý rằng có những thay đổi cần được commit.
Bạn có thể tạo commit bằng cách sử dụng lệnh sau:
git commit -m "Our first commit"
Sau đó, output xuất hiện và cung cấp một số thông tin cụ thể về các tệp của Git.
Output
[master c64ea03] Our first commit
4 files changed, 1948 insertions(+)
create mode 100644 hello.js
create mode 100644 package-lock.json
create mode 100644 package.json
create mode 100644 shipitfile.js
Bây giờ, chỉ còn lại việc push các commit của bạn lên remote repository để Shipit clone sang app server trong quá trình triển khai. Bạn hãy thực thi dòng lệnh sau đây:
git push origin master
Output chứa thông tin về việc đồng bộ hóa với remote repository:
Output
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 8 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 15.27 KiB | 7.64 MiB/s, done.
Total 6 (delta 0), reused 0 (delta 0)
To github.com:Asciant/hello-world.git
e274312..c64ea03 master -> master
Bạn hãy sử dụng lệnh dưới đây để triển khai ứng dụng:
npx shipit production deploy
Output của lệnh này cung cấp thông tin chi tiết về các task đang được thực thi và kết quả của chức năng cụ thể. Output về task pm2-server
dưới đây cho thấy ứng dụng Node.js đã được khởi chạy:
Output
Running 'deploy:init' task...
Finished 'deploy:init' after 432 μs
. . .
Running 'pm2-server' task...
Running "pm2 delete -s hello || :" on host "centos-ap-app.asciant.com".
Running "pm2 start /home/deployer/example.com/shared/ecosystem.config.js --env production --watch true" on host "centos-ap-app.asciant.com".
@centos-ap-app.asciant.com [PM2][WARN] Node 4 is deprecated, please upgrade to use pm2 to have all features
@centos-ap-app.asciant.com [PM2][WARN] Applications hello not running, starting...
@centos-ap-app.asciant.com [PM2] App [hello] launched (1 instances)
@centos-ap-app.asciant.com ┌──────────┬────┬─────────┬──────┬──────┬────────┬─────────┬────────┬─────┬──────────┬──────────┬──────────┐
@centos-ap-app.asciant.com │ App name │ id │ version │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ user │ watching │
@centos-ap-app.asciant.com ├──────────┼────┼─────────┼──────┼──────┼────────┼─────────┼────────┼─────┼──────────┼──────────┼──────────┤
@centos-ap-app.asciant.com │ hello │ 0 │ 1.0.0 │ fork │ 4177 │ online │ 0 │ 0s │ 0% │ 4.5 MB │ deployer │ enabled │
@centos-ap-app.asciant.com └──────────┴────┴─────────┴──────┴──────┴────────┴─────────┴────────┴─────┴──────────┴──────────┴──────────┘
@centos-ap-app.asciant.com Use `pm2 show <id|name>` to get more details about an app
Finished 'pm2-server' after 5.27 s
Running 'deploy:clean' task...
Keeping "5" last releases, cleaning others
Running "(ls -rd /home/deployer/example.com/releases/*|head -n 5;ls -d /home/deployer/example.com/releases/*)|sort|uniq -u|xargs rm -rf" on host "centos-ap-app.asciant.com".
Finished 'deploy:clean' after 1.81 s
Running 'deploy:finish' task...
Finished 'deploy:finish' after 222 μs
Finished 'deploy' [ deploy:init, deploy:fetch, deploy:update, deploy:publish, deploy:clean, deploy:finish ]
Bạn có thể sử dụng ứng dụng bằng cách nhập URL của trang web your-domain
trong trình duyệt để truy cập web server của bạn. Việc này sẽ phục vụ cho Node.js Application, thông qua reverse proxy, tại app server nơi các tệp của bạn được triển khai.
Bạn sẽ thấy dòng chữ Hello World xuất hiện trên giao diện.
Lưu ý: Sau lần triển khai đầu tiên, Git repository của bạn sẽ theo dõi một tệp mới được tạo có tên là ecosystem.config.js
. Do tệp này sẽ được rebuilt mỗi khi triển khai và có thể chứa các thông tin biên dịch riêng tư của ứng dụng, vì vậy bạn nên thêm tệp này vào .gitignore
trong root directory của ứng dụng trên máy tính trước lần git
commit tiếp theo của bạn.
. . .
# ecosystem.config
ecosystem.config.js
Bước 6: Theo dõi ứng dụng của bạn
PM2 là một công cụ rất hữu ích để quản lý các quy trình từ xa, đồng thời cung cấp các tính năng để theo dõi hiệu suất của các quy trình ứng dụng này.
Kết nối với remote app server của bạn thông qua SSH bằng cách sử dụng lệnh sau:
ssh deployer@your_app_server_ip
Bạn hãy thực thi lệnh sau để có được những thông tin cụ thể liên quan đến các quy trình được bản lý bởi PM2:
pm2 list
Một output sẽ xuất hiện như sau:
Output
┌─────────────┬────┬─────────┬──────┬──────┬────────┬─────────┬────────┬──────┬───────────┬──────────┬──────────┐
│ App name │ id │ version │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ user │ watching │
├─────────────┼────┼─────────┼──────┼──────┼────────┼─────────┼────────┼──────┼───────────┼──────────┼──────────┤
│ hello │ 0 │ 0.0.1 │ fork │ 3212 │ online │ 0 │ 62m │ 0.3% │ 45.2 MB │ deployer │ enabled │
└─────────────┴────┴─────────┴──────┴──────┴────────┴─────────┴────────┴──────┴───────────┴──────────┴──────────┘
Bạn sẽ nhận được một bản tóm tắt thông tin PM2 đã thu thập. Để có thể xem thông tin chi tiết hơn, hãy sử dụng lệnh:
pm2 show hello
Output được cung cấp bởi lệnh pm2 list
sẽ hiển thị thông tin chi tiết từ bản tóm tắt trên. Đồng thời cũng cung cấp thông tin về một số lệnh bổ sung và vị trí lưu trữ của các log file:
Output
Describing process with id 0 - name hello
┌───────────────────┬─────────────────────────────────────────────────────────────┐
│ status │ online │
│ name │ hello │
│ version │ 1.0.0 │
│ restarts │ 0 │
│ uptime │ 82s │
│ script path │ /home/deployer/example.com/releases/20190531213027/hello.js │
│ script args │ N/A │
│ error log path │ /home/deployer/.pm2/logs/hello-error.log │
│ out log path │ /home/deployer/.pm2/logs/hello-out.log │
│ pid path │ /home/deployer/.pm2/pids/hello-0.pid │
│ interpreter │ node │
│ interpreter args │ N/A │
│ script id │ 0 │
│ exec cwd │ /home/deployer │
│ exec mode │ fork_mode │
│ node.js version │ 4.2.3 │
│ node env │ production │
│ watch & reload │ ✔ │
│ unstable restarts │ 0 │
│ created at │ 2019-05-31T21:30:48.334Z │
└───────────────────┴─────────────────────────────────────────────────────────────┘
Revision control metadata
┌──────────────────┬────────────────────────────────────────────────────┐
│ revision control │ git │
│ remote url │ N/A │
│ repository root │ /home/deployer/example.com/releases/20190531213027 │
│ last update │ 2019-05-31T21:30:48.559Z │
│ revision │ 62fba7c8c61c7769022484d0bfa46e756fac8099 │
│ comment │ Our first commit │
│ branch │ master │
└──────────────────┴────────────────────────────────────────────────────┘
Divergent env variables from local env
┌───────────────────────────┬───────────────────────────────────────┐
│ XDG_SESSION_ID │ 15 │
│ HOSTNAME │ N/A │
│ SELINUX_ROLE_REQUESTED │ │
│ TERM │ N/A │
│ HISTSIZE │ N/A │
│ SSH_CLIENT │ 44.222.77.111 58545 22 │
│ SELINUX_USE_CURRENT_RANGE │ │
│ SSH_TTY │ N/A │
│ LS_COLORS │ N/A │
│ MAIL │ /var/mail/deployer │
│ PATH │ /usr/local/bin:/usr/bin │
│ SELINUX_LEVEL_REQUESTED │ │
│ HISTCONTROL │ N/A │
│ SSH_CONNECTION │ 44.222.77.111 58545 209.97.167.252 22 │
└───────────────────────────┴───────────────────────────────────────┘
. . .
PM2 cũng cung cấp một công cụ theo dõi ở terminal, để có thể xem chi tiết hãy chạy lệnh:
pm2 monit
Output sẽ xuất hiện một bảng điều khiển tương tác, trong đó pm2
cung cấp thông tin về quy trình thời gian thực, logs, số liệu và metadata. Bảng điều khiển này hỗ trợ giám sát tài nguyên và error logs:
Output
┌─ Process list ────────────────┐┌─ Global Logs ─────────────────────────────────────────────────────────────┐
│[ 0] hello Mem: 22 MB ││ │
│ ││ │
│ ││ │
└───────────────────────────────┘└───────────────────────────────────────────────────────────────────────────┘
┌─ Custom metrics (http://bit.l─┐┌─ Metadata ────────────────────────────────────────────────────────────────┐
│ Heap Size 10.73 ││ App Name hello │
│ Heap Usage 66.14 ││ Version N/A │
│ Used Heap Size 7.10 ││ Restarts 0 │
│ Active requests 0 ││ Uptime 55s │
│ Active handles 4 ││ Script path /home/asciant/hello.js │
│ Event Loop Latency 0.70 ││ Script args N/A │
│ Event Loop Latency p95 ││ Interpreter node │
│ ││ Interpreter args N/A │
└───────────────────────────────┘└───────────────────────────────────────────────────────────────────────────┘
Sau khi hiểu được cách sử dụng PM2 để có thể theo dõi quy trình ứng dụng, bạn đã có thể chuyển sang phần hướng dẫn tiếp theo về cách Shipit có thể hỗ trợ trong việc quay lại phiên bản hoạt động tốt hơn và đã được triển khai trước đó.
Bạn có thể tắt ssh
trên app server bằng cách thực thi exit
.
Bước 7: Quay lại phiên bản đã triển khai
Khi triển khai ứng dụng, đôi khi sẽ xuất hiện các lỗi không mong muốn hoặc các vấn đề khác gây ra sự số cho trang web của bạn. Tuy nhiên, các nhà phát triển và bảo trì của Shipit đã dự tính được điều này nên đã cung cấp tính năng để bạn có thể quay lại phiên bản triển khai (đã hoạt động được) trước đó của ứng dụng.
Để đảm bảo cấu hình PM2
của bạn vẫn được duy trì, hãy thêm event listener khác ở sự kiện rollback
trong tệp shipitfile.js
:
. . .
shipit.on('rollback', () => {
shipit.start('npm-install', 'copy-config');
});
Bạn thêm một listener vào sự kiện rollback
để chạy tác vụ npm-install
và copy-config
. Việc này là cần thiết vì khác với sự kiện published
, sự kiện updated
không được thực thi bởi vòng đời của Shipit khi quay trở lại một phiên bản đã được triển khai. Vì vậy, thêm event listener này để đảm bảo quy trình quản lý PM2
sẽ đi đến phiên bản triển khai gần nhất, bất kể có xảy ra trường hợp rollback hay không.
Quá trình này tương tự như triển khai, với một sự thay đổi nhỏ trong lệnh. Để thử rollback lại phiên bản triển khai trước đó, bạn có thể sử dụng lệnh như sau:
npx shipit production rollback
Giống như lệnh deploy
, rollback
cung cấp thông tin chi tiết về quá trình khôi phục và các task đang được thực thi:
Output
Running 'rollback:init' task...
Get current release dirname.
Running "if [ -h /home/deployer/example.com/current ]; then readlink /home/deployer/example.com/current; fi" on host "centos-ap-app.asciant.com".
@centos-ap-app.asciant.com releases/20190531213719
Current release dirname : 20190531213719.
Getting dist releases.
Running "ls -r1 /home/deployer/example.com/releases" on host "centos-ap-app.asciant.com".
@centos-ap-app.asciant.com 20190531213719
@centos-ap-app.asciant.com 20190531213519
@centos-ap-app.asciant.com 20190531213027
Dist releases : ["20190531213719","20190531213519","20190531213027"].
Will rollback to 20190531213519.
Finished 'rollback:init' after 3.96 s
Running 'deploy:publish' task...
Publishing release "/home/deployer/example.com/releases/20190531213519"
Running "cd /home/deployer/example.com && if [ -d current ] && [ ! -L current ]; then echo "ERR: could not make symlink"; else ln -nfs releases/20190531213519 current_tmp && mv -fT current_tmp current; fi" on host "centos-ap-app.asciant.com".
Release published.
Finished 'deploy:publish' after 1.8 s
Running 'pm2-server' task...
Running "pm2 delete -s hello || :" on host "centos-ap-app.asciant.com".
Running "pm2 start /home/deployer/example.com/shared/ecosystem.config.js --env production --watch true" on host "centos-ap-app.asciant.com".
@centos-ap-app.asciant.com [PM2][WARN] Node 4 is deprecated, please upgrade to use pm2 to have all features
@centos-ap-app.asciant.com [PM2][WARN] Applications hello not running, starting...
@centos-ap-app.asciant.com [PM2] App [hello] launched (1 instances)
@centos-ap-app.asciant.com ┌──────────┬────┬─────────┬──────┬──────┬────────┬─────────┬────────┬─────┬──────────┬──────────┬──────────┐
@centos-ap-app.asciant.com │ App name │ id │ version │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ user │ watching │
@centos-ap-app.asciant.com ├──────────┼────┼─────────┼──────┼──────┼────────┼─────────┼────────┼─────┼──────────┼──────────┼──────────┤
@centos-ap-app.asciant.com │ hello │ 0 │ 1.0.0 │ fork │ 4289 │ online │ 0 │ 0s │ 0% │ 4.5 MB │ deployer │ enabled │
@centos-ap-app.asciant.com └──────────┴────┴─────────┴──────┴──────┴────────┴─────────┴────────┴─────┴──────────┴──────────┴──────────┘
@centos-ap-app.asciant.com Use `pm2 show <id|name>` to get more details about an app
Finished 'pm2-server' after 5.55 s
Running 'deploy:clean' task...
Keeping "5" last releases, cleaning others
Running "(ls -rd /home/deployer/example.com/releases/*|head -n 5;ls -d /home/deployer/example.com/releases/*)|sort|uniq -u|xargs rm -rf" on host "centos-ap-app.asciant.com".
Finished 'deploy:clean' after 1.82 s
Running 'rollback:finish' task...
Finished 'rollback:finish' after 615 μs
Finished 'rollback' [ rollback:init, deploy:publish, deploy:clean, rollback:finish ]
Bạn đã cấu hình Shipit để giữ 5 phiên bản thông qua keepReleases: 5
trong tệp shipitfile.js
. Shipit sẽ theo dõi các phiên bản này để đảm bảo có thể quay trở lại khi cần thiết. Shipit cũng cung cấp một cách rất hữu dụng để xác định được các bản phiên bản bằng cách tạo một thư mục được đặt theo định dạng timestamp (YYYYMMDDHHmmss – Ví dụ: /home/deployer/your-sdomain/releases/20190420210548
).
Nếu bạn muốn cài đặt thêm cho quá trình rollback, bạn có thể lắng nghe các event cụ thể cho thao tác rollback. Sau đó, bạn có thể sử dụng các event này để thực thi các task bổ sung cho quá trình rollback của bạn.
Khả năng khôi phục cho phép bạn cung cấp một phiên bản đang hoạt động của ứng dụng cho người dùng, ngay cả khi việc triển khai có thể tồn tại các lỗi hoặc sự cố không mong muốn.
Ngoài ra, bạn nên tham khảo thêm về cách cài đặt và sử dụng TimescaleDB trên CentOS 7 để tối ưu hóa hiệu suất cơ sở dữ liệu của mình. Với TimescaleDB, bạn có thể quản lý và truy xuất các dữ liệu thời gian lớn một cách nhanh chóng và hiệu quả hơn, từ đó tối ưu hiệu quả công việc được tốt nhất.
Lời kết
Trong bài hướng dẫn về cách tự động hóa triển khai Node js với Shipit trên CentOS 7 này, bạn đã cấu hình được quy trình làm việc cho phép bạn tạo một giải pháp thay thế có mức tùy chỉnh cao cho Platform as a Service, chỉ từ một vài máy chủ. Quy trình làm việc này cho phép cài đặt việc triển khai và cấu hình, giám sát quy trình với PM2, khả năng mở rộng quy mô và thêm dịch vụ, các máy chủ, hoặc môi trường bổ sung để triển khai khi được yêu cầu. Nếu còn gì thắc mắc, hãy để lại bình luận bên dưới nhé.