マンガっぽくKubernetesを勉強してみる②
Kubernetesを動かす
甘いもの食べてアタマ休ませたいよ〜
…こほん。今ギャルちゃん(API)がお菓子(リソース)を持ってきて、わたしが食べ(登録)たら仕事し始めたように、Kubernetesも同じような動きをするよ
なんとっ!?
この記事の着地点
Kubernetesを動かすための基本的な操作、全体像を理解する。
勉強中のため、記載した内容については後日訂正する可能性もあります。
Kubernetesの基本的な操作
前回、Kubernetesの全体構成を図に描いてみたけど、Master Nodeにいるkube-apiserverにyml登録の指示をしていたね
クライアントにいるkubectlで登録するんですよねー
そう。実際には、ymlに書かれたリソース情報をAPI経由でMasterに登録しているんだよ
じゃあわたしたちはymlの書き方と、kubectlの使い方が分かればOKってことね♪
kubectlでもいいし↓でAPIの仕様を見て、直接プログラムに組み込んで登録することもできる
リソースの種類について
リソースは大きく分類すると5種類あるみたい。今時点の理解はこんな感じかな…
Workloadsリソース
コンテナ起動のためのリソース
Discovery & LBリソース
コンテナへのルーティング、ロードバランシングのためのリソース
Config & Storageリソース
各種設定、データ格納のためのリソース
Clusterリソース
セキュリティ、CPU/メモリ割り当てのためのリソース
Metadataリソース
コンテナ制御のためのリソース
こんなにたくさん…まぁ色々やってくれるんだから仕方ないかぁ…
開発者が特に気にするのは上の3つらしいよ。下2つはより運用的な話かな…
でもそれぞれymlで定義するんだから、一回作っちゃえば流用もしやすいはず!
未来のわたしのため…がんばるっ
動作確認環境について
言ってなかったけど、今回の勉強は↓の書籍をバイブルにして、自分なりに理解しやすい順番・言葉で表現しています
仕組みだけでなくノウハウがギッシリ詰まった本なので、全てを網羅することは無理ですが…
Kubernetes完全ガイド (impress top gear)
- 作者: 青山真也
- 出版社/メーカー: インプレス
- 発売日: 2018/09/21
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
サンプルコードなどはこちらから抜粋させてもらいます♪
それと、今回はKatacodaのプレイグラウンドを利用してブラウザ上で確認しています
Kubernetes Playground | Katacoda
プレイグラウンドだと、Masterと1つのNodeが初めから準備されているね
# Master Node master $ kubectl get nodes ---- NAME STATUS ROLES AGE VERSION master Ready master 94m v1.14.0 node01 Ready <none> 93m v1.14.0
Nodeからだとkubectlコマンドエラーになる…なんでだろ
# Node
node01 $ kubectl get nodes
----
The connection to the server localhost:8080 was refused - did you specify the right host or port?
APIを実行するには、Masterの接続先情報と、認証情報が必要だからね。 今はMasterから実行できるし、いったん後回しにしよう
リソースを登録する
まずは基本的な操作で、ymlファイルからリソースを登録してみよう。ちなみに ymlファイルのことをKubernetesではマニフェストっていうらしいよ
この内容を実現します!っていうカンジ?笑
apiVersion: v1 kind: Pod metadata: name: sample-pod spec: containers: - name: nginx-container image: nginx:1.12
Podっていう種類のリソースっぽい?あ、dockerイメージも書いてある!
そう、PodはWorkloadsリソースの最小単位で、コンテナが1つ以上あるグループみたいなものかな。ここではnginxのコンテナをPodとして登録するよ
マニフェストからリソースを操作するためのコマンドは次の3つ
① 新規作成 kubectl create
② 更新 kubectl apply
③ 削除 kubectl delete
master $ kubectl apply -f sample-pod.yml
----
pod/sample-pod created
新規なのに、apply
コマンド?
apply
は、前回の差分を抽出して更新するんだけど、リソースが登録されてなかったら新規作成してくれるから、こっちのほうが推奨されてるんだ
な、なるほど〜?あ、Podも起動してるっぽい!
master $ kubectl get pods ---- NAME READY STATUS RESTARTS AGE sample-pod 1/1 Running 0 13s
Kubernetesで簡単なコンテナ構成を組んでみる
現状確認
まだPodが配置されただけで、通信も何もできない状態だね
そういえばDockerのときも同じだったね…ポートフォワード?
ローカルホスト宛の通信をポートフォワードするやり方もあるけど、Kubernetesはコンテナオーケストレーションツールだからね。 各Podに対してロードバランシングするためのリソースを作る必要があるんだ
ちなみに、今のリソースの全量はkubectl get all
で見れるよ
master $ kubectl get all ---- NAME READY STATUS RESTARTS AGE pod/sample-pod 1/1 Running 0 4m23s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 54m
ClusterIPっていうのがある…Podはさっき作ったやつだけど何だろ?
serviceっていうのがDiscovery & LBリソースの一つで、ロードバランシングをしてくれるやつだよ。 ClusterIPってのはそのServiceリソースのタイプのひとつなんだ
このservice/kubernetesってやつは、デフォルトで作られてるAPI接続用のServiceリソースみたい
Workloadsリソースでコンテナを配備
ということで、まずはPodを3つくらい作って動きを見てみようか
1個だと分からないもんね♪
ReplicaSetとDeployment
ReplicaSetリソースで、コンテナの複製(レプリカ)を作れるよ
コンテナのスケーリングってやつだね!
apiVersion: apps/v1 kind: ReplicaSet metadata: name: sample-rs spec: replicas: 3 selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app spec: containers: - name: nginx-container image: nginx:1.12 ports: - containerPort: 80
長くなってきた…あ、でもtemplateのspecは見覚えある!
そう、Podと同じだね。今回はコンテナのポートとラベルを書き加えてるけど
そのレプリカを3つ作るってことね!じゃあさっそくkubectl apply
で…
…と思ったけどやっぱりこっちのマニフェストで作ろう!
apiVersion: apps/v1 kind: Deployment metadata: name: sample-deployment spec: replicas: 3 selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app spec: containers: - name: nginx-container image: nginx:1.12 ports: - containerPort: 80
ええナゼっ!?…ってあれ、あまり変わらないような…リソースの種類が違う?
これはDeploymentリソース。ReplicaSetを管理して、コンテナのアップデートをサービスに影響無いよう、徐々にやってくれたり ロールバック出来るようになるんだ。
おぉ〜!これ一つでPodもReplicaSetも作れるなら、ラクチンでイイね♪
# Deploymentリソースを作成 master $ kubectl apply -f sample-deployment.yml ---- deployment.apps/sample-deployment created # podをsample-appラベルで絞って一覧表示 master $ kubectl get pods -l app=sample-app ---- NAME READY STATUS RESTARTS AGE sample-deployment-6cd85bd5f-f2v8h 1/1 Running 0 17s sample-deployment-6cd85bd5f-q9mtr 1/1 Running 0 17s sample-deployment-6cd85bd5f-xbl5x 1/1 Running 0 17s
サクッとできた!
コンテナが落ちると、マニフェストで指定したレプリカ数に戻るよ。試しにPod1つ削除してみよう
# 指定したPodを削除 master $ kubectl delete pod sample-deployment-6cd85bd5f-f2v8h ---- pod "sample-deployment-6cd85bd5f-f2v8h" deleted # 一覧表示 master $ kubectl get pods -l app=sample-app ---- NAME READY STATUS RESTARTS AGE sample-deployment-6cd85bd5f-q9mtr 1/1 Running 0 119s sample-deployment-6cd85bd5f-xbl5x 1/1 Running 0 119s sample-deployment-6cd85bd5f-xqbds 1/1 Running 0 35s
新しい名前のPodが1つ増えてるね、すっごい!
その他のWorkloadsリソース
Deploymentリソースさえ使えればカンペキかな!?
Workloadsリソースは他にもいくつかあるよ。特定の用途で使い分けが必要だね。
DaemonSetリソース
各ノードに1Podづつ配置したい場合に利用。1PodなのでReplicaは設定できない。
StatefulSetリソース
データベースなど、永続化データボリュームの利用が必要場合に利用。
Jobリソース
1度だけの処理を実行し、コンテナが終了するような場合に利用。
CronJobリソース
Jobを定期的に作成したい場合に利用。
Discovery & LBリソースでコンテナ疎通
じゃあ次はコンテナに外部からアクセスできるようにしていこう。
Serviceリソース…だっけ?
Discovery & LBリソースには、L4ロードバランシングをするServiceリソースと、L7ロードバランシングをするIngressリソースがあるよ。
(L4とL7ってなんだ…ググろ…)
ロードバランサー(L4)とL7ロードバランサー(Pulse Secure Virtual Traffic Manager)の違いを教えてください | ニフクラ
ClusterIPとExternalIP
ちなみに今の状態でも、コンテナ間のネットワークは作られてて、お互いに通信は出来るんだ
# Pod情報を確認 master $ kubectl get pods -o custom-columns="NAME:{metadata.name}, IP:{status.podIP}" ---- NAME IP sample-deployment-6cd85bd5f-q9mtr 10.44.0.2 sample-deployment-6cd85bd5f-xbl5x 10.44.0.3 sample-deployment-6cd85bd5f-xqbds 10.44.0.1 # Podのターミナルを開く master $ kubectl exec -it sample-deployment-6cd85bd5f-q9mtr /bin/bash # 確認用にcurlをインストール root@sample-deployment-6cd85bd5f-q9mtr:/# apt-get update && apt-get install -y curl # 1個めのPodから2個めのPodにリクエスト(curlコマンドでHTTPリクエスト結果コードのみを表示) root@sample-deployment-6cd85bd5f-q9mtr:/# curl -s http://10.44.0.3:80 -o /dev/null -w '%{http_code}\n' ---- 200
200は成功レスポンスだから…ホントだ!でも外からは接続できない、ってことよね?
そう。それにPodのIP指定でしか接続できないし、ロードバランシングもしてくれないんだ。 そんな時に使うのが、Serviceリソースだよ
マニフェストはこんな感じ
apiVersion: v1 kind: Service metadata: name: sample-clusterip spec: type: ClusterIP externalIPs: - 172.17.0.65 ports: - name: "http-port" protocol: "TCP" port: 8080 targetPort: 80 selector: app: sample-app
ここでClusterIPが出てくるのね!
ClusterIPは、Kubernetesクラスタ内部のネットワークで疎通が出来る仮想IPだよ。この場合 sample-clusteripに8080番ポートで接続が来たら、sample-appラベルがついたPodの80番ポートに分散される
externalIPってのもある…これは何のIPだろ?
これはNode自体のIPで、externalIPとして書くとNodeに対する接続をPodに転送することができるんだ
# NodeのIPアドレスを確認 master $ kubectl get nodes -o custom-columns="NAME:{metadata.name}, IP:{status.addresses[].address}" ---- NAME IP master 172.17.0.39 node01 172.17.0.65 # Nodeに対してHTTPリクエスト master $ curl -X GET http://172.17.0.65:8080 -o /dev/null -w '%{http_code}\n' ---- % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 612 100 612 0 0 282k 0 --:--:-- --:--:-- --:--:-- 597k 200
これでようやく、外部からコンテナに通信できるってワケね!
そう!ちなみにClusterIPだと、転送元にしたいNode分のIPを書く必要があるけど、 全てのNodeに対して転送させたい場合は、NodePortタイプがあるよ
その他のServiceタイプ
むむ…色々種類があるのね…アタマが混乱するぅ〜
他にもServiceリソースのタイプとしては↓があるけど、Discovery & LBリソースの基本はこんなところかな
LoadBalancerタイプ
Kubernetesクラスタ外部のLoadBalancerサービスから疎通できる仮想IP
Headlessタイプ
ロードバランシングでなく、クラスタ内DNSから順次PodのIPを返すタイプ(DNSラウンドロビン)
ExternalNameタイプ
外部ドメイン宛のCNAME(ドメインの別名)を返すタイプ
つづく!