node.js - 如何避免更改 docker 中非 root 用户对 node_modules 的权限
问题描述
我当前文件的问题是,在我的entrypoint.sh
文件中,我必须将整个项目目录的所有权更改为非管理用户 ( chown -R node /node-servers
)。但是,当npm
安装了很多包时,这会花费很多时间。有没有办法避免chown
进入node_modules
目录?
背景:我将所有内容都创建为 root 的原因Dockerfile
是因为这样我可以匹配开发人员的本地用户的UID
和GID
。这使得安装卷更容易。缺点是我必须在一个entrypoint.sh
文件中从root下级,并确保整个项目文件的权限都已更改为非管理员用户。
我的码头文件:
FROM node:10.24-alpine
#image already has user node and group node which are 1000, thats what we will use
# grab gosu for easy step-down from root
# https://github.com/tianon/gosu/releases
ENV GOSU_VERSION 1.14
RUN set -eux; \
\
apk add --no-cache --virtual .gosu-deps \
ca-certificates \
dpkg \
gnupg \
; \
\
dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \
wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \
wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \
\
# verify the signature
export GNUPGHOME="$(mktemp -d)"; \
gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \
gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \
command -v gpgconf && gpgconf --kill all || :; \
rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \
\
# clean up fetch dependencies
apk del --no-network .gosu-deps; \
\
chmod +x /usr/local/bin/gosu; \
# verify that the binary works
gosu --version; \
gosu nobody true
COPY ./ /node-servers
# Setting the working directory
WORKDIR /node-servers
# Install app dependencies
# Install openssl
RUN apk add --update openssl ca-certificates && \
apk --no-cache add shadow && \
apk add libcap && \
npm install -g && \
chmod +x /node-servers/entrypoint.sh && \
setcap cap_net_bind_service=+ep /usr/local/bin/node
# Entrypoint used to load the environment and start the node server
#ENTRYPOINT ["/bin/sh"]
我的 entrypoint.sh
# In Prod, this may be configured with a GID already matching the container
# allowing the container to be run directly as Jenkins. In Dev, or on unknown
# environments, run the container as root to automatically correct docker
# group in container to match the docker.sock GID mounted from the host
set -x
if [ -z ${HOST_UID+x} ]; then
echo "HOST_UID not set, so we are not changing it"
else
echo "HOST_UID is set, so we are changing the container UID to match"
# get group of notadmin inside container
usermod -u ${HOST_UID} node
CUR_GID=`getent group node | cut -f3 -d: || true`
echo ${CUR_GID}
# if they don't match, adjust
if [ ! -z "$HOST_GID" -a "$HOST_GID" != "$CUR_GID" ]; then
groupmod -g ${HOST_GID} -o node
fi
if ! groups node | grep -q node; then
usermod -aG node node
fi
fi
# gosu drops from root to node user
set -- gosu node "$@"
[ -d "/node-servers" ] && chown -v -R node /node-servers
exec "$@"
解决方案
你根本不需要chown
在这里跑步。保留 root(或主机用户)拥有的文件。只要它们是世界可读的,应用程序仍然可以运行;但如果存在某种安全问题或其他错误,应用程序将无法意外覆盖其自己的源代码。
然后,您可以继续进一步简化它。在大多数情况下,Unix 中的用户是通过他们的数字用户 ID 来识别的;实际上并没有要求将用户列在/etc/passwd
. 如果您不需要更改node
用户 ID 并且不需要chown
文件,则入口点脚本简化为“切换用户 ID 并运行主脚本”;但是 Docker 可以通过该docker run -u
选项为您提供备用用户 ID。这意味着您也不需要安装gosu
,这是很多 Dockerfile 内容。
所有这一切意味着您可以将 Dockerfile 缩减为:
FROM node:10.24-alpine
# Install OS-level dependencies (before you COPY anything in)
apk add openssl ca-certificates
# (Do not install gosu or its various dependencies)
# Set (and create) the working directory
WORKDIR /node-servers
# Copy language-level dependencies in
COPY package.json package-lock.json .
RUN npm ci
# Copy the rest of the application in
# (make sure `node_modules` is in .dockerignore)
COPY . .
# (Do not call setcap here)
# Set the main command to run
USER node
CMD npm run start
然后在运行容器时,可以使用 Docker 选项来指定当前用户和附加功能。
docker run \
-d \ # in the background
-u $(id -u) \ # as an alternate user
-v "$PWD/data:/node-servers/data" \ # mounting a data directory
-p 8080:80 \ # publishing a port
my-image
Docker默认授予该NET_BIND_SERVICE
功能,因此您无需专门设置它。
如果您使用绑定挂载来覆盖应用程序代码,同样的权限设置也将起作用;再次,没有chown
电话。
docker run ... \
-u $(id -u) \
-v "$PWD:/node-servers" \ # run the application from the host, not the image
-v /node-servers/node_modules \ # with libraries that will not be updated ever
...
推荐阅读
- html - Is it possible to put arrows between these flipping circles?
- firebase - Building a REST API, using firebase as a backend
- javascript - VueJS 是否提供某种重定向参数白名单?
- android - AsyncTask 卡住了
- javascript - Facebook will not ask the required permission on log in
- c# - 如何将网络摄像头捕获的图像保存到项目文件夹/特定文件夹中
- string - 将字符串转换为插入次数最少的回文
- sql-server - 使用 in 语句的具有多个值的 SQL 搜索查询
- foreign-keys - 具有相同 ID 的表连接到另一个表
- php - WooCommerce 以编程方式修改购物车总数