疑問1: external-dnsのPolicyの種類って何がある?
https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/aws.md --policy=upsert-only
と書いてあるが、他にどんなpolicyがあるのか見当たらなかった。
- --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization
policyの種類
-
sync
: Create, UpdateOld, UpdateNew, DeleteのすべてがActionに対応 -
upsert-only
: Create, UpdateOld, UpdateNewのみ対応 -
create-only
: Createのみ対応- Create-only policyというissueからスタートして、 このprでマージされ、v0.5.17で追加された
疑問2: これらのpolicyがどうやって適応されてる?
内部ロジック読み解き
全体像
ロジック読み終わってから書いた図
1. policyがcfg.policyの値によって設定されている (main.go
)
policy, exists := plan.Policies[cfg.Policy]
plan.Policies
は?
1.1 plan.Policies
はStringからPolicyへのmapである (plan/policy.go
)
// Policies is a registry of available policies.
var Policies = map[string]Policy{
"sync": &SyncPolicy{},
"upsert-only": &UpsertOnlyPolicy{},
"create-only": &CreateOnlyPolicy{},
}
sync
, upsert-only
, create-only
それぞれに対応するPolicyに変換
2. Policyを渡して、Controllerを初期化 (main.go
)
ctrl := controller.Controller{
Source: endpointsSource,
Registry: r,
Policy: policy,
Interval: cfg.Interval,
DomainFilter: domainFilter,
ManagedRecordTypes: cfg.ManagedDNSRecordTypes,
MinEventSyncInterval: cfg.MinEventSyncInterval,
}
3. MainはControllerのRunOnce()かRun()を呼ぶ
if cfg.Once {
err := ctrl.RunOnce(ctx)
if err != nil {
log.Fatal(err)
}
os.Exit(0)
}
if cfg.UpdateEvents {
// Add RunOnce as the handler function that will be called when ingress/service sources have changed.
// Note that k8s Informers will perform an initial list operation, which results in the handler
// function initially being called for every Service/Ingress that exists
ctrl.Source.AddEventHandler(ctx, func() { ctrl.ScheduleRunOnce(time.Now()) })
}
ctrl.ScheduleRunOnce(time.Now())
ctrl.Run(ctx)
4. Controller内のRunもRunOnceを呼ぶ (controller/controller.go
)
// Run runs RunOnce in a loop with a delay until context is canceled
func (c *Controller) Run(ctx context.Context) {
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
if c.ShouldRunOnce(time.Now()) {
if err := c.RunOnce(ctx); err != nil {
log.Error(err)
}
}
select {
case <-ticker.C:
case <-ctx.Done():
log.Info("Terminating main controller loop")
return
}
}
}
-> RunOnceにメインロジックがある
5. RunOnce()でPlanの初期化 (controller/controller.go
)
controller/controller.go#L148-L155
plan := &plan.Plan{
Policies: []plan.Policy{c.Policy},
Current: records,
Desired: endpoints,
DomainFilter: c.DomainFilter,
PropertyComparator: c.Registry.PropertyValuesEqual,
ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME},
}
Policies: []plan.Policy{c.Policy}
でControllerにSetされたPolicyがセットされている。
6. plan.Calculate()
が呼ばる (controller/controller.go
)
plan = plan.Calculate()
6.1 plan.Calculate()
で changesの更新とPlanの初期化し、planを返す (plan/plan.go
)
for _, pol := range p.Policies {
changes = pol.Apply(changes) // changesを更新
}
plan := &Plan{ // Planを初期化
Current: p.Current,
Desired: p.Desired,
Changes: changes,
ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME},
}
return plan # 返す
changes = pol.Apply(changes)
は?
6.2 changes = pol.Apply(changes)
で Policyごとに、で対応するChangesを返す (plan/policy.go
)
plan/policy.go#L31-L59 のApply
関数がそれぞれのPolicyに定義されている
-
SyncPolicy
ならchanges
をそのまま返す// Apply applies the sync policy which returns the set of changes as is. func (p *SyncPolicy) Apply(changes *Changes) *Changes { return changes }
-
UpserOnlyPolicy
ならCreate, UpdateOld, UpdateNew
だけを返す// Apply applies the upsert-only policy which strips out any deletions. func (p *UpsertOnlyPolicy) Apply(changes *Changes) *Changes { return &Changes{ Create: changes.Create, UpdateOld: changes.UpdateOld, UpdateNew: changes.UpdateNew, } }
-
CreateOnlyPolicy
ならCreate
だけを返す// Apply applies the create-only policy which strips out updates and deletions. func (p *CreateOnlyPolicy) Apply(changes *Changes) *Changes { return &Changes{ Create: changes.Create, } }
7. 上のステップでセットされたplan
を使って変更をApply (controller/controller.go
)
err = c.Registry.ApplyChanges(ctx, plan.Changes)
Policyに対応するChangesで変更がApplyされている