5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

Kubernetes魅力的です!以下では、Kubernetesの基礎知識を書いていきます。
検証環境はAzureのAzure Kubernetes Service(以下、AKS)です。

Kubernetesとは

  • コンテナ化されたアプリケーションのデプロイメント、スケーリング、および管理を自動化するオープンソースのコンテナオーケストレーションプラットフォームです。以下、k8sと記載します。
    image.png

Kubernetesにおける重要概念

コンセプト

  • システム構築時の手間を減らす
  • 運用時の手間を減らす

上記を実現するための3つのコンセプトがある

  1. Immutable Infrastructure
  2. 宣言的設定
  3. 自己修復機能

Immutable Infrastructure

  • 従来の発想
    構築した後のサーバをバージョンアップしていく

  • k8sにおける発想
    一度構築したサーバは変更を加えずに破棄して、新しく作り直す。コンテナ技術などを使用して実現する

宣言的設定

  • 従来の発想
    命令的設定。手順書やパラメータシートに基づいて設定を行い、サーバに対して変更を加えた場合は変更履歴を管理していた。

  • k8sにおける発想
    システムのあるべき姿を定義ファイルに記述するとk8sクラスターが自動的にそうなるように状態を保とうとする。k8sのReconciliation Loopsなどを使用して実現する。

自己修復機能

  • 従来の発想
    システム管理者がリストアや再起動により障害復旧する

  • k8sにおける発想
    k8sがkubernetes APIにより自動的に障害を検知、復旧する

スケジューリングとディスカバリー

  • スケジューリング

それぞれのコンテナを適切なサーバ上に配置する仕組み。
このサービスはGPUを使いたい、などの要件がある場合に、それを定義ファイルに定義しておけばk8sがスケジューリングの機能で適切なサーバに配置してくれる=Resource Requests。

  • ディスカバリー

スケジューリングにより配置されたコンテナがどこのサーバに配置されているのかを見つけ出す仕組み。

マニフェストファイル

YAMLファイルの書き方

  • Key-Valueは「:」と半角スペースで区切る。
  • インデントは半角スペースのみでタブは使用できない。
  • コメントは「#」で行う
  • 整数、浮動小数点数、真偽値(true/false,yes/no)、null、日付、タイムスタンプは自動的にデータ型を判定する。上記以外と「’」か「”」で囲んだ場合は文字列として判定する。
  • 「-」と半角スペースからデータを始めることで配列の要素を表すことができる。

以下はnginxのコンテナを10台起動するReplicaSetのマニフェストファイル

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: webserver
spec:
  # Pod数
  replicas: 10
  selector:
    matchLabels:
  # 起動しておくPodのLabel
      app: webfront
# Podのテンプレート
  template:
    metadata:
      labels:
        app: webfront
    spec:
      containers:
      - image: nginx
        name: webfront-container
        ports:
          - containerPort: 80

マニフェストファイルは大体以下のような構成になっている。

apiVersion: [APIのバージョン情報]
kind: [リソースの種類]
metadata:
  name: [リソースの名前]
spec: 
[リソースの詳細]

Label

kubernetesではLabelの付け外しによって簡単に本番/検証環境を切り替えたり、Nodeの役割を変更したり、スケールアップ・ダウンするので、kubernetesの管理においてLabelは思ったより重要な概念なのである。
以下はDeploymentのマニフェストファイル。

# A. 基本項目
apiVersion: apps/v1
kind: Deployment
metadata:
  name: photoview-deployment

# B. Deploymentのスペック
spec:
  replicas: 5   # レプリカ数
  selector:
    matchLabels:
      app: photo-view   # テンプレートの検索条件

  # C. Podのテンプレート
  template:
    metadata:
      labels:
        app: photo-view
        env: stage
    spec:
      containers:
      - image: azfooacr01.azurecr.io/photo-view:v1.0   # コンテナイメージの場所
        name: photoview-container   # コンテナ名
        ports:
        - containerPort: 80   # ポート番号

podに対してlabelsで「app」ラベルを「photo-view」に、「env」ラベルを「stage」に定義している。
このようにラベルを使って適切にラベリングすることで、k8s内のリソースの管理を効率的に行うことができる。
各Podのラベルは以下のコマンドで表示することが可能。

kubectl get pods —show-labels

image.png

envラベルがstageであり、かつappラベルがphoto-viewでないPodだけを表示する

kubectl get pods -l env=stage,app!=photo-view

マニフェストファイルを変更してから以下のようなコマンドを使用すると徐々にPodのラベルが変更されている様子がわかる。

kubectl apply -f sample-deployment.yaml

image.png
なお、kubectl label deploymentコマンドを実行することでラベルを書き換えることも可能だが、構成管理の観点からもマニフェストファイルを変更することが推奨される。

NodeSelector

Podを動かすNodeを明示的に指定するためのKey。
以下は、serverラベルがwebapであるnodeで実行する例。

apiVersion: v1
kind: Pod
metadata:
 name: nginx
 labels:
  env: stage

spec:
 containers:
 - name: nginx
   image: nginx
 nodeSelector:
   server: webap

nodeにラベルをつけるコマンド

kubectl label node aks-nodepool-67404889-vmss000000 server=webap

Resource Requests

Podを実行するために必要最低限割り当てたいリソースを指定する。
上記を設定することによって、k8s schedulerが適切なノードを選択し、Podに十分なリソースを割り当てることができる。
以下はPodに400mのCPUと2Giのメモリを割り当てるように指定するマニフェストファイル。

apiVersion: v1
kind: Pod
metadata:
 name: requests-pod

spec:
 containers:
 - image: busybox
   command: ["dd", "if=/dev/zero", "of=/dev/null"]
   name: main
   resources:
    requests:
     cpu: 400m
     memory: 2Gi

実際にkubectl describe node [割り当てられたnode名]コマンドを実行すると、指定したリソースがpodに割り当たっていることがわかる。
image.png
Nodeのリソースを超えた値をResource Requestsで指定するとどうなるか。

  1. podのstatusがpendingになる
    image.png

  2. kubectl describe [podname]を実行するとnode欄がnoneになっている

  3. eventログにfailedschedulingが理由でmemoryがinsufficientである旨メッセージがでているのがわかる。
    image.png

Resource Limits

Podを実行する上でのリソースの上限を指定する。
上記を指定することによって、特定のPodが異常な量のリソースを使用してクラスター全体の動作を不安定なものにすることを防ぐ。

apiVersion: v1
kind: Pod
metadata:
 name: limits-pod

spec:
 containers:
 - name: main
   image: polinux/stress
   resources:
    limits:
     cpu: 400m
     memory: 1Gi
   command: ["stress"]
   args: ["--vm", "1", "--vm-bytes", "500M", "--vm-hang", "1"]

上限を超えた負荷をかけるとどうなるか。
stressコマンドの引数を500M→2Gにしてみると、Podが再起動を繰り返していることがわかる。
image.png

kubectl describe pod [podname]コマンドを使用すると削除されており(Terminated)理由は「OOMKilled」となっている。コンテナ内のOOM Killer(Linuxカーネルの機能であり、メモリ不測の際に実行中のプロセスを強制終了させる役割を持つ)にプロセスをkillされている。
image.png

Liveness Probe

プロセスの死活監視などとは異なる、”サービス”として正しく動いてるか、を監視してくれるk8sの監視機能。

  • httpGet

HTTPリクエストの戻り値をチェックする。

apiVersion: v1
kind: Pod
metadata: 
 name: liveness-pod

spec:
 containers:
 - name: liveness
   image: k8s.gcr.io/liveness
   args:
   - /server
   livenessProbe:
    httpGet:
     path: /healthz
     port: 8080
     httpHeaders:
     - name: Z-Custom-Header
       value: Awesome
    initialDelaySeconds: 10
    periodSeconds: 5
  • tcpSocket

HTTP以外のリクエストの戻り値をチェックする。

  • exec

コンテナ内でコマンドを実行しその結果が0で返ってくるかどうかをチェックする。

apiVersion: v1
kind: Pod
metadata:
 labels:
  test: liveness
 name: liveness-exec-pod

spec:
 containers:
 - name: liveness
   image: busybox
   args:
   - /bin/sh
   - -c
   - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
   livenessProbe:
    exec:
     command:
     - cat
     - /tmp/healthy
    initialDelaySeconds: 10
    periodSeconds: 5

describeコマンドよりeventログを見てみる。
コンテナ作成後30秒は/tmp/healthyが存在するため監視に成功する。
image.png

30秒経つと/tmp/healthyが削除されるため監視に失敗し、Podが削除、作成が繰り返されている
image.png
image.png

kubectlコマンド

ローカルのマニフェストファイルを用いてクラスター上にdeploymentをデプロイ

kubectl apply -f sample-deployment.yaml

上記のコマンドの流れ

  1. クライアントにてホームディレクトリの.kube/configに記載のk8sクラスターのAPI Serverに対して同ファイルに記載の認証情報を用いて接続要求を行う。
  2. 上記接続要求を受け取ったAPI Serverは認証を行い、合っていれば接続を確立する。
  3. クライアントにてsample-deployment.yamlの情報を読み取り、kubectlコマンドにてAPI Serverに対してnginxのコンテナを10台起動するようにリクエストを行う。
  4. リクエストを受け取ったAPI Serverは認証を行い、合っていれば要求のあった変更内容「Podを作成する」についてetcdに書き込む。
  5. SchedulerがPodの情報が更新されたことを検知する
  6. SchedulerがどのNodeにPodを配置するかを決定する(=スケジューリング)
  7. SchedulerはAPI Serverを呼び出し、etcd上にPodの配置先のNodeの情報を書き込む。
  8. Node上のkubeletが自身のNodeの情報が更新されたことを検知する
  9. kubeletがコンテナランタイムに対してPodの作成を指示する。

その他よく使うコマンド

クラスター上のサービスを取得する

kubectl get svc

image.png

上記のようにexternal-IPとclusterIPを見ることができる。

Podの詳細情報・エラー情報を表示する

kubectl describe pods [pod-name]

Podを削除する

kubectl delete -f sample-deployment.yaml

Serviceを削除する

kubectl delete -f sample-service.yaml

k8sのMasterサーバ

  • 概要

管理する側のサーバ。etcdというデータベースにNodeも含めたk8s全般の設定情報を格納している。

  • API Server

k8sを操作するためのAPIがここに集約されている。RESTfulなAPI。システム管理者はkubectlを使ってここにアクセスする。
k8s内のコンポーネントは何をするにもここを介して操作を行っている。
kubectlはホームディレクトリの~/.kube/configに書かれている認証情報をもとにクラスターに接続する。その認証情報をもとにAPI Serverが認証・認可を行う。

認証情報は以下のコマンドでCLI上で確認可能。

kubectl config view

image.png

上記の例ではユーザのトークン、クライアントキー、クライアント証明書にて認証を行っている。

  • Scheduler

PodをどのNodeで動かすかを決めるコンポーネント。

  • Controller Manager

k8sクラスター全体を監視し、Podやコンテナ上のアプリケーションがetcd内の定義ファイル上で定義された内容と一致しているかを監視してそれを維持しようとするコンポーネント。
Node Controller, ReplicaSet Controller, Service Controllerなど様々なControllerなどのkube-controller-managerとクラウド独自のコントローラであるcloud-controller-managerがいる。

  • データベース(etcd)

Podなどの状態を定義ファイルの形で保持しておくコンポーネント。
Masterから切り離されることもある。

k8sのリソース

以下では代表的なリソースのみ紹介する。

Node

  • 概要

実際にコンテナ、アプリケーションが動くサーバ群。

  • kubelet

Masterからの指示に従って実際にコンテナを実行する機能を持つコンポーネント。また、Nodeの状態を監視し、定期的にAPI Serverに通知する。

  • kube-proxy

ネットワークプロキシのコンポーネント。

image.png

Pod

コンテナアプリケーションをk8sで管理する上での最小単位。役割が似ている複数のコンテナのセット。
複数のコンテナを1つのPodの中に含めることが可能。
1つのPodの中に入っているコンテナは必ず1つのノードの中に配置される。
Pod内はlocalhostで通信が可能。ストレージも共有する。
同じPod内にどのようなコンテナをいれるのかは機能要件・非機能要件によるが、以下のようなパターンがよくある。

  1. プロキシの役割をするコンテナを同じPodにいれる。
    例えばHTTPのWebコンテナの前にSSLプロキシーコンテナをいれるなど。Pod内はローカルホストでアクセス可能なため、既存アプリケーションに手が入らないで済む。

  2. 認証機能(OAuthなど)をもつコンテナを同じPodにいれる。

ReplicaSet

マニフェストファイルで指定された数のPodを起動してその状態を保ち続けるための仕組み。
LabelSelectorの機能を使用し、該当するラベルのPod数があるべき数と一致しているかを確認している。
以下はReplicaSetのマニフェストファイルの例(再掲)。

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: webserver
spec:
  # Pod数
  replicas: 10
  selector:
    matchLabels:
  # 起動しておくPodのLabel
      app: webfront
# Podのテンプレート
  template:
    metadata:
      labels:
        app: webfront
    spec:
      containers:
      - image: nginx
        name: webfront-container
        ports:
          - containerPort: 80

上記のReplicaSetはappラベルがwebfrontであるPodを10台起動しておくよう定義している。
Podのテンプレートではappラベルをwebfrontにしており、ReplicaSetの下に一緒にPodの定義もかけるようになっている。

仮に元々クラスター内にappラベルがwebfrontであるPodが2台存在している場合は、上記マニフェストファイルをapplyしてから新規に作成されるPodの数は8台である。

あくまでも、最終的に10台になるように制御されるということなのである。

describeコマンドで状態を確認すると、Replicasのところが10台起動すべきところが10台起動していることがわかる。

image.png

ReplicaSet Controllerは、ReplicaSet APIの状態を常に監視している。
以下はReplicaSet APIであるため、ReplicaSet Controllerは内部的に以下のコマンドを実行している可能性が高いと思っている。

image.png

DESIREDとCURRENTのPod数に差分が出たとき、ReplicaSet Controllerは以下の処理を行う。

  1. Podの数が想定より少ない
    Pod APIを呼び出して、ReplicaSetのマニフェストファイルのspecに記載されたスペックのPodを差分の数だけ作成する。

  2. Podの数が想定より多い

Pod APIを呼び出して、差分の数だけPodを削除する。

Deployment

複数のReplicaSetに1つのDeploymentを紐づけることでローリングアップデートすることが可能になる。

image.png

全てのPodでバージョンアップ後にOld ReplicaSetのReplica数を0から3に戻すことで切り戻しが可能。

DaemonSet

k8sではどのノードにどのPodが配置されるかk8sが動的に決定するが、全てのノード上に1つ特定のPodを配置したい場合もある。そのようなときにDaemonSetを使用する。

DaemonSetもReplicaSetと同じように配置したPodを監視しているため、特定のノードでDaemonSetによって配置されるべきPodが配置されていない状態になった場合は、DaemonSetによってそれが検知され状態を保とうとする機能をもつ。

ちなみに、kube-proxyもDaemonSetの仕組みによって配置されている。

StatefulSet

基本的にコンテナアプリケーションは、ステートレスでありスケールダウン時にどのPodを落とすかはアルゴリズムに従って自動的に決められてしまうが、データベースなどのステートフルな状態を維持したいときは、これを使用する。

ネットワーク関連

Service

以下のような種類がある。

Cluster IP:クラスター内のPod同士で通信するためのプライベートIP
External IP:クラスターの外部に公開するIP。
LoadBalancer:L4のロードバランサ。

Ingress

クラスター外部からのHTTP、HTTPSの通信をk8sクラスター内にL7のルーティング、TLS/SSL終端(暗号、復号)、L7のロードバランシングなどをするリソース。

アプリケーションの設定情報の管理

アプリケーションに必要な環境変数をコンテナのイメージの中に入れてしまうと都度コンテナが生き死にを繰り返すk8sにおいては不便。なので各コンテナで共有しておきたい情報については、以下のようなリソースにて一元管理される。

ConfigMap

アプリケーションの設定情報や構成ファイル(apacheの設定ファイルなど)などをPodから参照するためのリソース。

ここに格納されたデータは各コンテナに対してボリュームとしてマウントすることができ、コンテナから見ると普通のファイルとしてみえる。

Secrets

ConfigMapと同じように各コンテナ間で共有しておきたい情報の中でもパスワードなど秘匿性の高い情報を格納するためのリソース。

バッチジョブの管理

ジョブを実現するためのリソース。普通Podの停止は異常終了を表すが以下のリソースにおいてPodの停止はジョブの終了を表す。

Job

1回限りの実行が想定されるジョブを実行するためのリソース。

CronJob

ストレージのバックアップなど定期的に実行されることが想定されるジョブを実行するためのリソース。

その他のリソース

namespace

namespaceによって、一つのk8sクラスターの名前空間を論理的に区分けすることができる。

また、区分けしたnamespaceごとにロールベースの権限管理が可能。

よって、複数のプロジェクトのリソースを一つのクラスター内で管理することが可能。

namespaceを一覧表示する

kubectl get namespace

image.png

デフォルトで作成されるnamespaceはk8sのバージョン1.26.3時点では以下の4つである。
defalut:namespaceを明示的に指定しない場合のデフォルト
kube-public:全ユーザーが利用可能なConfigMapなどのリソースが入っている
kube-system:k8sクラスターが内部で利用するリソースが入っている
kube-node-lease:v1.14以降でデフォルトで作成されるようになった。

Nodeのハートビートを監視するためのleaseオブジェクトというリソースが入る。他のコンポーネントはこのleaseオブジェクトの状態を監視することでNodeの正常性を確認する。

kube-systemのnamespaceであるPodのみを表示する

kubectl get pods —namespace kube-system

image.png

おわりに

良きk8sライフを!

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?