diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e2878c7..b1e29ac 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,6 +4,10 @@ updates: directory: "/pdns-mysql" schedule: interval: "monthly" + - package-ecosystem: "docker" + directory: "/pdns-pgsql" + schedule: + interval: "monthly" - package-ecosystem: "docker" directory: "/pdns-recursor" schedule: diff --git a/.github/workflows/docker-image-pr.yml b/.github/workflows/docker-image-pr.yml index 7e7777f..ece0515 100644 --- a/.github/workflows/docker-image-pr.yml +++ b/.github/workflows/docker-image-pr.yml @@ -86,6 +86,46 @@ jobs: - name: Image digest run: echo ${{ steps.docker_build_pdns_mysql_alpine.outputs.digest }} + test-pdns-pgsql-latest: + runs-on: ubuntu-latest + steps: + - name: Check Out Repo + uses: actions/checkout@v4 + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v3 + - name: Build PDNS pgsql latest + id: docker_build_pdns_pgsql_latest + uses: docker/build-push-action@v5 + with: + context: ./pdns-pgsql + file: ./pdns-pgsql/Dockerfile + builder: ${{ steps.buildx.outputs.name }} + push: false + tags: pdns-pgsql:latest + - name: Image digest + run: echo ${{ steps.docker_build_pdns_pgsql_latest.outputs.digest }} + + test-pdns-pgsql-alpine: + runs-on: ubuntu-latest + steps: + - name: Check Out Repo + uses: actions/checkout@v4 + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v3 + - name: Build PDNS pgsql alpine + id: docker_build_pdns_pgsql_alpine + uses: docker/build-push-action@v5 + with: + context: ./pdns-pgsql + file: ./pdns-pgsql/Dockerfile.alpine + builder: ${{ steps.buildx.outputs.name }} + push: false + tags: pdns-pgsql:alpine + - name: Image digest + run: echo ${{ steps.docker_build_pdns_pgsql_alpine.outputs.digest }} + test-pdns-admin: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/docker-image-tag-pdns-admin.yml b/.github/workflows/docker-image-tag-pdns-admin.yml new file mode 100644 index 0000000..122599c --- /dev/null +++ b/.github/workflows/docker-image-tag-pdns-admin.yml @@ -0,0 +1,48 @@ +name: Docker Image CI pdns-admin + +on: + push: + tags: + - 'pdns-admin-*' + +jobs: + + build: + + runs-on: ubuntu-latest + + steps: + + - name: Check Out Repo + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + + - name: Set output + id: vars + run: echo ::set-output name=version::${GITHUB_REF##*-} + + - name: Build and push PDNS Admin + id: docker_build_pdns_admin + uses: docker/build-push-action@v5 + with: + context: ./pdns-admin + file: ./pdns-admin/Dockerfile + platforms: linux/amd64,linux/arm64 + builder: ${{ steps.buildx.outputs.name }} + push: true + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/pdns-admin:${{ steps.vars.outputs.version }} + + - name: Image digest + run: echo ${{ steps.docker_build_pdns_admin.outputs.digest }} diff --git a/.github/workflows/docker-image-tag-pdns-mysql-alpine.yml b/.github/workflows/docker-image-tag-pdns-mysql-alpine.yml index 9524788..53f11bf 100644 --- a/.github/workflows/docker-image-tag-pdns-mysql-alpine.yml +++ b/.github/workflows/docker-image-tag-pdns-mysql-alpine.yml @@ -3,7 +3,7 @@ name: Docker Image CI pdns-mysql alpine on: push: tags: - - 'pdns-mysql-alpine-*' + - 'pdns-alpine-*' jobs: diff --git a/.github/workflows/docker-image-tag-pdns-mysql-fedora.yml b/.github/workflows/docker-image-tag-pdns-mysql-fedora.yml index 1ab7d21..6ac2ea8 100644 --- a/.github/workflows/docker-image-tag-pdns-mysql-fedora.yml +++ b/.github/workflows/docker-image-tag-pdns-mysql-fedora.yml @@ -3,7 +3,7 @@ name: Docker Image CI pdns-mysql fedora on: push: tags: - - 'pdns-mysql-fedora-*' + - 'pdns-fedora-*' jobs: diff --git a/.github/workflows/docker-image-tag-pdns-pgsql-alpine.yml b/.github/workflows/docker-image-tag-pdns-pgsql-alpine.yml new file mode 100644 index 0000000..2551a9a --- /dev/null +++ b/.github/workflows/docker-image-tag-pdns-pgsql-alpine.yml @@ -0,0 +1,48 @@ +name: Docker Image CI pdns-pgsql alpine + +on: + push: + tags: + - 'pdns-alpine-*' + +jobs: + + build: + + runs-on: ubuntu-latest + + steps: + + - name: Check Out Repo + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + + - name: Set output + id: vars + run: echo ::set-output name=version::${GITHUB_REF##*-} + + - name: Build and push PDNS pgsql + id: docker_build_pdns + uses: docker/build-push-action@v5 + with: + context: ./pdns-pgsql + file: ./pdns-pgsql/Dockerfile.alpine + platforms: linux/amd64,linux/arm64 + builder: ${{ steps.buildx.outputs.name }} + push: true + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/pdns-pgsql:${{ steps.vars.outputs.version }}-alpine + + - name: Image digest + run: echo ${{ steps.docker_build_pdns.outputs.digest }} diff --git a/.github/workflows/docker-image-tag-pdns-pgsql-fedora.yml b/.github/workflows/docker-image-tag-pdns-pgsql-fedora.yml new file mode 100644 index 0000000..b3bb264 --- /dev/null +++ b/.github/workflows/docker-image-tag-pdns-pgsql-fedora.yml @@ -0,0 +1,48 @@ +name: Docker Image CI pdns-pgsql fedora + +on: + push: + tags: + - 'pdns-fedora-*' + +jobs: + + build: + + runs-on: ubuntu-latest + + steps: + + - name: Check Out Repo + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + + - name: Set output + id: vars + run: echo ::set-output name=version::${GITHUB_REF##*-} + + - name: Build and push PDNS pgsql + id: docker_build_pdns + uses: docker/build-push-action@v5 + with: + context: ./pdns-pgsql + file: ./pdns-pgsql/Dockerfile + platforms: linux/amd64,linux/arm64 + builder: ${{ steps.buildx.outputs.name }} + push: true + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/pdns-pgsql:${{ steps.vars.outputs.version }} + + - name: Image digest + run: echo ${{ steps.docker_build_pdns.outputs.digest }} diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index de4d62d..45bc1f8 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -118,6 +118,62 @@ jobs: - name: Image digest run: echo ${{ steps.docker_build_pdns_mysql_alpine.outputs.digest }} + build-pdns-pgsql-latest: + runs-on: ubuntu-latest + steps: + - name: Check Out Repo + uses: actions/checkout@v4 + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v3 + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + - name: Build and push PDNS pgsql latest + id: docker_build_pdns_pgsql_latest + uses: docker/build-push-action@v5 + with: + context: ./pdns-pgsql + file: ./pdns-pgsql/Dockerfile + platforms: linux/amd64,linux/arm64 + builder: ${{ steps.buildx.outputs.name }} + push: true + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/pdns-pgsql:latest + - name: Image digest + run: echo ${{ steps.docker_build_pdns_pgsql_latest.outputs.digest }} + + build-pdns-pgsql-alpine: + runs-on: ubuntu-latest + steps: + - name: Check Out Repo + uses: actions/checkout@v4 + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v3 + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + - name: Build and push PDNS pgsql alpine + id: docker_build_pdns_pgsql_alpine + uses: docker/build-push-action@v5 + with: + context: ./pdns-pgsql + file: ./pdns-pgsql/Dockerfile.alpine + platforms: linux/amd64,linux/arm64 + builder: ${{ steps.buildx.outputs.name }} + push: true + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/pdns-pgsql:alpine + - name: Image digest + run: echo ${{ steps.docker_build_pdns_pgsql_alpine.outputs.digest }} + build-pdns-admin: runs-on: ubuntu-latest steps: diff --git a/README.md b/README.md index eb0c0c3..af04ddd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # PowerDNS Docker Images -This repository contains the following Docker images - pdns-mysql, pdns-recursor and pdns-admin. Image **pdns-mysql** contains completely configurable [PowerDNS 4.x server](https://www.powerdns.com/) with mysql backend (without mysql server). Image **pdns-recursor** contains completely configurable [PowerDNS 4.x recursor](https://www.powerdns.com/). Image **pdns-admin** contains fronted (Caddy) and backend (uWSGI) for the [PowerDNS Admin](https://github.com/PowerDNS-Admin/PowerDNS-Admin) web app, which is written in Flask and used for managing PowerDNS servers. +This repository contains the following Docker images - pdns-mysql, pdns-pgsql, pdns-recursor and pdns-admin. Image **pdns-mysql** contains completely configurable [PowerDNS 4.x server](https://www.powerdns.com/) with mysql backend (without mysql server). Image **pdns-pgsql** contains completely configurable [PowerDNS 4.x server](https://www.powerdns.com/) with postgres backend (without postgres server). Image **pdns-recursor** contains completely configurable [PowerDNS 4.x recursor](https://www.powerdns.com/). Image **pdns-admin** contains fronted (Caddy) and backend (uWSGI) for the [PowerDNS Admin](https://github.com/PowerDNS-Admin/PowerDNS-Admin) web app, which is written in Flask and used for managing PowerDNS servers. The pdns-mysql and pdns-recursor images also have the `alpine` tag, thanks to @PoppyPop. @@ -8,17 +8,21 @@ All images are available on Docker Hub: https://hub.docker.com/r/pschiffe/pdns-mysql/ +https://hub.docker.com/r/pschiffe/pdns-pgsql/ + https://hub.docker.com/r/pschiffe/pdns-recursor/ https://hub.docker.com/r/pschiffe/pdns-admin/ +Source GitHub repository: https://github.com/pschiffe/docker-pdns + ## pdns-mysql ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/pschiffe/pdns-mysql/latest?label=latest) ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/pschiffe/pdns-mysql/alpine?label=alpine) ![Docker Pulls](https://img.shields.io/docker/pulls/pschiffe/pdns-mysql) https://hub.docker.com/r/pschiffe/pdns-mysql/ -Docker image with [PowerDNS 4.x server](https://www.powerdns.com/) and mysql backend (without mysql server). Requires external mysql server. Env vars for mysql configuration: +Docker image with [PowerDNS 4.x server](https://www.powerdns.com/) and mysql backend. Requires external mysql server. Env vars for mysql configuration: ``` (name=default value) @@ -69,6 +73,63 @@ docker run -d -p 53:53 -p 53:53/udp --name pdns-slave \ pschiffe/pdns-mysql ``` +## pdns-pgsql + +![Docker Image Size (tag)](https://img.shields.io/docker/image-size/pschiffe/pdns-pgsql/latest?label=latest) ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/pschiffe/pdns-pgsql/alpine?label=alpine) ![Docker Pulls](https://img.shields.io/docker/pulls/pschiffe/pdns-pgsql) + +https://hub.docker.com/r/pschiffe/pdns-pgsql/ + +Docker image with [PowerDNS 4.x server](https://www.powerdns.com/) and postgres backend. Requires external postgres server. Env vars for pgsql configuration: +``` +(name=default value) + +PDNS_gpgsql_host=pgsql +PDNS_gpgsql_port=5432 +PDNS_gpgsql_user=postgres +PDNS_gpgsql_password=powerdns +PDNS_gpgsql_dbname=powerdns +``` + +If linked with the official [postgres](https://hub.docker.com/_/postgres) image using the alias `pgsql`, the connection can be automatically configured, eliminating the need to specify any of the above. The DB is automatically initialized if tables are missing. + +The PowerDNS server is configurable via env vars. Every variable starting with `PDNS_` will be inserted into `/etc/pdns/pdns.conf` conf file in the following way: prefix `PDNS_` will be stripped away and every `_` will be replaced with `-`. For example, from the above pgsql config, `PDNS_gpgsql_host=pgsql` will became `gpgsql-host=pgsql` in `/etc/pdns/pdns.conf` file. This way, you can configure PowerDNS server in any way you need within a `docker run` command. + +The `SUPERMASTER_IPS` env var is also supported, which can be used to configure supermasters for a slave DNS server. [Docs](https://doc.powerdns.com/md/authoritative/modes-of-operation/#supermaster-automatic-provisioning-of-slaves). Multiple IP addresses separated by spaces should work. + +You can find all the available settings [here](https://doc.powerdns.com/md/authoritative/). + +### Examples + +Example of a master server with the API enabled and one slave server configured: +``` +docker run -d -p 53:53 -p 53:53/udp --name pdns-master \ + --hostname ns1.example.com --link postgres:pgsql \ + -e PDNS_master=yes \ + -e PDNS_api=yes \ + -e PDNS_api_key=secret \ + -e PDNS_webserver=yes \ + -e PDNS_webserver_address=0.0.0.0 \ + -e PDNS_webserver_password=secret2 \ + -e PDNS_version_string=anonymous \ + -e PDNS_default_ttl=1500 \ + -e PDNS_allow_axfr_ips=172.5.0.21 \ + -e PDNS_only_notify=172.5.0.21 \ + pschiffe/pdns-pgsql +``` + +Example of a slave server with a supermaster: +``` +docker run -d -p 53:53 -p 53:53/udp --name pdns-slave \ + --hostname ns2.example.com --link postgres:pgsql \ + -e PDNS_gpgsql_dbname=powerdnsslave \ + -e PDNS_slave=yes \ + -e PDNS_version_string=anonymous \ + -e PDNS_disable_axfr=yes \ + -e PDNS_allow_notify_from=172.5.0.20 \ + -e SUPERMASTER_IPS=172.5.0.20 \ + pschiffe/pdns-pgsql +``` + ## pdns-recursor ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/pschiffe/pdns-recursor/latest?label=latest) ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/pschiffe/pdns-recursor/alpine?label=alpine) ![Docker Pulls](https://img.shields.io/docker/pulls/pschiffe/pdns-recursor) @@ -99,7 +160,7 @@ docker run -d -p 53:53 -p 53:53/udp --name pdns-recursor \ https://hub.docker.com/r/pschiffe/pdns-admin/ -Docker image with [PowerDNS Admin](https://github.com/PowerDNS-Admin/PowerDNS-Admin) web app, written in Flask, for managing PowerDNS servers. It needs external mysql server. +Docker image with [PowerDNS Admin](https://github.com/PowerDNS-Admin/PowerDNS-Admin) web app, written in Flask, for managing PowerDNS servers. It needs external mysql or postgres server. There is also an official image for the pdns-admin on [Docker Hub](https://hub.docker.com/r/powerdnsadmin/pda-legacy). That image contains only gunicorn process that handles both - static files and the python app. Image in this repo contains uWSGI server handling requests for python app and Caddy web server handling static files and optionally HTTPS with Let's Encrypt. @@ -107,13 +168,25 @@ Env vars for mysql configuration: ``` (name=default value) -PDNS_ADMIN_SQLA_DB_HOST="mysql" -PDNS_ADMIN_SQLA_DB_PORT="3306" -PDNS_ADMIN_SQLA_DB_USER="root" -PDNS_ADMIN_SQLA_DB_PASSWORD="powerdnsadmin" -PDNS_ADMIN_SQLA_DB_NAME="powerdnsadmin" +PDNS_ADMIN_SQLA_DB_HOST=mysql +PDNS_ADMIN_SQLA_DB_PORT=3306 +PDNS_ADMIN_SQLA_DB_USER=root +PDNS_ADMIN_SQLA_DB_PASSWORD=powerdnsadmin +PDNS_ADMIN_SQLA_DB_NAME=powerdnsadmin +``` +If linked with official [mariadb](https://hub.docker.com/_/mariadb/) image with alias `mysql`, the connection can be automatically configured, so you don't need to specify any of the above. + +Env vars for pgsql configuration: ``` -If linked with official [mariadb](https://hub.docker.com/_/mariadb/) image with alias `mysql`, the connection can be automatically configured, so you don't need to specify any of the above. The DB is automatically initialized if tables are missing. +PDNS_ADMIN_SQLA_DB_TYPE=postgres +PDNS_ADMIN_SQLA_DB_HOST=pgsql +PDNS_ADMIN_SQLA_DB_PORT=5432 +PDNS_ADMIN_SQLA_DB_USER=postgres +PDNS_ADMIN_SQLA_DB_PASSWORD=powerdnsadmin +PDNS_ADMIN_SQLA_DB_NAME=powerdnsadmin +``` + +The DB is automatically initialized if tables are missing. Similar to the pdns-mysql, pdns-admin is also completely configurable via env vars. Prefix in this case is `PDNS_ADMIN_`, configuration will be written to the `/opt/powerdns-admin/powerdnsadmin/default_config.py` file. @@ -180,14 +253,14 @@ docker run -d -p 80:8080 -p 443:8443 -p 443:8443/udp --name pdns-admin \ ## Docker Compose -Included docker compose file contains example configuration of how to use these containers: +Included docker compose files contain example configuration of how to use these containers: ``` -docker-compose up -d -f docker-compose-mysql.yml +docker-compose -f docker-compose-mysql.yml up -d ``` ## Ansible playbook -Included ansible playbook can be used to build and run the containers from this repo. Run it with: +Included ansible playbooks can be used to build and run the containers from this repo. Run it with: ``` ansible-playbook ansible-playbook-mysql.yml ``` diff --git a/ansible-playbook-mysql.yml b/ansible-playbook-mysql.yml index ea6aba0..0ad3dba 100644 --- a/ansible-playbook-mysql.yml +++ b/ansible-playbook-mysql.yml @@ -1,5 +1,5 @@ --- -- name: PDNS +- name: PDNS mysql hosts: localhost vars: pdns_master_ip: 172.5.0.20 @@ -11,7 +11,7 @@ tasks: - name: Create docker network community.docker.docker_network: - name: pdns-net + name: pdns-net-mysql state: present ipam_config: - subnet: '172.5.0.0/16' @@ -49,11 +49,11 @@ - name: PDNS recursor community.docker.docker_container: - name: pdns-recursor + name: pdns-recursor-mysql image: pschiffe/pdns-recursor:{{ "alpine" if alpine | bool else "latest" }} state: '{{ c_state }}' networks: - - name: pdns-net + - name: pdns-net-mysql volumes: - /etc/localtime:/etc/localtime:ro ulimits: @@ -68,13 +68,13 @@ pull: true state: '{{ c_state }}' networks: - - name: pdns-net + - name: pdns-net-mysql aliases: - db - mysql volumes: - /etc/localtime:/etc/localtime:ro - - pdns-mariadb-volume:/var/lib/mysql:z + - pdns-mariadb-volume:/var/lib/mysql:Z env: MYSQL_ROOT_PASSWORD: 'my-secret-pw' healthcheck: @@ -91,7 +91,7 @@ pull: true state: '{{ c_state }}' networks: - - name: pdns-net + - name: pdns-net-mysql published_ports: - '8888:80' volumes: @@ -99,7 +99,7 @@ tags: - db - - name: Build pdns + - name: Build pdns mysql community.docker.docker_image: name: pschiffe/pdns-mysql state: '{{ i_state }}' @@ -111,7 +111,7 @@ tags: - pdns - - name: Build pdns alpine version + - name: Build pdns mysql alpine version community.docker.docker_image: name: pschiffe/pdns-mysql tag: alpine @@ -125,15 +125,17 @@ tags: - pdns - - name: PDNS master + - name: PDNS mysql master community.docker.docker_container: - name: pdns + name: pdns-mysql image: pschiffe/pdns-mysql:{{ "alpine" if alpine | bool else "latest" }} state: '{{ c_state }}' hostname: ns1.example.com networks: - - name: pdns-net + - name: pdns-net-mysql ipv4_address: '{{ pdns_master_ip }}' + aliases: + - pdns etc_hosts: ns1.example.com: '{{ pdns_master_ip }}' ns2.example.com: '{{ pdns_slave_ip }}' @@ -154,14 +156,14 @@ tags: - pdns - - name: PDNS slave + - name: PDNS mysql slave community.docker.docker_container: - name: pdns-slave + name: pdns-mysql-slave image: pschiffe/pdns-mysql:{{ "alpine" if alpine | bool else "latest" }} state: '{{ c_state }}' hostname: ns2.example.com networks: - - name: pdns-net + - name: pdns-net-mysql ipv4_address: '{{ pdns_slave_ip }}' etc_hosts: ns1.example.com: '{{ pdns_master_ip }}' @@ -198,11 +200,11 @@ - name: PDNS-admin community.docker.docker_container: - name: pdns-admin + name: pdns-admin-mysql image: pschiffe/pdns-admin state: '{{ c_state }}' networks: - - name: pdns-net + - name: pdns-net-mysql aliases: - pdns-admin published_ports: @@ -224,6 +226,6 @@ - name: Remove network community.docker.docker_network: - name: pdns-net + name: pdns-net-mysql state: absent when: wipe | bool diff --git a/ansible-playbook-pgsql.yml b/ansible-playbook-pgsql.yml new file mode 100644 index 0000000..6442856 --- /dev/null +++ b/ansible-playbook-pgsql.yml @@ -0,0 +1,235 @@ +--- +- name: PDNS pgsql + hosts: localhost + vars: + pdns_master_ip: 172.7.0.20 + pdns_slave_ip: 172.7.0.21 + wipe: false + c_state: '{{ "absent" if wipe | bool else "started" }}' + i_state: present + alpine: false + tasks: + - name: Create docker network + community.docker.docker_network: + name: pdns-net-pgsql + state: present + ipam_config: + - subnet: '172.7.0.0/16' + gateway: '172.7.0.1' + tags: + - pdns + - pdns-admin + - pdns-recursor + + - name: Build pdns recursor + community.docker.docker_image: + name: pschiffe/pdns-recursor + state: '{{ i_state }}' + source: build + force_source: true + build: + pull: true + path: ./pdns-recursor + tags: + - pdns-recursor + + - name: Build pdns recursor alpine version + community.docker.docker_image: + name: pschiffe/pdns-recursor + tag: alpine + state: '{{ i_state }}' + source: build + force_source: true + build: + pull: true + path: ./pdns-recursor + dockerfile: Dockerfile.alpine + tags: + - pdns-recursor + + - name: PDNS recursor + community.docker.docker_container: + name: pdns-recursor-pgsql + image: pschiffe/pdns-recursor:{{ "alpine" if alpine | bool else "latest" }} + state: '{{ c_state }}' + networks: + - name: pdns-net-pgsql + volumes: + - /etc/localtime:/etc/localtime:ro + ulimits: + - 'nofile:5000:5000' + tags: + - pdns-recursor + + - name: DB + community.docker.docker_container: + name: pdns-postgres + image: postgres:16-alpine + pull: true + state: '{{ c_state }}' + networks: + - name: pdns-net-pgsql + aliases: + - db + - pgsql + volumes: + - /etc/localtime:/etc/localtime:ro + - pdns-postgres-volume:/var/lib/postgresql/data:Z + env: + POSTGRES_PASSWORD: 'my-secret-pw' + healthcheck: + test: ['CMD', 'pg_isready', '-U', 'postgres'] + timeout: 10s + retries: 5 + tags: + - db + + - name: Adminer + community.docker.docker_container: + name: pdns-adminer + image: adminer + pull: true + state: '{{ c_state }}' + networks: + - name: pdns-net-pgsql + published_ports: + - '7888:8080' + volumes: + - /etc/localtime:/etc/localtime:ro + tags: + - db + + - name: Build pdns pgsql + community.docker.docker_image: + name: pschiffe/pdns-pgsql + state: '{{ i_state }}' + source: build + force_source: true + build: + pull: true + path: ./pdns-pgsql + tags: + - pdns + + - name: Build pdns pgsql alpine version + community.docker.docker_image: + name: pschiffe/pdns-pgsql + tag: alpine + state: '{{ i_state }}' + source: build + force_source: true + build: + pull: true + path: ./pdns-pgsql + dockerfile: Dockerfile.alpine + tags: + - pdns + + - name: PDNS pgsql master + community.docker.docker_container: + name: pdns-pgsql + image: pschiffe/pdns-pgsql:{{ "alpine" if alpine | bool else "latest" }} + state: '{{ c_state }}' + hostname: ns1.example.com + networks: + - name: pdns-net-pgsql + ipv4_address: '{{ pdns_master_ip }}' + aliases: + - pdns + etc_hosts: + ns1.example.com: '{{ pdns_master_ip }}' + ns2.example.com: '{{ pdns_slave_ip }}' + volumes: + - /etc/localtime:/etc/localtime:ro + env: + PDNS_gpgsql_password: 'my-secret-pw' + PDNS_master: 'yes' + PDNS_api: 'yes' + PDNS_api_key: 'secret' + PDNS_webserver: 'yes' + PDNS_webserver_address: '0.0.0.0' + PDNS_webserver_allow_from: '172.7.0.0/16' + PDNS_version_string: 'anonymous' + PDNS_default_ttl: '1500' + PDNS_allow_axfr_ips: '{{ pdns_slave_ip }}' + PDNS_only_notify: '{{ pdns_slave_ip }}' + tags: + - pdns + + - name: PDNS pgsql slave + community.docker.docker_container: + name: pdns-pgsql-slave + image: pschiffe/pdns-pgsql:{{ "alpine" if alpine | bool else "latest" }} + state: '{{ c_state }}' + hostname: ns2.example.com + networks: + - name: pdns-net-pgsql + ipv4_address: '{{ pdns_slave_ip }}' + etc_hosts: + ns1.example.com: '{{ pdns_master_ip }}' + ns2.example.com: '{{ pdns_slave_ip }}' + volumes: + - /etc/localtime:/etc/localtime:ro + env: + PDNS_gpgsql_dbname: 'powerdnsslave' + PDNS_gpgsql_password: 'my-secret-pw' + PDNS_slave: 'yes' + PDNS_superslave: 'yes' + PDNS_webserver: 'yes' + PDNS_webserver_address: '0.0.0.0' + PDNS_webserver_allow_from: '172.7.0.0/16' + PDNS_version_string: 'anonymous' + PDNS_disable_axfr: 'yes' + PDNS_allow_notify_from: '{{ pdns_master_ip }}' + SUPERMASTER_IPS: '{{ pdns_master_ip }}' + tags: + - pdns + + - name: Build pdns-admin + community.docker.docker_image: + name: pschiffe/pdns-admin + tag: latest + state: '{{ i_state }}' + source: build + force_source: true + build: + pull: true + path: ./pdns-admin + tags: + - pdns-admin + + - name: PDNS-admin pgsql + community.docker.docker_container: + name: pdns-admin-pgsql + image: pschiffe/pdns-admin + state: '{{ c_state }}' + networks: + - name: pdns-net-pgsql + aliases: + - pdns-admin + published_ports: + - '7889:8080' + volumes: + - /etc/localtime:/etc/localtime:ro + env: + PDNS_ADMIN_SQLA_DB_TYPE: 'postgres' + PDNS_ADMIN_SQLA_DB_HOST: 'pgsql' + PDNS_ADMIN_SQLA_DB_PORT: '5432' + PDNS_ADMIN_SQLA_DB_USER: 'postgres' + PDNS_ADMIN_SQLA_DB_PASSWORD: 'my-secret-pw' + PDNS_VERSION: '4.8' + PDNS_API_KEY: 'secret' + tags: + - pdns-admin + + - name: Remove docker volume + community.docker.docker_volume: + name: pdns-postgres-volume + state: absent + when: wipe | bool + + - name: Remove network + community.docker.docker_network: + name: pdns-net-pgsql + state: absent + when: wipe | bool diff --git a/docker-compose-mysql.yml b/docker-compose-mysql.yml index a059528..b27280b 100644 --- a/docker-compose-mysql.yml +++ b/docker-compose-mysql.yml @@ -2,10 +2,10 @@ version: '2.4' services: - pdns-recursor: + pdns-recursor-mysql: image: pschiffe/pdns-recursor:${RECURSOR_TAG:-latest} networks: - - pdns + - pdns-mysql volumes: - /etc/localtime:/etc/localtime:ro ulimits: @@ -16,13 +16,13 @@ services: mariadb: image: mariadb:11 networks: - pdns: + pdns-mysql: aliases: - db - mysql volumes: - /etc/localtime:/etc/localtime:ro - - mariadb:/var/lib/mysql:z + - mariadb:/var/lib/mysql:Z environment: - MYSQL_ROOT_PASSWORD=my-secret-pw healthcheck: @@ -33,17 +33,17 @@ services: phpmyadmin: image: phpmyadmin:5 networks: - - pdns + - pdns-mysql ports: - '8988:80' volumes: - /etc/localtime:/etc/localtime:ro - pdns-master: + pdns-mysql-master: image: pschiffe/pdns-mysql:${PDNS_MYSQL_TAG:-latest} hostname: ns1.example.com networks: - pdns: + pdns-mysql: ipv4_address: 172.6.0.20 aliases: - pdns @@ -67,11 +67,11 @@ services: depends_on: - mariadb - pdns-slave: + pdns-mysql-slave: image: pschiffe/pdns-mysql:${PDNS_MYSQL_TAG:-latest} hostname: ns2.example.com networks: - pdns: + pdns-mysql: ipv4_address: 172.6.0.21 extra_hosts: - 'ns1.example.com:172.6.0.20' @@ -92,12 +92,12 @@ services: - SUPERMASTER_IPS=172.6.0.20 depends_on: - mariadb - - pdns-master + - pdns-mysql-master - pdns-admin: + pdns-admin-mysql: image: pschiffe/pdns-admin networks: - pdns: + pdns-mysql: aliases: - pdns-admin ports: @@ -110,10 +110,10 @@ services: - PDNS_API_KEY=secret depends_on: - mariadb - - pdns-master + - pdns-mysql-master networks: - pdns: + pdns-mysql: ipam: config: - subnet: 172.6.0.0/16 diff --git a/docker-compose-pgsql.yml b/docker-compose-pgsql.yml new file mode 100644 index 0000000..c2b2401 --- /dev/null +++ b/docker-compose-pgsql.yml @@ -0,0 +1,127 @@ +version: '2.4' + +services: + + pdns-recursor-pgsql: + image: pschiffe/pdns-recursor:${RECURSOR_TAG:-latest} + networks: + - pdns-pgsql + volumes: + - /etc/localtime:/etc/localtime:ro + ulimits: + nofile: + soft: 5000 + hard: 5000 + + postgres: + image: postgres:16-alpine + networks: + pdns-pgsql: + aliases: + - db + - pgsql + volumes: + - /etc/localtime:/etc/localtime:ro + - pgsql:/var/lib/postgresql/data:Z + environment: + - POSTGRES_PASSWORD=my-secret-pw + healthcheck: + test: ['CMD', 'pg_isready', '-U', 'postgres'] + timeout: 10s + retries: 5 + + adminer: + image: adminer + networks: + - pdns-pgsql + ports: + - '7988:8080' + volumes: + - /etc/localtime:/etc/localtime:ro + + pdns-pgsql-master: + image: pschiffe/pdns-pgsql:${PDNS_PGSQL_TAG:-latest} + hostname: ns1.example.com + networks: + pdns-pgsql: + ipv4_address: 172.8.0.20 + aliases: + - pdns + extra_hosts: + - 'ns1.example.com:172.8.0.20' + - 'ns2.example.com:172.8.0.21' + volumes: + - /etc/localtime:/etc/localtime:ro + environment: + - PDNS_gpgsql_password=my-secret-pw + - PDNS_master=yes + - PDNS_api=yes + - PDNS_api_key=secret + - PDNS_webserver=yes + - PDNS_webserver_address=0.0.0.0 + - PDNS_webserver_allow_from=172.8.0.0/16 + - PDNS_version_string=anonymous + - PDNS_default_ttl=1500 + - PDNS_allow_axfr_ips=172.8.0.21 + - PDNS_only_notify=172.8.0.21 + depends_on: + - postgres + + pdns-pgsql-slave: + image: pschiffe/pdns-pgsql:${PDNS_PGSQL_TAG:-latest} + hostname: ns2.example.com + networks: + pdns-pgsql: + ipv4_address: 172.8.0.21 + extra_hosts: + - 'ns1.example.com:172.8.0.20' + - 'ns2.example.com:172.8.0.21' + volumes: + - /etc/localtime:/etc/localtime:ro + environment: + - PDNS_gpgsql_dbname=powerdnsslave + - PDNS_gpgsql_password=my-secret-pw + - PDNS_slave=yes + - PDNS_superslave=yes + - PDNS_webserver=yes + - PDNS_webserver_address=0.0.0.0 + - PDNS_webserver_allow_from=172.8.0.0/16 + - PDNS_version_string=anonymous + - PDNS_disable_axfr=yes + - PDNS_allow_notify_from=172.8.0.20 + - SUPERMASTER_IPS=172.8.0.20 + depends_on: + - postgres + - pdns-pgsql-master + + pdns-admin-pgsql: + image: pschiffe/pdns-admin + networks: + pdns-pgsql: + aliases: + - pdns-admin + ports: + - '7989:8080' + volumes: + - /etc/localtime:/etc/localtime:ro + environment: + - PDNS_ADMIN_SQLA_DB_TYPE=postgres + - PDNS_ADMIN_SQLA_DB_HOST=pgsql + - PDNS_ADMIN_SQLA_DB_PORT=5432 + - PDNS_ADMIN_SQLA_DB_USER=postgres + - PDNS_ADMIN_SQLA_DB_PASSWORD=my-secret-pw + - PDNS_VERSION=4.8 + - PDNS_API_KEY=secret + depends_on: + - postgres + - pdns-pgsql-master + +networks: + pdns-pgsql: + ipam: + config: + - subnet: 172.8.0.0/16 + gateway: 172.8.0.1 + +volumes: + pgsql: diff --git a/pdns-admin/Dockerfile b/pdns-admin/Dockerfile index 2b3cf6d..1037bb0 100644 --- a/pdns-admin/Dockerfile +++ b/pdns-admin/Dockerfile @@ -5,7 +5,7 @@ RUN arch=$([ "$(arch)" = 'aarch64' ] && echo -n 'arm64' || echo -n 'amd64') \ && echo 'tsflags=nodocs' >> /etc/dnf/dnf.conf \ && echo 'assumeyes=True' >> /etc/dnf/dnf.conf \ && curl -fsSL -o /etc/yum.repos.d/yarn.repo https://dl.yarnpkg.com/rpm/yarn.repo \ - && dnf module enable nodejs:20 \ + && dnf module enable nodejs:20 postgresql:15 \ && dnf install dnf-plugins-core epel-release \ && dnf config-manager --set-disabled epel-cisco-openh264 \ && dnf config-manager --set-enabled crb \ @@ -14,11 +14,13 @@ RUN arch=$([ "$(arch)" = 'aarch64' ] && echo -n 'arm64' || echo -n 'amd64') \ caddy \ mariadb \ npm \ + postgresql \ python3-cffi \ python3-ldap \ python3-lxml \ python3-mysqlclient \ python3-pip \ + python3-psycopg2 \ python3-pyyaml \ python3-saml \ python3-xmlsec \ diff --git a/pdns-admin/config.py.tpl b/pdns-admin/config.py.tpl index edd3658..c037044 100644 --- a/pdns-admin/config.py.tpl +++ b/pdns-admin/config.py.tpl @@ -28,5 +28,5 @@ SAML_ENABLED = False {{ end -}} {{ end }} ### DATABASE CONFIG -SQLALCHEMY_DATABASE_URI = 'mysql://' + SQLA_DB_USER + ':' + SQLA_DB_PASSWORD + '@' + SQLA_DB_HOST + ':' + str(SQLA_DB_PORT) + '/' + SQLA_DB_NAME +SQLALCHEMY_DATABASE_URI = SQLA_DB_TYPE + '://' + SQLA_DB_USER + ':' + SQLA_DB_PASSWORD + '@' + SQLA_DB_HOST + ':' + str(SQLA_DB_PORT) + '/' + SQLA_DB_NAME SQLALCHEMY_TRACK_MODIFICATIONS = True diff --git a/pdns-admin/docker-entrypoint.sh b/pdns-admin/docker-entrypoint.sh index 46ecae2..b417441 100755 --- a/pdns-admin/docker-entrypoint.sh +++ b/pdns-admin/docker-entrypoint.sh @@ -2,24 +2,26 @@ set -euo pipefail -# Configure mysql env vars +# Configure db env vars +: "${PDNS_ADMIN_SQLA_DB_TYPE:=mysql}" # or postgres : "${PDNS_ADMIN_SQLA_DB_HOST:=${MYSQL_ENV_MYSQL_HOST:-mysql}}" : "${PDNS_ADMIN_SQLA_DB_PORT:=${MYSQL_ENV_MYSQL_PORT:-3306}}" -: "${PDNS_ADMIN_SQLA_DB_USER:=${MYSQL_ENV_MYSQL_USER:-root}}" +: "${PDNS_ADMIN_SQLA_DB_USER:=${MYSQL_ENV_MYSQL_USER:-${PGSQL_ENV_POSTGRES_USER:-root}}}" if [ "${PDNS_ADMIN_SQLA_DB_USER}" = "root" ]; then : "${PDNS_ADMIN_SQLA_DB_PASSWORD:=$MYSQL_ENV_MYSQL_ROOT_PASSWORD}" fi -: "${PDNS_ADMIN_SQLA_DB_PASSWORD:=${MYSQL_ENV_MYSQL_PASSWORD:-powerdnsadmin}}" -: "${PDNS_ADMIN_SQLA_DB_NAME:=${MYSQL_ENV_MYSQL_DATABASE:-powerdnsadmin}}" +: "${PDNS_ADMIN_SQLA_DB_PASSWORD:=${MYSQL_ENV_MYSQL_PASSWORD:-${PGSQL_ENV_POSTGRES_PASSWORD:-powerdnsadmin}}}" +: "${PDNS_ADMIN_SQLA_DB_NAME:=${MYSQL_ENV_MYSQL_DATABASE:-${PGSQL_ENV_POSTGRES_DB:-powerdnsadmin}}}" -# Cleanup quotes from mysql env vars +# Cleanup quotes from db env vars +PDNS_ADMIN_SQLA_DB_TYPE="${PDNS_ADMIN_SQLA_DB_TYPE//[\'\"]}" PDNS_ADMIN_SQLA_DB_HOST="${PDNS_ADMIN_SQLA_DB_HOST//[\'\"]}" PDNS_ADMIN_SQLA_DB_PORT="${PDNS_ADMIN_SQLA_DB_PORT//[\'\"]}" PDNS_ADMIN_SQLA_DB_USER="${PDNS_ADMIN_SQLA_DB_USER//[\'\"]}" PDNS_ADMIN_SQLA_DB_PASSWORD="${PDNS_ADMIN_SQLA_DB_PASSWORD//[\'\"]}" PDNS_ADMIN_SQLA_DB_NAME="${PDNS_ADMIN_SQLA_DB_NAME//[\'\"]}" -export PDNS_ADMIN_SQLA_DB_HOST PDNS_ADMIN_SQLA_DB_PORT PDNS_ADMIN_SQLA_DB_USER PDNS_ADMIN_SQLA_DB_PASSWORD PDNS_ADMIN_SQLA_DB_NAME +export PDNS_ADMIN_SQLA_DB_TYPE PDNS_ADMIN_SQLA_DB_HOST PDNS_ADMIN_SQLA_DB_PORT PDNS_ADMIN_SQLA_DB_USER PDNS_ADMIN_SQLA_DB_PASSWORD PDNS_ADMIN_SQLA_DB_NAME # Configure pdns server env vars : "${PDNS_API_URL:=http://${PDNS_ENV_PDNS_webserver_host:-pdns}:${PDNS_ENV_PDNS_webserver_port:-8081}/}" @@ -36,26 +38,41 @@ subvars --prefix 'SSL_' < '/Caddyfile.tpl' > '/etc/caddy/Caddyfile' subvars --prefix 'PDNS_ADMIN_' < '/config.py.tpl' > '/opt/powerdns-admin/powerdnsadmin/default_config.py' # Initialize DB if needed -MYSQL_COMMAND="mysql -h ${PDNS_ADMIN_SQLA_DB_HOST} -P ${PDNS_ADMIN_SQLA_DB_PORT} -u ${PDNS_ADMIN_SQLA_DB_USER} -p${PDNS_ADMIN_SQLA_DB_PASSWORD}" +if [[ "${PDNS_ADMIN_SQLA_DB_TYPE}" == 'mysql' ]]; then + SQL_COMMAND="mysql -h ${PDNS_ADMIN_SQLA_DB_HOST} -P ${PDNS_ADMIN_SQLA_DB_PORT} -u ${PDNS_ADMIN_SQLA_DB_USER} -p${PDNS_ADMIN_SQLA_DB_PASSWORD} -e" +elif [[ "${PDNS_ADMIN_SQLA_DB_TYPE}" == 'postgres' ]]; then + PGPASSWORD="${PDNS_ADMIN_SQLA_DB_PASSWORD}" + export PGPASSWORD + SQL_COMMAND="psql -h ${PDNS_ADMIN_SQLA_DB_HOST} -p ${PDNS_ADMIN_SQLA_DB_PORT} -U ${PDNS_ADMIN_SQLA_DB_USER} -c" +else + >&2 echo "Invalid DB type: ${PDNS_ADMIN_SQLA_DB_TYPE}" + exit 1 +fi -until $MYSQL_COMMAND -e ';' ; do - >&2 echo 'MySQL is unavailable - sleeping' +until $SQL_COMMAND ';' ; do + >&2 echo 'DB is unavailable - sleeping' sleep 1 done -$MYSQL_COMMAND -e "CREATE DATABASE IF NOT EXISTS ${PDNS_ADMIN_SQLA_DB_NAME}" +if [[ "${SKIP_DB_CREATE:-false}" != 'true' ]]; then + if [[ "${PDNS_ADMIN_SQLA_DB_TYPE}" == 'mysql' ]]; then + $SQL_COMMAND "CREATE DATABASE IF NOT EXISTS ${PDNS_ADMIN_SQLA_DB_NAME}" + elif [[ "${PDNS_ADMIN_SQLA_DB_TYPE}" == 'postgres' ]]; then + echo "SELECT 'CREATE DATABASE ${PDNS_ADMIN_SQLA_DB_NAME}' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '${PDNS_ADMIN_SQLA_DB_NAME}')\gexec" | ${SQL_COMMAND::-3} + fi +fi flask db upgrade # initial settings if not available in the DB -$MYSQL_COMMAND "${PDNS_ADMIN_SQLA_DB_NAME}" -e "INSERT INTO setting (name, value) SELECT * FROM (SELECT 'pdns_api_url', '${PDNS_API_URL//[\'\"]}') AS tmp WHERE NOT EXISTS (SELECT name FROM setting WHERE name = 'pdns_api_url') LIMIT 1;" -$MYSQL_COMMAND "${PDNS_ADMIN_SQLA_DB_NAME}" -e "INSERT INTO setting (name, value) SELECT * FROM (SELECT 'pdns_api_key', '${PDNS_API_KEY//[\'\"]}') AS tmp WHERE NOT EXISTS (SELECT name FROM setting WHERE name = 'pdns_api_key') LIMIT 1;" -$MYSQL_COMMAND "${PDNS_ADMIN_SQLA_DB_NAME}" -e "INSERT INTO setting (name, value) SELECT * FROM (SELECT 'pdns_version', '${PDNS_VERSION//[\'\"]}') AS tmp WHERE NOT EXISTS (SELECT name FROM setting WHERE name = 'pdns_version') LIMIT 1;" +$SQL_COMMAND "INSERT INTO setting (name, value) SELECT * FROM (SELECT 'pdns_api_url', '${PDNS_API_URL//[\'\"]}') AS tmp WHERE NOT EXISTS (SELECT name FROM setting WHERE name = 'pdns_api_url') LIMIT 1;" "${PDNS_ADMIN_SQLA_DB_NAME}" +$SQL_COMMAND "INSERT INTO setting (name, value) SELECT * FROM (SELECT 'pdns_api_key', '${PDNS_API_KEY//[\'\"]}') AS tmp WHERE NOT EXISTS (SELECT name FROM setting WHERE name = 'pdns_api_key') LIMIT 1;" "${PDNS_ADMIN_SQLA_DB_NAME}" +$SQL_COMMAND "INSERT INTO setting (name, value) SELECT * FROM (SELECT 'pdns_version', '${PDNS_VERSION//[\'\"]}') AS tmp WHERE NOT EXISTS (SELECT name FROM setting WHERE name = 'pdns_version') LIMIT 1;" "${PDNS_ADMIN_SQLA_DB_NAME}" # update pdns api settings if env changed -$MYSQL_COMMAND "${PDNS_ADMIN_SQLA_DB_NAME}" -e "UPDATE setting SET value='${PDNS_API_URL//[\'\"]}' WHERE name='pdns_api_url';" -$MYSQL_COMMAND "${PDNS_ADMIN_SQLA_DB_NAME}" -e "UPDATE setting SET value='${PDNS_API_KEY//[\'\"]}' WHERE name='pdns_api_key';" -$MYSQL_COMMAND "${PDNS_ADMIN_SQLA_DB_NAME}" -e "UPDATE setting SET value='${PDNS_VERSION//[\'\"]}' WHERE name='pdns_version';" +$SQL_COMMAND "UPDATE setting SET value='${PDNS_API_URL//[\'\"]}' WHERE name='pdns_api_url';" "${PDNS_ADMIN_SQLA_DB_NAME}" +$SQL_COMMAND "UPDATE setting SET value='${PDNS_API_KEY//[\'\"]}' WHERE name='pdns_api_key';" "${PDNS_ADMIN_SQLA_DB_NAME}" +$SQL_COMMAND "UPDATE setting SET value='${PDNS_VERSION//[\'\"]}' WHERE name='pdns_version';" "${PDNS_ADMIN_SQLA_DB_NAME}" mkdir -p /run/uwsgi chown uwsgi: /run/uwsgi diff --git a/pdns-mysql/docker-entrypoint.sh b/pdns-mysql/docker-entrypoint.sh index 5a3f7e9..0865131 100755 --- a/pdns-mysql/docker-entrypoint.sh +++ b/pdns-mysql/docker-entrypoint.sh @@ -12,7 +12,7 @@ fi : "${PDNS_gmysql_password:=${MYSQL_ENV_MYSQL_PASSWORD:-powerdns}}" : "${PDNS_gmysql_dbname:=${MYSQL_ENV_MYSQL_DATABASE:-powerdns}}" -# use first part of node name as database name suffix +# 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_gmysql_dbname="${PDNS_gmysql_dbname}${NODE_NAME}" diff --git a/pdns-pgsql/Dockerfile b/pdns-pgsql/Dockerfile new file mode 100644 index 0000000..b49e244 --- /dev/null +++ b/pdns-pgsql/Dockerfile @@ -0,0 +1,28 @@ +FROM fedora:39 + +RUN arch=$([ "$(arch)" = 'aarch64' ] && echo -n 'arm64' || echo -n 'amd64') \ + && echo 'install_weak_deps=False' >> /etc/dnf/dnf.conf \ + && echo 'assumeyes=True' >> /etc/dnf/dnf.conf \ + && sed -i 's/enabled=1/enabled=0/g' /etc/yum.repos.d/fedora-cisco-openh264.repo \ + && dnf --refresh upgrade \ + && dnf install \ + hostname \ + pdns \ + postgresql16 \ + https://github.com/kha7iq/subvars/releases/download/v0.1.5/subvars_${arch}.rpm \ + && dnf --setopt 'tsflags=' install pdns-backend-postgresql \ + && dnf clean all + +COPY pdns.conf.tpl docker-entrypoint.sh / + +ENV VERSION=4.8 \ + PDNS_guardian=yes \ + PDNS_setuid=pdns \ + PDNS_setgid=pdns \ + PDNS_launch=gpgsql + +EXPOSE 53 53/udp + +ENTRYPOINT [ "/docker-entrypoint.sh" ] + +CMD [ "/usr/sbin/pdns_server" ] diff --git a/pdns-pgsql/Dockerfile.alpine b/pdns-pgsql/Dockerfile.alpine new file mode 100644 index 0000000..72f5dea --- /dev/null +++ b/pdns-pgsql/Dockerfile.alpine @@ -0,0 +1,27 @@ +FROM alpine:3.19.0 + +RUN arch=$([ "$(arch)" = 'aarch64' ] && echo -n 'arm64' || echo -n 'amd64') \ + && apk update \ + && apk upgrade \ + && apk add \ + pdns \ + pdns-backend-pgsql \ + pdns-doc \ + postgresql16-client \ + && wget -O subvars.apk https://github.com/kha7iq/subvars/releases/download/v0.1.5/subvars_${arch}.apk \ + && apk add --allow-untrusted subvars.apk \ + && rm -rf subvars.apk /var/cache/apk/* + +COPY pdns.conf.tpl docker-entrypoint.sh / + +ENV VERSION=4.8 \ + PDNS_guardian=yes \ + PDNS_setuid=pdns \ + PDNS_setgid=pdns \ + PDNS_launch=gpgsql + +EXPOSE 53 53/udp + +ENTRYPOINT [ "/docker-entrypoint.sh" ] + +CMD [ "/usr/sbin/pdns_server" ] diff --git a/pdns-pgsql/docker-entrypoint.sh b/pdns-pgsql/docker-entrypoint.sh new file mode 100755 index 0000000..68f7b95 --- /dev/null +++ b/pdns-pgsql/docker-entrypoint.sh @@ -0,0 +1,70 @@ +#!/bin/sh + +set -eu + +# 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 + + +PGPASSWORD="${PDNS_gpgsql_password}" +export PGPASSWORD +PGSQL_COMMAND="psql -h ${PDNS_gpgsql_host} -p ${PDNS_gpgsql_port} -U ${PDNS_gpgsql_user}" + +# Wait for pgsql to respond +until $PGSQL_COMMAND -c ';' ; do + >&2 echo 'Pgsql is unavailable - sleeping' + sleep 3 +done + +# 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 + +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 + $PGSQL_COMMAND -d "$PDNS_gpgsql_dbname" < /usr/share/doc/pdns/schema.pgsql.sql +fi + +if [ "${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 + +unset PGPASSWORD + +# Create config file from template +subvars --prefix 'PDNS_' < '/pdns.conf.tpl' > '/etc/pdns/pdns.conf' + +exec "$@" diff --git a/pdns-pgsql/pdns.conf.tpl b/pdns-pgsql/pdns.conf.tpl new file mode 100644 index 0000000..e4e181e --- /dev/null +++ b/pdns-pgsql/pdns.conf.tpl @@ -0,0 +1,3 @@ +{{ range $key, $value := match "PDNS_" -}} +{{- $key | trimPrefix "PDNS_" | replace "_" "-" }} = {{ $value }} +{{ end -}}