コンテナの標準仕様について調査してみた件

Red Hatでコンサルタントをしている @mamomamo です。この記事は、[赤帽エンジニア Advent Calendar 2018](https://qiita.com/advent-calendar/2018/rh_engineers) の15日目です。


# はじめに
2018/12/3に Kubernetes 1.13 がリリースされました。このニュースリリースにおいて、"Container Storage Interface (CSI) Goes GA" という項目があり、v1.9からベータ版が採用された CSI（Container Storage Interface） がv1.13から正式版になったと発表されています。
CSI（Container Storage Interface）は、Kubernetesなどのコンテナオーケストレーションツールとストレージとの間のインターフェースの標準仕様ですが、他にもコンテナ関連にはいくつかの標準仕様が存在しています。本記事では、いくつかの代表的なコンテナ関連の標準仕様について、その概要を調査した内容を書いてみたいと考えています。


# OCI（Open Container Initiative）とは
Open Container Initiative（OCI）とは、コンテナのランタイムとイメージ関連のオープンな業界標準を作成するため、2015年6月にDocker社などの複数の企業により設立された、現在はLinux Foundation傘下のオープンソース団体です。

2018年12月時点のメンバは以下の通りで、Red Hatをはじめほとんどの大手テクノロジー企業が参加しています。
![スクリーンショット 2018-12-12 18.08.40.png](https://qiita-image-store.s3.amazonaws.com/0/136020/599b4064-fc04-1e3a-9a9e-fa3c1da9c950.png)
※引用： https://www.opencontainers.org/about/members

2017年7月に「OCI v1.0」が策定され、コンテナランタイムの標準仕様である「Runtime Specification」と、コンテナイメージの標準仕様である「Image Format Specification」がリリースされています。
また、2018年4月にはコンテナイメージ配布の標準仕様を策定する、「Distribution Specification」プロジェクトへの着手が発表されています。

※参考： https://www.opencontainers.org/blog/2018/04/09/distribution-spec-is-here


## OCI Runtime Specification
コンテナランタイムの標準仕様であり、現在の主要なコンテナランタイムが全て準拠しており、広く普及した標準仕様となっています。また、Linuxコンテナの標準仕様だけでなく、Solaris・Windows・Virtual Machine上のコンテナランタイムの仕様についても決められています。
詳細な仕様はGitHubのSpecificationのページを確認してもらった方が確実ですが、Linuxコンテナの場合には Default Filesystem・Namespace・cgropus などの仕様が決められています。


## OCI Image Format Specification
OCI Runtime Specificationと同じタイミングの2017年7月に策定され、こちらも広く普及しているコンテナイメージの標準仕様です。Image Manifest・Image Index・Image Layout・Filesystem Layout・Image Configuration などの仕様が決められています。


## OCI Distribution Specification
前述の通り2018年4月に着手開始が発表されたコンテナイメージ配布の標準仕様ですが、OCIのニュースリリースやGitHubのコミット履歴を見る限り、本記事の執筆時点（2018年12月中旬）では仕様の策定が止まっているように見えます。


# CRI（Container Runtime Interface）とは
CRI（Container Runtime Interface）とは、2016年12月にKubernetes 1.5からαリリースされた、kubeletとコンテナランタイムが通信するためのインターフェースを規定したものです。

CRIの概要は以下の図の通りです。

![Image 2016-12-19 at 17.13.16.png](https://qiita-image-store.s3.amazonaws.com/0/136020/bb787b05-c8dd-5a5a-ab87-95f2a126cd7c.png)

※引用：　https://kubernetes.io/blog/2016/12/container-runtime-interface-cri-in-kubernetes/

CRIが規定される以前は、コンテナランタイム側がkubeletの内部構造を理解しなければならず、新しいコンテナランタイムをKubernetesに組み込むことは非常に障壁の高いことでした。しかし、CRIが規定されることにより、KubernetesはDocker以外のコンテナランタイムを組み込み易くなっています。
このため、Red Hatが提供する OpenShift Container Platform では、Dockerよりも軽量なコンテナランタイムである、[CRI-O](https://cri-o.io/) をv4.0からデフォルトのコンテナランタイムに採用する予定です。


# CSI（Container Storage Interface）とは
CSI（Container Storage Interface）とは、Kubernetesなどのコンテナオーケストレーションツールとストレージとの間のインターフェースの標準仕様であり、2018年11月にv1.0に到達しました。
CSIの策定が開始される以前には、外部ストレージを開発するベンダーがコンテナオーケストレーションツール側の内部構造を理解していなければならず、機能追加や修正を行う場合にはコンテナオーケストレーションツール側に手を入れる必要がありました。
これに対応するため、コンテナオーケストレーションツールとストレージのインターフェースの間の標準仕様を策定することにより、コンテナオーケストレーションツール側に依存せず、独立にストレージ側の機能追加や修正を行えることを目指しています。

CSIのアーキテクチャは以下の通りです。
![スクリーンショット 2018-12-12 18.15.06.png](https://qiita-image-store.s3.amazonaws.com/0/136020/66eeab9e-216c-623c-fa84-c2514fcefe3b.png)
※引用： https://medium.com/google-cloud/understanding-the-container-storage-interface-csi-ddbeb966a3b

CSIでは、Kubernetes（コンテナオーケストレーションツール）側が、以下の3つのサイドカーコンテナを提供することになっています。

 - external-attacher： VolumeAttachmentオブジェクトを監視し、CSIエンドポイントに対してボリュームをノードにアタッチする命令を行います
 - external-provisoner： PersistentVolumeClaimオブジェクトを監視し、CSIエンドポイントに対してボリューム作成や削除の命令を行います
 - driver-register： CSI driverをkubeletに登録します

また、ストレージベンダー側は、以下の3つのサービスを実装する必要があります。

 - Identity Service：　コンテナオーケストレーションツールがプラグインに対してCapability/Health/その他メタデータなどを問い合わせるために実装します。
 - Controller Service： ボリュームやスナップショットの作成・削除・一覧表示を行う機能を実装します。
 - Node Service： コンテナオーケストレーションツール側からボリュームをマウントする際に呼び出される機能を実装します。


# CNI（Container Network Interface）とは
CNI（Container Network Interface）とは、CNCF（Cloud Native Computing Foundation）にホストされたプロジェクトの一つであり、コンテナがネットワークに接続するインターフェースの標準仕様とリファレンスプラグインを提供しています。
CNIは、コンテナが作成された際のネットワークの接続性の確保とコンテナが解放された際のリソースの解放を行っており、KubernetesやOpenShift Container Platformなどの様々なコンテナオーケストレーションツールで採用されており、デファクトになりつつあると考えられます。

※参考： https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/#cni
※参考： https://docs.openshift.com/container-platform/3.11/architecture/networking/network_plugins.html

また、2018年12月時点ではバージョンが1.0に到達しておらず、今後も仕様変更があると考えられます。

CNIの基本的な動作原理は以下の図の通りです。
JSONフォーマットのネットワーク設定が標準入力として、 CNIの設定が環境変数としてプラグインへ渡され、ブラグインが渡された情報に基づいて命令を実行します。

<img width="665" alt="スクリーンショット 2018-12-12 18.14.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/136020/f8377c0c-4d1b-8121-f91e-28947312ade6.png">

※引用： https://www.slideshare.net/weaveworks/introduction-to-the-container-network-interface-cni

CNIの標準仕様では、以下の4つがサポートすべきオペレーションとして決められています。

 - ADD： コンテナをネットワークへ追加
 - DEL： コンテナをネットワークから削除
 - CHECK： コンテナのネットワークが期待したものかチェック
 - VERSION：　バージョンの確認

また、コンテナランタイムからブラグインへ渡されるネットワーク設定には、以下の内容を設定することができます。

 - cniVersion (string): CNI Specificationのバージョン
 - name (string): ネットワーク名
 - type (string): 実行するネットワークプラグインのファイル名
 - args (dictionary, optional): コンテナランタイムより与えられる追加情報
 - ipMasq (boolean, optional): IPマスカレードの設定
 - ipam (dictionary, optional): IPAM設定のための情報
   - type (string): 実行するIPAMプラグインのファイル名
 - dns (dictionary, optional): DNS設定のための情報
   - nameservers (list of strings, optional): DNSネームサーバのリスト
   - domain (string, optional): ローカルドメインの指定
   - search (list of strings, optional): サーチドメインのリスト
   - options (list of strings, optional): リゾルバに渡すオプションのリスト
    

# さいごに
本記事では、コンテナの標準仕様について調査した結果を書いてみました。
全ての標準仕様について調査できたと思っていませんし、GitHubのSpecificationの内容をただ和訳するだけでは面白くないと考えたため、調査した4つの標準仕様について概要をまとめるに留めています。
もっと詳しい仕様を知りたい方は、以下の参考情報にそれぞれのリンクを貼っておきましたので、お時間のある時などにご確認ください。


# 参考情報
 - [Kubernetes 1.13: Simplified Cluster Management with Kubeadm, Container Storage Interface (CSI), and CoreDNS as Default DNS are Now Generally Available](https://kubernetes.io/blog/2018/12/03/kubernetes-1-13-release-announcement/)
 - [Open Container Initiative](https://www.opencontainers.org/)
 - [Open Container Initiative Runtime Specification](https://github.com/opencontainers/runtime-spec/blob/master/spec.md)
 - [Image Format Specification](https://github.com/opencontainers/image-spec/blob/master/spec.md)
 - [Open Container Initiative Distribution Specification](https://github.com/opencontainers/distribution-spec)
 - [Introducing Container Runtime Interface (CRI) in Kubernetes](https://kubernetes.io/blog/2016/12/container-runtime-interface-cri-in-kubernetes/)
 - [Container Storage Interface (CSI)](https://github.com/container-storage-interface/spec/blob/master/spec.md)
 - [Container Network Interface Specification](https://github.com/containernetworking/cni/blob/master/SPEC.md)