Better dev docker containers, Simpler production docker file, caddy for ssl (#136)

* Better dev docker containers, Simpler production docker file, caddy for ssl

* Fix repeater docker image

* Add depends on

* Use recommended caddy volumes & change to using databag image

* move to using examples folder for installation

* lint

* Tested example linux on bare metal

* Add DATABAG_PORT env and fix caddy

* Add dev_database for local sqlite testing

* incorrect use -z

* Add platform goarch goos optional envs

* Add more caching for faster rebuilds
This commit is contained in:
Lucian I. Last 2025-02-05 21:04:29 +01:00 committed by GitHub
parent 69755d1fea
commit 2b3052ac3f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
39 changed files with 402 additions and 241 deletions

1
.dockerignore Normal file
View File

@ -0,0 +1 @@
dev_database

22
.editorconfig Normal file
View File

@ -0,0 +1,22 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.{go,sh}]
indent_style = tab
[{Makefile,Caddyfile}]
indent_style = tab
[LICENSE]
trim_trailing_whitespace = false
insert_final_newline = false

1
.gitignore vendored
View File

@ -14,3 +14,4 @@
# Dependency directories (remove the comment below to include it)
# vendor/
dev_database/

45
Dockerfile Normal file
View File

@ -0,0 +1,45 @@
FROM node:22-alpine AS node
WORKDIR /app
# Download the node dependencies first before adding the rest for caching
COPY ./net/web/package.json ./net/web/yarn.lock ./
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn \
yarn --frozen-lockfile
COPY ./net/web/ ./
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn \
yarn run build
FROM golang:alpine AS go
EXPOSE 7000
WORKDIR /app/databag
RUN apk add --no-cache build-base imagemagick sqlite ffmpeg curl
RUN mkdir -p /opt/databag
RUN mkdir -p /var/lib/databag
RUN mkdir -p /app/databag/net
COPY ./net/server /app/databag/net/server
COPY ./net/transform /opt/databag/transform
WORKDIR /app/databag/net/server
RUN --mount=type=cache,target=/go/pkg/mod \
if [ -n "${DATABAG_GOARCH}" ]; then GOARCH=${DATABAG_GOARCH}; fi; \
if [ -n "${DATABAG_GOOS}" ]; then GOOS=${DATABAG_GOOS}; fi; \
go mod download
ARG DATABAG_GOARCH
ARG DATABAG_GOOS
RUN --mount=type=cache,target=/go/pkg/mod \
if [ -n "${DATABAG_GOARCH}" ]; then GOARCH=${DATABAG_GOARCH}; fi; \
if [ -n "${DATABAG_GOOS}" ]; then GOOS=${DATABAG_GOOS}; fi; \
CGO_ENABLED=1 go build -o databag .
COPY --from=node /app/build /app/databag/net/web/build
ENV DEV=0
ENV ADMIN=password
ENTRYPOINT /app/databag/net/server/entrypoint.sh

20
Makefile Normal file
View File

@ -0,0 +1,20 @@
default:
@grep '^[^#[:space:].].*:' Makefile
dev-start:
docker compose -f docker-compose.dev.yml up -d
dev-stop:
docker compose -f docker-compose.dev.yml down
dev-restart-server:
docker compose -f docker-compose.dev.yml restart net-server
dev-restart-web:
docker compose -f docker-compose.dev.yml restart net-web
dev-restart-repeater:
docker compose -f docker-compose.dev.yml restart net-repeater
prod-docker-start:
docker compose up -d
prod-raw-build:
./build.sh

46
docker-compose.dev.yml Normal file
View File

@ -0,0 +1,46 @@
name: databag-dev
services:
net-web:
build:
context: ./net/web
dockerfile: Dockerfile.dev
working_dir: /app
volumes:
- ./net/web:/app
- cache_yarn:/root/.yarn
environment:
- YARN_CACHE_FOLDER=/root/.yarn
command: sh -c "yarn && chokidar '**/*.js' '**/*.ts' -c 'yarn run build' --debounce 18000 --initial --ignore node_modules --ignore build"
net-server:
build:
context: ./net/server
dockerfile: Dockerfile.dev
ports:
- 127.0.0.1:7000:7000
volumes:
- ./net/server:/app/databag/net/server
- ./dev_database:/var/lib/databag
- ./net/transform:/opt/databag/transform
- ./net/web/build:/app/databag/net/web/build
- cache_go:/go/pkg/mod
working_dir: /app
environment:
- ADMIN=password
- DEV=1
command: /app/databag/net/server/entrypoint.sh
net-repeater:
build:
context: ./net/repeater
dockerfile: Dockerfile.dev
working_dir: /app
volumes:
- ./net/repeater:/app
- cache_go:/go/pkg/mod
ports:
- 127.0.0.1:7878:7878
command: go run main.go
volumes:
cache_go:
cache_yarn:

22
docker-compose.yml Normal file
View File

@ -0,0 +1,22 @@
name: databag
services:
app:
build: .
# # For building cross environment containers
# build:
# context: .
# args:
# DATABAG_GOARCH: arm64
# DATABAG_GOOS: linux
# platform: "linux/arm64"
ports:
- 127.0.0.1:7000:7000
volumes:
- database:/var/lib/databag
environment:
- ADMIN=password
volumes:
database:

View File

@ -0,0 +1,14 @@
name: databag-example-http
services:
app:
image: balzack/databag:latest
restart: unless-stopped
ports:
- 127.0.0.1:7000:7000
volumes:
- database:/var/lib/databag
environment:
- ADMIN=password
volumes:
database:

View File

@ -0,0 +1,3 @@
example.com {
reverse_proxy http://app:443
}

View File

@ -0,0 +1,29 @@
name: databag-example-ssl
services:
caddy:
image: caddy
restart: unless-stopped
ports:
- 80:80
- 443:443
volumes:
# Edit the Caddyfile and replace "example.com" with your own domain
- ./Caddyfile:/etc/caddy/Caddyfile:ro
# Recommended by Caddy
- caddy_data:/data
- caddy_config:/config
depends_on:
- app
app:
image: balzack/databag:latest
restart: unless-stopped
volumes:
- database:/var/lib/databag
environment:
- ADMIN=password
- DATABAG_PORT=443
volumes:
database:
caddy_data:
caddy_config:

View File

@ -0,0 +1,17 @@
[Unit]
Description=databag server
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=1
User=databag
ExecStart=/app/databag/net/server/entrypoint.sh
# [Service]
# Environment="ADMIN=password"
[Install]
WantedBy=multi-user.target

85
examples/linux/install.sh Executable file
View File

@ -0,0 +1,85 @@
#!/bin/bash
set -e
function confirm() {
read -p "Are you sure you want to continue? [Y/n] " reply
if [ "$reply" != "Y" ] && [ "$reply" != "y" ]; then
echo "Aborting"
exit 1
fi
}
if ! id "databag" >/dev/null 2>&1; then
echo "User databag not found, creating..."
confirm
sudo useradd databag
fi
if [[ ! -d "/app/databag" ]]; then
echo "Creating app directory for databag, this requires sudo permissions"
sudo rm -rf /app/databag || true
sudo mkdir -p /app/databag
echo "Downloading databag repository into /app/databag"
git clone --depth 1 https://github.com/balzack/databag.git /app/databag
sudo chown -R databag:databag /app/databag
fi
cd /app/databag
# You might be running this script from the root of this repository
if [[ "/app/databag" != $(pwd) ]]; then
cd ../..
fi
if [[ "/app/databag" != $(pwd) ]]; then
echo "Install databag must be done from /app/databag"
echo "Please re-clone the github repository into /app/databag, like so:"
echo "mkdir -p /app; https://github.com/balzack/databag /app/databag"
exit 1
fi
if [[ -z $(which yarn) ]]; then
echo "Yarn is not installed, installing..."
npm install --global yarn
fi
echo "Building frontend files..."
cd net/web
yarn --frozen-lockfile
echo "Removing old frontend files, requires sudo permissions..."
sudo rm -rf build
yarn run build
sudo chown -R databag:databag build
cd ../..
echo "Building backend files..."
cd net/server
CGO_ENABLED=1 go build -o databag .
cd ../..
echo "Creating databag locations..."
sudo mkdir -p /opt/databag
sudo mkdir -p /var/lib/databag
sudo chown -R databag:databag /var/lib/databag
echo "Copying transform scripts..."
sudo mkdir -p /opt/databag/transform
sudo cp net/transform/*.sh /opt/databag/transform/
sudo chmod +x /opt/databag/transform/*.sh
if [[ ! -f /etc/systemd/system/databag.service ]]; then
function createService() {
echo "Creating databag service, requires sudo permissions..."
sudo cp examples/linux/databag.service /etc/systemd/system/databag.service
sudo chmod 664 /etc/systemd/system/databag.service
sudo systemctl daemon-reload
}
function startService() {
echo "Starting databag service..."
sudo systemctl start databag.service
}
createService $? "Failed to install databag service"
startService $? "Failed to start databag service"
fi
echo ""
echo "Done"

29
examples/linux/uninstall.sh Executable file
View File

@ -0,0 +1,29 @@
#!/bin/bash
function confirm() {
read -p "Are you sure you want to continue? [Y/n] " reply
if [ "$reply" != "Y" ] && [ "$reply" != "y" ]; then
echo "Aborting"
exit 1
fi
}
echo "Stopping, disabling and removing databag service..."
confirm
sudo systemctl stop databag.service
sudo systemctl disable databag.service
sudo rm /etc/systemd/system/databag.service
sudo systemctl reload
echo "Removing databag data..."
confirm
sudo rm -rf /app/databag /opt/databag /var/lib/databag
if [ -z "$(ls -A /app)" ]; then
sudo rmdir /app
fi
echo "Removing databag user..."
confirm
sudo userdel databag
echo "Done"

View File

@ -1,67 +0,0 @@
FROM ubuntu:20.04 as build
ARG TARGETPLATFORM
LABEL maintainer="roland.osborne@gmail.com"
EXPOSE 7000
ENV TZ=America/Los_Angeles
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt-get update
RUN apt-get -y install curl net-tools jq netcat unzip wget git vim fail2ban imagemagick-6.q16 ffmpeg build-essential sqlite3 npm
RUN apt-get -y upgrade
RUN npm install --global yarn
RUN npm install -g n
RUN n stable
RUN mkdir /app
RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then ARCHITECTURE=amd64; elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then ARCHITECTURE=arm64; elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then ARCHITECTURE=aarch64; else ARCHITECTURE=unsupported; fi \
&& wget -P /app https://go.dev/dl/go1.23.1.linux-${ARCHITECTURE}.tar.gz \
&& tar -C /usr/local -xzf /app/go1.23.1.linux-${ARCHITECTURE}.tar.gz
RUN git clone https://github.com/balzack/databag.git /app/databag
RUN yarn config set network-timeout 300000
RUN yarn --cwd /app/databag/net/web install
RUN yarn --cwd /app/databag/net/web build
RUN cd /app/databag/net/server; /usr/local/go/bin/go build databag
RUN mkdir /opt/databag
ADD transform /opt/databag/transform
RUN mkdir -p /var/lib/databag
RUN echo 'export PATH=$PATH:/usr/local/go/bin' >> /root/.bashrc
RUN echo "set expandtab\nset tabstop=2\nset softtabstop=2\nset shiftwidth=2\nset encoding=utf-8\nset fileencoding=utf-8\n" > /root/.vimrc
RUN echo "bind 'set mark-symlinked-directories on'" >> /root/.bashrc
ADD entrypoint.sh /app
ADD dev_setup.sh /app
RUN rm -rf /usr/local/go
RUN rm -rf /root/go
RUN rm -rf /app/go*
RUN rm -rf /root/.cache/go*
RUN yarn cache clean
RUN rm -rf /app/databag/app
RUN rm -rf /app/databag/net/web/node_modules
RUN n prune
RUN npm uninstall -g n
RUN rm -rf /usr/local/n
RUN rm -rf /usr/local/bin/node
RUN apt-get -y remove git build-essential npm vim nodejs linux-libc-dev
RUN rm -rf /var/lib/apt/lists
FROM scratch
COPY --from=build / /
ENTRYPOINT ["/app/entrypoint.sh"]

View File

@ -1,50 +0,0 @@
FROM ubuntu:20.04 as build
ARG TARGETPLATFORM
LABEL maintainer="roland.osborne@gmail.com"
EXPOSE 7000
ENV TZ=America/Los_Angeles
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt-get update
RUN apt-get -y install curl net-tools jq netcat unzip wget git vim fail2ban imagemagick-6.q16 ffmpeg build-essential sqlite3 npm
RUN apt-get -y upgrade
RUN npm install --global yarn
RUN npm install -g n
RUN n stable
RUN mkdir /app
RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then ARCHITECTURE=amd64; elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then ARCHITECTURE=arm64; elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then ARCHITECTURE=aarch64; else ARCHITECTURE=unsupported; fi \
&& wget -P /app https://go.dev/dl/go1.22.2.linux-${ARCHITECTURE}.tar.gz \
&& tar -C /usr/local -xzf /app/go1.22.2.linux-${ARCHITECTURE}.tar.gz
RUN git clone https://github.com/balzack/databag.git /app/databag
RUN yarn config set network-timeout 300000
RUN yarn --cwd /app/databag/net/web install
RUN yarn --cwd /app/databag/net/web build
RUN cd /app/databag/net/server; /usr/local/go/bin/go build databag
RUN mkdir /opt/databag
ADD transform /opt/databag/transform
RUN mkdir -p /var/lib/databag
RUN echo 'export PATH=$PATH:/usr/local/go/bin' >> /root/.bashrc
RUN echo "set expandtab\nset tabstop=2\nset softtabstop=2\nset shiftwidth=2\nset encoding=utf-8\nset fileencoding=utf-8\n" > /root/.vimrc
RUN echo "bind 'set mark-symlinked-directories on'" >> /root/.bashrc
ADD dev_setup.sh /app
ADD entrypoint.sh /app
FROM scratch
COPY --from=build / /
ENTRYPOINT ["/app/entrypoint.sh"]

View File

@ -1,20 +0,0 @@
cd /root
wget -P /app https://go.dev/dl/go1.22.2.linux-amd64.tar.gz
tar -C /usr/local -xzf /app/go1.22.2.linux-amd64.tar.gz
apt-get update
apt-get -y install git build-essential npm vim
curl -fsSL https://deb.nodesource.com/setup_18.x | bash -
apt install -y nodejs
npm install --global yarn
npm install -g n
n stable
cd /app/databag
git checkout .
yarn --cwd /app/databag/net/web install
yarn --cwd /app/databag/net/web build
cd /app/databag/net/server; /usr/local/go/bin/go build databag

View File

@ -1,36 +0,0 @@
---
version: "2.1"
services:
databag:
image: balzack/databag:latest
container_name: databag
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/London
ports:
- "7000:7000"
volumes:
- $HOME/appdata/databag:/var/lib/databag
restart: unless-stopped
swag:
image: lscr.io/linuxserver/swag
container_name: databag-ssl-proxy
cap_add:
- NET_ADMIN
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/London
- URL=YOURDOMAIN.COM
- SUBDOMAINS=databag,
- VALIDATION=http
- ONLY_SUBDOMAINS=true
- STAGING=false #optional
volumes:
- $HOME/appdata/swag:/config
- $PWD/net/container/ssl-proxy.conf:/config/nginx/proxy-confs/databag.subdomain.conf
ports:
- 443:443
- 80:80
restart: unless-stopped

View File

@ -1,12 +0,0 @@
version: "3.9"
services:
databag:
environment:
- DEV=1
container_name: databag
image: balzack/databag:latest
ports:
- "7000:7000"
volumes:
- ./databag-data:/var/lib/databag

View File

@ -1,10 +0,0 @@
version: "3.9"
services:
databag:
container_name: databag
image: balzack/databag:latest
ports:
- "7000:7000"
volumes:
- ./databag-data:/var/lib/databag

View File

@ -1,23 +0,0 @@
#!/bin/bash
set -e
sqlite3 /var/lib/databag/databag.db "VACUUM;"
sqlite3 /var/lib/databag/databag.db "CREATE TABLE IF NOT EXISTS 'configs' ('id' integer NOT NULL UNIQUE,'config_id' text NOT NULL,'str_value' text,'num_value' integer,'bool_value' numeric,'bin_value' blob,PRIMARY KEY ('id'));"
sqlite3 /var/lib/databag/databag.db "CREATE UNIQUE INDEX IF NOT EXISTS 'idx_configs_config_id' ON 'configs'('config_id');"
if [[ -v ADMIN ]]; then
sqlite3 /var/lib/databag/databag.db "delete from configs where config_id='configured';"
sqlite3 /var/lib/databag/databag.db "delete from configs where config_id='token';"
sqlite3 /var/lib/databag/databag.db "insert into configs (config_id, str_value) values ('token', '$ADMIN');"
sqlite3 /var/lib/databag/databag.db "insert into configs (config_id, bool_value) values ('configured', true);"
fi
if [ "$DEV" == "1" ]; then
/app/dev_setup.sh || true
while true; do
sleep 1;
done
else
cd /app/databag/net/server
./databag -p 7000 -w /app/databag/net/web/build -s /var/lib/databag -t /opt/databag/transform
fi

View File

@ -1,23 +0,0 @@
# make sure that your dns has a cname set for databag
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name databag.*;
include /config/nginx/ssl.conf;
client_max_body_size 0;
location / {
include /config/nginx/proxy.conf;
resolver 127.0.0.11 valid=30s;
set $upstream_app databag;
set $upstream_port 7000;
set $upstream_proto http;
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
}
}

9
net/repeater/Dockerfile Normal file
View File

@ -0,0 +1,9 @@
FROM golang:alpine
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o repeater .
EXPOSE 7878
ENTRYPOINT ./repeater

View File

@ -0,0 +1,6 @@
FROM golang:alpine
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
RUN rm go.mod go.sum

1
net/server/.dockerignore Normal file
View File

@ -0,0 +1 @@
databag

1
net/server/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/databag

16
net/server/Dockerfile.dev Normal file
View File

@ -0,0 +1,16 @@
FROM golang:alpine
RUN apk add --no-cache build-base imagemagick sqlite ffmpeg curl
RUN mkdir -p /opt/databag
RUN mkdir -p /var/lib/databag
RUN mkdir -p /app/databag/net
RUN mkdir -p /tmp/databag-go-cache
WORKDIR /tmp/databag-go-cache
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod \
go mod download
WORKDIR /
RUN rm -rf /tmp/databag-go-cache

24
net/server/entrypoint.sh Executable file
View File

@ -0,0 +1,24 @@
#!/bin/sh
set -e
sqlite3 /var/lib/databag/databag.db "VACUUM;"
sqlite3 /var/lib/databag/databag.db "CREATE TABLE IF NOT EXISTS 'configs' ('id' integer NOT NULL UNIQUE,'config_id' text NOT NULL,'str_value' text,'num_value' integer,'bool_value' numeric,'bin_value' blob,PRIMARY KEY ('id'));"
sqlite3 /var/lib/databag/databag.db "CREATE UNIQUE INDEX IF NOT EXISTS 'idx_configs_config_id' ON 'configs'('config_id');"
if [[ -n "$ADMIN" ]]; then
sqlite3 /var/lib/databag/databag.db "delete from configs where config_id='configured';"
sqlite3 /var/lib/databag/databag.db "delete from configs where config_id='token';"
sqlite3 /var/lib/databag/databag.db "insert into configs (config_id, str_value) values ('token', '$ADMIN');"
sqlite3 /var/lib/databag/databag.db "insert into configs (config_id, bool_value) values ('configured', true);"
fi
if [[ -z "$DATABAG_PORT" ]]; then
DATABAG_PORT=7000
fi
cd /app/databag/net/server
if [[ "$DEV" == "1" ]]; then
CGO_ENABLED=1 go run main.go -p $DATABAG_PORT -w /app/databag/net/web/build -s /var/lib/databag -t /opt/databag/transform
else
./databag -p $DATABAG_PORT -w /app/databag/net/web/build -s /var/lib/databag -t /opt/databag/transform
fi

1
net/web/.dockerignore Normal file
View File

@ -0,0 +1 @@
node_modules

2
net/web/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules
build

8
net/web/Dockerfile.dev Normal file
View File

@ -0,0 +1,8 @@
FROM node:22-alpine
WORKDIR /app
RUN --mount=type=cache,target=/root/.npm \
npm install --global chokidar-cli
ENV SHELL=/bin/sh