在 Microservice 架構下,理論上 Nginx 與 Node 應該各自放在不同 Container 下,但有時 API 就是要控制 Nginx 或其他執行檔如 FFmpeg,此時將 Node 與 Nginx 包在同一個 Image 會更方便。
Version
Nginx 1.18.0
Node 12.15.0
Dockerfile
FROM nginx:stable-alpine
WORKDIR /usr/src/app
COPY default.conf /etc/nginx/conf.d/
COPY package.json .
COPY index.js .
COPY entrypoint.sh /
RUN apk add nodejs -q
RUN apk add yarn -q
RUN yarn install
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
第 1 行
FROM nginx:stable-alpine
以 nginx:stable-alpine
為基底。
第 2 行
WORKDIR /usr/src/app
將預設目錄設定在 /usr/src/app
,也就是 Node 相關 *.js
的所在目錄。
第 4 行
COPY default.conf /etc/nginx/conf.d/
將自定義了 Nginx configuration 檔複製進 image。
第 5 行
COPY package.json .
將 package.json
複製進 image。
第 6 行
COPY index.js .
將 Node 所有檔案複製進 image。
第 7 行
COPY entrypoint.sh /
將自定義的 entrypoint.sh
複製進 image。
為什麼要使用 script ? 稍後會解釋
第 9 行
RUN apk update
RUN apk add nodejs -q
RUN apk add yarn -q
安裝 Node 與 Yarn。
在 alpine 內只能使用
apk
,不能使用apt-get
12 行
RUN yarn install
根據 package.json
安裝 NPM package,如 express
。
13 行
RUN chmod +x /entrypoint.sh
賦予 entrypoint.sh
有執行權利。
15 行
ENTRYPOINT ["/entrypoint.sh"]
最後執行 entrypoint.sh
。
Nginx Configuration
default.conf
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
採用預設的 Nginx 設定檔。
Node
index.js
let express = require('express')
let app = express()
let port = 3000
app.get('/hello', (req, res) => {
res.send('world')
})
app.listen(port, _ => console.log(`Node listening on port ${port}`))
使用 Express 實現簡單的 RESTful GET API。
Shell Script
entrypoint.sh
#!/bin/sh
node index.js &
nginx -g 'daemon off;'
由於 container 必須啟動 Node 與 Nginx,因此必須透過 entrypoint.sh
啟動。
因為已經設定好 WORKDIR
為 /usr/src/app
,可直接以 node
執行 index.js
。
但還得啟動 Nginx,只好在 node
最後加上 &
,表示在背景執行,最後執行 Nginx。
Docker Compose
version: "3"
services:
nginx:
image: nginx-node:0.1.0
container_name: MyNginx
restart: always
ports:
- "80:80"
- "3000:3000"
Nginx 使用了 port 80
,而 Node 使用了 port 3000
,須在 docker-compose.yml
特別設定。
NPM Script
{
"name": "nginx-node",
"version": "0.1.0",
"private": true,
"scripts": {
"api": "node index.js",
"docker:build": "docker build -t $npm_package_name:$npm_package_version .",
"docker:save": "docker save $npm_package_name:$npm_package_version | gzip > $npm_package_name-$npm_package_version.tar.gz",
"docker:login": "docker exec -it MyNginx sh",
"docker:log": "docker logs MyNginx",
"docker:rmi": "docker rmi $npm_package_name:$npm_package_version",
"docker:up": "docker-compose up -d",
"docker:down": "docker-compose down"
},
"dependencies": {
"express": "^4.17.1"
}
}
將常用 Docker command 以 NPM script 管理。
Conclusion
- 若其他 server 也想將 Node 包進去,也可參考此文方式