狠狠撸

狠狠撸Share a Scribd company logo
Container Storage
Interface のすべて
KubeFest Tokyo 2020
2020/06/13 サイボウズ株式会社 Yuji Ito
自己紹介
▌伊藤祐司
? 分散システムにかかわる仕事がしたく、2019年10月
からNecoチームでデータセンタの開発に参画している。
▌サイボウズ株式会社 Necoチーム
? 自社データセンタに1000ノード規模のKubernetes
クラスタを構築する。
? ストレージ専従ではなく、約1ヵ月ごとに班を変えながら
満遍なく知識を蓄える。
2
本発表の目的
▌Container Storage Interface (CSI) について知ってもらう。
? 概要
? どのような機能が実装可能なのか
▌CSIドライバの開発を行うための情報を提供する。
? CSIドライバの開発方法
? CSIドライバのテスト方法
3
発表の流れ
▌PV, PVC, SC のおさらい
▌CSIの概要
▌CSI?CSIドライバの構造
▌最小限のCSIドライバの実装
▌CSIドライバのテスト
▌オプション機能の拡張方法
▌ドキュメント?参考情報
▌まとめ
4
metadata:
name: pv01
spec:
capacity: ...
storageClassName: sc01
PV: Persistent Volume
metadata:
name: sc01
provisioner: ...
parameters: ...
SC: Storage Class
metadata:
name: pvc01
spec:
resources: ...
storageClassName: sc01
PVC: Persistent Volume Claim
PV, PVC, SC のおさらい
5
metadata:
name: pod01
spec:
containers:
volumes:
- name: volume01
persistentVolumeClaim:
claimName: pvc01
1. PodおよびPodが利用する
volumeをPVCとして定義
0. (前準備)
SCでPVをグループ分け
することが可能
ストレージ
システム
2. Podから利用可能なvolume (ファイルシステムまたはRawブロックデバイス)
ごとにPVを定義し、関連付ける
4. PVCに関連付けられた
PVのvolumeを用い、
Podが起動
3. PVCで定義した条件に
マッチするPVがPVCに
関連付けられる
CSIの概要
6
CSIの定義に
従った拡張
CSIとはなんなのか
▌各種Container
Orchestrators (CO)において、
ストレージ機能を拡張するための
統一されたインタフェース。
▌PVCの変更に対し、PV?スト
レージを自動で作成?拡張?削
除するなどの仕組みを追加可能。
7
ストレージ
システム
CSIドライバ
K8s CSI sidecar container
開発対象となるCSIドライバはKubernetesから
独立しており (out of tree) 誰でも開発可能
監視
作成?変更
操作
Kubernetes プロジェクトから
提供されている
CSIで定義されたgRPC
Kubernetesに絞って説明
CSI関連の用語
▌Volume
CSIを通して利用可能になるストレージの単位。ファイルシステムまたはブロックデバイ
スのこと。 KubernetesのPVから指示される実際に利用可能な領域に対応。
▌CSIドライバ / CSIDriver オブジェクト
CSIドライバ: CSIを利用するドライバ全体。
CSIDriver: KubernetesにCSIの情報を渡すためのオブジェクト。
▌Node Plugin
各KubernetesのNode上で動く、CSIドライバのプログラム及びコンテナ。
8
CSIを利用して実現できる機能
▌ファイルシステム, Rawブロックデバイスを扱う。
▌PVCの作成?削除に対応し、PV?ストレージを自動で割当て、削除する。
- Dynamic Provisioning
▌PVCで定義される容量の変更に対応し、ストレージを拡張する。
- Volume Expansion
▌Podの終了とともに開放される短期的な領域の割り当て。
9
CSIを利用して実現できる機能 (続き)
▌既存のPVをコピーしたPVを作成する。
▌PVのSnapshotを作成し、それをコピーしたPVを作成する。
▌ストレージシステムが利用できるRackやRegionが制限される場合に、
その状態に応じてPodを作る場所を制御する。
10
CSIドライバを開発することで、前述のような機能を
Kubernetesクラスタのサービスとして提供可能
CSI?CSIドライバの構造
11
CSIドライバに関連する主な要素
12
CSIDriver (Object)
当該CSIドライバの存在と機能をKubernetes に伝える
Controller Plugin の Pod
(Deployment/StatefulSet)
Node Plugin の Pod
(DaemonSet)
Controller Plugin コンテナ
? Controller サービス
? Identity サービス
K8s CSI の sidecar コンテナ
Node Plugin コンテナ
? Node サービス
? Identity サービス
Kubernetes プロジェクトから
提供されている
K8s CSI の sidecar コンテナ
Kubernetes プロジェクトから
提供されている
Kubernetes プロジェクトから
提供されている
開発対象
apiVersion: v1
kind: Pod
metadata:
name: pod-name
spec:
containers:
- image: container1:latest
name: container-1
volumeMounts:
- mountPath: /mnt/share
name: shared-volume
- image: container2:latest
name: container-2
volumeMounts:
- mountPath: /mnt/share
name: shared-volume
volumes:
- name: shared-volume
emptyDir: {}
sidecarのおさらい
▌複数のコンテナを内包するPod
▌コンテナ間で、Volumeの共有や
Volume内の Unix Domain
Socket (USD) を利用した通信
が可能
13
Pod
Container#2Container#1
Container#1
Container#2
Volume
Kubernetesプロジェクトから提供される主要な CSI sidecar
▌external-provisioner
Dynamic Provisioning 機能を提供する場合に利用する。
▌livenessprobe
CSIドライバの状態を Kubernetes に伝えるため、 Readiness Probe 機能と連
携する。
▌node-driver-registrar
Kubernetes がNodeを認識するための CSINode オブジェクトを作成する。
14
Kubernetes の Node
CSIに関するコンポーネントの連携
15
Controller Plugin の Pod
(Deployment/StatefulSet)
Controller Plugin コンテナ
? Controller サービス
? Identity サービス
K8s CSI の sidecar コンテナ
Node Plugin の Pod
(DaemonSet)
Node Plugin コンテナ
? Node サービス
? Identity サービス
K8s CSI の sidecar コンテナ
API
Server
gRPC
Unix Domain Socket
gRPC
Unix Domain Socket
Kubelet
Volume Volume詳しくは、CSI Volume Plugins in Kubernetes Design Doc を参照
作成
利用
最小限のCSIドライバの実装
16
CSIのspecについて
▌CSIドライバが実装するプロシージャの
細かい仕様が記載されている。
? 引数の内容
? 期待する戻り値
? エラー時の戻り値
▌https://github.com/
container-storage-interface/
spec/blob/master/spec.md
17
最小限のCSIドライバの状態遷移
▌host pathを用意するだけの最小限のCSIドライバを例示する。
▌構成要素はNodeサービスとIdentityサービスだけ。
18
Podの起動準備
完了
PUBLISHED
NodePublishVolume プロシージャの呼び出し
NodeUnpublishVolumeプロシージャの呼び出し
この時点でPodが動作する
Podの削除処理がトリガになる
サービスのスケルトンを生成
▌各gRPCサービス用のコードを生成。
? gRPCの定義は以下のリポジトリで公開されている。
https://github.com/container-storage-
interface/spec/blob/master/csi.proto
? 言語について制限は無いが、Kubernetesの機能を利用する場合、ライブラリが
充実しているgo言語が無難。
19
## protocコマンドをダウンロード?展開しておく
## csi.protoフィルをダウンロードしておく
GO111MODULE=on go get github.com/golang/protobuf/protoc-gen-go
protoc -I=. --go_out=plugins=grpc:. csi.proto
生成されたスケルトンについて
▌csi.pb.goが生成される
▌Identity, Controller, Node の各サービスで実装するべきプロシー
ジャが定義されている。
20
type IdentityServer interface {
GetPluginInfo(context.Context, *GetPluginInfoRequest) (*GetPluginInfoResponse, error)
...
type ControllerServer interface {
CreateVolume(context.Context, *CreateVolumeRequest) (*CreateVolumeResponse, error)
...
type NodeServer interface {
NodeStageVolume(context.Context, *NodeStageVolumeRequest) (*NodeStageVolumeResponse, ...
...
ドライバが提供する機能とcapability
▌CSIドライバで提供したい機能に応じて実装するgRPCメソッドは異なる。
▌gRPCのAPIを通じて、ドライバ?コンポーネントが提供する機能を
Kubernetes や CSI sidecar に伝える。
? GetPluginCapabilities (Identityサービス)
? ControllerGetCapabilities (Controllerサービス)
? NodeGetCapabilities (Nodeサービス)
21
func (ns *nodeServer) NodeGetCapabilities(ctx context.Context,
req *csi.NodeGetCapabilitiesRequest) (*csi.NodeGetCapabilitiesResponse, error) {
return &csi.NodeGetCapabilitiesResponse{
Capabilities: []*csi.NodeServiceCapability{
{
Type: &csi.NodeServiceCapability_Rpc{
Rpc: &csi.NodeServiceCapability_RPC{
Type: csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME,
},
},
},
...
},
}, nil
}
Capabilityの設定例
22https://github.com/kubernetes-csi/csi-driver-host-path/blob/v1.3.0/pkg/hostpath/nodeserver.go#L279-L299
CSIドライバで提供する機能に応じ、
capabilityを列挙する
NodePublishVolumeの例
▌領域をPodが利用可能な状態にする。
? ファイルシステムの場合、指定されたpathにファイルシステムをマウントする。
? Rawブロックデバイスの場合、指定されたpathにデバイスファイルを用意する。
23
targetPath := req.GetTargetPath()
...
if req.GetVolumeCapability().GetBlock() != nil {
...
loopDevice, err := volPathHandler.GetLoopDevice(vol.VolPath)
...
mount.New("").Mount(loopDevice, targetPath, "", options)
...
}
...
return &csi.NodePublishVolumeResponse{}, nil
https://github.com/kubernetes-csi/csi-driver-host-path/blob/v1.3.0/pkg/hostpath/nodeserver.go#L50-L189
loop deviceを作成している
引数で渡された場所に loop
device をマウントしている
プロシージャ実装時の注意点
▌CSIプロシージャは冪等性を満たすように実装する必要がある。
? Kubernetes 側でプロシージャの成否を取得できなかった場合などに、再度プロ
シージャを呼び出すことを許容するため。
? capacityやparameterが許容可能であれば、正常終了のレスポンスを返す。
24
CSIDriverの例
▌CSIドライバの存在と機能を Kubernetes に伝える
25
apiVersion: storage.k8s.io/v1beta1
kind: CSIDriver
metadata:
name: topolvm.cybozu.com
spec:
attachRequired: true
podInfoOnMount: true
volumeLifecycleModes:
- Persistent
- Ephemeral
該当CSIドライバが提供している機能についての定義
https://github.com/cybozu-go/topolvm/blob/v0.4.8/deploy/manifests/controller.yaml#L2-L11
該当CSIドライバが Kubernetes に要求する
挙動についての定義
CSIドライバのテスト
26
CSI Driver Sanity Tester
▌Kubernetes プロジェクトから提供されるCSIドライバのテストツール。
? https://github.com/kubernetes-csi/csi-
test/tree/master/pkg/sanity
▌CSIドライバを起動した状態で、gRPC の応答が正しく実装されているか
をテストしてくれる。
▌コマンドラインから起動 / Ginkgo (Go言語のTesting Framework)
から利用。
27
Tip: 手戻りをなくすため、最初からテストを実行できるようにする。
Sanity Testerの利用例
28
var _ = Describe("TopoLVM", func() {
Context("CSI sanity", func() {
... テスト対象のCSIドライバを起動しておく
sanity.GinkgoTest(&sanity.Config{
Address: "/tmp/topolvm/worker1/plugins/topolvm.cybozu.com/node/csi-topolvm.sock",
ControllerAddress: "/tmp/topolvm/worker1/plugins/topolvm.cybozu.com/controller/csi-topolvm.sock",
TargetPath: "/tmp/topolvm/worker1/plugins/topolvm.cybozu.com/node/mountdir",
StagingPath: "/tmp/topolvm/worker1/plugins/topolvm.cybozu.com/node/stagingdir",
TestVolumeSize: 1073741824,
IDGen: &sanity.DefaultIDGenerator{},
})
})
})
https://github.com/cybozu-go/topolvm/blob/v0.4.8/e2e/suite_test.go#L99-L137
Controller と Node の両方のエンドポイントに
アクセス可能な環境で実行
Sanity Tester 以外のテスト
▌Sanity Testerだけでは全てのテストをカバーしているわけではない。
▌実際にストレージが使えるかのE2Eテストを行っていない。
? Cybozuで開発しているCSIドライバ (TopoLVM) では、 kindを利用したE2E
テストを別途実施している。
▌個々のCSIドライバの実装に関する単体テストも必要に応じて追加する。
29
オプション機能の拡張方法
30
Volume Expansion 機能を提供する
▌定義するCapabilities
? EXPAND_VOLUME (ControllerCapabilities)
? EXPAND_VOLUME (NodeCapabilities)
▌実装するメソッド
? ControllerExpandVolume (Controllerサービス)
? NodeExpandVolume (Nodeサービス)
▌Sidecarとして external-resizer を追加
▌StorageClass に allowVolumeExpansion を定義
31
ControllerExpandVolumeの例
▌サイズの変更が可能かどうかを判定する。
requestGb, err := convertRequestCapacity(req.GetCapacityRange().GetRequiredBytes(),
req.GetCapacityRange().GetLimitBytes())
...
if requestGb <= currentGb {
return &csi.ControllerExpandVolumeResponse{
CapacityBytes: currentGb << 30,
NodeExpansionRequired: true,
}, nil
}
...
if capacity < (requestGb<<30 - currentGb<<30) {
return nil, status.Error(codes.Internal, "not enough space")
}
...
return &csi.ControllerExpandVolumeResponse{
CapacityBytes: requestGb << 30,
NodeExpansionRequired: true,
}, nil
領域の縮小が要求される場合もある
領域の拡張を許容する場合
NodeExpansionRequired が true の場合、
Node の NodeExpandVolume (次スライド) が呼ばれる
https://github.com/cybozu-go/topolvm/blob/v0.4.8/driver/controller.go#L310-L376 32
NodeExpandVolumeの例
▌各ノード上で、サイズ変更後のVolumeを利用可能にする。
? TopoLVMではlvmd (Kubernetes node 上の daemon) でlvを拡張してい
るため、NodeExpandVolume ではファイルシステムの拡張のみを行う。
33
vpath := req.GetVolumePath()
...
err = fs.Resize(vpath)
...
return &csi.NodeExpandVolumeResponse{}, nil
https://github.com/cybozu-go/topolvm/blob/v0.4.8/driver/node.go#L414-L498
Dynamic Provisioning 機能を提供する
▌定義するCapabilities
? CREATE_DELETE_VOLUME (ControllerCapabilities)
▌実装するメソッド
? CreateVolume (Controllerサービス)
? DeleteVolume (Controllerサービス)
▌Sidecarとして external-provisioner を追加
▌StorageClass の provisioner と、GetPluginInfo で戻すnameの
値を同じにしておく。
34
詳しい実装はTopoLVMを参照
ドキュメント?参考情報
35
CSIのバージョンについて
▌CSIのバージョンはKubernetesと
独立している。
▌Kubernetes v1.13 のタイミン
グで CSIはGAとなりバージョンが
1.0になった。
36https://github.com/container-storage-interface/spec/releases
CSI sidecarのバージョンについて
▌各sidecarのバージョンはspecか
ら独立して管理される
? CSIがGAになった後に追加された機
能もあり、機能ごとにalpha, beta,
GAの状況は異なる
▌Kubernetes, spec, sidecar
のバージョンの対応については、各
sidecarのReleasesに記載があ
る。
37https://github.com/kubernetes-csi/external-provisioner/releases
参考となるCSIドライバ
▌sig-storage でCSIドライバのサンプルを公開している。
▌https://github.com/kubernetes-csi/
? csi-driver-host-path
? csi-driver-nfs
? csi-driver-smb
38
既存のCSIドライバ
▌以下のページより既存のCSIドライバ一覧が探すことが可能。
? https://kubernetes-csi.github.io/docs/drivers.html
▌サイボウズでもTopoLVMというCSIドライバを開発?公開している。
? 各NodeのLVM領域を動的に提供する。
? Topologyを考慮し、ストレージ容量の空きが多いNodeにPodが優先配置され
る。
? https://blog.cybozu.io/entry/2019/11/08/090000
39
ドキュメント
▌Container Storage Interface (CSI) のspec
https://github.com/container-storage-interface/spec/
▌CSI Volume Plugins in Kubernetes Design Doc
https://github.com/kubernetes/community/blob/master/contribut
ors/design-proposals/storage/container-storage-interface.md
▌Kubernetes CSI Developer Documentation
https://kubernetes-csi.github.io/docs/introduction.html
▌各sidecarのREADME.mdにオプションなどが記載されている
40
まとめ
▌シンプルなCSIドライバを例に、実装方法ついて説明した。
? まだたくさんのドキュメントを読む必要がある。
? 特にCSIのspecは、詳細まで記述してある。
▌実装時の注意点?Tipについて説明した。
? CSIドライバで提供したい機能に合わせて利用するsidecarや実装するプロシー
ジャが変わる。
? CSIドライバのプロシージャは冪等性を満たす必要がある。
? 開発初期からSanity Testerを利用し、手戻りを防ぐ。
41

More Related Content

Container Storage Interface のすべて