Skip to content

Commit

Permalink
Small docker improvements and fixes (#12335)
Browse files Browse the repository at this point in the history
* feat: disable uneecessary npm features

disables npm audit, fund and update-notifier for a few second startup speedup

* fix: make default actually defaults not forced values

* feat: upgrade on container changes

* feat: support changing build verb

* fix: use local volumes instead of bind mounts

* fix: save just the hash without any unexpected whitespace

* feat: use run with mount instead of copying for cross-platfomr builds

* ci: try with minimal cache

* ci: don't fetch all branches

* feat: bsic support for other package managers via PACKAGE_MANAGER env var

* refactor: better structured entrypoint

Co-authored-by: NavyStack <137406386+NavyStack@users.noreply.github.com>

* ci: properly cache the node_modules mount

* fix: syntax error

* refactor: fine tune docker-related files

* ci: docker image taging (time, latest)

* fix: remove the trailing slash for correct directory path

* docker: todo- use environment variables to create files

* docker: fix permissions

* docker: fix permissions

* docker: fix stage

* feat: auto-upgrade on package.json changes

* fix: don't profile-gate postgres

---------

Co-authored-by: NavyStack <137406386+NavyStack@users.noreply.github.com>
Co-authored-by: NavyStack <navystack@askfront.com>
  • Loading branch information
3 people committed May 10, 2024
1 parent febeede commit f4f0eb3
Show file tree
Hide file tree
Showing 19 changed files with 531 additions and 137 deletions.
Empty file added .docker/.gitkeep
Empty file.
Empty file added .docker/build/.gitkeep
Empty file.
Empty file added .docker/config/.gitkeep
Empty file.
Empty file.
Empty file.
Empty file.
Empty file added .docker/public/uploads/.gitkeep
Empty file.
17 changes: 14 additions & 3 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ jobs:
steps:

- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up QEMU
uses: docker/setup-qemu-action@v3
Expand All @@ -37,6 +35,9 @@ jobs:
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Get current date in NST
run: echo "CURRENT_DATE_NST=$(date +'%Y%m%d-%H%M%S' -d '-3 hours -30 minutes')" >> $GITHUB_ENV

- name: Docker meta
id: meta
uses: docker/metadata-action@v5
Expand All @@ -48,12 +49,22 @@ jobs:
type=semver,pattern={{major}}.x
type=raw,value=latest,enable={{is_default_branch}}
type=ref,event=branch,enable=${{ github.event.repository.default_branch != github.ref }}
type=raw,value=${{ env.CURRENT_DATE_NST }}
flavor: |
latest=true
- name: Cache node_modules
id: cache-node-modules
uses: actions/cache@v3
with:
path: var-cache-node-modules
key: var-cache-node-modules-${{ hashFiles('Dockerfile', 'install/package.json') }}

- name: Build and push Docker images
uses: docker/build-push-action@v5
with:
cache-from: type=gha
cache-to: type=gha,mode=max
cache-to: type=gha,mode=min
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64,linux/arm/v7
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,5 @@ package-lock.json
link-plugins.sh
test.sh

.docker/
.docker/**
!**/.gitkeep
87 changes: 55 additions & 32 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,51 +1,74 @@
FROM --platform=$BUILDPLATFORM node:lts as npm
FROM node:lts as build

RUN mkdir -p /usr/src/build && \
chown -R node:node /usr/src/build
WORKDIR /usr/src/build
ENV NODE_ENV=production \
DAEMON=false \
SILENT=false \
USER=nodebb \
UID=1001 \
GID=1001

ARG NODE_ENV
ENV NODE_ENV $NODE_ENV
WORKDIR /usr/src/app/

COPY --chown=node:node install/package.json /usr/src/build/package.json
COPY . /usr/src/app/

USER node
# Install corepack to allow usage of other package managers
RUN corepack enable

RUN npm install --omit=dev

FROM node:lts as rebuild
# Removing unnecessary files for us
RUN find . -mindepth 1 -maxdepth 1 -name '.*' ! -name '.' ! -name '..' -exec bash -c 'echo "Deleting {}"; rm -rf {}' \;

ARG BUILDPLATFORM
ARG TARGETPLATFORM
# Prepage package.json
RUN cp /usr/src/app/install/package.json /usr/src/app/

RUN mkdir -p /usr/src/build && \
chown -R node:node /usr/src/build
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \
apt-get -y --no-install-recommends install \
tini

COPY --from=npm /usr/src/build /usr/src/build
RUN groupadd --gid ${GID} ${USER} \
&& useradd --uid ${UID} --gid ${GID} --home-dir /usr/src/app/ --shell /bin/bash ${USER} \
&& chown -R ${USER}:${USER} /usr/src/app/

RUN if [ $BUILDPLATFORM != $TARGETPLATFORM ]; then \
npm rebuild && \
npm cache clean --force; fi
USER ${USER}

FROM node:lts-slim as run
RUN npm install --omit=dev
# TODO: generate lockfiles for each package manager
## pnpm import \

ARG NODE_ENV
ENV NODE_ENV=$NODE_ENV \
daemon=false \
silent=false
FROM node:lts-slim AS final

RUN mkdir -p /usr/src/app && \
chown -R node:node /usr/src/app
ENV NODE_ENV=production \
DAEMON=false \
SILENT=false \
USER=nodebb \
UID=1001 \
GID=1001

COPY --chown=node:node --from=rebuild /usr/src/build /usr/src/app
WORKDIR /usr/src/app/

COPY --from=build --chown=${USER}:${USER} /usr/src/app/ /usr/src/app/install/docker/setup.json /usr/src/app/
COPY --from=build --chown=${USER}:${USER} /usr/bin/tini /usr/src/app/install/docker/entrypoint.sh /usr/local/bin/

WORKDIR /usr/src/app
RUN corepack enable \
&& groupadd --gid ${GID} ${USER} \
&& useradd --uid ${UID} --gid ${GID} --home-dir /usr/src/app/ --shell /bin/bash ${USER} \
&& mkdir -p /usr/src/app/logs/ /opt/config/ \
&& chown -R ${USER}:${USER} /usr/src/app/ /opt/config/ \
&& chmod +x /usr/local/bin/entrypoint.sh \
&& chmod +x /usr/local/bin/tini

USER node
# TODO: Have docker-compose use environment variables to create files like setup.json and config.json.
# COPY --from=hairyhenderson/gomplate:stable /gomplate /usr/local/bin/gomplate

COPY --chown=node:node . /usr/src/app
USER ${USER}

EXPOSE 4567
VOLUME ["/usr/src/app/node_modules", "/usr/src/app/build", "/usr/src/app/public/uploads", "/opt/config"]
ENTRYPOINT ["./install/docker/entrypoint.sh"]

VOLUME ["/usr/src/app/node_modules", "/usr/src/app/build", "/usr/src/app/public/uploads", "/opt/config/"]

# Utilising tini as our init system within the Docker container for graceful start-up and termination.
# Tini serves as an uncomplicated init system, adept at managing the reaping of zombie processes and forwarding signals.
# This approach is crucial to circumvent issues with unmanaged subprocesses and signal handling in containerised environments.
# By integrating tini, we enhance the reliability and stability of our Docker containers.
# Ensures smooth start-up and shutdown processes, and reliable, safe handling of signal processing.
ENTRYPOINT ["tini", "--", "entrypoint.sh"]
76 changes: 76 additions & 0 deletions dev.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
FROM node:lts AS git

ENV USER=nodebb \
UID=1001 \
GID=1001

WORKDIR /usr/src/app/

RUN groupadd --gid ${GID} ${USER} \
&& useradd --uid ${UID} --gid ${GID} --home-dir /usr/src/app/ --shell /bin/bash ${USER} \
&& chown -R ${USER}:${USER} /usr/src/app/

RUN apt-get update \
&& apt-get -y --no-install-recommends install tini

USER ${USER}

# Change to the git branch you want to test
RUN git clone --recurse-submodules -j8 --depth 1 https://github.com/NodeBB/NodeBB.git .

RUN find . -mindepth 1 -maxdepth 1 -name '.*' ! -name '.' ! -name '..' -exec bash -c 'echo "Deleting {}"; rm -rf {}' \;

FROM node:lts AS node_modules_touch

ENV NODE_ENV=development \
USER=nodebb \
UID=1001 \
GID=1001

WORKDIR /usr/src/app/

RUN corepack enable \
&& groupadd --gid ${GID} ${USER} \
&& useradd --uid ${UID} --gid ${GID} --home-dir /usr/src/app/ --shell /bin/bash ${USER} \
&& chown -R ${USER}:${USER} /usr/src/app/

COPY --from=git --chown=${USER}:${USER} /usr/src/app/install/package.json /usr/src/app/

USER ${USER}

RUN npm install

FROM node:lts-slim AS final

ENV NODE_ENV=development \
DAEMON=false \
SILENT=false \
USER=nodebb \
UID=1001 \
GID=1001

WORKDIR /usr/src/app/

COPY --from=build --chown=${USER}:${USER} /usr/src/app/ /usr/src/app/install/docker/setup.json /usr/src/app/
COPY --from=build --chown=${USER}:${USER} /usr/bin/tini /usr/src/app/install/docker/entrypoint.sh /usr/local/bin/
COPY --from=node_modules_touch --chown=${USER}:${USER} /usr/src/app/ /usr/src/app/
COPY --from=git --chown=${USER}:${USER} /usr/src/app/ /usr/src/app/

RUN corepack enable \
&& groupadd --gid ${GID} ${USER} \
&& useradd --uid ${UID} --gid ${GID} --home-dir /usr/src/app/ --shell /bin/bash ${USER} \
&& mkdir -p /usr/src/app/logs/ /opt/config/ \
&& chown -R ${USER}:${USER} /usr/src/app/ /opt/config/ \
&& chmod +x /usr/local/bin/entrypoint.sh \
&& chmod +x /usr/local/bin/tini

# TODO: Have docker-compose use environment variables to create files like setup.json and config.json.
# COPY --from=hairyhenderson/gomplate:stable /gomplate /usr/local/bin/gomplate

USER ${USER}

EXPOSE 4567

VOLUME ["/usr/src/app/node_modules", "/usr/src/app/build", "/usr/src/app/public/uploads", "/opt/config/"]

ENTRYPOINT ["tini", "--", "entrypoint.sh"]
68 changes: 68 additions & 0 deletions docker-compose-pgsql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
version: '3.8'

services:
nodebb:
build: .
# image: ghcr.io/nodebb/nodebb:latest
restart: unless-stopped
ports:
- '4567:4567' # comment this out if you don't want to expose NodeBB to the host, or change the first number to any port you want
volumes:
- nodebb-build:/usr/src/app/build
- nodebb-uploads:/usr/src/app/public/uploads
- nodebb-config:/opt/config
- ./install/docker/setup.json:/usr/src/app/setup.json

postgres:
image: postgres:16.1-alpine
restart: unless-stopped
environment:
POSTGRES_USER: nodebb
POSTGRES_PASSWORD: nodebb
POSTGRES_DB: nodebb
volumes:
- postgres-data:/var/lib/postgresql/data

redis:
image: redis:7.2.3-alpine
restart: unless-stopped
command: ['redis-server', '--appendonly', 'yes', '--loglevel', 'warning']
# command: ["redis-server", "--save", "60", "1", "--loglevel", "warning"] # uncomment if you want to use snapshotting instead of AOF
volumes:
- redis-data:/data

volumes:
postgres-data:
driver: local
driver_opts:
o: bind
type: none
device: ./.docker/database/postgresql/data

redis-data:
driver: local
driver_opts:
o: bind
type: none
device: ./.docker/database/redis

nodebb-build:
driver: local
driver_opts:
o: bind
type: none
device: ./.docker/build

nodebb-uploads:
driver: local
driver_opts:
o: bind
type: none
device: ./.docker/public/uploads

nodebb-config:
driver: local
driver_opts:
o: bind
type: none
device: ./.docker/config
51 changes: 51 additions & 0 deletions docker-compose-redis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
version: '3.8'

services:
nodebb:
build: .
# image: ghcr.io/nodebb/nodebb:latest
restart: unless-stopped
ports:
- '4567:4567' # comment this out if you don't want to expose NodeBB to the host, or change the first number to any port you want
volumes:
- nodebb-build:/usr/src/app/build
- nodebb-uploads:/usr/src/app/public/uploads
- nodebb-config:/opt/config
- ./install/docker/setup.json:/usr/src/app/setup.json

redis:
image: redis:7.2.3-alpine
restart: unless-stopped
command: ['redis-server', '--appendonly', 'yes', '--loglevel', 'warning']
# command: ["redis-server", "--save", "60", "1", "--loglevel", "warning"] # uncomment if you want to use snapshotting instead of AOF
volumes:
- redis-data:/data

volumes:
redis-data:
driver: local
driver_opts:
o: bind
type: none
device: ./.docker/database/redis

nodebb-build:
driver: local
driver_opts:
o: bind
type: none
device: ./.docker/build

nodebb-uploads:
driver: local
driver_opts:
o: bind
type: none
device: ./.docker/public/uploads

nodebb-config:
driver: local
driver_opts:
o: bind
type: none
device: ./.docker/config

0 comments on commit f4f0eb3

Please sign in to comment.