Supermaster support, multiple slaves on the same mysql server (#32)

* better supermaster handling, support for multiple slaves on the same db server

* minor style fix

* requested changes

* replaced cut with awk

* manifests

* newlines

* clarification for axfr
This commit is contained in:
tafkam 2020-03-29 19:01:11 +02:00 committed by GitHub
parent 46f61c4799
commit 6fe7093c7b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 565 additions and 12 deletions

View file

@ -0,0 +1,39 @@
# PDNS example for Kubernetes
## Files
- master-daemonset.yaml : Daemonset for PDNS supermaster
- slave-daemonset.yaml : Daemonset for PDNS slaves
- admin-dashboard.yaml : Deployment for PDNS-Admin Web Dashboard
- mariadb.yaml : Example Mysql Deployment
## Example setup
This example deploys a supermaster and two slaves on the host network, so pdns can be reached from external networks. Access to the admin-dashboard has to be configured separately with ingress. The admin-dashboard uses a kubernetes clusterip service to use the supermaster-api. Supermaster, slaves and dashboard use the same MariaDB example deployment with different databases (not recommended for production environments).
For signed AXFR you have to manually deploy TSIG Keys to you supermaster and slaves (https://doc.powerdns.com/authoritative/tsig.html).
## Requirements
### Node Labels
The Daemonsets use node-role labels as nodeSelector:
kubectl label node node1 node-role.kubernetes.io/pdns-master=true
kubectl label node node2 node-role.kubernetes.io/pdns-slave=true
kubectl label node node3 node-role.kubernetes.io/pdns-slave=true
Any other node labels will also work.
### Service Names
Service names in the pdns namespace **must not** start with 'pdns' or they will break the pdns.conf environment templating.
### Pod-CIDR
Replace "10.244.0.0/16" in the manifests with your cluster's pod-cidr.
### Node IPs
Replace IPs and hostnames in the daemonset environments with your own node IPs and domains.
Used in this example:
| component | host | ip |
|--|--|--|
| supermaster | ns1.example.com | 10.0.0.1 |
| slave1 | ns2.example.com | 10.0.0.2 |
| slave2 | ns3.example.com | 10.0.0.3 |

View file

@ -0,0 +1,122 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/name: pdns-admin
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: admin
name: pdns-admin
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: pdns-admin
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: admin
template:
metadata:
labels:
app.kubernetes.io/name: pdns-admin
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: admin
spec:
hostAliases:
- ip: "127.0.0.1"
hostnames:
- "pdns-admin-uwsgi"
containers:
- name: pdns-admin-static
image: pschiffe/pdns-admin-static:ngoduykhanh
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP
resources:
limits:
cpu: 300m
memory: 128Mi
requests:
cpu: 50m
memory: 64Mi
- name: pdns-admin-uwsgi
image: pschiffe/pdns-admin-uwsgi:ngoduykhanh
imagePullPolicy: IfNotPresent
env:
- name: PDNS_ADMIN_SQLA_DB_HOST
value: "'mariadb-pdns'"
- name: PDNS_ADMIN_SQLA_DB_PORT
value: "'3306'"
- name: PDNS_ADMIN_SQLA_DB_USER
value: "'root'"
- name: PDNS_ADMIN_SQLA_DB_PASSWORD
valueFrom:
secretKeyRef:
name: pdns-admin-secret
key: quoted_mysql_password
- name: PDNS_ADMIN_SQLA_DB_NAME
value: "'pdnsadmin'"
- name: PDNS_API_URL
value: "http://master-api-pdns:8081/"
- name: PDNS_VERSION
value: "4.2.1"
- name: PDNS_API_KEY
valueFrom:
secretKeyRef:
name: master-pdns-secret
key: apikey
volumeMounts:
- name: uploads
mountPath: /opt/powerdns-admin/upload/
resources:
limits:
cpu: 300m
memory: 128Mi
requests:
cpu: 50m
memory: 64Mi
volumes:
- name: uploads
persistentVolumeClaim:
claimName: pdns-admin-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
labels:
app.kubernetes.io/name: pdns-admin-pvc
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: admin
name: pdns-admin-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: pdns-admin-svc
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: admin
name: admin-dashboard-pdns
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
selector:
app.kubernetes.io/name: pdns-admin
---
apiVersion: v1
kind: Secret
metadata:
labels:
app.kubernetes.io/name: pdns-admin-secret
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: admin
name: pdns-admin-secret
data:
quoted_mysql_password: J3Jvb3Qn

View file

@ -0,0 +1,6 @@
namespace: default
resources:
- mariadb.yaml
- master-daemonset.yaml
- slave-daemonset.yaml
- admin-dashboard.yaml

View file

@ -0,0 +1,126 @@
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
creationTimestamp: null
labels:
app.kubernetes.io/name: mariadb-pdns
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: mariadb
name: mariadb-pdns
spec:
podManagementPolicy: OrderedReady
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/name: mariadb-pdns
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: mariadb
serviceName: mariadb-pdns
template:
metadata:
labels:
app.kubernetes.io/name: mariadb-pdns
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: mariadb
spec:
containers:
- name: mariadb-pdns
image: mariadb:10.4
imagePullPolicy: Always
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mariadb-pdns-secret
key: password
volumeMounts:
- name: mariadb-pdns-storage
mountPath: /var/lib/mysql
- name: mariadb-pdns-config
mountPath: /etc/mysql/conf.d
ports:
- containerPort: 3306
resources:
limits:
cpu: 300m
memory: 256Mi
requests:
cpu: 50m
memory: 128Mi
volumes:
- name: mariadb-pdns-storage
persistentVolumeClaim:
claimName: mariadb-pdns-pvc
- name: mariadb-pdns-config
configMap:
name: mariadb-pdns-config
items:
- key: mariadb-override.cnf
path: mariadb-override.cnf
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: mariadb-pdns-svc
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: mariadb
name: mariadb-pdns
spec:
ports:
- name: tcp-mysql
port: 3306
protocol: TCP
targetPort: 3306
selector:
app.kubernetes.io/name: mariadb-pdns
sessionAffinity: None
type: ClusterIP
---
apiVersion: v1
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/name: mariadb-pdns-config
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: mariadb
name: mariadb-pdns-config
data:
mariadb-override.cnf: |
[mysqld]
collation-server = utf8mb4_unicode_ci
init-connect='SET NAMES utf8mb4'
character-set-server = utf8mb4
innodb_buffer_pool_size = 134217728
innodb_log_file_size = 134217728
innodb-log-files-in-group = 3
binlog_format = ROW
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
labels:
app.kubernetes.io/name: mariadb-pdns-pvc
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: mariadb
name: mariadb-pdns-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Secret
metadata:
labels:
app.kubernetes.io/name: mariadb-pdns-secret
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: mariadb
name: mariadb-pdns-secret
data:
username: cm9vdA==
password: cm9vdA==

View file

@ -0,0 +1,144 @@
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
app.kubernetes.io/name: pdns-master
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: master
name: pdns-master
spec:
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/name: pdns-master
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: master
template:
metadata:
creationTimestamp: null
labels:
app.kubernetes.io/name: pdns-master
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: master
spec:
nodeSelector:
node-role.kubernetes.io/pdns-master: "true"
containers:
- image: pschiffe/pdns-mysql:alpine
imagePullPolicy: IfNotPresent
name: pdns-master
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: PDNS_gmysql_host
value: "mariadb-pdns"
- name: PDNS_gmysql_port
value: "3306"
- name: PDNS_gmysql_user
valueFrom:
secretKeyRef:
name: mariadb-pdns-secret
key: username
- name: PDNS_gmysql_password
valueFrom:
secretKeyRef:
name: mariadb-pdns-secret
key: password
- name: PDNS_gmysql_dbname
value: "master_"
- name: PDNS_version_string
value: "anonymous"
- name: PDNS_master
value: "yes"
- name: PDNS_api
value: "yes"
- name: PDNS_api_key
valueFrom:
secretKeyRef:
name: master-pdns-secret
key: apikey
- name: PDNS_webserver
value: "yes"
- name: PDNS_webserver_address
value: "0.0.0.0"
- name: PDNS_webserver_allow_from
value: "127.0.0.1/32 10.244.0.0/16"
- name: PDNS_webserver_password
valueFrom:
secretKeyRef:
name: master-pdns-secret
key: webserver
- name: PDNS_default_ttl
value: "1500"
- name: PDNS_soa_minimum_ttl
value: "1200"
- name: PDNS_default_soa_name
value: "ns1.example.com"
- name: PDNS_default_soa_mail
value: "dnsmaster.example.com"
- name: PDNS_allow_axfr_ips
value: "10.0.0.2 10.0.0.3"
- name: PDNS_only_notify
value: "10.0.0.2 10.0.0.3"
- name: PDNS_dnsupdate
value: "yes"
- name: PDNS_allow_dnsupdate_from
value: "10.0.0.1/32 127.0.0.1/32 10.244.0.0/16"
resources:
limits:
cpu: 300m
memory: 256Mi
requests:
cpu: 50m
memory: 128Mi
ports:
- name: dns-udp
containerPort: 53
protocol: UDP
hostPort: 53
- name: dns-tcp
containerPort: 53
protocol: TCP
hostPort: 53
- containerPort: 8081
protocol: TCP
dnsPolicy: ClusterFirstWithHostNet
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
updateStrategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
---
apiVersion: v1
kind: Secret
metadata:
labels:
app.kubernetes.io/name: master-pdns-secret
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: master
name: master-pdns-secret
data:
apikey: MTIzNDU2Nzg5MA==
webserver: MDk4NzY1NDMyMQ==
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: master-api-pdns
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: master
name: master-api-pdns
spec:
type: ClusterIP
ports:
- port: 8081
targetPort: 8081
selector:
app.kubernetes.io/name: pdns-master

View file

@ -0,0 +1,96 @@
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
app.kubernetes.io/name: pdns-slave
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: slave
name: pdns-slave
spec:
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/name: pdns-slave
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: slave
template:
metadata:
creationTimestamp: null
labels:
app.kubernetes.io/name: pdns-slave
app.kubernetes.io/part-of: pdns
app.kubernetes.io/component: slave
spec:
nodeSelector:
node-role.kubernetes.io/pdns-slave: "true"
containers:
- image: pschiffe/pdns-mysql:alpine
imagePullPolicy: IfNotPresent
name: pdns-slave
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: PDNS_gmysql_host
value: "mariadb-pdns"
- name: PDNS_gmysql_port
value: "3306"
- name: PDNS_gmysql_user
valueFrom:
secretKeyRef:
name: mariadb-pdns-secret
key: username
- name: PDNS_gmysql_password
valueFrom:
secretKeyRef:
name: mariadb-pdns-secret
key: password
- name: PDNS_gmysql_dbname
value: "slave_"
- name: PDNS_version_string
value: "anonymous"
- name: PDNS_disable_axfr
value: "yes"
- name: PDNS_slave
value: "yes"
- name: PDNS_superslave
value: "yes"
- name: PDNS_allow_unsigned_supermaster
value: "no"
- name: PDNS_allow_notify_from
value: "10.0.0.1"
- name: SUPERMASTER_HOSTS
value: "ns1.example.com"
- name: SUPERMASTER_IPS
value: "10.0.0.1"
ports:
- name: dns-udp
containerPort: 53
protocol: UDP
hostPort: 53
- name: dns-tcp
containerPort: 53
protocol: TCP
hostPort: 53
resources:
limits:
cpu: 300m
memory: 256Mi
requests:
cpu: 50m
memory: 128Mi
securityContext:
privileged: false
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirstWithHostNet
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
updateStrategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate

View file

@ -12,17 +12,21 @@ fi
: "${PDNS_gmysql_password:=${MYSQL_ENV_MYSQL_PASSWORD:-powerdns}}"
: "${PDNS_gmysql_dbname:=${MYSQL_ENV_MYSQL_DATABASE:-powerdns}}"
export PDNS_gmysql_host PDNS_gmysql_port PDNS_gmysql_user PDNS_gmysql_password PDNS_gmysql_dbname
# 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}"
fi
# Create config file from template
envtpl < /pdns.conf.tpl > /etc/pdns/pdns.conf
export PDNS_gmysql_host PDNS_gmysql_port PDNS_gmysql_user PDNS_gmysql_password PDNS_gmysql_dbname
# Initialize DB if needed
MYSQL_COMMAND="mysql -h ${PDNS_gmysql_host} -P ${PDNS_gmysql_port} -u ${PDNS_gmysql_user} -p${PDNS_gmysql_password}"
until $MYSQL_COMMAND -e ';' ; do
>&2 echo 'MySQL is unavailable - sleeping'
sleep 1
sleep 3
done
$MYSQL_COMMAND -e "CREATE DATABASE IF NOT EXISTS ${PDNS_gmysql_dbname}"
@ -33,14 +37,30 @@ if [ "$MYSQL_NUM_TABLE" -eq 0 ]; then
$MYSQL_COMMAND -D "$PDNS_gmysql_dbname" < /usr/share/doc/pdns/schema.mysql.sql
fi
# Configure supermasters if needed
if [ "${SUPERMASTER_IPS:-}" ]; then
$MYSQL_COMMAND -D "$PDNS_gmysql_dbname" -e "TRUNCATE supermasters;"
MYSQL_INSERT_SUPERMASTERS=''
for i in $SUPERMASTER_IPS; do
MYSQL_INSERT_SUPERMASTERS="${MYSQL_INSERT_SUPERMASTERS} INSERT INTO supermasters VALUES('${i}', '$(hostname -f)', 'admin');"
done
$MYSQL_COMMAND -D "$PDNS_gmysql_dbname" -e "$MYSQL_INSERT_SUPERMASTERS"
if [ "${PDNS_superslave:-no}" == "yes" ]; then
# Configure supermasters if needed
if [ "${SUPERMASTER_IPS:-}" ]; then
$MYSQL_COMMAND -D "$PDNS_gmysql_dbname" -e "TRUNCATE supermasters;"
MYSQL_INSERT_SUPERMASTERS=''
if [ "${SUPERMASTER_COUNT:-0}" == "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
MYSQL_INSERT_SUPERMASTERS="${MYSQL_INSERT_SUPERMASTERS} INSERT INTO supermasters VALUES('${SUPERMASTER_IP}', '${SUPERMASTER_HOST}', 'admin');"
fi
i=$(( i + 1 ))
done
$MYSQL_COMMAND -D "$PDNS_gmysql_dbname" -e "$MYSQL_INSERT_SUPERMASTERS"
fi
fi
# Create config file from template
envtpl < /pdns.conf.tpl > /etc/pdns/pdns.conf
exec "$@"