Kubernetes1.8のリリースが話題になっていたので、ちょっと触って見たという話。 (1.8を触ったとは言っていない。)

具体的には、Kubernetes Basicsというチュートリアルをやりながら、MinikubeGoslingsをデプロイしたんだけど、この記事ではMinikubeをセットアップしたところまで。

Kubernetesとは

KubernetesはOSSのコンテナオーケストレーションツール。 英語だとクーバネティスみたいに発音する。 Googleが自身のコンテナ技術であるBorgの運用で培ったノウハウを活かして開発したもの。 2014年ころに開発が始まり、2015年夏にv1がリリースされたということで、かなり新しいツール。 よく比べられるものにはDockerのSwarmモードApache Mesosがあるが、何が違うのかは調べてないので知らない。 ただ、Dockerコンテナ管理ツールとしてはKubernetesが一番勢いがある雰囲気を感じる。

(2017/10/18追記: DockerがKubernetesとの統合を発表した。KubernetesはDockerネイティブなツールになり、Dockerとともにインストールされ、Docker ComposeのConposeファイルでデプロイできるようになったりする。Kubernetesの大勝利っぽい。)

Kubernetesを使うと、複数の物理マシンからなるHAクラスタ(Kubernetesクラスタ)を構成し、その上にコンテナをデプロイして管理できる。 Kubernetesクラスタは、一組のMasterコンポーネント群(a.k.a. Kubernetes Control Plane、または単にMaster)と一つ以上のNode(昔はMinionと呼ばれてたもの)で構成される。 Nodeは、Masterの管理下でコンテナを実行する機能を備えた、一台のVMや物理マシン。 MasterはNode上で動き、クラスタを管理し、コンテナのスケジューリング、状態管理、スケーリング、アップデートなどを担う。

Kubernetesのアーキテクチャを図にすると以下の感じ。 矢印の向きとかはちょっと間違ってるかも。

architecture

ごちゃごちゃするので省いたけど、図の下部のNode内のコンポーネントは、他のNode内でも動いている。


Masterにはkube-apiserverが含まれていて、Kubernetes APIというREST APIを公開する。 このAPIを通してKubernetesオブジェクトを定義したりすることで、宣言的にコンテナの管理ができる仕組み。 ユーザは普通、kubectl(キューブシーティーエル)というコマンドでkube-apiserverとやり取りする。

KubernetesオブジェクトはMasterのetcdによって分散キーバリューストアに永続化され、そのストアをkube-controller-managerkube-schedulerが(kube-apiserver経由で)watchしてて、変更に応じた処理をする。

kube-controller-managerは、ノードの管理や、オブジェクトのライフサイクルの管理や、コンテナのスケーリングなど、クラスタレベルの機能を実行する。 (よくわからない。)

kube-schedulerは、コンテナを実行するホストを選出し、コンテナのスケジューリングをする。


一方、各Nodeでは、kubelet(キューブレット)というMasterのエージェントになるプロセスが動く。

kubeletはkube-apiserverからの指示で、コンテナイメージを取得してコンテナを起動したり監視したり止めたりする。

kubeletがコンテナを扱うためのコンテナランタイムは、普通はDockerだけど、rktとかcri-oとかfraktiとかも使える。runcRailCarはどうなんだろう。

コンテナはデフォルトではクラスタ内のプライベートネットワークにつながるので、そこで動いているアプリにユーザからアクセスするには、何らかの形でトラフィックを中継してやる必要がある。 これをするのがkube-proxy。 ロードバランシングもしてくれる。

Kubernetesオブジェクトとは

Kubernetesオブジェクトは、Kubernetesクラスタ上で機能する構成要素を表現するもの。 オブジェクトはspecとstatusを持ち、オブジェクトに期待する状態やふるまい(spec)を定義しておくと、Kubernetesが実際の状態(status)をそれに合わせてくれる。 宣言的。

オブジェクトには以下のようなものがある。

  • Pod

    デプロイの最小単位。 一つ(またはリソースを共有する複数)のコンテナと、ストレージ、ネットワークなどを内包する。 一つのPodには一つのIPアドレスが付く。

    kubeletはPodの定義に従ってコンテナを起動する。

    因みに、etcd以外のMasterコンポーネントもPodとしてデプロイされる。

  • Service

    Podの論理グループ。 PodのIPアドレスは外部に公開されないので、外とのやり取りをするためにServiceがある。 kube-proxyはこいつの定義に従って働く。

    Serviceには複数のEndpoint(i.e. Pod等)が紐づき、外部からのトラフィックをラウンドロビンでルーティングするので、冗長化やロードバランサ的な働きもする。 ServiceはPodを抽象化するので、Podが死んだり入れ替わったりしても外に影響が見えにくくなる。

    Serviceには以下のtypeがある。

    • ClusterIP (デフォルト): Kubernetesクラスタ内からだけアクセスできる内部IPアドレスだけをもつ。
    • NodePort: ClusterIPの拡張。内部IPアドレスに加え、クラスタ外からアクセスできるポートを一つ持つ。
    • LoadBalancer: NodePortの拡張。外部ロードバランサを作って、固定の外部IPアドレスを付けて、内部IPアドレスへルーティングする。
    • ExternalName: 抽象名をもつサービス。Kubernetes DNS serverで名前解決する。詳細は読んでないので知らない。
  • Volume

    永続化やPod内でのファイル共有のためのオブジェクト。 Podとともに作られ、Podとともに破棄される。 実態はファイルシステム上のディレクトリ。 hostPathとか、nfsとか、awsElasticBlockStoreとかの種類があるらしい。

  • Namespace

    仮想クラスタを表すオブジェクト。 これを定義すると、ひとつの物理クラスタを複数の仮想クラスタに分割できる。 大規模ユーザ・プロジェクト向け機能。

  • Controller

    Podを管理するオブジェクト。レプリケーションしたり、スケーリングや自動再起動したり。

    以下のようなものがある。

    • Deployment

      Podのデプロイを管理するオブジェクト。 PodとReplicaSetの宣言的な生成・更新を実現する。

    • ReplicaSet

      指定した数のPodのレプリカを維持してくれる。 基本はDeploymentから作られて、Podの作成・削除・更新をオーケストレイトする。 ReplicationControllerというのもあるけど、今はReplicaSetが推奨。

    • StatefulSet

      ステートフルなアプリを管理するオブジェクト。 現時点でのKubernetes最新版の1.8でまだベータ。

    • DaemonSet

      全てのノードで動くアプリを実現するオブジェクト。

    • Job

      ジョブを表すオブジェクト。 指定された回数、Podを成功で完了させる。


オブジェクトにはラベルというキーバリューな属性を付けることができ、PodとServiceの紐づけや、オブジェクト検索時のフィルタとかに使える。


今回Goslingsを動かすのに使ったのは、Pod、Deployment、ReplicaSet、Service (NodePort)。

Podネットワーク

ちょっと細かい話だけど、Pod間の通信はどうなっているかという話についてちょっと調べたのでざっくり書いておく。

普通のDockerネットワークだと、コンテナはdocker0という仮想ブリッジ上のプライベートネットワークで動くため、同じホスト上のコンテナ間は通信できるけど、別のホスト上のコンテナ通信させたい場合は、ホストのIPアドレスのポートを割り当ててやらなければいけない。

これはめんどいので、Kubernetesは、各Podに一意なIPアドレスを与え、Podがどのホストにいるかにかかわらず、NAT無しで相互に通信できるネットワークを提供する。 これがPodネットワークとか呼ばれ、その仕様はCNIでオープンに定められていて、以下のような実装がある。

Minikubeとは

Kubernetesクラスタを構築する方法はいくつかあるが、中でももっとも簡単な方法がMinikube。

Minikubeは、単一NodeのKubernetesクラスタを詰めたVMをダウンロードして起動して、ローカルのkubectlから使えるようにしてくれるツール。 Linux、Windows、OS Xで動き、開発やテスト用途のKubernetes環境として使われる。

ちょっとVagrantっぽい感じ。Kubernetes専用の。

Minikubeインストール

Kubernetesのドキュメントにしたがって、Minikubeをインストールする。 環境はWindows 10 Home x64。

まず、MinikubeのVMを動かす仮想化ツールを入れる。 今のところMinikubeがサポートしてるのは、WindowsだとVirtualBoxHyper-V。 Windows 10 HomeだとHyper-Vが使えないので、VirtualBox一択。 VirtualBoxは、適当にVT-xを有効にして(してあった)、インストーラダウンロードしてインストールしただけ。 バージョンは5.1.28。


次に、minikubeコマンドを入れる。 このコマンドはGoで書かれていて、各プラットフォーム用にビルドされたバイナリがGitHubのプロジェクトページのReleasesに上がってるので、ダウンロードしてPathの通ったとこに置くだけ。 今回ダウンロードしたのはv0.22.2のminikube-windows-amd64で、これをminikube.exeにリネームして配置した。

で、minikubeがサポートしているKubernetesのバージョンを調べると、

C:\Users\kaitoy>minikube get-k8s-versions
The following Kubernetes versions are available:
        - v1.7.5
        - v1.7.4
        - v1.7.3
        - v1.7.2
        - v1.7.0
        (snip)

1.8はまだサポートされていない…

1.7.5が最新なのでそれでやることにする。


ということで、kubectlの1.7.5をインストールする。 kubectlもGoで書かれているので、以下のアドレスからWindowsバイナリをダウンロードしてPathの通ったところに置くだけ。

https://storage.googleapis.com/kubernetes-release/release/v1.7.5/bin/windows/amd64/kubectl.exe


以上でMinikubeの環境ができた。 簡単。

Minikube起動

Minikubeは、minikube startで起動することができ、Minikubeが起動したらすぐにKubernetesをいじれるようになる。

C:\Users\kaitoy>minikube start --vm-driver virtualbox --kubernetes-version v1.7.5
Starting local Kubernetes v1.7.5 cluster...
Starting VM...
Downloading Minikube ISO
 106.37 MB / 106.37 MB [============================================] 100.00% 0s
Getting VM IP address...
Moving files into cluster...
Setting up certs...
Connecting to cluster...
Setting up kubeconfig...
Starting cluster components...
Kubectl is now configured to use the cluster.

C:\Users\kaitoy>minikube status
minikube: Running
cluster: Running
kubectl: Correctly Configured: pointing to minikube-vm at 192.168.99.100

起動した。 VirtualBoxのGUIを見ると、minikubeというVMが起動しているのが分かる。 この中でKubernetesクラスタが動いているはずだ。

このVMには、minikube sshでログインできる。

C:\Users\kaitoy>minikube ssh
                         _             _
            _         _ ( )           ( )
  ___ ___  (_)  ___  (_)| |/')  _   _ | |_      __
/' _ ` _ `\| |/' _ `\| || , <  ( ) ( )| '_`\  /'__`\
| ( ) ( ) || || ( ) || || |\`\ | (_) || |_) )(  ___/
(_) (_) (_)(_)(_) (_)(_)(_) (_)`\___/'(_,__/'`\____)

$ uname -a
Linux minikube 4.9.13 #1 SMP Fri Sep 15 23:35:16 UTC 2017 x86_64 GNU/Linux

すごくVagrantっぽい。


Minikubeを起動すると、kubectlのコンテキストがminikubeというものに設定され、kubectlコマンドの接続先がMinikubeのKubernetesになる。

C:\Users\kaitoy>kubectl config current-context
minikube


で、kubectlでクラスタの状態とかを見てみようと思ったら、なんか様子が変。 なしのつぶて。

C:\Users\kaitoy>kubectl get nodes
Unable to connect to the server: dial tcp 192.168.99.100:8443: connectex: No connection could be made because the target machine actively refused it.

C:\Users\kaitoy>kubectl cluster-info dump
Unable to connect to the server: dial tcp 192.168.99.100:8443: connectex: No connection could be made because the target machine actively refused it.

C:\Users\kaitoy>minikube dashboard
Could not find finalized endpoint being pointed to by kubernetes-dashboard: Error validating service: Error getting service kubernetes-dashboard: Get https://192.168.99.100:8443/api/v1/namespaces/kube-system/services/kubernetes-dashboard: dial tcp 192.168.99.100:8443: connectex: No connection could be made because the target machine actively refused it.

再度minikube statusしてみたら、クラスタが落ちていた。

C:\Users\kaitoy>minikube status
minikube: Running
cluster: Stopped
kubectl: Correctly Configured: pointing to minikube-vm at 192.168.99.100


minikube logsでログを見てみると、エラーがたくさん出ていた。 以下のようなログが最初のほうに出てたので、認証系がだめで、サービス間でやり取りができなかったんじゃないかという感じ。

Oct 04 23:08:43 minikube localkube[2783]: W1004 23:08:43.599396    2783 authentication.go:368] AnonymousAuth is not allowed with the AllowAll authorizer.  Resetting AnonymousAuth to false. You should use a different authorizer


エラーの原因はよくわからないので、Kubernetesのバージョンをちょっと古いの(1.7.0)変えてみる。

kubectlの1.7.0をPathに置いて、Minikubeを1.7.0で再起動する。

C:\Users\kaitoy>minikube stop
Stopping local Kubernetes cluster...
Machine stopped.

C:\Users\kaitoy>minikube start --vm-driver virtualbox --kubernetes-version v1.7.0
Starting local Kubernetes v1.7.0 cluster...
Starting VM...
Getting VM IP address...
Kubernetes version downgrade is not supported. Using version: v1.7.5
Moving files into cluster...
Setting up certs...
Connecting to cluster...
Setting up kubeconfig...
Starting cluster components...
Kubectl is now configured to use the cluster.

Kubernetesのダウングレードはサポートされてないと言われた。 ので一回VMを消してからやりなおす。

C:\Users\kaitoy>minikube stop
Stopping local Kubernetes cluster...
Machine stopped.

C:\Users\kaitoy>minikube delete
Deleting local Kubernetes cluster...
Machine deleted.

C:\Users\kaitoy>minikube start --vm-driver virtualbox --kubernetes-version v1.7.0
Starting local Kubernetes v1.7.0 cluster...
Starting VM...
Getting VM IP address...
Moving files into cluster...
Setting up certs...
Connecting to cluster...
Setting up kubeconfig...
Starting cluster components...
Kubectl is now configured to use the cluster.

1.7.0で動いた。


様子はどうか。

C:\Users\kaitoy\Desktop\bin\pleiades\workspace\blog>minikube status
minikube: Running
cluster: Running
kubectl: Correctly Configured: pointing to minikube-vm at 192.168.99.100

C:\Users\kaitoy\Desktop\bin\pleiades\workspace\blog>kubectl get nodes
NAME       STATUS    AGE       VERSION
minikube   Ready     22s       v1.7.0

C:\Users\kaitoy\Desktop\bin\pleiades\workspace\blog>kubectl version
Client Version: version.Info{Major:"1", Minor:"7", GitVersion:"v1.7.0", GitCommit:"d3ada0119e776222f11ec7945e6d860061339aad", GitTreeState:"clean", BuildDate:"2017-06-29T23:15:59Z", GoVersion:"go1.8.3", Compiler:"gc", Platform:"windows/amd64"}
Server Version: version.Info{Major:"1", Minor:"7", GitVersion:"v1.7.0", GitCommit:"d3ada0119e776222f11ec7945e6d860061339aad", GitTreeState:"dirty", BuildDate:"2017-10-04T09:25:40Z", GoVersion:"go1.8.3", Compiler:"gc", Platform:"linux/amd64"}

ちゃんと動いているっぽい。


ダッシュボードだけはなぜか相変わらず開けないけどまあいいか。

C:\Users\kaitoy>minikube dashboard
Could not find finalized endpoint being pointed to by kubernetes-dashboard: Error validating service: Error getting service kubernetes-dashboard: services "kubernetes-dashboard" not found


続きはまた別の記事


因みに、ベーシック認証ありのプロキシ環境でMinikube on Windowsする場合は、まず以下の環境変数を設定:

NO_PROXYの値はminikube ipの値。 で、

minikube start --docker-env HTTP_PROXY=http://%http_proxy% --docker-env HTTPS_PROXY=https://%https_proxy% --docker-env NO_PROXY=%NO_PROXY%みたいにすればできる。

はず。(参考: https://github.com/kubernetes/minikube/issues/530)