tech.guitarrapc.cóm

Technical updates

HeadlampではじめるKubernetesダッシュボード

Kubernetesのダッシュボードは無数にありますが、Headlampというオープンソースのダッシュボードが手触りよかったので、備忘録を兼ねて紹介です。

OIDC認証に対応しているのでEKSならCognito連携もできて、Karpenterの状態もプラグインで詳細に追いかけることができます。また、イベントは警告でデフォルトフィルター表示されて、マップビューでクラスター全体のリソース展開状況を見たり、特定のノード、namespaceに絞り込めたり... 運用しててほしい情報が何か考えられている感じなのが気に入りました。

知ったきっかけはKubernetes公式ブログで、Karpenterプラグインの紹介記事を読んで興味を持ちました。公式ブログやXは割と面白いプロダクトを紹介してくれるので、気が向いたらチェックするとよいです。

誰向けのダッシュボード?

ダッシュボードと一口にいっても、対象ユーザーによって求められる機能は異なります。例えばKubernetes管理をするならクラスター全体の状態を把握したい一方で、アプリケーション開発者は自分のアプリケーションに関連するリソースの管理だけに集中したいでしょう。使う人によって欲しい情報の粒度が異なるのはKubernetes運用の地味に難しいところです。

HeadlampはKubernetesのリソース状態を詳細に追いかけたい運用担当者、開発者向けのダッシュボードです。特に以下のようなニーズを持つユーザーに適していると感じます。

  • Kubernetesのリソースを視覚的に管理したい開発者
  • クラスターの状態をリアルタイムで監視したい運用担当者
  • Podのイベントやログを迅速に確認したいエンジニア
  • KarpenterやKEDAなどのオートスケーリングツールの状態を詳細に把握したいユーザー

逆に、初心者向けのシンプルなダッシュボードを求めている場合や、特定のアプリケーションの監視に特化したダッシュボードを探している場合には、精細すぎるきらいがあります。

例えばアプリケーションエンジニアに向いたダッシュボード的な存在としてArgoCDがあります。Git Opsデプロイとして有名ですが、それに付随してアプリケーション単位でリソースをまとめてくれます。結果として、ArgoCD Web UIからリソースの正常状態が確認でき、Deploymentのリスタートもできたり、Ingressからsvc経由してDeploymentまでのネットワーク的な図も見られるため、デプロイしたアプリケーション管理に特化したい場合にはこっちが適しています。

Headlampの特徴

Headlampは以下のような特徴を持っています。

  • Kubernetes-sigが管理しているオープンソースプロジェクト - kubernetes-sigs/headlamp
  • 利用形態を2種類から選択可能
    • デスクトップアプリケーションとしての利用
    • Kubernetesインクラスターでダッシュボードサーバーとして利用
  • プラグインによる拡張性(Karpenterプラグインなど)
  • リソースの詳細な表示と管理
  • マップビューによるクラスター全体のリソース展開状況の可視化
  • OIDC認証のサポート

デスクトップアプリケーション版のHeadlamp

さくっとルックアンドフィールで触りたいならデスクトップアプリケーション版がおすすめです。公式サイトからダウンロードしてインストールするだけで、すぐにKubernetesクラスターに接続して利用できます。

よくあるツール同様、手元の.kube/configを参照して認証してくれるので、割と使い勝手がいいです。

Headlampをインストールする

インストール手順に従って自分のOSに合わせてHeadlampをインストールしましょう。なお、Kubernetes SIGに管理が移行してからアプリ署名ができていないようで、Windows/macOSでは起動時にセキュリティ警告が出る場合もあり自己責任でどうぞとのアナウンスが出ています。

もしバイナリが欲しいなら、リリースページからダウンロードできます。

# Windows
$ winget install headlamp

# macOS
$ brew install --cask --no-quarantine headlamp

# Linux (バイナリ版)
$ ./Headlamp-0.36.0-linux-x64.AppImage

起動してKubernetesクラスターに接続する

起動すると.kube/configに基づいてクラスターを選択できます。認証が取れていないクラスターのステータスはBad Gatewayが表示されます。接続できるときはアクティブ状態になります。

Headlampの起動画面

クラスターを選択するとダッシュボードが表示されます。あとは好きにリソースを見たり操作したりできます。ダッシュボード周りのUIはインクラスター版とほぼ同じなので、後述のクイックツアーを参考にしてください。

デスクトップ版Headlampのダッシュボード

ちなみに設定を見ると言語やテーマも調整できます。言語選択が日本語、英語に限らないのは、たいていのオープンソースが作者の自国+英語対応なのを考えると使いやすいですね。

Headlampの言語選択

インクラスター版のHeadlamp

インクラスター版はKubernetesクラスター内にHeadlampサーバーをデプロイして利用します。利用者各自がHeadlampをインストールせずとも利用できるので、チームでKubernetesクラスターを管理・利用している場合に便利です。

インクラスターを紹介するにあたり、HeadlampはOIDC認証が使えるのは重要なポイントです。1EKSならEKS OIDC Provider ConfigurationでCognito連携させれば、Cognitoに登録したユーザー・グループでOIDC認証が利用できます。

OIDC認証のEKS構成時の要点は次の通りです。Headlampに限らず、Cognito連携ではだいたいこの流れです。

  • Cognitoユーザープール・アプリクライアントを作成し、Headlampの接続URLを元にリダイレクトURIを設定
  • Cognitoドメインを設定 (必要ならCognito IdPも)
  • EKSクラスターのOIDCプロバイダーにCognitoユーザープールを紐づけ、Cognitoからemail/groups属性を取得可能に
  • HelmでHeadlampをデプロイ、values.yamlでoidc.configでOIDC設定
  • ClusterRoleBindingでKubernetes権限とCognitoグループ・Cognitoユーザーを紐づけ
  • Headlampにサインイン時、Cognito認証画面が表示されてHeadlampからKubernetes操作

Pulumiで構成する例

以下は公式のCognito OIDCドキュメントをベースに、PulumiでEKSクラスターとCognito連携のOIDC認証を構成する例です。Terraformも同様なので、参考にしてください。2

Cognitoユーザープールとアプリクライアントを作成する

Pulumi C#でCognitoユーザープールとアプリクライアントを作成するコード例を示します。ユーザープールはemail属性をユーザー名として利用し、セルフサインアップを許可しています。MFAはTOTPアプリを利用する設定です。

using Pulumi;
using Pulumi.Aws.Cognito;
using Pulumi.Aws.Cognito.Inputs;

namespace MyCognitoApp;

var name = "my-cognito";
var opt = new CustomResourceOptions { Parent = this };

var userPoolName = "my-cognito-userpool";
var callBackUrls = new[] { "http://localhost:8080/oidc-callback" }; // kubectl port-forwardでアクセスする想定
var defaultRedirectUri = "http://localhost:8080/oidc-callback";
var users = ["foo@example.com"];

// User Pool
var userPool = new UserPool($"{name}-userpool", new()
{
    Name = userPoolName,
    // emailをユーザー名として利用
    UsernameAttributes = [usernameAttribute],
    // ユーザー確認を行う際にEmailか電話で自動検証が必要、Emailを利用
    AutoVerifiedAttributes = ["email"],
    UserAttributeUpdateSettings = new UserPoolUserAttributeUpdateSettingsArgs
    {
        AttributesRequireVerificationBeforeUpdates = ["email"]
    },
    VerificationMessageTemplate = new UserPoolVerificationMessageTemplateArgs
    {
        DefaultEmailOption = "CONFIRM_WITH_CODE", // コードで確認
        EmailMessage = "Verification Code is {####}",
        EmailSubject = $"Your verification code for cognito userpool {userPoolName}",
        SmsMessage = "Your verification code is {####}",
    },

    // セルフサインアップOKで
    AdminCreateUserConfig = new UserPoolAdminCreateUserConfigArgs
    {
        AllowAdminCreateUserOnly = false,
        InviteMessageTemplate = new UserPoolAdminCreateUserConfigInviteMessageTemplateArgs
        {
            EmailSubject = $"Your temporary password for cognito {userPoolName}",
            EmailMessage = "Your username is {username} and temporary password is {####}.",
            SmsMessage = "Your username is {username} and temporary password is {####}.",
        },
    },

    // ユーザー名 = Email の大文字/小文字は区別しない
    UsernameConfiguration = new UserPoolUsernameConfigurationArgs
    {
        CaseSensitive = false,
    },

    // mfa
    MfaConfiguration = "ON",
    // totp app mfaとする. emailだと料金プランあがるので無料枠の大きいtotp appが使いやすい (Passkeyもいいぞ)
    AccountRecoverySetting = new UserPoolAccountRecoverySettingArgs
    {
        RecoveryMechanisms = [new UserPoolAccountRecoverySettingRecoveryMechanismArgs
        {
            Name = "verified_email",
            Priority = 1,
        }],
    },
    SoftwareTokenMfaConfiguration = new UserPoolSoftwareTokenMfaConfigurationArgs
    {
        Enabled = true,
    },
}, opt);

// Domain
var cognitoDomain = new UserPoolDomain($"{name}-domain", new()
{
    Domain = $"{name}-auth-cysharpdev",
    UserPoolId = userPool.Id,
}, opt);

// Group
var userGroup = new UserGroup($"{name}-group-admin", new()
{
    Name = "admin",
    UserPoolId = userPool.Id,
    Description = "Created by Pulumi",
    Precedence = 10,
}, opt);

// User (セルフサインアップするなら不要ですが、グループ紐づけは必要になります)
foreadch (var item in users)
{
    var user = new User($"{name}-user-{item}", new()
    {
        Username = item,
        UserPoolId = userPool.Id,
        DesiredDeliveryMediums = ["EMAIL"], // メール招待
        Enabled = true,
        ForceAliasCreation = true, // 既に同じEmailのユーザーがいたらマイグレートさせる
        TemporaryPassword = "TEMPORARYPassword!!!!9999999", // パスワードポリシーを満たさないとだめ
        Attributes = new InputMap<string>
        {
            ["email"] = item,
        },
    }, new CustomResourceOptions { Parent = this, IgnoreChanges = ["attributes[\"email_verified\"]"]});

    _ = new UserInGroup($"{name}-useringroup-{item}-admin", new()
    {
        UserPoolId = userPool.Id,
        GroupName = userGroup.Name,
        Username = user.Username,
    }, opt);
}

// Client
var client = new UserPoolClient($"{name}-client-eks", new()
{
    Name = item.Name,

    // ALB経由でOAuth 2.0を仕様するための設定 (典型)
    AllowedOauthFlowsUserPoolClient = true,
    AllowedOauthFlows = ["code"],
    AllowedOauthScopes = ["email", "openid", "profile"],

    // 認証後のリダイレクトURL
    CallbackUrls = callBackUrls,
    DefaultRedirectUri = defaultRedirectUri,
    LogoutUrls = [],

    // 認証プロバイダ
    UserPoolId = userPool.Id,
    SupportedIdentityProviders = ["COGNITO"],

    // クライアントシークレットの生成
    GenerateSecret = true,
}, opt);

// 必要ならCognito IdPも追加。headlamp的にはなくてもいい

EKSクラスターにOIDCプロバイダーを紐づける

EKSのOIDCプロバイダーをCognitoユーザープールに紐づけるコード例を示します。EKSクラスターを作成するコードはよくあるので割愛します。

ちなみにEKSクラスターのOIDCプロバイダーはEKSクラスターがReady状態になってからじゃないと設定できません。depends_onはリソースの作成を待つだけで、クラスターのReady状態を待つわけではないので使えないため、EKSクラスターの作成部分をPulumi Componentクラスに分離してクラスター完了まで待つのがオススメです。TerraformならModule分離すると、同様にクラスター完了まで待ってくれます。

var name = "automode";

// PulumiならComponentに分離するとクラスター完了まで待てるのでオススメ。TerraformならModuleを分離する。
// depends_onではクラスターのReady待ちはできないので注意。
var eksCluster = new Cluster($"{name}-cluster", new ClusterArgs
{
    // ... 省略 ...
}, opt);

// OIDCプロバイダーをCognitoユーザープールに紐づける。EKSが作成完了してからじゃないと紐づけられないので注意....
_ = new IdentityProviderConfig($"{name}-idp-config-cognito", new()
{
    ClusterName = eksCluster.Name,
    Oidc = new IdentityProviderConfigOidcArgs
    {
        IdentityProviderConfigName = "cognito-idp",
        ClientId = client.Id,
        IssuerUrl = userPool.Endpoint.Apply(x => $"https://{x}"),
        UsernameClaim = "email", // Cognito Userのemail属性を認証ユーザー名に使う (Cognitoと設定合わせましょう)
        GroupsClaim = "cognito:groups", // これでグループ属性を取得できる
        GroupsPrefix = "gid:", // ClusterRoleBindingでグループ名の頭にこれを入れることでグループ紐づけできる
    },
}, opt);

HeadlampをHelmでデプロイする

EKSとCognitoのOIDC連携ができたら、HelmでHeadlampをデプロイします。HelmチャートはArtifact Hubで公開されています。values.yamlにはCognito連携のOIDC設定を指定しておくとよいでしょう。

helm repo add headlamp https://kubernetes-sigs.github.io/headlamp/
helm repo update
helm upgrade --install headlamp headlamp/headlamp --version 0.37.0 -n kube-system -f ./values.yaml

以下はvalues.yamlの例です。簡単のためCognitoのclientID、clientSecretを直書きしていますが、Secrets ManagerなどにいれてExternal Secrets Operatorで参照するほうがおすすめです。

# values.yaml
config:
  inCluster: true
  # -- base url path at which headlamp should run
  baseURL: ""
  oidc:
    # cognito UserPool `oidc-sandbox-user-pool` & app client `headlamp`
    # -- OIDC client ID
    clientID: "CognitoUserPoolに作ったクライアントのclient IDを指定"
    # -- OIDC client secret
    clientSecret: "CognitoUserPoolに作ったクライアントのclient secretを指定"
    # -- OIDC issuer URL
    issuerURL: "CognitoユーザープールのURLを指定 (https://cognito-idp.{region}.amazonaws.com/{userPoolId})"
    # -- OIDC scopes to be used
    scopes: "openid,profile,email"
    # -- OIDC callback URL
    callbackURL: "http://localhost:8080/oidc-callback" # kubectl port-forwardで8080経由でアクセスする想定

インストールすると、Headlampサーバーが起動します。HeadlampのサービスタイプがClusterIPの場合、helmコマンドの実行時にkubectl port-forwardでローカルの8080ポートに転送してアクセスする案内が標準出力に出るので、http://localhost:8080でクラスター起動しているHeadlampにアクセスしてみましょう。

export POD_NAME=$(kubectl get pods --namespace {{ include "headlamp.namespace" . }} -l "app.kubernetes.io/name={{ include "headlamp.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace {{ include "headlamp.namespace" . }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace {{ include "headlamp.namespace" . }} port-forward $POD_NAME 8080:$CONTAINER_POR

Headlampにアクセスできるユーザー・グループと権限の紐づけ

ClusterRoleBingingで、OIDC認証したユーザー(UserClaim)やグループ(GroupsClaim)とKubernetesの権限を紐づけます。

kubectl apply -f headlamp-clusterrolebinding.yaml

例えば次のような設定にすると、foo@example.comユーザーがKubernetesのcluster-admin権限を持ってHeadlampにログインできます。

# headlamp-clusterrolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: headlamp-admin-user-clusterrolebinding
subjects:
  # user or group. Group is recommended when using Cognito User Pool
  - kind: User
    name: foo@example.com
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

あるいは次のような設定にすると、Cognito Groupadminに所属するユーザーがKubernetesのcluster-admin権限を持てます。

# headlamp-clusterrolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: headlamp-admin-user-clusterrolebinding
subjects:
  # user or group. Group is recommended when using Cognito User Pool
  - kind: Group
    name: gid:admin
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

Headlampクイックツアー

さくっとHeadlampのUIを見てみましょう。未認証だとログイン画面が表示されるので、Signinを選んでログインします。Cognito連携しているならCognitoのログイン画面が出ます。

トップページはログイン

サインインすると、デスクトップ版同様にダッシュボードが表示されます。左ペインにリソースなどの選択、右ペインに詳細が表示されます。トップページがイベント、かつ警告フィルターされているのよくわかってる感じあります。Kubernetes運用で一番欲しい情報はこれですからね。PodがPendingならイベントですぐ知りたいあるあるです。

ClusterトップはEventとクラスター全体のリソース表示

Namespace一覧、Node一覧も見やすいです。まぁ、Nodeが100台とかあるときりがないですがしょうがない。Taintsが出ているのは地味に便利です。kubectlでいい感じに拾うの、実はだるいんですよね。

Namespace一覧

Node一覧

他のダッシュボードと違うのがマップビューです。ノード、Namespaceなどで絞り込んだり、全展開してリソースを表示したりできます。イベント的に警告があると黄色マーカーがつくのもわかりやすいです。とはいえ、意外と正常でも警告イベントは出る、っていうのもありがちなので割り切りも必要です。

Map

リソースを選択すると、右ペインに詳細が表示されます。おおむねkubectl describe相当の情報が見られます。下にスクロールするとリソースのイベントも見られますし、右上アイコンからログを見たり、シェルをつないだりもできます。

リソースは右ペインに表示

ワークロードにはPodやDeployment、StatefulSet、DaemonSet、Jobなどよくあるリソースがまとめて表示されます。この辺りはEKSクラスターのUIも同じなので見慣れている人も多いでしょう。

Workloads

きりがないので端折ります。Secretsは目玉アイコンをクリックするとbase64デコードされた値が見られます。kubectlで-o jsonpathとかで取り出すの地味に面倒なので、地味に便利です。

Secretは目玉アイコンでbase64デコードされた値を見られる

CRDは他ダッシュボードより圧倒的に完成度が高いです。CRDであってもいい感じにデータを表示してくれます。プラグインを入れてなくても、YAMLで表示とか決まったカラムだけ出す、みたいな限定的な表示に収まっていないのはすごいです。

CRDがそれぞれ解釈できているのがえらい

Pluginsで機能拡張

Headlampの最大の特徴はPluginsによる機能拡張です。アーキテクチャの図にあるように、プラグインの実体はNodeアプリケーションです。

インクラスター版は、プラグインをクラスター内部で動作させる必要があるため、Helmのvalues.yamlでプラグインを指定します。

インクラスターでのプラグインアーキテクチャ

デスクトップ版は、先に紹介したPlugin Catalogから好きなプラグインを選んでインストールできます。必要なら適当にPluginリポジトリをクローン、ローカルでnpm startもできます。

デスクトップ版でのプラグインアーキテクチャ

デスクトップ版のプラグイン管理

デスクトップ版は、Plugin Catalogから好きなプラグインを選んでインストールできます。デフォルトでapp-catalogplugin-catalogprometheusプラグインが登録されているのでいい感じに選べる感じです。プラグインのインストールはインクラスターに比べると格段に楽です。デスクトップ版なので、各自で好きなプラグインを利用できるのも使いやすいポイントです。

Plugin Catalogからプラグインを選択できる

インストールしたプラグインはPlugin CatalogのInstalledタブから確認できます。

インストール済みプラグインの確認

例えばKarpenterプラグインを入れると、Karpenterで管理しているNodePoolやEC2NodeClassをHeadlampから確認できます。プラグインの詳細は後ほど。

Karpenterプラグインの表示例

インクラスター版のプラグイン管理

インクラスター版は、Helmのvalues.yamlでプラグインをインストールするのがGit履歴でも管理しやすくおすすめです。公式サイトのPluginページを見ると、Helm Valuesでプラグインを指定する方法が紹介されています。ちなみに、Pluginだけ別ファイルにしてHelm実行時にcatして割り当てる方法も載っていますが、ここではvalues.yamlに直接書き込む方法を紹介します。

利用できるプラグインは、Artifact HubにてHeadlamp Pluginカテゴリで公開されています。3 例えば、Karpenterプラグイン、KEDAプラグイン、Trivyプラグイン、AI Assistantプラグインを導入してみましょう。

ちなみに、config.watchPlugins: trueを指定しないとプラグイン認識しないので注意してください。私はこれに気づかず時間を使いました。設定キー名からそんな挙動だって思わなくないですか。

config:
  watchPlugins: true # ここをtrueにしないとプラグインが認識されない
pluginsManager:
  enabled: true
  # configFile: "plugin.yml"   # ここをコメントアウトしてconfigContentを使う
  configContent: |
    plugins:
      - name: karpenter
        source: https://artifacthub.io/packages/headlamp/headlamp-plugins/headlamp_karpenter
        version: 0.1.0
      - name: keda
        source: https://artifacthub.io/packages/headlamp/headlamp-plugins/headlamp_keda
        version: 0.1.1-beta
      - name: trivy
        source: https://artifacthub.io/packages/headlamp/headlamp-trivy/headlamp_trivy
        version: 0.3.1
      - name: ai-assistant
        source: https://artifacthub.io/packages/headlamp/headlamp-plugins/headlamp_ai_assistant
        version: 0.1.0-alpha
    installOptions:
      parallel: true
      maxConcurrent: 2
  baseImage: node:lts-alpine
  version: latest

  # これを追加しないと https://github.com/kubernetes-sigs/headlamp/issues/3999 のようにnpm permissionsエラーになる
  securityContext:
    runAsNonRoot: false
    readOnlyRootFilesystem: false
    runAsUser: 0

helmインストールすると、Headlamp Podにサイドカーコンテナheadlamp-pluginが生えて、プラグインがインストールされます。

headlamp-78d487fbd8-597zf headlamp-plugin 5 packages are looking for funding
headlamp-78d487fbd8-597zf headlamp-plugin   run `npm fund` for details
headlamp-78d487fbd8-597zf headlamp-plugin npm notice
headlamp-78d487fbd8-597zf headlamp-plugin npm notice New patch version of npm available! 11.6.1 -> 11.6.2
headlamp-78d487fbd8-597zf headlamp-plugin npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.6.2
headlamp-78d487fbd8-597zf headlamp-plugin npm notice To update run: npm install -g npm@11.6.2
headlamp-78d487fbd8-597zf headlamp-plugin npm notice
headlamp-78d487fbd8-597zf headlamp-plugin Installed headlamp-plugin successfully.
headlamp-78d487fbd8-597zf headlamp-plugin Installing plugins from config...
headlamp-78d487fbd8-597zf headlamp {"level":"info","duration_ms":"2.45","source":"/headlamp/backend/cmd/headlamp.go","line":1390,"time":"2025-10-29T09:37:08Z","message":"Request completed successfully"}
headlamp-78d487fbd8-597zf headlamp-plugin
headlamp-78d487fbd8-597zf headlamp-plugin plugins:
headlamp-78d487fbd8-597zf headlamp {"level":"info","duration_ms":"12.84","source":"/headlamp/backend/cmd/headlamp.go","line":1390,"time":"2025-10-29T09:37:08Z","message":"Request completed successfully"}
headlamp-78d487fbd8-597zf headlamp-plugin   - name: karpenter
headlamp-78d487fbd8-597zf headlamp {"level":"info","duration_ms":"9.28","source":"/headlamp/backend/cmd/headlamp.go","line":1390,"time":"2025-10-29T09:37:09Z","message":"Request completed successfully"}
headlamp-78d487fbd8-597zf headlamp-plugin     source: https://artifacthub.io/packages/headlamp/headlamp-plugins/headlamp_karpenter
headlamp-78d487fbd8-597zf headlamp-plugin     version: 0.1.0
headlamp-78d487fbd8-597zf headlamp-plugin   - name: keda
headlamp-78d487fbd8-597zf headlamp-plugin     source: https://artifacthub.io/packages/headlamp/headlamp-plugins/headlamp_keda
headlamp-78d487fbd8-597zf headlamp-plugin     version: 0.1.1-beta
headlamp-78d487fbd8-597zf headlamp-plugin   - name: trivy
headlamp-78d487fbd8-597zf headlamp-plugin     source: https://artifacthub.io/packages/headlamp/headlamp-trivy/headlamp_trivy
headlamp-78d487fbd8-597zf headlamp-plugin     version: 0.3.1
headlamp-78d487fbd8-597zf headlamp-plugin   - name: ai-assistant
headlamp-78d487fbd8-597zf headlamp-plugin     source: https://artifacthub.io/packages/headlamp/headlamp-plugins/headlamp_ai_assistant
headlamp-78d487fbd8-597zf headlamp-plugin     version: 0.1.0-alpha
headlamp-78d487fbd8-597zf headlamp-plugin installOptions:
headlamp-78d487fbd8-597zf headlamp-plugin   parallel: true
headlamp-78d487fbd8-597zf headlamp-plugin   maxConcurrent: 2
headlamp-78d487fbd8-597zf headlamp-plugin info: Installing plugins from config: /config/plugin.yml
headlamp-78d487fbd8-597zf headlamp-plugin 1 of 4 (karpenter): info: Installing plugin karpenter
headlamp-78d487fbd8-597zf headlamp-plugin 1 of 4 (karpenter): info: Fetching Plugin Metadata
headlamp-78d487fbd8-597zf headlamp-plugin 2 of 4 (keda): info: Installing plugin keda
headlamp-78d487fbd8-597zf headlamp-plugin 2 of 4 (keda): info: Fetching Plugin Metadata
headlamp-78d487fbd8-597zf headlamp-plugin 2 of 4 (keda): info: Plugin Metadata Fetched
headlamp-78d487fbd8-597zf headlamp-plugin 2 of 4 (keda): info: Downloading Plugin
headlamp-78d487fbd8-597zf headlamp-plugin 1 of 4 (karpenter): info: Plugin Metadata Fetched
headlamp-78d487fbd8-597zf headlamp-plugin 1 of 4 (karpenter): info: Downloading Plugin
headlamp-78d487fbd8-597zf headlamp-plugin 1 of 4 (karpenter): info: Plugin Downloaded
headlamp-78d487fbd8-597zf headlamp-plugin 1 of 4 (karpenter): info: Extracting Plugin
headlamp-78d487fbd8-597zf headlamp-plugin 2 of 4 (keda): info: Plugin Downloaded
headlamp-78d487fbd8-597zf headlamp-plugin 2 of 4 (keda): info: Extracting Plugin
headlamp-78d487fbd8-597zf headlamp-plugin 2 of 4 (keda): info: Plugin Extracted
headlamp-78d487fbd8-597zf headlamp-plugin Moved directory from /tmp/headlamp-plugin-temp-iMEOnN/headlamp_keda to /headlamp/plugins/headlamp_keda
headlamp-78d487fbd8-597zf headlamp-plugin 2 of 4 (keda): success: Plugin Installed
headlamp-78d487fbd8-597zf headlamp-plugin 2 of 4 (keda): success: Plugin installed successfully
headlamp-78d487fbd8-597zf headlamp-plugin 1 of 4 (karpenter): info: Plugin Extracted
headlamp-78d487fbd8-597zf headlamp-plugin Moved directory from /tmp/headlamp-plugin-temp-ApkBDO/headlamp_karpenter to /headlamp/plugins/headlamp_karpenter
headlamp-78d487fbd8-597zf headlamp-plugin 1 of 4 (karpenter): success: Plugin Installed
headlamp-78d487fbd8-597zf headlamp-plugin 1 of 4 (karpenter): success: Plugin installed successfully
headlamp-78d487fbd8-597zf headlamp-plugin 3 of 4 (trivy): info: Installing plugin trivy
headlamp-78d487fbd8-597zf headlamp-plugin 3 of 4 (trivy): info: Fetching Plugin Metadata
headlamp-78d487fbd8-597zf headlamp-plugin 4 of 4 (ai-assistant): info: Installing plugin ai-assistant
headlamp-78d487fbd8-597zf headlamp-plugin 4 of 4 (ai-assistant): info: Fetching Plugin Metadata
headlamp-78d487fbd8-597zf headlamp-plugin 3 of 4 (trivy): info: Plugin Metadata Fetched
headlamp-78d487fbd8-597zf headlamp-plugin 3 of 4 (trivy): info: Downloading Plugin
headlamp-78d487fbd8-597zf headlamp-plugin 4 of 4 (ai-assistant): info: Plugin Metadata Fetched
headlamp-78d487fbd8-597zf headlamp-plugin 4 of 4 (ai-assistant): info: Downloading Plugin
headlamp-78d487fbd8-597zf headlamp-plugin 3 of 4 (trivy): info: Plugin Downloaded
headlamp-78d487fbd8-597zf headlamp-plugin 3 of 4 (trivy): info: Extracting Plugin
headlamp-78d487fbd8-597zf headlamp-plugin 4 of 4 (ai-assistant): info: Plugin Downloaded
headlamp-78d487fbd8-597zf headlamp-plugin 4 of 4 (ai-assistant): info: Extracting Plugin
headlamp-78d487fbd8-597zf headlamp-plugin 3 of 4 (trivy): info: Plugin Extracted
headlamp-78d487fbd8-597zf headlamp-plugin Moved directory from /tmp/headlamp-plugin-temp-NlAooa/headlamp_trivy to /headlamp/plugins/headlamp_trivy
headlamp-78d487fbd8-597zf headlamp-plugin 3 of 4 (trivy): success: Plugin Installed
headlamp-78d487fbd8-597zf headlamp-plugin 3 of 4 (trivy): success: Plugin installed successfully
headlamp-78d487fbd8-597zf headlamp-plugin 4 of 4 (ai-assistant): info: Plugin Extracted
headlamp-78d487fbd8-597zf headlamp-plugin Moved directory from /tmp/headlamp-plugin-temp-FlcHCb/headlamp_ai_assistant to /headlamp/plugins/headlamp_ai_assistant
headlamp-78d487fbd8-597zf headlamp-plugin 4 of 4 (ai-assistant): success: Plugin Installed
headlamp-78d487fbd8-597zf headlamp-plugin 4 of 4 (ai-assistant): success: Plugin installed successfully
headlamp-78d487fbd8-597zf headlamp-plugin info: Bulk installation completed: {"total":4,"failed":0,"skipped":0,"successful":4}
headlamp-78d487fbd8-597zf headlamp-plugin Watching /config/plugin.yml for changes...

Headlampでプラグインを確認する

Headlampにプラグインをインストールすると、UIに変化が現れます。例えばKarpenter、Keda、Trivyプラグインをインストールすると左ペインにメニューが追加されます。

プラグインが左ペインメニューに表示

導入しているプラグインは、Headlampの設定画面からも確認できます。Helm values.yamlで指定したプラグインが導入できたかはここを見るのがオススメです。

設定 > プラグインから一覧で確認できる

Karpenterプラグイン

Karpenterプラグインを使うと、Karpenterで管理しているNodePoolやEC2NodeClassをHeadlampから確認できます。Karpenterでスケーリングしているノードの状態を詳細に把握できるのは便利です。

ただ、EKS AutomodeはEC2NodeClassではなくNodeClassを使うため、HeadlampのKarpenterプラグインではNodeClassは表示されません。プラグインリポジトリ的には対応している的な文言なので、将来的に対応されそうです。気長に待ちましょう。

EKS AutomodeではEC2 NodeClassは存在しない

Kubernetesを運用していて割とほしいのが、クラスター全体のCPU、メモリに対してどれぐらい使っているかです。これはHeadlampのClusterトップページで表示されないので弱いなぁと感じるのですが、KarpenterプラグインのNode Poolから、NodePoolごとにCPU、メモリ使用率が表示されるので便利です。

NodePool一覧で利用割合がわかる

運用していて気になるのが「ちゃんとPodはスケールアウトできているか」です。これを確認するにはKubernetesイベントの「Pending Podイベント」を見る必要があるのですがイベントって流れるんですよね。でも、Karpenterプラグインを入れるとPending PodsタブでPodの状態をリアルタイムで把握できます。これは本当に便利です。この気持ち、伝わってほしい。

Pending PodsタブでPodの状態を確認

Scaling ViewでNode Claimを見られるので、Karpenterでスケーリングしているノードの状態を詳細に把握できます。Zoneが出ているあたりがわかってる感じあります。

Node Claimの詳細が確認できる

KEDAプラグイン

KEDAプラグインを使うと、KEDAのスケーリング設定であるScaledObjectやTriggerAuthenticationリソースをHeadlampから確認できます。ネームスペース横断でスケール対象を一括確認できるのは結構便利です。KEDAはZero to Scale4ができることもあって、複数ネームスペースにアプリケーションやDeploymentが分散していても漏れにくくなるのは運用してて嬉しいポイントです。

KEDAのScaledObjectが一覧表示

ScaledObjectの対象Podやトリガーが確認できるのも便利です。KEDAのスケール条件って実はちょいちょい触るわりに、詳細を把握していないとkubectlから読み解くのも難しい代表です。UIでいい感じに見られるのは助かりますよね。

ScaledObjectの詳細が確認できる1

ScaledObjectの詳細が確認できる2

MapにもScaledObjectが表示されるので、KEDAでスケーリングしているアプリケーションの分布も把握できます。

MapでScaledObjectも表示される

AI Assistantプラグイン

AI Assistantプラグインを使うと、そのKubernetesクラスターについてAIを使ったサポートを受けられます。プラグインをインストールすると、右上にAIアイコンが表示され、チャット形式でKubernetesに関する質問ができる感じです。ローカル環境にKubernetes MCPを使って聞く方法も広く使われつつありますが、Headlampに組み込まれているというのはAI統制的には悪くないアプローチに思えます。

AIメニューが右上にある

AIチャットが表示する

AIの一覧はよくある感じです。OpenAIのモデルはGPT-4.1などでちょっと古いです。Azure OpenAIも選択できるので、企業としても使いやすい余地があります。

AI一覧

OpenAIの設定例

軽くやり取りをしてみましょう。

チャットは英語だけでなく日本語も行けます。例えば以下のような質問で英語同様の回答が返ってきていることがわかります。

さて、質問の回答はKubernetes管理者ならある程度なるほどとなる情報です。ちなみにtaintが... という部分は適切で、この時のEKSクラスターはsystemノードのみが起動していたので、taintが原因でスケジューリングされなかったことがわかります。

ただ、肝心の質問に対する回答としてはちょっと足りなくもあります。この時Podが起動しない原因は、Podが期待するnodeSelector: arm64を満たすノードに相当するNodeがないためです。Podを起動できるようにするには、KarpenterでNodePoolとしてarm64ノードを追加する必要があります。このAI回答から、どうすればいいかまで一直線にたどり着くのは難しいですが、モデルが少し古いのと、ファンクションコーリングが浅いあたり、今後のチューニングに期待です。

User
Why my nginx deployment'pod won't be running?

AI Assistant
Based on the reported warnings for your main cluster, here are several reasons why your nginx deployment pod (nginx-698f5c6f78) isn’t running:

Service Account Not Found:

The deployment is trying to use service account test-app in the default namespace, but it does not exist. You’ll see an error like:
pods "nginx-698f5c6f78-" is forbidden: error looking up service account default/test-app: serviceaccount "test-app" not found

Node Scheduling Problems:

No suitable nodes are available for pod scheduling. Specifically:

0/1 nodes are available: 1 node(s) had untolerated taint {CriticalAddonsOnly: }. no new claims to deallocate...

Your only node, i-0647b9224fd6861a2, has a taint discouraging regular pods from being scheduled unless they tolerate it.

Image Filesystem Capacity Issues:

There’s a warning indicating invalid capacity (0) on the image filesystem. This can prevent pods from starting due to lack of space.
To resolve these issues, you should:

Create the test-app service account in the default namespace, or change your nginx deployment to use an existing service account.
Either remove or add a toleration for the {CriticalAddonsOnly:} taint in your pod spec.
Check node disk/volume availability.
You
nginx Deploymentのpodが起動してこないのはなぜですか?

AI Assistant
main クラスターの警告から、nginx Deployment の Pod が起動しない主な理由は以下の通りです。

ServiceAccount が存在しない

Pod 起動時「pods "nginx-698f5c6f78-" is forbidden: error looking up service account default/test-app: serviceaccount "test-app" not found」というエラーが出ています。これは、Deployment で指定している test-app サービスアカウントが default namespace に存在しないためです。
ノードに taint がありスケジューリングできない

「0/1 nodes are available: 1 node(s) had untolerated taint {CriticalAddonsOnly: }」という警告があり、ノード i-0647b9224fd6861a2 に taint が付いているため、Pod がスケジュールされません。Pod の spec に tolerations を追加する必要があります。
image filesystem 容量が無効

「invalid capacity 0 on image filesystem」という警告があり、ノードのディスク容量不足または設定が正しくない可能性があります。
この3つが主な原因です。対応策としては:

test-app サービスアカウントを作成するか、Deployment の serviceAccount 名を修正
Pod の spec に taint を許容する tolerations を追加
ノードのディスク容量を確認し、必要であればリソース追加

チャットの例

調査だけでなく簡単な操作もできます。例えば、チャットからPodを削除させたり、Deploymentをリスタートさせることもできるのは怖さと便利さが入り混じっています。Get以外の操作をすると確認プロンプトが出ますが、結果がでないあたりもファンクションコールが足りない感じもあります。

You
Pod inflate-68c59b845-2phjgをterminateしてください。

削除操作でプロンプト表示される

削除後の結果は出ない

この辺りの挙動はai assistantプラグインの実装を見るといいでしょう。AI Assistantはkubectlのようなコマンドを実行するのではなく、Kubernetes APIを直接叩いて情報を取得しています。例えば、DeleteやUpdateなどの操作でプロンプト制御していることもわかります。

ベースプロンプトから、AIアシスタントでどのようなユーザー体験をさせたいのかがわかります。デスクトップ版ではマルチクラスター管理していることも想定していることもわかります。

AI Assistantの難点として、チャット履歴が残りません。つまり、Headlampのウェブページをリロードすると履歴が吹き飛びます、ひどい。細かな挙動やモデル更新、履歴保持など気になるところはあるので今後のアップデートに期待しつつも、MCPサーバーでローカルからKubernetes APIを叩いて情報を取得するよりも始めやすい感じはあります。

まとめ

割と細かいところまでKubernetesリソースを追いかけられるダッシュボードとしてHeadlampは優秀で好きです。特にプラグインによる拡張性が高く、KarpenterやKEDAなどのオートスケーリングツールの状態を詳細に把握できるのは便利です。

OIDC認証もHelmで完結できるのは割とちゃんと叩かれている感じがして好印象です。EKSでCognito連携しているなら、Headlampを使うことでKubernetesリソースの管理がより効率的になるでしょう。

kubectlでわかるも大事、ArgoCDでアプリケーションデプロイを管理できるのも大事、DatadogでKubernetesクラスター状態がわかるのも大事、でもHeadlampでそこにあるKubernetesクラスターを詳細に追いかけられるのも大事、という感じで、HeadlampはKubernetes管理の選択肢として十分に価値があります。

参考


  1. 実運用を考えるとインクラスターで使うときは認証付きにせざるを得ないので、クラスター認証しておくとかせずOIDC認証できる程度の状態で試すのがおすすめです。細かいけど大事。
  2. EKSのOIDC設定は公式ドキュメントやIntroducing OIDC identity provider authentication for Amazon EKS | AWS Blogが詳しく、悩んだときは大いに参考となります。
  3. カテゴリあるの気づかなかったのですが、便利すぎませんか。
  4. Podをゼロ台までスケールダウンさせ、必要に応じてスケールアウトさせる運用方法