hisamounaのブログ

アウトプットを習慣化するためのブログ

cluster-autoscalerのコードを読む (ASG一覧をどうやって取得しているか)

EKSでcluster-autoscalerを利用してASGをスケールさせているのですが、詳しい挙動を把握していなかったので調べてみました。EKSなので、今回はAWS環境に特化しています。

Karpenterについても気になっているので近々触れてみたいと考えています。

この記事では、ASG一覧をどうやって取得しているかを見ていきます。

podを割り当てるためにどのASGをスケールさせるかについても記事にしたいと思います。

cluster-autoscalerはscalInterval秒ごとに処理( RunOnce )を実行している

コード

for {
        select {
        case <-time.After(*scanInterval):
            {
                loopStart := time.Now()
                metrics.UpdateLastTime(metrics.Main, loopStart)
                healthCheck.UpdateLastActivity(loopStart)

                err := autoscaler.RunOnce(loopStart)

client-goを使って、node一覧を取得しています。

allNodes, readyNodes, typedErr := a.obtainNodeLists(a.CloudProvider)

どうやってcluster-autoscalerはターゲットとなるASGsを取得するのか

refreshInterval(1分)ごとにASG一覧を取得 (コード)

refreshIntervalはハードコーディングされているので、起動引数で変更することはできなそうです。ASGを削除してから1分以内にスケールイベントが発生するときはエラーが発生する可能性がありそうです。

func (m *AwsManager) Refresh() error {
    if m.lastRefresh.Add(refreshInterval).After(time.Now()) {
        return nil
    }
    return m.forceRefresh()
}

指定したtagsを元にASG一覧を取得

tagsはASGの起動引数(--node-group-auto-discovery)で指定しています。

e.g. --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/sample-eks-cluster

cluster-autoscalerが、引数の値をparseして、asg:tag=の右の値の箇所(k8s.io...,k8s.io...)をカンマ区切りでリスト化しています。 (コード)

aws-sdk-goを使って指定したTagを満たすASG一覧をフェッチ(コード)

tagごとにASG一覧を取得します。

err := m.DescribeTagsPages(input, func(out *autoscaling.DescribeTagsOutput, _ bool) bool {
        tags = append(tags, out.Tags...)
        // We return true while we want to be called with the next page of
        // results, if any.
        return true
})

すべてのtagを満たすASGをasgNamesにセット

asgNames := []string{}
asgNameOccurrences := make(map[string]int)
for _, t := range tags {
    asgName := aws.StringValue(t.ResourceId)
    occurrences := asgNameOccurrences[asgName] + 1
    if occurrences >= len(kvs) {
        asgNames = append(asgNames, asgName)
    }
    asgNameOccurrences[asgName] = occurrences
}

return asgNames, nil

asgNamesをasgCacheにセットします。

ASGの情報を取得するために、再度aws-sdk-goを使って、describe autoscalingを叩いています。(getAutoscalingGroupsByNames)

func (m *asgCache) regenerate() error {
    ...
    refreshNames, err := m.buildAsgNames()
    ...
    groups, err := m.awsService.getAutoscalingGroupsByNames(refreshNames)