Có rất nhiều cách để triển khai ứng dụng Nodejs, dù trên Cloud hay hạ tầng vật lý (on-premise). Tuy nhiên, phát triển ứng dụng ở đâu và như thế nào là điều chúng ta quan tâm. Ngoài ra, bảo mật cũng là một khía cạnh quan trọng mà nếu bỏ qua, ứng dụng của bạn sẽ không tồn tại dài lâu được, và sẽ luôn có khả năng cao các thông tin quan trọng sẽ bị tiết lộ cho người ngoài.
Do đó, bài viết này sẽ hướng dẫn bạn từng bước để triển khai một ứng dụng Nodejs trên AWS một cách đầy đủ nhất, đưa ứng dụng lên server sử dụng Docker container, RDS Amazon Aurora, Nginx với HTTPS, và truy cập vào ứng dụng bằng tên miền (domain name).
1. Tool Stack
Nodejs Sample App
Một sample app Nodejs với 3 API viz, status, insert và list. Các API này sẽ được sử dụng để kiểm tra trạng thái của ứng dụng, đưa dữ liệu vào cơ sở dữ liệu, và cho phép gửi và hiển thị dữ liệu từ cơ sở dữ liệu.
AWS EC2 Instance
Một AWS EC2 instance được chạy trên hệ điều hành Ubuntu 20.04 LTS được sử dụng để triển khai ứng dụng Nodejs được đóng gói (containerized). Ta sẽ tải Docker trong instance này, đặt bên trên các containers sẽ được tạo ra về sau. Chúng ta cũng sẽ tải MySQL Client vào trong instance. MySQL Client yêu cầu kết nối với Aurora Instance để tạo một table bắt buộc.
AWS RDS Amazon Aurora
Dữ liệu của bạn sẽ được lưu trữ tại AWS RDS Amazon Aurora. Ta sẽ lưu trữ các trường cơ bản như tên người dùng (username), email-id và tuổi.
Amazon Aurora là một hệ cơ sở dữ liệu liên kết dạng MySQL và PostgreSQL trên AWS.
Docker
Docker là một nền tảng được đóng gói (containerization) để xây các Docker Images, triển khai chúng qua containers. Ta sẽ triển khai ứng dụng Nodejs trên server, Nginx, và Certbot là Docker Containers.
Docker-Compose
Để code các containers Nodejs, Nginx hay Certbot, ta sử dụng Docker-Compose. Docker Compose giúp giảm thời gian triển khai container và quản lý thời gian tốt hơn.
Nginx
Nginx được sử dụng để kích hoạt HTTPS cho sample app Nodejs, điều hướng mọi request từ user tới ứng dụng Nodejs. Nó hoạt động như một reverse proxy dùng để điều hướng user request tới ứng dụng, đồng thời hỗ trợ bảo mật trong việc kết nối bằng việc cung cấp cấu hình để kích hoạt SSL/HTTPS.
Certbot
Certbot cho phép chúng ta tự động sử dụng Let’s Encrypt cho Domain Validation (xác thực miền – DV) và đạt được chứng chỉ SSL.
Domain
Ở cuối phần doc, bạn sẽ được truy cập vào sample app Nodejs, sử dụng tên miền của bạn trên HTTPS, ví dụ, sample app Nodejs của bạn sẽ được bảo mật trên Internet.
PostMan
Ta sẽ sử dụng Postman để kiểm tra các API như là kiểm tra trạng thái, chèn dữ liệu, liệt kê dữ liệu từ cơ sở dữ liệu.
Như đã nói phía trên, ta sẽ “triển khai một ứng dụng Nodejs trên AWS … đưa ứng dụng lên server sử dụng Docker container, RDS Amazon Aurora, Nginx với HTTPS, và truy cập vào ứng dụng bằng tên miền (domain name).” Đầu tiên, ta sẽ cùng tìm hiểu về hạ tầng kiến trúc trước khi bắt tay thực hiện.
2. Kiến trúc: Triển khai ứng dụng Nodejs lên server qua Docker container, RDS Amazon Aurora, Nginx với HTTPS, truy cập qua tên miền
Triển khai ứng dụng Nodejs lên EC2 instance bằng Docker sẽ khả dụng trên cổng 3000. Sample app Nodejs này sẽ truy xuất dữ liệu từ instance RDS Amazon Aurora được tạo ra từ các VPC tương tự như trên EC2 instance. Một instance Amazon Aurora DB sẽ được bảo mật và được truy cập trong cùng một VPC. Ứng dụng Nodejs được triển khai trên EC2 instance có thể được truy cập bằng cách sử dụng public IP trên cổng 3000, tuy nhiên chúng ta sẽ không làm vậy.
Truy cập vào các ứng dụng trên cổng non-standard là điều không khuyến khích, do đó chúng ta sẽ có Nginx được vận hành như một reserve proxy, kích hoạt cổng SSL. Người dùng sẽ cố gắng truy cập vào ứng dụng bằng cách sử dụng tên miền, và các yêu cầu này sẽ được chuyển tiếp sang cho Nginx. Nginx sẽ kiểm tra yêu cầu dựa trên API, rồi chuyển yêu cầu đó cho ứng dụng Nodejs. Việc yêu cầu này sẽ dừng lại với SSL, đánh dấu cho kết quả làm việc giữa client và server khi đã được bảo mật hoàn toàn.
Dưới đây là một sơ đồ kiến trúc hạ tầng giúp ta hình dung về cách triển khai ứng dụng Nodejs trên AWS:
3. Điều kiện tiên quyết
Trước khi ta bắt tay vào triển khai ứng dụng Nodejs trên AWS, hãy chắc chắn rằng ta đã hoàn thành xong các điều kiện tiên quyết dưới đây:
- Có một tài khoản AWS
- Có PostMan hoặc các phần mềm thay thế cho machine để kiểm tra APIs
- Một tên miền đã đăng ký được khai báo trên tài khoản AWS
4. Tạo Ubuntu 20.04 LTS EC2 Instance trên AWS
Truy cập vào trang web https://AWS.amazon.com/console/ và đăng nhập vào tài khoản của bạn.
Sau khi đã đăng nhập thành công, nhấn vào thanh tìm kiếm và gõ EC2. Nhấn vào kết quả để tới dashboard của EC2 và bắt đầu tạo một EC2 instance.
Tại đây, nhấn vào “Launch instance” để cấu hình và tạo một EC2 instance.
Chọn AMI “Ubuntu Server 20.04 LTS”.
Chúng tôi khuyên bạn nên chọn t3.small cho riêng việc kiểm thử, nó sẽ tốn khoảng 2 CPUs và 2GB RAM. Bạn có thể chọn loại instance tùy theo nhu cầu.
Bạn có thể giữ các cài đặt có sẵn và tiếp tục triển khai. Tại đây, tôi đã chọn VPC mặc định, nếu bạn muốn bạn có thể chọn VPC khác. Ghi nhớ rằng, ở đây chúng ta sẽ tạo một instance trên Public Subnet.
Tốt nhất, bạn nên chọn dung lượng lớn hơn khoảng 30GB. Các phần khác có thể để mặc định.
Chọn các tag như “Name” “Environment” tùy theo lựa chọn của bạn. Bạn cũng có thể bỏ qua phần này.
Cho phép kết nối tới cổng 22 chỉ qua IP của bạn. Nếu bạn cho phép kết nối từ 0.0.0.0/0., instance của bạn sẽ được truy cập bởi bất kỳ ai qua cổng 22.
Kiểm tra lại cấu hình, sau đó nhấn vào “Launch” nếu bạn thấy mọi thứ đã sẵn sàng để tạo một instance.
Trước khi một instance được tạo ra, nó cần một key-pair. Bạn có thể tạo ra một key-pair mới hoặc sử dụng một key-pair có sẵn. Nhấn vào “Launch instances” để bắt đầu bước khởi tạo một instance.
Vào bảng điều khiển và kiểm tra instance của bạn. Nhấn vào nút “View instances”.
Tại đây, bạn có thể thấy instance đã được tạo và đang trong giai đoạn “Initiating”. Trong khoảng 1-2 phút, bạn sẽ thấy instance bắt đầu chạy.
Trong thời gian đó, ta sẽ cùng tạo một RDS instance nhé.
5. Tạo RDS Aurora với MySql Instance trên AWS
Một lần nữa, nhấn vào thanh tìm kiếm ở đầu trang, và lần này ta sẽ tìm “RDS”. Nhấn vào kết quả để truy cập vào dashboard của RDS.
Tại trang chủ của RDS, nhấn vào “Create database” để cấu hình và tạo một RDS instance.
Chọn “Easy create” cho method, “Amazon Aurora” cho engine type, “Dev/Test” cho DB instance size.
Kéo xuống một chút và chọn “DB cluster identifier” như “my-Nodejs-database”. Bạn có thể đặt một tên khác tùy ý, khi nó chỉ là cái tên gán cho RDS instance. Tuy nhiên, ta nên sử dụng cái tên trùng nhau để không lẫn lộn trong các bước sau đó.
Đồng thời, đặt master username là “admin”, cài đặt mật khẩu, rồi nhấn vào “Create database”.
Đây là các bước tiên quyết để tạo ra một RDS Amazon Aurora instance. Lưu ý rằng trên môi trường production và live thì bạn không được đặt username và mật khẩu đơn giản.
Tại đây, bạn có thể thấy instance đang trong quá trình “khởi tạo”. Trong vòng 5-10 phút tới, instance sẽ chạy.
Tại đây, ta cần lưu ý:
- RDS Amazon Aurora instance sẽ ở trạng thái riêng tư theo mặc định, có nghĩa là ta không thể truy cập nó từ bên ngoài mà chỉ ở bên trong VPC.
- EC2 instance và RDS instance thuộc về một VPC chung.
- RDS instance có thể tiếp cận được qua EC2 instance.
6. Cài đặt dependencies trên EC2 Instance
Bây giờ, bạn có thể kết nối tới Instance mà bạn vừa tạo ra.
MySql Client
Ta sẽ cần một MySQL client để kết nối với RDS Amazon Aurora instance và tạo một cơ sở dữ liệu bên trong nó. Kết nối với EC2 instance và thực thi các lệnh từ đó.
- sudo apt update
- sudo apt install mysql-client
Tạo bảng
Ta sẽ cần một bảng trong RDS Amazon Aurora instance để lưu trữ dữ liệu từ các ứng dụng. Để tạo bảng, kết nối tới RDS Amazon Aurora instance bằng cách sử dụng MySQL server bạn vừa tải trên EC2 instance ở bước đầu tiên.
Sao chép Database Endpoint từ Amazon Aurora instance.
Thực thi các lệnh tiếp theo với giá trị chính xác
- mysql -u <user-name> -p<password> -h <host-endpoint>
Sau đó, lệnh của bạn sẽ xuất hiện như sau:
- mysql -u admin -padmin1234 -h my-Nodejs-database.cluster-cxxjkzcl1hwb.eu-west-3.rds.amazonAWS.com
Một khi bạn đã kết nối tới Amazon RDS Aurora instance, thực thi tiếp các lệnh sao để tạo một bảng có tên “users”.
show databases;
use main;
CREATE TABLE IF NOT EXISTS users(id int NOT NULL AUTO_INCREMENT, username varchar(30), email varchar(255), age int, PRIMARY KEY(id));
select * from users;
Bạn có thể nhìn vào ảnh chụp màn hình bên dưới để xem các lệnh trên đã chạy thế nào:
Tạo đường dẫn thư mục ứng dụng (Application Directory)
Bây giờ chúng ta sẽ tạo một đường dẫn có thể giúp ta lưu trữ codebase và các tệp cấu hình.
- pwd
- cd /home/ubuntu/
- mkdir Nodejs-docker
- cd Nodejs-docker
Clone phần code repository trên EC2 instance
Clone phần Github Repository đang chứa toàn bộ code của bạn. Đây là một bước không bắt buộc. Nếu bạn đã sao chép toàn bộ tệp từ repository sang application directory, bạn không cần phải tạo thêm tệp trong các bước sau nữa. Tuy nhiên, bạn vẫn cần tạo một số thay đổi nhất định.
- pwd
- cd /home/ubuntu/
- git clone https://github.com/shivalkarrahul/DevOps.git
- cp /home/ubuntu/DevOps/AWS/Nodejs-docker/* /home/ubuntu/Nodejs-docker
7. Triển khai ứng dụng Deploy Nodejs trên AWS EC2 instance sử dụng Docker container, RDS Amazon Aurora, Nginx với HTTPS, và truy cập ứng dụng qua tên miền
Tại sao cần sử dụng Docker trên EC2 instance?
Docker là một công cụ được đóng gói (containerization) để đóng gói các phần mềm trở thành các “image” có thể sử dụng để tạo các containers Docker. Docker giúp ta tạo lập, chia sẻ và triển khai các ứng dụng một cách dễ dàng.
Bước đầu tiên để “Docker hóa” chính là tải Docker.
Tải Docker
- Kiểm tra phiên bản Linux hiện tại
cat /etc/issue
- Cập nhật apt package index
sudo apt-get update
- Tải các packages cho phép apt sử dụng repository trên HTTPS
sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release
- Thêm key GPG của Docker
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg –dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
- Set up cho stable repository
echo “deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable” | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
- Cập nhật apt package index
sudo apt-get update
- Tải về phiên bản mới nhất của Docker Engine và containerd
sudo apt-get install docker-ce docker-ce-cli containerd.io
- Kiểm tra phiên bản Docker hiện tại
docker –version
- Quản lý Docker với tư cách là non-root user
- Tạo nhóm ‘docker’
sudo groupadd docker
- Thêm user vào nhóm docker
sudo usermod -aG docker <your-user-name>
- Thoát.
exit
- Đăng nhập lại vào terminal
- Xác thực việc bạn có thể chạy các lệnh docker mà không cần sudo
docker run hello-world
- Sau khi chạy các lệnh ở trên, bạn sẽ thấy output như dưới hình.
- Dưới đây là màn hình sau khi các lệnh ở trên được chạy.
Docker hóa ứng dụng Nodejs trên EC2 instance
Sau khi tải về Docker, bước tiếp theo bạn cần “docker hóa” ứng dụng của bạn. Docker hóa một ứng dụng Nodejs có thể hiểu là viết một Dockerfile theo hướng dẫn để tạo một Docker Image.
Ta sẽ cùng tạo một Dockerfile và một sample cho ứng dụng Nodejs.
- pwd
- cd /home/ubuntu/Nodejs-docker
- Create Dockerfile and paste the following in it, alternatively, you can copy the content from here as well.
vim Dockerfile
#Base Image node:12.18.4-alpine
FROM node:12.18.4-alpine
#Set working directory to /app
WORKDIR /app
#Set PATH /app/node_modules/.bin
ENV PATH /app/node_modules/.bin:$PATH
#Copy package.json in the image
COPY package.json ./
#Install Packages
RUN npm install express –save
RUN npm install mysql –save
#Copy the app
COPY . ./
#Expose application port
EXPOSE 3000
#Start the app
CMD [“node”, “index.js”]
- Tạo index.js và dán vào phần sau, hoặc bạn có thể copy đoạn code bên dưới. Đây sẽ là sample cho ứng dụng Nodejs của bạn.
vim index.js
const express = require(‘express’);
const app = express();
const port = 3000;
const mysql = require(‘mysql’);
const con = mysql.createConnection({
host:
“my-Nodejs-database.cluster-cxxjkzcl1hwb.eu-west3.rds.amazonAWS.com”,
user: “admin”,
password: “admin1234”
});
app.get(‘/status’, (req, res) => res.send({status: “I’m up and running”}));
app.listen(port, () => console.log(`Dockerized Nodejs Applications is listening on port ${port}!`));
app.post(‘/insert’, (req, res) => {
if (req.query.username && req.query.email && req.query.age) {
console.log(‘Received an insert call’);
con.connect(function(err) {
con.query(`INSERT INTO main.users (username, email, age) VALUES (‘${req.query.username}’, ‘${req.query.email}’, ‘${req.query.age}’)`, function(err, result, fields) {
if (err) res.send(err);
if (result) res.send({username: req.query.username, email: req.query.email, age: req.query.age});
if (fields) console.log(fields);
});
});
} else {
console.log(‘Something went wrong, Missing a parameter’);
}
});
app.get(‘/list’, (req, res) => {
console.log(‘Received a list call’);
con.connect(function(err) {
con.query(`SELECT * FROM main.users`, function(err, result, fields)
{
if (err) res.send(err);
if (result) res.send(result);
});
});
});
Ở file phía trên, hãy thay các giá trị của các biến dưới đây với một ứng dụng vào trong RDS Amazon Aurora instance của bạn:
- host: “my-Nodejs-database.cluster-cxxjkzcl1hwb.eu-west-3.rds.amazonAWS.com”
- user: “admin”
- password: “admin1234”
- Tạo package.json và dán vào phần sau, hoặc bạn có thể sao chép phần code phía dưới.
vim package.json
{
“name”: “Nodejs-docker”,
“version”: “12.18.4”,
“description”: “Nodejs on ec2 using docker container”,
“main”: “index.js”,
“scripts”: {
“test”: “echo \”Error: no test specified\” && exit 1″
},
“author”: “Rahul Shivalkar”,
“license”: “ISC”
}
Cập nhật AWS Security Group
Để truy cập vào ứng dụng, ta cần thêm một quy tắc vào trong Security Group để cho phép các kết nối vào cổng 3000. Như tôi đã nói ở trên, ta có thể truy cập vào các ứng dụng trên cổng 3000, nhưng tôi không khuyến khích. Bạn có thể đọc tiếp để hiểu hơn về các khuyến nghị của người viết.
- Truy cập vào EC2 Dashboard, chọn instance, chuyển sang lab “Security”, sau đó nhấn vào link của Security group.
- Chọn tab “Inbound rules” và nhấn vào nút “Edit inbound rules”.
- Thêm một quy tắc (rule) cho phép kết nối bên ngoài từ “Mylp” qua cổng “3000”.
Triển khai server Nodejs trên EC2 Server (Instance)
- Ta sẽ cùng tạo một docker image từ phần code đã có.
- cd /home/ubuntu/Nodejs-docker
- docker build -t Nodejs .
- Tạo một container sử dụng image ta vừa tạo và đưa nó sang cổng 3000.
docker run –name Nodejs -d -p 3000:3000 Nodejs
- Bạn có thể thấy code đang chạy.
docker ps
- Bạn thậm chí có thể kiểm tra các logs của container.
docker logs Nodejs
Giờ ta có Nodejs App Docker Container đang khởi chạy.
- Bạn có thể truy cập vào ứng dụng của bạn qua trình duyệt trên cổng 3000.
- Kiểm tra trạng thái của kết nối trên /status api sử dụng trình duyệt. http://<public-ip-of-ec2-instance>:3000/status
- Bạn có thể thêm một vài dữ liệu trong ứng dụng qua /insert api sử dụng ứng dụng Postman bằng cách gọi POST request.
http://<public-ip-of-ec2-instance>:3000/insert?username=abc&[email protected]&age=2
- Bạn có thể liệt kê các dữ liệu từ ứng dụng bằng cách sử dụng /list api từ trình duyệt. http://<public-ip-of-ec2-instance>:3000/list
- Hoặc bạn có thể sử dụng lệnh curl bên trong EC2 instance để kiểm tra trạng thái, thêm dữ liệu, liệt kê dữ liệu.
curl -XGET “http://<public-ip-of-ec2-instance>:3000/list”
curl -XPOST “http://<public-ip-of-ec2-instance>:3000/insert?username=abc&[email protected]&age=26″
- Dừng và loại bỏ container
docker stop Nodejs
docker rm Nodejs
Trong phần này, ta đã cố kết nối trực tiếp các API có sẵn cho ứng dụng bằng việc sử dụng Public IP:Port của EC2 instance. Tuy nhiên, chúng tôi không khuyến khích việc tiếp xúc với các cổng non-standard tới thế giới ngoài trong Security Group. Đồng thời, chúng tôi đã cố gắng truy cập ứng dụng qua HTTP protocol, nghĩa là việc kết nối từ trình duyệt tới ứng dụng một cách không được bảo mật và bất kỳ kẻ tấn công nào cũng có thể đọc các network packets.
Để tránh cho tình trạng này diễn ra, chúng tôi khuyên bạn sử dụng Nginx.
Set up Nginx
Chúng ta sẽ tạo một cấu hình Nginx sử dụng bên trong Nginx container qua một Docker Volume. Đồng thời, ta sẽ tạo một tệp và sao chép các nội dung bên dưới vào trong.
- cd /home/ubuntu/Nodejs-docker
- mkdir nginx-conf
- vim nginx-conf/nginx.conf
server {
listen 80;
listen [::]:80;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
location / {
rewrite ^ https://$host$request_uri? permanent;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name Nodejs.devopslee.com www.Nodejs.devopslee.com;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/Nodejs.devopslee.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/Nodejs.devopslee.com/privkey.pem;
ssl_buffer_size 8k;
ssl_dhparam /etc/ssl/certs/dhparam-2048.pem;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
ssl_ecdh_curve secp384r1;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8;
location / {
try_files $uri @Nodejs;
}
location @Nodejs {
proxy_pass http://Nodejs:3000;
add_header X-Frame-Options “SAMEORIGIN” always;
add_header X-XSS-Protection “1; mode=block” always;
add_header X-Content-Type-Options “nosniff” always;
add_header Referrer-Policy “no-referrer-when-downgrade” always;
add_header Content-Security-Policy “default-src * data: ‘unsafe-eval’ ‘unsafe-inline'” always;
}
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
}
Trong tệp ở trên, bạn có thể thay đổi ở 3 dòng bên dưới. Thay thế phần subdomain.domain, ví dụ như Nodejs.devopslee với phần bạn muốn.
- server_name Nodejs.devopslee.com www.Nodejs.devopslee.com;
- ssl_certificate /etc/letsencrypt/live/Nodejs.devopslee.com/fullchain.pem;
- ssl_certificate_key /etc/letsencrypt/live/Nodejs.devopslee.com/privkey.pem;
Tại sao ta cần Nginx ở trước dịch vụ của nodejs?
Ứng dụng Nodejs sẽ chạy trên cổng 3000 non-standard. Nodejs cung cấp một lối đi cho phép ta dùng HTTPS; tuy nhiên, việc cấu hình protocol và quản lý chứng chỉ SSL – một cái sẽ hết hạn theo chu kỳ – ở bên trong code base, là điều không đáng để bận tâm.
Để giải quyết vấn đề này, ta cần có Nginx ở trước với SSL termination và chuyển tiếp các request user tới Nodejs. Nginx là một loại server đặc biệt mà có thể hoạt động như một reverse proxy, cân bằng tải (load balancer), mail proxy, và HTTP cache. Tại đây, ta sẽ dùng Nginx như một reverse proxy để chuyển hướng các request về ứng dụng Nodejs và có SSL termination.
Tại sao ta không dùng Apache?
Apache cũng là một web server và có thể hoạt động như một reverse proxy. Nó cũng hỗ trợ SSL termination. Tuy nhiên, có một vài điểm khác biệt giữa Nginx và Apache. Do một vài lý do, phần lớn mọi người sẽ lựa chọn Nginx thay vì Apache. Chúng ta có thể điểm qua một vài lý do bên dưới.
- Nginx có quy trình đơn giản, xử lý bất đồng bộ (asynchronous) và có kiến trúc event-based. Trong khi đó Apache luôn cố tạo ra quy trình mới, tạo ra luồng mới cho mọi request trong mọi kết nối.
- Nginx có dung lượng nhẹ, có thể mở rộng, và dễ dàng để cấu hình. Apache dù có nhiều tính năng tốt nhưng tương đối khó học.
Docker-Compose
Tại bước này, ta sẽ tải docker-compose.
- Tải phần mở rộng mới nhất của Docker Compose
sudo curl -L “https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)” -o /usr/local/bin/docker-compose
- Áp dụng các lệnh có thể thực hiện cho docker-compose mà ta vừa tải ở bước trên.
sudo chmod +x /usr/local/bin/docker-compose
- Kiểm tra xem ta đã tải thành công chưa bằng việc kiểm tra phiên bản của docker-compose
docker-compose –version
- Tạo một tệp docker-compose .yaml, hoặc bạn có thể sao chép các nội dung bên dưới.
cd /home/ubuntu/Nodejs-docker
vim docker-compose.yml
version: ‘3’
services:
Nodejs:
build:
context: .
dockerfile: Dockerfile
image: Nodejs
container_name: Nodejs
restart: unless-stopped
networks:
– app-network
webserver:
image: nginx:mainline-alpine
container_name: webserver
restart: unless-stopped
ports:
– “80:80”
– “443:443”
volumes:
– web-root:/var/www/html
– ./nginx-conf:/etc/nginx/conf.d
– certbot-etc:/etc/letsencrypt
– certbot-var:/var/lib/letsencrypt
– dhparam:/etc/ssl/certs
depends_on:
– Nodejs
networks:
– app-network
certbot:
image: certbot/certbot
container_name: certbot
volumes:
– certbot-etc:/etc/letsencrypt
– certbot-var:/var/lib/letsencrypt
– web-root:/var/www/html
depends_on:
– webserver
command: certonly –webroot –webroot-path=/var/www/html –email [email protected] –agree-tos –no-eff-email –staging -d Nodejs.devopslee.com -d www.Nodejs.devopslee.com
#command: certonly –webroot –webroot-path=/var/www/html –email [email protected] –agree-tos –no-eff-email –force-renewal -d Nodejs.devopslee.com -d www.Nodejs.devopslee.com
volumes:
certbot-etc:
certbot-var:
web-root:
driver: local
driver_opts:
type: none
device: /home/ubuntu/Nodejs-docker/views/
o: bind
dhparam:
driver: local
driver_opts:
type: none
device: /home/ubuntu/Nodejs-docker/dhparam/
o: bind
networks:
app-network:
driver: bridge
Trong tệp ở trên, bạn có thể thay đổi các dòng bên dưới. Thay đổi phần subdomain.domain, ví dụ như Nodejs.devopsleee với phần mà bạn muốn. Thay đổi IP thành email cá nhân của bạn.
–email EMAIL, Email used for registration and recovery contact.
command: certonly –webroot –webroot-path=/var/www/html –email [email protected] –agree-tos –no-eff-email –staging -d Nodejs.devopslee.com -d www.Nodejs.devopslee.com
Cập nhật AWS security groups
Lần này, ta sẽ tiếp cận cổng 80 và 443 trong security group, gắn với EC2 instance. Đồng thời, loại bỏ cổng 3000 do không còn cần thiết – lúc này ứng dụng của bạn đã hoạt động qua cổng 443.
Bao gồm các thay đổi ở DNS
Tại đây, tôi đã tạo một sub-domain “Nodejs.devopslee.com” sẽ được dùng để truy cập sample ứng dụng Nodejs, sử dụng tên miền thay vì truy cập bằng IP.
Bạn có thể tạo một sub-domain trên AWS nếu bạn đã có sẵn một tên miền.
Tạo 2 “type A Recordsets” trên zone đang quản trị với giá trị như một public IP của EC2 instance. Một Recordset sẽ trở thành subdomain.domain.com và cái còn lại sẽ là www.subdomain.domain.com.
Tại đây, tôi đã tạo ra Nodejs.devopslee.com và www.Nodejs.devopslee.com, cả hai đều trỏ về Public IP của EC2 instance.
Lưu ý: Tôi đã không gán bất kỳ elastic IP nào tới EC2 instance. Tôi khuyên bạn gán một elastic IP và sử dụng nó trong Recordset, sau đó khi bạn khởi động lại EC2 instance, bạn không cần phải cập nhật IP trong Recordset nữa, do public IP thường sẽ thay đổi sau khi EC2 instance được khởi động lại.
Bây giờ, ta sẽ sao chép giá trị của “Type NS Recordset”, thứ mà ta sẽ cần trong các bước tiếp theo.
Vào hosted zone của tên miền, tạo một “record” mới với subdomain.domain.com, thêm các giá trị NS bạn vừa sao chép ở bước trên.
Bây giờ bạn đã có một sub-domain có thể truy cập vào ứng dụng của bạn.
Trong trường hợp của tôi, tôi có thể dùng Nodejs.devopslee.com để truy cập vào ứng dụng Nodejs. Bước tiếp theo, ta sẽ làm bảo mật cho ứng dụng web Nodejs.
Bao gồm chứng chỉ SSL
Ta sẽ tạo một key có thể sử dụng trong Nginx.
- cd /home/ubuntu/Nodejs-docker
- mkdir views
- mkdir dhparam
- sudo openssl dhparam -out /home/ubuntu/Nodejs-docker/dhparam/dhparam-2048.pem 2048
Triển khai ứng dụng Nodejs trên EC2 instance
Chúng ta đã sẵn sàng để khởi chạy ứng dụng Nodejs sử dụng docker-compose. Docker-compose sẽ khởi chạy ứng dụng Nodejs trên cổng 3000, Nginx với SSL trên cổng 80 và 443. Nginx sẽ điều hướng các requests về ứng dụng Nodejs khi được truy cập với tên miền. Nó cũng sẽ có một certbox client cho phép ta sở hữu chứng chỉ.
- docker-compose up
Sau khi bạn nhập lệnh phía trên, bạn sẽ thấy các output như dưới. Bạn sẽ thấy một dòng tin nhắn với nội dung “Successfully received certificates”.
Lưu ý: lệnh docker-compose phía trên sẽ làm các containers chạy và gắn kết với terminal. Ta sẽ không dùng lựa chọn -d để tách chúng ta khỏi terminal.
Giờ đây, bạn đã sẵn sàng. Hãy nhấn vào URL trên trình duyệt và bạn đã có ứng dụng Nodejs có sẵn trên HTTPS.
Bạn cũng có thể thử truy cập vào ứng dụng qua lệnh curl.
- Liệt kê các dữ liệu từ ứng dụng
curl https://Nodejs.devopslee.com/list
- Thêm một entry vào trong ứng dụng
curl -XPOST “https://Nodejs.devopslee.com/insert?username=abc&[email protected]&age=28“
- Một lần nữa, liệt kê các dữ liệu để xác thực xem dữ liệu tại bước (2) đã được thêm vào hay chưa.
curl https://Nodejs.devopslee.com/list
- Kiểm tra trạng thái của ứng dụng
https://Nodejs.devopslee.com/status
- Nhấn vào URL trên trình duyệt để có một danh sách các entries trong cơ sở dữ liệu.
https://Nodejs.devopslee.com/list
Auto-Renewal của chứng chỉ SSL Certificates
Với chứng chỉ mà ta đã tạo, sử dụng Let’s Encrypt, sẽ có giá trị trong 90 ngày. Do đó, ta cần có phương án để cập nhật chứng chỉ tự động, giúp ta tránh khỏi việc giữ chứng chỉ hết hiệu lực.
Để tự động hóa quy trình này, ta sẽ tạo một script giúp ta cập nhật chứng chỉ, và một cronjob để lên lịch chạy script.
- Tạo một script với -dry-run để kiểm tra script
vim renew-cert.sh
#!/bin/bash
COMPOSE=”/usr/local/bin/docker-compose –no-ansi”
DOCKER=”/usr/bin/docker”
cd /home/ubuntu/Nodejs-docker/
$COMPOSE run certbot renew –dry-run && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af
- Thay quyền truy cập của script sang cho phép nó khởi chạy
chmod 774 renew-cert.sh
- Tạo một cronjob
sudo crontab -e
*/5 * * * * /home/ubuntu/Nodejs-docker/renew-cert.sh >> /var/log/cron.log 2>&1
- Liệt kê các cronjobs.
sudo crontab -l
- Kiểm tra các logs của cronjob sau 5 phút, khi chúng ta đã cài đặt để cronjob sẽ hoạt động 5 phút một lần.
tail -f /var/log/cron.lo
Trong ảnh chụp màn hình phía trên, bạn có thể thấy dòng tin nhắn “Simulating renewal of an existing certificate….”. Đó là bởi vì ta đã nêu rõ lựa chọn “-dry-run” trong script.
- Loại bỏ lựa chọn “–dry-run” trong script.
vim renew-cert.sh
#!/bin/bash
COMPOSE=”/usr/local/bin/docker-compose –no-ansi”
DOCKER=”/usr/bin/docker”
cd /home/ubuntu/Nodejs-docker/
$COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af
Lần này, bạn không còn thấy tin nhắn kia nữa. Script sẽ kiểm tra nếu ta cần cập nhật chứng chỉ, và nếu ta cần, nó sẽ tự động cập nhật, hoặc không sẽ hiện tin nhắn “Certificates not yet due for renewal”.
8. Bước tiếp theo sau khi triển khai ứng dụng Nodejs trên AWS?
Ta đã hoàn thành xong việc cài đặt ứng dụng Nodejs sử dụng Docker trên AWS EC2 instance. Tuy nhiên, có một vài điều ta cần lưu ý khi muốn triển khai các ứng dụng khác cho môi trường production hay bất kỳ môi trường nào khác. Ở bước tiếp theo, ta sẽ dùng một Orchestrator như ECS hay EKS để quản lý ứng dụng Nodejs trong giai đoạn production. Việc nhân rộng, tự động mở rộng, cân bằng tải, định tuyến đường truyền, quản lý container health sẽ không tự động xuất hiện với Docker và Docker-compose. Để quản lý containers và kiến trúc vi dịch vụ, bạn cần các công cụ container orchestration như ECS hay EKS.
Ngoài ra, ta không dùng bất kỳ Docker repository để lưu trữ các Docker Image cho ứng dụng Nodejs. Bạn có thể dùng AWS ECR, một container fully-managed.
Kết luận
Để triển khai ứng dụng Nodejs trên AWS, ta không nhất thiết phải tạo một ứng dụng Nodejs và triển khai chúng trên EC2 instance với một cơ sở dữ liệu tự quản lý. Có rất nhiều khía cạnh như Container hóa ứng dụng Nodejs, SSL Termination, tên miền cho ứng dụng sẽ cần phải cân nhắc khi bạn muốn tăng tốc cho giai đoạn phát triển phần mền, bảo mật, tăng độ tin cậy và dự phòng dữ liệu.
Trong bài viết này, ta đã cùng dạo qua các bước để “docker hóa” một ứng dụng sample Nodejs, sử dụng AWS RDS Amazon Aurora và triển khai ứng dụng Nodejs trên EC2 instance bằng Docker và Docker-compose. Ta kích hoạt SSL Termination tới sub-domain để truy cập vào ứng dụng Nodejs. Ta cũng đi qua các bước để tự động hóa việc cấp phép cho tên miền và gia hạn chứng chỉ SSL sử dụng Certbox.
Đây là các bước cơ bản để bắt đầu với một ứng dụng Nodejs sample. Tuy nhiên, khi ta cần ứng dụng thực tế, 100 giây của vi dịch vụ, 1000 giây của containers, volumes, networking, secrets, egress-ingress, bạn sẽ cần công cụ container orchestration. Có rất nhiều công cụ như Kubernetes, AWS ECS, AWS EKS giúp bạn nâng cấp việc quản lý vòng đời của container trong ứng dụng thực tiễn.
Về VTI Cloud
VTI Cloud là Đối tác cấp cao (Advanced Consulting Partner) của AWS, với đội ngũ hơn 50+ kỹ sư về giải pháp được chứng nhận bởi AWS. Với mong muốn hỗ trợ khách hàng trong hành trình chuyển đổi số và dịch chuyển lên đám mây AWS, VTI Cloud tự hào là đơn vị tiên phong trong việc tư vấn giải pháp, phát triển phần mềm và triển khai hạ tầng AWS cho khách hàng tại Việt Nam và Nhật Bản.
Xây dựng các kiến trúc an toàn, hiệu suất cao, linh hoạt, và tối ưu chi phí cho khách hàng là nhiệm vụ hàng đầu của VTI Cloud trong sứ mệnh công nghệ hóa doanh nghiệp.
Liên hệ với chúng tôi: Tại đây
Nguồn: Rahul Shivalkar — từ clickittech.com