Help us understand the problem. What is going on with this article?

Kubernetes Operator

この記事は リクルートライフスタイル Advent Calendar 2018 の18日目の記事です。

はじめに

CETチーム 兼 新規サービス開発を担当している @shotat です。

先週シアトルで KubeCon + CloudNativeCon North America 2018 (以下KubeCon) が開催されました。自分も現地シアトルへ向かい、KubeConに参加してきました。なお、KubeConはキューブ(kjúːb)コンと発音するようです。

KubeConの規模は年々増加傾向にあり、今回は8000人以上のattendeeがいたようで、Kubernetes Communityの盛り上がりを肌で感じることができました。
KubeConではService meshやMachine Learning等様々なテーマが語られていたのですが、中でも CRD(CustomResourceDefinition)・Custom Controller・Operator 等、KubernetesのExtensibilityについての言及が非常に多く、キーノートや様々なセッションで繰り返し登場していたのが印象的でした。

本記事では、 上述の Kubernetes Operator についての概要について簡単にまとめ、実際に動かして見ます。

Kubernetes Operator の概要

Operator とは

Kubernetes OperatorはCoreOSによって2016年に提唱された概念で、以下のブログに詳細が記述されています。

Operatorを一言でまとめると、 "アプリケーション特化型のKubernetes Controller" です。
複雑になりがちなStatefulアプリケーションの運用(scaling, backup, failover, upgrade 等)を自動化することがOperatorの役割です。

何故 Operator が必要なのか

StatelessなアプリケーションであればKubernetesのDeployments等である程度十分に実用レベルの運用が可能といえます。
しかし、Statefulなアプリケーションはより複雑な運用タスクが必要であり、アプリケーション毎に最適な運用方法は異なります。
Statefulなアプリケーションを正しくスケーリング・アップデートするにはアプリケーション固有の運用知見が必要になります。
こういったアプリケーション固有の運用を人間の手で行うのは非常に骨が折れるため、運用知見をコード化してKubernetes上の仕組みに乗せてしまおう!という思想がOperatorに繋がります。

仕組み

Kubernetes Control Loop

前提としてまずKubernetesの Control Loop について簡単に復習しておきます。詳細は Kubernetesの公式ドキュメント をご参照下さい。

Kubernetes内ではDesired Stateと実際のCurrent State(Actual State, Observed State表記もあり)を一致・更新させる処理のループを回しており、これをControl Loopと呼びます。
またDesired StateとCurrent Stateの乖離を埋める働きをReconciliationと呼びます。

Desired Stateは kubectl apply ... コマンド等でKubernetesユーザがAPI経由で直接登録・更新することができ、実際にどうやってCurrent StateをDesired Stateに近づけていくかはKubernetesユーザはほとんど意識しなくて良いインタフェースになっています。

つまり、ユーザはKubernetesに対して宣言的に What を伝えるだけで良く、 How の部分(Reconciliation Logic)はKubernetes内部に隠蔽されています。

Operator

Operatorは Custom ResourceCustom Controller から成り立ちます。
Custom ResourceはKubernetes上に登録可能な独自リソースであり、上述の What 部に相当します。
Custom Resourceを作成するには CRD (CustomResourceDefinition) という機能を利用します。
CRDに独自のリソース(Kind: MySQL等)とそのスペックを定義してKubernetes上に登録することで、Custom Resourceの利用が可能になります。

一方Custom Controllerは上述の How に相当し、どのようにCurrent StateとDesired Stateを一致させるか(Reconciliation Logic)を担います。Operatorの文脈ではCustom ResourceをCustom Controllerが扱う対象とします。

つまり、Custom Resourceに定義されたDesired Stateを実現するのがCustom Controllerであり、これらを一括りにOperatorと呼びます。

Operator を動かしてみる

理解を深めるために実際にOperatorを利用し、動作を観察してみます。
KubeConのキーノートではUberが M3DB Operator について紹介していたので、今回はそちらを使ってみようと思います。
なお、M3DBはUberが開発している時系列データベースです。

また、以下のGitHub Repositoryに他にもいくつかのOperatorが公開されています。

GKE クラスタの作成

https://github.com/m3db/m3db-operator のREADMEに記述されている以下の制約に従ってGKEクラスタを立てます。

  • Kubernetes 1.10 and 1.11
  • Kubernetes clusters with nodes in at least 3 zones
$ gcloud container clusters create m3db-example \
    --zone us-central1-a \
    --node-locations us-central1-a,us-central1-b,us-central1-c

クラスタが構築できたらkubectlを先程構築したクラスタに向けましょう。

$ gcloud container clusters get-credentials m3db-example --zone us-central1-a --project <PROJECT_NAME>

Fetching cluster endpoint and auth data.
kubeconfig entry generated for m3db-example.

GKEのドキュメント にも記載されているように、RoleBindingを設定が必要です。

$ kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=<name@domain.com>

clusterrolebinding.rbac.authorization.k8s.io/cluster-admin-binding created

Operatorのデプロイ

ドキュメントに従い、以下のコマンドでM3DB Operatorをデプロイします。

$ kubectl apply -f https://raw.githubusercontent.com/m3db/m3db-operator/v0.1.1/bundle.yaml

bundle.yaml の中身を覗いてみます。すると、m3db-operatorは quay.io/m3db/m3db-operator:v0.1.1 というImageを使ったStatefulSetであるということが分かります。
また、必ずしもStatefulSetを使う必要はなく、他のOperatorの例を見ると普通のDeploymentだったりします。

# ...中略
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: m3db-operator
  namespace: default
spec:
  serviceName: m3db-operator
  replicas: 1
  selector:
    matchLabels:
      name: m3db-operator
  template:
    metadata:
      labels:
        name: m3db-operator
    spec:
      containers:
        - name: m3db-operator
          image: quay.io/m3db/m3db-operator:v0.1.1
          command:
          - m3db-operator
          imagePullPolicy: Always
          env:
            - name: ENVIRONMENT
              value: production
      serviceAccount: m3db-operator

この時点でOperatorのログを確認してみると、CustomResourceDefinitionが生成されていることが分かります。

$ kubectl logs pod/m3db-operator-0 | grep CRD
{"level":"error","ts":1544814329.1473405,"caller":"k8sops/crd.go:67","msg":"could not get CRD","error":"customresourcedefinitions.apiextensions.k8s.io \"m3dbclusters.operator.m3db.io\" not found","stacktrace":"github.com/m3db/m3db-operator/pkg/k8sops.(*k8sops).GetCRD\n\t/go/src/github.com/m3db/m3db-operator/pkg/k8sops/crd.go:67\ngithub.com/m3db/m3db-operator/pkg/k8sops.(*k8sops).CreateCRD\n\t/go/src/github.com/m3db/m3db-operator/pkg/k8sops/crd.go:75\ngithub.com/m3db/m3db-operator/pkg/controller.(*Controller).Init\n\t/go/src/github.com/m3db/m3db-operator/pkg/controller/controller.go:223\nmain.main\n\t/go/src/github.com/m3db/m3db-operator/cmd/m3db-operator/main.go:187\nruntime.main\n\t/usr/local/go/src/runtime/proc.go:198"}
{"level":"info","ts":1544814329.6673043,"caller":"k8sops/crd.go:113","msg":"CRD created"}

kubectlコマンドでCRDが生成されていることも確認してみます。

$ kubectl get crd
NAME                                    CREATED AT
m3dbclusters.operator.m3db.io           2018-12-14T19:05:29Z
$ kubectl describe crd m3dbclusters.operator.m3db.io
Name:         m3dbclusters.operator.m3db.io
Namespace:
Labels:       <none>
Annotations:  <none>
API Version:  apiextensions.k8s.io/v1beta1
Kind:         CustomResourceDefinition
Metadata:
  Creation Timestamp:  2018-12-14T19:05:29Z
  Generation:          1
  Resource Version:    3077
  Self Link:           /apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions/m3dbclusters.operator.m3db.io
  UID:                 38d89036-ffd3-11e8-9a7e-42010a800140
Spec:
  Group:  operator.m3db.io
  Names:
    Kind:       M3DBCluster
    List Kind:  M3DBClusterList
    Plural:     m3dbclusters
    Singular:   m3dbcluster
  Scope:        Namespaced
  Version:      v1alpha1
Status:
  Accepted Names:
    Kind:       M3DBCluster
    List Kind:  M3DBClusterList
    Plural:     m3dbclusters
    Singular:   m3dbcluster
  Conditions:
    Last Transition Time:  2018-12-14T19:05:29Z
    Message:               no conflicts found
    Reason:                NoConflicts
    Status:                True
    Type:                  NamesAccepted
    Last Transition Time:  2018-12-14T19:05:29Z
    Message:               the initial names have been accepted
    Reason:                InitialNamesAccepted
    Status:                True
    Type:                  Established
Events:                    <none>

このCustomResourceDefinitionでは M3DBCluster というCustom Resourceが定義されていることが分かります。
M3DB Operator(Controller)はこの M3DBCluster リソースを扱うことになります。

M3DB クラスタの構築

M3DBのクラスタを構築してみます。
M3DBはクラスタトポロジやメタデータを etcd に保存するため、まずはetcdを構築します。

$ kubectl apply -f https://raw.githubusercontent.com/m3db/m3db-operator/v0.1.1/example/etcd/etcd-basic.yaml

CustomResourceDefinitionに従い、M3DBCluster リソースを作成してみましょう。
以下のファイルを m3db-cluster.yaml として保存し、applyします。

apiVersion: operator.m3db.io/v1alpha1
kind: M3DBCluster
metadata:
  name: simple-cluster
spec:
  image: quay.io/m3db/m3dbnode:latest
  replicationFactor: 3
  numberOfShards: 256
  isolationGroups:
    - name: us-central1-a
      numInstances: 1
    - name: us-central1-b
      numInstances: 1
    - name: us-central1-c
      numInstances: 1
  podIdentityConfig:
    sources:
      - PodUID
  namespaces:
    - name: metrics-10s:2d
      preset: 10s:2d
$ kubectl apply -f m3db-cluster.yaml
m3dbcluster.operator.m3db.io/simple-cluster created

上記のmanifestをapplyして少し待つとKubernetes上にM3DBが構築されます。

$ kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
etcd-0                  1/1     Running   0          ...
etcd-1                  1/1     Running   0          ...
etcd-2                  1/1     Running   0          ...
m3db-operator-0         1/1     Running   0          ...
simple-cluster-rep0-0   1/1     Running   0          ...
simple-cluster-rep1-0   1/1     Running   0          ...
simple-cluster-rep2-0   1/1     Running   0          ...
$ kubectl get m3dbcluster
NAME             CREATED AT
simple-cluster   ...

無事Operatorを使ってクラスタを立てることができました。

Operator を作成する

今まで、OperatorがCustom ControllerとCustom Resourceによって動作することを確認してきましたが、実際にはどうやってOperatorを作成すれば良いのでしょうか。Custom ControllerにはKubernetes APIを利用してReconciliation Logicを記述する必要がありますが、フルスクラッチで処理を書くのは相当厳しいと思います。

Operator Framework

そこで、Operator Frameworkの利用が可能です。
中でもOperator SDKを使うことで、Kubernetes APIの詳細を知らずともCRDの生成やReconsilication Logicの実装に集中できるようになります(Golangがサポートされています)。

Operator Frameworkを利用することでKubernetes APIを詳細に理解せずともReconcile ロジックの実装に集中できるようになります。

(実際にOperator Frameworkで何かOperatorを作る...というところまでやりたかったのですが、それはまた別の機会に。)

まとめ

本記事ではKubernetes Operatorを紹介しました。
今後はメジャーなStatefulアプリケーション運用のベストプラクティスを吸収したOperatorがOSSとして急速に発展していくのではないかと期待しています。

recruitlifestyle
飲食・美容・旅行領域の情報サイトや『Airレジ』などの業務支援サービスなど、日常消費領域に関わるサービスの提供するリクルートグループの中核企業
http://www.recruit-lifestyle.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした