長らくこのブログもストップしていましたがこの度ごっそり構成を変えて復活したのでまとめます。
これまでの構成
旧バージョン(ESXi + kubespray + Istio)
以下のような構成になっていました
(構成図を書くたびに世の中の人々の作図能力の高さが身に染みる。いたい)
ESXi上にVMをぽちぽち建てた後にkubesprayでk8sを構成してistio-ingressgatewayをNodePortでデプロイしてそこからリクエストを振り分けていました
この構成で運用する上で以下の辛さがあった
- なるべく構成をコード管理をしたかった
- ESXiのterraform-providerがあるにはあるものの公式のものではないこと
- その分ドキュメントも少ない
- 無料版だったので作成可能なVMのサイズに制限があった
- kubesprayが一発で通ることが無くてググりながら修正して通すのが地味に面倒だった
新バージョン(KVM/QEMU + Opennebula + Rancher + nginx-ingress)
この構成にしてよくなったところ
- rancherでk8sクラスタを立ち上げるようにしたことでそもそもterraformが不要になった
- ノードの増減がGUIでポチポチで良くなった
- ノードが落ちてしまった時rancherが勝手に新しいノードを作成して割り当ててくれる
手順
以下の順でインストールしていった (当たり前といえばそう)
- KVM/QEMU
- Opennebula
- Rancher
- nginx-ingress-controller
KVM/QEMU
ここで詰まる事はなかった
ググったらいくらでも手順が出てきた
強いて言えばopennebulaがubuntu 22.04だと上手く動かなかったので一度20.04をインストールし直す必要があったくらい
備忘録も兼ねているので一応参考リンクを貼っておく
https://ubuntu.com/blog/kvm-hyphervisor
Opennebula
本家のドキュメントを見ながらインストールした
minioneを使ってポンって最初やっていたがやってくうちによくわからんくなったので順に手動でインストールした
https://docs.opennebula.io/6.4/installation_and_configuration/frontend_installation/install.html
物理マシンは1台なのでfrontendと本体?も一緒にインストールした
ここもそんなに躓くことはなかった。
rancherを動かす用のVMをfirecrackerで動かそうとしてたもののKVMと共存ができないらしく諦めた
ケチ臭い人間なのでdocker-machineでわざわざ専用のVMを動かすのもその分のオーバーヘッドが嫌だったのでホスト上で直接docker動かしてrancherを動かしている
今のところ問題ない
rancher
このあたりから結構躓いた
基本は以下のドキュメントを見ながらインストールした
https://docs.opennebula.io/6.4/integration_and_development/automation_tools_integration/rancher.html
rancherの起動
まずdockerを動かすときに --plivileged
オプションが必要だった
また、opennebulaを80番で動かしていてポートが被ったので別ポートで動かしている
バージョンは固定しないと発作が出るので今回はv2.6.9にしている
docker run -d --restart=unless-stopped --privileged -p 8080:80 -p 8443:443 rancher/rancher:v2.6.9
node driverのインストール
ドキュメントにあるURL(https://downloads.opennebula.io/packages/opennebula-6.4.0/opennebula-docker-machine-6.4.0.tar.gz)をそのまま使うと上手く読み込めていなかった
どうも複数のバイナリが入っていていい感じに選べなかったらしい
ホストのアーキテクチャに合うバイナリだけ選んでtarで固めた物を適当な所においてhttpで参照できるようにしてそのURLをDownloadURLとして指定すると上手くいった
クラスタの作成
k8sのノードに使用するイメージもubuntu 22.04を使おうとするとdockerのインストールまでは上手くいくのにsshが途中で出来なくなってこけていた
ubuntu 20.04を使うとすんなり上手くいった
node templateの設定でtemplateを使うと上手くいかなかったのでimage id, network idを指定して設定した
最終的には以下のようになった
NodeTemplates > View API > Editで出てくる情報
(環境次第で可変になりそうなところはマスクしてます)
{"b2dSize":"","cpu":"4","devPrefix":"vd","disableVnc":false,"diskResize":"20480","imageId":"0","imageName":"","imageOwner":"oneadmin","memory":"16384","networkId":"<networkId>","networkName":"","networkOwner":"<networkOwner>","password":"<opennebulaのpassword>","sshUser":"<VMのssh可能なユーザー>","startRetries":"600","templateId":"","templateName":"","user":"<opennebulaのユーザー>","vcpu":"4","xmlrpcurl":"http://<host ip>:2633/RPC2"}
クラスタの設定
nginx-ingressはデフォルトでインストールされてしまうが、自分でいろいろ設定してまとめてインストールしたかったのでデフォルトでインストールされないようにした。
“
ここまででk8s側はだいたいOK
サービスのデプロイ
サービスを外部公開する為の物をデプロイ
nginx-ingress
helm-chartを手元に置いておきたかったのでkubernetes/ingress-nginxのリポジトリからクローンしてきてvaluesを少し弄った
https://github.com/kubernetes/ingress-nginx/tree/main/charts/ingress-nginx
変更点を簡単に説明すると
- nginx-ingress-controllerをdaemonsetでデプロイ
- ロードバランサを用意するのもノードポートでアクセスするようにするのもちょっと面倒だし気に食わなかった
- ssl-redirectの無効化
- デフォルトでnginx-ingress-controllerがhttpsへのリダイレクトをするらしい
- wordpressとかアプリ側でもリダイレクトがあったりすると無限ループが発生していてややこしかったので無効化した
- 多分cloudflareとも無限ループしてるケースがあった気がする
- cert-managerも上手く動いていなかったような気もする(ここは記憶が曖昧)
- nodeSelectorでmasterノードにのみデプロイされるように
- 外部のnginxでリクエストをそれぞれのノードに振り分けるのにノードのIPはある程度定まっていてほしかった
- workerは結構増減しそうだったのでmasterのみにデプロイ
- minecraft用に25565ポートを追加で空ける
diff --git a/charts/ingress-nginx/values.yaml b/charts/ingress-nginx/values.yaml
index 35f922f6b..7a5846fe9 100644
--- a/charts/ingress-nginx/values.yaml
+++ b/charts/ingress-nginx/values.yaml
@@ -41,9 +41,15 @@ controller:
containerPort:
http: 80
https: 443
+ minecraft: 25565
# -- Will add custom configuration options to Nginx https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/
- config: {}
+ config: {
+ "ssl-redirect": "false",
+ "proxy-body-size": "0",
+ "proxy-connect-timeout": "600s",
+ "proxy-read-timeout": "600s",
+ }
# -- Annotations to be added to the controller config configuration configmap.
configAnnotations: {}
@@ -92,12 +98,13 @@ controller:
## Disabled by default
hostPort:
# -- Enable 'hostPort' or not
- enabled: false
+ enabled: true
ports:
# -- 'hostPort' http port
http: 80
# -- 'hostPort' https port
https: 443
+ minecraft: 25565
# -- Election ID to use for status update, by default it uses the controller name combined with a suffix of 'leader'
electionID: ""
@@ -191,7 +198,7 @@ controller:
# name: secret-resource
# -- Use a `DaemonSet` or `Deployment`
- kind: Deployment
+ kind: DaemonSet
# -- Annotations to be added to the controller Deployment or DaemonSet
##
@@ -290,7 +297,7 @@ controller:
## Ref: https://kubernetes.io/docs/user-guide/node-selection/
##
nodeSelector:
- kubernetes.io/os: linux
+ node-role.kubernetes.io/controlplane: "true"
## Liveness and readiness probe values
## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes
@@ -498,12 +505,14 @@ controller:
ports:
http: 80
https: 443
+ minecraft: 25565
targetPorts:
http: http
https: https
+ minecraft: minecraft
- type: LoadBalancer
+ type: ClusterIP
## type: NodePort
## nodePorts:
@@ -935,7 +944,8 @@ imagePullSecrets: []
# -- TCP service key-value pairs
## Ref: https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/exposing-tcp-udp-services.md
##
-tcp: {}
+tcp:
+ 25565: "external-service/forgemc:25565"
# 8080: "default/example-tcp-svc:9000"
# -- UDP service key-value pairs
valuesの変更が出来たら以下のコマンドでデプロイする
helm upgrade --install ingress-nginx path/to/chart --namespace ingress-nginx --create-namespace
ここまででk8sのmasterノードになってるIPの80,443ポートでリクエストを受けられるようになっている
この状態ではリクエストの振り分け先が無いのでデフォルトバックエンドに降られて404が返る
動作確認用のbootcampのデプロイ
動作確認用にbootcampをデプロイする
yamlは以下の通り
bootcampフォルダを作ってそこに配置する
- 後でapplyが楽なので
bootcamp/deployment.yaml
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
bootcamp/service.yaml
apiVersion: v1
kind: Service
metadata:
name: bootcamp
labels:
app: bootcamp
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8080
selector:
app: bootcamp
bootcamp/ingress.yaml
cert-managerの設定とかも入ってるけどこれは今度また書く
kind: Ingress
metadata:
name: bootcamp
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/issuer: "letsencrypt"
spec:
tls:
- hosts:
- home.ideta.net
secretName: bootcamp-tls
rules:
- host: home.ideta.net
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: bootcamp
port:
number: 80
デプロイ
kubectl apply -f bootcamp
チェック
ingressがhostにIPの指定を許していないのでとりあえず適当に名前を割り当てておく
ちゃんとノードにリクエストが飛ぶ名前にしておけばこれでもうつながる
ただし、うちには外部接続性のない貧しい家庭なので追加の手順が必要になる
各ノードにリクエストを振り分けるnginxの設定
うちは家に外部からの接続性がないのでリクエストを受け付ける用のVMをvultrに用意している
k8sのクラスタ外にあるそのVMでnginxを動かしてそこからVPN経由でクラスタにリクエストをプロキシしている
自分の場合は以下みたいな感じで外から接続する用のnginxが各masterノードにリクエストを振り分けてる
- 厳密にはVPNで繋いでいるプロキシ用のVMが宅内側にもう一台いるがやっていることは同じくVPN経由の外からのリクエストをnginxでプロキシしているだけなので省略
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
stream {
upstream http {
server 10.1.0.1:80 max_fails=10 fail_timeout=10;
server 10.1.0.2:80 max_fails=10 fail_timeout=10;
server 10.1.0.3:80 max_fails=10 fail_timeout=10;
}
server {
listen 80;
proxy_pass http;
}
upstream https {
server 10.1.0.1:443 max_fails=10 fail_timeout=10;
server 10.1.0.2:443 max_fails=10 fail_timeout=10;
server 10.1.0.3:443 max_fails=10 fail_timeout=10;
}
server {
listen 443;
proxy_pass https;
}
}
この状態で http://home.ideta.net に接続するとbootcampにつながっている
リロードしてると2個あるpodにいい感じに振り分けられてるのを感じられる
力尽きたのでcert-managerの設定の話とその他諸々はまた書く