시리즈 소개
시리즈 구성
- 왜 GitOps인가?
- Kubernetes 클러스터와 Traefik
- ExternalDNS - 자동 DNS 레코드 관리 (현재 글)
- SOPS + age - 시크릿 암호화
- ArgoCD - GitOps 배포 자동화
ExternalDNS란?
ExternalDNS는 Kubernetes 리소스(Service, Ingress 등)를 기반으로 DNS 레코드를 자동으로 생성/관리하는 컨트롤러입니다.
왜 ExternalDNS가 필요한가?
ExternalDNS 없이:
ExternalDNS 사용 시:
지원하는 DNS Provider
ExternalDNS는 다양한 DNS 프로바이더를 지원합니다:
- DigitalOcean DNS (이 글에서 사용)
- Cloudflare
- AWS Route53
- Google Cloud DNS
- Azure DNS
- 그 외 다수
ExternalDNS 설치
Helmfile 설정
# helmfile.yaml
repositories:
- name: bitnami
url: https://charts.bitnami.com/bitnami
releases:
- name: external-dns
namespace: external-dns
createNamespace: true
chart: bitnami/external-dns
version: 8.8.2
values:
- ./values/external-dns/common.yaml
- ./values/external-dns/{{ .Environment.Name }}.yamlvalues 파일
# values/external-dns/common.yaml
provider: digitalocean
# 어떤 소스에서 DNS 정보를 가져올지
sources:
- service
- ingress
- traefik-proxy # Traefik IngressRoute 지원
# traefik-proxy source 사용 시 필요
extraArgs:
traefik-disable-legacy:
# 관리할 도메인 필터
domainFilters:
- "example.com"
# 동기화 주기
interval: "1m"
# 동기화 정책: sync (삭제도 동기화) vs upsert-only (추가만)
policy: sync
# TXT 레코드로 소유권 관리
registry: txt
txtOwnerId: "external-dns"
logLevel: info
# DigitalOcean API 토큰이 저장된 Secret
digitalocean:
secretName: digitalocean-dns-secret
rbac:
create: true
serviceAccount:
create: true
name: external-dnsDigitalOcean API Token Secret 생성
ExternalDNS가 DigitalOcean DNS API를 호출하려면 API 토큰이 필요합니다.
# DigitalOcean Console에서 API Token 생성
# https://cloud.digitalocean.com/account/api/tokens
# Secret 생성
kubectl create secret generic digitalocean-dns-secret \
--namespace external-dns \
--from-literal=digitalocean_token=<YOUR_DO_API_TOKEN>이 Secret은 3편 SOPS + age에서 암호화하여 Git에 저장하는 방법을 다룹니다.
설치 실행
helmfile -e dev sync설치 확인
# Pod 상태 확인
kubectl get pods -n external-dns
# 로그 확인
kubectl logs -n external-dns -l app.kubernetes.io/name=external-dns -f동작 방식
DNS 레코드 생성 흐름
TXT 레코드의 역할
ExternalDNS는 각 DNS 레코드에 대응하는 TXT 레코드를 함께 생성합니다.
# 실제 생성되는 레코드 예시
app.example.com. A 143.xxx.xxx.xxx
app.example.com. TXT "heritage=external-dns,external-dns/owner=external-dns"TXT 레코드가 필요한 이유:
- 소유권 표시: ExternalDNS가 관리하는 레코드임을 표시
- 충돌 방지: 다른 ExternalDNS 인스턴스나 수동 레코드와 구분
- 안전한 삭제:
policy: sync사용 시 자신이 생성한 레코드만 삭제
Ingress와 연동
어노테이션 사용
Ingress에 external-dns.alpha.kubernetes.io/hostname 어노테이션을 추가하면 해당 도메인으로 DNS 레코드가 생성됩니다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
annotations:
# ExternalDNS가 이 어노테이션을 읽어 DNS 레코드 생성
external-dns.alpha.kubernetes.io/hostname: my-app.example.com
# Traefik TLS 설정
traefik.ingress.kubernetes.io/router.tls: "true"
traefik.ingress.kubernetes.io/router.tls.certresolver: letsencrypt
spec:
ingressClassName: traefik
rules:
- host: my-app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
name: http실제 사용 예시 (JVM 앱)
저희 팀에서 사용하는 실제 values 파일입니다:
# values/kohi-core-api/values.yaml
nameOverride: kohi-core-api
fullnameOverride: kohi-core-api
replicaCount: 2
ingress:
annotations:
traefik.ingress.kubernetes.io/router.tls: "true"
traefik.ingress.kubernetes.io/router.tls.certresolver: letsencrypt
external-dns.alpha.kubernetes.io/hostname: kohi-api.dev.example.com
hosts:
- host: kohi-api.dev.example.com
paths:
- path: /
pathType: Prefix
tls:
- hosts:
- kohi-api.dev.example.com
app:
resources:
requests:
cpu: 300m
memory: 768Mi
service:
type: ClusterIP
ports:
- name: http
port: 8080
targetPort: 8080
protocol: TCP배포 시 자동으로 일어나는 일:
- ArgoCD가 Helm Chart를 배포
- Ingress 리소스 생성
- ExternalDNS가 Ingress 감지
kohi-api.dev.example.comA 레코드 자동 생성- Traefik이 Let’s Encrypt 인증서 자동 발급
- HTTPS로 서비스 접근 가능
환경별 도메인 구조
개발/운영 환경을 서브도메인으로 구분하면 관리가 편합니다.
example.com
├── dev.example.com # 개발 환경
│ ├── api.dev.example.com
│ └── app.dev.example.com
├── staging.example.com # 스테이징 환경
└── example.com # 운영 환경
├── api.example.com
└── app.example.com환경별 values 파일
# values/external-dns/dev.yaml
domainFilters:
- "dev.example.com"
# values/external-dns/prod.yaml
domainFilters:
- "example.com"트러블슈팅
DNS 레코드가 생성되지 않는 경우
# 1. ExternalDNS 로그 확인
kubectl logs -n external-dns -l app.kubernetes.io/name=external-dns
# 2. Ingress 어노테이션 확인
kubectl get ingress my-app -o yaml | grep external-dns
# 3. domainFilters 확인 (필터에 해당 도메인이 포함되어 있는지)
# 4. API 토큰 권한 확인 (DigitalOcean)
# DNS write 권한이 있는지 확인일반적인 오류와 해결
| 증상 | 원인 | 해결 |
|---|---|---|
level=error msg="failed to list... |
API 토큰 문제 | Secret 확인, 토큰 권한 확인 |
| 레코드 생성 안됨 | domainFilters 미포함 | 도메인 필터 설정 확인 |
| 레코드 중복 | txtOwnerId 충돌 | 각 환경별 고유 ID 사용 |
다음 글 예고
다음 글에서는 SOPS + age를 사용하여 Kubernetes Secret을 안전하게 Git에 저장하는 방법을 다룹니다. API 토큰, 데이터베이스 비밀번호 등 민감한 정보도 GitOps로 관리할 수 있습니다.