Browse Source

work in progress

main
Nicolas Massé 2 months ago
parent
commit
f49afc289f
  1. 91
      Makefile.common
  2. 1
      README.md
  3. 8
      generate-butane-spec.sh
  4. 64
      nextcloud/Makefile
  5. 3
      nextcloud/config/config.env
  6. 4
      nextcloud/config/custom-noinit.sh
  7. 14
      nextcloud/config/custom-post.sh
  8. 7
      nextcloud/config/custom-pre.sh
  9. 0
      nextcloud/config/redis-session.ini
  10. 9
      nextcloud/config/redis.conf
  11. 22
      nextcloud/nextcloud-app.container
  12. 51
      nextcloud/nextcloud-cron.container
  13. 12
      nextcloud/nextcloud-cron.timer
  14. 55
      nextcloud/nextcloud-init.container
  15. 2
      nextcloud/nextcloud-nginx.container
  16. 7
      nextcloud/nextcloud-redis.container
  17. 57
      nextcloud/nextcloud-upgrade.container
  18. 5
      nextcloud/nextcloud.target
  19. 3
      nextcloud/sysctl.d/nextcloud.conf
  20. 2
      nextcloud/tmpfiles.d/nextcloud.conf
  21. 6
      postgresql/Makefile
  22. 4
      postgresql/postgresql-backup.container
  23. 11
      postgresql/postgresql-backup.timer
  24. 7
      postgresql/postgresql-server.container
  25. 3
      postgresql/postgresql.target
  26. 3
      postgresql/sysctl.d/postgresql.conf
  27. 1
      postgresql/tmpfiles.d/postgresql.conf

91
Makefile.common

@ -1,4 +1,6 @@
.PHONY: all install install-etc install-var uninstall pre-requisites clean dryrun tail-logs butane help fcos-vm clean-vm console .PHONY: all install install-etc install-var uninstall pre-requisites clean dryrun
.PHONY: tail-logs butane help fcos-vm clean-vm console
.PHONY: clean-pre clean-post install-pre install-post uninstall-pre uninstall-post
all: help all: help
help: help:
@ -14,7 +16,6 @@ help:
@echo " clean-vm - Clean up the Fedora CoreOS VM and its resources" @echo " clean-vm - Clean up the Fedora CoreOS VM and its resources"
@echo " console - Connect to the Fedora CoreOS VM console" @echo " console - Connect to the Fedora CoreOS VM console"
TARGET_CHROOT ?= TARGET_CHROOT ?=
PROJECT_NAME := $(shell basename "$${PWD}") PROJECT_NAME := $(shell basename "$${PWD}")
QUADLETS_FILES = $(wildcard *.container *.volume *.network *.pod *.build) QUADLETS_FILES = $(wildcard *.container *.volume *.network *.pod *.build)
@ -28,10 +29,17 @@ QUADLET_UNIT_NAMES := $(patsubst %.container, %.service, $(wildcard *.container)
$(patsubst %.pod, %-pod.service, $(wildcard *.pod)) \ $(patsubst %.pod, %-pod.service, $(wildcard *.pod)) \
$(patsubst %.build, %-build.service, $(wildcard *.build)) $(patsubst %.build, %-build.service, $(wildcard *.build))
CONFIG_FILES = $(wildcard config/*) CONFIG_FILES = $(wildcard config/*)
TMPFILESD_FILES = $(wildcard tmpfiles.d/*)
SYSCTLD_FILES = $(wildcard sysctl.d/*)
TARGET_QUADLETS_FILES = $(addprefix $(TARGET_CHROOT)/etc/containers/systemd/, $(QUADLETS_FILES)) TARGET_QUADLETS_FILES = $(addprefix $(TARGET_CHROOT)/etc/containers/systemd/, $(QUADLETS_FILES))
TARGET_SYSTEMD_FILES = $(addprefix $(TARGET_CHROOT)/etc/systemd/system/, $(SYSTEMD_FILES)) TARGET_SYSTEMD_FILES = $(addprefix $(TARGET_CHROOT)/etc/systemd/system/, $(SYSTEMD_FILES))
TARGET_CONFIG_FILES = $(patsubst config/%, $(TARGET_CHROOT)/etc/quadlets/$(PROJECT_NAME)/%, $(CONFIG_FILES)) TARGET_CONFIG_FILES = $(patsubst config/%, $(TARGET_CHROOT)/etc/quadlets/$(PROJECT_NAME)/%, $(CONFIG_FILES))
TARGET_FILES = $(TARGET_QUADLETS_FILES) $(TARGET_SYSTEMD_FILES) $(TARGET_CONFIG_FILES) TARGET_FILES = $(TARGET_QUADLETS_FILES) $(TARGET_SYSTEMD_FILES) $(TARGET_CONFIG_FILES)
TARGET_TMPFILESD_FILES = $(patsubst tmpfiles.d/%, $(TARGET_CHROOT)/etc/tmpfiles.d/%, $(TMPFILESD_FILES))
TARGET_SYSCTLD_FILES = $(patsubst sysctl.d/%, $(TARGET_CHROOT)/etc/sysctl.d/%, $(SYSCTLD_FILES))
DEPENDENCIES ?=
I_KNOW_WHAT_I_AM_DOING ?=
DEPENDENCIES_IGNITION_FILES = $(shell for dep in $(DEPENDENCIES); do echo $(TOP_LEVEL_DIR)/$$dep/$$dep.ign; done)
pre-requisites: pre-requisites:
@if [ -z "$(TOP_LEVEL_DIR)" ]; then \ @if [ -z "$(TOP_LEVEL_DIR)" ]; then \
@ -55,6 +63,12 @@ $(TARGET_CHROOT)/etc/systemd/system:
$(TARGET_CHROOT)/etc/quadlets/$(PROJECT_NAME): $(TARGET_CHROOT)/etc/quadlets/$(PROJECT_NAME):
install -D -d -m 0755 -o root -g root $@ install -D -d -m 0755 -o root -g root $@
$(TARGET_CHROOT)/etc/tmpfiles.d:
install -D -d -m 0755 -o root -g root $@
$(TARGET_CHROOT)/etc/sysctl.d:
install -D -d -m 0755 -o root -g root $@
$(TARGET_CHROOT)/etc/containers/systemd/%.container: %.container $(TARGET_CHROOT)/etc/containers/systemd $(TARGET_CHROOT)/etc/containers/systemd/%.container: %.container $(TARGET_CHROOT)/etc/containers/systemd
install -m 0644 -o root -g root $< $@ install -m 0644 -o root -g root $< $@
@ -90,25 +104,58 @@ $(TARGET_CHROOT)/etc/quadlets/$(PROJECT_NAME)/%: config/% $(TARGET_CHROOT)/etc/q
$(TARGET_CHROOT)/var/lib/quadlets/$(PROJECT_NAME): $(TARGET_CHROOT)/var/lib/quadlets/$(PROJECT_NAME):
install -d -m 0755 -o root -g root $@ install -d -m 0755 -o root -g root $@
install-etc: $(TARGET_QUADLETS_FILES) $(TARGET_SYSTEMD_FILES) $(TARGET_CONFIG_FILES) $(TARGET_CHROOT)/etc/tmpfiles.d/%: tmpfiles.d/% $(TARGET_CHROOT)/etc/tmpfiles.d
install -D -m 0644 -o root -g root $< $@
$(TARGET_CHROOT)/etc/sysctl.d/%: sysctl.d/% $(TARGET_CHROOT)/etc/sysctl.d
install -D -m 0644 -o root -g root $< $@
install-etc: $(TARGET_QUADLETS_FILES) $(TARGET_SYSTEMD_FILES) $(TARGET_CONFIG_FILES) $(TARGET_TMPFILESD_FILES) $(TARGET_SYSCTLD_FILES)
install-var: $(TARGET_CHROOT)/var/lib/quadlets/$(PROJECT_NAME) install-var: $(TARGET_CHROOT)/var/lib/quadlets/$(PROJECT_NAME)
install: pre-requisites dryrun install-etc install-var install-pre::
@run() { echo $$*; "$$@"; }; \
for dep in $(DEPENDENCIES); do \
run $(MAKE) -C $(TOP_LEVEL_DIR)/$$dep install; \
done
install-post::
install: pre-requisites dryrun install-etc install-var install-pre
systemctl daemon-reload systemctl daemon-reload
systemd-analyze --generators=true verify $(QUADLET_UNIT_NAMES) $(SYSTEMD_UNIT_NAMES) systemd-analyze --generators=true verify $(QUADLET_UNIT_NAMES) $(SYSTEMD_UNIT_NAMES)
systemctl enable $(SYSTEMD_UNIT_NAMES) @run() { echo $$*; "$$@"; }; \
if [ -f /etc/tmpfiles.d/$(PROJECT_NAME).conf ]; then \
run systemd-tmpfiles --create /etc/tmpfiles.d/$(PROJECT_NAME).conf; \
fi; \
if [ -f /etc/sysctl.d/$(PROJECT_NAME).conf ]; then \
run sysctl -q -p /etc/sysctl.d/$(PROJECT_NAME).conf; \
fi
systemctl enable $(SYSTEMD_MAIN_UNIT_NAMES) $(SYSTEMD_TIMER_NAMES)
systemctl start $(SYSTEMD_MAIN_UNIT_NAMES) systemctl start $(SYSTEMD_MAIN_UNIT_NAMES)
$(MAKE) install-post
uninstall: pre-requisites uninstall-pre::
systemctl --no-block disable $(SYSTEMD_UNIT_NAMES) || true uninstall-post::
systemctl --no-block stop $(SYSTEMD_UNIT_NAMES) $(QUADLET_UNIT_NAMES) || true @run() { echo $$*; "$$@"; }; \
for dep in $(DEPENDENCIES); do \
run $(MAKE) -C $(TOP_LEVEL_DIR)/$$dep uninstall; \
done
uninstall: pre-requisites uninstall-pre
systemctl disable $(SYSTEMD_MAIN_UNIT_NAMES) $(SYSTEMD_TIMER_NAMES) || true
systemctl stop $(SYSTEMD_UNIT_NAMES) $(QUADLET_UNIT_NAMES) || true
@run() { echo $$*; "$$@"; }; \
if [ -f /etc/tmpfiles.d/$(PROJECT_NAME).conf ]; then \
run systemd-tmpfiles --purge /etc/tmpfiles.d/$(PROJECT_NAME).conf; \
fi
rm -f $(TARGET_QUADLETS_FILES) $(TARGET_SYSTEMD_FILES) $(TARGET_CONFIG_FILES) rm -f $(TARGET_QUADLETS_FILES) $(TARGET_SYSTEMD_FILES) $(TARGET_CONFIG_FILES)
systemctl daemon-reload systemctl daemon-reload
$(MAKE) uninstall-post
tail-logs: pre-requisites tail-logs: pre-requisites
@run() { echo $$*; "$$@"; }; \ @run() { echo $$*; "$$@"; }; \
declare -a journalctl_args=( -f ); \ declare -a journalctl_args=( -f ); \
for unit in $(SYSTEMD_MAIN_UNIT_NAMES) $(QUADLET_UNIT_NAMES); do \ for unit in $(SYSTEMD_UNIT_NAMES) $(QUADLET_UNIT_NAMES); do \
journalctl_args+=( -u "$$unit" ); \ journalctl_args+=( -u "$$unit" ); \
done; \ done; \
run journalctl "$${journalctl_args[@]}" run journalctl "$${journalctl_args[@]}"
@ -133,7 +180,12 @@ butane:
$(TOP_LEVEL_DIR)/local.ign: $(TOP_LEVEL_DIR)/local.bu $(TOP_LEVEL_DIR)/local.ign: $(TOP_LEVEL_DIR)/local.bu
butane --strict -o $@ $< butane --strict -o $@ $<
fcos.ign: fcos.bu $(TOP_LEVEL_DIR)/local.ign $(PROJECT_NAME).ign # Because we don't know how to build this file, it is safer to declare it as phony and let the Makefile of the dependency handle it.
.PHONY: $(DEPENDENCIES_IGNITION_FILES)
$(DEPENDENCIES_IGNITION_FILES):
$(MAKE) -C $(dir $@) $(notdir $@)
fcos.ign: fcos.bu $(TOP_LEVEL_DIR)/local.ign $(PROJECT_NAME).ign $(DEPENDENCIES_IGNITION_FILES)
@run() { echo $$*; "$$@"; }; \ @run() { echo $$*; "$$@"; }; \
tmp=$$(mktemp -d /tmp/butane-XXXXXX); \ tmp=$$(mktemp -d /tmp/butane-XXXXXX); \
run cp $(filter %.ign,$^) $$tmp; \ run cp $(filter %.ign,$^) $$tmp; \
@ -170,14 +222,23 @@ clean-vm: pre-requisites
rm -rf /var/lib/libvirt/images/$(PROJECT_NAME) rm -rf /var/lib/libvirt/images/$(PROJECT_NAME)
console: pre-requisites console: pre-requisites
@while sleep 2; do virsh console $(PROJECT_NAME); done @while sleep 2; do virsh console $(PROJECT_NAME); echo -e "Disconnected. Reconnecting in 2 seconds...\nPress Ctrl-C to abort.\n"; done
clean: pre-requisites clean-pre::
@run() { echo $$*; "$$@"; }; \
for dep in $(DEPENDENCIES); do \
run $(MAKE) -C $(TOP_LEVEL_DIR)/$$dep clean; \
done
clean-post::
clean: clean-pre pre-requisites
rm -f *.butane rm -f *.butane
@run() { echo $$*; "$$@"; }; \ @run() { echo $$*; "$$@"; }; \
if [ "$(I_KNOW_WHAT_I_AM_DOING)" != "yes" ]; then \
read -p "This will remove all data of '$(PROJECT_NAME)'. Are you sure? (only 'yes' is accepted) " ans; \ read -p "This will remove all data of '$(PROJECT_NAME)'. Are you sure? (only 'yes' is accepted) " ans; \
if [ "$$ans" = "yes" ] || [ "$$ans" = "YES" ]; then \ if [ "$$ans" != "yes" ] && [ "$$ans" != "YES" ]; then \
run rm -rf /var/lib/quadlets/$(PROJECT_NAME)/ /var/run/quadlets/$(PROJECT_NAME)/ /etc/quadlets/$(PROJECT_NAME)/; \
else \
echo "Aborted."; exit 1; \ echo "Aborted."; exit 1; \
fi; \
fi fi
rm -rf /var/lib/quadlets/$(PROJECT_NAME)/ /var/run/quadlets/$(PROJECT_NAME)/ /etc/quadlets/$(PROJECT_NAME)/
$(MAKE) clean-post

1
README.md

@ -7,6 +7,7 @@ This repository gathers all the recipes (hence the name "Cookbook") to deploy Op
- [nginx](nginx/): starts Nginx, content is initialized / updated from a GIT repository - [nginx](nginx/): starts Nginx, content is initialized / updated from a GIT repository
- [postgresql](postgresql/): starts a PostgreSQL server, handles automated major upgrades, periodic backup and initialization of the database from the last backup. - [postgresql](postgresql/): starts a PostgreSQL server, handles automated major upgrades, periodic backup and initialization of the database from the last backup.
- [nextcloud](nextcloud/): starts a Nextcloud server with all its dependencies, handles automated upgrades.
## License ## License

8
generate-butane-spec.sh

@ -35,9 +35,9 @@ for file in $(find "$TARGET_CHROOT" \! -type d); do
group: group:
id: $(stat -c '%g' "$file") id: $(stat -c '%g' "$file")
contents: contents:
compression: gzip inline: |
source: data:;base64,$(gzip -c "$file" | base64 -w0)
EOF EOF
sed 's/^/ /; $s/$/\n/' "$file"
done done
cat <<"EOF" cat <<"EOF"
directories: directories:
@ -45,8 +45,10 @@ EOF
for dir in $(find "$TARGET_CHROOT" -type d); do for dir in $(find "$TARGET_CHROOT" -type d); do
rel_path="${dir#$TARGET_CHROOT}" rel_path="${dir#$TARGET_CHROOT}"
if [[ "$rel_path" != "/var/lib/quadlets/"* ]] && [[ "$rel_path" != "/etc/quadlets/"* ]] \ if [[ "$rel_path" != "/var/lib/quadlets/"* ]] && [[ "$rel_path" != "/etc/quadlets/"* ]] \
&& [[ "$rel_path" != "/etc/systemd/system/"* ]] && [[ "$rel_path" != "/etc/containers/systemd/"* ]]; then && [[ "$rel_path" != "/etc/systemd/system/"* ]] && [[ "$rel_path" != "/etc/containers/systemd/"* ]] \
&& [[ "$rel_path" != "/etc/tmpfiles.d/"* ]] && [[ "$rel_path" != "/etc/sysctl.d/"* ]]; then
# Skip files & directories that are already part of the CoreOS default installation
continue continue
fi fi
cat <<EOF cat <<EOF

64
nextcloud/Makefile

@ -1,7 +1,14 @@
DEPENDENCIES = postgresql
TOP_LEVEL_DIR := .. TOP_LEVEL_DIR := ..
include $(TOP_LEVEL_DIR)/Makefile.common include $(TOP_LEVEL_DIR)/Makefile.common
.PHONY: test .PHONY: test test-set-nextcloud-major
NEXTCLOUD_MAJOR_START ?= 25
NEXTCLOUD_MAJOR_LAST ?= 31
test-set-nextcloud-major:
sed -i 's/^NEXTCLOUD_MAJOR=.*/NEXTCLOUD_MAJOR=$(NEXTCLOUD_MAJOR_START)/' config/config.env
$(TARGET_CHROOT)/var/lib/quadlets/nextcloud/redis: $(TARGET_CHROOT)/var/lib/quadlets/nextcloud/redis:
install -m 0700 -o 0 -g 0 -d $@ install -m 0700 -o 0 -g 0 -d $@
@ -9,19 +16,22 @@ $(TARGET_CHROOT)/var/lib/quadlets/nextcloud/redis:
$(TARGET_CHROOT)/var/lib/quadlets/nextcloud/data $(TARGET_CHROOT)/var/lib/quadlets/nextcloud/config: $(TARGET_CHROOT)/var/lib/quadlets/nextcloud/data $(TARGET_CHROOT)/var/lib/quadlets/nextcloud/config:
install -m 0700 -o 82 -g 82 -d $@ install -m 0700 -o 82 -g 82 -d $@
install-var: $(TARGET_CHROOT)/var/lib/quadlets/nextcloud/redis $(TARGET_CHROOT)/var/lib/quadlets/nextcloud/data $(TARGET_CHROOT)/var/lib/quadlets/nextcloud/config $(TARGET_CHROOT)/etc/quadlets/nextcloud/www.conf: config/www.conf
install -m 0755 -o 82 -g 82 -D $< $@
# Nextcloud depends on the PostgreSQL quadlets install-var: $(TARGET_CHROOT)/var/lib/quadlets/nextcloud/redis $(TARGET_CHROOT)/var/lib/quadlets/nextcloud/data $(TARGET_CHROOT)/var/lib/quadlets/nextcloud/config
.PHONY: $(TOP_LEVEL_DIR)/postgresql/postgresql.ign
$(TOP_LEVEL_DIR)/postgresql/postgresql.ign:
make -C $(TOP_LEVEL_DIR)/postgresql postgresql.ign
fcos.ign: $(TOP_LEVEL_DIR)/postgresql/postgresql.ign
test: uninstall clean install test: uninstall clean test-set-nextcloud-major install
@run() { echo $$*; "$$@"; }; \ @run() { echo $$*; "$$@"; }; \
echo "Running Nextcloud tests..."; \ echo "Running Nextcloud upgrade test..."; \
set -Eeuo pipefail; \ set -Eeuo pipefail; \
source config/config.env; \ source config/config.env; \
echo "Waiting for Nextcloud to be ready..."; \
until run curl -X GET -sSf -u "$${NEXTCLOUD_ADMIN_USER}:$${NEXTCLOUD_ADMIN_PASSWORD}" "$${OVERWRITECLIURL}/status.php" &> /dev/null; do \
echo "Nextcloud is not ready yet. Retrying in 5 seconds..."; \
sleep 5; \
done; \
echo "Nextcloud is ready!"; \
echo "Uploading file..."; \ echo "Uploading file..."; \
run curl -X PUT -sSf -u "$${NEXTCLOUD_ADMIN_USER}:$${NEXTCLOUD_ADMIN_PASSWORD}" --data-binary @tests/witness.txt "$${OVERWRITECLIURL}/remote.php/webdav/witness.txt"; \ run curl -X PUT -sSf -u "$${NEXTCLOUD_ADMIN_USER}:$${NEXTCLOUD_ADMIN_PASSWORD}" --data-binary @tests/witness.txt "$${OVERWRITECLIURL}/remote.php/webdav/witness.txt"; \
echo "Verifying file upload..."; \ echo "Verifying file upload..."; \
@ -31,5 +41,37 @@ test: uninstall clean install
else \ else \
echo "File upload verification failed!"; \ echo "File upload verification failed!"; \
exit 1; \ exit 1; \
fi fi; \
sleep 2; \
for (( ver=$(NEXTCLOUD_MAJOR_START); ver<$(NEXTCLOUD_MAJOR_LAST); ver++ )); do \
nextver=$$(($$ver + 1)); \
echo "Upgrading Nextcloud from $$ver to $$nextver..."; \
sed -i "s/^NEXTCLOUD_MAJOR=.*/NEXTCLOUD_MAJOR=$$nextver/" /etc/quadlets/nextcloud/config.env; \
systemctl stop nextcloud.target; \
sleep 1; \
systemctl start nextcloud.target; \
echo "Waiting for Nextcloud to be ready..."; \
until run curl -X GET -sSf -u "$${NEXTCLOUD_ADMIN_USER}:$${NEXTCLOUD_ADMIN_PASSWORD}" "$${OVERWRITECLIURL}/status.php" &> /dev/null; do \
echo "Nextcloud is not ready yet. Retrying in 5 seconds..."; \
sleep 5; \
done; \
echo "Nextcloud is ready after upgrade!"; \
echo "Verifying file upload after upgrade..."; \
run curl -X GET -sSf -u "$${NEXTCLOUD_ADMIN_USER}:$${NEXTCLOUD_ADMIN_PASSWORD}" "$${OVERWRITECLIURL}/remote.php/webdav/witness.txt" -o /tmp/witness.txt; \
if run cmp -s tests/witness.txt /tmp/witness.txt ; then \
echo "File upload verified successfully after upgrade!"; \
else \
echo "File upload verification failed after upgrade!"; \
exit 1; \
fi; \
# Assert Nextcloud version after upgrade from status.php \
ACTUAL_VERSION=$$(run curl -X GET -sSf -u "$${NEXTCLOUD_ADMIN_USER}:$${NEXTCLOUD_ADMIN_PASSWORD}" "$${OVERWRITECLIURL}/status.php" | grep -oP '"version":"\K[^"]+'); \
EXPECTED_VERSION_PREFIX="$$nextver."; \
if [[ "$$ACTUAL_VERSION" == "$$EXPECTED_VERSION_PREFIX"* ]]; then \
echo "Nextcloud version $$ACTUAL_VERSION verified successfully after upgrade to $$nextver!"; \
else \
echo "Nextcloud version verification failed after upgrade to $$nextver! Expected prefix: $$EXPECTED_VERSION_PREFIX, Actual: $$ACTUAL_VERSION"; \
exit 1; \
fi; \
done; \
echo "Nextcloud upgrade tests completed successfully."

3
nextcloud/config/config.env

@ -2,6 +2,9 @@
## Nextcloud Configuration Environment Variables ## Nextcloud Configuration Environment Variables
## ##
# Nextcloud version
NEXTCLOUD_MAJOR=31
# Nextcloud domain configuration # Nextcloud domain configuration
NEXTCLOUD_TRUSTED_DOMAINS=localhost NEXTCLOUD_TRUSTED_DOMAINS=localhost
OVERWRITEHOST=localhost OVERWRITEHOST=localhost

4
nextcloud/config/custom-noinit.sh

@ -0,0 +1,4 @@
#!/bin/sh
echo "This container is not intented to perform initialization or upgrade tasks."
exit 1

14
nextcloud/config/custom-post.sh

@ -0,0 +1,14 @@
#!/bin/sh
set -Eeuo pipefail
# Disable maintenance mode
echo "Disabling maintenance mode..."
php occ maintenance:mode --off
# Run database optimizations
echo "Adding missing database indices..."
php occ db:add-missing-indices || true
echo "Converting database columns to big int..."
php occ db:convert-filecache-bigint --no-interaction || true

7
nextcloud/config/custom-pre.sh

@ -0,0 +1,7 @@
#!/bin/sh
set -Eeuo pipefail
# Enable maintenance mode
echo "Enabling maintenance mode..."
php occ maintenance:mode --on || true

0
nextcloud/config/redis-session.ini

9
nextcloud/config/redis.conf

@ -1,3 +1,10 @@
requirepass nextcloud # Network settings
port 6379 port 6379
bind 127.0.0.1 bind 127.0.0.1
# Set a password for Redis
requirepass nextcloud
# Hybrid mode (AOF + RDB)
appendonly yes
aof-use-rdb-preamble yes

22
nextcloud/nextcloud-app.container

@ -1,22 +1,20 @@
[Unit] [Unit]
Description=Nextcloud PHP-FPM Application Description=Nextcloud PHP-FPM Application
Documentation=https://hub.docker.com/_/nextcloud/ Documentation=https://hub.docker.com/_/nextcloud/
After=network.target nextcloud-redis.service postgresql-server.service After=network.target nextcloud-redis.service postgresql-server.service nextcloud-upgrade.service
Requires=nextcloud-redis.service postgresql-server.service Requires=nextcloud-redis.service postgresql-server.service nextcloud-upgrade.service
# Require initialization to complete first
Requires=nextcloud-redis.service
After=nextcloud-redis.service
# Only start if Nextcloud has been configured # Only start if Nextcloud has been configured
ConditionPathExists=/etc/quadlets/nextcloud/config.env ConditionPathExists=/etc/quadlets/nextcloud/config.env
# and initialized (config.php exists)
ConditionPathExists=/var/lib/quadlets/nextcloud/data/config/config.php
# Start/stop this unit when the target is started/stopped # Start/stop this unit when the target is started/stopped
PartOf=nextcloud.target PartOf=nextcloud.target
[Container] [Container]
ContainerName=nextcloud-app ContainerName=nextcloud-app
Image=docker.io/library/nextcloud:31-fpm-alpine Image=docker.io/library/nextcloud:${NEXTCLOUD_MAJOR}-fpm-alpine
# Fix the UID/GID of the PHP-FPM daemon # Fix the UID/GID of the PHP-FPM daemon
User=82:82 User=82:82
@ -30,8 +28,9 @@ EnvironmentFile=/etc/quadlets/nextcloud/config.env
# Volume mounts # Volume mounts
Volume=/var/lib/quadlets/nextcloud/data:/var/www/html:z Volume=/var/lib/quadlets/nextcloud/data:/var/www/html:z
Volume=/var/lib/quadlets/nextcloud/config/www.conf:/usr/local/etc/php-fpm.d/www.conf:Z Volume=/etc/quadlets/nextcloud/www.conf:/usr/local/etc/php-fpm.d/www.conf:Z
Volume=/var/lib/quadlets/nextcloud/config/redis-session.ini:/usr/local/etc/php/conf.d/redis-session.ini:Z Volume=/run/quadlets/nextcloud/redis-session.ini:/usr/local/etc/php/conf.d/redis-session.ini:Z
Volume=/etc/quadlets/nextcloud/custom-noinit.sh:/docker-entrypoint-hooks.d/pre-installation/custom.sh:z,ro
# Health check (equivalent to readiness probe) # Health check (equivalent to readiness probe)
HealthCmd=nc -z localhost 9000 HealthCmd=nc -z localhost 9000
@ -46,9 +45,8 @@ RestartSec=10
TimeoutStartSec=600 TimeoutStartSec=600
TimeoutStopSec=30 TimeoutStopSec=30
# Skaffold filesystem + fix permissions # These environment variables are sourced to be used by systemd in the Exec* commands
ExecStartPre=/bin/bash -Eeuo pipefail -c 'install -m 0700 -o 82 -g 82 /etc/quadlets/nextcloud/www.conf /var/lib/quadlets/nextcloud/config/www.conf ; \ EnvironmentFile=/etc/quadlets/nextcloud/config.env
install -m 0700 -o 82 -g 82 /etc/quadlets/nextcloud/redis-session.ini /var/lib/quadlets/nextcloud/config/redis-session.ini'
# Wait for PostgreSQL to be ready on localhost # Wait for PostgreSQL to be ready on localhost
ExecStartPre=/bin/sh -c 'exec 2>/dev/null; for try in $(seq 0 12); do if ! /bin/true 5<> /dev/tcp/127.0.0.1/5432; then echo "Waiting for PostgreSQL to be available..."; sleep 5; else exit 0; fi; done; exit 1' ExecStartPre=/bin/sh -c 'exec 2>/dev/null; for try in $(seq 0 12); do if ! /bin/true 5<> /dev/tcp/127.0.0.1/5432; then echo "Waiting for PostgreSQL to be available..."; sleep 5; else exit 0; fi; done; exit 1'

51
nextcloud/nextcloud-cron.container

@ -0,0 +1,51 @@
[Unit]
Description=Nextcloud Application - Cron Job
Documentation=https://hub.docker.com/_/nextcloud/
After=nextcloud-redis.service postgresql-server.service
Requires=nextcloud-redis.service postgresql-server.service
# Only start if Nextcloud has been configured
ConditionPathExists=/etc/quadlets/nextcloud/config.env
# and initialized (config.php exists)
ConditionPathExists=/var/lib/quadlets/nextcloud/data/config/config.php
[Container]
ContainerName=nextcloud-cron-job
Image=docker.io/library/nextcloud:${NEXTCLOUD_MAJOR}-fpm-alpine
# Fix the UID/GID of the PHP-FPM daemon
User=82:82
# Network configuration
Network=host
# Environment variables from config
EnvironmentFile=/etc/quadlets/nextcloud/config.env
# This is specific to the cron container
Entrypoint=php
Exec=-f /var/www/html/cron.php
# Volume mounts
Volume=/var/lib/quadlets/nextcloud/data:/var/www/html:z
Volume=/etc/quadlets/nextcloud/www.conf:/usr/local/etc/php-fpm.d/www.conf:Z
Volume=/run/quadlets/nextcloud/redis-session.ini:/usr/local/etc/php/conf.d/redis-session.ini:Z
[Service]
Restart=no
TimeoutStartSec=600
# These environment variables are sourced to be used by systemd in the Exec* commands
EnvironmentFile=/etc/quadlets/nextcloud/config.env
# This container is a job - run once to completion
Type=oneshot
# Wait for PostgreSQL to be ready
ExecStartPre=/bin/sh -c 'exec 2>/dev/null; for try in $(seq 0 12); do if ! /bin/true 5<> /dev/tcp/127.0.0.1/5432; then echo "Waiting for PostgreSQL to be available..."; sleep 5; else exit 0; fi; done; exit 1'
# Wait for Redis to be ready
ExecStartPre=/bin/sh -c 'exec 2>/dev/null; for try in $(seq 0 12); do if ! /bin/true 5<> /dev/tcp/127.0.0.1/6379; then echo "Waiting for Redis to be available..."; sleep 5; else exit 0; fi; done; exit 1'
[Install]
WantedBy=nextcloud-cron.timer

12
nextcloud/nextcloud-cron.timer

@ -0,0 +1,12 @@
[Unit]
Description=Nextcloud Application - Initialization
Documentation=https://hub.docker.com/_/nextcloud/
PartOf=nextcloud.target
[Timer]
OnActiveSec=15min
RandomizedDelaySec=15s
DeferReactivation=true
[Install]
WantedBy=nextcloud.target

55
nextcloud/nextcloud-init.container

@ -0,0 +1,55 @@
[Unit]
Description=Nextcloud Application - Initialization
Documentation=https://hub.docker.com/_/nextcloud/
After=network.target nextcloud-redis.service postgresql-server.service
Before=nextcloud-app.service
Requires=nextcloud-redis.service postgresql-server.service
# Only start if Nextcloud has been configured
ConditionPathExists=/etc/quadlets/nextcloud/config.env
# and NOT initialized (config.php does NOT exist)
ConditionPathExists=!/var/lib/quadlets/nextcloud/data/config/config.php
# Start/stop this unit when the target is started/stopped
#PartOf=nextcloud.target
[Container]
ContainerName=nextcloud-init-job
Image=docker.io/library/nextcloud:${NEXTCLOUD_MAJOR}-fpm-alpine
# Fix the UID/GID of the PHP-FPM daemon
User=82:82
# Network configuration
Network=host
# Environment variables from config
EnvironmentFile=/etc/quadlets/nextcloud/config.env
# This is specific to the initialization container
Environment=NEXTCLOUD_UPDATE=1
Exec=/bin/true
# Volume mounts
Volume=/var/lib/quadlets/nextcloud/data:/var/www/html:z
Volume=/etc/quadlets/nextcloud/www.conf:/usr/local/etc/php-fpm.d/www.conf:Z
Volume=/run/quadlets/nextcloud/redis-session.ini:/usr/local/etc/php/conf.d/redis-session.ini:Z
[Service]
Restart=no
TimeoutStartSec=600
# These environment variables are sourced to be used by systemd in the Exec* commands
EnvironmentFile=/etc/quadlets/nextcloud/config.env
# This container is a job - run once to completion
Type=oneshot
# Wait for PostgreSQL to be ready
ExecStartPre=/bin/sh -c 'exec 2>/dev/null; for try in $(seq 0 12); do if ! /bin/true 5<> /dev/tcp/127.0.0.1/5432; then echo "Waiting for PostgreSQL to be available..."; sleep 5; else exit 0; fi; done; exit 1'
# Wait for Redis to be ready
ExecStartPre=/bin/sh -c 'exec 2>/dev/null; for try in $(seq 0 12); do if ! /bin/true 5<> /dev/tcp/127.0.0.1/6379; then echo "Waiting for Redis to be available..."; sleep 5; else exit 0; fi; done; exit 1'
[Install]
WantedBy=nextcloud.target

2
nextcloud/nextcloud-nginx.container

@ -29,7 +29,7 @@ Volume=/etc/quadlets/nextcloud/nginx.conf:/etc/nginx/nginx.conf:ro
HealthCmd=curl -sSfL http://localhost/status.php HealthCmd=curl -sSfL http://localhost/status.php
HealthInterval=30s HealthInterval=30s
HealthTimeout=10s HealthTimeout=10s
HealthStartPeriod=30s HealthStartPeriod=10s
HealthRetries=3 HealthRetries=3
[Service] [Service]

7
nextcloud/nextcloud-redis.container

@ -1,6 +1,6 @@
[Unit] [Unit]
Description=Redis Cache for Nextcloud Description=Redis Cache for Nextcloud
Documentation=https://redis.io/ Documentation=https://hub.docker.com/_/redis/
After=network.target After=network.target
# Only start if Nextcloud has been configured # Only start if Nextcloud has been configured
@ -27,7 +27,7 @@ Volume=/var/lib/quadlets/nextcloud/redis:/data:Z
Volume=/etc/quadlets/nextcloud/redis.conf:/usr/local/etc/redis/redis.conf:ro Volume=/etc/quadlets/nextcloud/redis.conf:/usr/local/etc/redis/redis.conf:ro
# Health check # Health check
HealthCmd=redis-cli ping -t 5 | grep -q PONG HealthCmd=redis-cli -t 5 ping | grep -qFx PONG
HealthInterval=30s HealthInterval=30s
HealthTimeout=5s HealthTimeout=5s
HealthStartPeriod=10s HealthStartPeriod=10s
@ -39,5 +39,8 @@ RestartSec=5
TimeoutStartSec=300 TimeoutStartSec=300
TimeoutStopSec=30 TimeoutStopSec=30
# These environment variables are sourced to be used by systemd in the Exec* commands
EnvironmentFile=/etc/quadlets/nextcloud/config.env
[Install] [Install]
WantedBy=nextcloud.target WantedBy=nextcloud.target

57
nextcloud/nextcloud-upgrade.container

@ -0,0 +1,57 @@
[Unit]
Description=Nextcloud Application - Upgrade
Documentation=https://hub.docker.com/_/nextcloud/
After=network.target nextcloud-redis.service postgresql-server.service
Before=nextcloud-app.service
Requires=nextcloud-redis.service postgresql-server.service
# Only start if Nextcloud has been configured
ConditionPathExists=/etc/quadlets/nextcloud/config.env
# and initialized (config.php exists)
ConditionPathExists=/var/lib/quadlets/nextcloud/data/config/config.php
# Start/stop this unit when the target is started/stopped
PartOf=nextcloud.target
[Container]
ContainerName=nextcloud-upgrade-to-${NEXTCLOUD_MAJOR}-job
Image=docker.io/library/nextcloud:${NEXTCLOUD_MAJOR}-fpm-alpine
# Fix the UID/GID of the PHP-FPM daemon
User=82:82
# Network configuration
Network=host
# Environment variables from config
EnvironmentFile=/etc/quadlets/nextcloud/config.env
# This is specific to the upgrade container
Environment=NEXTCLOUD_UPDATE=1
Exec=/bin/true
Volume=/etc/quadlets/nextcloud/custom-pre.sh:/docker-entrypoint-hooks.d/pre-upgrade/custom.sh:z,ro
Volume=/etc/quadlets/nextcloud/custom-post.sh:/docker-entrypoint-hooks.d/post-upgrade/custom.sh:z,ro
# Volume mounts
Volume=/var/lib/quadlets/nextcloud/data:/var/www/html:z
Volume=/etc/quadlets/nextcloud/www.conf:/usr/local/etc/php-fpm.d/www.conf:Z
Volume=/run/quadlets/nextcloud/redis-session.ini:/usr/local/etc/php/conf.d/redis-session.ini:Z
[Service]
Restart=no
TimeoutStartSec=600
# These environment variables are sourced to be used by systemd in the Exec* commands
EnvironmentFile=/etc/quadlets/nextcloud/config.env
# This container is a job - run once to completion
Type=oneshot
# Wait for PostgreSQL to be ready
ExecStartPre=/bin/sh -c 'exec 2>/dev/null; for try in $(seq 0 12); do if ! /bin/true 5<> /dev/tcp/127.0.0.1/5432; then echo "Waiting for PostgreSQL to be available..."; sleep 5; else exit 0; fi; done; exit 1'
# Wait for Redis to be ready
ExecStartPre=/bin/sh -c 'exec 2>/dev/null; for try in $(seq 0 12); do if ! /bin/true 5<> /dev/tcp/127.0.0.1/6379; then echo "Waiting for Redis to be available..."; sleep 5; else exit 0; fi; done; exit 1'
[Install]
WantedBy=nextcloud.target

5
nextcloud/nextcloud.target

@ -1,8 +1,9 @@
[Unit] [Unit]
Description=Nextcloud Service Target Description=Nextcloud Service Target
Documentation=man:systemd.target(5) Documentation=man:systemd.target(5)
Requires=postgresql.target nextcloud-redis.service nextcloud-app.service nextcloud-nginx.service Requires=postgresql.target nextcloud-redis.service nextcloud-nginx.service nextcloud-app.service nextcloud-upgrade.service nextcloud-cron.timer
After=postgresql.target nextcloud-redis.service nextcloud-app.service nextcloud-nginx.service After=postgresql.target nextcloud-redis.service nextcloud-nginx.service nextcloud-app.service nextcloud-upgrade.service
Before=nextcloud-cron.timer
# Allow isolation - can stop/start this target independently # Allow isolation - can stop/start this target independently
AllowIsolate=yes AllowIsolate=yes

3
nextcloud/sysctl.d/nextcloud.conf

@ -0,0 +1,3 @@
# Redis recommended settings for stability
# See https://redis.io/docs/latest/develop/get-started/faq/#background-saving-fails-with-a-fork-error-on-linux
#vm.overcommit_memory=1

2
nextcloud/tmpfiles.d/nextcloud.conf

@ -0,0 +1,2 @@
d$ /run/quadlets/nextcloud 0700 82 82 -
f+$ /run/quadlets/nextcloud/redis-session.ini 0600 82 82 -

6
postgresql/Makefile

@ -1,17 +1,17 @@
TOP_LEVEL_DIR := .. TOP_LEVEL_DIR := ..
include $(TOP_LEVEL_DIR)/Makefile.common include $(TOP_LEVEL_DIR)/Makefile.common
.PHONY: test test-set-pgmajor .PHONY: test test-set-pgmajor install-var
PG_MAJOR_START ?= 14 PG_MAJOR_START ?= 14
PG_MAJOR_LAST ?= 18 PG_MAJOR_LAST ?= 18
test-set-pgmajor: test-set-pgmajor:
sed -i 's/^PG_MAJOR=.*/PG_MAJOR=$(PG_MAJOR_START)/' config/config.env sed -i 's/^PG_MAJOR=.*/PG_MAJOR=$(PG_MAJOR_START)/' config/config.env
$(TARGET_CHROOT)/var/lib/quadlets/postgresql/backup $(TARGET_CHROOT)/var/lib/quadlets/postgresql $(TARGET_CHROOT)/var/run/quadlets/postgresql: $(TARGET_CHROOT)/var/lib/quadlets/postgresql/backup $(TARGET_CHROOT)/var/lib/quadlets/postgresql:
install -m 0700 -o 70 -g 70 -d $@ install -m 0700 -o 70 -g 70 -d $@
install-var: $(TARGET_CHROOT)/var/run/quadlets/postgresql $(TARGET_CHROOT)/var/lib/quadlets/postgresql $(TARGET_CHROOT)/var/lib/quadlets/postgresql/backup install-var: $(TARGET_CHROOT)/var/lib/quadlets/postgresql/backup
test: uninstall clean test-set-pgmajor install test: uninstall clean test-set-pgmajor install
@echo "Running PostgreSQL integration tests..."; \ @echo "Running PostgreSQL integration tests..."; \

4
postgresql/postgresql-backup.container

@ -27,8 +27,8 @@ User=postgres
Volume=/var/lib/quadlets/postgresql:/var/lib/postgresql:z Volume=/var/lib/quadlets/postgresql:/var/lib/postgresql:z
Volume=/etc/quadlets/postgresql/backup.sh:/usr/local/bin/backup.sh:z,ro Volume=/etc/quadlets/postgresql/backup.sh:/usr/local/bin/backup.sh:z,ro
# Share /var/run/postgresql/ between containers in the pod for the Unix socket # Share /run/postgresql/ between containers in the pod for the Unix socket
Volume=/var/run/quadlets/postgresql:/var/run/postgresql:z Volume=/run/quadlets/postgresql:/var/run/postgresql:z
[Service] [Service]
Restart=no Restart=no

11
postgresql/postgresql-backup.timer

@ -0,0 +1,11 @@
[Unit]
Description=PostgreSQL Database Backup Timer
Documentation=https://hub.docker.com/_/postgresql/
PartOf=postgresql.target
[Timer]
OnCalendar=daily
RandomizedDelaySec=15min
[Install]
WantedBy=postgresql.target

7
postgresql/postgresql-server.container

@ -47,8 +47,8 @@ HealthTimeout=10s
HealthStartPeriod=60s HealthStartPeriod=60s
HealthRetries=3 HealthRetries=3
# Share /var/run/postgresql/ between containers in the pod for the Unix socket # Share /run/postgresql/ between containers in the pod for the Unix socket
Volume=/var/run/quadlets/postgresql:/var/run/postgresql:z Volume=/run/quadlets/postgresql:/var/run/postgresql:z
[Service] [Service]
Restart=always Restart=always
@ -59,8 +59,5 @@ TimeoutStopSec=30
# These environment variables are sourced to be used by systemd in the Exec* commands # These environment variables are sourced to be used by systemd in the Exec* commands
EnvironmentFile=/etc/quadlets/postgresql/config.env EnvironmentFile=/etc/quadlets/postgresql/config.env
# Skaffold filesystem + fix permissions
ExecStartPre=install -m 0700 -o 70 -g 70 -d /var/run/quadlets/postgresql
[Install] [Install]
WantedBy=postgresql.target WantedBy=postgresql.target

3
postgresql/postgresql.target

@ -1,8 +1,9 @@
[Unit] [Unit]
Description=PostgreSQL Service Target Description=PostgreSQL Service Target
Documentation=man:systemd.target(5) Documentation=man:systemd.target(5)
Requires=postgresql-server.service postgresql-upgrade.service postgresql-init.service postgresql-set-major.service Requires=postgresql-server.service postgresql-upgrade.service postgresql-init.service postgresql-set-major.service postgresql-backup.timer
After=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
Before=postgresql-backup.timer
# Allow isolation - can stop/start this target independently # Allow isolation - can stop/start this target independently
AllowIsolate=yes AllowIsolate=yes

3
postgresql/sysctl.d/postgresql.conf

@ -0,0 +1,3 @@
# PostgreSQL recommended settings for stability
#vm.overcommit_memory=2
#vm.overcommit_ratio=80

1
postgresql/tmpfiles.d/postgresql.conf

@ -0,0 +1 @@
d$ /run/quadlets/postgresql 0700 70 70 -
Loading…
Cancel
Save