Kubernetes Deployment¶
Deploy bindcar to Kubernetes using the sidecar pattern.
Prerequisites¶
- Kubernetes 1.24 or later
- kubectl configured with cluster access
- BIND9 container image
Sidecar Pattern¶
bindcar runs alongside BIND9 in the same pod, sharing a volume for zone files.
Architecture¶
┌─────────────────────────────────────┐
│ Pod │
│ ┌──────────────┐ ┌─────────────┐ │
│ │ BIND9 │ │ bindcar │ │
│ │ Container │ │ Container │ │
│ │ :53 │ │ :8080 │ │
│ └──────────────┘ └─────────────┘ │
│ │ │ │
│ └────────────────┘ │
│ emptyDir Volume │
│ /var/cache/bind │
└─────────────────────────────────────┘
Basic Deployment¶
Pod Specification¶
apiVersion: v1
kind: Pod
metadata:
name: dns-server
labels:
app: dns
spec:
containers:
# BIND9 Container
- name: bind9
image: ubuntu/bind9:latest
ports:
- name: dns-tcp
containerPort: 53
protocol: TCP
- name: dns-udp
containerPort: 53
protocol: UDP
volumeMounts:
- name: zones
mountPath: /var/cache/bind
- name: config
mountPath: /etc/bind
# bindcar Container
- name: bindcar
image: ghcr.io/firestoned/bindcar:latest
ports:
- name: api
containerPort: 8080
protocol: TCP
env:
- name: BIND_ZONE_DIR
value: "/var/cache/bind"
- name: API_PORT
value: "8080"
- name: RUST_LOG
value: "info"
- name: DISABLE_AUTH
value: "false"
volumeMounts:
- name: zones
mountPath: /var/cache/bind
livenessProbe:
httpGet:
path: /api/v1/health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /api/v1/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: zones
emptyDir: {}
- name: config
configMap:
name: bind9-config
Deployment¶
For production, use a Deployment for replica management:
apiVersion: apps/v1
kind: Deployment
metadata:
name: dns-server
spec:
replicas: 1 # BIND9 typically runs as single instance
selector:
matchLabels:
app: dns
template:
metadata:
labels:
app: dns
spec:
containers:
- name: bind9
image: ubuntu/bind9:latest
# ... (same as pod spec)
- name: bindcar
image: ghcr.io/firestoned/bindcar:latest
# ... (same as pod spec)
Service¶
Expose bindcar API:
apiVersion: v1
kind: Service
metadata:
name: bindcar-api
spec:
selector:
app: dns
ports:
- name: api
port: 8080
targetPort: 8080
protocol: TCP
type: ClusterIP
Expose BIND9 DNS:
apiVersion: v1
kind: Service
metadata:
name: dns-service
spec:
selector:
app: dns
ports:
- name: dns-tcp
port: 53
protocol: TCP
- name: dns-udp
port: 53
protocol: UDP
type: LoadBalancer # or NodePort
Authentication¶
ServiceAccount¶
Create a ServiceAccount for API clients:
Get Token¶
# Kubernetes 1.24+
TOKEN=$(kubectl create token bindcar-client)
# Use token
curl -H "Authorization: Bearer $TOKEN" \
http://bindcar-api:8080/api/v1/zones
RBAC (Optional)¶
Limit what the bindcar service account can do:
apiVersion: v1
kind: ServiceAccount
metadata:
name: bindcar
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: bindcar-role
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: bindcar-binding
subjects:
- kind: ServiceAccount
name: bindcar
roleRef:
kind: Role
name: bindcar-role
apiGroup: rbac.authorization.k8s.io
ConfigMap for BIND9¶
apiVersion: v1
kind: ConfigMap
metadata:
name: bind9-config
data:
named.conf: |
options {
directory "/var/cache/bind";
listen-on { any; };
listen-on-v6 { any; };
allow-query { any; };
};
controls {
inet 127.0.0.1 allow { localhost; } keys { "rndc-key"; };
};
key "rndc-key" {
algorithm hmac-sha256;
secret "your-secret-key-here";
};
Persistent Storage¶
For production, use PersistentVolumes:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: bind9-zones
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
# In pod spec:
volumes:
- name: zones
persistentVolumeClaim:
claimName: bind9-zones
Resource Limits¶
containers:
- name: bindcar
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
Security Context¶
Run as non-root:
Network Policies¶
Restrict traffic to bindcar:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: bindcar-netpol
spec:
podSelector:
matchLabels:
app: dns
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: trusted-namespace
ports:
- protocol: TCP
port: 8080
Complete Example¶
Deploy everything:
kubectl apply -f - <<EOF
apiVersion: v1
kind: Namespace
metadata:
name: dns-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: bindcar
namespace: dns-system
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dns-server
namespace: dns-system
spec:
replicas: 1
selector:
matchLabels:
app: dns
template:
metadata:
labels:
app: dns
spec:
serviceAccountName: bindcar
containers:
- name: bind9
image: ubuntu/bind9:latest
ports:
- containerPort: 53
name: dns
volumeMounts:
- name: zones
mountPath: /var/cache/bind
- name: bindcar
image: ghcr.io/firestoned/bindcar:latest
ports:
- containerPort: 8080
name: api
env:
- name: BIND_ZONE_DIR
value: "/var/cache/bind"
- name: RUST_LOG
value: "info"
volumeMounts:
- name: zones
mountPath: /var/cache/bind
livenessProbe:
httpGet:
path: /api/v1/health
port: 8080
readinessProbe:
httpGet:
path: /api/v1/ready
port: 8080
volumes:
- name: zones
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: bindcar-api
namespace: dns-system
spec:
selector:
app: dns
ports:
- port: 8080
targetPort: 8080
type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
name: dns-service
namespace: dns-system
spec:
selector:
app: dns
ports:
- name: dns-tcp
port: 53
protocol: TCP
- name: dns-udp
port: 53
protocol: UDP
type: LoadBalancer
EOF
Verify Deployment¶
# Check pods
kubectl get pods -n dns-system
# Check services
kubectl get svc -n dns-system
# Test health
kubectl port-forward -n dns-system svc/bindcar-api 8080:8080
curl http://localhost:8080/api/v1/health
# Check logs
kubectl logs -n dns-system -l app=dns -c bindcar
Troubleshooting¶
See Troubleshooting for common issues.
Next Steps¶
- Configuration - Configure bindcar
- Monitoring - Monitor your deployment
- Troubleshooting - Debug issues