まっしろけっけ

めもてきなやーつ

EKS で Auto Scale 導入した後のトラブルを解消する

はじめに

shiro-16.hatenablog.com

Auto Scale 導入に関しては上記を参照。

今回のトラブルとは

Auto Scale によって workernode 自体は増えたのにその workernode に pod が作られた時に IP が の状態のままで pod が起動しないというもの。

調査をする

正常に pod が起動する workernode と正常に pod が起動しない workernode を比べると後者は セカンダリプライベート IP の欄に IP がない事がわかった。さらにその workernode のサブネットをみると 利用可能な IPv4 アドレス が 0 になっているというのが確認できた。

数時間後にそのサブネットの 利用可能な IPv4 アドレス をみると数字が増えていることわかった。

つまり workernode の セカンダリプライベート IP に割り当てられた IP が workernode が Auto Scale によって削除された後に再利用可能になるまでに時間がかかり過ぎて IP が足らなくなるという現象ということを突き止めた。

対応する

利用可能な IPv4 アドレス を増やす

上記の現象を AWS の中の人に共有した際に「もともと大量の IP を用意して使うものなので...」(意訳)ということを言われて、ですよね〜となったので単純に workernode に割り当てられるサブネットの IPv4 CIDR を変更して利用可能な IPv4 アドレス を増やすということをやった。

これで上記のトラブルは発生しなくなった。がしかし仮に今後アクセスが増えて workernode の数が大量に必要になった場合などに同じ現象に遭遇しないとも限らないということでもう一つ対応を行ってみた。

ネットワークインターフェイスを定期的に掃除する

workernode(というか EC2) の IP 周りはネットワークインターフェイスを見る事によって現在の status を確認できる。

status が available のものは定期的に削除されている模様というのがわかった。がしかしこの間隔が長すぎるので上記の問題が発生する

という事でこちら側で短い間隔でネットワークインターフェイスを掃除するという対応を行った。

Kubernetes の CronJob でやって貰った。

ネットワークインターフェイスを掃除するスクリプト

まずは AWS SDK for Ruby | AWS を使用してネットワークインターフェイスを掃除するスクリプトを作成

require 'aws-sdk'

ec2 = Aws::EC2::Client.new()
filters = {
  filters: [
    {
      name: :status,
      values: [:available]
    },
    {
      name: :description,
      values: ["aws-K8S-i-*"] # 今回は workernode 用に作成されたものだけ削除する
    }
  ]
}
ec2.describe_network_interfaces(filters).network_interfaces.each do |network|
  ec2.delete_network_interface({network_interface_id: network.network_interface_id})
end

これだけ

CronJob の yaml を用意する


15 分ごとに上記のスクリプトを実行する CronJob を用意する。
aws-sdk の install が遅いので aws-sdk 入りの image を用意しても良いと思います。(自分はそうしている)

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: network-interface-releaser
spec:
  failedJobsHistoryLimit: 1
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - command:
            - gem
            - install
            - aws-sdk
            - &&
            - ruby
            - network-interface-releaser.rb
            env:
            - name: AWS_REGION
              value: ap-northeast-1
            image: ruby:2.7.0
            name: network-interface-releaser
          restartPolicy: Never
  schedule: '*/15 * * * *'
アクセス権限周りの設定

下記のアクセス権限を持つユーザを追加して アクセスキー ID などを kubernetes の Secret にして使う(この場合上記の yaml に env などの追記が必要)か workernode の IAM に追加すると CronJob からネットワークインターフェイスの操作が可能になる。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ec2:DeleteNetworkInterface",
                "ec2:DescribeNetworkInterfaces"
            ],
            "Resource": "*"
        }
    ]
}
最後に CronJob の yaml を apply する

EKS の cluster に yaml を apply すれば定期的に CronJob がネットワークインターフェイスを掃除してくれて綺麗な状態を保ってくれるようになる。

さいごに

個人の見解ですが、調査する時に正常に動作しているものと正常に動作していないものが既に両方存在してると勝ったなって思いますよね。