diff --git a/postgresql/Makefile b/postgresql/Makefile new file mode 100644 index 0000000..9dd1ec6 --- /dev/null +++ b/postgresql/Makefile @@ -0,0 +1,66 @@ +.PHONY: all install uninstall pre-requisites clean dryrun + +PROJECT_NAME := $(shell basename "$${PWD}") +QUADLETS_FILES = $(wildcard *.container *.volume *.network *.pod *.build) +SYSTEMD_FILES = $(wildcard *.service *.target *.timer) +SYSTEMD_UNIT_NAMES := $(wildcard *.service *.target *.timer) +SYSTEMD_MAIN_UNIT_NAMES := $(wildcard *.target) +QUADLET_UNIT_NAMES := $(patsubst %.container, %.service, $(wildcard *.container)) \ + $(patsubst %.volume, %-volume.service, $(wildcard *.volume)) \ + $(patsubst %.network, %-network.service, $(wildcard *.network)) \ + $(patsubst %.pod, %-pod.service, $(wildcard *.pod)) \ + $(patsubst %.build, %-build.service, $(wildcard *.build)) +CONFIG_FILES = $(wildcard config/*) +TARGET_QUADLETS_FILES = $(addprefix /etc/containers/systemd/, $(QUADLETS_FILES)) +TARGET_SYSTEMD_FILES = $(addprefix /etc/systemd/system/, $(SYSTEMD_FILES)) +TARGET_CONFIG_FILES = $(patsubst config/%, /etc/quadlets/$(PROJECT_NAME)/%, $(CONFIG_FILES)) + +pre-requisites: + @test "$$(id -u)" -eq 0 || (echo "This Makefile must be run as root" >&2; exit 1) + +all: install + +dryrun: + QUADLET_UNIT_DIRS="$$PWD" /usr/lib/systemd/system-generators/podman-system-generator -dryrun > /dev/null + +/etc/containers/systemd/%.container: %.container + install -D -m 0644 -o root -g root $< $@ + +/etc/containers/systemd/%.volume: %.volume + install -D -m 0644 -o root -g root $< $@ + +/etc/containers/systemd/%.network: %.network + install -D -m 0644 -o root -g root $< $@ + +/etc/containers/systemd/%.pod: %.pod + install -D -m 0644 -o root -g root $< $@ + +/etc/containers/systemd/%.build: %.build + install -D -m 0644 -o root -g root $< $@ + +/etc/systemd/system/%.service: %.service + install -D -m 0644 -o root -g root $< $@ + +/etc/systemd/system/%.target: %.target + install -D -m 0644 -o root -g root $< $@ + +/etc/systemd/system/%.timer: %.timer + install -D -m 0644 -o root -g root $< $@ + +/etc/quadlets/$(PROJECT_NAME)/%: config/% + install -D -m 0644 -o root -g root $< $@ + +install: pre-requisites dryrun $(TARGET_QUADLETS_FILES) $(TARGET_SYSTEMD_FILES) $(TARGET_CONFIG_FILES) + systemctl daemon-reload + systemd-analyze --generators=true verify $(QUADLET_UNIT_NAMES) $(SYSTEMD_UNIT_NAMES) + systemctl enable $(SYSTEMD_UNIT_NAMES) + systemctl start $(SYSTEMD_MAIN_UNIT_NAMES) + +uninstall: pre-requisites + systemctl --no-block disable $(SYSTEMD_UNIT_NAMES) || true + systemctl --no-block stop $(SYSTEMD_UNIT_NAMES) $(QUADLET_UNIT_NAMES) || true + rm -f $(TARGET_QUADLETS_FILES) $(TARGET_SYSTEMD_FILES) $(TARGET_CONFIG_FILES) + systemctl daemon-reload + +clean: + rm -rf /var/lib/quadlets/$(PROJECT_NAME)/ /etc/quadlets/$(PROJECT_NAME)/ diff --git a/postgresql/config/config.env b/postgresql/config/config.env new file mode 100644 index 0000000..772ef58 --- /dev/null +++ b/postgresql/config/config.env @@ -0,0 +1,7 @@ +POSTGRES_USER=postgres +POSTGRES_PASSWORD=postgres +POSTGRES_DB=postgres +POSTGRES_HOST_AUTH_METHOD=scram-sha-256 +POSTGRES_INITDB_ARGS=--auth-host=scram-sha-256 +PGPORT=5432 +PG_MAJOR=17 diff --git a/postgresql/postgresql-init.container b/postgresql/postgresql-init.container new file mode 100644 index 0000000..c6590f5 --- /dev/null +++ b/postgresql/postgresql-init.container @@ -0,0 +1,51 @@ +[Unit] +Description=PostgreSQL Database Server - Initialization +Documentation=https://hub.docker.com/_/postgres/ +After=network.target postgresql-set-major.service +Before=postgresql-server.service +Requires=postgresql-set-major.service + +# Only start if PostgreSQL has been configured +ConditionPathExists=/etc/quadlets/postgresql/config.env +# and NOT initialized +ConditionPathExists=!/var/lib/quadlets/postgresql/.initialized + +# Start/stop this unit when the target is started/stopped +PartOf=postgresql.target + +[Container] +ContainerName=postgresql-init-job +Image=docker.io/library/postgres:${PG_MAJOR}-alpine + +# Network configuration +Network=host + +# PostgreSQL storage is specific to major version +Environment=PGDATA=/var/lib/postgresql/${PG_MAJOR}/docker + +# Those environment variables will be injected by podman into the container +EnvironmentFile=/etc/quadlets/postgresql/config.env + +# Use the official entrypoint script to initialize the database +Entrypoint=/usr/local/bin/docker-ensure-initdb.sh +# Entrypoint=/bin/sleep +# Exec=INF + +# Volume mounts +Volume=/var/lib/quadlets/postgresql:/var/lib/postgresql:z + +[Service] +Restart=no +TimeoutStartSec=30 + +# These environment variables are sourced to be used by systemd in the Exec* commands +EnvironmentFile=/etc/quadlets/postgresql/config.env + +# This container is a job - run once to completion +Type=oneshot + +# Mark the database as intialized +ExecStartPost=touch /var/lib/quadlets/postgresql/.initialized + +[Install] +WantedBy=postgresql.target diff --git a/postgresql/postgresql-server.container b/postgresql/postgresql-server.container new file mode 100644 index 0000000..3266c2f --- /dev/null +++ b/postgresql/postgresql-server.container @@ -0,0 +1,54 @@ +[Unit] +Description=PostgreSQL Database Server +Documentation=https://hub.docker.com/_/postgres/ +After=network.target postgresql-upgrade.service postgresql-init.service +Requires=postgresql-upgrade.service postgresql-init.service +Before=postgresql.target + +# Only start if PostgreSQL has been configured +ConditionPathExists=/etc/quadlets/postgresql/config.env +# and initialized +ConditionPathExists=/var/lib/quadlets/postgresql/.initialized +# and upgraded +ConditionPathExists=/var/lib/quadlets/postgresql/latest/docker/PG_VERSION + +# Start/stop this unit when the target is started/stopped +PartOf=postgresql.target + +[Container] +ContainerName=postgresql-server +Image=docker.io/library/postgres:${PG_MAJOR}-alpine + +# Network configuration +Network=host + +# PostgreSQL storage is specific to major version +Environment=PGDATA=/var/lib/postgresql/${PG_MAJOR}/docker + +# Safety flag to avoid initialization of an unwanted database +Environment=DATABASE_ALREADY_EXISTS=true + +# Those environment variables will be injected by podman into the container +EnvironmentFile=/etc/quadlets/postgresql/config.env + +# Volume mounts +Volume=/var/lib/quadlets/postgresql:/var/lib/postgresql:z + +# Health check +HealthCmd=pg_isready -U $POSTGRES_USER -d $POSTGRES_DB -p $PGPORT +HealthInterval=30s +HealthTimeout=10s +HealthStartPeriod=60s +HealthRetries=3 + +[Service] +Restart=always +RestartSec=10 +TimeoutStartSec=120 +TimeoutStopSec=30 + +# These environment variables are sourced to be used by systemd in the Exec* commands +EnvironmentFile=/etc/quadlets/postgresql/config.env + +[Install] +WantedBy=postgresql.target diff --git a/postgresql/postgresql-set-major.service b/postgresql/postgresql-set-major.service new file mode 100644 index 0000000..e5c2272 --- /dev/null +++ b/postgresql/postgresql-set-major.service @@ -0,0 +1,29 @@ +[Unit] +Description=PostgreSQL Database Server - Set major version +Documentation=https://hub.docker.com/_/postgres/ +Before=postgresql-update.service postgresql-server.service + +# Only start if PostgreSQL has been configured +ConditionPathExists=/etc/quadlets/postgresql/config.env + +# Start/stop this unit when the target is started/stopped +PartOf=postgresql.target + +[Service] +Restart=no +TimeoutStartSec=30 + +# These environment variables are sourced to be used by systemd in the Exec* commands +EnvironmentFile=/etc/quadlets/postgresql/config.env + +# Skaffold filesystem + fix permissions +ExecStartPre=install -m 0700 -o 70 -g 70 -d /var/lib/quadlets/postgresql + +# Set the "latest" symlink to point to the desired major version +ExecStart=ln -sfT ${PG_MAJOR} /var/lib/quadlets/postgresql/latest + +# This service is a job - run once to completion +Type=oneshot + +[Install] +WantedBy=postgresql.target diff --git a/postgresql/postgresql-upgrade.container b/postgresql/postgresql-upgrade.container new file mode 100644 index 0000000..d1f2036 --- /dev/null +++ b/postgresql/postgresql-upgrade.container @@ -0,0 +1,46 @@ +[Unit] +Description=PostgreSQL Database Server - Upgrade +Documentation=https://hub.docker.com/r/pgautoupgrade/pgautoupgrade +After=network.target postgresql-set-major.service +Before=postgresql-server.service +Requires=postgresql-set-major.service + +# Only start if PostgreSQL has been configured +ConditionPathExists=/etc/quadlets/postgresql/config.env +# and initialized +ConditionPathExists=/var/lib/quadlets/postgresql/.initialized +# and not yet upgraded +ConditionPathExists=!/var/lib/quadlets/postgresql/latest/docker/PG_VERSION + +# Start/stop this unit when the target is started/stopped +PartOf=postgresql.target + +[Container] +ContainerName=postgresql-upgrade-to-${PG_MAJOR}-job +Image=docker.io/pgautoupgrade/pgautoupgrade:${PG_MAJOR}-alpine + +# Network configuration +Network=host + +# PostgreSQL storage is specific to major version +Environment=PGDATA=/var/lib/postgresql/${PG_MAJOR}/docker +Environment=PGAUTO_ONESHOT=yes + +# Those environment variables will be injected by podman into the container +EnvironmentFile=/etc/quadlets/postgresql/config.env + +# Volume mounts +Volume=/var/lib/quadlets/postgresql:/var/lib/postgresql:z + +[Service] +Restart=no +TimeoutStartSec=600 + +# These environment variables are sourced to be used by systemd in the Exec* commands +EnvironmentFile=/etc/quadlets/postgresql/config.env + +# This container is a job - run once to completion +Type=oneshot + +[Install] +WantedBy=postgresql.target diff --git a/postgresql/postgresql.target b/postgresql/postgresql.target new file mode 100644 index 0000000..55f9f2b --- /dev/null +++ b/postgresql/postgresql.target @@ -0,0 +1,13 @@ +[Unit] +Description=PostgreSQL Service Target +Documentation=man:systemd.target(5) +Requires=postgresql-server.service postgresql-upgrade.service postgresql-init.service postgresql-set-major.service +After=postgresql-server.service postgresql-upgrade.service postgresql-init.service postgresql-set-major.service + +# Allow isolation - can stop/start this target independently +AllowIsolate=yes +# Only start if PostgreSQL has been configured +ConditionPathExists=/etc/quadlets/postgresql/config.env + +[Install] +WantedBy=multi-user.target