最近めちゃくちゃ良く聞くようになりましたので、話についてけないので調べてみました。
Webを見てるだけだと良く分からなかったので公式のTutorialをやってみることにしました。
- Tutorials - Hello Minikube
https://kubernetes.io/docs/tutorials/hello-minikube/
Tutorialの内容は、Node.jsのHello worldアプリをDockerイメージに落としてK8sで動かすものです。 k8sといってもMinikubeという簡易版を使ってローカルPCで動かすようですが。
セットアップ
このTutrialにはDocker for Macも必要ですが、すでに入っているので割愛。
まず、Home brewでMiniCubeをインストールします。
$ brew cask install minikube
続いて手順に従って、HyperKit driverをインストールします。
最後にkubectlをインストールします。
$ brew install kubernetes-cli
Minikube クラスタの起動
minikube start
でMinKubeを起動します。--vm-driver
オプションでhyperkitを指定します。
$ minikube start --vm-driver=hyperkit
Starting local Kubernetes v1.10.0 cluster...
Starting VM...
Downloading Minikube ISO
160.27 MB / 160.27 MB [============================================] 100.00% 0s
Getting VM IP address...
Moving files into cluster...
Downloading kubeadm v1.10.0
Downloading kubelet v1.10.0
Finished Downloading kubelet v1.10.0
Finished Downloading kubeadm v1.10.0
Setting up certs...
Connecting to cluster...
Setting up kubeconfig...
Starting cluster components...
Kubectl is now configured to use the cluster.
Loading cached images from config file.
Turorialに従い、Contextを切り替えます。
~/.kube/config
を見るとどうやらminikube
というcontextが勝手に登録されてるようなのでそれを使います。
実行すると問題が発生。
$ kubectl config use-context minikube
failed MSpanList_Insert 0xc0b000 0x148027ce3801 0x0
fatal error: MSpanList_Insert
ググると、私の環境に入っているGoogle Cloud SDKが古いせいみたいなので、gcloud components update
した後でやったらうまく行きました。
$ kubectl config use-context minikube
Switched to context "minikube".
kubectl cluster-info
を叩くと、Kubernetes masterとKubeDNSというのが動いているようです。
$ kubectl cluster-info
Kubernetes master is running at https://192.168.64.2:8443
KubeDNS is running at https://192.168.64.2:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
まだ全く使いこなせませんが、minikube dashboard
でダッシュボードが開けるようです。メモリは1.5GBぐらい食っていて貧弱な私のPCでは辛いです。
サンプルアプリケーションの作成
NodeでHello Worldするだけのアプリを作成します。server.jsというファイル名で保存します。
var http = require('http');
var handleRequest = function(request, response) {
console.log('Received request for URL: ' + request.url);
response.writeHead(200);
response.end('Hello World!');
};
var www = http.createServer(handleRequest);
www.listen(8080);
TutorialにしたがってDockerfileも作成します。
FROM node:6.9.2
EXPOSE 8080
COPY server.js .
CMD node server.js
次に、docker buildしてイメージを作成します。
$ docker build -t hello-node:v1 .
出来ました。docker images
の一番上が今ビルドしたものですが、関連してたくさんのimageが取得されていることが分かります。
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE
hello-node v1 479cfa661a95 8 hours ago 655MB
k8s.gcr.io/kube-proxy-amd64 v1.10.0 bfc21aadc7d3 6 months ago 97MB
k8s.gcr.io/kube-controller-manager-amd64 v1.10.0 ad86dbed1555 6 months ago 148MB
k8s.gcr.io/kube-apiserver-amd64 v1.10.0 af20925d51a3 6 months ago 225MB
k8s.gcr.io/kube-scheduler-amd64 v1.10.0 704ba848e69a 6 months ago 50.4MB
k8s.gcr.io/etcd-amd64 3.1.12 52920ad46f5b 6 months ago 193MB
k8s.gcr.io/kube-addon-manager v8.6 9c16409588eb 7 months ago 78.4MB
k8s.gcr.io/k8s-dns-dnsmasq-nanny-amd64 1.14.8 c2ce1ffb51ed 8 months ago 41MB
k8s.gcr.io/k8s-dns-sidecar-amd64 1.14.8 6f7f2dc7fab5 8 months ago 42.2MB
k8s.gcr.io/k8s-dns-kube-dns-amd64 1.14.8 80cc5ea4b547 8 months ago 50.5MB
k8s.gcr.io/pause-amd64 3.1 da86e6ba6ca1 9 months ago 742kB
k8s.gcr.io/kubernetes-dashboard-amd64 v1.8.1 e94d2f21bc0c 9 months ago 121MB
gcr.io/k8s-minikube/storage-provisioner v1.8.1 4689081edb10 10 months ago 80.8MB
node 6.9.2 faaadb4aaf9b 21 months ago 655MB
サンプルアプリケーションの起動
kubectl run
でコンテナを起動します。--image-pull-policy=Never
とすることでローカルのイメージだけが使用されます。ただ、なぜかエラーになりました。
$ kubectl run hello-node --image=hello-node:v1 --port=8080 --image-pull-policy=Never
error: failed to discover supported resources: Get https://192.168.64.2:8443/apis/apps/v1beta1?timeout=32s: http2: no cached connection was available
単純にもう一度実行したら正常起動しました。何でだろう。
$ kubectl run hello-node --image=hello-node:v1 --port=8080 --image-pull-policy=Never
deployment.apps/hello-node created
確認コマンド色々
Podはコンテナを束ねる単位で、DeploymentはPodを管理するもののようですが、確認しろというのでそれぞれコマンドを叩いて状態を確認してみます。
$ kubectl get pods NAME READY STATUS RESTARTS AGE
hello-node-57c6b66f9c-lz4ll 1/1 Running 0 1m
$ kubectl get deployments NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
hello-node 1 1 1 1 53s
kubectl get events
で内部のイベントを確認できるそうです。
$ kubectl get events
LAST SEEN FIRST SEEN COUNT NAME KIND SUBOBJECT TYPE REASON SOURCE MESSAGE
3m 3m 1 hello-node-57c6b66f9c-lz4ll.15572ff0e4dd83b8 Pod Normal Scheduled default-scheduler Successfully assigned hello-node-57c6b66f9c-lz4ll to minikube
3m 3m 1 hello-node-57c6b66f9c.15572ff0d9febff2 ReplicaSet Normal SuccessfulCreate replicaset-controller Created pod: hello-node-57c6b66f9c-lz4ll
3m 3m 1 hello-node.15572ff0cfc21ad7 Deployment Normal ScalingReplicaSet deployment-controller Scaled up replica set hello-node-57c6b66f9c to 1
3m 3m 1 hello-node-57c6b66f9c-lz4ll.15572ff114eaea55 Pod Normal SuccessfulMountVolume kubelet, minikube MountVolume.SetUp succeeded for volume "default-token-jd4sd"
2m 2m 1 hello-node-57c6b66f9c-lz4ll.15572ff2b28df380 Pod spec.containers{hello-node} Normal Pulled kubelet, minikube Container image "hello-node:v1" already present on machine
2m 2m 1 hello-node-57c6b66f9c-lz4ll.15572ff2dc1480b1 Pod spec.containers{hello-node} Normal Created kubelet, minikube Created container
2m 2m 1 hello-node-57c6b66f9c-lz4ll.15572ff32abf3df6 Pod spec.containers{hello-node} Normal Started kubelet, minikube Started container
最初の方で、~/.kube/config
を参照しましたが、コマンドでも見れるようです。
$ kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority: /Users/foo/.minikube/ca.crt
server: https://192.168.64.2:8443
name: minikube
contexts:
- context:
cluster: minikube
user: minikube
name: minikube
current-context: minikube
kind: Config
preferences: {}
users:
- name: minikube
user:
client-certificate: /Users/foo/.minikube/client.crt
client-key: /Users/foo/.minikube/client.key
サービスの有効化
kubectl get services
するとサンプルアプリが出てこない。
$ kubectl get services 9:59:28
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 12h
kubectl expose
することで初めて使えるようになるようです。
$ kubectl expose deployment hello-node --type=LoadBalancer
service/hello-node exposed
$ kubectl get services 10:01:54
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-node LoadBalancer 10.100.26.53 <pending> 8080:31578/TCP 48s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 12h
アプリを動かしてみる
minikube service hello-node
とすることで、ブラウザでアプリを開けます。
$ minikube service hello-node
ログの確認
kubectl logs <Pod名>
でログを確認できます。console.log
したものが見れるようです。
$ kubectl logs hello-node-57c6b66f9c-lz4ll
Received request for URL: /
Received request for URL: /favicon.ico
サンプルアプリケーションのバージョンアップ
今度はアプリのバージョンアップについて試していきます。 server.jsで表示しているメッセージを書き換えます。
< response.end('Hello World!');
---
> response.end('Hello World Again!');
v2としてDockerビルドします。
$ docker build -t hello-node:v2 .
kubectl set image
でイメージを更新します。
$ kubectl set image deployment/hello-node hello-node=hello-node:v2
deployment.extensions/hello-node image updated
minikube service hello-node
でブラウザを開くと変更が反映されています。 まあ簡単。
後始末
Serviceを削除します。
$ kubectl delete service hello-node
service "hello-node" deleted
$ kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 13h
Deploymentを削除します。
$ kubectl delete deployment hello-node deployment.extensions "hello-node" deleted
Dockerイメージも不要なので削除。
$ docker rmi hello-node:v1 hello-node:v2 -f
Minikubeを停止。
$ minikube stop
Stopping local Kubernetes cluster...
Machine stopped.
ただ初回はしばらく待った挙句エラーになり停止できませんでした。単純にリトライしたら何事もなく停止しましたが、何だろう。
$ minikube stop Stopping local Kubernetes cluster...
Error stopping machine: Error stopping host: minikube: Maximum number of retries (60) exceeded
環境変数も消しておきます。
$ eval $(minikube docker-env -u)
Minikube VMも削除しておきます。
$ minikube delete
Deleting local Kubernetes cluster...
Machine deleted.
おわりに
- hyperkitが1.6GB、com.docker.hyperkitが1.5GBと、メモリ消費が激しいので私のMacBook Air 2013(メモリ4GB)では辛かった。
- MacBook Proタッチバーなしメモリ沢山モデル、頼む出してくれ
- クラウドで動くイメージだったけど開発環境はローカルで作れるみたい
- ローカルと本番の環境差異が少なそうなので、それは良さげ
- ただ、よく分からないエラーも発生したので実際に使う時つらいかも
- 大まかな構成は理解できたものの、複数コンテナ扱う場合の起動順とか、複雑なことはこれから
- 会社に転がってた本を借りてきたので、足りない知識は補っていく
技術評論社
とりあえず雰囲気は少し掴んだので、話に少しはついていけそう。