Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

kubernetes入門

Cybozu
July 26, 2024
530

 kubernetes入門

Cybozu

July 26, 2024
Tweet

Transcript

  1. 目次 (前半) ▌ コンテナオーケストレーションの必要性 ▌ Kubernetesとは ▌ サイボウズとKubernetes ▌ Kubernetesの構造と動作

    ▌ Kubernetesの代表的なリソース ▌ Kubernetesクラスタへのアクセス (後半) ▌ 実際にKubernetesクラスタに触れてみる 2
  2. Kubernetesとは ▌ コンテナを複数のサーバー上で協調動作、管理するためのシステム(=コンテナオーケストレーション) ▌ Googleの社内で使用していた「borg」を元にして作られた 主要な機能 ⚫ 宣言的なリソースの管理 ⚫ 「あるべき状態」を定義する

    ⚫ スケジューリング ⚫ アプリケーションを複数のサーバーに適切にスケジュールする ⚫ サービスディスカバリーと負荷分散 ⚫ アプリケーション間の通信を容易にし、負荷分散を可能にする ⚫ セルフヒーリング ⚫ コンテナに障害が発生した際の自動回復 5
  3. Kubernetesが解決する問題 ▌ 運用の自動化 ⚫ デプロイのたびに煩雑なオペレーションを行わなくて済む ▌ 高可用性 ⚫ ローリングアップデート ⚫

    障害が発生したときの自動回復 ⚫ 負荷分散 ▌ サーバ群の抽象化 ⚫ ユーザはサーバ1個1個のことを考えずに、大量のサーバー上にアプリケーションをデ プロイできる 6
  4. Kubernetesの構造 9 control-plane クラスタを管理するためのコンポーネントの総称 • etcd • kube-apiserver • kube-scheduler

    • kube-controller-manager Node アプリケーションがデプロイされるサーバ(数台~数千台) • kubelet • kube-proxy CLIツールやプログ ラム等からの操作
  5. コントロールプレーンコンポーネント ▌ etcd • 分散KVS • リソースの情報が保存される ▌ kube-apiserver •

    リソースにアクセスするためのAPIサーバ • ユーザーや各コンポーネントからの操作はすべてkube-apiserverを経 由する • etcdに保存された情報を用いる ▌ kube-scheduler • 作成されたPod*をどのNodeに配置するかを決定する • *Pod:アプリケーションをデプロイする単位のこと(後で説明) • 配置には様々な条件式や設定が存在する ▌ kube-controller-manager • リソースの状態を管理するコンポーネント • リソースの状態を監視し、あるべき状態になるように操作する 10
  6. 宣言的な構成管理 ▌ Kubernetesはリソースの「あるべき状態」をmanifestで定義し、システムはそれを 満たすように動作する(=reconcile) 14 apiVersion: apps/v1 kind: Deployment metadata:

    name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80 Deploymentリソースの定義 app:nginxのラベルがついたPodが3個必要 Podリソースの定義 Nginxのコンテナを動かし、80番ポート を使う ※PodやDeploymentの概念は後で説明します ※例 手続的 宣言的 シェルスクリプトで作った インストールスクリプト Kubernetesのmanifest
  7. Pod ▌ アプリケーションをデプロイするための最小単位 ⚫ 1個以上のコンテナをまとめたもの ▌ Pod毎にIPアドレスを持ち、各コンテナはnetwork namespaceを共有する ▌ PID

    namespaceはコンテナ毎に別々(共有することも 可能) ▌ ファイルシステムもコンテナ毎に別々 17 よくある使い方 • アプリケーションのコンテナ • Proxyなどのコンテナ • メトリクスやログを取るコンテナ をまとめてPodにする
  8. Podのmanifest ▌ .spec以下にPodの設定を書く ▌ .spec.containers[]の配列にコンテナの設定を 書いていく ▌ .spec.containers[].commandがDockerの ENTRYPOINTに相当する 18

    apiVersion: v1 # リソースが属するグループの名前 kind: Pod # リソースの種類 metadata: name: my-pod # Podの名前 spec: containers: # コンテナの設定 - name: container-1 # 1つめのコンテナの設定 image: ubuntu:latest command: ["sleep", "infinity"] - name: container-2 # 2つめのコンテナの設定 image: ubuntu:latest command: ["sleep", "infinity"]
  9. ReplicaSet & Deployment ▌ ReplicaSet ⚫ 負荷分散・可用性のために、複数のPodをまとめたもの ⚫ ※Replicaset単体で使う事はほぼない ▌

    Deployment ⚫ ReplicaSetを用いてローリングアップデートの機能などを提供 する ▌ ReplicaSetのセルフヒーリング ⚫ ReplicaSetは指定した数のPodが動作することを保証する ⚫ Node故障などでPodが消されると、新しく作り直す 21 Nodeの故障などでPodを作り直す例
  10. Deploymentのマニフェスト 23 apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec:

    replicas: 3 # Podのレプリカ数 selector: matchLabels: # app:nginxのラベルを持つPodを配下にする app: nginx template: # 作成するPodのテンプレート metadata: labels: app: nginx # app:nginxのラベルをつける spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80 ▌ .spec以下にDeploymentの設定を書く ▌ .spec.replicsasがレプリカ数の設定 ▌ .spec.selectorで配下にするPodの指定をする ▌ .spec.templateにPodのテンプレートを書く
  11. Service ▌ Podとの通信を抽象化する ▌ 負荷分散の機能を持つ ▌ Podと通信をする時に、Podの名前やIPアドレスの直接指定は基本的にしない ⚫ Podのライフサイクルは短いので、IPアドレスはすぐに変わる ⚫

    特定のPodではなく、「ある機能を持つPodのどれか」で指定したい ▌ 4つのタイプがある ⚫ ClusterIP: クラスタ内のみでアクセスできる ⚫ NodePort: 各Nodeの指定したポートに来たトラフィックをPodに転送する ⚫ LoadBalancer: 外部のロードバランサーを利用してトラフィックを転送する ⚫ ExternalName:クラスタ外のドメインをServiceのCNAMEに登録する NodePort,LoadBalancerを使うことでクラスタ外からのアクセスを受け付けられる 24
  12. Serviceのmanifest 25 apiVersion: v1 kind: Service metadata: name: nginx-service spec:

    type:ClusterIP # Serviceのtypeを指定する selector: app: nginx # app:nginxのラベルを持つPodにトラフィックを流す ports: - protocol: TCP port: 80 # Serviceが公開するポート targetPort: 80 # トラフィックを流す先のPodのポート apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 # Podのレプリカ数 selector: matchLabels: # app:nginxのラベルを持つPodを配下にする app: nginx template: # 作成するPodのテンプレート metadata: labels: app: nginx # app:nginxのラベルをつける spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80 ↓のDeploymentに対するService .spec.typeでServiceのtypeを ClusterIP, NodePort, LoadBalancer, ExternalName から選ぶ .spec.selectorで対象のPodを選択する .spec.portsでプロトコルやポートの設定を行う
  13. Serviceのmanifest 先ほどのmanifestの例を挙げると・・・ nginx-service.default.svc.cluster.local:80 にアクセスが来ると、配下のnginxのPodにトラフィックが振り分けられる ▌ Nodeの障害などでPodが減った場合、そのPodは振り分け先から 自動的に外される ▌ Deploymentのセルフヒーリングによって新たにPodが作られた場合、 振り分け先に自動的に追加される

    26 apiVersion: v1 kind: Service metadata: name: nginx-service spec: type:ClusterIP # Serviceのtypeを指定する selector: app: nginx # app:nginxのラベルを持つPodにトラフィックを流す ports: - protocol: TCP port: 80 # Serviceが公開するポート targetPort: 80 # トラフィックを流す先のPodのポート
  14. kubectl ▌ Kubernetesクラスタを操作するためのCLIツール よく使うコマンド ▌ リソースの状態の取得(一覧) ⚫ kubectl get <リソース名>

    kubectl get pod ▌ リソースの状態の取得(個別) ⚫ kubectl get <リソース名> <名前> ⚫ 例:kubectl get pod example-pod ▌ manifestの適用 ⚫ kubectl apply –f <ファイル名> ⚫ 例: kubectl apply –f example-pod.yaml 30
  15. 実際にKubernetesクラスタを作って操作してみる ▌ kindというソフトウェアで、ローカル環境にKubernetesクラスタを作ることができる ▌ DockerコンテナでKubernetesノードを動かし、その中でコンテナが動作する (Docker in Docker) 32 https://kind.sigs.k8s.io/

    この章では、以下の資料の一部をかいつまんで説明します。 https://cybozu.github.io/introduction-to- kubernetes/introduction-to-kubernetes.html 興味のある方はご自身の環境でも試してみてください
  16. クラスタの立ち上げ $ kind create cluster でシングルノードのクラスタが立ち上がる Configを書いて指定すると複数ノードも可能 33 ❯ kind

    create cluster Creating cluster "kind" ... ✓ Ensuring node image (kindest/node:v1.27.3) ✓ Preparing nodes ✓ Writing configuration ✓ Starting control-plane ✓ Installing CNI ✓ Installing StorageClass Set kubectl context to "kind-kind" You can now use your cluster with: kubectl cluster-info --context kind-kind Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/#community
  17. クラスタの確認 34 ❯ kubectl get node NAME STATUS ROLES AGE

    VERSION kind-control-plane Ready control-plane 2m31s v1.27.3 $ kubectl get node でノード一覧を取得 1ノード作られていることがわかる
  18. Podをデプロイしてみる 35 apiVersion: v1 kind: Pod metadata: name: my-first-pod labels:

    component: nginx spec: containers: - name: nginx image: nginx:latest $ kubectl apply –f nginx-pod.yaml でmanifestを適用する ❯ kubectl apply -f nginx-pod.yaml pod/my-first-pod created # Podの名前 # コンテナの名前 # Podにつけるラベル # コンテナイメージ nginx-pod.yaml
  19. デプロイしたPodの確認 36 ❯ kubectl get pod NAME READY STATUS RESTARTS

    AGE my-first-pod 1/1 Running 0 3m47s ❯ kubectl exec -it my-first-pod -- bash root@my-first-pod:/# curl -i localhost:80 HTTP/1.1 200 OK Server: nginx/1.25.4 … $ kubectl get pod でpod一覧を取得 $ kubectl execでPodの中に入りシェルを実行、curlでnginxの動作を確認 ← my-first-podが作られている
  20. Podとの通信① 37 apiVersion: v1 kind: Pod metadata: name: bastion spec:

    containers: - name: bastion image: debian:stable command: ["sleep", "infinity"] Pod間の通信を行う方法 ①PodのIPアドレスを使う ②ServiceのClusterIPを使う ←まずはこちらを試す bastion.yaml $ kubectl apply -f bastion.yaml でmanifst適用 Bastion Pod nginx Pod Kubernetesクラスタ HTTP
  21. Podとの通信① 38 ❯ kubectl get pod -o wide NAME READY

    STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES bastion 1/1 Running 0 116m 10.244.0.6 kind-control-plane <none> <none> my-first-pod 1/1 Running 0 136m 10.244.0.5 kind-control-plane <none> <none> ❯ kubectl exec -it bastion -- bash root@bastion:/# apt update && apt install -y curl root@bastion:/# curl -i http://10.244.0.5 HTTP/1.1 200 OK Server: nginx/1.25.4 NginxのPodのIPアドレスは10.244.0.5 $ kubectl get pod でpod一覧を取得 $ kubectl execでbastion Podの中に入りシェルを実行、curlでnginx PodのIPアドレスにリクエストしてみる Bastion Pod nginx Pod Kubernetesクラスタ curl 10.244.0.5 10.244.0.5 10.244.0.6
  22. Podとの通信② 40 apiVersion: v1 kind: Service metadata: name: my-first-service spec:

    selector: component: nginx ports: - protocol: TCP port: 80 targetPort: 80 nginx-service.yaml #ここで設定したラベルを持つPod にトラフィックが振り分けられる 同様にこのmanifestを適用して Serviceをデプロイする Bastion Pod nginx Pod Kubernetesクラスタ Service
  23. Podとの通信② 41 ❯ kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP

    PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 160m my-first-service ClusterIP 10.96.207.133 <none> 80/TCP 4s ❯ kubectl exec -it bastion -- bash root@bastion:/# curl -i http://my-first-service/ HTTP/1.1 200 OK Server: nginx/1.25.4 $ kubectl execでbastion Podの中に入りシェルを実行 今度はservice名でリクエストを行う ※Kubernetes内にServiceのIPアドレスと名前を解決するDNSがあるので、Serviceの名前でアクセスできる Serviceが作られている
  24. 同じ Pod をいくつも立てる ▌ 前の節のように、複数の同じPodで冗 長構成にするのが一般的 ▌ ReplicaSetを用いて同じPodを指定 しただけ作る この例では、

    「component: nginxのラベルを持つ Podを3個デプロイする」 ということになる 42 apiVersion: apps/v1 kind: ReplicaSet metadata: name: nginx-replicaset labels: component: nginx spec: replicas: 3 selector: matchLabels: component: nginx template: metadata: labels: component: nginx spec: containers: - name: nginx image: nginx:latest nginx-replicaset.yaml #Podの数 #ここに一致した条件のPodをReplicaSetが管理する # Podのテンプレート
  25. デプロイしたReplicaSetの確認 43 ❯ kubectl get replicaset NAME DESIRED CURRENT READY

    AGE nginx-replicaset 3 3 3 7s ❯ kubectl get pod NAME READY STATUS RESTARTS AGE bastion 1/1 Running 0 149m my-first-pod 1/1 Running 0 169m nginx-replicaset-29jmp 1/1 Running 0 10s nginx-replicaset-8ph49 1/1 Running 0 10s 「component: nginxのラベルを持つPod」はすでに1個あったので、追加で2個作成される その際、Podの定義はtemplateに書いた内容が使われる
  26. ReplicaSetの動作の確認 44 ❯ kubectl delete pod my-first-pod pod "my-first-pod" deleted

    ❯ kubectl get pod NAME READY STATUS RESTARTS AGE bastion 1/1 Running 0 152m nginx-replicaset-29jmp 1/1 Running 0 2m51s nginx-replicaset-8ph49 1/1 Running 0 2m51s nginx-replicaset-cvrv5 1/1 Running 0 4s 「component: nginxのラベルを持つPod」を1個消してみる(my-first-pod) 削除された分、新た1個のPodが作成される
  27. ReplicaSetの動作の確認 45 ❯ vim nginx-replicaset.yaml ❯ kubectl apply -f nginx-replicaset.yaml

    replicaset.apps/nginx-replicaset configured ❯ kubectl get pod NAME READY STATUS RESTARTS AGE bastion 1/1 Running 0 153m nginx-replicaset-29jmp 1/1 Running 0 3m43s nginx-replicaset-8ph49 1/1 Running 0 3m43s nginx-replicaset-btlk4 1/1 Running 0 3s nginx-replicaset-cvrv5 1/1 Running 0 56s nginx-replicaset.yamlのreplicasを4に変更する replicasが4になり1個足りないので、追加で1個Podがデプロイされる ReplicaSetは定義されたレプリカ数を維持するようにPodを増やしたり減らしたりする
  28. Deploymentの作成 47 前の章で作成したReplicaSetは消しておきます $kubectl delete replicaset nginx-replicaset apiVersion: apps/v1 kind:

    Deployment metadata: name: nginx-deployment labels: component: nginx spec: replicas: 3 selector: matchLabels: component: nginx template: metadata: labels: component: nginx spec: containers: - name: nginx image: nginx:1.20 nginx-deployment.yaml ManifestはReplicaSetとほぼ同じで、リソース名が Deploymentになっているだけ
  29. デプロイしたDeploymentの確認 48 ❯ kubectl get deploy NAME READY UP-TO-DATE AVAILABLE

    AGE nginx-deployment 3/3 3 3 16s ❯ kubectl get pod -o 'custom- columns=NAME:.metadata.name,IMAGE:.spec.containers[*].image,PHASE:.status.phase' NAME IMAGE PHASE bastion debian:stable Running nginx-deployment-79b59fbc9b-k76vl nginx:1.20 Running nginx-deployment-79b59fbc9b-ppcbj nginx:1.20 Running nginx-deployment-79b59fbc9b-q5zgj nginx:1.20 Running ReplicaSetの時と同様、nginxのPodが3つデプロイされている ※実験のためコンテナイメージのバージョンを表示している
  30. ローリングアップデートしてみる 49 ❯ vim nginx-deployment.yaml ❯ kubectl apply -f nginx-deployment.yaml

    deployment.apps/nginx-deployment configured ❯ kubectl get pod -o 'custom-columns=NAME:.metadata.name,IMAGE:.spec.containers[*].image,PHASE:.status.phase' NAME IMAGE PHASE bastion debian:stable Running nginx-deployment-6566fcf8b5-bcl2s nginx:1.21 Pending nginx-deployment-79b59fbc9b-k76vl nginx:1.20 Running nginx-deployment-79b59fbc9b-ppcbj nginx:1.20 Running nginx-deployment-79b59fbc9b-q5zgj nginx:1.20 Running ❯ kubectl get replicaset NAME DESIRED CURRENT READY AGE nginx-deployment-6566fcf8b5 2 2 2 5m36s nginx-deployment-79b59fbc9b 2 2 1 6m52s コンテナイメージをnginx:1.20からnginx:1.21に書き換えて適用 新しいReplicaSetで1.21のPodが作られ、置き換えられていくことがわかる