TT Lab
はじめる
学ぶ 学習パス コース

Kubespray と Terraform でクラスターを構築する

閉域網は一覧の勝負 — Kubespray が取得するものを外で確定する

TT Labで続きを見る

一言でいうと

kubesprayのエアギャップ環境でのインストールは、「ダウンロードするものの一覧を作り → 社内に同じパスで用意しておき → インベントリの変数でアドレスだけを変える」作業です。このモジュールは、そのうち一覧と変数までを扱います。

なぜ必要なのか

kubesprayは、インストールの途中でインターネットからかなり多くのものをダウンロードします。このコースの実測インストールでも、github.comのリリース(containerd・runc・etcd・CNIプラグイン・calicoctl)、dl.k8s.io(kubeadm・kubelet・kubectl)、registry.k8s.io・quay.io・docker.ioのイメージ、Ubuntuのaptリポジトリのパッケージをダウンロードしました。金融・公共・製造の現場のサーバーは、このうちどれにも届きません。そのため、kubesprayのドキュメントのエアギャップ環境の節は、事前に持っていくべきものを5つに分けています。静的ファイル(バイナリ・アーカイブ)、OSパッケージ、コンテナイメージ、そしてオプションでPythonパッケージとHelmチャートです。そして、社内に用意すべきものも、それに合わせて書いています。ファイル用のHTTPミラー、社内のdebとrpmのリポジトリ、社内のコンテナレジストリ、オプションでPyPIとHelmリポジトリです。

どう動くのか

一覧はツールが作ります。contrib/offline/generate_list.shは、download.ymlから*_download_urlとイメージのrepoとtagを取り出してテンプレートを作り、小さなプレイブック(generate_list.yml)でそのテンプレートに変数を埋めて、temp/files.listとtemp/images.listを出力します。このVMで実測すると、3.6秒でファイル24行、イメージ48行が出ます。有効にしていないCNI(cilium・flannelなど)やアドオンのものまですべて入っているので、実際のインストールで使われるものより余裕があります。持ち込み審査を一度で終わらせるには、余裕があるほうがよいです。イメージの取得元は、quay.io 18・registry.k8s.io 18・docker.io 10・ghcr.io 2でした。

落とし穴: 一覧のプレイブックはlocalhostで動きます。READMEは、インベントリかgroup_varsにバージョンの変数を書いて、-iで渡すよう書いています。ところが、generate_list.ymlの対象はhosts: localhostで、localhostはインベントリのどのグループにも属さないので、allのgroup_varsしか受け取りません。このコースのようにkube_versionをgroup_vars/k8s_clusterに書いておくと(kubesprayのサンプルが置く場所です)、一覧のプレイブックはその値を見ずに、デフォルト値で一覧を作ります。実測では、インベントリは1.35.8なのに、一覧は1.36.4で出て、エラーも警告もありませんでした。-e kube_version=1.35.8を指定するか、バージョンをgroup_vars/allに置くのが正解です。

アドレスは変数で変えます。サンプルのgroup_vars/all/offline.ymlとドキュメントが示す変数は、2系統です。

이미지   kube_image_repo · gcr_image_repo · docker_image_repo · quay_image_repo · github_image_repo  → "{{ registry_host }}"
파일     github_url · dl_k8s_io_url · storage_googleapis_url · get_helm_url                         → "{{ files_repo }}/<원래 도메인>"
노드     containerd_registries_mirrors(containerd 2) · containerd_registry_auth(1.7)                 → 사내 레지스트리를 믿게
OS 패키지 ubuntu_repo · debian_repo · yum_repo                                                         → 사내 저장소

このコードブロックの韓国語の部分は、行の見出しがイメージ、ファイル、ノード、OSパッケージであること、files_repoの後ろのプレースホルダーが元のドメインであること、ノードについては社内レジストリを信頼させること、OSパッケージは社内リポジトリに向けることを述べています。

イメージは、レジストリのアドレスだけが変わり、パス(coredns/coredns:v…)はそのままです。ファイルも、ドキュメントのヒントのとおり、元のドメインを最初のディレクトリにしておくと(files_repo/dl.k8s.io/release/…)、元のURLからミラーのURLへ機械的に移せます。これらの変数をallに置く理由は、etcdだけを担当するノードもダウンロードする必要があり、上の一覧のプレイブックも読み取る必要があるからです。実測では、allに置いたオフラインの変数で、一覧72行が1行も漏れることなく社内のアドレスに変わりました。

コントロールノードも持ち込みの対象です。kubespray v2.32.0は、ansible==12.3.0といくつかのPythonパッケージを、正確なバージョンで要求します。エアギャップ環境のコントロールノードでpip install -r requirements.txtを行うには、ホイールを事前にダウンロードして持っていく必要があり、ダウンロードした環境とインストールする環境の、Pythonのバージョンとアーキテクチャが同じである必要があります。pip install --dry-run --no-index --find-linksで、インターネットなしで解決できるかを、外で先に確認できます。

現場での姿

エアギャップ環境への持ち込みは、たいてい「一覧の提出 → 審査 → 持ち込み → インストール」の順序で、一覧が間違っていると、全体の日程が1周分ずれます。最もよくあるミスは、3つです。バージョンが異なる一覧(上の落とし穴)、イメージのアドレスを1つ抜かしたオフラインの変数(その1つのイメージだけを元のドメインからダウンロードしようとして止まる)、そしてコントロールノードのAnsibleを忘れることです。このモジュールのラボは、この3つを外で事前に確認する順序で組まれています。

実際に社内レジストリを起動して、一覧のイメージを移し入れ(manage-offline-container-images.sh)、ファイルミラーをnginxで公開し(manage-offline-files.sh)、インターネットが切れたノードでインストールを最後まで実行する作業は、エアギャップ環境を別に扱うコースに続きます。ここで作った一覧・対応表・Pythonのバンドルが、そのコースの入力です。

次のラボですること

generate_list.shでデフォルトの一覧を作り、取得元ごとに数えます。インベントリを渡したときと、バージョンを-eで渡したときで、一覧のバージョンがどう違うかを確認します。offline.ymlに社内ミラーのアドレスを入れて、一覧がすべて社内を指しているかを見て、元とミラーの対応表を作ります。ノードが社内レジストリを使うようにするcontainerdの設定を加え、最後に、Ansibleまで入れたPythonのバンドルが、インターネットなしで解決できるかを確認します。