Closed17

minikube で始める kubernetes 学習

sakaNasakaNa

ツール

学習に必要なツールたち

ツール名 用途
kubectl Kubernetesのコマンドラインツール (CLI)
Kubernetesと接続してkubernetesを操作するツール
minikube Kubernetesをローカルで実行するツール

通常、k8s環境はサーバーなどで大規模な環境に構築するもの。それをローカルなどの小規模な環境でk8s環境を構築できるようにしたものがminikube
Dockerなどの仮想環境上でシングルノードのKubernetesクラスターを構築する。

ツールたちの関係性

簡単に書くと下記のような関係性
PC/Mac -> [kubectl] -> minikube (Docker上で動く)

引用元: https://qiita.com/fukumasa/items/884eadd2694de19d64ff
上記だとVMになっているがMacで立ち上げたDocker container 内で minikube は動作していると思う。

(ここでは触れないが、ややこしいのはnode上のクラスターの上でさらにDocker containerが動作していること)

ツールのインストール

大前提としてDockerがインストールされていること

kubectl をインストール

brew install kubectl

minikube をインストール

brew install minikube

ちなみに 自分の環境では k8s 自体は Mac で Docker 動かすのに使っている Rancher Desktop に入っているので kubectl のインストールは不要だった。

sakaNasakaNa

kubernetes とは

コンテナ化されたアプリケーションを管理するためのプラットフォーム
https://kubernetes.io/ja/docs/concepts/overview/

前提として、社内などのたくさんのアプリケーションがあるような状況を想定しているっぽい

メリット

コンテナ管理の簡略化

複数のコンテナ管理を自動化して、アプリケーションのデプロイ、変更の適用、スケールアップやスケールダウンを行ってくれる。コンテナがダウンしてしまったり、間違えて削除してしまったりした場合も自動で回復させることが可能。

これを実現させているのが、宣言的設定である。
宣言的設定とは、あるべき状態だけが定義され、その状態にするための手順は指示しない設定のこと。これによりあるべき状態から外れた場合にその状態に戻そうとしてくれる。宣言的設定と対照的なのが、命令的設定で操作やコマンドを記述した設定であり、Dockerfile がこれにあたる。

物理サーバーとアプリケーションの間の抽象レイヤー

物理サーバーとアプリケーションの間に抽象レイヤーとして入り、両者の間の依存関係を断ち切ってくれる (アプリケーションはk8sにだけ依存する)

複数の物理/仮想サーバーを束ねることが出来き、複数のサーバーで複数のコンテナを動かすことができる。さらに物理サーバーが1つダウンしても他のサーバーでカバーされ、アプリケーション開発者は物理サーバーの構成やメンテナンス、障害を気にする必要がなくなる

参考

k8s を使う理由は下記の説明がわかりやすかった
https://zenn.dev/esaka/articles/2d117655af1f03cf2444
https://cybozu.github.io/introduction-to-kubernetes/introduction-to-kubernetes.html

sakaNasakaNa

前提知識

https://kubernetes.io/ja/docs/concepts/overview/components/

コントロールプレーン (Control Plane)

Kubernetesクラスタのマスターコンポーネント(kube-apiserver, kube-controller-manager, kube-scheduler, etcdなどを実行) で、クラスタの状態を管理・制御を行う。マスターノード上で実行される。

ノード (Node)

クラスタ内の個々の物理または仮想マシンを指し、コンテナ化されたアプリケーションの実行環境

  • ワーカーノード: アプリケーションのコンポーネントであるPodをホストする
  • マスターノード: クラスタ内のワーカーノードとPodを管理する Control Plane を実行する

一般的にどのNodeでどのアプリケーションを動かすかなどを指定することはなく、アプリケーション側は実行環境であるNodeを意識することはない (どこのNodeで稼働しているかは確認できる)

クラスタ (Cluster)

Kubernetes クラスタは、コンテナ化されたアプリケーションを実行するためのノードの集合。Kubernetes を実行しているときは、クラスタが実行される。
クラスタは、1 つのControl Planeと、1 つ以上のNodeで構成される。この2つは物理レイヤの話しであり、クラスタはこの上のレイヤー

これ以降出てくる用語はクラスター内部の話。

ポッド (Pod)

Kubernetesの最小実行単位であり、1つ以上のコンテナをまとめて実行するためのひとつの空間。Pod内には複数のコンテナを配置することができる。

サービス (Service)

クラスタの内部および外部からPodとの通信を容易に行うためにエンドポイントの提供を行ってくれる機能。クラスター内のPod (コンテナ) に対して一意なネットワークアクセスを提供する抽象化されたリソース。
通常、NodeのIPアドレスは一定ではないが、サービスによってアプリケーションの安定したネットワーク接続を実現する。

デプロイメント (Deployment)

アプリケーションのデプロイとアップデートを管理するためのKubernetesリソース
指定された数のレプリカセットを作成し、Podのデプロイとスケーリングを簡素化する。アプリケーションのバージョンアップやロールバックなどの操作もデプロイメントを介して行われる。

またk8s の特徴である宣言的設定を実現する。
(宣言的設定とは、あるべき状態だけが定義され、その状態にするための手順は指示しない設定のこと。これによりあるべき状態から外れた場合にその状態に戻そうとしてくれる)

ネームスペース (Namespace)

クラスタ内のリソースを論理的に分割するための仕組み。異なるチームやプロジェクト、環境などを区別するために使用される。

sakaNasakaNa

minikube を試す

前提知識を学んだ後で、やっと最初に戻ってチュートリアル。
https://kubernetes.io/ja/docs/setup/learning-environment/minikube/

クラスタ構築

通常の k8s だと複数の Node 上にクラスタを構築するが、minikube では一つの Node 上に構築する (=シングルノード)

構築

下記のコマンドでクラスタが構築される (初回はminikubeのdockerコンテナをbuildするので時間かかる)

minikube start

Docker が入っていれば VM は Docker が選ばれるらしいが、一応確認 -> いるのでOK

$ docker ps
CONTAINER ID   IMAGE                                 COMMAND                   CREATED         STATUS         PORTS                                                                                                                                  NAMES
6c854c5670cb   gcr.io/k8s-minikube/kicbase:v0.0.39   "/usr/local/bin/entr…"   8 minutes ago   Up 8 minutes   127.0.0.1:49157->22/tcp, 127.0.0.1:49156->2376/tcp, 127.0.0.1:49155->5000/tcp, 127.0.0.1:49154->8443/tcp, 127.0.0.1:49153->32443/tcp   minikube

ちゃんとクラスタが動作しているかも確認 -> RunningになってるのでOK

$ minikube status
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured

停止

停止するのは下記のコマンド

minikube stop

止めるとStoppedになることも確認

$ minikube status
minikube
type: Control Plane
host: Stopped
kubelet: Stopped
apiserver: Stopped
kubeconfig: Stopped

もう一度minikube startすれば、再度クラスタが立ち上がる。

sakaNasakaNa

クラスタを操作

minikube によってクラスタが構築されたので、次にクラスタに接続&操作する。
先述した通り、kubectl を用いてクラスタを操作する。

接続するクラスタの設定

なお本来は接続するクラスタを kubectl で設定する必要があるが、minikube startによってその設定も自動で行われ、設定はkubeconfig (~/.kube/config) に書き込まれている。

下記で設定された内容を確認可能 (複数のクラスタに接続したい場合は、こちらに従ってcontext を追加する)

$ kubectl config view

念のため、現在の context が minikube になっていることを確認

$ kubectl config current-context
minikube

ちなみに context の切り替えは下記で可能 (minikube ところに 切り替え先のcontext 名をいれる)

$ kubectl config use-context minikube
Switched to context "minikube".
sakaNasakaNa

クラスタの構成を確認

接続するクラスタの設定が完了したので、kubectl でクラスタを構成する Nodeを確認してみる。

minikube startによってクラスタを構築すると下記のようなイメージでクラスタが作成される。マスターノードは省く。

なおminikube はシングルノードのためクラスタを構成する Node は一つであり、マスターノードも兼ねる。
下記でコマンドで構成するNodeを確認できるので確認してみると 、

$ kubectl get node              
NAME       STATUS   ROLES           AGE     VERSION
minikube   Ready    control-plane   4h59m   v1.26.3

1つだけしか表示されないのでシングルノードだとわかる

マルチノード化

ここはやらなくてもOKなので参考までに。
minikube の標準ではシングルノードだけれどもワーカーノードを増やしてマルチノード化することもできる。下記の例ではワーカーノードを2つにしている

minikube node add --worker 2

Nodeを確認してみると2つに増えている

$ kubectl get node            
NAME           STATUS   ROLES           AGE     VERSION
minikube       Ready    control-plane   4h59m   v1.26.3
minikube-m02   Ready    <none>          7s      v1.26.3

下記のようにクラスタを構成するワーカーノードが2つになる。これによって k8s のメリットである複数のサーバーを束ねることができているのがわかる。

sakaNasakaNa

本来、Node は別のマシンで動くはずなのに「なぜ同じMac上で複数 Node を実現できるの?」となると思うが、minikube では Node 自体がコンテナ上で動いており、複数の Node コンテナを立てることでマルチノードを実現できている。

試しに稼働中の Docker コンテナを確認してみると、2つのコンテナが稼働していることがわかる

$ docker ps
CONTAINER ID   IMAGE                                 COMMAND                   CREATED        STATUS        PORTS                                                                                                                                  NAMES
a3a21d3ffd77   gcr.io/k8s-minikube/kicbase:v0.0.39   "/usr/local/bin/entr…"   9 hours ago    Up 9 hours    127.0.0.1:49167->22/tcp, 127.0.0.1:49166->2376/tcp, 127.0.0.1:49165->5000/tcp, 127.0.0.1:49164->8443/tcp, 127.0.0.1:49163->32443/tcp   minikube-m02
6c854c5670cb   gcr.io/k8s-minikube/kicbase:v0.0.39   "/usr/local/bin/entr…"   14 hours ago   Up 14 hours   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
sakaNasakaNa

Deployment の作成

k8s では 各アプリケーションは Pod という単位でデプロイされ、実行される。 「どんな Pod を用意するか」を決めるためのものが Deployment であり、Deploymentに記述した Pod が自動で起動する。
このような宣言的設定 (あるべき姿の定義) を Deployment で行う。

Deployment の作成 (manifestを使用しないケース)

まずはシンプルに、チュートリアルに従い Deployment を作成してみる。

はじめに Pod が起動していないことを確認

$ kubectl get pod                         
No resources found in default namespace.

Deployment を作成

$ kubectl create deployment hello-minikube --image=kicbase/echo-server:1.0
deployment.apps/hello-minikube created

これは--image=で指定したコンテナイメージの Pod をhello-mminikubeという名前で用意するという意味。(チュートリアルの image だとうまくいかないのでこちらのものを用いた)

再度、Pod を確認すると、新たに Pod が起動していることを確認できる

$ kubectl get pod                                                         
NAME                              READY   STATUS    RESTARTS   AGE
hello-minikube-77b6f68484-8pvbw   1/1     Running   0          1s

この時点で下記のような状態になる

sakaNasakaNa

Service の作成

無事 Pod が立ち上がったが、このままだとクラスタの中からしかアクセスできない。そこで Pod との通信を容易に行うためにエンドポイントの提供してくれる Service 作成する。

下記コマンドで hello-minikube という名前の Deployment を外部に公開する Service を作成することができる。--type=NodePortとは Node のIPアドレスを使って公開すること指している (参考)。

$ kubectl expose deployment hello-minikube --type=NodePort --port=8080    
service/hello-minikube exposed

このService によって Deployment によって定義された Pod のポート (8080) が公開され、外部からアクセスが可能になる

Port forward 設定

実はまだローカル環境からはアクセスできない。
localhost のあるポートへ届いたパケットを 先ほど公開した Pod の 8080 へ転送するように設定する必要がある。下記コマンドでポート転送できる (今回は locahost:7080 を 8080 へ繋げる)

$ kubectl port-forward service/hello-minikube 7080:8080

Forwarding from 127.0.0.1:7080 -> 8080
Forwarding from [::1]:7080 -> 8080

この状態のまま、別の terminl を開いて curl で導通確認する

$ curl http://localhost:7080/ 
Request served by hello-minikube-77b6f68484-8pvbw

HTTP/1.1 GET /

Host: localhost:7080
Accept: */*
User-Agent: curl/7.88.1

response が返ってきていれば、導通確認はOK

これで立ち上げた Pod を公開することができた。

sakaNasakaNa

掃除 (Service, Deployment の削除)

最後に作成した Service, Deployment, Pod を削除させておく。

Service の削除

$ kubectl delete services hello-minikube
service "hello-minikube" deleted

Deployment の削除

$ kubectl delete deployment hello-minikube
deployment.apps "hello-minikube" deleted

Deployment が削除されたことで 定義されていた Pod も停止する

$ kubectl get pod
No resources found in default namespace.

作成した Service も削除されている

kubectl get svc
sakaNasakaNa

マニフェストの適用

上記で Deployment および Service を作成したが、通常はマニフェストと呼ばれる yaml ファイルで定義しておき、それを使ってリソースを作成することができる。

マニフェストの定義

マニフェストは下記のように定義される
deployment.yaml

apiVersion: apps/v1
# 定義の種類
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  # 指定した条件に一致する Pod をこの Deployment が管理する (ここではlabelが一致すること)
  selector:
    matchLabels:
      app: nginx
  # レプリカ数: レプリカとは複数のことで、ここの数字分の Pod を常に起動させる
  replicas: 3
  # 作成する Pod の定義
  template:
    metadata:
      labels:
        app: nginx
    spec:
      # Pod で起動するコンテナの定義 (Docker hubから取ってくる image を記載する)
      containers:
        - name: nginx
          image: nginx:1.7.9
          ports:
            - containerPort: 80

service.yaml

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
  # 指定したラベルにマッチする Pod に Service へのアクセスが割り振られる
  type: NodePort
  selector:
    app: nginx

マニフェストの適用

Deployment の定義を適用

$ kubectl apply -f deployment.yaml
deployment.apps/nginx-deployment created

Service の定義を適用

$ kubectl apply -f service.yaml
service/nginx-service created

適用されたリソースを確認

Pod の確認

上記のマニフェストでは Pod のレプリカ数を3としているので、起動中の Pod を確認すると3つ起動しているのを確認することができる。

$ kubectl get pod
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-699bfcdcb6-7rf4q   1/1     Running   0          78s
nginx-deployment-699bfcdcb6-h9ntg   1/1     Running   0          78s
nginx-deployment-699bfcdcb6-xh7tl   1/1     Running   0          78s

ちなみに Pod を一つ削除してみても

kubectl delete pod nginx-deployment-699bfcdcb6-xh7tl

Deployment に定義された状態に戻そうと自己復旧するので、すぐに別の Pod が立ち上がる

$ kubectl get pod
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-699bfcdcb6-7rf4q   1/1     Running   0          112s
nginx-deployment-699bfcdcb6-h9ntg   1/1     Running   0          112s
nginx-deployment-699bfcdcb6-tzcks   1/1     Running   0          13s

Deployment の確認

$ kubectl get deployment                       
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           10m

Service の確認

$ kubectl get service                          
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes      ClusterIP   10.96.0.1        <none>        443/TCP        20h
nginx-service   NodePort    10.105.159.180   <none>        80:32563/TCP   10m

導通確認

ポート転送を行い

$ kubectl port-forward service/nginx-service 7080:80
Forwarding from 127.0.0.1:7080 -> 80
Forwarding from [::1]:7080 -> 80
Handling connection for 7080

上記の状態で下記のURLへアクセスする
[http://localhost:7080/]

下記が表示されれば、接続できている

作成したリソースのイメージは下記の通り。
Deployment のレプリカセットから3つの Pod が起動する。また今回の場合、Pod が起動する Node の指定を特にしていないので、2つの Node に分かれて配置されている。kubectl describe podで確認可能
Pod への通信は Service によって適切な Pod へルーティングされる。

sakaNasakaNa

ちなみに pod のログは下記コマンドで確認できる

kubectl logs -p {pod name} -n {namespace}
sakaNasakaNa

Namespace の作成

クラスタ内のリソースを論理的に分割するための仕組みである Namespace を作成する。
複数のチーム・プロジェクトにまたがる多くのユーザーがいる環境で、クラスタを分けて管理運用した場合に使われる仕組みであり、小規模プロジェクトでは不要っぽい
https://kubernetes.io/ja/docs/concepts/overview/working-with-objects/namespaces/

Namespace の作成

下記コマンドで作成できる。(もちろんマニフェストでも作成可能)

$ kubectl create namespace sample
namespace/sample create

作成した Namespace を確認すると、さきほど作成した sample があるのがわかる

$ kubectl get namespace
NAME                   STATUS   AGE
default                Active   21h
kube-node-lease        Active   21h
kube-public            Active   21h
kube-system            Active   21h
kubernetes-dashboard   Active   19h
sample                 Active   66s

Namesapce ごとにリソース作成

Namespace ごとにマニフェストを適用させることができる。-n {namespace}で指定
(マニフェストに適用させる Namespace を指定しておくこともできる -> 通常こっちの方法)

$ kubectl apply -f deployment.yaml,service.yaml -n sample
deployment.apps/nginx-deployment created
service/nginx-service created

論理的に分割されており、default の Namespace からは作成した Pod を確認できない

$ kubectl get pod   
No resources found in default namespace.

Namespace を指定してあげると見れる

$ kubectl get pod -n sample
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-57c68fcd95-8mzgl   1/1     Running   0          22s
nginx-deployment-57c68fcd95-dmkp5   1/1     Running   0          22s
nginx-deployment-57c68fcd95-xfhq2   1/1     Running   0          22s

Namespace を導入した場合のイメージは下記である

sakaNasakaNa

k8s 特有の用語が多数出てくるのでとっつきにくかったが、実際に操作しながら試すことで、基本知識はイメージ込みで習得できたと思う。(イメージ図を書き出したのが良かった気がする)

業務で使うのは k8s 自体の構築ではなく、各アプリケーション Client 側ってパターンはよくあると思うが、最低限ここの知識はもって置くのがよいと思う。

このスクラップは2023/06/11にクローズされました