Node.js 的 Docker 最佳实践指南
Node官方引用的 jmealo 写的一篇docker 和 node.js 的最佳实践。
前言
Node官方引用的 jmealo 写的一篇docker 和 node.js 的最佳实践。
环境变量
运行时将 NODE_ENV
设置为 production
。这也是你向你的应用程序传递加密和其他运行时配置的方式。
-e "NODE_ENV=production"
全局npm依赖
如果你需要安装全局npm依赖项,建议将这些依赖项放在非root用户目录下。为了实现这一点,在你的 Dockerfile
文件中添加以下一行:
ENV NPM_CONFIG_PREFIX=/home/node/.npm-global
ENV PATH=$PATH:/home/node/.npm-global/bin
# optionally if you want to run npm global bin without specifying path
升级/降级 Yarn
本地(局部)
如果你需要对本地安装的 yarn
进行升级/降级,你可以通过在 Dockerfile
中发出以下命令来实现:
注意,如果你创建了一些其他的目录,而这些目录不是你运行命令的地方的后代目录,你最终会使用全局(过时)的版本。如果你想在全局范围内升级yarn,请按照下一节的说明进行。
当按照本地安装说明进行安装时,由于重复的yarn,镜像最终会变大。
FROM node:6
ENV YARN_VERSION 1.16.0
RUN yarn policies set-version $YARN_VERSION
全局
FROM node:6
ENV YARN_VERSION 1.16.0
RUN curl -fSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \
&& tar -xzf yarn-v$YARN_VERSION.tar.gz -C /opt/ \
&& ln -snf /opt/yarn-v$YARN_VERSION/bin/yarn /usr/local/bin/yarn \
&& ln -snf /opt/yarn-v$YARN_VERSION/bin/yarnpkg /usr/local/bin/yarnpkg \
&& rm yarn-v$YARN_VERSION.tar.gz
如果你使用的是基于Alpine的镜像,curl
命令将不存在,所以你需要确保在使用它的时候安装了它:
FROM node:6-alpine
ENV YARN_VERSION 1.5.1
RUN set -eux && sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
#国内可能需要切换下系统软件源
RUN apk add --no-cache --virtual .build-deps-yarn curl \
&& curl -fSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \
&& tar -xzf yarn-v$YARN_VERSION.tar.gz -C /opt/ \
&& ln -snf /opt/yarn-v$YARN_VERSION/bin/yarn /usr/local/bin/yarn \
&& ln -snf /opt/yarn-v$YARN_VERSION/bin/yarnpkg /usr/local/bin/yarnpkg \
&& rm yarn-v$YARN_VERSION.tar.gz \
&& apk del .build-deps-yarn
处理内核信号
Node.js不是被设计成以PID 1的形式运行的,这导致了在Docker内部运行时的意外行为。例如,作为PID 1运行的Node.js进程不会响应 SIGINT
(CTRL-C
)和类似的信号。从Docker 1.13开始,你可以使用 --init
标志将你的Node.js进程包裹在一个轻量级的init系统中,该系统可以正确处理作为PID 1运行。
$ docker run -it --init node
你也可以在你的Dockerfile文件中直接包含Tini,确保你的进程总是以init包装器启动。
非root用户
默认情况下,Docker以root身份在容器内运行命令,当超级用户权限不是严格需要时这违反了最低权限原则(PoLP)。你希望尽可能地以非特权用户的身份运行容器。node镜像为这种目的提供了 node
用户。然后可以用 node
用户运行Docker Image,方法如下:
-u "node"
或者,可以在 Dockerfile
文件中激活该用户:
FROM node:6.10.3
...
# At the end, set the user to use when running this image
USER node
注意,node
用户既不是构建时的依赖,也不是运行时的依赖,只要你想添加到容器中的应用程序的功能不依赖于它,它就可以被删除或改变。
如果你不想要也不需要在这个镜像中创建的用户,你可以用下面的方法删除它:
# For debian based images use:
RUN userdel -r node
# For alpine based images use:
RUN deluser --remove-home node
如果你需要改变用户的uid/gid,你可以使用:
RUN groupmod -g 999 node && usermod -u 999 -g 999 node
如果你需要用户的另一个名字(例如:myapp
),执行:
RUN usermod -d /home/myapp -l myapp node
对于基于alpine的镜像,你没有 groupmod
也没有 usermod
,所以要改变uid/gid你必须删除以前的用户:
RUN deluser --remove-home node \
&& addgroup -S node -g 999 \
&& adduser -S -G node -u 999 node
内存
默认情况下,任何Docker容器可能消耗大量的硬件资源,如CPU和RAM。如果你在同一台主机上运行多个容器,你应该限制它们能消耗多少内存。
-m "300M" --memory-swap "1G"
CMD
在创建镜像时,你可以绕过 package.json
的 start
命令,直接将其记录到镜像本身。首先,这可以减少在你的容器内运行的进程的数量。其次,它导致退出信号如 SIGTERM
和 SIGINT
被Node.js进程接收,而不是npm吞下它们。
CMD ["node","index.js"]
Docker Run
下面是一个如何运行默认的Node.JS Docker容器化应用程序的例子:
$ docker run \
-e "NODE_ENV=production" \
-u "node" \
-m "300M" --memory-swap "1G" \
-w "/home/node/app" \
--name "my-nodejs-app" \
node [script]
安全
Docker团队提供了一个工具来分析你正在运行的容器的潜在安全问题。你可以从这里下载并运行这个工具:https://github.com/docker/docker-bench-security
node-gyp alpine
下面是一个例子,说明你如何在alpine变体上安装需要node-gyp支持的软件包的依赖:
FROM node:alpine
RUN apk add --no-cache --virtual .gyp python3 make g++ \
&& npm install [ your npm dependencies here ] \
&& apk del .gyp
国内需要切换系统软件源,需在FROM下一行加上:
RUN set -eux && sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
这里有一个多阶段构建的例子:
FROM node:alpine as builder
## Install build toolchain, install node deps and compile native add-ons
RUN apk add --no-cache python3 make g++
RUN npm install [ your npm dependencies here ]
FROM node:alpine as app
## Copy built node modules and binaries without including the toolchain
COPY --from=builder node_modules .
总结
十分实用的实践技巧。
参考链接:
更多推荐
所有评论(0)