今まで(2021年頃まで) は、社内サーバの Kubernetes 環境を作る際は、 Rancher を Docker で起動し、その中の RKE で Kubernetes クラスタを構築していました。
ところが、それだと OS のアップデートがあったりした時など、年一回ぐらいのペースでトラブルがあり、環境が再構築不能になってしまっていました。
Rancher + RKE で Kubernetes 環境を作っている場合、トラブルの原因を追うのが非常に難しくて、原因まで解明して解決できたことはありません。
今回は、 Kubernetes 環境は Ubuntu の MicroK8s で起動し、その K8s の中で、 Deployment として Rancher を起動するようにしました。
試してみた所、なかなか快適だったため、今後もこのパターンは使っていこうと思います。
OS は Ubutntu 22.04 で、ノードはシングルノード構成です。やはり OS が Ubutnu の場合は MicroK8s が簡単で安定しており、Ingress なども一発で有効化できるため、セットアップは楽でした。
1. MicroK8s の セットアップ
1-1. インストール
sudo snap install microk8s --classic
1-2. ユーザーに権限を付与する
sudo usermod -a -G microk8s ubuntu
sudo chown -f -R ubuntu ~/.kube
newgrp microk8s
1-3. DNS, Ingress の有効化
microk8s enable dns ingress
1-4. ダッシュボードを使う場合
Rancher が起動したらダッシュボードは不要だと思いますが、Rancher 起動前の確認用として重宝します。
microk8s enable dashboard
Kubernetes のノード上で
microk8s kubectl port-forward -n kube-system service/kubernetes-dashboard --address 0.0.0.0 31443:443
してから、https://<your-host>:31443/ を見る
2. kubeconfig の取得
microk8s config
コピペして、 Mac の .kube/config-<Config名>
にコピーしておく
3. namespace の作成
※ Macで実行
#!/usr/bin/env zsh
export KUBECONFIG=${HOME}/.kube/config-<Config名>
kubectl create namespace <ネームスペース>
4. secrets の作成
SSL証明書 (wildcard.example.com.key, wildcard.example.com.crt) を mac のディレクトリに用意して、
※ Macで実行
#!/usr/bin/env zsh
export KUBECONFIG=${HOME}/.kube/config-<Config名>
kubectl -n <ネームスペース> create secret tls tls-certificate \
--key <wildcard.example.com.key> \
--cert <wildcard.example.com.crt>
5. Rancher のインストール
サーバに /data/rancher
ディレクトリを作っておく
deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-awesome-rancher-deployment
namespace: <ネームスペース>
spec:
replicas: 1
selector:
matchLabels:
app: my-awesome-rancher
template:
metadata:
labels:
app: my-awesome-rancher
spec:
containers:
- name: my-awesome-rancher
image: rancher/rancher:v2.6-head
imagePullPolicy: Always
ports:
- containerPort: 80
volumeMounts:
- name: data-rancher
mountPath: /var/lib/rancher
imagePullSecrets:
- name: ecr-credeintial
volumes:
- name: data-rancher
hostPath:
path: /data/rancher
service.yml
apiVersion: v1
kind: Service
metadata:
name: my-awesome-rancher-service
namespace: <ネームスペース>
spec:
type: NodePort
ports:
- port: 80
protocol: TCP
targetPort: 80
name: my-awesome-rancher-http
selector:
app: my-awesome-rancher
ingress.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-awesome-rancher-ingress
namespace: <ネームスペース>
spec:
tls:
- hosts:
- my-awesome-rancher.example.com
secretName: tls-certificate
rules:
- host: my-awesome-rancher.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-awesome-rancher-service
port:
number: 80
※ mac で実行
#!/usr/bin/env zsh
export KUBECONFIG=${HOME}/.kube/config-<Config名>
kubectl apply -f deployment.yml
kubectl apply -f service.yml
kubectl apply -f ingress.yml
6. Rancher の ブートストラップパスワードの取得
Rancher を起動すると、「ブートストラップパスワード」が発行され、ログに表示されます。
今回は Kubernetes の Pod として起動しているため、Pod のログを grep します。
※ Macで実行
#!/usr/bin/env zsh
export KUBECONFIG=${HOME}/.kube/config-<Config名>
pods=( $(kubectl get pod -n <ネームスペース> | egrep -o "my-awesome-rancher-deployment-[a-zA-Z0-9-]+") )
for pod in "${pods[@]}" ; do
kubectl logs -n <ネームスペース> ${pod} | grep "Bootstrap Password:"
done
7. ブラウザから Rancher へのログイン
my-awesome-rancher.example.com (仮のドメインです) というドメインで Rancher が起動しているはずなので、DNS を設定してからブラウザでアクセスします。
Bootstrap Password の入力を求められるので、先程取得したものを入力します。
ローカルで起動している MicroK8s のシングルノードクラスタを自動的に認識し、管理できるようになります。
付録
kubernetes の secret へ、AWS の EKS のログイントークンを登録する Python スクリプト
当社は、Docker イメージリポジトリは AWS ECR を使っています。
ローカルPCの ~/.aws/credentials
の認証情報を元に、 Kubernetes の Secret を作るスクリプトを紹介します。
#!/usr/bin/env python3
import subprocess
import re
import sys
namespace = '<ネームスペース>'
secret_name = 'ecr-credeintial'
aws_region = 'ap-northeast-1'
docker_server = 'https://<AWS-ID>.dkr.ecr.ap-northeast-1.amazonaws.com'
def main():
output = subprocess.check_output([
'/usr/bin/aws', 'ecr', 'get-login',
'--no-include-email', '--region', aws_region,
]).decode()
words = output.split()
username = words[words.index('-u') + 1]
password = words[words.index('-p') + 1]
// 既に作成済みの secret を消す
command = [
// kubectl の実行環境に合わせて調整してください
'microk8s', 'kubectl', '-n', namespace, 'delete', 'secret', secret_name]
subprocess.run(command)
// secret を再登録する
command = [
'microk8s', 'kubectl', '-n', namespace, 'create', 'secret',
'docker-registry', secret_name,
f'--docker-username={username}',
f'--docker-password={password}',
f'--docker-server={docker_server}'
]
subprocess.run(command)
if __name__ == '__main__':
main()