Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
valentindeaconu committed Apr 11, 2024
1 parent 38acb6b commit 479ff8b
Show file tree
Hide file tree
Showing 6 changed files with 319 additions and 0 deletions.
32 changes: 32 additions & 0 deletions .github/renovate.json5
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
extends: [
"config:base",
"schedule:daily",
],
commitMessageSuffix: " in {{packageFile}}",
dependencyDashboardAutoclose: true,
automerge: true,
baseBranches: ["main"],
platformAutomerge: true,
labels: ["dependencies"],
prHourlyLimit: 1,
lockFileMaintenance: {
enabled: true,
},
vulnerabilityAlerts: {
enabled: true,
labels: [
"security",
],
},
regexManagers: [
{
fileMatch: ["(^|/)Dockerfile$", "(^|/)Dockerfile\\.[^/]*$"],
matchStrings: [
"renovate: datasource=(?<datasource>.*?) depName=(?<depName>.*?)( versioning=(?<versioning>.*?))?\\sENV .*?_VERSION=(?<currentValue>.*)\\s",
],
versioningTemplate: "{{#if versioning}}{{{versioning}}}{{else}}semver{{/if}}",
extractVersionTemplate: '^v(?<version>\\d+\\.\\d+\\.\\d+)',
},
]
}
72 changes: 72 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: "Build Image"

on:
push:
branches:
- "master"
tags:
- "v*"
workflow_dispatch:
inputs:
version:
description: The version to release
type: string
required: true

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

permissions:
contents: read
packages: write

jobs:
build:
name: "Build"
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3

- name: Set release version
run: |
if [ "${{ startsWith(github.ref, 'refs/tags/') }}" = "true" ]; then
echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
elif [ "${{ github.event_name == 'workflow_dispatch' }}" = "true" ]; then
echo "RELEASE_VERSION=${{ inputs.version }}" >> $GITHUB_ENV
else
echo "Could not identify the release version."
exit 1
fi
- name: Set the commit hash
run: echo "COMMIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV

- name: Set the build timestamp
run: echo "BUILD_TIMESTAMP=$(date +"%Y%m%d%H%M%S")" >> $GITHUB_ENV

- name: Login to Packages Container registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
file: "./Dockerfile"
builder: ${{ steps.buildx.outputs.name }}
platforms: linux/arm64/v8,linux/amd64
push: true
tags: |
ghcr.io/${{ github.repository }}:latest
ghcr.io/${{ github.repository }}:${{ env.RELEASE_VERSION }}
ghcr.io/${{ github.repository }}:${{ env.RELEASE_VERSION }}-${{ env.COMMIT_HASH }}
ghcr.io/${{ github.repository }}:${{ env.RELEASE_VERSION }}-${{ env.COMMIT_HASH }}-${{ env.BUILD_TIMESTAMP }}
40 changes: 40 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# syntax=docker/dockerfile:1

FROM alpine:3.18

# Install the dependencies
RUN apk add --no-cache \
ca-certificates \
unzip \
wget \
zip \
zlib-dev \
bash

ARG TARGETOS
ARG TARGETARCH

# Download and install Litestream
# renovate: datasource=github-releases depName=benbjohnson/litestream
ARG LITESTREAM_VERSION=0.3.13
ADD https://github.com/benbjohnson/litestream/releases/download/v${LITESTREAM_VERSION}/litestream-v${LITESTREAM_VERSION}-${TARGETOS}-${TARGETARCH}.tar.gz /tmp/litestream.tar.gz
RUN tar -C /usr/local/bin -xzf /tmp/litestream.tar.gz \
&& chmod +x /usr/local/bin/litestream \
&& rm -f /tmp/litestream.tar.gz

# Download and install PocketBase
# renovate: datasource=github-releases depName=pocketbase/pocketbase
ARG POCKETBASE_VERSION=0.22.8
ADD https://github.com/pocketbase/pocketbase/releases/download/v${POCKETBASE_VERSION}/pocketbase_${POCKETBASE_VERSION}_${TARGETOS}_${TARGETARCH}.zip /tmp/pocketbase.zip
RUN unzip /tmp/pocketbase.zip -d /usr/local/bin/ \
&& chmod +x /usr/local/bin/pocketbase \
&& rm -f /tmp/pocketbase.zip

# Copy Litestream configuration file
COPY etc/litestream.yml /etc/litestream.yml

# Copy custom entrypoint script
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh

CMD [ "entrypoint.sh" ]
84 changes: 84 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# pocketbase-litestream-docker

This project builds a Docker image that wraps the [PocketBase](https://pocketbase.io/) server with [litestream](https://litestream.io/) to continuously back up the SQLite databases to a remote S3 storage.

The entry point is overwritten so that if the database does not exist at startup, it will be downloaded from the remote storage before starting the actual database.

Litestream also exposes a port that can be scraped for metrics. If you wish to enable that, expose the port `9090`.

## Inputs

| Variable | Description | Default |
| --- | --- | --- |
| PORT | The port PocketBase should listen to. | `8090` |
| LITESTREAM_PORT | The port litestream should listen to. | `9090` |
| LITESTREAM_ACCESS_KEY | Access Key for the S3-compatible storage. | `n/a` |
| LITESTREAM_SECRET_ACCESS_KEY | Secret Access Key for the S3-compatible storage. | `n/a` |
| ENABLE_LITESTREAM_DATA_RESTORATION | Whether to restore the data database at startup or not. | `true` |
| ENABLE_LITESTREAM_LOGS_RESTORATION | Whether to restore the logs database at startup or not. | `true` |
| ENABLE_LITESTREAM_REPLICATION | Whether to enable continuous replication via litestream or not. | `true` |
| DATA_REPLICA_URI | An S3 URI where the data database should be replicated. | `n/a` |
| LOGS_REPLICA_URI | An S3 URI where the logs database should be replicated. | `n/a` |
| PB_ENCRYPTION_KEY | The secret used to encrypt PocketBase settings. | `n/a` |
| PB_DATA_PATH | The path to the data directory. | `/data` |
| PB_STATIC_PATH | The path to the static directory. | `/static` |
| PB_MIGRATIONS_PATH | The path to the migrations directory. | `/migrations` |
| PB_HOOKS_PATH | The path to the custom hooks directory. | `/app/hooks` |
| PB_ENABLE_AUTO_MIGRATION | Whether to enable auto-migrations or not. | `false` |
| PB_ENABLE_INDIVIDUAL_MIGRATIONS | Whether to enable individual migrations or not. | `true` |
| PB_DEV | Enables dev mode for PocketBase. | `false` |
| DATA_REPLICA_RETENTION | The amount of time that snapshot & WAL files will be kept. | `24h` |
| DATA_REPLICA_RETENTION_CHECK_INTERVAL | Specifies how often Litestream will check if retention needs to be enforced. | `1h` |
| DATA_REPLICA_SNAPSHOT_INTERVAL | Specifies how often new snapshots will be created. Should be less or equal with the retention interval. | `24h` |
| DATA_REPLICA_VALIDATION_INTERVAL | Specifies how often Litestream will automatically restore and validate that the data on the replica matches the local copy. | `12h` |
| DATA_REPLICA_SYNC_INTERVAL | Frequency in which frames are pushed to the replica. | `1s` |
| LOGS_REPLICA_RETENTION | The amount of time that snapshot & WAL files will be kept. | `48h` |
| LOGS_REPLICA_RETENTION_CHECK_INTERVAL | Specifies how often Litestream will check if retention needs to be enforced. | `12h` |
| LOGS_REPLICA_SNAPSHOT_INTERVAL | Specifies how often new snapshots will be created. Should be less or equal with the retention interval. | `48h` |
| LOGS_REPLICA_SYNC_INTERVAL | Frequency in which frames are pushed to the replica. | `10m` |

### AWS default credentials provider chain

If you wish to configure Litestream to use the default credentials providers chain, omit to set `LITESTREAM_ACCESS_KEY` and `LITESTREAM_SECRET_ACCESS_KEY` and configure the AWS credentials instead.

## Deploy and test locally

### Build

```
docker build -t pocketbase-litestream-docker:dev .
```

### Run

```
docker run \
-p 8090:8090 \
-v ${PWD}/.volumes/data:/data \
-v ${PWD}/.volumes/migrations:/migrations \
-v ${PWD}/.volumes/static:/static \
-v ${PWD}/.volumes/hooks:/app/hooks \
-e PORT=8090 \
-e DATA_REPLICA_URI=s3://YOURBUCKETNAME/data \
-e LOGS_REPLICA_URI=s3://YOURBUCKETNAME/logs \
-e LITESTREAM_ACCESS_KEY_ID \
-e LITESTREAM_SECRET_ACCESS_KEY \
pocketbase-litestream-docker:dev
```

### Run without replication for local development

```
docker run \
-p 8090:8090 \
-v ${PWD}/.volumes/data:/data \
-v ${PWD}/.volumes/migrations:/migrations \
-v ${PWD}/.volumes/static:/static \
-v ${PWD}/.volumes/hooks:/app/hooks \
-e PORT=8090 \
-e ENABLE_LITESTREAM_REPLICATION=false \
-e ENABLE_LITESTREAM_DATA_RESTORATION=false \
-e ENABLE_LITESTREAM_LOGS_RESTORATION=false \
-e PB_DEV=true \
pocketbase-litestream-docker:dev
```
74 changes: 74 additions & 0 deletions entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/bin/bash

set -e

# Configure defaults
export LITESTREAM_PORT="${LITESTREAM_PORT:-"9090"}"
export ENABLE_LITESTREAM_DATA_RESTORATION="${ENABLE_LITESTREAM_DATA_RESTORATION:-"true"}"
export ENABLE_LITESTREAM_LOGS_RESTORATION="${ENABLE_LITESTREAM_LOGS_RESTORATION:-"true"}"
export ENABLE_LITESTREAM_REPLICATION="${ENABLE_LITESTREAM_REPLICATION:-"true"}"

export PB_DEV="${PB_DEV:-"false"}"
export PB_DATA_PATH="${PB_DATA_PATH:-"/data"}"
export PB_STATIC_PATH="${PB_STATIC_PATH:-"/static"}"
export PB_MIGRATIONS_PATH="${PB_MIGRATIONS_PATH:-"/migrations"}"
export PB_HOOKS_PATH="${PB_HOOKS_PATH:-"/app/hooks"}"

export PB_ENABLE_AUTO_MIGRATIONS="${PB_ENABLE_AUTO_MIGRATIONS:-"false"}"
export PB_ENABLE_INDIVIDUAL_MIGRATIONS="${PB_ENABLE_INDIVIDUAL_MIGRATIONS:-"true"}"

export DATA_REPLICA_RETENTION="${DATA_REPLICA_RETENTION:-"24h"}"
export DATA_REPLICA_RETENTION_CHECK_INTERVAL="${DATA_REPLICA_RETENTION_CHECK_INTERVAL:-"1h"}"
export DATA_REPLICA_SNAPSHOT_INTERVAL="${DATA_REPLICA_SNAPSHOT_INTERVAL:-"24h"}"
export DATA_REPLICA_VALIDATION_INTERVAL="${DATA_REPLICA_VALIDATION_INTERVAL:-"12h"}"
export DATA_REPLICA_SYNC_INTERVAL="${DATA_REPLICA_SYNC_INTERVAL:-"1s"}"

export LOGS_REPLICA_RETENTION="${LOGS_REPLICA_RETENTION:-"48h"}"
export LOGS_REPLICA_RETENTION_CHECK_INTERVAL="${LOGS_REPLICA_RETENTION_CHECK_INTERVAL:-"12h"}"
export LOGS_REPLICA_SNAPSHOT_INTERVAL="${LOGS_REPLICA_SNAPSHOT_INTERVAL:-"48h"}"
export LOGS_REPLICA_SYNC_INTERVAL="${LOGS_REPLICA_SYNC_INTERVAL:-"10m"}"

# Sanity checks
if [ "$PB_ENABLE_AUTO_MIGRATIONS" = "true" ] && [ "$PB_ENABLE_INDIVIDUAL_MIGRATIONS" = "true" ]; then
echo "Auto-migrations and individual migrations can not be set simultaneously."
exit 1
fi

# Make sure PocketBase directories exists
mkdir -p "${PB_DATA_PATH}"
mkdir -p "${PB_STATIC_PATH}"
mkdir -p "${PB_MIGRATIONS_PATH}"
mkdir -p "${PB_HOOKS_PATH}"

# Check if the data restoration is enabled
if [ "$ENABLE_LITESTREAM_DATA_RESTORATION" = "true" ]; then
# Restore the data database if it does not already exist.
if [ -f "${PB_DATA_PATH}/data.db" ]; then
echo "Data database already exists, skipping restore."
else
echo "No data database found, restoring from replica if exists."
litestream restore -if-replica-exists -o "${PB_DATA_PATH}/data.db" "${DATA_REPLICA_URI}"
fi
fi

# Check if the logs restoration is enabled
if [ "$ENABLE_LITESTREAM_LOGS_RESTORATION" = "true" ]; then
# Restore the logs database if it does not already exist.
if [ -f "${PB_DATA_PATH}/logs.db" ]; then
echo "Logs database already exists, skipping restore."
else
echo "No logs database found, restoring from replica if exists."
litestream restore -if-replica-exists -o "${PB_DATA_PATH}/logs.db" "${LOGS_REPLICA_URI}"
fi
fi

if [ "$PB_ENABLE_INDIVIDUAL_MIGRATIONS" = "true" ]; then
/usr/local/bin/pocketbase --migrationsDir=${PB_MIGRATIONS_PATH} migrate
fi

if [ "$ENABLE_LITESTREAM_REPLICATION" = "true" ]; then
# Run litestream with pocketbase as the subprocess.
exec litestream replicate -exec "/usr/local/bin/pocketbase --automigrate=${PB_ENABLE_AUTO_MIGRATIONS} --dir=${PB_DATA_PATH} --publicDir=${PB_STATIC_PATH} --migrationsDir=${PB_MIGRATIONS_PATH} --hooksDir=${PB_HOOKS_PATH} serve --http=0.0.0.0:${PORT:-8090} --encryptionEnv=PB_ENCRYPTION_KEY --dev=${PB_DEV}"
else
/usr/local/bin/pocketbase --automigrate=${PB_ENABLE_AUTO_MIGRATIONS} --dir=${PB_DATA_PATH} --publicDir=${PB_STATIC_PATH} --migrationsDir=${PB_MIGRATIONS_PATH} --hooksDir=${PB_HOOKS_PATH} serve --http=0.0.0.0:${PORT:-8090} --encryptionEnv=PB_ENCRYPTION_KEY --dev=${PB_DEV}
fi
17 changes: 17 additions & 0 deletions etc/litestream.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
addr: ":${LITESTREAM_PORT}"
dbs:
- path: ${PB_DATA_PATH}/data.db
replicas:
- url: ${DATA_REPLICA_URI}
retention: ${DATA_REPLICA_RETENTION}
retention-check-interval: ${DATA_REPLICA_RETENTION_CHECK_INTERVAL}
snapshot-interval: ${DATA_REPLICA_SNAPSHOT_INTERVAL}
validation-interval: ${DATA_REPLICA_VALIDATION_INTERVAL}
sync-interval: ${DATA_REPLICA_SYNC_INTERVAL}
- path: ${PB_DATA_PATH}/logs.db
replicas:
- url: ${LOGS_REPLICA_URI}
retention: ${LOGS_REPLICA_RETENTION}
retention-check-interval: ${LOGS_REPLICA_RETENTION_CHECK_INTERVAL}
snapshot-interval: ${LOGS_REPLICA_SNAPSHOT_INTERVAL}
sync-interval: ${LOGS_REPLICA_SYNC_INTERVAL}

0 comments on commit 479ff8b

Please sign in to comment.