From 4d0147a174a67c5cc15d1df6002d3b49938994b6 Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Wed, 24 Jan 2024 11:28:48 -0500 Subject: [PATCH 1/3] feat: Add dockerfile and docker-compose --- Dockerfile | 71 +++++++++++++++++++ docker-compose.yml | 30 ++++++++ .../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 | 7 ++ .../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 12 files changed, 147 insertions(+) create mode 100644 Dockerfile create mode 100644 docker-compose.yml 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 new file mode 100644 index 0000000..4a0d38b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,71 @@ +FROM lsiobase/alpine:3.18 as base + +ENV TZ=Etc/GMT + +RUN \ + echo "**** install build packages ****" && \ + apk add --no-cache \ + nodejs \ + npm && \ + echo "**** cleanup ****" && \ + rm -rf \ + /root/.cache \ + /tmp/* + +# set OS timezone specified by docker ENV +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +ARG data_dir=/config +VOLUME $data_dir +ENV CONFIG_DIR=$data_dir + +COPY docker/root/ / + +# Dir ENVs need to be set before building or else build throws errors +ENV PUBLIC_KENER_FOLDER=/config/static \ + MONITOR_YAML_PATH=/config/monitors.yaml \ + SITE_YAML_PATH=/config/site.yaml + +# 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 --chown=abc:abc . /app + +# build requires PUBLIC_KENER_FOLDER dir exists so create temporarily +# -- it is non-existent in final stage to allow proper startup and chown'ing/example population +RUN mkdir -p mkdir -p "${CONFIG_DIR}"/static \ + && npm install \ + && chown -R root:root node_modules \ + && npm run kener: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 scripts /app/scripts +COPY --chown=abc:abc static /app/static +COPY --chown=abc:abc config /app/config +COPY --from=build --chown=abc:abc /app/build /app/build +COPY --from=build --chown=abc:abc /app/prod.js /app/prod.js + +ENV NODE_ENV=production + +# install prod depdendencies and clean cache +RUN npm install --omit=dev \ + && npm cache clean --force \ + && chown -R abc:abc node_modules + +ARG webPort=3000 +ENV PORT=$webPort +EXPOSE $PORT + +# 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-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..bec7792 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,30 @@ +version: '3.7' +services: + kener: + image: rajnandan1/kener:latest # assuming this is final namespace/image + container_name: kener + environment: + - TZ=Etc/GMT + #- GH_TOKEN= + #- API_TOKEN= + #- API_IP + + # If running on a LINUX HOST and not podman rootless these MUST BE SET + # run "id $user" from command line and replace numbers below with output from command + #- PUID=1000 # gid + #- PGID=1000 # uid + + ### Most likely DO NOT need to change anything below this ### + + #- PORT=3000 Port app listens on IN CONTAINER + + ### If any of the below are changed make sure the bound volume is correct as well ### + #- CONFIG_DIR=/config + #- PUBLIC_KENER_FOLDER=/config/static + #- MONITOR_YAML_PATH=/config/monitors.yaml + #- SITE_YAML_PATH=/config/site.yaml + + ports: + - '3000:3000/tcp' + volumes: + - '/host/path/to/config:/config:rw' 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 0000000..e69de29 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 0000000..a6791d9 --- /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 0000000..bdd22a1 --- /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 0000000..aba26a8 --- /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 0000000..e69de29 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 0000000..e69de29 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 0000000..6a00a20 --- /dev/null +++ b/docker/root/etc/s6-overlay/s6-rc.d/svc-app/run @@ -0,0 +1,7 @@ +#!/usr/bin/with-contenv bash + +echo -e "\nApp is starting!" +export NODE_ENV=production +cd /app || exit +exec \ + s6-setuidgid abc /usr/bin/node $NODE_ARGS /app/prod.js 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 0000000..5883cff --- /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 0000000..e69de29 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 0000000..e69de29 From 139da41e28b59ae219d2d34474dbe1d073977a95 Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Wed, 24 Jan 2024 11:48:57 -0500 Subject: [PATCH 2/3] docs: Add docker install and usage instructions --- docs.md | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/docs.md b/docs.md index fb6887c..a094963 100644 --- a/docs.md +++ b/docs.md @@ -4,6 +4,50 @@ Kener has been tested from Node18. +# Install using Docker + +[Dockerhub](https://hub.docker.com/r/rajnandan1/kener) +``` +docker.io/rajnandan1/kener:latest +``` + +[Github Packages](https://github.com/rajnandan1/kener/pkgs/container/kener) +``` +ghcr.io/rajnandan1/kener:latest +``` + +You should mount a host directory to persist your configuration and expose the web port. Environmental variables [found below](#environment-variable) can be passed with `-e` An example `docker run` command: + +```shell +docker run -d -v /path/on/host/config:/config -p 3000:3000 -e "GH_TOKEN=1234" rajnandan1/kener +``` + +Or use **Docker Compose** with the example [docker-compose.yaml](docker-compose.yml) + +### Using PUID and PGID + +If you are + +* running on a **linux host** (ie unraid) and +* **not** using [rootless containers with Podman](https://developers.redhat.com/blog/2020/09/25/rootless-containers-with-podman-the-basics#why_podman_) + +then you must set the [environmental variables **PUID** and **PGID**.](https://docs.linuxserver.io/general/understanding-puid-and-pgid) in the container in order for it to generate files/folders your normal user can interact it. + +Run these commands from your terminal + +* `id -u` -- prints UID for **PUID** +* `id -g` -- prints GID for **PGID** + +Then add to your docker command like so: + +```shell +docker run -d ... -e "PUID=1000" -e "PGID=1000" ... rajnandan1/kener +``` + +or substitute them in [docker-compose.yml](/docker-compose.yml) + +# Install Locally + ## Clone the repository ```bash git clone https://github.com/rajnandan1/kener.git @@ -46,7 +90,7 @@ Kener has two parts. One is a svelte app which you can find in the src folder an ├── prod.js(starts an express server, runs the scripts and serves the svelte site) ├── dev.js (starts the dev server) ``` -## Environment Vairable +## Environment Variable #### PUBLIC_KENER_FOLDER (Required) ```shell export PUBLIC_KENER_FOLDER=/path/to/a/directory From 9ae7405166fcd06527ef884019cb0898510156c9 Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Wed, 24 Jan 2024 11:52:28 -0500 Subject: [PATCH 3/3] feat: Add github actions docker image publish workflow --- .github/workflows/publishImage.yml | 73 ++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 .github/workflows/publishImage.yml diff --git a/.github/workflows/publishImage.yml b/.github/workflows/publishImage.yml new file mode 100644 index 0000000..17f3a47 --- /dev/null +++ b/.github/workflows/publishImage.yml @@ -0,0 +1,73 @@ +name: Publish Docker image to Dockerhub and GHCR + +on: + push: + branches: + - 'main' + # add additional branches that should build to images here + # they will be tagged based on the branch name IE kener:test + #- 'test' + tags: + - '*.*.*' + # don't trigger if just updating docs + paths-ignore: + - 'docs.md' + +jobs: + push_to_registry: + name: Push Docker image to Docker Hub + runs-on: ubuntu-latest + # only run if we've specified image tag to push to + if: ${{ vars.DOCKERHUB_IMAGE_NAME != '' || vars.GHCR_IMAGE_NAME != '' }} + # https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token + permissions: + packages: write + contents: read + steps: + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Log in to Docker Hub + if: ${{ github.event_name != 'pull_request' && vars.DOCKERHUB_IMAGE_NAME != '' }} + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Login to GitHub Container Registry + if: ${{ github.event_name != 'pull_request' && vars.GHCR_IMAGE_NAME != '' }} + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v3 + with: + images: | + ${{ vars.DOCKERHUB_IMAGE_NAME }} + ${{ vars.GHCR_IMAGE_NAME }} + # generate Docker tags based on the following events/attributes + tags: | + type=raw,value=latest,enable=${{ endsWith(github.ref, 'main') }} + type=ref,event=branch,enable=${{ !endsWith(github.ref, 'main') }} + type=semver,pattern={{version}} + flavor: | + latest=false + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Build and push Docker image + uses: docker/build-push-action@v4 + with: + context: . + push: ${{ github.event_name != 'pull_request' && !env.ACT}} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64