オフライン環境のK8s:Zarfでスタックを安全にパッケージ化する

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

午前2時のスニーカーネットという現実

想像してみてください。窓のない機密情報隔離施設(SCIF)で午前2時。スマホはただの文鎮と化し、サーバーラックは悲鳴を上げ、パブリックインターネットへの経路は皆無です。

これが「エアギャップ(物理隔離)」です。あなたの任務は、Google DNSを見たこともないKubernetesクラスターに20個のマイクロサービススタックをデプロイすること。以前なら、これはdocker saveコマンドの悪夢、壊れやすいシェルスクリプト、および依存関係を一つでも忘れることへの絶え間ない恐怖を意味していました。もし50MB of イメージを一つでも忘れたら、デプロイ全体がストップし、修正のためにオフィスまで車で2時間かけて戻る羽目になります。

こうした切断された環境をマスターできるかどうかが、シニアプラットフォームエンジニアとそれ以外を分ける境界線です。「自分のマシンでは動く」というセットアップから、完全に自律したクラウドへと移行するには、異なるツールキットが必要です。そこで登場するのがZarfです。Defense Unicornsによって開発されたZarfは、イメージ、バイナリ、Helmチャートを単一の圧縮された.zstファイルにまとめるオープンソースツールです。アプリケーションスタック全体を、一つのポータブルなアーティファクトとして扱うことができます。

クイックスタート:5分で最初のパッケージを作成する

まず、初期依存関係をプルするために、インターネット接続のあるマシンにZarf CLIをインストールする必要があります。パッケージが完成したら、ハードウェア暗号化されたドライブに入れて隔離環境に持ち込むことができます。

1. CLIのインストール

# Homebrewを使用したmacOS/Linuxの場合
brew install zarf

# またはLinuxバイナリを直接取得する場合
curl -s https://api.github.com/repos/defenseunicorns/zarf/releases/latest | grep browser_download_url | cut -d '"' -f 4 | grep Linux_amd64 | xargs curl -L -o zarf
chmod +x zarf
sudo mv zarf /usr/local/bin/

2. zarf.yamlの定義

zarf.yamlファイルはマニフェストとして機能します。オフラインになる前に、ウェブから何をスクレイピングするかをツールに指示します。

kind: ZarfPackageConfig
metadata:
  name: secure-nginx-demo
  description: "エアギャップ環境向けNginxデプロイ"

components:
  - name: web-server
    required: true
    manifests:
      - name: nginx-deployment
        files:
          - nginx-deployment.yaml
    images:
      - nginx:1.25.3-alpine

3. パッケージ化とデプロイ

createコマンドを実行してイメージをプルし、パッケージ化します。標準的なNginxパッケージは通常20〜30MB程度ですが、フルスタックになると5GB以上に達することもあります。

# パッケージを作成する
zarf package create .

# .zstファイルをオフラインのマシンに移動する

# クラスターを初期化する(内部レジストリをセットアップ)
zarf init

# パッケージをデプロイする
zarf package deploy zarf-package-secure-nginx-demo-amd64.tar.zst

Zarfがどのようにレジストリ問題を解決するか

zarf initを実行することは、単にバイナリをインストールするだけではありません。クラスター内にローカルコンテナレジストリとMutating Webhookをデプロイします。これが、オフラインデプロイをシームレスにする核心的なメカニズムです。

標準的な環境では、K8sノードはDocker Hubからnginx:latestをプルしようとします。エアギャップ環境では、そのリクエストは30秒後にタイムアウトします。Zarfのエージェントはこれらの「プル」リクエストをインターセプトし、ノードをクラスター上の内部Zarfレジストリに自動的にリダイレクトします。50個ものYAMLファイルを書き換えてローカルIPアドレスを指定する必要はありません。Zarfがその場で変換を処理します。

オフラインでの状態管理

Zarfは、環境内でどのコンポーネントバージョンが実行されているかを正確に追跡します。午前3時にデプロイが失敗した場合、zarf package listを実行すれば、K8sログや難解なマニフェストを掘り起こすことなく、切断された環境の状態を明確に把握できます。

複雑なHelmチャートの処理

最近のスタックが単一のPodに依存することは稀です。通常、数十の依存関係を含むHelmチャートを扱います。Zarfは、チャート内で言及されているすべてのイメージを再帰的に特定し、バンドルに取り込むことで、この分野で威力を発揮します。

components:
  - name: database-layer
    charts:
      - name: postgresql
        url: https://charts.bitnami.com/bitnami
        version: 12.1.0
    images:
      - bitnami/postgresql:15.2.0-debian-11-r0
  
  - name: config-assets
    files:
      - source: ./scripts/init-db.sh
        target: /usr/local/bin/init-db.sh
        executable: true

このシナリオでは、ZarfはBitnamiチャートと特定のPostgresイメージを取得します。これをオフラインでデプロイすると、ZarfはHelmの値を「リタグ(再タグ付け)」します。これにより、クラスターはインターネットにアクセスしようとするのではなく、ローカルのZarfレジストリから800MBのPostgresイメージをプルするようになります。

現場で得た教訓

長年、切断されたシステムと格闘してきた結果、わずかな見落としがデプロイを台無しにすることを学びました。よくある落とし穴を避けるためのヒントをいくつか紹介します。

  • 無駄を削ぎ落とす: コンテナイメージは重いです。’latest’タグや巨大なUbuntuベースのイメージを使用すると、.zstファイルが膨れ上がります。標準のPythonイメージ(900MB)からAlpineベース(50MB)に切り替えるだけで、転送時間を大幅に短縮できます。
  • ハッシュを確認する: USB経由のファイル移動やクロスドメイン転送では、データの破損がよく起こります。Zarfは内部チェックを行いますが、zarf package deployを開始する前に、必ずパッケージのsha256sumを確認してください。
  • コンポーネントをモジュール化する: インフラ全体を一つの巨大なコンポーネントに詰め込むのは避けましょう。PrometheusやGrafanaなどの必須ではないツールにはrequired: falseフラグを使用します。これにより、ローカルハードウェアのスペックが低い場合に、リソースを大量に消費するモニタリングをスキップできます。
  • 軽量な初期化: zarf initコマンドはデフォルトでいくつかのサービスをインストールします。4GBのRAMしかない小型のエッジデバイスにデプロイする場合は、--componentsフラグを使用してロギングスタックなどをスキップし、オーバーヘッドを節約してください。

エアギャップ環境へのデプロイは、かつては週末を潰す退屈な作業でした。Zarfのような宣言的なツールを採用することで、手動でミスが起きやすいプロセスを、再現可能でバージョン管理されたワークフローに変えることができます。次にあの静かなサーバー室に立つときは、必要なものがすべて詰まった一つのファイルがあることに感謝するはずです。

Share: