From 18e851a205fdd5b6f154aa92f724b8e4cd5d707e Mon Sep 17 00:00:00 2001 From: Raj Nandan Sharma Date: Wed, 13 Nov 2024 21:28:46 +0530 Subject: [PATCH] build: new docker build --- Dockerfile | 103 +++++++++--------- .../dependencies.d/init-config | 0 .../s6-overlay/s6-rc.d/init-app-config/run | 36 ++++++ .../s6-overlay/s6-rc.d/init-app-config/type | 1 + .../etc/s6-overlay/s6-rc.d/init-app-config/up | 1 + .../svc-app/dependencies.d/init-app-config | 0 .../svc-app/dependencies.d/init-services | 0 .../root/etc/s6-overlay/s6-rc.d/svc-app/run | 14 +++ .../root/etc/s6-overlay/s6-rc.d/svc-app/type | 1 + .../s6-rc.d/user/contents.d/init-app-config | 0 .../s6-rc.d/user/contents.d/svc-app | 0 src/lib/server/startup.js | 2 +- 12 files changed, 104 insertions(+), 54 deletions(-) create mode 100644 docker/root/etc/s6-overlay/s6-rc.d/init-app-config/dependencies.d/init-config create mode 100755 docker/root/etc/s6-overlay/s6-rc.d/init-app-config/run create mode 100644 docker/root/etc/s6-overlay/s6-rc.d/init-app-config/type create mode 100644 docker/root/etc/s6-overlay/s6-rc.d/init-app-config/up create mode 100644 docker/root/etc/s6-overlay/s6-rc.d/svc-app/dependencies.d/init-app-config create mode 100644 docker/root/etc/s6-overlay/s6-rc.d/svc-app/dependencies.d/init-services create mode 100755 docker/root/etc/s6-overlay/s6-rc.d/svc-app/run create mode 100644 docker/root/etc/s6-overlay/s6-rc.d/svc-app/type create mode 100644 docker/root/etc/s6-overlay/s6-rc.d/user/contents.d/init-app-config create mode 100644 docker/root/etc/s6-overlay/s6-rc.d/user/contents.d/svc-app diff --git a/Dockerfile b/Dockerfile index 81ae4f74..47a0060e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,72 +1,69 @@ -# Stage 1: Build stage -FROM node:18-alpine AS builder +FROM lsiobase/alpine:3.18 as base -WORKDIR /app +ENV TZ=Etc/GMT -# Copy package files first for better caching -COPY package*.json ./ +RUN \ + echo "**** install build packages ****" && \ + apk add --no-cache \ + nodejs \ + npm && \ + echo "**** cleanup ****" && \ + rm -rf \ + /root/.cache \ + /tmp/* -# Install dependencies -RUN npm install +# set OS timezone specified by docker ENV +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone -# Copy project files -COPY . . -# Build the application -RUN npm run build -# Stage 2: Run stage -FROM lsiobase/alpine:3.18 +COPY docker/root/ / -# Set timezone and user -ENV TZ=Etc/GMT \ - PUID=911 \ - PGID=911 \ - NODE_ENV=production \ - PORT=3000 -# Install Node.js and npm -RUN echo "**** install build packages ****" && \ - apk add --no-cache \ - nodejs \ - npm && \ - echo "**** cleanup ****" && \ - rm -rf \ - /root/.cache \ - /tmp/* -# Configure timezone -RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \ - echo $TZ > /etc/timezone +# build requires devDependencies which are not used by production deploy +# so build in a stage so we can copy results to clean "deploy" stage later +FROM base as build WORKDIR /app -# Copy built files from builder stage -COPY --from=builder /app/build ./build -COPY --from=builder /app/package*.json ./ -COPY --from=builder /app/main.js ./ -COPY --from=builder /app/build.js ./ -COPY --from=builder /app/src ./src -COPY --from=builder /app/static ./static -COPY --from=builder /app/database ./database -COPY --from=builder /app/config ./config -COPY --from=builder /app/node_modules ./node_modules -COPY --from=builder /app/.env ./.env +COPY --chown=abc:abc . /app + +RUN npm install \ + && chown -R root:root node_modules \ + && npm run build + +FROM base as app + +# copy package, required libs (npm,nodejs) results of build, prod entrypoint, and examples to be used to populate config dir +# to clean, new stage +COPY --chown=abc:abc package*.json ./ +COPY --from=base /usr/local/bin /usr/local/bin +COPY --from=base /usr/local/lib /usr/local/lib + +COPY --chown=abc:abc static /app/static +COPY --chown=abc:abc config /app/config +COPY --chown=abc:abc database /app/database +COPY --chown=abc:abc build.js /app/build.js +COPY --chown=abc:abc src/lib/server /app/src/lib/server +COPY --chown=abc:abc src/lib/helpers.js /app/src/lib/helpers.js -# Install production dependencies only +COPY --from=build --chown=abc:abc /app/build /app/build +COPY --from=build --chown=abc:abc /app/main.js /app/main.js - -# Create and configure database directory -RUN mkdir -p /app/database && \ - chown -R $PUID:$PGID /app/database && \ - chmod -R 755 /app/database +ENV NODE_ENV=production -# Declare volume for persistence -VOLUME /app/database +# install prod depdendencies and clean cache +RUN npm install --omit=dev \ + && npm cache clean --force \ + && chown -R abc:abc node_modules -# Expose port +ARG webPort=3000 +ENV PORT=$webPort EXPOSE $PORT -# Set startup command -CMD ["sh", "-c", "node build.js && (node src/lib/server/startup.js & node main.js & wait)"] \ No newline at end of file +# leave entrypoint blank! +# uses LSIO s6-init entrypoint with scripts +# that populate CONFIG_DIR with static dir, monitor/site.yaml when dir is empty +# and chown's all files so they are owned by proper user based on PUID/GUID env diff --git a/docker/root/etc/s6-overlay/s6-rc.d/init-app-config/dependencies.d/init-config b/docker/root/etc/s6-overlay/s6-rc.d/init-app-config/dependencies.d/init-config new file mode 100644 index 00000000..e69de29b diff --git a/docker/root/etc/s6-overlay/s6-rc.d/init-app-config/run b/docker/root/etc/s6-overlay/s6-rc.d/init-app-config/run new file mode 100755 index 00000000..a6791d9e --- /dev/null +++ b/docker/root/etc/s6-overlay/s6-rc.d/init-app-config/run @@ -0,0 +1,36 @@ +#!/usr/bin/with-contenv bash + +# used https://github.com/linuxserver/docker-plex as a template + +POPULATE_EXAMPLES=false + +echo "-------------------------------------" +echo -e "Setting up app config directory based on CONFIG_DIR env: ${CONFIG_DIR}\n" + +# make config folder if it does not exist +if [ ! -d "${CONFIG_DIR}" ]; then + echo "Directory does not exist! Creating..." + POPULATE_EXAMPLES=true + mkdir -p "${CONFIG_DIR}" +else + if [ "$(ls -A ${CONFIG_DIR})" ]; then + echo "Directory is not empty, not populating with defaults." + else + POPULATE_EXAMPLES=true + fi +fi + +# add example configs +if [ "$POPULATE_EXAMPLES" = true ]; then + echo "Directory is empty, adding defaults..." + mkdir -p "${CONFIG_DIR}"/static + cp -r /app/static/. "${CONFIG_DIR}"/static + mv /app/config/monitors.example.yaml "${CONFIG_DIR}"/monitors.yaml + mv /app/config/site.example.yaml "${CONFIG_DIR}"/site.yaml +fi + +# permissions +echo "chown'ing directory to ensure correct permissions." +chown -R abc:abc "${CONFIG_DIR}" +echo "Done!" +echo -e "-------------------------------------\n" diff --git a/docker/root/etc/s6-overlay/s6-rc.d/init-app-config/type b/docker/root/etc/s6-overlay/s6-rc.d/init-app-config/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/docker/root/etc/s6-overlay/s6-rc.d/init-app-config/type @@ -0,0 +1 @@ +oneshot diff --git a/docker/root/etc/s6-overlay/s6-rc.d/init-app-config/up b/docker/root/etc/s6-overlay/s6-rc.d/init-app-config/up new file mode 100644 index 00000000..aba26a87 --- /dev/null +++ b/docker/root/etc/s6-overlay/s6-rc.d/init-app-config/up @@ -0,0 +1 @@ +/etc/s6-overlay/s6-rc.d/init-app-config/run diff --git a/docker/root/etc/s6-overlay/s6-rc.d/svc-app/dependencies.d/init-app-config b/docker/root/etc/s6-overlay/s6-rc.d/svc-app/dependencies.d/init-app-config new file mode 100644 index 00000000..e69de29b diff --git a/docker/root/etc/s6-overlay/s6-rc.d/svc-app/dependencies.d/init-services b/docker/root/etc/s6-overlay/s6-rc.d/svc-app/dependencies.d/init-services new file mode 100644 index 00000000..e69de29b diff --git a/docker/root/etc/s6-overlay/s6-rc.d/svc-app/run b/docker/root/etc/s6-overlay/s6-rc.d/svc-app/run new file mode 100755 index 00000000..ff7586f9 --- /dev/null +++ b/docker/root/etc/s6-overlay/s6-rc.d/svc-app/run @@ -0,0 +1,14 @@ +#!/usr/bin/with-contenv bash + +echo -e "\nApp is starting!" +export NODE_ENV=production +cd /app || exit + +# Run build first +s6-setuidgid abc /usr/bin/node $NODE_ARGS /app/build.js && ( + # Run startup and main in parallel + s6-setuidgid abc /usr/bin/node $NODE_ARGS /app/src/lib/server/startup.js & + s6-setuidgid abc /usr/bin/node $NODE_ARGS /app/main.js & + # Wait for both processes + wait +) \ No newline at end of file diff --git a/docker/root/etc/s6-overlay/s6-rc.d/svc-app/type b/docker/root/etc/s6-overlay/s6-rc.d/svc-app/type new file mode 100644 index 00000000..5883cff0 --- /dev/null +++ b/docker/root/etc/s6-overlay/s6-rc.d/svc-app/type @@ -0,0 +1 @@ +longrun diff --git a/docker/root/etc/s6-overlay/s6-rc.d/user/contents.d/init-app-config b/docker/root/etc/s6-overlay/s6-rc.d/user/contents.d/init-app-config new file mode 100644 index 00000000..e69de29b diff --git a/docker/root/etc/s6-overlay/s6-rc.d/user/contents.d/svc-app b/docker/root/etc/s6-overlay/s6-rc.d/user/contents.d/svc-app new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/server/startup.js b/src/lib/server/startup.js index e4fd2766..af483830 100644 --- a/src/lib/server/startup.js +++ b/src/lib/server/startup.js @@ -23,7 +23,7 @@ let monitors = []; let site = {}; const envSecrets = []; const DATABASE_PATH = "./database"; - +console.log(process.env); const Startup = async () => { const FOLDER_MONITOR_JSON = DATABASE_PATH + "/monitors.json"; const monitors = fs.readJSONSync(FOLDER_MONITOR_JSON);