明日から本気だす

データベース好きなサポートエンジニアのメモです.

Minikube で kubernetes 入門してみた

はじめに

前々から気になっていた kubernetes を入門するため、まずはローカルの Minikube 環境でいろいろと触ってみたときのメモ。どこから手を付けるべきか迷ったので Udemy の 米シリコンバレーDevOpsエンジニア監修!超Kubernetes完全入門(2020)【優しい図解説とハンズオン】 をセール時に購入し、コースのハンズオンに沿って勉強した。すごいわかりやすいのでおすすめ。

Minikube とは

PC 上の VM 環境でシングルノードの Kubenetes クラスターを実行するためのツール。以下の環境にインストール。

  • Docker Desktop 3.1.0
  • WSL v2 Ubuntu 20.04

環境の構築

kubectl のインストール

まずは kubectl をインストールする。kubectlクラスターのエンドポイント(API Server)と SSL 通信してリソースなどを制御する。WSL2 上の Ubuntu で実行する。

$ curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl"
$ chmod +x ./kubectl
$ sudo mv ./kubectl /usr/local/bin/kubectl

Minikube のインストール

Minikube のインストール。同じく WSL2 上の Ubuntu で実行する。

$ curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
$ sudo install minikube-linux-amd64 /usr/local/bin/minikube

起動と停止

起動

WSL2 上の Ubuntuminikube start を実行する。

$ /usr/local/bin/minikube start --vm-driver=docker
😄  minikube v1.17.0 on Ubuntu 20.04
✨  Using the docker driver based on existing profile
🎉  minikube 1.17.1 is available! Download it: https://github.com/kubernetes/minikube/releases/tag/v1.17.1
💡  To disable this notice, run: 'minikube config set WantUpdateNotification false'

👍  Starting control plane node minikube in cluster minikube
🔄  Restarting existing docker container for "minikube" ...
🐳  Preparing Kubernetes v1.20.2 on Docker 20.10.2 ...
🔎  Verifying Kubernetes components...
🌟  Enabled addons: storage-provisioner, default-storageclass
🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default

docker コマンドで確認すると minikube のコンテナが稼働してる。

$ docker ps -a
CONTAINER ID   IMAGE                                 COMMAND                  CREATED      STATUS                      PORTS     NAMES
37cb31974986   gcr.io/k8s-minikube/kicbase:v0.0.17   "/usr/local/bin/entr…"   7 days ago   Exited (130) 35 hours ago             minikube

停止

停止は minikube stop で OK。

$ minikube stop
✋  Stopping node "minikube"  ...
🛑  Powering off "minikube" via SSH ...
🛑  1 nodes stopped.

Pod

k8s では Pod という単位でコンテナを管理する。Pod は仮想 NIC や Volume が共有され、同一のノードに配置される。

Hello World Pod の起動

kubectlrun オプションで Pod を起動する。 --restart=Never を指定しないとデフォルトでは deployment が作成されてしまう。

$ kubectl run --image gcr.io/google-samples/hello-app:1.0 --restart Never helloworld

Pod の情報を確認

curl コマンドで Pod にアクセスする場合、Service が作成されていないので、curl イメージからのみアクセスが可能。

$ kubectl get pod,svc -o wide
# -- Pod 内のログを確認
$ kubectl describe pod helloworld 
# -- Pod のメタ情報を確認
$ kubectl logs helloworld

# -- pod の IP アドレスを確認
$ kubectl get pod -o wide | awk 'NR>1 {print $6}; END{sub(/[ \t]+$/, "")}'
# -- curl image からアクセス
$ kubectl run --restart Never --image curlimages/curl:7.68.0 -it --rm curl sh

Pod への接続

-it はコンテナの標準入力に擬似 tty を割り当てるオプション。

$ kubectl exec -it helloworld sh

Pod 削除

$ kubectl delete pod hellworld

Pod に環境変数を設定

docker コマンドと同じ。

$ kubectl run --env TEST_ENV=hello_world --image gcr.io/google-samples/hello-app:1.0 --restart Never helloworld
# -- 確認方法
$ kubectl exec -it helloworld env

Service

永続的な IP アドレスを持たない Pod に対して、クライアントからのアクセスするためのオブジェクト。Pod 内外に公開するための L4 ロードバランサーの役割を担う。サービスのタイプは以下のとおり。

サービスタイプ 内容
ClusterIP Pod の前でスタティック IP をもったロードバランサーとして機能する。クラスター外からは接続不可。
NodePort Node に対して振られるので、クラスター外からも IPと指定 Port でアクセスすることができる。ポートは 3000 番台が割り当てられる。
LoadBalancer NodePort の前でロードバランサーとして動作し、クラスター外からも代表 IP アドレスと Port でアクセスができる。L4 のロードバランシングのみ。
ExternalName

ClusterIP

ClusterIP を helloworld Pod に作成したあとに別 Pod から curl で接続を確認する。kubectl expose--type のデフォルトは ClusterIP となるため、省略可。

$ kubectl expose pod helloworld --type ClusterIP --port 8080 --name helloworld-clusterip

# -- curl image の Pod から確認
$ kubectl run --restart Never --image curlimages/curl:latest -it --rm curl sh
$ curl helloworld-clusterip:8080

NodeIP

NodeIP を作成して接続を確認する。Windows WSL を利用しているので Minikube は Docker Desktop 上のコンテナとして動作している。外部からの接続は Minikube のコンテナから実施する。

$ kubectl expose pod helloworld --type NodePort --port 8080 --name helloworld-nodeport

# -- NodeIP と Port を調べる
$ minikube ip
$ kubectl get pod,service

# -- minikube コンテナから接続を確認
$ docker exec -it minikube bash
$ curl <ip>:<port>

LoadBalancer

LoadBalancer を作成して接続を確認する。接続方法は NodeIP と同様。

$ kubectl expose pod helloworld --type LoadBalancer --port 8080 --name helloworld-lb

Ingress

LoadBalancer だと L4 でのロードバランシングとなり、Service 毎に作成されるので非効率。 L7 のロードバランシングでクラスター内外に Pod を公開する場合は Ingress を作成する。クラスター外部からアクセスする場合は URL パスによる Service の切り替えができる。

Minikube で Ingress を作成するための準備

Minikube の場合、アドオンで Ingress を有効にすると、Ingress Pod が追加される。

$ minikube addons list
$ minikube addons enable ingress
🔎  Verifying ingress addon...
🌟  The 'ingress' addon is enabled

# -- namespace で kube-system を指定
$ kubectl get pod --namespace kube-system
NAME                                        READY   STATUS      RESTARTS   AGE
coredns-74ff55c5b-wb628                     1/1     Running     5          7d11h
etcd-minikube                               1/1     Running     5          7d11h
ingress-nginx-admission-create-cf4n8        0/1     Completed   0          42s
ingress-nginx-admission-patch-rt69n         0/1     Completed   0          42s
ingress-nginx-controller-558664778f-2sdl5   0/1     Running     0          42s
kube-apiserver-minikube                     1/1     Running     5          7d11h
kube-controller-manager-minikube            1/1     Running     5          7d11h
kube-proxy-95zns                            1/1     Running     5          7d11h
kube-scheduler-minikube                     1/1     Running     5          7d11h
storage-provisioner                         1/1     Running     10         7d11h

YAML ファイルを指定して作成

Ingress リソースの作成して接続を確認する。YAML ファイルの kind:Ingress を指定。metadata: name: を helloworld で作成した。その他の YAML ファイルの書き方はドキュメントを参照。

参考: Ingress リソース

$ kubectl apply -f ingress.yaml
$ kubectl get ingress
# -- 詳細表示
$ kubectl describe ingress helloworld

ReplicaSet

Pod の複製(レプリカ)数を管理する。Deployment と一緒に利用する。YAML ファイルの kind: で ReplicaSet を指定。

参考: ReplicaSet

$ kubectl apply -f replicaset.yaml
$ kubectl get replicaset

replicaset 数の変更。下記のコマンドだと 5 へ変更している。

$ kubectl scale --replicas=5 replicaset.apps/helloworld

Deployment

複数の Pod でクラスタを構成する。ReplicaSet が利用され Pod のスケールアップなどが可能。Pod を作成時のオプション --restart Never を省略すると Deployment が作成される。

$ kubectl run --image gcr.io/google-samples/hello-app:1.0 helloworld

もしくは、以下のコマンドで作成する。kubectl のバグ(?)のため、自分の環境だと kubectl create による作成が必要だった。

$ kubectl create deployment --image gcr.io/google-samples/hello-app:1.0 helloworld

Deployment に NodePort を作成して curl でアクセス。

$ kubectl expose deployment helloworld --type NodePort --port 8080 --name helloworld-nodeport

# -- minikube 
$ docker exec -it minikube bash
$ curl <IP>:<Port>

Deployment のイメージをバージョンアップし crul でアクセスすると、徐々に Pod が 2.0 になっていくのがわかる。

$ kubectl set image deploy/helloworld hello-app=gcr.io/google-samples/hello-app:2.0

# -- minikube 
$ docker exec -it minikube bash
$ for i in {1..30}; do  curl <IP>:<Port>; sleep 3; done

YAML の利用

kubectl コマンドでリソース作成時に --dry-run=client-o yamlYAML 形式でマニュフェスト・ファイルを出力できる。ここまで、リソース作成に kubectl コマンドを利用してきたが、実運用ではマニュフェスト・ファイルでコードとして管理するほうが一般的。

# -- helloworld Pod の設定を yaml ファイルで出力
$ kubectl run --image grc.io/google-samples/hello-app:1.0 --restart Never --dry-run=client -o yaml helloworld > pod_helloworld.yaml
# -- Deployment の設定を yaml ファイルで出力
$ kubectl create deployment --image gcr.io/google-samples/hello-app:1.0 helloworld --dry-run=client -o yaml > deployment_helloworld.yaml

以下は YAML ファイルで複数のコンテナを定義した Deployment を定義したサンプル。kubectl create deployment で作成した deployment_helloworld.yamlimage: busybox の部分を追加したもの。 replicas: 5 なので、コンテナ hello-appsleep を含む Pod が 5 つデプロイされる。

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: helloworld
  name: helloworld
spec:
  replicas: 5
  selector:
    matchLabels:
      app: helloworld
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: helloworld
    spec:
      containers:
      - command:
        - /bin/sh
        - -c
        - sleep 5000
        image: busybox
        name: sleep
        ports:
        - containerPort: 80
      - image: gcr.io/google-samples/hello-app:1.0
        name: hello-app
        ports:
        - containerPort: 8080
status: {}

YAML からリソース作成

上記の YAML ファイルからリソースを作成するには以下のコマンドを実行。

$ kubectl apply -f deployment_helloworld.yaml
# -- リソースを削除
$ kubectl delete -f deployment_helloworld.yaml

Deployment の helloworld Pod のコンテナに接続する場合は -c オプションでコンテナ名を指定。

$ kubectl exec -it helloworld-77597bdc79-5qh75 -c hello-app sh

Config Map

設定をキーと値のペアで保存するための API オブジェクト。下記では、環境変数 TEST_ENV=helloworld の設定を ConfigMap で作成。

$ kubectl create configmap my-config --from-literal=TEST_ENV=helloworld --dry-run=client -o yaml > configmap.yaml
$ kubectl apply -f configmap.yaml

# -- 確認方法
$ kubectl get configmap
$ kubectl describe configmap my-config

Pod の YMAL ファイルの configMapKeyRef で作成した ConfigMap を指定する。

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: helloworld
  name: helloworld
spec:
  containers:
  - env:
    - name: TEST_ENV
      valueFrom:
        configMapKeyRef:
          name: my-config
          key: TEST_ENV
    image: gcr.io/google-samples/hello-app:1.0
    name: helloworld
    ports:
    - containerPort: 8080
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Never
status: {}

Pod を作成し、環境変数を確認すると ConfigMap を介して設定されている。

$ kubectl apply -f helloworld.yaml
# -- 確認方法
$ kubectl exec -it helloworld env

ConfigMap の KeyValue を Pod の Volume としてマウントすることもできる。

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: helloworld
  name: helloworld
spec:
  containers:
  - image: gcr.io/google-samples/hello-app:1.0
    name: helloworld
    ports:
    - containerPort: 8080
    resources: {}
    volumeMounts:
    - name: my-config-volume
      mountPath: /my-config/TEST_ENV
  volumes:
    - name: my-config-volume
      configMap:
        name: my-config
        items:
        - key: TEST_ENV
          path: keys
status: {}

PVC(永続ボリューム要求)

DB のデータファイルなどはノードに Persistent Volume を作成し保存することで、Pod が削除されてもデータの永続化が可能。Pod が Persistent Volume を利用する場合は PVC(永続ボリューム要求)を行う。

マウントボリュームの作成

Minikube でマウントボリュームを作成。

$ minikube ssh
$ sudo mkdir /mnt/pvc && sudo chown docker:docker /mnt/pvc
$ touch /mnt/pvc/persistent.txt

PV の作成

以下の YAML ファイルで PV を作成。

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv
spec:
  storageClassName: manual
  capacity:
    storage: 100M
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/pvc"

リソースの作成と確認

$ kubectl apply -f persistent_vol.yaml
# -- 確認方法
$ kubectl get pv

PVC(永続ボリューム要求)

以下の YAML ファイルで PVC を作成。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10M

同様にリソースの作成と確認

$ kubectl apply -f persistent_vol_claim.yaml
# -- 確認方法
$ kubectl get pvc

Pod で PV を利用

Pod の YAML ファイルの persistentVolumeClaim で作成した PVC リソースを指定。

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: helloworld-pvc
  name: helloworld-pvc
spec:
  containers:
  - image: gcr.io/google-samples/hello-app:1.0
    name: helloworld-pvc
    ports:
    - containerPort: 8080
    resources: {}
    volumeMounts:
    - name: my-pv
      mountPath: /mnt/pvc
  volumes:
    - name: my-pv
      persistentVolumeClaim:
        claimName: pvc

Pod の作成と確認。Pod が削除されても Minikube(ホスト)上の /mnt/pvc に hogehoge.txt は保持される。

$ kubectl exec -it helloworld-pvc sh
$ cd /mnt/pvc
$ echo "hogehoge" > hogehoge.txt

その他

Master API Server エンドポイントを表示。

$ kubectl cluster-info

クラスターエンドポイントと CA cert を表示

$ kubectl config view

すべてのリソースを表示。

$ kubectl get all -o wide

ToDo

Kubernetes クラスターの構築にチャレンジしたい。