メインコンテンツまでスキップ

【チュートリアル】ゼロから k3s クラスタを構築する

k3s 高可用クラスタカバー画像

ヒント:本チュートリアルは Linux + fish shell に基づいて作成されており、一部のコマンド構文は Bash と若干異なります。自分のシステム環境に合わせてコマンドを調整してください。

はじめに

ご存知の通り、k3sRancher Labs によって開発された軽量な Kubernetes ディストリビューションであり、現在最も人気のある K8s 軽量化ソリューションです。

従来の運用方法(1Panel/宝塔/SSH など)と比較して、k3s の学習曲線はより急峻であり、より多くのコンテナオーケストレーション概念を理解する必要があります。しかし一度習得すれば、以下を得ることができます:

k3s のコア利点

  • 軽量で効率的 - 単一のバイナリファイル、メモリ使用量 < 512MB、低スペック VPS に最適
  • 本番環境対応 - Kubernetes API と完全互換、標準 K8s への円滑な移行が可能
  • 宣言型運用 - YAML で期待状態を記述、システムが自動的に維持
  • 高可用性保証 - 自動フェイルオーバー + マルチノード負荷分散
  • すぐに使える - ネットワーク、ストレージ、Ingress などのコアコンポーネントが組み込み

k3s を通じて、複数の低価格 VPS を企業級の高可用クラスタに統合し、従来の運用では達成困難な自動化レベルを実現できます。

対象読者と準備

適切な対象者

  • Linux の基礎知識がある開発者
  • 従来の運用からコンテナオーケストレーションへの移行を希望する人
  • 個人用の高可用サービスを構築したい技術愛好家

前提知識

  • Linux コマンドラインの操作に精通していること
  • Docker コンテナの基礎を理解していること
  • 基本的なネットワーク知識(SSH、ファイアウォール)を持つこと

学習成果

本チュートリアルを完了すると、以下を習得できます:

  1. k3sup を使用した k3s クラスタの迅速なデプロイ
  2. k3s のコアコンポーネント(API Server、etcd、kubelet など)の役割の理解
  3. デフォルトコンポーネントの置き換えによるパフォーマンス最適化(Cilium CNI、Nginx Ingress など)
  4. 最初のアプリケーションのデプロイと外部アクセスの設定
  5. 基本的なクラスタ運用とトラブルシューティングのスキル

デプロイメント計画

k3s はデフォルトで簡潔なコンポーネントセットをインストールしますが、本番環境レベルの要件を満たすために、どのモジュールを保持または置き換えるかを事前に計画する必要があります。以下の表は推奨される取捨選択戦略を示しています:

コンポーネントタイプk3s デフォルトコンポーネント置き換えコンポーネント置き換え理由k3sup 無効化パラメータ
コンテナランタイムcontainerd-デフォルトのままで問題なし-
データストレージSQLite / etcd-シングルノードは SQLite、クラスタは etcd-
Ingress ControllerTraefikNginx Ingress / その他チームがより精通、機能要件が異なる--disable traefik
LoadBalancerService LB (Klipper-lb)デプロイしないロードバランシングを管理したくない、Cloudflare を購入--disable servicelb
DNSCoreDNS-デフォルトのままで問題なし-
Storage ClassLocal-path-provisionerLonghorn分散ストレージ、高可用性、バックアップ機能--disable local-storage
CNIFlannelCiliumeBPF パフォーマンス、ネットワークポリシー、可観測性--flannel-backend=none --disable-network-policy

k3s デフォルトコンポーネントと置き換えソリューション比較表

環境準備

必須ツール

まず、k3sup、kubectl、Helm などのツールが正しくインストールされていることを確認してください(各 GitHub プロジェクトが提供するインストール説明を参照):

k3sup version
kubectl version
helm version

以下のように表示されます:

ツールインストールバージョン確認スクリーンショット

サーバー要件

最小限の 3 ノード高可用コントロールプレーン(Ubuntu 24.04 を使用した例)として機能する、少なくとも 3 台のクラウドサーバーを準備してください(推奨構成 ≥ 4C4G)。各ノードの IP を事前に記録し、SSH 公開鍵が配布されていることを確認し、ローカル秘密鍵のパスを把握してください。これらは後続のステップで使用されます。

初期コントロールプレーンのデプロイ

k3sup を使用して初期コントロールノードをデプロイします:

k3sup install \
--ip 初期ノード IP \
--user root \
--ssh-key 秘密鍵位置 \
--k3s-channel latest \
--cluster \
--k3s-extra-args "--disable traefik --disable servicelb --disable local-storage --flannel-backend=none --disable-network-policy"

以下のように表示されます: k3sup 初期コントロールノードインストール出力

インストール完了後、k3sup は自動的に kubeconfig を現在のディレクトリにコピーします。この設定を直接使用することもできますが、より堅牢な方法は既存の設定ファイルとマージすることです。

kubeconfig のマージ

  1. 現在の kubeconfig をバックアップします(デフォルトは ~/.kube/config):
cp ~/.kube/config ~/.kube/config.backup

fish shell(参考用):

cp $KUBECONFIG {$KUBECONFIG}.backup
  1. 新旧の kubeconfig を 1 つのフラットファイルにマージします:
KUBECONFIG=~/.kube/config:./kubeconfig kubectl config view --flatten > ~/.kube/config.new

fish shell(参考用):

KUBECONFIG=$KUBECONFIG:./kubeconfig kubectl config view --flatten > kubeconfig-merged.yaml
  1. 新しいファイルの内容が正しいことを確認した後、古い設定を上書きします:
mv ~/.kube/config.new ~/.kube/config

fish shell

mv ./kubeconfig-merged.yaml $KUBECONFIG
  1. 新しいコンテキストが有効になったことを確認します:
kubectl config get-contexts
kubectl config use-context default

Cilium のインストール(Flannel の置き��え)

k3s をインストールする際、デフォルト CNI(Flannel)を無効化したため、ノード間の通信が一時的に不可能です。計画に従い、Cilium をデプロイしてネットワークとネットワークポリシー機能を提供します。

Helm を使用して Cilium をインストールします:

# Cilium Helm リポジトリを追加
helm repo add cilium https://helm.cilium.io/

# Helm リポジトリを更新
helm repo update

# Cilium CNI をインストール(シングルレプリカ、デフォルトモード)
helm install cilium cilium/cilium \
--namespace kube-system \
--set operator.replicas=1 \
--set ipam.mode=kubernetes

クラスタが既に kube-proxy を無効化している場合、追加で --set kubeProxyReplacement=strict を指定できます。本チュートリアルではより多くのシナリオとの互換性を保つため、デフォルト値を使用しています。

実行完了後、以下が表示されます: Helm Cilium インストール終了出力 Cilium Pod とノード状態確認出力

Cilium コンポーネントの起動完了を待ちます:

# Cilium 関連 Pod の状態を確認
kubectl get pods -n kube-system -l k8s-app=cilium

# ノード状態を確認(NotReady から Ready に変わるはず)
kubectl get nodes

kubectl コントロールプレーンノード準備完了スクリーンショット

ノードが Cilium に切り替わった後、NotReady から Ready に変わるはずです。次に k3sup を使用して他の 2 つのコントロールノードを追加します。

コントロールプレーンの拡張

高可用性を実現するには、少なくとも 3 つのコントロールノードが必要です。以下のコマンドを使用して 2 番目のコントロールノードを追加します:

k3sup join \
--ip 2 番目のノード IP \
--user root \
--ssh-key 秘密鍵位置 \
--server-ip 初期ノード IP \
--server \
--k3s-channel latest \
--k3s-extra-args "--disable traefik --disable servicelb --disable local-storage --flannel-backend=none --disable-network-policy"

同じ方法で 3 番目のコントロールノードを追加します:

k3sup join \
--ip 3 番目のノード IP \
--user root \
--ssh-key 秘密鍵位置 \
--server-ip 初期ノード IP \
--server \
--k3s-channel latest \
--k3s-extra-args "--disable traefik --disable servicelb --disable local-storage --flannel-backend=none --disable-network-policy"

数分待った後、クラスタの状態を確認します:

kubectl get nodes

3 つのコントロールノードがすべて Ready 状態になったら、コントロールプレーンの構築は完了です。

複数のコントロールノード追加後のクラスタ状態

Nginx Ingress Controller のインストール

k3s デフォルトの Traefik を置き換え、Nginx Ingress Controller をインストールします:

# Nginx Ingress Helm リポジトリを追加
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

# Nginx Ingress Controller をインストール(長時間待つ必要がある場合があります)
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--create-namespace \
--set controller.hostPort.enabled=true \
--set controller.hostPort.ports.http=80 \
--set controller.hostPort.ports.https=443 \
--set controller.service.type=ClusterIP
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx

Nginx Ingress Controller コンポーネント状態スクリーンショット

Longhorn 分散ストレージのインストール

Longhorn は Rancher によって開発されたクラウドネイティブ分散ブロックストレージシステムで、高可用性、バックアップ、スナップショットなどのエンタープライズグレード機能を提供します。k3s デフォルトの local-path-provisioner と比較して、Longhorn はノード間の永続ストレージをサポートしています。

前提条件の確認

Longhorn をインストールする前に、各ノードに必要な依存関係がインストールされていることを確認する必要があります。Ansible を使用してバッチ処理したい場合は、後続の例を参照してください:

# 各ノードで実行(SSH 経由)
# open-iscsi の確認とインストール
apt update
apt install -y open-iscsi nfs-common

# 起動と自動起動の設定
systemctl enable --now iscsid
systemctl status iscsid

Ansible を使用して依存関係をバッチインストールしたい場合は、以下のタスク片を参照できます:

---
- name: Setup K3s nodes with Longhorn dependencies and CrowdSec
hosts: k3s
become: true
vars:
crowdsec_version: "latest"

tasks:
# ============================================
# Longhorn Prerequisites
# ============================================
- name: Install Longhorn required packages
ansible.builtin.apt:
name:
- open-iscsi # iSCSI support for volume mounting
- nfs-common # NFS support for backup target
- util-linux # Provides nsenter and other utilities
- curl # For downloading and API calls
- jq # JSON processing for Longhorn CLI
state: present
update_cache: true
tags: longhorn

- name: Enable and start iscsid service
ansible.builtin.systemd:
name: iscsid
enabled: true
state: started
tags: longhorn

- name: Load iscsi_tcp kernel module
community.general.modprobe:
name: iscsi_tcp
state: present
tags: longhorn

- name: Ensure iscsi_tcp loads on boot
ansible.builtin.lineinfile:
path: /etc/modules-load.d/iscsi.conf
line: iscsi_tcp
create: true
mode: '0644'
tags: longhorn

- name: Check if multipathd is installed
ansible.builtin.command: which multipathd
register: multipathd_check
failed_when: false
changed_when: false
tags: longhorn

- name: Disable multipathd if installed (conflicts with Longhorn)
ansible.builtin.systemd:
name: multipathd
enabled: false
state: stopped
when: multipathd_check.rc == 0
tags: longhorn

Longhorn のデプロイ

Helm を使用して Longhorn をインストールします:

# Longhorn Helm リポジトリを追加
helm repo add longhorn https://charts.longhorn.io
helm repo update

# Longhorn をインストール(長時間待つ必要がある場合があります)。ディスク容量を節約するため、ここではシングルレプリカのみを設定しています。必要に応じて調整してください
helm install longhorn longhorn/longhorn \
--namespace longhorn-system \
--create-namespace \
--set defaultSettings.defaultDataPath="/var/lib/longhorn" \
--set persistence.defaultClass=true \
--set persistence.defaultClassReplicaCount=1

Longhorn コンポーネントの起動を待ちます:

# Longhorn コンポーネントの状態を確認
kubectl get pods -n longhorn-system

# StorageClass を確認
kubectl get storageclass

Longhorn コンポーネント実行状態スクリーンショット Longhorn ストレージクラスリストスクリーンショット

Longhorn UI へのアクセス(オプション)

Longhorn はストレージボリュームを管理するための Web UI を提供しています。ポート転送を使用して一時的にアクセスできます:

# ローカルにポート転送
kubectl port-forward -n longhorn-system svc/longhorn-frontend 8081:80

# ブラウザで http://localhost:8081 にアクセス

確認完了後、ターミナルで Ctrl+C を押してポート転送を停止し、ローカルポートの継続的な占有を避けてください。

Agent ノードの追加

ここまでで、3 ノードの高可用コントロールプレーン(control-plane)を構築しました。本番環境では、control-plane ノード上で実際のアプリケーションプログラムを実行したくありません(API Server、etcd などのコアコンポーネントのリソースを占有するため)。

したがって、ワークロード(Pods)を実行するための専用 Agent ノード(Worker ノードとも呼ばれます)を追加する必要があります。

インストール前の依存関係

control-plane ノードと同様に、Agent ノードも Longhorn の依存関係を満たす必要があります(これらのノードが永続ボリュームをスケジュールおよび保存できるようにする場合)。

追加予定のすべての Agent ノードで、事前に以下のコマンドを実行してください:

# 各 Agent ノードで実行(SSH 経由)
apt update
apt install -y open-iscsi nfs-common

# 起動と自動起動の設定
systemctl enable --now iscsid

追加コマンドの実行

Agent ノードを追加するコマンドは control-plane ノードを追加するコマンドとほぼ同じですが、2 つの重要な違いがあります:--server フラグを使用せず、追加パラメータが不要です。

k3sup join \
--ip <AGENT_ノード IP> \
--user root \
--ssh-key <秘密鍵位置> \
--server-ip <任意の Control ノード IP> \
--k3s-channel latest

ノード状態の確認

複数の Agent ノードを一度に追加できます。追加完了後、数分待つと Cilium と Longhorn のコンポーネントが新しいノードに自動的にスケジュールされます。

kubectl を使用してクラスタの状態を確認します:

kubectl get nodes -o wide

新しく追加されたノードが表示され、ROLE 列は <none> と表示されるはずです(k3s では、<none> は agent/worker ロールを表します)。 同時に、Cilium と Longhorn の Pod が新しいノード上で正常に起動したかどうかを監視できます:

# Cilium agent は新しいノード上で起動するはず
kubectl get pods -n kube-system -o wide

# Longhorn instance-manager も新しいノード上で起動するはず
kubectl get pods -n longhorn-system -o wide

これで、クラスタは高可用コントロールプレーンとアプリケーション実行用のワーカーノードを備えました。

次のステップ

  • Argo CD、Flux などの GitOps ツールを設定し、クラスタの宣言型管理プロセスを標準化します。
  • Prometheus、Loki、Grafana などの可観測性コンポーネントをデプロイし、監視とログシステムを改善します。
  • Ansible Playbook を使用してノード初期化とコンポーネントアップグレードを自動化し、後続の運用コストを削減します。

参考資料