skip to Main Content

With the aim of avoiding root user running in the container, I’ve got the following Dockerfile:

FROM public.ecr.aws/docker/library/node:14-alpine AS deps

RUN apk add --no-cache libc6-compat curl 
 && addgroup --system --gid 1001 app_user 
 && adduser --system --uid 1001 app_user

RUN mkdir /app 
  && chown -R app_user:app_user /app
USER app_user
WORKDIR /app

COPY --chown=app_user:app_user package*.json yarn.lock ./
RUN yarn install --production=false --pure-lockfile --ignore-engines

FROM public.ecr.aws/docker/library/node:14-alpine AS builder
WORKDIR /app

COPY --chown=app_user:app_user components pages public queries styles lib @types ./
COPY --chown=app_user:app_user tsconfig.json constants.js next.config.js .babelrc ./
COPY --chown=app_user:app_user scripts/cache/ ./scripts/cache

COPY --chown=app_user:app_user --from=deps /usr/src/app/package.json ./
COPY --chown=app_user:app_user --from=deps /usr/src/app/node_modules ./node_modules

ENV CACHE_REFRESH_SECRET_TOKEN=$CACHE_REFRESH_SECRET_TOKEN

RUN CODEBUILD_BUILD_ID=$CODEBUILD_BUILD_ID DEBUG=graphql:errors,graphql:queries,cache:redis DEBUG_COLORS=true npm run build

EXPOSE 8080 6379
ENTRYPOINT [ "npm", "start"]

Line COPY --chown=app_user:app_user package*.json yarn.lock ./ won’t fail, but once reaching the line COPY --chown=app_user:app_user components pages public queries styles lib @types ./ it’ll err out with the following message:

unable to convert uid/gid chown string to host mapping: can't find uid for user app_user: no such user: app_user

I’m a bit strange as I think I’m following directions from docs and multiple guides. What should be corrected?

2

Answers


  1. In multistage of docker build you can not re-use the same user so in each FROM you must re-create it.

    I made the changes in lines 17 to 23

      1 FROM public.ecr.aws/docker/library/node:14-alpine AS deps
      2 
      3 RUN apk add --no-cache libc6-compat curl 
      4  && addgroup --system --gid 1001 app_user 
      5  && adduser --system --uid 1001 app_user
      6 
      7 RUN mkdir /app 
      8   && chown -R app_user:app_user /app
      9 USER app_user
     10 WORKDIR /app
     11 
     12 COPY --chown=app_user:app_user package*.json yarn.lock ./
     13 RUN yarn install --production=false --pure-lockfile --ignore-engines
     14 
     15 FROM public.ecr.aws/docker/library/node:14-alpine AS builder
     16 
     17 RUN apk add --no-cache libc6-compat curl 
     18  && addgroup --system --gid 1001 app_user 
     19  && adduser --system --uid 1001 app_user
     20 
     21 RUN mkdir /app 
     22   && chown -R app_user:app_user /app
     23 USER app_user
     24 WORKDIR /app
     25 
     26 ARG NODE_ENV=production
     27 ARG CODEBUILD_RESOLVED_SOURCE_VERSION
     28 ARG CODEBUILD_BUILD_ID
     29 ARG CODEBUILD_BUILD_NUMBER
     30 ARG CODEBUILD_START_TIME
     31 ARG ELASTIC_CACHE_NODE_ADDRESS
     32 ARG CONTENTFUL_SPACE_ID
     33 ARG CONTENTFUL_ENVIRONMENT_ID
     34 ARG CONTENTFUL_DELIVERY_TOKEN
     35 ARG CONTENTFUL_PREVIEW_TOKEN
     36 ARG PREVIEW_MODE_SECRET_TOKEN
     37 ARG BUILD_TRIGGER_SECRET_TOKEN
     38 ARG CACHE_REFRESH_SECRET_TOKEN
     39 ARG BUILD_RSS_SECRET_TOKEN
     40 
     41 ARG NEXT_PUBLIC_ALGOLIA_APPLICATION_ID
     42 ARG NEXT_PUBLIC_ALGOLIA_INDEX_NAME
     43 ARG NEXT_PUBLIC_ALGOLIA_SEARCH_KEY
     44 ARG ALGOLIA_INDEXING_SECRET_TOKEN
     45 
     46 ARG CSP_REPORT_URI
     47 ARG CSP_ENABLED
     48 
     49 ARG POSTS_CSV_SECRET_TOKEN
     50 
     51 ENV CODEBUILD_RESOLVED_SOURCE_VERSION=$CODEBUILD_RESOLVED_SOURCE_VERSION
     52 ENV CODEBUILD_BUILD_ID=$CODEBUILD_BUILD_ID
     53 ENV ELASTIC_CACHE_NODE_ADDRESS=$ELASTIC_CACHE_NODE_ADDRESS
     54 ENV CONTENTFUL_SPACE_ID=$CONTENTFUL_SPACE_ID
     55 ENV CONTENTFUL_ENVIRONMENT_ID=$CONTENTFUL_ENVIRONMENT_ID
     56 ENV CONTENTFUL_DELIVERY_TOKEN=$CONTENTFUL_DELIVERY_TOKEN
     57 ENV CONTENTFUL_PREVIEW_TOKEN=$CONTENTFUL_PREVIEW_TOKEN
     58 ENV PREVIEW_MODE_SECRET_TOKEN=$PREVIEW_MODE_SECRET_TOKEN
     59 ENV BUILD_TRIGGER_SECRET_TOKEN=$BUILD_TRIGGER_SECRET_TOKEN
     60 ENV BUILD_RSS_SECRET_TOKEN=$BUILD_RSS_SECRET_TOKEN
     61 
     62 ENV CSP_REPORT_URI=$CSP_REPORT_URI
     63 ENV CSP_ENABLED=$CSP_ENABLED
     64 
     65 ENV NEXT_PUBLIC_ALGOLIA_APPLICATION_ID=$NEXT_PUBLIC_ALGOLIA_APPLICATION_ID
     66 ENV NEXT_PUBLIC_ALGOLIA_INDEX_NAME=$NEXT_PUBLIC_ALGOLIA_INDEX_NAME
     67 ENV NEXT_PUBLIC_ALGOLIA_SEARCH_KEY=$NEXT_PUBLIC_ALGOLIA_SEARCH_KEY
     68 ENV ALGOLIA_INDEXING_SECRET_TOKEN=$ALGOLIA_INDEXING_SECRET_TOKEN
     69 
     70 ENV POSTS_CSV_SECRET_TOKEN=$POSTS_CSV_SECRET_TOKEN
     71 
     72 ENV NEXT_PUBLIC_CODEBUILD_RESOLVED_SOURCE_VERSION=$CODEBUILD_RESOLVED_SOURCE_VERSION
     73 ENV NEXT_PUBLIC_CODEBUILD_BUILD_ID=$CODEBUILD_BUILD_ID
     74 ENV NEXT_PUBLIC_CTF_ENVIRONMENT_ID=$CONTENTFUL_ENVIRONMENT_ID
     75 ENV NEXT_PUBLIC_CODEBUILD_BUILD_NUMBER=$CODEBUILD_BUILD_NUMBER
     76 ENV NEXT_PUBLIC_CODEBUILD_START_TIME=$CODEBUILD_START_TIME
     77 
     78 COPY --chown=app_user:app_user components pages public queries styles lib @types ./
     79 COPY --chown=app_user:app_user tsconfig.json constants.js next.config.js .babelrc ./
     80 COPY --chown=app_user:app_user scripts/cache/ ./scripts/cache
     81 
     82 COPY --chown=app_user:app_user --from=deps /usr/src/app/package.json ./
     83 COPY --chown=app_user:app_user --from=deps /usr/src/app/node_modules ./node_modules
     84 
     85 ENV CACHE_REFRESH_SECRET_TOKEN=$CACHE_REFRESH_SECRET_TOKEN
     86 
     87 RUN CODEBUILD_BUILD_ID=$CODEBUILD_BUILD_ID DEBUG=graphql:errors,graphql:queries,cache:redis DEBUG_COLORS=true npm run build
     88 
     89 EXPOSE 8080 6379
     90 ENTRYPOINT [ "npm", "start"]
    
    Login or Signup to reply.
  2. There’s no particular requirement that the (non-root) user running the container be the same user that owns the files. It can be a minor security improvement to have the source code owned by root and not world-writable, which will prevent the application from doing things like overwriting its own static images (intentionally or otherwise).

    One straightforward approach is to do all of the package installation and building as root in the Dockerfile, and only switch to the non-root user at the very end of the Dockerfile.

    FROM public.ecr.aws/docker/library/node:14-alpine AS deps
    
    # Doing the `yarn install` step as root, so no need to create a user here
    RUN apk add --no-cache libc6-compat curl
    
    WORKDIR /app
    COPY package*.json yarn.lock ./
    RUN yarn install --production=false --pure-lockfile --ignore-engines
    
    FROM public.ecr.aws/docker/library/node:14-alpine AS builder
    
    # Create the non-root user, without a specific uid; do not switch yet
    RUN adduser --system app_user
    
    # Do the rest of the installation steps, still as root
    WORKDIR /app
    COPY components pages public queries styles lib @types ./
    COPY tsconfig.json constants.js next.config.js .babelrc ./
    COPY scripts/cache/ ./scripts/cache
    
    COPY --from=deps /app/package.json /app/yarn.lock ./
    COPY --from=deps app/node_modules ./node_modules
    
    RUN yarn build
    
    # As part of the runtime setup, switch to the non-root user now
    EXPOSE 8080
    USER app_user
    CMD ["yarn", "start"]
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search