Harvesterでオンプレ環境を作ろうのカバー画像
Harvesterでオンプレ環境を作ろう
2026/6/21
このエントリーをはてなブックマークに追加

オンプレミスでHCI環境を構築してサービスを公開するまで

お家にk8sクラスタを用意しつつ、普段使いするためのVMを家に用意するために、これまではopennebulaのnode driverを利用してrancherでクラスタを作成・管理していました。

但し、以下の課題がありました。
これはrancherやopennebulaの課題というよりは自身の構築の仕方の課題が大半でした。

  • opennebulaのnode driverを自分で追加でインストールが必要なこと
    • 公式の配布しているurlだと複数アーキテクチャのバイナリが入っておりrancher側が良い感じに使用してくれず、自分でどこかバイナリ単体を置いて置く必要があった
  • ロードバランサが良い感じには置けず、host port でingress-nginxを利用する必要があった。
    • また、それらに対してリクエストを振り分けるnginxを外に置く必要があった
  • rancherをdockerで動かしていたため本番運用には本来は非推奨

そこで今回見つけた Harvester で環境を作り直してみました。
ここまでああだこうだ書いていますが、きっかけはrkeのバージョンを更新しようとしたらクラスタが崩壊したのですべて作り直しました。

次にぶち壊したときの備忘録にするために手順をメモ程度に残します。

構成

今回構築する環境は以下のようになります

構成図

環境

ハードウェア

  • ルーター: Cisco 891fj
  • 物理マシン: HP DL360 Gen9
    • ストレージ: 900GB
    • メモリ: 126GB
    • CPU: Intel(R) Xeon(R) CPU E5-2643 v3 @ 3.40GHz * 2

ソフトウェア

  • Harvester v1.3.1
  • Rancher v2.8.5
  • k3s v1.28.10+k3s1
  • rke2 v1.28.10+rke2r1
  • ingress-nginx v4.11.0 (helm chart version)
  • cert-manager v1.15.0 (helm chart version)

導入

Harvester インストール

Harvester はisoが配布されているので通常のOSインストールと同様にインストールUSBを作成したうえでプロンプトに従いつつインストールします

この時、dhcpでIPを設定するとIPが変わった時にetcdクラスタがIPの変更に追従できずに壊れてしまい、かなり厄介なので固定します。
(画像はデフォルトの設定でDHCPになっているもの)

dhcpがデフォルトになっている画像
ref

後はデフォルト値のままで問題ありませんでした。

完了後、設定したIPに同じネットワークから接続し、インストール時の情報でログインすると以下のような画面が出迎えてくれます
harvesterのトップ画面

Rancher Serverの作成

この赤枠の部分を作成します
構成図

VMの作成

インストールするためのisoをharvester上に用意します。
ダウンロードリンクを渡すだけで勝手にダウンロードしてくれます。

サイドメニューのImagesからImage用の画面に行き、Createから作成

Virtual Machines からVMを作成します。
Volumes から isoの選択と、それとは別でインストールするためのvolumeを作成します。
vm作成画面

Rancherインストール

VM上にk3sをインストールし、その上にRancherをインストールします。
また外から接続できるように ingress-nginxとcert-managerもインストールします。

k3s インストール

以下のコマンドでインストールしました。
クラスタに外からも繋げられるように tls-sanでドメインやIPを指定しました。

curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.28.10+k3s1 K3S_TOKEN=mytoken INSTALL_K3S_EXEC="--tls-san example.com --tls-san 192.0.2.1" sh -s - server --cluster-init

rancher インストール

helmでインストールします。
httpsで接続できるようにletsencryptのオプションを有効にします

helm upgrade rancher rancher-stable/rancher --install --create-namespace \
        --namespace cattle-system --create-namespace \
        --set hostname=example.com \
        --set replicas=1 \
        --set bootstrapPassword=password \
        --set letsEncrypt.ingress.class=nginx \
        --set ingress.tls.source=letsEncrypt \
        --set [email protected]
ingress-nginx, cert-managerのインストール
helm upgrade --install ingress-nginx ingress-nginx \
  --repo https://kubernetes.github.io/ingress-nginx \
  --namespace ingress-nginx --create-namespace

helm install \
        cert-manager jetstack/cert-manager \
        --namespace cert-manager \
        --create-namespace \
        --set crds.enabled=true

インストール後、configmapを直接編集して以下の項目を追加しています

apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  use-forwarded-headers: "true"

これを入れておかないとharvesterにクラスタを作成する際にwebsocketの利用に失敗します。

ここまでするとrancherが起動して外からhttpsで繋がるようになっています。
rancherのトップ画面

k8sクラスタの作成

以下の図の赤枠の部分を作成します
構成図

rancherからharvester node driver を使用してharvester上にk8sクラスタを作成します。

基本的には以下のドキュメントの通り進められます

今回詰まったところとしては以下の2点でした

利用イメージ

cloud-initが利用できるイメージを用意する
以下のページから利用するイメージをharvesterに追加しておく必要がありました

longhornのReadWriteManyでのPVC作成

pvcをReadWriteManyで利用するためにcifs-utils,nfs-commonをインストールする必要があった
以下の設定をクラスタ作成時にpoolの Advanced設定にある UserDataに追加しました

#cloud-config
package_update: true
packages:
  - qemu-guest-agent
+  - cifs-utils
+  - nfs-common
runcmd:
  - - systemctl
    - enable
    - '--now'
    - qemu-guest-agent.service

ingress-nginx, cert-manager のインストール

作成したクラスタの方にingress-nginx, cert-manager をインストールします。
helm前提です。

ingress-nginx

以下のvaluesでインストールします

controller:

  # -- Will add custom configuration options to Nginx https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/
  config: {
      "enable-real-ip": "true",
      "use-forwarded-headers": "true",
      "ssl-redirect": "false",
      "client_body_buffer_siz": "32k",
      "proxy-body-size": "0",
      "proxy-connect-timeout": "600",
      "proxy-read-timeout": "600",
      "proxy-send-timeout": "600",
      "allow-snippet-annotations": "true",
      "enable-modsecurity": "true",
      "enable-owasp-modsecurity-crs": "true",
      "modsecurity-snippet": "SecAuditLog /dev/stdout\nSecRequestBodyAccess On\nSecRuleRemoveById 920350\nSecAuditLogFormat JSON",
  }
  service:
    enabled: true

    annotations:
      prometheus.io/port: "10254"
      prometheus.io/scrape: "true"
      cloudprovider.harvesterhci.io/ipam: "dhcp"

基本は好きなようにしたらいいと思います。  
harvester上のクラスタにインストールする上で大切なのはの部分でこの設定を入れておくことで、harvesterが提供しているloadbalancerをingress-nginxから利用することが出来るようになります。
VMはdhcpでIPを貰えるネットワークに接続している必要はあります。

cloudprovider.harvesterhci.io/ipam: "dhcp"

あとはlbに割り当てられたIPに対して上流のルーターからポートフォワードするといい感じに各VMにリクエストを振り分けてくれます。

cert-manager

以下の設定を有効にしてインストールします
installCRDs: true

また、DNSはCloudflareを利用しているのでcloudflareのapiを叩けるようにapi-tokenをsecretとして作成しておきます。
ref: cert-manager - cloudflare

apiVersion: v1
kind: Secret
metadata:
  name: cloudflare-api-token-secret
  namespace: cert-manager
type: Opaque
stringData:
  api-token: <api-token>

cluster issuerを作成します

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt
  namespace: cert-manager
spec:
  acme:
    # The ACME server URL
    server: https://acme-v02.api.letsencrypt.org/directory
    # Email address used for ACME registration
    email: [email protected]
    # Name of a secret used to store the ACME account private key
    privateKeySecretRef:
      name: letsencrypt
    solvers:
    - dns01:
        cloudflare:
          email: [email protected] # cloudflareのメールアドレス
          apiTokenSecretRef:
            name: cloudflare-api-token-secret
            key: api-token
      selector:
        dnsZones:
        - 'example.com'

ここまできたら後は好きにアプリをデプロイするだけです。

動作確認

bootcampをデプロイして動作確認します

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: bootcamp
  name: bootcamp
spec:
  replicas: 2
  selector:
    matchLabels:
      app: bootcamp
  template:
    metadata:
      labels:
        app: bootcamp
    spec:
      containers:
      - image: gcr.io/google-samples/kubernetes-bootcamp:v1
        name: bootcamp
        ports:
        - containerPort: 8080
      dnsPolicy: ClusterFirst
      restartPolicy: Always

---

apiVersion: v1
kind: Service
metadata:
  name: bootcamp
  labels:
    app: bootcamp
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: bootcamp

---

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: bootcamp
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - example.com
    secretName: bootcamp-tls
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: bootcamp
            port:
              number: 80

ブラウザからアクセスしてみて繋がれば終了
動作確認

Harvesterでオンプレ環境を作ろう - ねこの部屋