オンプレミスで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になっているもの)
後はデフォルト値のままで問題ありませんでした。
完了後、設定したIPに同じネットワークから接続し、インストール時の情報でログインすると以下のような画面が出迎えてくれます
Rancher Serverの作成
この赤枠の部分を作成します
VMの作成
インストールするためのisoをharvester上に用意します。
ダウンロードリンクを渡すだけで勝手にダウンロードしてくれます。
サイドメニューのImagesからImage用の画面に行き、Createから作成
Virtual Machines からVMを作成します。
Volumes から isoの選択と、それとは別でインストールするためのvolumeを作成します。
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で繋がるようになっています。
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
ブラウザからアクセスしてみて繋がれば終了