From 80864f1c886fa36e6aafa07d39ad2226256a47a0 Mon Sep 17 00:00:00 2001 From: Simon Waldburger Date: Thu, 9 Oct 2025 19:21:20 +0200 Subject: [PATCH] Init Commit --- Dockerfile | 46 +++++++++++++++ build/entrypoint.sh | 127 +++++++++++++++++++++++++++++++++++++++++ build/pdns.conf.tpl | 3 + build/pdns.preferences | 3 + build/pdns.sources | 5 ++ build/postgres.sources | 5 ++ 6 files changed, 189 insertions(+) create mode 100644 Dockerfile create mode 100644 build/entrypoint.sh create mode 100644 build/pdns.conf.tpl create mode 100644 build/pdns.preferences create mode 100644 build/pdns.sources create mode 100644 build/postgres.sources diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a0861f3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,46 @@ +FROM debian:trixie-slim + +LABEL maintainer="Simon M. Waldburger " +LABEL last_changed="2025-10-09" + +RUN apt-get update && \ + apt-get -y upgrade && \ + apt-get install -y curl ca-certificates locales && \ + localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +ADD https://www.postgresql.org/media/keys/ACCC4CF8.asc /etc/apt/keyrings/postgres-pub.asc +ADD build/postgres.source /etc/apt/sources.list.d/postgres.source +ADD https://repo.powerdns.com/FD380FBB-pub.asc /etc/apt/keyrings/powerdns-pub.asc +ADD build/pdns.sources /etc/apt/sources.list.d/pdns.sources +ADD build/pdns.preferences /etc/apt/preferences.d/pdns + +RUN chmod 644 /etc/apt/keyrings/powerdns-pub.asc && \ + apt-get update && \ + echo "path-include /usr/share/doc/*/*.sql" >> /etc/dpkg/dpkg.cfg.d/docker && \ + DEBIAN_FRONTEND=noninteractive apt-get install -q -y pdns-server pdns-backend-pgsql postgresql-client-18 && \ + rm /etc/powerdns/pdns.d/*.conf && rm /etc/powerdns/*.conf && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +USER root +RUN mkdir -p /app +COPY build/entrypoint.sh /app/entrypoint.sh +COPY build/pdns.conf.tpl /app/pdns.conf.tpl +RUN chmod 755 /app/entrypoint.sh /app/wait-for-it.sh +RUN chown -R pdns: /app + +ENV VERSION=4.9 \ + PDNS_guardian=yes \ + PDNS_setuid=pdns \ + PDNS_setgid=pdns \ + PDNS_launch=gpgsql + +EXPOSE 8081 53 53/udp + +HEALTHCHECK --interval=10s --timeout=10s --retries=3 --start-period=2s CMD ["pdns_control", "ping"] + +ENTRYPOINT [ "/docker-entrypoint.sh" ] + +CMD [ "/usr/sbin/pdns_server" ] \ No newline at end of file diff --git a/build/entrypoint.sh b/build/entrypoint.sh new file mode 100644 index 0000000..d7dfecc --- /dev/null +++ b/build/entrypoint.sh @@ -0,0 +1,127 @@ +#!/bin/sh + +set -eu + +: "${DEBUG:=0}" + +if [ "${DEBUG}" -eq 1 ]; then + set -x +fi + +##### Function definitions #### + +derivePostgreSQLSettingsFromExistingConfigFile() { + if [ ! -f /etc/pdns/pdns.conf ]; then + echo "Use of existing file /etc/pdns/pdns.conf requested but file does not exist!" + exit 1 + fi + + PDNS_gpgsql_host=$(sed -n 's/^gpgsql-host=\(.*\)/\1/p' < /etc/pdns/pdns.conf) + PDNS_gpgsql_port=$(sed -n 's/^gpgsql-port=\(.*\)/\1/p' < /etc/pdns/pdns.conf) + PDNS_gpgsql_user=$(sed -n 's/^gpgsql-user=\(.*\)/\1/p' < /etc/pdns/pdns.conf) + PDNS_gpgsql_password=$(sed -n 's/^gpgsql-password=\(.*\)/\1/p' < /etc/pdns/pdns.conf) + PDNS_gpgsql_dbname=$(sed -n 's/^gpgsql-dbname=\(.*\)/\1/p' < /etc/pdns/pdns.conf) +} + +derivePostgreSQLSettingsFromEnvironment() { + # Configure gpgsql env vars + : "${PDNS_gpgsql_host:=pgsql}" + : "${PDNS_gpgsql_port:=5432}" + : "${PDNS_gpgsql_user:=${PGSQL_ENV_POSTGRES_USER:-postgres}}" + : "${PDNS_gpgsql_password:=${PGSQL_ENV_POSTGRES_PASSWORD:-powerdns}}" + : "${PDNS_gpgsql_dbname:=${PGSQL_ENV_POSTGRES_DB:-powerdns}}" + + # Use first part of node name as database name suffix + if [ "${NODE_NAME:-}" ]; then + NODE_NAME=$(echo "${NODE_NAME}" | sed -e 's/\..*//' -e 's/-//') + PDNS_gpgsql_dbname="${PDNS_gpgsql_dbname}${NODE_NAME}" + fi + + export PDNS_gpgsql_host PDNS_gpgsql_port PDNS_gpgsql_user PDNS_gpgsql_password PDNS_gpgsql_dbname +} + +generatePostgreSQLCommand() { + PGSQL_COMMAND="psql -h ${PDNS_gpgsql_host} -p ${PDNS_gpgsql_port} -U ${PDNS_gpgsql_user}" +} + +createDatabaseIfRequested() { + # Initialize DB if needed + if [ "${SKIP_DB_CREATE:-false}" != 'true' ]; then + echo "SELECT 'CREATE DATABASE ${PDNS_gpgsql_dbname}' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '${PDNS_gpgsql_dbname}')\gexec" | $PGSQL_COMMAND + fi +} + +initDatabase() { + if [ "${SKIP_DB_INIT:-false}" != 'true' ]; then + PGSQL_CHECK_IF_HAS_TABLE="SELECT COUNT(DISTINCT table_name) FROM information_schema.columns WHERE table_catalog = '${PDNS_gpgsql_dbname}' AND table_schema = 'public';" + PGSQL_NUM_TABLE=$($PGSQL_COMMAND -At -d "$PDNS_gpgsql_dbname" -c "$PGSQL_CHECK_IF_HAS_TABLE") + if [ "$PGSQL_NUM_TABLE" -eq 0 ]; then + echo "Database exists and has no tables yet, doing init"; + $PGSQL_COMMAND -d "$PDNS_gpgsql_dbname" < /usr/share/doc/pdns/schema.pgsql.sql + else + echo "Database exists but already has tables, will not try to init"; + fi + fi +} + +initSuperslave() { + if [ "${PDNS_autosecondary:-no}" = 'yes' ] || [ "${PDNS_superslave:-no}" = 'yes' ]; then + # Configure supermasters if needed + if [ "${SUPERMASTER_IPS:-}" ]; then + $PGSQL_COMMAND -d "$PDNS_gpgsql_dbname" -c 'TRUNCATE supermasters;' + PGSQL_INSERT_SUPERMASTERS='' + if [ "${SUPERMASTER_COUNT:-0}" -eq 0 ]; then + SUPERMASTER_COUNT=10 + fi + i=1; while [ $i -le "${SUPERMASTER_COUNT}" ]; do + SUPERMASTER_HOST=$(echo "${SUPERMASTER_HOSTS:-}" | awk -v col="$i" '{ print $col }') + SUPERMASTER_IP=$(echo "${SUPERMASTER_IPS}" | awk -v col="$i" '{ print $col }') + if [ -z "${SUPERMASTER_HOST:-}" ]; then + SUPERMASTER_HOST=$(hostname -f) + fi + if [ "${SUPERMASTER_IP:-}" ]; then + PGSQL_INSERT_SUPERMASTERS="${PGSQL_INSERT_SUPERMASTERS} INSERT INTO supermasters VALUES('${SUPERMASTER_IP}', '${SUPERMASTER_HOST}', 'admin');" + fi + i=$(( i + 1 )) + done + $PGSQL_COMMAND -d "$PDNS_gpgsql_dbname" -c "$PGSQL_INSERT_SUPERMASTERS" + fi + fi +} + +generateAndInstallConfigFileFromEnvironment() { + # Create config file from template + subvars --prefix 'PDNS_' < '/app/pdns.conf.tpl' > '/etc/pdns/pdns.conf' +} + +#### End of function definitions, let's get to work ... + +if [ "${USE_EXISTING_CONFIG_FILE:-false}" = 'true' ]; then + derivePostgreSQLSettingsFromExistingConfigFile +else + derivePostgreSQLSettingsFromEnvironment +fi + +generatePostgreSQLCommand + +PGPASSWORD="${PDNS_gpgsql_password}" +export PGPASSWORD + +# Wait for pgsql to respond +until $PGSQL_COMMAND -c ';' ; do + >&2 echo 'Pgsql is unavailable - sleeping' + sleep 3 +done + +createDatabaseIfRequested +initDatabase +initSuperslave + +if [ "${USE_EXISTING_CONFIG_FILE:-false}" = 'false' ]; then + echo "(re-)generating config file from environment variables" + generateAndInstallConfigFileFromEnvironment +fi + +unset PGPASSWORD + +exec "$@" \ No newline at end of file diff --git a/build/pdns.conf.tpl b/build/pdns.conf.tpl new file mode 100644 index 0000000..eecfd0a --- /dev/null +++ b/build/pdns.conf.tpl @@ -0,0 +1,3 @@ +{{ range $key, $value := match "PDNS_" -}} +{{- $key | trimPrefix "PDNS_" | replace "_" "-" }} = {{ $value }} +{{ end -}} \ No newline at end of file diff --git a/build/pdns.preferences b/build/pdns.preferences new file mode 100644 index 0000000..675b8a1 --- /dev/null +++ b/build/pdns.preferences @@ -0,0 +1,3 @@ +Package: pdns-* +Pin: origin repo.powerdns.com +Pin-Priority: 600 \ No newline at end of file diff --git a/build/pdns.sources b/build/pdns.sources new file mode 100644 index 0000000..75ffd7e --- /dev/null +++ b/build/pdns.sources @@ -0,0 +1,5 @@ +Types: deb +URIs: https://repo.powerdns.com/debian/ +Suites: trixie-auth-50 +Components: main +Signed-By: /etc/apt/keyrings/powerdns-pub.asc \ No newline at end of file diff --git a/build/postgres.sources b/build/postgres.sources new file mode 100644 index 0000000..b31e82e --- /dev/null +++ b/build/postgres.sources @@ -0,0 +1,5 @@ +Types: deb +URIs: https://apt.postgresql.org/pub/repos/apt +Suites: trixie-pgdg +Components: main +Signed-By: /etc/apt/keyrings/postgres-pub.asc \ No newline at end of file