You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在GCP虚拟机容器运行NestJS遇权限错误及解决过程

NestJS容器部署GCP虚拟机时EACCES权限错误的原因与修复

问题场景

通过GitHub Actions将NestJS应用部署到Google Cloud虚拟机的容器中,本地运行一切正常,但虚拟机上出现大量权限错误:

error TS5033: Could not write file '/usr/src/app/dist/users/enums/role.enum.js': EACCES: permission denied, mkdir '/usr/src/app/dist'.

error TS5033: Could not write file '/usr/src/app/dist/users/enums/role.enum.js.map': EACCES: permission denied, mkdir '/usr/src/app/dist'.

# 省略其余相同类型错误
[6:19:10 PM] Found 154 errors. Watching for file changes.

原使用的多阶段Dockerfile、docker-compose及CI工作流配置如下:

原Dockerfile

###################
# BUILD FOR LOCAL DEVELOPMENT
###################

FROM node:18 As development

WORKDIR /usr/src/app

COPY --chown=node:node package*.json ./

RUN npm ci

COPY --chown=node:node . .

USER node

###################
# BUILD FOR PRODUCTION
###################

FROM node:18 As build

WORKDIR /usr/src/app

COPY --chown=node:node package*.json ./

COPY --chown=node:node --from=development /usr/src/app/node_modules ./node_modules

COPY --chown=node:node . .

RUN npm run build

ENV NODE_ENV production

RUN npm ci --only=production && npm cache clean --force

USER node

###################
# PRODUCTION
###################

FROM node:18 As production

COPY --chown=node:node --from=build /usr/src/app/node_modules ./node_modules
COPY --chown=node:node --from=build /usr/src/app/dist ./dist

CMD [ "node", "dist/main.js" ]

原docker-compose配置

services:
  api:
    restart: always
    build:
      dockerfile: Dockerfile
      context: .
      target: development
    env_file:
    - .env
    command: npm run start:dev
    ports:
      - 3000:3000
    depends_on:
      - postgres

  postgres:
    image: postgres
    restart: always
    ports:
      - "5435:5432"
    environment:
      POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
      
  pgadmin:
    image: dpage/pgadmin4
    restart: always
    container_name: pgadmin4
    environment:
      - PGADMIN_DEFAULT_EMAIL=${PGADMIN_DEFAULT_EMAIL}
      - PGADMIN_DEFAULT_PASSWORD=${PGADMIN_DEFAULT_PASSWORD}
    ports:
      - '5050:80'
    depends_on:
      - postgres
  
  redis:
    image: redis
    ports:
      - "6379:6379"
    restart: always
    environment:
      - REDIS_PASSWORD=${REDIS_PASSWORD}
    command: redis-server --requirepass ${REDIS_PASSWORD}

原CI工作流

name: deployment

on:
  push:
    branches: [ "test" ]
  pull_request:
    branches: [ "test" ]

jobs:

  deploy:

    runs-on: self-hosted

    steps:
    - name: Clone repository 
      uses: actions/checkout@v4
      with:
        ref: ${{ github.event.pull_request.head.ref }}
    - run: echo "🖥️ The workflow is now ready to test your code on the runner."
    - name: List files in the repository
      run: |
        ls ${{ github.workspace }}
    - run: cp .env.example .env
    - run: npm install
    - name: deploy
      run: docker compose -f ci.docker-compose.yml up --detach --force-recreate

尝试过在Dockerfile和docker-compose中添加chown、mkdir dist等语句,但均未解决问题。重构后的简化配置(不切换node用户)可正常运行。

问题原因

原配置的核心问题在于开发阶段以node非root用户运行,但容器内的工作目录/usr/src/app本身属于root用户:

  1. WORKDIR /usr/src/app由root用户创建,目录所有者为root
  2. 虽然用COPY --chown=node:node复制了文件,但仅修改了文件的所有者,目录本身的权限并未变更
  3. npm run start:dev需要实时编译TypeScript到dist目录,但node用户没有在/usr/src/app下创建新目录的权限,因此抛出EACCES错误

重构后的配置未切换到node用户,默认以root身份运行容器,自然拥有目录写入权限,因此能正常工作,但这种方式在生产环境存在安全风险。

原配置修复方案

无需重构配置,只需在development阶段确保node用户拥有工作目录或dist目录的写入权限:

方案1:提前创建dist目录并修改所有者

在原Dockerfile的development阶段、USER node之前添加以下指令:

# 在切换到node用户前,创建dist目录并修改所有者
RUN mkdir dist && chown node:node dist

方案2:修改工作目录的所有者

更彻底的方式是直接修改整个工作目录的所有者,确保node用户拥有完整写入权限:

FROM node:18 As development

WORKDIR /usr/src/app
# 修改工作目录所有者为node用户
RUN chown node:node /usr/src/app

COPY --chown=node:node package*.json ./
RUN npm ci
COPY --chown=node:node . .

USER node

方案3:临时以root用户运行开发容器(不推荐)

在docker-compose的api服务中添加user: root,强制以root身份启动容器:

services:
  api:
    restart: always
    build:
      dockerfile: Dockerfile
      context: .
      target: development
    user: root # 添加此行
    # ... 其余配置不变

该方式仅适合开发环境临时测试,生产环境禁止使用root用户运行容器。

内容的提问来源于stack exchange,提问作者Kacper Woźniak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 18:33:21