Welcome to the second post in my data stack setup journey! šŸŽ‰ My goal is to hustle through setting up all the components so I can get to the good stuff: data and analytics engineering.

But first, I need a documentation server, because, letā€™s be realā€”Iā€™m already forgetting where Iā€™ve documented things. šŸ™ƒ

What is Bookstack?

BookStack describes itself as a “simple, self-hosted, easy-to-use platform for organizing and storing information.” I like to think of it as: a wiki thatā€™s easy to host, simple to back up, and doesnā€™t make you cry.

What are you using this for?

BookStack is my documentation layer in the data stack. Hereā€™s what I plan to use it for:

  • Network configurations
  • Initial data catalog repository
  • Notes and configs for everything Iā€™m doing

Basically, itā€™s where my brain will live when it canā€™t keep up. šŸ§ 

Is Bookstack the best option for documentation?

Honestly? I have no idea. It works for me, and the price is right! (Spoiler: itā€™s free.)
If youā€™re looking for the definitive guide to all things documentation, this isnā€™t it. Move along. šŸ˜„

Okay whatever, so how are doing this?

Iā€™m using Docker Compose for pretty much everything. Back in the day, I tried installing tools directly on bare metal. It was a pain to maintain and update.

Docker Compose changed the game. Infrastructure as code? Yes, please.

Will you explain how to setup docker and what docker compose and does?

No.

Great.

It is great, you should check it out!

For this setup, Iā€™m using the official LinuxServer.io BookStack Docker image.

The documentation is pretty great. Hereā€™s the base Docker Compose configuration from their docs:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
---
services:
    bookstack:
    image: lscr.io/linuxserver/bookstack:latest
    container_name: bookstack
    environment:
    - PUID=1000
    - PGID=1000
    - TZ=Etc/UTC
    - APP_URL=
    - APP_KEY=
    - DB_HOST=
    - DB_PORT=3306
    - DB_USERNAME=
    - DB_PASSWORD=
    - DB_DATABASE=
    - QUEUE_CONNECTION= #optional
    volumes:
    - /path/to/bookstack/config:/config
    ports:
    - 6875:80
    restart: unless-stopped

The first thing that sticks out to me is that this image requires a database (that isn’t included). Reading through the documentation BookStack needs a MySQL-compatible database, but one isnā€™t included in the image. Enter: MariaDB (the first database in this journey).

Now I have a decision to make:

  1. Add the database to the same docker-compose.yaml file.
  2. Set up a separate database container for future reuse.

Since I need this documentation server running yesterday, Iā€™m going with option 1. Letā€™s flex those Docker skills. šŸ’Ŗ

Adding the database: MariaDB šŸ›¢ļø

LinuxServer.io suggests their MariaDB image, so letā€™s roll with it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
services:
  mariadb:
    image: lscr.io/linuxserver/mariadb:latest
    container_name: mariadb
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Etc/UTC
      - MYSQL_ROOT_PASSWORD=ROOT_ACCESS_PASSWORD
      - MYSQL_DATABASE=USER_DB_NAME #optional
      - MYSQL_USER=MYSQL_USER #optional
      - MYSQL_PASSWORD=DATABASE_PASSWORD #optional
    volumes:
      - /path/to/mariadb/config:/config
    ports:
      - 3306:3306
    restart: unless-stopped

Stitching it together šŸ§µ

Hereā€™s what Iā€™m adding to the docker-compose.yaml file:

  • Environment variables
  • The depends_on property so BookStack waits for the database to be ready
  • A healthcheck to ensure MariaDB finishes initializing before BookStack tries to connect

Hereā€™s the final docker-compose.yaml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
version: '3.9'

services:
  bookstack:
    image: lscr.io/linuxserver/bookstack:latest
    container_name: bookstack
    depends_on:
      mariadb:
        condition: service_healthy
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
      - APP_URL=${APP_URL}
      - APP_KEY=${APP_KEY}
      - DB_HOST=${DB_HOST}
      - DB_PORT=${DB_PORT}
      - DB_USERNAME=${DB_USERNAME}
      - DB_PASSWORD=${DB_PASSWORD}
      - DB_DATABASE=${DB_DATABASE}
      - QUEUE_CONNECTION=${QUEUE_CONNECTION}
    volumes:
      - ./bookstack/config:/config
    ports:
      - 6875:80
    restart: unless-stopped

  mariadb:
    image: lscr.io/linuxserver/mariadb:latest
    container_name: mariadb
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - MYSQL_DATABASE=${MYSQL_DATABASE}
      - MYSQL_USER=${MYSQL_USER}
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
    volumes:
      - ./mariadb/config:/config
    ports:
      - 3306:3306
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 3

Environment Variables: .env File

To keep things tidy, Iā€™m storing all sensitive info in a .env file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# Common Settings
PUID=1000
PGID=1000
TZ=America/Chicago

# BookStack Settings
APP_URL=http://your-app-url-here
APP_KEY=base64:YOUR_APP_KEY_HERE
DB_HOST=mariadb
DB_PORT=3306
DB_USERNAME=bookstack
DB_PASSWORD=your-db-password-here
DB_DATABASE=bookstack
QUEUE_CONNECTION=sync

# MariaDB Settings
MYSQL_ROOT_PASSWORD=your-root-password-here
MYSQL_DATABASE=bookstack
MYSQL_USER=bookstack
MYSQL_PASSWORD=your-db-password-here

Running the containers

With the docker-compose.yaml and .env files in place, itā€™s time to fire it up:

1
docker compose up

Well…. Something’s gone wrong.

Checking the logs, I find this gem:

1
2
bookstack  | An application key is missing, halting init!
bookstack  | You can generate a key with: docker run -it --rm --entrypoint /bin/bash lscr.io/linuxserver/bookstack:latest appkey

No worriesā€”I run the command to generate the key, update the .env file, and try again.


Success! šŸŽ‰

And there it is: my shiny new BookStack instance, up and running.

Bookstack Login Screen

Next stop: Probably airflow! Maybe. šŸ›¤ļø