はじめに
ローカルに実験的にKubernetesを立てようと思った時、本番環境との構成の違いに悩んでしまうことがあります。Kubernetes自体は動かすことはできますが、PODのボリュームやIngressを同じように作成できないことなどがあります。そのすべてを解決するものではありませんが、ある程度の機能を持つものとしてminikubeがあります。
この記事では、minikubeのインストールからリソースの作成を行い、ローカルでのKubernetesを少しでも身近に感じてもらえれば幸いです。
minikubeの特徴
この記事では以下のminikubeの特徴について、後述のハンズオンで触れてみます。
・PersistentVolumeの動的プロビジョニングの機能を持つ
クラウドのKubernetesクラスタでは、ボリュームの場所を動的に確保しPVを作成できるものがあります。minikubeでもVMドライバーの場所を動的に確保しPVを作成することができます。
・ローカルのDockerイメージを使用できる
クラウドではコンテナレジストリを使用しますが、minikubeでは不要でローカルのイメージを使用できます。
・Ingressコントローラーをアドオンとして使うことができる
minikubeにはアドオンの機能があり、楽にNginxのIngressコントローラーを作成することができます。お手軽にIngressに触れることができます。
詳細は以下のドキュメントになります。
minikubeを動かすためのCPU,メモリー
参考にKubernetesも載せておきます。minikubeが軽いわけではないですね。
CPUコア数 | メモリー | 参照URL | |
---|---|---|---|
minikube | 2 | 2GB | https://kubernetes.io/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm/ |
Kubernetes | 2 | 2GB | https://minikube.sigs.k8s.io/docs/start/ |
minikubeのインストールとstart
前提としてOSはAmazon Linux 2です。
まずはDockerをインストールします。
$ sudo yum install -y docker-20.10.17-1.amzn2.0.1
$ sudo systemctl start docker
$ sudo systemctl enable docker
$ sudo gpasswd -a ec2-user docker
ユーザーのグループを変更したので、いったん再ログインします。
その後、minikubeをインストールします。
$ curl -LO https://storage.googleapis.com/minikube/releases/v1.27.1/minikube-linux-amd64
$ sudo install minikube-linux-amd64 /usr/local/bin/minikube
minikubeをstartさせます。オプションとしてKubernetesのバージョン指定やリソースの制限などができます。
[ec2-user@ip-10-0-0-50 ~]$ minikube start \
--cpus='2' \
--memory='2g' \
--driver='docker' \
--kubernetes-version=v1.25.2
😄 minikube v1.27.1 on Amazon 2 (xen/amd64)
▪ MINIKUBE_ACTIVE_DOCKERD=minikube
✨ Using the docker driver based on user configuration
📌 Using Docker driver with root privileges
👍 Starting control plane node minikube in cluster minikube
🚜 Pulling base image ...
💾 Downloading Kubernetes v1.25.2 preload ...
> preloaded-images-k8s-v18-v1...: 385.41 MiB / 385.41 MiB 100.00% 41.56 M
🔥 Creating docker container (CPUs=2, Memory=2048MB) ...
🐳 Preparing Kubernetes v1.25.2 on Docker 20.10.18 ...
▪ Generating certificates and keys ...
▪ Booting up control plane ...
▪ Configuring RBAC rules ...
🔎 Verifying Kubernetes components...
▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟 Enabled addons: default-storageclass, storage-provisioner
💡 kubectl not found. If you need it, try: 'minikube kubectl -- get pods -A'
🏄 Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
この時点で、kubectlコマンドを使うことができます。
$ minikube kubectl -- get node
NAME STATUS ROLES AGE VERSION
minikube Ready control-plane 2m34s v1.25.3
しかし、コマンドが長く面倒なのでaliasを設定します。
$ alias k="minikube kubectl --"
$ echo 'alias k="minikube kubectl --"' >> ~/.bash_profile
これで「minikube kubectl --」から「k」にコマンドを短くできました。
また、このままではDockerでビルドしたイメージを使うことができません。以下のコマンドを実行します。
$ eval $(minikube docker-env)
$ echo 'eval $(minikube docker-env)' >> ~/.bash_profile
ハンズオン
PVの動的プロビジョニングの確認
それではクラスター上にKubernetesリソースを作成してみます。
以下のサンプルからStatefulSet、Serviceを作成します。
[ec2-user@ip-10-0-0-50 ~]$ k apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/ja/examples/application/web/web.yaml
service/nginx created
statefulset.apps/web created
StatefulSetのボリュームテンプレートから、自動で動的にボリュームが作成されます。
[ec2-user@ip-10-0-0-50 ~]$ k get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-257531da-0c5f-4142-b50b-faf3f91897a0 1Gi RWO Delete Bound default/www-web-0 standard 12m
pvc-af257a5b-ddd5-40be-b753-d836a2e5757a 1Gi RWO Delete Bound default/www-web-1 standard 11m
[ec2-user@ip-10-0-0-50 ~]$ k get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www-web-0 Bound pvc-257531da-0c5f-4142-b50b-faf3f91897a0 1Gi RWO standard 12m
www-web-1 Bound pvc-af257a5b-ddd5-40be-b753-d836a2e5757a 1Gi RWO standard 12m
どこにボリュームの場所が作成されているかですが、PVをdescribeするとわかります。
[ec2-user@ip-10-0-0-50 ~]$ k describe pv pvc-257531da-0c5f-4142-b50b-faf3f91897a0
Name: pvc-257531da-0c5f-4142-b50b-faf3f91897a0
Labels: <none>
Annotations: hostPathProvisionerIdentity: 8481dbd2-eea1-4c46-90ba-17db4f7a928b
pv.kubernetes.io/provisioned-by: k8s.io/minikube-hostpath
Finalizers: [kubernetes.io/pv-protection]
StorageClass: standard
Status: Bound
Claim: default/www-web-0
Reclaim Policy: Delete
Access Modes: RWO
VolumeMode: Filesystem
Capacity: 1Gi
Node Affinity: <none>
Message:
Source:
Type: HostPath (bare host directory volume)
Path: /tmp/hostpath-provisioner/default/www-web-0
HostPathType:
Events: <none>
minikubeではVMドライバー上に場所が確保されます。minikubeの起動ログにUsing Docker driver with root privileges
とあったのでroot権限でコンテナを動かしていそうです。確認してみます。
[ec2-user@ip-10-0-0-50 ~]$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
440ec508be92 gcr.io/k8s-minikube/kicbase:v0.0.35 "/usr/local/bin/entr…" 20 minutes ago Up 20 minutes 127.0.0.1:49162->22/tcp, 127.0.0.1:49161->2376/tcp, 127.0.0.1:49160->5000/tcp, 127.0.0.1:49159->8443/tcp, 127.0.0.1:49158->32443/tcp minikube
[ec2-user@ip-10-0-0-50 ~]$ sudo docker exec -it minikube bash
root@minikube:/# ls /tmp/hostpath-provisioner/default/
www-web-0 www-web-1
minikubeのコンテナ上にPVの場所を確認することができました。コンテナ上なので、再起動すると消える一時的なものになると思います。
ローカルのDockerイメージの使用
コンテナのイメージを別のNginxに切り替えてみます。
$ docker pull nginx
$ docker tag nginx:latest my-nginx:v1.0
$ k edit statefulset web #imageをmy-nginx:v1.0に書き換える。
PODの参照するイメージが切り替わり、再起動できていればローカルのイメージを使えていそうです。
[ec2-user@ip-10-0-0-20 ~]$ k get pod
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 10s
web-1 1/1 Running 0 14s
[ec2-user@ip-10-0-0-20 ~]$ k describe pod web-0 | grep 'Image:'
Image: my-nginx:v1.0
自動で再起動されていました。もしeval $(minikube docker-env)
を実行しなければローカルのイメージを使えず、実行後イメージの再ビルドをすることになりました。。
Ingressコントローラーをアドオンとして使用する
Ingressコントローラーをminikubeで使いたい場合、アドオンとして楽に作成できます。しかし、以下のドキュメントのようにクラウド、クラスタによって適したIngressコントローラーは異なります。環境毎に違うものになってしまうため、お手軽にIngressを試したい場合に以下の手順が参考になると思います。
以下のコマンドで作成します。
$ minikube addons enable ingress
Ingressコントローラーを追加できると、Namespace「ingress-nginx」が自動で作られDeploymentができています。
[ec2-user@ip-10-0-0-20 ~]$ k get deployment -n ingress-nginx
NAME READY UP-TO-DATE AVAILABLE AGE
ingress-nginx-controller 1/1 1 1 107s
[ec2-user@ip-10-0-0-20 ~]$ k get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-l5qzs 0/1 Completed 0 2m3s
ingress-nginx-admission-patch-2tnrq 0/1 Completed 0 2m3s
ingress-nginx-controller-5959f988fd-bvfww 1/1 Running 0 2m3s
早速Ingressコントローラーを使って、前に作ったStatefulSetのPODにアクセスできるようにしてみます。
まず、POD内部でアクセスできるようになっているか確認します。
[ec2-user@ip-10-0-0-20 ~]$ k exec web-0 -it -- bash
root@web-0:/# curl localhost #htmlファイルがないのでエラーになります。
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.23.2</center>
</body>
root@web-0:/# echo "hogehoge web-0" > /usr/share/nginx/html/index.html #表示できればよいので内容はなんでも良しとします。
root@web-0:/# curl localhost
hogehoge web-0
</html>
同様にもう1台のPODもhtmlファイルを作成しておきます。
次にIngressを作成します。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-nginx
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: test-nginx
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx
port:
number: 80
$ k apply -f test-nginx-ingress.yaml
Ingressが存在して、バックエンドにPODが存在しているかを確認します。
[ec2-user@ip-10-0-0-20 ~]$ k get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
test-nginx nginx test-nginx 192.168.49.2 80 83s
[ec2-user@ip-10-0-0-20 ~]$ k describe ingress
Name: test-nginx
Labels: <none>
Namespace: default
Address: 192.168.49.2
Ingress Class: nginx
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
test-nginx
/ nginx:80 (172.17.0.3:80,172.17.0.4:80)
Annotations: nginx.ingress.kubernetes.io/rewrite-target: /$1
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 47s (x2 over 94s) nginx-ingress-controller Scheduled for sync
バックエンドにはPODが2台ともいました。
また、Ingressの設定におかしなところがないかはIngressコントローラーのログを見るとわかります。
$ k logs -n ingress-nginx ingress-nginx-controller-5959f988fd-bvfww
また、IngressにはIPアドレス「192.168.49.2」が割り当てられており、アクセスすることができます。
[ec2-user@ip-10-0-0-20 ~]$ curl 192.168.49.2:80
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
404エラーなので、バックエンドのPODには到達せずIngressコントローラーから応答が返ってきています。
バックエンドのPODにアクセスするには、ホスト名を指定します。
[ec2-user@ip-10-0-0-20 ~]$ curl 192.168.49.2:80 -H "Host:test-nginx"
hogehoge web-0
[ec2-user@ip-10-0-0-20 ~]$ curl 192.168.49.2:80 -H "Host:test-nginx"
hogehoge web-1
[ec2-user@ip-10-0-0-20 ~]$ curl 192.168.49.2:80 -H "Host:test-nginx"
hogehoge web-1
[ec2-user@ip-10-0-0-20 ~]$ curl 192.168.49.2:80 -H "Host:test-nginx"
hogehoge web-0
アクセスできました。繰り返すと応答が異なっており2台のPODにアクセスしていることがわかります。
minikube実験後のKubernetesへの移行について
minikubeでの実験後、Kubernetes本番で検証することになると思います。この時、どうしても設定の違いは出て切ると思います(annotations,パラメータなど)。
そのため、minikubeとKubernetesを行き来するたび、設定を書き換えなくてはならないかと思ってしまいます。
そこでKustomizeの使用が検討されることになると思いますので、今後調べたいと思っています。
終わりに
今回はローカルでKubernetesを動かす方法について触れました。
記事にすると、今まで学んだ様々なことを俯瞰して整理できてよいと思いました。
今後も勉強します。