A powerful tool that automatically syncs DNS records from active cloud instances to DNS zones. It monitors your cloud infrastructure and keeps your DNS records up-to-date with changing IP addresses of your instances.
- Automatic DNS Synchronization: Monitors cloud instances and automatically updates DNS records with their current IP addresses
- Multi-Cloud Support: Currently supports DigitalOcean (with extensible architecture for other cloud providers)
- Weighted Round-Robin DNS: Distributes traffic across multiple instances using weighted DNS records
- Health Checks: Includes readiness probes to ensure only healthy instances are included in DNS
- Flexible Configuration: JSON-based configuration with support for multiple sync jobs
- IP Type Selection: Choose between public or private IP addresses for DNS records
- Ignore Lists: Exclude specific instances from DNS updates using ignore lists
- Concurrent Processing: Runs multiple sync jobs in parallel for better performance
- Tag-based Filtering: Filter instances by tags for targeted DNS updates
- Configurable Intervals: Set custom polling intervals for different sync jobs
Before using dns-sync, ensure you have:
- DigitalOcean: API token with read access to droplets
- Google Cloud DNS: Service account with DNS administrator permissions
- Google Cloud project with DNS zones configured
- Go 1.16+ (for building from source)
- Network access to cloud provider APIs
- Appropriate IAM permissions for DNS zone management
Download the latest release from the releases page:
# Linux AMD64
wget https://github.com/chandanpasunoori/dns-sync/releases/download/v0.0.3/dns-sync_0.0.3_linux_amd64.tar.gz
tar -xzf dns-sync_0.0.3_linux_amd64.tar.gz
chmod +x dns-sync
sudo mv dns-sync /usr/local/bin/
# Verify installation
dns-sync --versionbrew tap chandanpasunoori/tap
brew install dns-syncgit clone https://github.com/chandanpasunoori/dns-sync.git
cd dns-sync
go mod tidy
go build -o dns-sync .# Pull the image
docker pull ghcr.io/chandanpasunoori/dns-sync:latest
# Or build locally
docker build -t dns-sync .dns-sync uses JSON configuration files to define sync jobs. Each job specifies a source (cloud provider) and destination (DNS zone).
Set the following environment variables for authentication:
# DigitalOcean API Token
export DIGITALOCEAN_ACCESS_TOKEN="your_digitalocean_token"
# Google Cloud credentials (one of the following)
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account.json"
# OR set individual fields
export GOOGLE_CLOUD_PROJECT="your-project-id"The configuration file contains an array of jobs, each defining a sync operation:
{
"jobs": [
{
"name": "job-name",
"suspend": false,
"source": { /* source configuration */ },
"tagName": "instance-tag",
"destination": { /* destination configuration */ }
}
]
}Here's a complete example configuration (sample-config.json):
{
"jobs": [
{
"name": "web-servers-sync",
"suspend": false,
"source": {
"type": "digitalocean",
"cloud": "digitalocean",
"interval": "30s"
},
"tagName": "web-server",
"destination": {
"type": "gcp",
"project": "your-gcp-project-id",
"zone": "your-zone-id",
"zoneName": "example.com.",
"recordName": "api.example.com.",
"recordType": "A",
"ipType": "public",
"ttl": "300s",
"readinessProbe": {
"period": "10s",
"timeout": "5s",
"successThreshold": 2,
"failureThreshold": 3,
"ipType": "public",
"httpGet": {
"path": "/health",
"port": 8080,
"scheme": "HTTP"
},
"progressDeadline": "300s"
},
"ignoreListFilePath": "/path/to/ignore-list.json"
}
}
]
}- name: Unique identifier for the job
- suspend: Set to
trueto disable the job - tagName: DigitalOcean tag to filter instances
- source: Source configuration (cloud provider)
- destination: Destination configuration (DNS provider)
- type: Cloud provider type (
"digitalocean") - cloud: Cloud provider name (
"digitalocean") - interval: Polling interval (e.g.,
"30s","1m","5m")
- type: DNS provider type (
"gcp"for Google Cloud DNS) - project: Google Cloud project ID
- zone: DNS zone ID in Google Cloud
- zoneName: DNS zone name (must end with
.) - recordName: DNS record name (must end with
.) - recordType: DNS record type (
"A"or"AAAA") - ipType: IP address type (
"public"or"private") - ttl: DNS record TTL (e.g.,
"300s","1h") - readinessProbe: (Optional) Health check configuration
- ignoreListFilePath: (Optional) Path to ignore list file
- period: How often to check health
- timeout: Request timeout
- successThreshold: Consecutive successful checks needed
- failureThreshold: Consecutive failed checks before marking unhealthy
- ipType: IP type to use for health checks
- httpGet: HTTP health check configuration
- path: Health check endpoint path
- port: Port number
- scheme:
"HTTP"or"HTTPS"
- progressDeadline: Maximum time to wait for health checks
Create an ignore list file to exclude specific instances from DNS updates:
{
"nodes": [
{
"name": "job-name:instance-name",
"privateIp": "10.0.0.100",
"publicIp": "203.0.113.100"
}
]
}The node name format is {job-name}:{instance-name}.
# Run with default config file (app.json)
dns-sync
# Specify custom config file
dns-sync --config /path/to/config.json
# Enable verbose logging
dns-sync --config config.json --verbose
# Check version
dns-sync --version# Run with config file mounted
docker run -d \
--name dns-sync \
-v /path/to/config.json:/app.json \
-v /path/to/service-account.json:/credentials.json \
-e GOOGLE_APPLICATION_CREDENTIALS=/credentials.json \
-e DIGITALOCEAN_ACCESS_TOKEN="your_token" \
ghcr.io/chandanpasunoori/dns-sync:latest
# Check logs
docker logs dns-syncapiVersion: apps/v1
kind: Deployment
metadata:
name: dns-sync
spec:
replicas: 1
selector:
matchLabels:
app: dns-sync
template:
metadata:
labels:
app: dns-sync
spec:
containers:
- name: dns-sync
image: ghcr.io/chandanpasunoori/dns-sync:latest
args: ["--config", "/config/app.json"]
env:
- name: DIGITALOCEAN_ACCESS_TOKEN
valueFrom:
secretKeyRef:
name: dns-sync-secrets
key: digitalocean-token
- name: GOOGLE_APPLICATION_CREDENTIALS
value: /credentials/service-account.json
volumeMounts:
- name: config
mountPath: /config
- name: credentials
mountPath: /credentials
volumes:
- name: config
configMap:
name: dns-sync-config
- name: credentials
secret:
secretName: gcp-credentials-
Create API Token:
- Go to DigitalOcean Control Panel β API β Generate New Token
- Give it read access to droplets
- Copy the token and set it as
DIGITALOCEAN_ACCESS_TOKEN
-
Tag Your Instances:
- Tag your droplets with meaningful tags (e.g.,
web-server,database) - These tags will be used to filter instances for DNS updates
- Tag your droplets with meaningful tags (e.g.,
-
Create Service Account:
gcloud iam service-accounts create dns-sync-service \ --display-name="DNS Sync Service Account" -
Grant DNS Admin Role:
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \ --member="serviceAccount:dns-sync-service@YOUR_PROJECT_ID.iam.gserviceaccount.com" \ --role="roles/dns.admin"
-
Create and Download Key:
gcloud iam service-accounts keys create service-account.json \ --iam-account=dns-sync-service@YOUR_PROJECT_ID.iam.gserviceaccount.com
-
Create DNS Zone (if not exists):
gcloud dns managed-zones create example-zone \ --dns-name="example.com." \ --description="Example zone for dns-sync"
-
Create Configuration File:
cp sample-config.json app.json # Edit app.json with your specific values -
Set Environment Variables:
export DIGITALOCEAN_ACCESS_TOKEN="your_digitalocean_token" export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account.json"
-
Test Configuration:
dns-sync --config app.json --verbose
- Instance Discovery: Polls DigitalOcean API for droplets with specified tags
- Health Checks: (Optional) Performs HTTP health checks on discovered instances
- IP Collection: Collects public or private IP addresses from healthy instances
- DNS Update: Updates Google Cloud DNS with weighted round-robin records
- Continuous Monitoring: Repeats the process based on configured intervals
dns-sync creates weighted DNS records where traffic is distributed across multiple instances:
- Total weight: 1000 points
- Weight per instance: 1000 Γ· number_of_healthy_instances
- Automatically adjusts as instances are added/removed
-
Authentication Errors:
Error: failed to authenticate with DigitalOcean- Verify
DIGITALOCEAN_ACCESS_TOKENis set correctly - Check token permissions in DigitalOcean control panel
- Verify
-
Google Cloud DNS Errors:
Error: failed to update DNS record- Verify service account has DNS admin permissions
- Check
GOOGLE_APPLICATION_CREDENTIALSpath is correct - Ensure DNS zone exists and zone name ends with
.
-
No Instances Found:
Info: total droplet count: 0- Check if droplets have the specified tag
- Verify droplets are in running state
- Check DigitalOcean API token permissions
-
Health Check Failures:
Error: health check failed for instance- Verify health check endpoint is accessible
- Check firewall rules allow health check traffic
- Adjust health check thresholds if needed
Enable verbose logging for detailed troubleshooting:
dns-sync --config app.json --verboseKey log messages to monitor:
getting node ips- Instance discovery phasetotal droplet count: X- Number of instances foundhealth check passed/failed- Health check resultsupdating record- DNS update operationsweightage: X- Load balancing calculations
- Store API tokens and service account keys securely
- Use least-privilege access for service accounts
- Regularly rotate API tokens and keys
- Monitor dns-sync logs for unauthorized access attempts
- Use private networks where possible for internal services
- Instance Discovery: Number of instances found per job
- Health Check Success Rate: Percentage of successful health checks
- DNS Update Frequency: How often DNS records are updated
- Error Rates: Authentication and API call failures
Set up log monitoring for:
- Authentication failures
- API rate limits
- DNS update errors
- Health check timeouts
Contributions are welcome! Please see the contributing guidelines for details.
-
Clone the repository:
git clone https://github.com/chandanpasunoori/dns-sync.git cd dns-sync -
Install dependencies:
go mod tidy
-
Build and test:
go build -o dns-sync . go test ./...
This project is licensed under the MIT License - see the LICENSE file for details.