この記事はリクルートライフスタイル Advent Calendar 2016の10日目の記事です。
DEPRECATED! [2020/12/05追記]
この記事内のコマンドは現在のバージョンの挙動と一部異なっていたり、説明に不正確な部分があります。
例えば公式のチュートリアルなど、信頼できる情報を参照ください。
https://kubernetes.io/ja/docs/tutorials/kubernetes-basics/
2019/05/30追記
下記内容は若干の不正確を含みますので、軽く読み流して雰囲気を掴んでいただいたあとは
https://qiita.com/Kta-M/items/ce475c0063d3d3f36d5d
などご参照いただくとよいかと思います。
こんばんは
「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には触りません。
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がどうなってるか確認しましょう。
[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を確認してみましょう。
[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
にアクセスしてみましょう。
表示されたらOKです。ちなみに今まで作成していたものの全体像はこんな感じです。
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みたいなので気にしなくていのかな…?
設定の中身を見ていきましょう。
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
を使うと、containers
のimage
で引っ張ってきたイメージが変わった場合に、ちょっとずつ古いimageのpodから更新してくれます。これで安全にdeployできそう。
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>
describe
はget
より細かく確認するコマンドです。うまく作成できてるかserviceにアクセスし…おや…どこにアクセスすればいいのか?
spec:
selector:
name: web-server
type: LoadBalancer
イントロダクションではserviceをexposeしてロードバランサーと紐付けましたが、今回はserviceを作成したときにロードバランサーを同時に作っていたのでした。
さっきのようにserviceの外部IPを確認して、アクセスしてみましょう。
無事にnginx経由でwebサーバーにアクセスできました!最終的に作成されたものはこんなイメージです。
作成したものを消したいときには
kubectl delete <type> <name>
です。例えばkubectl delete pods --all
とかやるとpodが全て消えます。deploymentが存在する限り、そのdeploymentが管理するpodは無限に蘇るので、二度とpodが立ち上がらないようにするときはkubectl delete deployments web-server
などと打ちます。
まとめ
k8sの基本的な使い方について、ざっくり説明してみました。
今回はhttpで行いましたが、httpsも使えます。他にもIngressなど紹介できていない機能がたくさんあります。
省いた説明も大いにあるので、ぜひkubernetes本家のチュートリアルやいろいろな入門コンテンツをご参考ください。
日本語の記事がまだまだ少ないので、何かの参考になれば幸いです。