I’m trying to run NestJS app inside a container on VM on Google Cloud via GitHub Actions.
Locally everything is running correctly, however on VM I receive below permission errors:
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'.
error TS5033: Could not write file '/usr/src/app/dist/users/users.module.d.ts': EACCES: permission denied, mkdir '/usr/src/app/dist'.
error TS5033: Could not write file '/usr/src/app/dist/users/users.module.js': EACCES: permission denied, mkdir '/usr/src/app/dist'.
error TS5033: Could not write file '/usr/src/app/dist/users/users.module.js.map': EACCES: permission denied, mkdir '/usr/src/app/dist'.
error TS5033: Could not write file '/usr/src/app/dist/users/users.resolver.d.ts': EACCES: permission denied, mkdir '/usr/src/app/dist'.
error TS5033: Could not write file '/usr/src/app/dist/users/users.resolver.js': EACCES: permission denied, mkdir '/usr/src/app/dist'.
error TS5033: Could not write file '/usr/src/app/dist/users/users.resolver.js.map': EACCES: permission denied, mkdir '/usr/src/app/dist'.
error TS5033: Could not write file '/usr/src/app/dist/users/users.service.d.ts': EACCES: permission denied, mkdir '/usr/src/app/dist'.
error TS5033: Could not write file '/usr/src/app/dist/users/users.service.js': EACCES: permission denied, mkdir '/usr/src/app/dist'.
error TS5033: Could not write file '/usr/src/app/dist/users/users.service.js.map': EACCES: permission denied, mkdir '/usr/src/app/dist'.
[6:19:10 PM] Found 154 errors. Watching for file changes.
My 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
As you can see I’m using only development part from the Dockerfile.
I was using different statements in Dockerfile and docker-compose: chown, mkdir dist, etc., however unsuccessfully.
Edit:
I restructured Dockerfile:
FROM node:18
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "run", "start:dev"]
and docker compose:
services:
api:
build:
dockerfile: Dockerfile
context: .
restart: always
ports:
- '3000:3000'
env_file:
- .env
depends_on:
- postgres
volumes:
- .:/app/src
postgres:
image: postgres
restart: always
ports:
- "5432: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}
I don’t know what was wrong with previous configuration, but works alright with this one.
2
Answers
try this, I hope it works.
check your dist directory’s owner, if it was root change it to non-root user
$USER
or delete your directory and rebuild it without sudo permission.I guess this is because user "node" does not have the permission to mkdir "dist" and modify files in it.
If I were you, I will connect to the container’s file system and check the owner. This is the most reliable way to find the real reason.