Skip to content

Commit

Permalink
Merge pull request #39 from FoxxMD/docker
Browse files Browse the repository at this point in the history
feat: Add dockerfile and docker-compose
  • Loading branch information
rajnandan1 authored Jan 24, 2024
2 parents 6766bec + 9ae7405 commit cbcdebb
Show file tree
Hide file tree
Showing 14 changed files with 265 additions and 1 deletion.
73 changes: 73 additions & 0 deletions .github/workflows/publishImage.yml
Original file line number Diff line number Diff line change
@@ -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
71 changes: 71 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -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
30 changes: 30 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -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'
Empty file.
36 changes: 36 additions & 0 deletions docker/root/etc/s6-overlay/s6-rc.d/init-app-config/run
Original file line number Diff line number Diff line change
@@ -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"
1 change: 1 addition & 0 deletions docker/root/etc/s6-overlay/s6-rc.d/init-app-config/type
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
oneshot
1 change: 1 addition & 0 deletions docker/root/etc/s6-overlay/s6-rc.d/init-app-config/up
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/init-app-config/run
Empty file.
Empty file.
7 changes: 7 additions & 0 deletions docker/root/etc/s6-overlay/s6-rc.d/svc-app/run
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions docker/root/etc/s6-overlay/s6-rc.d/svc-app/type
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
longrun
Empty file.
Empty file.
46 changes: 45 additions & 1 deletion docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit cbcdebb

Please sign in to comment.