Dockerizing Node.js web app

Trong bài viết này mình sẽ chỉ cho các bạn cách đưa một ứng dụng node.js vào một docker container. Tuy nhiên hướng dẫn chỉ cho môi trường develop, không phải cho môi trường product. Ngoài ra trong đây còn mô tả về cài đặt docker cũng như cấu trúc cơ bản của một ứng dụng Node.js

Docker ra đời cho giải pháp đóng gói, vận chuyển và triển khai ứng dụng hết sức nhanh chóng và đơn giản. Với Docker, các thành viên trong team (cũng như với người muốn trải nghiệm thử project) sẽ triển khai ngay được môi trường ứng dụng mà không phải mất nhiều thời gian, công việc của SysAdmin cũng nhẹ nhàng hơn.

Mình sẽ hướng dẫn cách đóng gói build image docker cho ứng dụng Nodejs một cách cơ bản nhất.

Tạo Node.js app

Mỗi ứng dụng viết bằng Nodejs bắt buộc đều phải có package.json, lưu thông tin về các gói cần thiết, nhiều thông tin khác về tên, phiên bản, ...

{
  "name": "docker_web_app",
  "version": "1.0.0",
  "description": "Node.js on Docker",
  "author": "First Last <[email protected]>",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.16.1"
  }
}

Với file package.json, chạy npm install. Nếu bạn sử dụng npm version >= 5.0, file package-lock.json được tạo ra sẽ được copy vào Docker image Tiếp theo, tạo một server.js file để định nghĩa ứng dụng sử dung Express.js framework:

'use strict';

const express = require('express');

// Constants
const PORT = 8080;
const HOST = '0.0.0.0';

// App
const app = express();
app.get('/', (req, res) => {
  res.send('Hello world\n');
});

app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);

Bước tiếp theo, chúng ta học cách chạy một ứng dụng bên trong một docker container sử dụng docker image. Trước tiên, ta cần build một docker image của ứng dụng.

Tạo Dockerfile

Tạo một file trống Dockerfile và mở trong editor:

touch Dockerfile Mở file Dockerfile bằng Editor. Đầu tiên, cần định nghĩa ứng dụng sẽ build trên image nào. Danh sách các image Nodejs có tại đây.

FROM node:carbon

Tạo thư mục chứa toàn bộ code ứng dụng ở trong image, đây sẽ là thư mụn làm việc cho ứng dụng của bạn.

# Create app directory
WORKDIR /usr/src/app

Image trên sẽ có sẵn Node.js và Nmp, vì vậy, chúng ta chỉ cần cài ứng dụng một cách độc lập sử dung npm binanry. Chú ý rằng nếu bạn sử dụng npm version <= 4. thì file package-lock.json sẽ không được sinh ra.

# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available ([email protected]+)
COPY package*.json ./

RUN npm install
# If you are building your code for production
# RUN npm install --only=production

Thay vì copy toàn bộ thư mục, ta chỉ copy file package.json. Bundle source code ứng dụng trong docker image :

# Bundle app source
COPY . .

sử dụng EXPOSE để mở PORT 8080 trên Container, thay 8080 bằng port ứng dụng của bạn:

EXPOSE 8080

Cuối cùng quan trọng nhất là lệnh để khởi động ứng dụng Nodejs, lệnh CMD sẽ chạy npm start, cũng như start node app.js được định nghĩa trong package.json

CMD [ "npm", "start" ]

Cuối cùng được Dockerfile hoàn chỉnh như thế này:

FROM node:carbon

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available ([email protected]+)
COPY package*.json ./

RUN npm install
# If you are building your code for production
# RUN npm install --only=production

# Bundle app source
COPY . .

EXPOSE 8080
CMD [ "npm", "start" ]

.dockerignore file

Tạo .dockerignore file trong cùng thư mục của Dockerfile với nội dung:

node_modules
npm-debug.log

Build image

Cd đến thư mục chứa Dockerfile, chạy lệnh bên dưới để build image. --tag dùng để đặt tên cho ảnh dễ nhớ, nhớ đừng bỏ xót dấu chấm ở cuối.

$ docker build -t <your username>/node-web-app .

Sau khi build thành công, xem lại danh sách Docker image bằng:

$ docker images

# Example
REPOSITORY                      TAG        ID              CREATED
node                            carbon     1934b0b038d1    5 days ago
<your username>/node-web-app    latest     d64d3505b0d2    1 minute ago

Khởi chạy image

Run docker image với tùy chọn -d sẽ chạy container dưới background, tùy chọn -p sẽ mapping port của máy thật (public) với port của container (private)

$ docker run -p 49160:8080 -d <your username>/node-web-app

Xem danh sách các container và log đang chạy:

# Get container ID
$ docker ps

# Print app output
$ docker logs <container id>

# Example
Running on http://localhost:8080

Nếu cần truy cập vào container đang chạy, sử dụng:

# Enter the container
$ docker exec -it <container id> /bin/bash

Test

$ docker ps

# Example
ID            IMAGE                                COMMAND    ...   PORTS
ecce33b30ebf  <your username>/node-web-app:latest  npm start  ...   49160->8080

Trong ví dụ trên, docker map cổng 8080 của container ra cổng 49160 của máy bạn Test: truy cập thử ứng dụng bằng trình duyệt: http://localhost:49160

Bây giờ bạn có thể gọi ứng dụng bằng curl (cài đặt: sudo apt-get install curl):

$ curl -i localhost:49160

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 12
ETag: W/"c-M6tWOb/Y57lesdjQuHeB1P/qTV0"
Date: Mon, 13 Nov 2017 20:53:59 GMT
Connection: keep-alive

Hello world

Chúc các bạn chạy được ứng dụng Node.js đơn giản trên Docker.