🐕

Minikubeで動かして学ぶKubernetesとHelm入門

に公開

はじめに

本記事は、KubernetesとHelmに初めて触れる方に向けて、できるだけわかりやすく、最小構成でアプリをデプロイする手順を紹介するものです。
筆者自身、現在の職場でKubernetesやHelmを初めて触れた際、最初の理解に非常に苦労しました。この記事は、そのときの「どこでつまずいたか」「どうすれば理解が進んだか」をベースに、同じように悩む方の助けになればという思いと、自分の備忘録の意味も込めて書いています。

Kubernetes

Kubernetesは、コンテナ化されたワークロードやサービスを、宣言的な設定や自動化を用いながら、管理するための、ポータブルで拡張可能なオープンソースプラットフォームです。公式サイトでは以下のような定義がされています。

Kubernetes is a portable, extensible, open source platform for managing containerized workloads and services, that facilitates both declarative configuration and automation. It has a large, rapidly growing ecosystem. Kubernetes services, support, and tools are widely available.

https://kubernetes.io/docs/concepts/overview/

Kubernetesは、コンテナの起動や停止だけでなく、必要に応じたスケーリング(Podの増減)や障害発生時のフェイルオーバーも自動的に行ってくれるため、安定した運用と効率的なリソース管理を実現できます。

Kubernetesの理解を深めるうえでは、コンテナの基本を押さえておくと理解がスムーズになります。コンテナは、仮想化技術の一つで、コードやその依存関係、ランタイムなどをパッケージにすることができます。これにより、アプリケーションをどの環境でも同じように動作させることが可能になります。Kubernetesは、こうしたコンテナを効率的かつ安定的に運用するためのプラットフォームです。

以下に公式サイトのリンクを貼っておきますが、ネット上に先人の方が書いた解説記事なども多数あるので、そちらを調べてみても良いかもしれません。今回の記事では、KubernetesとHelmのデプロイ周りに焦点を当てたいので、説明は省きます。

https://www.docker.com/ja-jp/resources/what-container/

Kubernetes Objects

Kubernetesでは、アプリケーションの状態を「オブジェクト」として宣言し、それに基づいてシステム全体が自動的に管理・調整されます。
オブジェクトはすべてYAML(またはJSON)形式のマニフェストファイルで定義され、kubectl や API 経由でKubernetesに適用されます。

Kubernetes objects are persistent entities in the Kubernetes system. Kubernetes uses these entities to represent the state of your cluster.

https://kubernetes.io/docs/concepts/overview/working-with-objects/

以下が主要なオブジェクトの一覧です。

オブジェクト 説明
Pod コンテナを実行する最小単位(通常は1コンテナ)
Deployment 複数のPodを一貫して管理・スケーリング・更新
ReplicaSet Deploymentが内部で使う、Podのレプリカ維持機構
Service Podに対するネットワークアクセスを提供
Ingress 外部のHTTPリクエストを、内部のServiceへルーティング
ConfigMap / Secret アプリの設定値や機密情報をPodに渡す仕組み

これらのオブジェクトをどのように記述し、適用していくかは、次の章で紹介する「マニフェストファイル」の構造とあわせて具体的に見ていきます。

マニフェストファイル

Kubernetesでは、クラスタ上で動かすオブジェクトの情報を、マニフェストという設定ファイルに記述して管理します。このファイルは主に YAML形式 で書かれ、Kubernetesに「こういう状態にしてほしい」と伝えるための宣言的な定義です。

When you use the Kubernetes API to create the object (either directly or via kubectl), that API request must include that information as YAML or JSON in the request body. Most often, you provide the information to kubectl in a file known as a manifest.

https://kubernetes.io/docs/concepts/overview/working-with-objects/

マニフェストの特徴として、以下が挙げられます。

  1. 宣言的(declarative)
    「何をどうしてほしいか」を定義するだけで、Kubernetesが状態を維持・調整してくれる
  2. バージョン管理が容易
    YAMLファイルなのでGitなどで変更履歴を管理しやすい
  3. 再現性が高い
    同じマニフェストを適用すれば、他の環境でも同じ状態を再現できる

マニフェストの基本構造は以下のようになっており、必須のプロパティとして、以下を持ちます。

フィールド 説明
apiVersion そのリソースが使う Kubernetes API のバージョン
kind 作成したいオブジェクトの種類(例: Deployment, Service など)
metadata オブジェクト名、ラベル、Namespace などの識別情報
spec 望ましい状態(例: Pod 数、イメージ名、ポートなど)を具体的に記述するセクション
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 2
  # ここにPodのテンプレート(containers、imageなど)を定義します

作成したマニフェストファイルは、kubectl apply コマンドでKubernetesに適用します:

kubectl apply -f deployment.yaml

これにより、Kubernetesは指定されたオブジェクトを作成し、望ましい状態に保つよう自動で制御を始めます。

これらのオブジェクトをどのように記述し、適用していくかは、Developmentと Service、Ingressの書き方を例として、この先の章で紹介していきます。

Deployment

Kubernetesにおける Deployment は、アプリケーションを構成するPodを安定的に管理するためのコントローラーです。

公式ドキュメントでは次のように定義されています:

A Deployment manages a set of Pods to run an application workload, usually one that doesn't maintain state.

https://kubernetes.io/docs/concepts/workloads/controllers/deployment/

Deploymentは内部的に ReplicaSet を利用して、指定した数のPodを常に維持し、必要に応じて再起動やローリングアップデート(段階的な更新)を行います。そのため、単なるPodの起動だけでなく、バージョン更新・スケーリング・フェイルオーバーといった実運用に欠かせない機能を支えてくれる重要な存在です。

deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app.kubernetes.io/name: proxy
  template:
    metadata:
      labels:
        app.kubernetes.io/name: proxy
    spec:
      containers:
      - name: nginx
        image: nginx:stable
        ports:
        - containerPort: 80
          name: http-web-svc

フィールド 説明
replicas 起動するPodの数(例:2つ)
selector このDeploymentが管理するPodを識別するための条件
template 実際に作成されるPodの仕様を定義
containers Pod内で起動するコンテナ(ここではnginx)

このマニフェストを deployment.yaml として保存し、以下のコマンドで適用することができます。

kubectl apply -f deployment.yaml

このように、Deploymentを使うことで、アプリケーションの起動・維持・更新をKubernetesに任せることができます。

次章では、Podに外部からアクセスするために必要なServiceの定義について紹介します。

Service

Kubernetesにおける Service は、複数のPodに対して安定したネットワークアクセスを提供するための抽象化オブジェクトです。
アプリケーションをPodとして動かす場合、Deploymentの仕組みによってPodは動的に作成・削除され、IPアドレスも変わります。
そのため、クライアントが直接PodのIPを指定して通信するのは現実的ではありません。Serviceは、複数のPodを1つのサービスとしてまとめ、仮想IPやDNS名を通じてアクセスできるようにする“ネットワーク上の入り口”です。

公式ドキュメントでは以下のように説明されています:

Expose an application running in your cluster behind a single outward-facing endpoint, even when the workload is split across multiple backends.

https://kubernetes.io/docs/concepts/services-networking/service/

service.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app.kubernetes.io/name: proxy
  ports:
  - name: name-of-service-port
    protocol: TCP
    port: 80
    targetPort: http-web-svc
フィールド 説明
selector ラベルにより対象Podを指定。DeploymentのPodと一致させる必要がある
port クライアントがアクセスするServiceのポート
targetPort http-web-svc は、Pod定義内のコンテナポートに name: http-web-svc が指定されている場合に使用されます。数値(例: 80)で書くことも可能です。

このマニフェストを service.yaml として保存し、以下のコマンドで適用することができます。

kubectl apply -f service.yaml

次章では、URLルーティングや複数Serviceの統合入り口として使える Ingress について解説します。

Ingress

Kubernetesにおける Ingress は、クラスタ外部から内部のServiceへHTTP/HTTPSアクセスをルーティングするためのエントリポイントです。

公式ドキュメントでは次のように説明されています。

Make your HTTP (or HTTPS) network service available using a protocol-aware configuration mechanism, that understands web concepts like URIs, hostnames, paths, and more. The Ingress concept lets you map traffic to different backends based on rules you define via the Kubernetes API.

https://kubernetes.io/docs/concepts/services-networking/ingress/

ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
spec:
  ingressClassName: nginx
  rules:
    - host: example.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx-service
                port:
                  number: 80
フィールド 説明
ingressClassName 利用する Ingress Controller の指定(例: nginx
rules リクエストのホストやパスに基づいてルーティングするための定義
backend.service 該当リクエストを転送するServiceとそのポート番号
pathType Prefix(前方一致)や Exact(完全一致)などのマッチ方式

このマニフェストを ingress.yaml として保存し、以下のコマンドで適用することができます。

kubectl apply -f ingress.yaml

※Gateway APIについて
Kubernetesでは、Ingressに代わるよオブジェクトとして、 Gateway API が登場しています。

Gateway API is a family of API kinds that provide dynamic infrastructure provisioning and advanced traffic routing.

詳細は以下をご参照ください。
https://kubernetes.io/docs/concepts/services-networking/gateway/

Helm

Kubernetesでは、アプリケーションを構成するマニフェスト(Deployment、Service、Ingressなど)を複数ファイルで管理する必要があります。これが増えてくると、設定の重複や環境差分の管理が煩雑になってきます。

Helm は、こうしたKubernetesのマニフェストをテンプレート化して管理・再利用・バージョン管理しやすくするパッケージマネージャーです。

公式では以下のように紹介されています。

Helm helps you manage Kubernetes applications — Helm Charts help you define, install, and upgrade even the most complex Kubernetes application.

Helm Chart

Helm Chartは、Kubernetesアプリケーションを定義するためのテンプレートの集合体です。

A Chart is a Helm package. It contains all of the resource definitions necessary to run an application, tool, or service inside of a Kubernetes cluster. Think of it like the Kubernetes equivalent of a Homebrew formula, an Apt dpkg, or a Yum RPM file.

チャートの構成の例

mychart/
  Chart.yaml            # チャートのメタ情報(名前、バージョンなど)
  values.yaml           # 変数のデフォルト値(テンプレートに注入される)
  templates/                # Kubernetesマニフェストのテンプレートが格納される
    deployment.yaml         # Podの起動定義(アプリケーション本体)
    service.yaml            # PodにアクセスするためのService定義
    ingress.yaml            # 外部からのアクセスをルーティングするIngress定義

テンプレート内では {{ .Values.image.repository }} のように テンプレート構文を用いて値を埋め込みます。これにより、開発・ステージング・本番などの環境ごとに設定だけを変えて同じチャートを使い回すことができます。

minikube上で、オブジェクトを作成する

ローカルで Kubernetes を試すには、minikube を使うのが最も手軽です。ここでは Helm を使って Nginx アプリケーションを minikube 上にデプロイし、Ingress 経由でアクセスできるように構築します。

minikubeに関しては、公式ドキュメントに以下のように説明が載っています。

minikube quickly sets up a local Kubernetes cluster on macOS, Linux, and Windows. We proudly focus on helping application developers and new Kubernetes users.

https://minikube.sigs.k8s.io/docs/

minikube の起動

minikube start

完了したら、以下でクラスタが起動していることを確認できます。

kubectl get nodes

Helm チャートの作成

helm create mychart
cd mychart

生成されたチャート構成は以下のようになっています。

mychart/
  Chart.yaml
  values.yaml
  templates/
    deployment.yaml
    service.yaml
    ingress.yaml
    ...

values.yaml を編集

values.yaml を以下のようにシンプル化します。

value.yaml
replicaCount: 2

image:
  repository: nginx
  tag: stable
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: true
  className: nginx
  hosts:
    - host: example.local
      paths:
        - path: /
          pathType: Prefix

設定ファイルの編集

各ファイルの以下のように編集します。

development.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "mychart.fullname" . }}-deployment
spec:
  replicas: {{ .Values.replicaCount | default 1 }}
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ include "mychart.name" . }}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: {{ include "mychart.name" . }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - containerPort: {{ .Values.service.port }}
              name: http-web-svc

service.yaml
apiVersion: v1
kind: Service
metadata:
  name: {{ include "mychart.fullname" . }}-service
spec:
  type: {{ .Values.service.type }}
  selector:
    app.kubernetes.io/name: {{ include "mychart.name" . }}
  ports:
    - name: http
      protocol: TCP
      port: {{ .Values.service.port }}
      targetPort: http-web-svc
ingress.yaml
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ include "mychart.fullname" . }}-ingress
spec:
  ingressClassName: {{ .Values.ingress.className }}
  rules:
    {{- range .Values.ingress.hosts }}
    - host: {{ .host }}
      http:
        paths:
          {{- range .paths }}
          - path: {{ .path }}
            pathType: {{ .pathType }}
            backend:
              service:
                name: {{ include "mychart.fullname" $ }}-service
                port:
                  number: {{ $.Values.service.port }}
          {{- end }}
    {{- end }}
{{- end }}

Ingress Controller を有効化

minikube addons enable ingress

以下で反映が完了したか確認することができます。

kubectl get pods -n ingress-nginx

アプリケーションのインストール

helm install myapp .

インストールされたリソースを確認:

kubectl get all
kubectl get ingress

hosts ファイルの設定

以下のように minikube ip を使って example.local をローカルで解決できるようにします

minikube ip

/etc/hosts に以下を追記(macOS / Linux):

192.168.49.2 example.local

動作確認

以下のコマンドを実施して、

minikube tunnel

ブラウザで http://example.local にアクセス。Nginx の初期画面が表示されれば成功です。

まとめ

本記事では、Kubenertesの主要なオブジェクトと、Helmの使い方の概要と、実践の説明をしました。本記事が、読者が Kubenertesに触れる際の、理解の一助になると幸いです。

GitHubで編集を提案

Discussion