以下の内容はhttps://tech.timee.co.jp/entry/2026/02/06/141426より取得しました。


GitHub Actions Self-hosted Runner 基盤の EKS バージョンアップを自動化した話

こんにちは、タイミーでエンジニアをしている徳富(@yannKazu1)です。

前回の記事では、EKS 上に self-hosted GitHub Actions Runner 基盤を構築した話をご紹介しました。

▼ 前回の記事

https://tech.timee.co.jp/entry/2025/09/22/122415

ありがたいことに、この取り組みは AWS さんの公式ブログでもご紹介いただきました

👉 AWS ブログ

https://aws.amazon.com/jp/blogs/news/timee-amazon-eks-auto-mode/

今回はその続編として、

EKS のクラスターバージョンアップを、どうやって安全に自動化したか

についてお話しします。

EKS のクラスターバージョンアップ、地味につらい

EKS を運用していると、どうしても避けて通れないのが定期的なクラスターバージョンアップです。

  • Kubernetes のマイナーバージョンは定期的に EOL が来る
  • 放置するとサポート切れになる
  • とはいえ、毎回人が確認して手動で上げるのは正直しんどい

「これ、もう少し楽にできないか?」

そう思ったのが、今回の仕組みを考え始めたきっかけでした。

今回の前提:EKS Auto Mode を使っている

今回運用している EKS では、EKS Auto Mode を採用しています。

EKS Auto Mode では、

  • ノード管理
  • 主要な Add-on 管理(VPC CNI / AWS Load Balancer Controller など)

を AWS 側で管理しており、運用負荷を軽減できます。

そのため、クラスターバージョンアップの流れは比較的シンプルです。

  1. マニフェストで 非推奨 API を使っていないか確認する
  2. 問題なければ クラスターバージョンをアップする
  3. ノードや主要 Add-on は AWS が自動で追従する

さらに EKS にはUpgrade Insightsという便利な仕組みがあります。

  • 非推奨 API の使用状況
  • バージョンアップ時に問題になりそうな点

を事前にチェックできるため、

「このバージョンに上げて大丈夫か?」をかなり楽に判断できます。

自動化の方針

とはいえ、いきなり本番クラスターバージョンを自動で上げるのは、さすがに怖い。

そこで、次の方針で仕組みを作りました。

1. 本番とは別にテスト用クラスターを用意する

Self-hosted Runner 用の main クラスターとは別に、検証専用の test クラスターを用意しています。

  • コストを抑えるため Spot インスタンスを使用する
  • 最小構成で test-runner のみを起動する

インフラは次のように管理しています。

  • クラスターや AWS リソース:Terraform
  • ARC Controller などの Helm リソース:Terraform
  • その他の Kubernetes リソース:マニフェスト(Kustomize)

この構成にしていることで、

  • test / main クラスターに ほぼ同じ設定をそのまま適用できる
  • runner の 台数やサイズだけを環境ごとに切り替えられる

といったことが簡単にできます。

結果として、

  • コントローラや設定は本番と同一
  • リソース(インスタンスサイズ・台数)を最小構成にした test-runner

という、「本番に限りなく近いが、低コストなコピー環境」を作れています。

2. テストクラスターで先にバージョンアップする

テストクラスターでは、次の条件を満たした場合のみ

自動でバージョンアップを行います。

① リリースから 1 か月以上経過したバージョンであること

aws eks describe-cluster-versions \
  --include-all \
  --query 'clusterVersions[?versionStatus==`STANDARD_SUPPORT`].{version: clusterVersion, releaseDate: releaseDate}' \
  --output json

取得した結果を jq で加工し、

「リリースから 1 か月以上経過しているバージョン」のみを対象にします。

② Upgrade Insights がすべて PASS していること

INSIGHTS_JSON=$(aws eks list-insights \
  --cluster-name ${{ inputs.cluster-name }} \
  --output json)

ERROR_COUNT=$(echo "$INSIGHTS_JSON" | jq '[.insights[] | select(.category=="UPGRADE_READINESS" and .insightStatus.status=="ERROR")] | length')
WARNING_COUNT=$(echo "$INSIGHTS_JSON" | jq '[.insights[] | select(.category=="UPGRADE_READINESS" and .insightStatus.status=="WARNING")] | length')
  • ERROR / WARNING があればブロックする
  • UNKNOWN は未使用機能なので許容する

これらの条件をすべて満たしている場合のみ、毎朝 7 時に GitHub Actions から aws eks update-cluster-version を実行します。

3. test クラスターの結果を cluster_version.txt の PR として残す

本番クラスターのバージョンアップは、cluster_version.txt に書かれたバージョンへ更新する

という前提で設計しています。

そのため、本番をいつ上げるかだけは人が判断できるように

cluster_version.txt の更新は必ず PR 経由にしています。

test クラスターバージョンアップが正常に完了すると、

  • 実際に上がった EKS バージョンを
  • そのまま cluster_version.txt に書き込み
  • 自動で PR を作成

します。

# **cluster_version.txt**
1.34

この PR をマージすると、その日の深夜に本番クラスターバージョンアップが実行されます。

  • 検証は自動で完了済み
  • 本番反映の日付だけ人が判断する

というバランスに落ち着きました。

本番クラスターバージョンアップフロー

本番クラスターバージョンアップは、毎日 深夜 2 時

GitHub Actions から定期実行しています。

流れは次のとおりです。

1. cluster_version.txt との差分を確認

  • cluster_version.txt のバージョン
  • 現在の本番クラスターのバージョン

を比較し、差分がなければここで終了します。

差分がある場合のみ、以降のチェックに進みます。

2. Upgrade Insights が PASS していることを確認

INSIGHTS_JSON=$(aws eks list-insights \
  --cluster-name ${{ inputs.cluster-name }} \
  --output json)

ERROR_COUNT=$(echo "$INSIGHTS_JSON" | jq '[.insights[] | select(.category=="UPGRADE_READINESS" and .insightStatus.status=="ERROR")] | length')
WARNING_COUNT=$(echo "$INSIGHTS_JSON" | jq '[.insights[] | select(.category=="UPGRADE_READINESS" and .insightStatus.status=="WARNING")] | length')

3. test-runner のヘルスチェックを実行

本番アップグレード前に、

test クラスター上の Self-hosted Runner が正常に動くかを確認します。

簡単な workflow_dispatch のワークフローを用意しています。

name: Test Runner Health Check

on:
  workflow_dispatch

jobs:
  health-check:
    runs-on: test-runner # testクラスター上のtest-runnerを指定する
    timeout-minutes: 10
    steps:
      - run: |
          echo "✅ test-runner is healthy!"
          hostname
          date

このワークフローをgh コマンドで起動し、

10 分以内に success することを確認します。

(ポーリング処理は省略していますが、実装上は完了を待っています)

4. 問題なければ本番クラスターバージョンアップ

aws eks update-cluster-version \
  --name ${{ env.MAIN_CLUSTER_NAME }} \
  --kubernetes-version "$TARGET_VERSION"

流れを図で表すと、以下のとおりです。

なぜ深夜 2 時に「自動で」上げるのか?

「本番反映の日付は人が制御」と書きましたが、厳密には PR をマージした日の深夜 2 時に自動でクラスターバージョンアップが走る 仕組みです。

つまり、人が決めるのは 「いつの深夜にクラスターバージョンアップを実行するか」 だけ。

この設計にしている理由は 2 つあります。

1. 深夜ならデプロイと競合しない

  • デプロイが走っていない時間帯である
  • ノード更新時に Pod が退避しても影響が出にくい
  • デプロイ途中で Pod が落ちる事故を防げる

2. 問題が起きても業務開始後に対処できる

Self-hosted Runner の利用箇所では、Organization variablesを使って runner を指定しています。

runs-on: ${{ vars.RUNNER_AMD64_STANDARD }}

もしクラスターバージョンアップ後に問題が発覚しても、この変数の値を ubuntu-latest などに変更するだけで、全リポジトリのワークフローが GitHub-hosted runner で動くようになります。

コードを一切変更せずにフォールバックできるため、業務開始後に気づいてからの対応でも十分間に合います

このフォールバック手段があるからこそ、

  • 深夜に自動でクラスターバージョンアップを実行
  • 人は「日付を決める」だけ

という運用が成り立っています。

Terraform 管理との付き合い方

インフラは Terraform で管理していますが、

EKS のクラスターバージョンだけは Terraform 管理外にしています。

  • cluster_versionignore_changes を設定している
  • バージョンアップは CLI で実施している

これにより、

  • CLI で上げても Terraform 差分が出ない
  • IaC と運用の責務をきれいに分離できる

というメリットがあります。

まとめ

この仕組みを導入したことで、

  • クラスターバージョンアップの toil を大幅に削減できた
  • 「test → 本番」の安心できるフローを自動化できた
  • Self-hosted Runner が壊れないことを事前に保証できるようになった

という成果が得られました。

EKS Auto Mode の特性を活かすことで、

「人が気合で回す運用」から一段階進められたかなと思っています。

同じように EKS を運用している方の参考になれば嬉しいです 🙌




以上の内容はhttps://tech.timee.co.jp/entry/2026/02/06/141426より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14