初心者
入門
Docker
kubernetes
ハンズオン
More than 1 year has passed since last update.

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


こんばんは

「sshするときの-p 443ってなんの数字ですか?」ぐらいの素人がインフラ周りを担当し8ヶ月、kubernetes始めました。

そんな初心者に送るkubernetes入門記事です。


なんでわざわざkubernetes?

一般のwebサイトはサーバーの上で動いているわけですが、このサーバーが1台だとこんな問題が起きます。


  • キャンペーンをやったら急にアクセスが集中して負荷に耐え切れず、webサイト全体がダウンしてしまった

  • サーバーのライブラリをアップデートしたら変なエラーが出るようになってしまった

ああ大変だ。こうなっては困るので、サーバーを複数台にする対策があります。冗長化と呼ばれます。

ラウンドロビンの話は飛ばしますが、最近だとAWSやGCPでロードバランサーと呼ばれるアクセス分配器的なものを用意して、いくつかのサーバーにアクセスをバラすのがナウいです。

クラウドサービスを使っていれば、オートスケーリングと呼ばれる機能で、サーバーの台数を自動で増減することができます。

しかしこの冗長化構成にも新たな要求が出てきます。


  • サーバーの台数を少なめにしておくと、急にアクセスが来た時にサーバー台数を増やすのが間に合わず、結局サービスが落ちてしまう

  • かといって多く用意しておくと、アクセスが少ない時にお金がもったいない

  • Immutable Infrastructureとはいうものの、デプロイの度にサーバー入れ替えるの時間かかる

ああ困った。そこにkubernetes(以下k8s)が現れます。 k8sはこれらの問題に対して以下のようなメリットを与えます。


  • サーバー台数と関係なく、複数のapplicationを起動できる(コンピュータ資源の最適化ができる)

  • 負荷に応じてapplicationごとに自動で数を増減できる

  • サーバーを入れ替えることなくapplicationのデプロイができる。軽いものならば数秒程度

k8sを使うには、通常はmasterと呼ばれる親機とnodeと呼ばれる子機サーバーを用意して、k8sをそれぞれインストールし、それぞれ通信設定…めんどくさいです。

しかし、 AWSのECSやGCPのGKEのようなk8sのマネージドサービス上で展開すれば、masterとnodeは数分で勝手に準備され、不調になったnodeは自動で入れ替わる、さらにnodeの数も増減できる、などいいことだらけ。

ということで長くなりましたが、ここからGKE上で実際にハンズオンをしていきましょう。


前準備

まずGCPのセットアップです。無料使用期間あるので、入門記事など参考に登録しましょう。gcloudとかkubectlとか含めてセットアップが終わったら次のコマンドを叩きます。

gcloud container clusters create k0 

コーヒーを淹れるくらいの時間で、上述のmasterとnode(defaultだと3台)が立ち上がります。nodeとはGCPでのVM、AWSでのinstanceに相当します。GKE上では基本的にmasterには触りません。


result

Creating cluster k0...done.

Created [https://container.googleapis.com/v1/projects/user/zones/asia-east1-a/clusters/k0].
kubeconfig entry generated for k0.
NAME ZONE MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS
k0 asia-east1-a 1.4.6 104.199.249.239 n1-standard-1 1.4.6 3 RUNNING


1.イントロダクション

細かいことは飛ばして、とりあえず動かしましょう。

kubectl run nginx --image=nginx:1.11.3

何が起きたかというと、さっき立ち上げたnode内で、podが動き始めました。


podとは?

nodeの中で動いているdocker containerの集まり、みたいなイメージです。k8sでは、nodeの集合(nodes)のパワー全体をリソースとして、podがいくつも立ち上がります。

面白いのは、あるnodeにはpodAとpodBが1つずつ、あるnodeにはpodBが3つ、といったように、node全体としてpodsを共有している点です。

pod1つの中に、任意の数のdocker containerを詰め込むことが可能です。nginxとweb apllicationとredisとか。pod 1 つに対して内部IPが 1 つ割り当てられ、container間で共有できるvolumeも任意の数持てます。


引数で指定したのは、Docker Hub 公式のnginx containerです。つまり上のコマンドは「nginx imageを使ってpodを作れ」という意味になります。

ではnginxのpodがどうなってるか確認しましょう。


result

[user:~]$ kubectl get pods

NAME READY STATUS RESTARTS AGE
nginx-527997929-1m6nj 1/1 Running 0 22s

kubectl get <name>nameの概要を見れます。無事作成できました。

でもこれだと、nodesの中でcontainerが動いてるだけなので外部からアクセスできません。外部アクセスさせるために次のコマンドを打ちます。

kubectl expose deployment nginx --port 80 --type LoadBalancer

これで、serviceとロードバランサーが作られました。


serviceとは?

pods(podの集合)に対して外部と通信を行うための通り道みたいなものです。serviceひとつにpodsがぶらさがって、serviceに来たアクセスをどれかのpodにいい感じで分配します(内部に賢いroutingがいます)。


今回はオプションに LoadBalancer を指定したので、GCP上に外部IPを持ったロードバランサーが作成され、その外部IPに対してのアクセスがserviceに来るようになります。

これで、さっき作成したnginx入りのpodが外部IPと紐付きました。serviceを確認してみましょう。


result

[user:~]$ kubectl get services

NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes 10.23.240.1 <none> 443/TCP 6m
nginx 10.23.248.197 104.198.112.131 80/TCP 1m

今回はnginxという名前でserviceが作成されました。一緒にでてくるkubernetesはmasterからnodeに通信する用のserviceです。

作成されたロードバランサーの外部IP 104.198.112.131にアクセスしてみましょう。




スクリーンショット 2016-12-08 16.10.10.png

表示されたらOKです。ちなみに今まで作成していたものの全体像はこんな感じです。


スクリーンショット 2016-12-08 16.10.10.png


2.カスタマイズしたpodとserviceを作る

さっきはdefaultのnginx imageを使いましたが、今度はカスタマイズして、nginx+webアプリの構成でpodを作ってみましょう。

サンプルを用意したので、利用するコードをgit cloneしてください。

git clone https://github.com/mihirat/advent.git

cd /path/to/advent/kubernetes
cd k8s

ここにあるdeployment.ymlがpodの設定、service.ymlがserviceの設定になります。

ちなみにpath/to/advent/kubernetes/docker というディレクトリに今回のdocker imageの設定があります、ご参考まで。本ハンズオンではDockerHubにあるものを使ってください。


deploymentとは?

podを管理するコントローラーであるReplication Controllerとpodの両方を一括で管理できるものです。k8sはアップデートが早いので、1年前の記事とかだとReplication Controllerとpodを別で作成していることが多いのですが、絶対にdeploymentを使った方が楽です。

お気づきかもしれませんが、イントロダクションの段階からずっとdeploymentを使っていました。

実はbetaですが、もう1年近くbetaみたいなので気にしなくていのかな…?


設定の中身を見ていきましょう。


deployment.yml

etc...

strategy:
type: RollingUpdate
...
containers:
- name: go-server
image: mihirat/go-server
...
readinessProbe:
httpGet:
# Path to probe; should be cheap, but representative of typical behavior
path: /readiness.html
etc...

↑部分のRollingUpdateを使うと、containersimageで引っ張ってきたイメージが変わった場合に、ちょっとずつ古いimageのpodから更新してくれます。これで安全にdeployできそう。


service.yml

spec:

selector:
name: web-server

ここで対象podのlabelを指定しており、podのlabelの名前を対応させることで、serviceとpodが対応付けられます。

readinessProbeとは?死活監視の仕組みをざっと説明します。


死活監視の仕組み

podが生きてるかどうかを、いわゆるロードバランサーの仕組みと同じように内部で監視しています。

各nodeでkubeletという監視等するプロセスが走っており、「調子はどうだい?」とpodに定期的に呼びかけます。死んでた場合にはdeployment(replication controller)により入れ替え・増減されます。


サンプルでは、nginxの設定内部で /readiness.html にアクセスが来たら200を返すようにしてあるので、nginx自体が通常通り稼働していれば、状態がreadyとしてkubeletに認知されます。

これと別にlivenessProbeもありますが今は略。


3.実際に動かしてみる

これらを以下のコマンドで作成しましょう。

kubectl apply -f k8s/deployment.yml

kubectl apply -f k8s/service.yml

これで、deploymentと同時にpodが生成され、serviceが生成されます。作成したもろもろを細かく確認するコマンドとして

kubectl describe {pods|services|deployments} <name>

describegetより細かく確認するコマンドです。うまく作成できてるかserviceにアクセスし…おや…どこにアクセスすればいいのか?


service.yml

spec:

selector:
name: web-server
type: LoadBalancer

イントロダクションではserviceをexposeしてロードバランサーと紐付けましたが、今回はserviceを作成したときにロードバランサーを同時に作っていたのでした。

さっきのようにserviceの外部IPを確認して、アクセスしてみましょう。


スクリーンショット 2016-12-08 16.22.11.png

無事にnginx経由でwebサーバーにアクセスできました!最終的に作成されたものはこんなイメージです。


スクリーンショット 2016-12-08 16.22.11.png

作成したものを消したいときには

kubectl delete <type> <name>

です。例えばkubectl delete pods --allとかやるとpodが全て消えます。deploymentが存在する限り、そのdeploymentが管理するpodは無限に蘇るので、二度とpodが立ち上がらないようにするときはkubectl delete deployments web-serverなどと打ちます。


まとめ

k8sの基本的な使い方について、ざっくり説明してみました。

今回はhttpで行いましたが、httpsも使えます。他にもIngressなど紹介できていない機能がたくさんあります。

省いた説明も大いにあるので、ぜひkubernetes本家のチュートリアルいろいろな入門コンテンツをご参考ください。

日本語の記事がまだまだ少ないので、何かの参考になれば幸いです。