GitOps DNS Management
From Ansible Automation to Full CI/CD Pipeline
Building on our Technitium DNS automation, we’ll implement GitLab CI/CD for a complete GitOps workflow with automatic deployment triggers, runner configuration, and Infrastructure as Code.
Previously: Manual Ansible
In a previous post, we automated Technitium DNS management using Ansible playbooks: exporting zones for backup, importing zones for deployment, and updating servers for maintenance. Ansible helped us eliminate manual SSH sessions and GUI clicking.
The Gap: You still had to run playbooks manually when DNS changes were needed, and there was no version control integration, no automatic triggers, no audit trail.
Today, we’re evolving to “GitOps DNS management,” where Git commits automatically trigger infrastructure changes via CI/CD pipelines.
GitOps Architecture
🔄 Git Repository
DNS zone files, Ansible playbooks, and CI configuration stored in GitLab. Every change is tracked, reviewed, and versioned.
⚡ GitLab CI/CD
Pipeline automatically triggers on zone file changes. Executes Ansible playbooks against DNS servers with proper authentication and error handling.
🎯 GitLab Runner
Self-hosted runner with Ansible, SSH keys, and network access to DNS servers. Executes jobs in isolated environments with proper secrets management.
GitOps Workflow
Edit Zone File → Git Commit → Pipeline Trigger → Ansible Deploy → DNS Updated
Repository Structure
Organized for GitOps
Your Ansible repository gets enhanced with CI/CD configuration while maintaining the existing playbook structure.
# GitLab Repository: projects/ansible
ansible/
├── .gitlab-ci.yml # CI/CD pipeline definition
├── playbooks/
│ └── dns/
│ ├── dns_deploy.yml # Import/deploy playbook
│ ├── dns_export.yml # Export/backup playbook
│ └── records/
│ └── example.zone # Zone file (triggers CI)
└── inventory/
└── dns_servers.yml # DNS server inventory
GitLab CI Pipeline
Automated DNS Deployment
Pipeline triggers automatically when zone files change, executes your existing Ansible playbook, and deploys DNS updates without manual intervention.
# .gitlab-ci.yml - DNS GitOps Pipeline
stages:
- dns-deploy
deploy_dns_changes:
stage: dns-deploy
image: alpine:latest
before_script:
# Resolve DNS server hostnames in container
- echo "$DNS_IP dns1.example.local" >> /etc/hosts
# Install required tools
- apk add --no-cache ansible openssh-client
# Configure SSH agent with private key
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | base64 -d | ssh-add -
# Add known hosts to prevent SSH prompts
- mkdir -p ~/.ssh
- ssh-keyscan -t rsa dns1.example.local >> ~/.ssh/known_hosts
script:
- cd playbooks/dns
# Create temporary vault password file
- echo "$ANSIBLE_VAULT_PASSWORD" > /tmp/vault_pass
# Execute DNS deployment playbook
- ansible-playbook dns_deploy.yml -i ../../inventory/dns_servers.yml --vault-password-file /tmp/vault_pass
- rm /tmp/vault_pass
only:
changes:
- playbooks/dns/records/*.zone
after_script:
- rm -f /tmp/vault_pass
Pipeline Features
- Smart triggering: Only runs when zone files change
- DNS resolution: Container can reach your DNS servers
- Security: SSH keys and vault passwords from GitLab variables
- Isolation: Each job runs in fresh Alpine container
- Cleanup: Temporary files removed automatically
GitLab Variables Setup
Configure CI/CD Variables
Store sensitive credentials in GitLab project variables. Navigate to your project’s CI/CD settings to add these required variables.
Step 1: Access GitLab Variables
- Go to your GitLab project
- Navigate to Settings → CI/CD
- Expand the “Variables” section
- Click “Add variable” for each required variable
SSH_PRIVATE_KEY
Base64-encoded SSH private key for server access.
Type: Variable • Visible • Expand: ✓ Yes
ANSIBLE_VAULT_PASSWORD
Password for decrypting Ansible Vault encrypted files.
Type: Variable • Visible • Expand: ✓ Yes
DNS_IP
IP address of your primary DNS server for hostname resolution.
Type: Variable • Visibility: Visible
# Step 2: Generate base64 SSH key value
cat ~/.ssh/id_ed25519 | base64 -w 0
# Copy the output and use it as SSH_PRIVATE_KEY value
# Example output: LS0tLS1CRUdJTi0tLS0t...
# Step 3: Variable configuration in GitLab:
SSH_PRIVATE_KEY = LS0tLS1CRUdJTi... # Your base64 key
ANSIBLE_VAULT_PASSWORD = your-vault-password # Your vault password
DNS_IP = 192.168.1.10 # Your DNS server IP
GitLab Runner Setup
Self-Hosted Runner
Install GitLab Runner on a server with network access to your DNS infrastructure. This runner will execute the Ansible playbooks when zone files change.
# Step 1: Install GitLab Runner
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
sudo apt-get install gitlab-runner
# Step 2: Create runner in GitLab UI first
# Go to: GitLab → Admin → Runners → New instance runner
# Configuration:
# - Description: DNS Automation Runner
# - Tags: (leave empty for untagged jobs)
# - Run untagged jobs: ✓ Enabled
# - Copy the authentication token from the UI
# Step 3: Register runner with authentication token
sudo gitlab-runner register \
--url https://your-gitlab.example.com \
--token glrt-your-authentication-token
# When prompted, enter:
# Description: DNS Automation Runner
# Executor: docker
# Default image: alpine:latest
# Step 4: Start runner service
sudo gitlab-runner start
sudo systemctl enable gitlab-runner
Runner Requirements
- Network access: Runner server must reach your DNS servers
- Docker executor: Provides clean, isolated environments for each job
- No tags required: Runner accepts all untagged jobs automatically
- Authentication token: Generated in GitLab UI, not command line
GitOps Workflow in Action
Complete DNS Change Process
From local zone file edit to live DNS infrastructure – the full GitOps workflow with automatic deployment.
# 1. Clone your GitLab repository
git clone [email protected]:projects/ansible.git
cd ansible
# 2. Edit DNS zone file locally
vim playbooks/dns/records/example.zone
# Add new service:
webapp 3600 IN A 192.168.1.100
api 3600 IN CNAME webapp.example.local.
# 3. Commit and push changes
git add playbooks/dns/records/example.zone
git commit -m "DNS: Add webapp and api endpoints"
git push origin main
# 4. GitLab CI automatically:
# - Detects zone file change
# - Triggers dns-deploy pipeline
# - Spins up Alpine container
# - Installs Ansible and SSH
# - Configures authentication
# - Executes dns_deploy.yml playbook
# - Updates Technitium DNS server
# - Zone transfer will replicate to secondary if configured
# 5. Verify deployment
dig @192.168.1.10 webapp.example.local
dig @192.168.1.10 api.example.local
⚡ Automatic Trigger
Git push instantly triggers pipeline
🔐 Secure Deployment
SSH keys and vault passwords from GitLab secrets
📝 Audit Trail
Every change tracked in Git commits and CI logs
🔄 Zone Replication
Primary updates automatically replicate to secondary DNS
GitOps Benefits
Infrastructure as Code
- DNS configuration in version control
- Complete change history and rollback capability
- Peer review via merge requests
- Branching for experimental changes
Automated Deployment
- Git push triggers immediate deployment
- No manual SSH or playbook execution
- Consistent deployment process
- Error handling and notifications
Security & Compliance
- Centralized secrets management
- Audit trail for all infrastructure changes
- Access control via GitLab permissions
- Isolated execution environments
DNS GitOps Complete
We’ve evolved from manual DNS management to Ansible automation to full GitOps deployment with GitLab CI/CD. Your DNS infrastructure now follows modern DevOps practices with automatic deployment, version control, and audit trails. Every DNS change is now a git commit away.
🚀 Ready for Production
