feat(services): bookstack (#33)

* feat(bookstack): working example bookstack instance

* build(taskfiles): add Taskfile to handle start+stop

* fix: ensure that network exists without erroring

* chore(git): ignore Task bin

* docs: notes on volumes, task commands

* build(taskfiles): add build command, centralized user-supplied env

* refactor(taskfiles): split away internal tasks

* refactor(taskfiles): move environment variables into shared env.yml
This commit is contained in:
Marc 2023-12-15 12:40:14 -05:00 committed by GitHub
parent 913886283c
commit 92d8d3672d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 189 additions and 0 deletions

2
.gitignore vendored
View file

@ -1,5 +1,7 @@
spadinaistan.venv spadinaistan.venv
env.yml
bin
services.yml services.yml
**/*.env **/*.env
**/.env **/.env

View file

@ -10,3 +10,26 @@ anyone else.
Use `. script/bootstrap` to set up the Python environment needed for the invoke and pyinfra tooling to work. Use `. script/bootstrap` to set up the Python environment needed for the invoke and pyinfra tooling to work.
This expects `pyenv` to be set up on your system. This expects `pyenv` to be set up on your system.
## Configuration
### Environment provided to tasks
The task runner requires a `env.yml` file to exist at the top level. This should define a few global variables that are
specific to the environment:
```
version: '3'
env:
# Path to the application data storage root.
APP_DATA_DIR: ...
# Prefix to all container names.
CONTAINER_NAME_PREFIX: ...
# Path to the app-specific dotenv files.
ENV_FILE_DIR: ...
# Name of the network associated with the tunnel exposing services.
SHARED_NETWORK_NAME: ...
```
The `env.yml` file is ignored by version-control.

18
Taskfile.internal.yml Normal file
View file

@ -0,0 +1,18 @@
version: '3'
output: prefixed
internal: true
tasks:
build-images:
prefix: "build image: {{ .SERVICE }}"
dir: services/{{ .SERVICE }}
cmd: . ./build.sh
start-service:
prefix: "start: {{ .SERVICE }}"
dir: services/{{ .SERVICE }}
cmd: . ./start.sh
stop-service:
prefix: "stop: {{ .SERVICE }}"
dir: services/{{ .SERVICE }}
cmd: . ./stop.sh

41
Taskfile.yml Normal file
View file

@ -0,0 +1,41 @@
version: '3'
includes:
# This file should be supplied by the environment and is not committed.
global-env:
taskfile: ./env.yml
internal: true
internal:
taskfile: ./Taskfile.internal.yml
internal: true
output: prefixed
tasks:
build:
desc: "Builds images for one or more services. Include service names as a space-separated list."
cmds:
- for: { var: CLI_ARGS }
task: internal:build-images
vars:
SERVICE: "{{ .ITEM }}"
prefix: "build: {{ .CLI_ARGS }}"
dir: services
start:
desc: "Starts one or more services. Include service names as a space-separated list."
cmds:
- for: { var: CLI_ARGS }
task: internal:start-service
vars:
SERVICE: "{{ .ITEM }}"
prefix: "start: {{ .CLI_ARGS }}"
dir: services
stop:
desc: "Stops one or more services. Include service names as a space-separated list."
cmds:
- for: { var: CLI_ARGS }
task: internal:stop-service
vars:
SERVICE: "{{ .ITEM }}"
prefix: "stop: {{ .CLI_ARGS }}"
dir: services

18
script/bootstrap-tasks Normal file
View file

@ -0,0 +1,18 @@
#!/bin/bash
TASK_VERSION="v3.28.0"
BIN_PATH=$PWD/bin
if [[ ! -f $BIN_PATH/task || -z "$($BIN_PATH/task --version | grep $TASK_VERSION)" ]]; then
sh -c "$(curl --location https://taskfile.dev/install.sh)" -- $TASK_VERSION -d
fi
BIN_PATH=$PWD/bin
BIN_MATCH=$(echo $PATH | grep "\:$BIN_PATH")
if [[ -z $BIN_MATCH ]]; then
echo "Adding Task to \$PATH."
export PATH=$PATH:$BIN_PATH
fi
echo "All done!"

View file

@ -0,0 +1 @@
FROM linuxserver/bookstack:23.10.4

View file

@ -0,0 +1 @@
FROM mariadb:10.6

View file

@ -0,0 +1,43 @@
# Bookstack
Sets up and manages a [Bookstack](https://www.bookstackapp.com/) instance.
## Getting started
- `start.sh` starts the database and application.
- `stop.sh` stops the database and application.
- `build.sh` builds images for the database and application and should be run _before_ starting anything.
Any commitable constant can be defined in `constants.sh` and will be injected in all of the scripts above.
__The `task` commands should be used to interact with the service.__
## Volumes
This expects two volumes to exist at `$APP_DATA_DIR`: `bookstack-app` and `bookstack-db`.
## Note on dotenv files
dotenv files are expected to exist at `$ENV_FILE_DIR` under `bookstack-db.env` and `bookstack-app.env`.
See reference:
```
# bookstack-db-env
MARIADB_USER=...
MARIADB_PASSWORD=...
MARIADB_ROOT_PASSWORD=...
MARIADB_DATABASE=...
```
```
# bookstack-app.env
DB_PORT=...
DB_USER=...
DB_PASS=...
DB_DATABASE=...
DB_HOST=...
APP_URL=...
```

View file

@ -0,0 +1,6 @@
#!/bin/bash
source constants.sh
docker build -t $DB_IMAGE_NAME:dev -f Dockerfile-bookstack-db .
docker build -t $APP_IMAGE_NAME:dev -f Dockerfile-bookstack-app .

View file

@ -0,0 +1,8 @@
#!/bin/bash
export APP_NAME="bookstack"
export APP_CONTAINER_NAME=$APP_NAME-app
export APP_IMAGE_NAME=$CONTAINER_NAME_PREFIX-$APP_CONTAINER_NAME
export DB_CONTAINER_NAME=$APP_NAME-db
export DB_IMAGE_NAME=$CONTAINER_NAME_PREFIX-$DB_CONTAINER_NAME
export NETWORK_NAME=$APP_NAME-local

View file

@ -0,0 +1,22 @@
#!/bin/bash
source constants.sh
docker network create $NETWORK_NAME || echo "Network $NETWORK_NAME already exists"
docker run \
--detach \
--network $NETWORK_NAME \
--name $DB_CONTAINER_NAME \
--env-file $ENV_FILE_DIR/bookstack-db.env \
--mount type=bind,source=$APP_DATA_DIR/bookstack-db,target=/var/lib/mysql \
$DB_IMAGE_NAME:dev
docker run \
--detach \
--network $NETWORK_NAME \
--name $APP_CONTAINER_NAME \
--env-file $ENV_FILE_DIR/bookstack-app.env \
--publish 6875:80 \
--mount type=bind,source=$APP_DATA_DIR/bookstack-app,target=/config \
$APP_IMAGE_NAME:dev

View file

@ -0,0 +1,6 @@
#!/bin/bash
source constants.sh
docker rm -f $APP_CONTAINER_NAME
docker rm -f $DB_CONTAINER_NAME