LoginSignup
1
1

More than 1 year has passed since last update.

[Kubernetes] external-dnsのPolicyの種類とそれぞれのPolicyに対応する変更ロジック

Last updated at Posted at 2021-06-08

疑問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のみ対応

疑問2: これらのpolicyがどうやって適応されてる?

内部ロジック読み解き

全体像

ロジック読み終わってから書いた図

external-dns-policy.png

1. policyがcfg.policyの値によって設定されている (main.go)

main.go#L337

    policy, exists := plan.Policies[cfg.Policy]

plan.Policies は?

1.1 plan.PoliciesはStringからPolicyへのmapである (plan/policy.go)

plan/policy.go#L25-L29

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)

main.go#L342-L350

main.go#L342-L350
    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()を呼ぶ

main.go#L352-L370

main.go#L352-L370
    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)

controller.go#L187-L204

controller.go#L187-L204
// 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

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)

controller/controller.go#L157

controller.go#L157
    plan = plan.Calculate()

6.1 plan.Calculate()で changesの更新とPlanの初期化し、planを返す (plan/plan.go)

plan/plan.go#L155-L166 で、

plan.go#L155-L166
    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-L59Apply 関数がそれぞれのPolicyに定義されている

  1. SyncPolicy なら changesをそのまま返す

    // Apply applies the sync policy which returns the set of changes as is.
    func (p *SyncPolicy) Apply(changes *Changes) *Changes {
        return changes
    }
    
  2. 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,
        }
    }
    
  3. 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)

controller.go#L159

controller.go#L159
    err = c.Registry.ApplyChanges(ctx, plan.Changes)

Policyに対応するChangesで変更がApplyされている

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1