LoginSignup
32
21

More than 3 years have passed since last update.

はじめに

Kubernetesについての初心者向けまとめ兼自分のメモです。なお、この記事は「Docker/Kubernetes 実践コンテナ開発入門」という技術書の内容に則っています。

Kubernetesとは

KubernetesはGoogle社主導で開発された、コンテナの運用を自動化するためのコンテナオーケストレーションシステムです。コンテナオーケストレーションを実現・管理するための統合的なシステムであり、その操作のためのAPIやCLIツールも併せて提供されています。

Kubernetesの概念

Kubernetesで実行されるアプリケーションは様々なリソースと協調して動作することで成立しています。Kubernetesのリソースとは、アプリケーションのデプロイ構成するための部品のようなもので以下のようなものがあります。

リソース名 用途
Node Kubernetesクラスタで実行するコンテナを配置するためのサーバ
Namespace Kubernetesクラスタ内で作る仮想的なクラスタ
Pod コンテナ集合体の単位で、コンテナを実行する方法を定義する
ReplicaSet 同じ仕様のPodを複数生成・管理する
Deployment ReplicaSetの世代を管理する
Service Podの集合にアクセスするための経路を定義する
Ingress ServiceをKubernetesクラスタの外に公開する
ConfigMap 設定情報を定義し、Podに供給する
PersistentVolume Podが利用するストレージのサイズや種別を定義する
PersistentVolumeClaim PersistentVolumeを動的に確保する
StorageClass PersistentVolumeが確保するストレージの種類を定義する
StatefulSet 同じ仕様で一貫性のあるPodを複数生成・管理する
Job 常駐目的ではない複数のPodを作成し、正常終了することを保証する
CronJob cron記法でスケジューリングして実行されるJob
Secret 認証情報等の機密データを定義する
Role Namespace内で操作可能なKubernetesリソースのルールを定義する
RoleBinding RoleとKubernetesリソースを利用するユーザーを紐づける
ClusterRole Cluster全体で操作可能なKubernetesリソースのルールを定義する
ClusterRoleBinding ClusterRoleとKubernetesリソースを利用するユーザーを紐づける
ServiceAccount PodにKubernetesリソースを操作させる際に利用するユーザー

KubernetesクラスタとNode

KubenetesクラスタはKubernetesの様々なリソースを管理する集合体のことを指します。NodeはKubernetesクラスタの管理下に登録されているDockerホストのことでKubernetesでコンテナをデプロイするために利用されます。Kubernetesクラスタは以下のようにMasterとNode郡によって構成されます。

図1.png

Master Nodeにデプロイされるコンポーネントの役割は以下のようになっています。

コンポーネント名 役割
kube apiserver KubernetesのAPIを公開するコンポーネント。kubectlからのリソース操作を受け付ける
etcd 高可用性を備えた分散キーバリューストアでKubernetesクラスタのバッキングストアとして利用される
kube scheduler Nodeを監視し、コンテナを配置する最適なNodeを選択する
kube controller manager リソースを制御するコントローラーを実行する

Namespace

kubernetesはクラスタの中に入れ子となる仮想的なクラスタを作成できます。これがNamespaceという概念です。クラスタを構築するとあらかじめdefault,docker,kube-public,kube-systemというNamespaceが用意されます。Namespaceごとに操作権限を用意できるのでより堅牢で細やかな権利制御を実現できます。

Pod

Podの概要

Podはコンテナの集合体の単位で、少なくとも1つのコンテナを持ちます。Podは以下のようにどこかのNodeに配置されるようになっています。同じPodを複数のNodeに配置する、1つのNodeに複数配置することも可能です。

図2.png

Podの作成

作成するPodは以下のようにyamlファイル(マニフェストファイル)で定義します。ここでは例としてプロキシの役割をもつNginxとアプリケーションであるechoで構成されるPodを定義します。(イメージは既に作成済みとします)

echo-pod.yaml
apiVersion: v1
kind: Pod    # リソースの種類の指定
metadate:
  name: echo    # リソース名
spec:    # kind属性の値次第でspec以下のスキーマが変わる
  containers:    # コンテナ郡の指定
  - name: nginx    # コンテナ名
    image: example/nginx:latest    # イメージ保存先
    env:    # 環境変数の指定
    - name: BACKEND_HOST
      value: localhost:8080
    ports:    # EXPOSEするポートの指定
    - containerPort: 80
  - name: echo
    image: example/echo:latest
    ports:
    - containerPort: 8080

このファイルで定義したPodをKubernetesクラスタに反映させるには以下のコマンドを実行します。

$ kubectl apply -f echo.yaml
pod "echo" created

以降に紹介するリソースも同様のコマンドで反映させることができます。

Podの操作

Podの状態の確認

Podの状態は以下のコマンドを実行することで一覧取得できます。STATUSがRunningになっていればPod内の全てのコンテナが実行状態になったことを示します。READYの分母はPodに定義されたコンテナ数、分子は実行状態になったコンテナ数を表します。

$ kubectl get pod
NAME         READY      STATUS     RESTARTS     AGE
echo         2/2        Running    0            11m

コンテナ内でのコマンド実行

以下のコマンドでコンテナ内でコマンドを実行することができます。

# kubectl exec -it Pod名 コマンド -c コンテナ名
$ kubectl exec -it echo sh -c nginx
#

コンテナの標準出力表示

# kubectl logs -f Pod名 -c コンテナ名
$ kubectl logs -f echo -c echo

Podの削除

# kubectl delete pod Pod名
$ kubectl delete pod echo
# kubectl delete -f マニフェストファイル名
$ kubectl delete -f echo.yaml

PodとPod内コンテナのアドレス

Podにはそれぞれ固有の仮想IPアドレスが割り振られます。Podに割り振られた仮想IPアドレスはそのPod内の全てのコンテナと共有されます。

図3.png

ReplicaSet

ReplicaSetは同じ仕様のPodを複数生成・管理するためのリソースです。例としてReplicaSetを記述したマニフェストファイルecho-replicaset.yamlを示します。

echo-replicaset.yaml
apiVersion: apps/v1
kind: ReplicaSet    # リソースの種類の指定
metadate:
  name: echo    # リソース名
  labels:
    app: echo
spec:    # kind属性の値次第でspec以下のスキーマが変わる
  replicas: 3    # Pod数
  selector:
    matchLabels:
      app: echo
  template:
    metadate:
      labels:
        app: echo
    spec:
      containers:    # コンテナ郡の指定
      - name: nginx    # コンテナ名
        image: example/nginx:latest    # イメージ保存先
        env:    # 環境変数の指定
        - name: BACKEND_HOST
          value: localhost:8080
        ports:    # EXPOSEするポートの指定
        - containerPort: 80
      - name: echo
        image: example/echo:latest
        ports:
        - containerPort: 8080

ReplicaSetを操作してPodの数を減らすと、減らした分のPodは削除されます。削除されたPodを復元することはできません。そのためWebアプリケーションのようなステートレスな性質を持つPodの利用に向いています。

Deployment

ReplicaSetより上位のリソースとしてDeploymentというリソースがあります。Deploymentはアプリケーションデプロイの基本単位となるリソースです。DeploymentはReplicaSetを管理・操作するために提供されているリソースです。例としてDeploymentを記述したマニフェストファイルecho-deployment.yamlを示します。

echo-deployment.yaml
apiVersion: apps/v1
kind: Deployment    # リソースの種類の指定
metadate:
  name: echo    # リソース名
  labels:
    app: echo
spec:    # kind属性の値次第でspec以下のスキーマが変わる
  replicas: 3    # Pod数
  selector:
    matchLabels:
      app: echo
  template:
    metadate:
      labels:
        app: echo
    spec:
      containers:    # コンテナ郡の指定
      - name: nginx    # コンテナ名
        image: example/nginx:latest    # イメージ保存先
        env:    # 環境変数の指定
        - name: BACKEND_HOST
          value: localhost:8080
        ports:    # EXPOSEするポートの指定
        - containerPort: 80
      - name: echo
        image: example/echo:latest
        ports:
        - containerPort: 8080

Deploymentの定義はReplicaSetと大差ありません。違いはDeploymentがReplicaSetの世代管理を可能にする点です。Deploymentのリビジョンは以下のコマンドで確認できます。

$ kubectl rollout history deployment echo
deployments "echo"
REVISION   CHANGE-CASE
1          kubectl apply --filename=echo-deployment.yaml --record=true

Service

Serviceはkubernetesクラスタ内において、Podの集合(主にReplicaSet)に対する経路やサービスディスカバリを提供するためのリソースです。例として2つのReplicaSetを記述したマニフェストファイルecho-ReplicaSet-with-label.yamlを示します。

echo-ReplicaSet-with-label.yaml
apiVersion: apps/v1
kind: ReplicaSet    # リソースの種類の指定
metadate:
  name: echo    # リソース名
  labels:
    app: echo
    release: spring    # ラベル
spec:    # kind属性の値次第でspec以下のスキーマが変わる
  replicas: 1    # Pod数
  selector:
    matchLabels:
      app: echo
      release: spring
  template:
    metadate:
      labels:
        app: echo
        release: spring
    spec:
      containers:    # コンテナ郡の指定
      - name: nginx    # コンテナ名
        image: example/nginx:latest    # イメージ保存先
        env:    # 環境変数の指定
        - name: BACKEND_HOST
          value: localhost:8080
        ports:    # EXPOSEするポートの指定
        - containerPort: 80
      - name: echo
        image: example/echo:latest
        ports:
        - containerPort: 8080

---
apiVersion: apps/v1
kind: ReplicaSet    # リソースの種類の指定
metadate:
  name: echo    # リソース名
  labels:
    app: echo
    release: summer    # ラベル
spec:    # kind属性の値次第でspec以下のスキーマが変わる
  replicas: 2    # Pod数
  selector:
    matchLabels:
      app: echo
      release: summer
  template:
    metadate:
      labels:
        app: echo
        release: summer
    spec:
      containers:    # コンテナ郡の指定
      - name: nginx    # コンテナ名
        image: example/nginx:latest    # イメージ保存先
        env:    # 環境変数の指定
        - name: BACKEND_HOST
          value: localhost:8080
        ports:    # EXPOSEするポートの指定
        - containerPort: 80
      - name: echo
        image: example/echo:latest
        ports:
        - containerPort: 8080

release=summerを持つPodだけにアクセスできるようなServiceを定義したマニフェストファイルを以下のように作成します。

echo-service-summer.yaml
apiVersion: v1
kind: Service
metadate:
  name: echo
spec:
  selector:
    app: echo
    release: summer
  ports:
    - name: http
      port: 80

このServiceとラベル付で区別されたPodとの関係を表しているのが次の図です。

図4.png

Ingress

kubenetesクラスタの外にServiceを公開するためにはServiceをNodePortで公開することで可能ですが、この手法はあくまでL4層レベルまでしか扱えないため、HTTP/HTTPSのようにパスベースで転送先のServiceを切り替えるといったL7層レベルの制御までは行えません。これを解決するためのリソースがIngressです。ServiceのKubernetesクラスタの外への公開と、パスベースでの高度なHTTPルーティングを両立します。例として以下のServiceを考えます。

echo-service.yaml
apiService: v1
kind: Service
metadata:
  name: echo
spec:
  selector:
    app: echo
  ports:
    - name: http
      port: 80

このServiceをKubernetesクラスタの外へ公開するためのIngressは以下のように定義できます。

echo-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: echo
spec:
  rules:
  - host: example.local
    http:
      paths:
      - path: /
        backend:
          serviceName: echo
          servicePort: 80

PersistentVolumeとPersistentVolumeClaim

kubernetesではストレージを確保するためにPersistentVolumeとPersistentVolumeClaimというリソースが提供されています。これらはクラスタが提供されているプラットフォームnに対応した永続ボリュームを作成するためのリソースです。PersistentVolumeはストレージの実体(GCPではGCEPersistentDisk)で、PersistentVolumeClaimはPersistentVolumeに対して必要な容量を動的に確保できます。PersistentVolumeClaimのマニフェストファイルのイメージは次のようなものです。

pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-example
spec:
  accessModes:    # ストレージへのマウントポリシー
    - ReadWriteOnce
  storageClassName: ssd    # StorageClassリソースの名前
  resources:
    requests:
      storage: 4Gi

StorageClass

StorageClassはPersistentVolumeが確保するストレージの種類を定義できるリソースです。StorageClassのマニフェストファイルのイメージは次のようなものです。

storage-class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ssd
  annotation:
    storageclass.kubernetes.io/is-default-class: "false"
  labels:
    kubernetes.io/cluster-service: "true"
provisioner: kubernetes.io/gce-pd    # GCPの永続ストレージであるGCEPersistentDiskに対応したVolumePlugin
parameters:
  type: pd-ssd

StatefulSet

Deploymentは定義されたPod仕様に基づきPodを作成するリソースで、一意性を持つPodや永続かデータを持つ必要がないステートレスなアプリケーションをデプロイするのに向いています。対して、StatefulSetはデータストアのように継続的にデータを永続化するステートフルなアプリケーションの管理に向いたリソースです。DeploymentではPodにランダムな識別子が付与されますが、StatefulSetではpod-0,pod-1,pod-2のような連番で一意な識別子でPodを作成します。マニュフェストファイルの定義はReplicaSetとほとんど同じです。

Job

Jobは1つ以上のPodを作成し、指定された数のPodが正常に完了するまでを管理するためのリソースです。Jobによる全てのPodが正常に終了しても、Podは削除されずに保持されるため、終了後にPodのログや実行結果を分析できます。そのため、Webアプリケーション等の常駐型アプリケーションではなく大規模な計算やバッチ指向のアプリケーションに向いています。Jobのマニフェストファイルのイメージは次のようなものです。

job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: pingpong
  labels:
    app: pingpong
spec:
  parallelism: 3    # 同時に実行するPod数
  template:
    metadata:
      labels:
        app: pingpong
    spec:
      containers:
      - name: pingpong
        image: example/alpine:bash
        command: ["/bin/sh"]
        args:
          - "-c"
          - |
            echo ['date'] ping!
            sleep 10
            echo ['date'] pong!
      restartPolicy: Never    # Pod終了時の再実行の設定

Podの状態を確認すると終了したPodはSTATUS=Completedとして表示されます。

CronJob

Jobは一度きりのPodの実行ですが、CronJobリソースを利用するとスケジューリングして定期的にPodを実行できます。CronJobのマニフェストファイルのイメージは次のようなものです。

cron-job.yaml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: pingpong
spec:
  schedule: "*/1 * * * *"    # Jobのスケジュール(cron記法)
  jobTemplate:
    spec:
      template:
        metadata:
          labels:
            app: pingpong
        spec:
          containers:
          - name: pingpong
            image: example/alpine:bash
            command: ["/bin/sh"]
            args:
              - "-c"
              - |
                echo ['date'] ping!
                sleep 10
                echo ['date'] pong!
          restartPolicy: OnFailure    # Pod終了時の再実行の設定

Secret

KubernetesではSecretリソースを定義すると、機密情報の文字列をBase64エンコードした状態で扱えます。Secretのマニフェストファイルのイメージは次のようなものです。

secret.yaml
apiVersion: v1
kind: Secret
matadata:
  name: example-secret
type: Opaque
data:
  .htpasswd: Base64エンコードした機密情報の文字列

Secretリソースを確認すると、Base64を複合した状態のファイルとしてダッシュボードからその内容を確認できます。

(Cluster)Roleと(Cluster)RoleBinding

KubernetesにおけるRBACの仕組み

RBACでの権限制御は、Kubernetes APIのどの操作が可能であるかを定義したロールと、認証ユーザー・グループ・ServiceAccountとロールの紐付けの2つの要素で成立します。2つの要素の関係は以下のような図で表すことができます。

図5.png

RBACでの権限制御を実現するために、次のようなKubernetesリソースが提供されています。

リソース名 内容
Role Kubernetes APIへの操作許可のルールを定義し、指定のNamespace内でのみ有効
RoleBinding 認証ユーザー・グループ・ServiceAccountとRoleの紐付けを定義する
ClusterRole Kubernetes APIへの操作許可のルールを定義し、クラスタ全体で有効
ClusterRoleBinding 認証ユーザー・グループ・ServiceAccountとClusterRoleの紐付けを定義する

マニフェストファイル

ClusterRoleとClusterRoleBindingのマニフェストファイルは以下のように記述する。

cruster-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
cruster-role-binding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: pod-reader-binding
subjects:    # Roleを紐付ける対象の認証ユーザー
- kind: ServiceAccount
  name: user
  namespace: default
roleRef:    # Role
  kind: ClusterRole
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io
32
21
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
32
21