1
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?

kindによるk8sへの理解を深める

1
Posted at

1. 概要

私が担当するプロジェクトって気づいたら長いことここ数年、EKS(AWS), GKE(GCP)などを利用しているため、k8s環境にかなり携わっていたんですよねぇ。
色々インフラも触ることは多いのですが、なんとなく理解している知識だけで業務を遂行していたので、この際ちゃんと理解したいなと思い、ローカルでk8sシミュレーションとしてkindを利用してみました。

本プロジェクトの目的は、「Podがクラッシュしても自動でアクセスが復旧し、かつ実行ログがホストPCに永続化される」、モダンで堅牢なローカル開発環境をKind(Kubernetes in Docker)上に構築することです。
Goアプリケーションを核とし、Ingress Controller、二段ボリュームマウント、およびKubernetesの自己修復機能を組み合わせて実現しました。

結論:
Kind(Kubernetes in Docker)を用いたローカル環境構築は、Kubernetes(K8s)のコア概念である「自己修復機能(Self-healing)」と「インフラの抽象化(ネットワーク・ストレージ)」を深く理解するための最適なアプローチです。

理由:
クラウド環境に依存せず、意図的な障害(Podのクラッシュ)に対するK8sの自律的な振る舞いや、コンテナ・ノード・ホスト間の複雑なデータの受け渡しを、ローカルで安全かつ手軽に実験できるためです。本件では、自動復旧とログ永続化を備えたGoアプリの開発環境構築を通じて、K8sのアーキテクチャを実践的に学習しました。

2. 解決したい課題

ローカル開発において、以下のような不便さを解消することを目指しました。

  • Podを再起動するたびにコンテナ内のログが消えてしまう。
  • アプリがクラッシュすると接続が切れ、手動で復旧作業が必要になる。

3. 実装の詳細

① アプリケーション層 (main.go)

kind install setup

go install sigs.k8s.io/kind@v0.31.0

まず、ログを標準出力とファイルの両方に出力し、かつ「意図的に壊せる」機能を備えたGoアプリを用意しました。

package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
)

func main() {
	logPath := "/var/log/app/app.log"
	// ログファイルを開く(追記モード)
	f, _ := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if f != nil {
		defer f.Close()
	}

	// 標準出力とファイルの両方に書き出す
	multiWriter := io.MultiWriter(os.Stdout, f)
	log.SetOutput(multiWriter)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		log.Println("Access: /")
		fmt.Fprintf(w, "Log recorded on host PC!\n")
	})

	// 自爆エンドポイント:K8sの自動復旧を試すためのもの
	http.HandleFunc("/kill", func(w http.ResponseWriter, r *http.Request) {
		log.Println("CRITICAL: Self-destructing...")
		os.Exit(1)
	})

	log.Println("Server starting on :8080...")
	http.ListenAndServe(":8080", nil)
}

② インフラ層:Kindの設定 (kind-config.yaml)

Kindは「Dockerの中でNodeを動かす」構造のため、ホストPCのディレクトリをまずNodeにマウントする必要があります。

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraMounts:
  # [1段目] ホストPCの ./logs を Nodeの /var/local/kind-logs に繋ぐ
  - hostPath: ./logs
    containerPath: /var/local/kind-logs
  extraPortMappings:
  # Ingress用のポートマッピング(localhost:80 でアクセス可能にする)
  - containerPort: 80
    hostPort: 80
    protocol: TCP

③ デプロイ層:K8sマニフェスト (deployment.yaml)

Nodeにマウントされたディレクトリを、さらにPod(コンテナ)へマウントします。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: go-app-deployment
spec:
  replicas: 1
  template:
    spec:
      containers:
      - name: go-app
        image: my-go-app:v3
        volumeMounts:
        - name: log-volume
          mountPath: /var/log/app # アプリが書き出すパス
      volumes:
      - name: log-volume
        hostPath:
          path: /var/local/kind-logs # [2段目] Node上のパスを指定
          type: DirectoryOrCreate

4. この構成の「魔法」

この環境のポイントは、**「二段マウント」「Ingress」**の組み合わせです。

  1. ログの永続化ルート:
    Pod (/var/log/app)Node (/var/local/kind-logs)Host PC (./logs)
    このルートにより、Podが削除されても、Nodeが再起動されても、ログはホストPC의 ファイルとして残り続けます。

  2. 自動復旧の体験:
    curl http://localhost/kill を実行するとアプリは死にますが、Kubernetesが数秒で新しいPodを立ち上げます。Ingress Controllerがトラフィックを自動で新しいPodへ流すため、開発者はブラウザをリロードするだけで作業を再開できます。

自動復旧フロー

  1. アプリが /kill で停止。
  2. Kubernetesの liveness 管理によりPodが即座に再起動。
  3. Ingress経由のため、IPやポートの変化を意識せずブラウザ更新だけで接続が再開。

5. 基礎的なkubectlコマンド

構築した環境の動作確認やトラブルシューティングで頻繁に使用するコマンドです。

① Podの状態を確認する

Podが正しく起動しているか、再起動が発生していないかを確認します。

# Podの一覧を表示(RESTARTS列で再起動回数がわかる)
kubectl get pods

# より詳細な情報を出力(IPアドレスやノード名など)
kubectl get pods -o wide

② ログを確認する

アプリの挙動やエラーを追跡します。

# 最新のログを表示
kubectl logs <pod-name>

# ログをリアルタイムで流し読みする(動作確認に最適)
kubectl logs -f <pod-name>

③ Podの詳細・イベントを確認する

Podが起動しない原因(イメージ取得失敗など)や、再起動がいつ起きたかの履歴を調査します。

# Podの設定とイベント履歴を表示
kubectl describe pod <pod-name>

④ コンテナ内部に入る

ファイルが正しくマウントされているかなど、内部の状態を直接確認します。

# シェルを起動してコンテナ内に潜入
kubectl exec -it <pod-name> -- /bin/sh

⑤ 意図的にPodを削除して自律復旧を試す

K8sが自動で新しいPodを立ち上げる様子を観察できます。

# Podを削除(すぐに新しいPodが作成される)
kubectl delete pod <pod-name>

6. docker compose (restart) と kind (Kubernetes) の比較

「落ちても自動で立ち上がる」という点では、docker composerestart: alwaysも似ていますが、その本質的な違いを整理しました。

項目 Docker Compose (restart) Kind (Kubernetes)
管理単位 コンテナ単体 Pod / ReplicaSet (宣言的な状態管理)
復旧のトリガー プロセスの終了 (Exit) Liveness Probe等の高度なヘルスチェック
拡張性 単一ホスト内での再起動 複数ノードへのスケジューリング、負荷分散
抽象化 ホストに依存したポート管理 Ingress / Service によるネットワークの抽象化
用途・メリット 軽量、シンプルで個人開発に最適 本番環境(K8s)を見据えた高度な設計・学習

実務における選択(結論):
アーキテクチャの学習や、高度なオーケストレーションの実験としてはKind(Kubernetes)は最高の環境でした。
しかし、今回の私の**「個人開発の本番環境」としては、最終的に docker compose (restart: always) を採用**しました。
理由は以下の通りです。

  • 軽量さ: 単一ホストでの運用であれば、K8sのコントロールプレーン等のオーバーヘッドがなく、リソース消費が圧倒的に少ない。
  • 運用コスト: 個人開発の規模では、宣言的な状態管理や高度なネットワーク機能よりも、シンプルに「プロセスが死んだら再起動する」だけの機能で十分要件を満たせたためです。

7. まとめ

本プロジェクトでは、あえてローカル環境でKindを構築し、Podの破壊やログの永続化を実験することで、Kubernetesの「あるべき状態を維持する」という強力な自己修復機能(Self-healing)を深く体感することができました。

結果として本番環境には軽量なDocker Composeを採用しましたが、**「アプリが死ぬことを前提としたインフラ設計」**の思想をK8sを通じて学べたことは、設計の大きな糧となりました。
大規模なシステムを見据えた学習環境として、ローカルでのKind運用は非常におすすめです。ぜひ「自爆エンドポイント」を作って、K8sの魔法を体験してみてください!

備考

k9sというpodの管理ツールも結構使いやすかったです!

1
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
1
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?