# ------------------------------------------------------------------------------ # Dockerfile based on Price's best practice # - using multi-stage builds # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # Standard Args (with default values) for Price's docker image # ------------------------------------------------------------------------------ ARG org_label_schema_vendor="Price.com.hk" ARG org_label_schema_schema_version=1.0 ARG org_label_schema_name=unknown ARG org_label_schema_version=unknown ARG org_label_schema_vcs_url=unknown ARG org_label_schema_vcs_ref=unknown ARG org_label_schema_build_date=unknown ARG org_label_schema_description ARG maintainer="it.web@price.com.hk" # ----------------------------------------------------------------------------- # Application Args/Envs # ----------------------------------------------------------------------------- ARG NODEJS_VERSION="18.12" ARG SUITE_VERSION="bullseye-slim" ARG APP_ROOT="/home/node/app" ARG APP_VERSION="not-yet-set" ARG APP_PORT=3000 # ------------------------------------------------------------------------------ # Build the base image layer with Docker multi-stage builds # - Install necessary packages as to add cache layer # ------------------------------------------------------------------------------ FROM node:${NODEJS_VERSION}-${SUITE_VERSION} AS base # ----------------------------------------------------------------------------- # Install required software package # ----------------------------------------------------------------------------- RUN apt update -y \ # - health check & timezone && apt install -y curl tzdata dumb-init # ----------------------------------------------------------------------------- # Purge / Clean up # ----------------------------------------------------------------------------- RUN apt-get clean autoclean \ && apt-get autoremove --yes \ && rm -rf \ /var/lib/{apt,dpkg,cache,log}/ \ /tmp/* # ------------------------------------------------------------------------------ # Build the NodeJS Application with Docker multi-stage builds # - Making node_modules, separate from source as to add cache layer # ------------------------------------------------------------------------------ FROM base AS nodejs_build ARG APP_ROOT RUN mkdir -p ${APP_ROOT} && chown node:node ${APP_ROOT} WORKDIR ${APP_ROOT} # Set the user for building operation USER node # ----- Install dependencies packages # NOTE: Should not use `--ignore-optional --production` options # because of TS or Bable is used. COPY package.json yarn.lock ${APP_ROOT}/ RUN yarn install # ---- Copy application source codes and build COPY src ${APP_ROOT}/src COPY tsconfig*.json .eslint*.js .prettierrc ${APP_ROOT}/ RUN yarn build # NOTE: run install with `--ignore-optional --production` options again # will remove non-production packages RUN yarn install --ignore-optional --production # ------------------------------------------------------------------------------ # Make the Final image # ------------------------------------------------------------------------------ FROM base # ------------------------------------------------------------------------------ # Arguments / Environment variables # ------------------------------------------------------------------------------ # - Standard args and Envs ARG org_label_schema_vendor ARG org_label_schema_schema_version ARG org_label_schema_name ARG org_label_schema_version ARG org_label_schema_vcs_url ARG org_label_schema_vcs_ref ARG org_label_schema_build_date ARG org_label_schema_description ARG maintainer # - Application specific ARG APP_ROOT ENV APP_ROOT=${APP_ROOT} ARG APP_PORT ENV APP_PORT=${APP_PORT} # ----------------------------------------------------------------------------- # Copy the 'image_files' directory to overrwrite root directory. # Note: It is good to do after the main section # ----------------------------------------------------------------------------- COPY ./image_files/fsroot / # ----------------------------------------------------------------------------- # Provisioning (as root) # For docker-entrypoint, it needed to change the owner to node # ----------------------------------------------------------------------------- RUN chmod g+w -R /docker-entrypoint.d /docker-entrypoint.sh \ && chown -R node:node /docker-entrypoint.d /docker-entrypoint.sh \ && chmod ug+x /docker-entrypoint.sh # ------------------------------------------------------------------------------ # Setup APP_ROOT for Node.js # ------------------------------------------------------------------------------ RUN mkdir -p ${APP_ROOT} && chown node:node ${APP_ROOT} WORKDIR ${APP_ROOT} USER node # ------------------------------------------------------------------------------ # Copy necessary files # ------------------------------------------------------------------------------ COPY --chown=node:node --from=nodejs_build ${APP_ROOT}/dist ${APP_ROOT}/dist COPY --chown=node:node --from=nodejs_build ${APP_ROOT}/node_modules ${APP_ROOT}/node_modules COPY --chown=node:node --from=nodejs_build ${APP_ROOT}/package.json ${APP_ROOT}/yarn.lock ${APP_ROOT}/ # ------------------------------------------------------------------------------ # TODO: Remove TS or any other source code if the image is 'release' # ------------------------------------------------------------------------------ # ----------------------------------------------------------------------------- # Expose ports # ----------------------------------------------------------------------------- EXPOSE ${APP_PORT} # ----------------------------------------------------------------------------- # Healthcheck (Optional for service) # ----------------------------------------------------------------------------- HEALTHCHECK --interval=10s --timeout=3s --start-period=5s --retries=3 \ CMD curl -f http://localhost:${APP_PORT}/healthcheck || exit 1 # ----------------------------------------------------------------------------- # Setting the Label and Args # Shoukd be placed at the end (just before CMD) to avoid # regenerating the cache layer above # ----------------------------------------------------------------------------- LABEL org.label-schema.vendor=$org_label_schema_vendor \ org.label-schema.schema-version=$org_label_schema_schema_version \ org.label-schema.name=$org_label_schema_name \ org.label-schema.version=$org_label_schema_version \ org.label-schema.vcs-url=$org_label_schema_vcs_url \ org.label-schema.vcs-ref=$org_label_schema_vcs_ref \ org.label-schema.build-date=$org_label_schema_build_date \ org.label-schema.description=$org_label_schema_description \ maintainer=$maintainer ENV ENABLE_DUMMY_DAEMON=false ENV APP_ENV="production" # Set the LOG_LEVEL will override application logger level. # Default "" mean unset # See 30-prepare-env.sh for details ENV LOG_LEVEL="" ENV LOG_IN_JSON_FMT=false ARG APP_VERSION ENV APP_VERSION=${APP_VERSION} # ----------------------------------------------------------------------------- # Command or Entrypoint # ----------------------------------------------------------------------------- CMD [ "dumb-init", "sh", "-c", "/docker-entrypoint.sh" ]