Kubernetes 1.20から始まるDockerランタイムの非推奨化に備えよう!我々が知っておくべきこと・すべきこと
はじめに
Kubernetesの次のマイナーバージョン1.20が、2020年12月8日にリリースされました。今回のリリースではGraceful Node Shutdownの追加やkubectl debugのBeta昇格など、運用に嬉しいさまざまな機能のアップデートがあります。その中でも、12月初頭にGitHubや公式Slack、Twitterなどを賑わせたのがDockershimの非推奨化でした。公式のリリースノートには以下のように書かれています。
Docker support in the kubelet is now deprecated and will be removed in a future release. The kubelet uses a module called "dockershim" which implements CRI support for Docker and it has seen maintenance issues in the Kubernetes community. We encourage you to evaluate moving to a container runtime that is a full-fledged implementation of CRI (v1alpha1 or v1 compliant) as they become available.
参考リンク:kubernetes/CHANGELOG-1.20.md
今回はこの変更に着目して、DockerとKubernetesの関係から、なぜ非推奨になったのかを解説しつつ、運用者・開発者がどのような対応をとればよいかについてご紹介します。
具体的に何がどうなるのか
バージョン1.20から「Dockershim」が非推奨になることで、KubernetsをDockerランタイムで動かしている場合は非推奨の注意書きがKubernetesのクラスターログに表示されるようになります。この変更によってすぐにKubernetesが動かなくなるわけではありません。しかし、来年後半にリリースを予定しているバージョン1.23からはDockershimがKubernetesから削除され、KubernetesをDockerと一緒に動かすためには自前で別途準備が必要になります。
まずは、このDockershimについて何をしているものなのか見てみましょう。
Dockershimの役割
DockershimはDockerとKubernetesのAPIをつなぐブリッジの役割を持ちます。Kubernetesが作られた当時に、アプリケーションを動かすために最も便利で汎用性のあったDockerがコンテナランタイムとして採用されました。一方、Docker社はKubernetesの公開後まもなく、独自のオーケストレーションツールであるDocker Swarmを発表しました。そのほかにもCoreOS社のrktやRancher社のCattleコンテナ管理のためのツールが生まれる中で、KubernetesにとってのDockerは依存すべき関係ではなく選択肢の一つとして考えていく必要がありました。
そこで、Kubernetesに必要な「コンテナを操作するためのAPI仕様」としてCRI(Container Runtime Interface)が作られ、DockershimはCRIとDockerのAPIを変換するためのブリッジとなり、現在も内部的に使われています。
なお、削除される予定のDockershimは、今後Mirantis社がhttps://github.com/Mirantis/cri-dockerdというリポジトリで管理を継続していくと発表しています。「自前で別途準備が必要になる」という点では変わりませんが、Dockerを使っていても、Kubernetesが一切動かなくなる、というわけではなさそうです。
また、Mirantis社が提供する「Mirantis Kubernetes Engine」もあるため、こちらをお使いの場合はDockerとの統合に関する将来的な期待ができそうです。
KubernetesはDockerの一部の機能しか使わない
「Docker」という言葉にはいろいろな意味合いが含まれます。これは、手元で作った環境をDockerコマンドでイメージにBuildし、作成したイメージをレジストリでShareし、それを他の環境でRunできるという、一般に「Build、Share、Run」と呼ばれる仕組みが開発者にとって広く浸透してきたことのあらわれでもあると筆者は考えていますが、KubernetesはDockerが持つ機能の中でも一部しか利用していません。
Kubernetesが使うDockerの機能
Dockerの中でもDockerコンテナを作成して動かし、管理する機能のことを「ランタイム」と呼びます。Kubernetesでは、このDockerが持つランタイム機能を使ってアプリケーションの実行や削除、アップデートなどを実現しています。
Kubernetesが使わないDockerの機能
Dockerイメージをビルドするための「イメージビルダー」や、Dockerコンテナが動く上で必要な「ボリューム」、「ネットワーク」といった機能はKubernetesでは利用しません。その代わり、実際にはコンテナを管理することに特化した「containerd」を中心とした機能が使われます(下図参照)。
Dockerが非推奨となる最も大きな理由はDockershim自体のメンテナンスコストが高いことですが、一部の理由としては、このように使われない機能を多く含むDockerを「基盤の根幹」として使い続けることによるリソースのオーバーヘッドなどの問題が指摘されてきたという背景があります。
containerdについて
containerdは、Dockerがmoby projectを発表したのと同時期にCNCFに寄贈されたDockerの一部です。moby projectはDocker社が2017年に発表したOSSのプロジェクトで、Dockerを構成する機能を切り出すことによって、開発者が好きな機能を自分のプロジェクトに取り入れられるようにしたり、車輪の再発明をしなくてもよくなるような工夫がなされているプロジェクトです。containerdはこのプロジェクトの発足と同時に発表されたコンテナランタイムのOSSで、ほぼ同じタイミングでCNCF Projectに寄贈されました。
containerdはDockerの持つランタイムそのものでありながら、CRIが実装されています。そのため、Kubernetes上でこれまでDockerを使っていた基盤運用者がDockerからの移行を考えるにあたっては最も有力な候補と言えます。
なお、Kubernetesの世界ではこのようなCRIを備えるランタイムを「CRIランタイム」と呼びます。
CRIランタイム
CRIランタイムは高レベルランタイムとも呼ばれ、Dockerと同じくKubernetesがコンテナを管理するための機能を提供します。2020年12月現在、CRIランタイムには「containerd」と「CRI-O」という2つの実装があります。
containerd
containerdはKubernetesと同じくCNCFのプロジェクトの一つで、Dockerの裏側で動くランタイムです。CRIを備えつつDockerにもさまざまな機能を提供しています。ランタイムとしてはDockerが必要なものをすべて持っているため、これまでKubernetesでランタイムにDockerを使ってきた利用者にとっても、多くの場合で何も気にすることなく移行をすることができるかと思います(移行に考慮が必要なケースについては後述します)。
containerdはパブリッククラウドで利用されているケースが多く、例えばAWSのEKS FargateやBottlerocketではDockerの代わりにcontainerdが動くほか、GCPのGKEでもcontainerdを動かすことができ、1.19からはデフォルトのコンテナランタイムがDockerからcontainerdに変更されています。AzureのAKSについては2020年12月頭の段階ではプレビューフェーズで、少なくとも1.23のリリースまでにはGAになるものと思われます。
CRI-O
CRI-OはRed Hat社が中心となって開発しているOSSで、containerdとは違い純粋なCRI実装であるため、「Kubernetesを動かすために作られたコンテナランタイム」と呼ぶこともできます。現在はRed Hatの主力製品の一つである「Red Hat OpenShift」のコンポーネントとして導入され、Dockerの代わりにコンテナを動かすためのツールとしてさまざまな環境で利用されています。containerdとの一番の違いはその実装背景にあります。「CRIのためのランタイム」と呼ばれるだけあって、軽量かつよりセキュアなランタイムである、と公式ドキュメントでも謳っています。
ランタイム移行のメリット
CRIランタイムに移行すると、kubeletはDockershimを経由することなく直接ランタイムと会話することができます。そのため、コードベースも軽量になりつつ通信のオーバーヘッドが改善される、といったメリットがあります。
OCIランタイム
CRIランタイムの話をしたので、OCIランタイムについても簡単に触れておきましょう。OCIはOpen Container Initiativeの略称で、Dockerコンテナに必要なさまざまな規格を標準化している団体です。規格には以下のようなものがあり、その中でもRuntime Specを満たしているのがOCIランタイムです。CRIランタイムが高レベルランタイムと呼ばれるのに対し、OCIランタイムは低レベルランタイムと呼ばれています。
- OCI Runtime Specification
- OCIイメージを動かすための「ランタイム」の標準仕様
- OCI Image Specification
- Dockerでも使われる「イメージ」の標準仕様
- OCI Distribution Specification
- コンテナレジストリの標準仕様
CRIランタイムとOCIランタイムについては非常に関係性が複雑なので、下記の図を用意しました。
Kubernetesからランタイムを利用する場合、はじめにkubectlコマンドなどを用いてPodを作成します。このとき、Kubernetes内部ではetcdにPodを作成するための情報が書き込まれ、スケジューリングなどの処理を経て特定ノードのkubeletがPodの情報を取得します。
kubeletは作成するPodの情報をCRIを通じて高レベルランタイムに渡します。CRIランタイムはそれをJSONの構成ファイルに変換し、最終的に「OCIランタイム」のバイナリを実行することによって作成します。
このとき、Linuxカーネルとの対話などはOCIランタイムが請け負っており、CRIランタイムはあくまでそれらの管理のために動くプロセスです。
OCIランタイムもCRIランタイムと同様いくつかの実装がありますが、今回は直接関係のないトピックのため、名前を列挙するまでにとどめます。興味がある方はそれぞれの特徴や違いについて調べてみてください。
Dockershimの削除によるOCI規格への影響
Dockerランタイムが使えなくなることで、これまで使っていたDockerイメージやレジストリが使えなくなるのでは?と不安に思う方も一部いらっしゃるようですが、CRI、OCIの関係はこれまでもこれからも変わりません。
CRIランタイムはそれぞれOCIイメージやレジストリを扱うための実装を含んでいるので、ローカルマシンで作成したDockerイメージをレジストリにプッシュしておけば、これまでと同じようにPodがKubernetes上で動きます。
対応の有無の判断基準
今回こちらの記事をお読みになっている方の多くはKubernetesを触ったことがあるか、すでに何らかの環境で動かしている方だと思います。その中でもマネージドサービスを使われている方に関しては、ワーカーノードのタイプを変更するだけでcontainerdへの移行が終わってしまうかと思います。実際の移行例については、イギリスの決済サービスPaybase社のエンジニアがKubeCon EU 2019にて発表した動画「Lessons Learned Migrating Kubernetes from Docker to containerd Runtime」についても合わせてご覧いただくとよさそうです。
確認方法
お使いのKubernetesクラスターに向けて以下のコマンドを実行します。
kubectl get node -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME minikube Ready master 4d18h v1.19.4 192.168.49.2 <none> Ubuntu 20.04.1 LTS 4.19.128-microsoft-standard docker://19.3.13
上記の例のように、CONTAINER-RUNTIMEの項目がdockerになっている場合は、対応が必要となります。以下に対応が必要な場合とそうでない場合のケースについてまとめました。
対応が不要なケース
Kubernetesを使っていない方、使う予定がない人
今回の非推奨はKubernetesにおけるDockerの扱い方が変わるという話なので、今Kubernetesをお使いになられていない場合は特に何も気にする必要がありません。
Kubernetesで動くアプリケーションをDocker(Docker Compose)で開発している開発者
対応不要です。本番を動かす基盤側は影響があるかもしれませんが、手元の開発は変わらないと思ってください。
対応が必要なケース
手元の環境でKubernetesを利用する開発者
本人がなにか対応しないといけないというよりは、使うツールによって対応状況を確認する必要があります。
- Docker DesktopのKubernetesを使っている場合
- 2020年12月初頭の段階において、Docker Desktopが今回の措置にどう対応するか発表がなく、またオープンソースでもないため、現状はDocker社の対応を待つしかないでしょう。ただしまだ1年近くは猶予があるため、すぐに問題は発生しません
- Docker EE(Enterprise Edition)を買収したMirantisがDockershimの継続開発を表明しているため、今後も何らかの形で対応が進んでいくものと思われます
- Minikubeのnone driverまたはMicrok8sを使っている場合
- 現状はホスト上のDockerが使われているため、今後はcontainerdのソケットを指定して動かす必要があります
- Minikubeの場合は「--container-runtime='containerd'」または「'cri-o'」オプションを利用すればよいでしょう
- Minikubeのdocker driverまたはkindを使っている場合
- これらは「Docker環境の上でKubernetesを動かす」ためのツールなので、特に開発者が対応することはありません
NVIDIA DockerをKubernetes上で使っている場合
機械学習のアプリケーションがKubernetesの上で動く環境では、多くの場合で「NVIDIA Docker」と呼ばれるツールが使われています。これを移行する場合、現状であればNVIDIA/nvidia-container-runtimeがcontainerdに対応しているため、そちらを利用することができます。
また、NVIDIA/gpu-operatorもcontainerdに関する対応を1.4.0で行うと予告しているため、近いうちにリリースされるようです。
Kubernetes上で「Docker in Docker」や「Docker API」を使うワークロードを動かしている場合
例えばDockerイメージのビルド処理や、バッチ処理の都合でDocker APIから何らかのメタデータを取得するなどの処理を行っている場合、何も検討せずにDockerをcontainerdやCRI-Oに入れ替えてしまうとDocker APIが使えなくなってしまうので注意が必要です。
なお、コンテナ関連のメタデータの取得に関してはできる限りKubernetes APIを使うか、Podの環境変数から取得する方向で調査・検討をすすめるほうがよいでしょう。
Dockerイメージのビルド処理については、代替のOSSが存在するためそちらへの移行を検討してください。Dockerが持つイメージビルダーと違いDockerの有無に依存しないため、コンテナ単体で動かすことができるようなものも存在します。
ここでは代表的なOSSを挙げておきます。
また、NTTの須田瑛大氏がKubeCon EU 2019にて発表した「Building Images Efficiently and Securely on Kubernetes with BuildKit」(動画)についても合わせてご覧ください(本人による発表レポートはこちら)。
おわりに
今回の対応は国内外ともに一部ソーシャルメディアでトレンドに上がるなど話題を呼びましたが、Kubernetesにおけるさまざまなユースケースの中でも一部にのみ影響を与えるものとなっています。本記事の情報が基盤運用者、開発者の方にとって技術的な指針となっていれば幸いです。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- CNDO 2021、サイバーエージェントのテックリードがコンテナランタイムの最新情報を解説
- runC vs. cc-runtime vs. kata-runtime?コンテナランタイムの内部構造と性能比較
- コンテナを使いこなすための心強い味方!「Kubernetes」(前編)
- CNDO 2021、Kubernetesとコンテナの基本的構造をNTTの徳永航平氏が解説
- KubeCon報告からKubernetes対応版Dockerまで、Docker Meetup Tokyo #20開催
- CloudNative Days Fukuoka 2023、コンテナランタイムの今と未来を解説するキーノートセッションを紹介
- 「Cloud Native Trail Map」の10ステップを紐解く(ステップ8~10)
- Oracle Cloud Hangout Cafe Season5 #3「Kubernetes のセキュリティ」(2022年3月9日開催)
- CNDT2021、CNCFの元TOCメンバーがOSSにおける標準の重要性を解説
- Kubernetes環境を構築して、実際にコンテナを動かしてみよう