このブログを検索

この記事の内容は、個人の見解、検証の範囲のものであり、誤りがある可能性があります。
個人の責任において情報活用をお願いします。


ラベル Kubernetes(k8s) の投稿を表示しています。 すべての投稿を表示
ラベル Kubernetes(k8s) の投稿を表示しています。 すべての投稿を表示

2023年6月30日金曜日

Rancharでkubernetesの管理をしてみる 第3回 デフォルトで作成したユーザーは思っていた以上にできることが少なかった・・・

今回は、前回作成したデフォルト設定のユーザーが管理者権限と比べてどんなことが制限されているのか見ていきたいと思います。
まずログインしてみると、メンバー追加したクラスターだけが確認できます。
では、このクラスターへ実行可能な操作を確認してみましょう。


とはいえ、この辺の操作は問題なくできると思っています。
kubectlshellでコマンドが実行できることは確認できました。


新しく名前空間を作成し、ローカルのYAMLファイルを読み込ませてPodやServiceを作成してみましょう。


あ、名前空間作るための権限ついてないっぽいw
うーん、defaultの名前空間だったらリソースは作れるのか・・・?
『Import YAML』ボタンからYAMLファイルを読み込ませてみましょう


『Read from File』から読み込ませるYAMLファイルを選びます。


内容が表示されたら『Import』で・・・えぇ・・・


あー、ダメなんですね・・・
なるほど、デフォルト状態では操作はできないみたいですね。
defaultの名前空間でも、このユーザーは作成しようとしたリソースの操作を許可されてないと怒られてしまったようです。 ユーザー作ったり権限与えたりとかその辺ができないとイメージしていましたが、考えが甘かったようです。


せっかくなので、ほかにもできないことを調べたいと思います。
メニュー画面からやはりユーザーに対する管理、クラスタに対しての管理もできないようです。


この辺はイメージ通りではありました。
ちょっと思った通りではなくて思いのほかショックを受けてしまいましたが、よい確認ができたと思っておきます。

次回は、どうやったら今回できなかったPodの作成などができるのかについて調べてみたいと思います。

2023年5月26日金曜日

Rancharでkubernetesの管理をしてみる 第2回 ユーザーの作成とクラスタメンバーへの追加

前回、Rancharを構築してKubernetesを管理下に置いてみました。
今回は、作業用のユーザーをデフォルトの設定で作成してクラスタが操作できるようにクラスタのメンバーに追加する作業を行ってみます。

まずは、ユーザーの作成を行います。
「CONFIGURATION」から「Users&Authentication」を選択します
「Create」からユーザーの作成を行います。
作成自体はユーザー名を入れて、パスワードを設定し「Create」をするだけで可能です。
今回は使用しませんでしたが、チェックボックスで次回ログイン時にパスワードを変更させたり、ランダムでパスワードを生成したりもできるようですね。
細かい権限設定もできるようですが、それはまた今度調べたいと思います。
今回は「user01」を作成してみます。
作成したuser01で再ログインしてみます。
作っただけではログインしても以下のように何も操作できない状態となります。
では、このユーザーにアクセスを行わせるクラスタへ権限の付与を行いましょう。
adminでログインしなおします。
ユーザーに操作させたいKubernetesクラスタをクリックします。
「Cluster Members」を表示し「Add」をクリックします。
「Select Member」で追加したいユーザー検索して設定します。
今回は先ほど作成した「user01」になります。
user01がクラスタのメンバーとして追加されました。
この状態で改めてログインすると、先ほど権限をくっつけたk8s-1クラスタが表示されました。
今回はここまでにします。
次回は、管理者権限と比べてどんなことが制限されているのか見ていきたいと思います。

2023年4月28日金曜日

Rancharでkubernetesの管理をしてみる 第1回 『Rancharの構築とkubernetesの追加』

kubernetesでいろいろと構築することを過去にやってきましたので、今回からは管理系のお勉強をしたいと思います。
早速導入ですが、これはDockerのコマンド一発でできてしまいました。
世の中便利になりましたね・・・

公式ドキュメント:https://www.rancher.co.jp/quick-start/

ただ、それを知っているかどうかとそれを見つけられるかどうかなど、いろいろなものがありすぎて複雑だなぁと感じる私は地球の重力に魂を引かれているのでしょう。
Dockerの入っているマシンを用意したら以下のコマンドを実行して下さい。
このあとkubernetesのクラスタを追加するので、各ノードと通信できるマシンという点だけ注意してください。
# docker run -d --restart=unless-stopped -p 80:80 -p 443:443 --privileged rancher/rancher
これだけで作業完了です。
コンテナ起動時にホストへのhttps通信をコンテナに転送するように設定されているので、ブラウザでアクセス可能ですがそのままだとパスワードがわからないので確認しておきましょう。

パスワードの確認はコンテナのlogから確認するので、コンテナのIDを確認します。
# sudo docker ps
CONTAINER ID   IMAGE             COMMAND           CREATED          STATUS          PORTS                                                                      NAMES
977d197a93b5   rancher/rancher   "entrypoint.sh"   41 seconds ago   Up 35 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp   frosty_meninsky
この「CONTAINER ID」を使ってログを表示するとその中にパスワードが入っているので以下のコマンドでそれを抽出します。
# docker logs 977d197a93b5 2>&1 | grep "Bootstrap Passwor ログイン後は、パスワードの再設定を行います。
12文字以上という結構長いパスワード要求でちょっと困りました(個人的にはNSX以外で初めてでしたね。)

ログインすると画面はこんな感じです。
ここからkubernetesの構築を行うこともできるようなのですが、既存のkubernetesをこのRancharに追加してみたいと思います。
クラスターのページから、『Inport Existing』を実行します。
『Import any Kubernetes cluster』の『Generic』をクリックします。
登録するクラスタの名前を設定します。
ここでは k8s-1 と設定しました『Create』をクリックします。
そうすると、クラスターの追加を行う Kubectl のコマンドが表示されます。
証明書の問題が発生した場合は2つ目のコマンドを使うように案内されるため、そちらを使いましょう
実際に実行してみると、以下のものが作られます。
clusterrole.rbac.authorization.k8s.io/proxy-clusterrole-kubeapiserver created
clusterrolebinding.rbac.authorization.k8s.io/proxy-role-binding-kubernetes-master created
namespace/cattle-system created
serviceaccount/cattle created
clusterrolebinding.rbac.authorization.k8s.io/cattle-admin-binding created
secret/cattle-credentials-7e1f7cb created
clusterrole.rbac.authorization.k8s.io/cattle-admin created
Warning: spec.template.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[0].key: beta.kubernetes.io/os is deprecated since v1.14; use "kubernetes.io/os" instead
deployment.apps/cattle-cluster-agent created
正常に展開できた場合はしばらくして、RancherのUIに戻ると『Active』と追加スタクラスターで表示されます。
Rancherのホームを表示すると、クラスターの右端のボタンからなんとkubectlを実行可能なshellが起動可能です。

先ほどクラスターを追加した際に作成された名前空間『cattle-system』にあるpodを確認してみましょう。
こんな感じで複数k8sクラスターがあってもここからk8sの切り替えてkubectlコマンドが実行できるので楽でいいですね。

2022年2月25日金曜日

俺とkubernetesと時々vSphere -DeploimentとStatefulsetについて-

このブログは、コンテナのオーケストレーターであるkubernetesについて

自分の知識をまとめることを目的として記事を書いています。

もともとなが~くvSphereのあれやこれやに携わってきたのでvSphereとの類似点や

相違点についてもちょっと混ぜていけたりしたらいいかなぁとかも思っています。


今回は、Podの展開を行う方法である『Deploiment』と『Statefulset』という

リソースの違いについてご説明したいと思います。


Deploiment


 Deploimentは、展開するPodの数を決めて一度に複数のPodを展開することができます。

 vSphereで考えると、一つのテンプレートから複数の仮想マシンをグループとして

 一度に作成するようなイメージでしょうか。


 ただ、PVCを利用した場合、すべてのPodで同じ領域を使用するため個別にデータを

 残しておきたいようなアプリケーションには不向きとなります。


 ただ単にプリケーションを実行したいとか、Webサーバーにしておきたいとかそう

 いった用途のPodはこの方式でよく作られていると思います。

 ※仮に残しておきたいデータがあった場合は、定期的に外部にデータを保存する仕組み

  を持たせていると思います。


Statefulset


 Statefulsetも、展開するPodの数を決めて一度に複数のPodを展開することができます。

 Deploimentとの違いは、こちらはPVCを使用することでPod毎にデータ絵領域を持たせる

 ことができる点です。


 データベースなど、個別に情報を残しておく必要があるPod用の展開方式となります。


大きな違いは上記となります。

また、単体のPodではなく、DeploimentやStatefulsetとして展開することで、得られる

以下の様なメリットもあります。


 ・必要展開数の保持

  展開したPodに何かしら問題が発生して正常に動いているPodの数が設定したPodの数に

  足りなくなった場合、自動的にPodを展開して正常に稼働しているPodの数を保ちます。 

  

 ・Podの展開数調整が容易(スケールアウト、スケールイン)

  yamlに記載するPod展開数を変更し、再度kubectl applyすることで数を増やしたり

  減らしたりがすぐにできます。


 ・ローリングアップデート

  yamlファイルに変更があって更新されたことを感知すると、新しいyamlファイルで

  展開したPodと入れ替えてくれる機能。

  1台づつ入れ替えてくれるので、提供しているサービスは停止しない優れもの。


     どうやって、ローリングアップデートしているかというと。

   

  実はDeploimentもStatefulsetも内部にPodの展開をするReplicaSetというリソース

  を持っていたりします。

  それをうまく使っているということになりますが、ここでは、仮にDeploimentか

  Statefulsetで現在動いているPodたちがあったとして説明したいと思います。

    

  yamlファイルに変更が起きると、新しいyamlファイルでReplicaSetがPodを作ります。

  実は、複数のReplicaSetを管理する機能をDeploimentもStatefulset持っているので、

  古いReplicaSetと新しいReplicaSetが同時に存在しているのです。


  新しいyamlファイルでの展開が終わると、現在メインとなっている古いReplicaSetの

  Podと新しいReplicaSetのPodを1台入れ替えてくれます。

     この動作を必要なPod台数分実施することで、提供しているサービスを止めることなく

  Podアップデートを行えるようにしているわけです。


次回は実際にStatefulsetを展開とローリングアップデートを確認してみたいと思います。

2022年1月31日月曜日

俺とkubernetesと時々vSphere -動的PVCの利用について その2-

このブログは、コンテナのオーケストレーターであるkubernetesについて

自分の知識をまとめることを目的として記事を書いています。

もともとなが~くvSphereのあれやこれやに携わってきたのでvSphereとの類似点や

相違点についてもちょっと混ぜていけたりしたらいいかなぁとかも思っています。


今回はPodのストレージ周りのお話の続きとなります。

Podがデータを保存するために追加するPod用の外部ストレージ、PersistentVolumeを自動的に作ってくれる動的PVCの導入です。


今回は、nfs-clientを導入しNFSで動的PVCを使えるようにします。

そのため、ノードとなっているOSに/NFSという領域を作って、そこにCentOSで作成したNFSサーバーをくっ付けて使います。

気を付けていただきたいのは、Kubernetesクラスタはマスターとワーカーのノードがあり、Podはワーカーで動くのでワーカーとなっているサーバーにNFSをマウントしておかないとPodがNFSの領域を使えません。


うっかりマスターにだけ追加して、あれ? PV作られないじゃん??? とならないようご注意ください。(n敗

では、すべてのノードにNFSがマウントされている状態を前提として、nfs-clientの導入手順を紹介したいと思います


nfs-clientの導入方法はいくつか方法がありますが、簡単なのでhelmを使って導入したいと思います。

helmは、Kubernetes用のyamlみたいなものです。

これを使うと、Kubernetes上にアプリケーションのPodを展開してくれます。


作業自体は、マスターノードで行います。

まず、helmを使えるようにします。

  curl -O https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3

  ls

  bash ./get-helm-3


nfs-clientを導入するためhelmのレポジトリ追加

  helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/


nfs-clientインストール

  helm install nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \

  --set nfs.server=192.168.0.5 \

  --set nfs.path=/nfs


        nfs.server → NFSサーバーのIPアドレス

        nfs.path → NFSサーバー側で共有しているディレクトリ


※なんかうまくいかなくてアンインストールする場合は以下

  helm uninstall nfs-subdir-external-provisioner


何ができたかの確認

  # kubectl get pod

  NAME                                              READY   STATUS    RESTARTS   AGE

  nfs-subdir-external-provisioner-59479459d5-qbbdv   1/1     Running   0          22h


  # kubectl get sc

  NAME         PROVISIONER                                     RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE

  nfs-client   cluster.local/nfs-subdir-external-provisioner   Delete          Immediate           true                   5m43s


nfs-subdir-external-provisionerのPodとStorageClassが作成されます。

このnfs-clientという名前で作られたStorageClassを指定してPVCを作成すると自動でPVを作ってくれるというわけです。


実際にやってみましょう!

こんな感じでyamlを用意します。


確認用のPVC作成例

 pvc.yaml

  ----

  apiVersion: v1

  kind: PersistentVolumeClaim

  metadata:

    name: my-provisioner

    annotations:

      # ここでStorageClass の名称を指定

      volume.beta.kubernetes.io/storage-class: nfs-client

  spec:

    accessModes:

      - ReadWriteOnce

    resources:

      requests:

        # ここでリクエストするボリュームサイズを決定

        storage: 5Gi

  ----


PVCの作成

  # kubectl apply -f pvc.yaml


作成したPVCを確認する

  # kubectl get pvc

  NAME             STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE

  my-provisioner   Bound    pvc-4b8ca59d-28cf-4f2d-a078-e8392bde5a81   5Gi        RWO            nfs-client     36s


PVCを作成すると、NFS側に以下の命名規則でディレクトリが作成される。


   ${namespace}-${pvcName}-${pvName}


   ※ここの例では以下のディレクトリがNFSサーバー側にできる


     default-my-provisioner-pvc-4b8ca59d-28cf-4f2d-a078-e8392bde5a81


当然PVも自動で作成される。

  # kubectl get pv

  NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                    STORAGECLASS   REASON   AGE

  pvc-4b8ca59d-28cf-4f2d-a078-e8392bde5a81   5Gi        RWO            Delete           Bound    default/my-provisioner   nfs-client              46s             15s



このPVCを要求するPodを作成する


確認用のPVC作成例

  test-pod.yaml

  ----

  apiVersion: v1

  kind: Pod

  metadata:

    name: my-mginx

  spec:

    containers:

      - name: my-mginx

        image: nginx

        ports:

          - containerPort: 80

            name: web

        volumeMounts:

        - mountPath: /usr/share/nginx/html  #インデックス用ファイルを後で置いて確認する予定

          name: nginx-pvc

    volumes:

      - name: nginx-pvc

        persistentVolumeClaim:

          claimName: my-provisioner # 作成した PVC 名

  ----


Podの作成

  # kubectl apply -f test-pod.yaml


作成したPodはnginxなのでアクセスして状態を確認するため、IPアドレスを確認する。

  # kubectl get pod -o wide

  NAME                                              READY   STATUS    RESTARTS   AGE     IP             NODE                      NOMINATED NODE   READINESS GATES

  my-mginx                                           1/1     Running   0          38s   10.244.2.5   snt-k8s-node2.snt.local   <none>           <none>

  nfs-subdir-external-provisioner-59479459d5-qbbdv   1/1     Running   0          13m   10.244.1.4   snt-k8s-node1.snt.local   <none>           <none>


確認できたIPアドレスにcurlでアクセスすると、以下の表示になる。


  # curl 10.244.2.5

  <html>

  <head><title>403 Forbidden</title></head>

  <body>

  <center><h1>403 Forbidden</h1></center>

  <hr><center>nginx/1.21.6</center>

  </body>

  </html>


NFSサーバー側にできたディレクトリ(PV)にインデックスファイルを置いて表示される内容が期待した通りになるか確認。


  まず、PVの領域に移動 # cd /mnt/default-my-provisioner-pvc-4b8ca59d-28cf-4f2d-a078-e8392bde5a81/


  ファイルはこのコマンドで作成 # echo "nfs-clint TEST" > index.html


  ファイルができてるか確認 # ls


再びcurlでアクセスし、nfs-clint TEST が表示されることを確認。

  # curl 10.244.2.5

  nfs-clint TEST


自動でPVCからPVが作られ、その領域にPodからちゃんとアクセスできていることが確認できた。

ということで、nfs-clientを導入し動的PVCが使えるようになりました。

これがあるとステートフルセットというPodの作り方ができるので、現在一般的なpodの作り方である

デプロイメントと合わせてそれぞれのPodの作り方と違いを解説したいと思います。

2021年12月31日金曜日

俺とkubernetesと時々vSphere -動的PVCの利用について その1-

このブログは、コンテナのオーケストレーターであるkubernetesについて

自分の知識をまとめることを目的として記事を書いています。

もともとなが~くvSphereのあれやこれやに携わってきたのでvSphereとの類似点や

相違点についてもちょっと混ぜていけたりしたらいいかなぁとかも思っています。


今回はPodのストレージ周りのお話となります。

Podは停止=削除となりますので、Podが停止するとPodがなくなります。

当然Podの中に蓄えられていたデータも消えてなくなります。


データベース等のPodを停止するたびに情報がなくなってしまっては困ります。

そこで、永続ボリュームというPod外部にPod用のデータ保存領域を作成してデータを

保存しようという仕組みがあります。

Strageclass(SC)、PersistentVolume(PV)、PersistentVolumeClaim(PVC)ですね。


SCは一度定義してしまえばそうそう作り直し等の作業はないと思いますが、

PVとPVCは利用するPod毎に用意する必要があり、毎度毎度必要なサイズのPVを作って

それを要求するPVCを作ってとやっていると手間ですし、PVの数が増えると管理も大変です。


そこで、PVCで要求する内容のPVを自動で作成するというのが動的PVCと呼ばれるものです。

動的PVCが使えるかどうかは、SCでその機能が使えるかどうかとなります。

SCの機能を決めているのは、プロビジョナーと呼ばれるプラグインです。


■プロビジョナー一覧はこちら

 https://kubernetes.io/docs/concepts/storage/storage-classes/


プロビジョナーの一覧を見ると、基本的にはマネージドKubernetes毎に提供されている

プロビジョナーを使ってくださいねとなっています。

そのため、手動で構築したKubernetesでは機能として動的PVCは備えてはいません。


と、いうことでどうやったらこの機能を手動で構築したお手製Kubernetesに組み込んでいくのか

というお話です。


じつはKubernetesノードに接続したNFSサーバーを使用して動的PVCが利用可能なSCを作成可能

にしてくれる「nfs-cient」というものがあります。

こちらの導入は意外と簡単に行えますので、次回の記事でやっていきたいと思います。


2021年11月26日金曜日

俺とkubernetesと時々vSphere -ServiceのLoadBalancerタイプその2-

 このブログは、コンテナのオーケストレーターであるkubernetesについて

自分の知識をまとめることを目的として記事を書いています。

もともとなが~くvSphereのあれやこれやに携わってきたのでvSphereとの類似点や

相違点についてもちょっと混ぜていけたりしたらいいかなぁとかも思っています。


前回、ServiceのタイプLoadBalancerは手動で作っただけのkubernetesでは使えないこと、

このServiceと連携してくれるLoadBalancerが必要となってしまうことをお話ししました。


今回ですが、kubernetesの外にあるLoadBalancerと連携するのではなく、kubernetes上に

LoadBalancerを用意して、ServiceのタイプLoadBalancerを動かしてしまえるMetalLBを

導入してみたいと思います。


MetalLBの公式はこちら

https://metallb.universe.tf/


公式に案内されていることをやれば動いてくれます。

早速作ってみましょう。


まず、MetalLBで払い出してもらうIPアドレスのレンジを決めます。

今回は192.168.0.200-192.168.0.210としました。

以下が設定となるConfigMapのyaml内容です。

configmap.yml

----

apiVersion: v1

kind: ConfigMap

metadata:

  namespace: metallb-system

  name: config

data:

  config: |

    address-pools:

    - name: default

      protocol: layer2

      addresses:

      - 192.168.0.200-192.168.0.210

----


インストールをしていきます。

MetalLB用のnamespaceを作成するyamlがあるので使用して作成します。

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.3/manifests/namespace.yaml


名前空間ができているはずなので、kubectl get nsで名前空間を確認してみます。

NAME              STATUS   AGE

----

default           Active   37d

kube-node-lease   Active   37d

kube-public       Active   37d

kube-system       Active   37d

metallb-system    Active   53s ※新しく作成された名前空間

----


MetalLBを作成します。

kubectl apply -f  https://raw.githubusercontent.com/metallb/metallb/v0.9.3/manifests/metallb.yaml

kubectl apply -f configmap.yml

kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)"


これでMetalLBが作成されています。

先ほど作成した名前空間「metallb-system」を指定してPodを見てみると


kubectl get pod,svc -n metallb-system

NAME                            READY   STATUS    RESTARTS   AGE

pod/controller-fb659dc8-nf5xp   1/1     Running   0          9m34s

pod/speaker-5km2t               1/1     Running   0          9m34s

pod/speaker-7gkzv               1/1     Running   0          9m34s

pod/speaker-gbx4d               1/1     Running   0          9m34s


このようにMetalLB用のPodが作成されているのがわかります。

それでは、ServiceのタイプLoadBarancerを作成して、外部アクセス用のIPアドレスが割り当てられるか見てみましよう。

前回使用したServiceを作成するのですが、確認用のPodも作成しようと思います。

今までの流れだと2個のyamlを使用していましたが、実はyamlは「---」を使用して一つにまとめることができます。

具体的には以下のような形となります。


pod.yaml

---

kind: Pod

apiVersion: v1

metadata:

  name: test-pod

  labels:

    site: test

spec:

  containers:

  - image: nginx

    name: nginx-container

---

kind: Service

apiVersion: v1

metadata:

  name: test-svc-1

  labels:

    app: test

    site: test

spec:

  type: LoadBalancer

  ports:

  - port: 80

    protocol: TCP

    targetPort: 80

  selector:

    site: test

---


ではこちらのファイルを元に作成を行ってみましょう。


kubectl apply -f pod.yaml

pod/test-pod created

service/test-svc-1 created


このように、PodとServiceが作成されていることがわかります。

MetalLBのyamlを使用して導入した際にも同じように複数のリソースを作成した出力結果

が出てきたと思いますが、あちらで使用したyamlファイルにも同様に複数のリソースを

1つのyamlにまとめていたからということです。


では、PodとServiceの状態を見てみましょう

kubectl get pod,svc

NAME           READY   STATUS    RESTARTS   AGE

pod/test-pod   1/1     Running   0          61s


NAME                 TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE

service/kubernetes   ClusterIP      10.96.0.1       <none>          443/TCP        37d

service/test-svc-1   LoadBalancer   10.100.102.86   192.168.0.200   80:32383/TCP   61s


どうでしょう、作成したService「test-svc-1」にEXTERNAL-IPが割り当てられていると思います。

ここでは、tcp:80番で192.168.0.200にアクセスした場合にPodに転送されるようになっているはずです。

実際に通信可能な作業PCなどからブラウザでhttpでの通信をしてみてください。

nginxのデフォルトページが表示されると思います。


無事、ServiceタイプLoadBalancerが利用可能になりました。

これにより、IngressによるL7通信制御などもnginxのコントローラーを導入するとことで利用が

可能となり、やれることの範囲が広がっていきます。


ここで、タイトルにある時々vSphereのvSphere部分を無理やり書いてみると、vSphereのTanzuでは

この部分はNSX、HAproxy、Aviのどれかを選んで構築することになる部分となります。

VCとESXiだけではロードバランサーの役割はさすがに果たせないので仕方ない部分だと思いますが、

その分構築が複雑なのとライセンスでお金かかっちゃうのがネックですね・・・


今回は以上となります。

次回は永続ボリュームに関する『そのままだとできないこと』について書きたいと思います。

2021年10月29日金曜日

俺とkubernetesと時々vSphere -ServiceのLoadBalancerタイプ-

このブログは、コンテナのオーケストレーターであるkubernetesについて

自分の知識をまとめることを目的として記事を書いています。

もともとなが~くvSphereのあれやこれやに携わってきたのでvSphereとの類似点や

相違点についてもちょっと混ぜていけたりしたらいいかなぁとかも思っています。


前回までで、Kubernetesの構築、Pod、Service、永続ボリュームの利用を説明しました。

vSphereでいうところの、ESXiをインストールしてVCを構築して統合管理を行い、ストレージ

の設定してデータストアを作成し、仮想マシンを作って起動したというところですね。


基本的なことはできるようになっていますが、自分で作ったkubernetesの場合は便利な機能が

使えない状態になっています。


例えば、ServiceにはLoadBalancerというタイプのものがあります。

これを作成してみましょう。

以下のyamlを用意し、kubectl apply -f を実行します。

---

kind: Service

apiVersion: v1

metadata:

  name: test-svc-1

  labels:

    app: test

    site: test

spec:

  type: LoadBalancer

  ports:

  - port: 80

    protocol: TCP

    targetPort: 80

  selector:

    site: test

---


無事作成できたように見えますが、状態を見てみると以下の様にいつまでもEXTERNAL-IPが<pending>のままです。


kubectl get svc

NAME         TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE

kubernetes   ClusterIP      10.96.0.1        <none>        443/TCP        27h

test-svc-1   LoadBalancer   10.107.138.238   <pending>     80:31352/TCP   7s


当然外部からアクセスするIPアドレスがないので通信ができません。

このように、手動作成のKubernetesには一部機能が備わっていなくてそのままだと使えないものがあるという状態です。


今回例として挙げた、ServiceのLoadBalancerタイプですが、以下の様な動作でユーザーからのアクセスをさばいてくれます。

                                    

<ユーザー>

  →<Service:LoadBalancer>

   →<Kubernetesクラスタノードのどれか>

    →<Serviceと紐ついているPodのどれか>


つまり、ユーザーとKubernetesクラスタの間にLoadBalancerが入って、ユーザーからのアクセスをNodePortdで待ち構えるKubernetesクラスタのノードどれかに渡します。

ユーザーはLoadBalancerのIPにアクセスすればいいわけですから、KubernetesクラスタのノードのIPアドレスが変わっても特に意識することがなくなります。


勘のいい方は、えっそれって・・・と思われたかもしれません。

そうです。Kubernetesクラスタの外部にLB立ってます。

なので、手動で構築したままのKubernetesクラスタでServiceのLoadBalancerを作成しても、連携してくれるLoadBalancerがいないので、EXTERNAL-IPが<pending>のままになってしまうのです。

しかし、それをどうにかやってくれるありがたい存在があります。

その名をMetalLB、来月はこのMetalLBをどのように導入してどのように使うのかについて解説したいと思います。


ちなみに、マネージドkubernetes(GCPやAWS等で提供されているKubernetes)は、ServiceのLoadBalancerが作成されると連携してLoadBalancerが展開されます。

この辺の管理も含めて便利になっているのがサービスとして提供されているKuberneteのいいところですね。

2021年9月30日木曜日

俺とkubernetesと時々vSphere -PodとServiceの作り方-

このブログは、コンテナのオーケストレーターであるkubernetesについて自分の知識をまとめることを目的として記事を書いています。

もともとなが~くvSphereのあれやこれやに携わってきたのでvSphereとの類似点や相違点についてもちょっと混ぜていけたりしたらいいかなぁとかも思っています。


今回は前回からの続きで、Podにストレージを追加するための作業をやっていきたいと思います。

今回はちょっと登場人物が多かったり、作業を行うための準備が必要だったりで少し難しいと思います。

文章だけだと難しいと思いますので、読み飛ばして実際にyamlから物を作成してもらったほうが早いかもしれません。


Podのストレージを永続ストレージと呼び、具体的にKubernetesではそれのことをPersistentVolumeと呼びます。

仮想マシンに置き換えると、仮想ディスクに当たる部分になります。

Pod同様PersistentVolumeもyamlで作るのですが、PersistentVolume(PV)を作っていい領域がどこかそれが定義されていないと作れません。

何のことかちょっとよくわからないかもしれませんが、vSphere的に言うと仮想ディスクを作成するためのデータストアを用意しないといけないという感じです。

では、そのデータストアをどう作るかというと、StorageClass(SC)というリソースを作成してKubernetesに「この領域が使えますよ」と定義するわけです。

これで、SCで定義された領域にPVを作ることができました。

しかし、この状態は、仮想ディスクはできたけど仮想ディスクを使うのは誰かという部分が設定されていません。

その設定を行えるようにするのがPersistentVolumeClaim(PVC)です。

PVCはPVを要求するためのリソースで、どんなサイズのPVが欲しいかという内容が定義されています。

このPVCをPodのyamlに書いてあげると、PVCに要求されたサイズのPVがPodと紐づくことができます。

これは文章で読んでもあんまり理解できないと思いますので、気にせず実際に作ってみましょう。


まずはStorageClassから。

ここでは、NFSやiSCSIなどの外部ストレージ装置ではなく、ローカル領域を指定します。

以下の内容をKubernetesクラスターにvi等で作成してください。


  local-sc.yaml

  ----

  kind: StorageClass

  apiVersion: storage.k8s.io/v1

  metadata:

    name: local-sc

  provisioner: kubernetes.io/no-provisioner

  ----


続いて、作成したStorageClassであるlocal-scを指定してPersistentVolumeを作成。

以下の内容をKubernetesクラスターにvi等で作成してください。


  local-pv.yaml

  ----

  apiVersion: v1

  kind: PersistentVolume

  metadata:

    name: local-pv

  spec:

    capacity:

      storage: 3Gi

    volumeMode: Filesystem

    accessModes:

      - ReadWriteOnce

    persistentVolumeReclaimPolicy: Delete

    storageClassName: local-sc

    hostPath:

      path: /local-pv/

  ----


さらに、用意したPersistentVolumeを要求するPersistentVolumeClaimを作成します。

以下の内容をKubernetesクラスターにvi等で作成してください。


  local-pvc.yaml

  ----

  apiVersion: v1

  kind: PersistentVolumeClaim

  metadata:

    name: local-pvc

  spec:

    accessModes:

    - ReadWriteOnce

    volumeMode: Filesystem

    resources:

      requests:

        storage: 3Gi

    storageClassName: local-sc

  ----


それでは順番に、作成を行いましょう


  kubectl apply -f local-sc.yaml

  kubectl apply -f local-pv.yaml

  kubectl apply -f local-pvc.yaml


確認は以下のコマンドで


  kubectl get sc,pv,pvc


出力結果はこんな感じ


  NAME                                                   PROVISIONER                                     RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE

  storageclass.storage.k8s.io/local-storage              kubernetes.io/no-provisioner                    Delete          Immediate           false                  82s 

  

  NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                    STORAGECLASS   REASON   AGE

  persistentvolume/local-pv                                   3Gi        RWO            Delete           Bound    default/local-pvc        local-sc                18s

  

  NAME                                   STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS               AGE

  persistentvolumeclaim/local-pvc        Bound     local-pv                                   3Gi        RWO            local-sc                   3s


と、ここまでで仮想マシンで言うと仮想ディスクができたわけです。

しかしこのままでは、この仮想ディスクを使う仮想マシンが誰かという設定がされていません。

そこでもう一つyamlが必要となります。


どんなyamlが必要となるかというと、Podのyamlです。

Podのymalにこのpvcを組み込むことで、PodがようやくPVCを使えるようになります。

前回作ったnginxのPodにくっ付けて新しいPodのyamlファイルを作ってみましょう


  nginx-pv.yaml

  ----

  kind: Pod

  apiVersion: v1

  metadata:

    name: nginx-pod-2

    labels:

      app: wcp-demo

  spec:

    containers:

    - image: nginx

      name: nginx-container

      volumeMounts:

      - name: nginx-pv

        mountPath: /pv

    volumes:

    - name: nginx-pv

      persistentVolumeClaim: 

        claimName: local-pvc

  ----


これを作成するとPodが付いています。


  kubectl apply -f nginx-pv.yaml


しかし、実際にPVはどこにできているかというと、Podが動いているnodeの/local-pv/になります。

確認するには"kubectl get pod -o wide"を実行するとわかります。


Podにくっ付けられたPVは本当にくっついているか確認します。

Podの内部に入って/pvディレクトリがあるか確認しましょう。


  kubectl exec -i -t pod/nginx-pod-2 /bin/bash


  cd /pv


ディレクトリ/pvに移動することができました。

ダミーファイルを作成してみましょう。


  dd if=/dev/zero of=2G.dummy bs=1M count=2048


ファイルができたら、exitでPodから抜けます。

Podが動作しているノードへログインして、/local-pv/にファイルがあることを確認してください。


では、以下のコマンドでPodを削除してみましょう。


  kubectl delete -f nginx-pv.yaml


PVをくっ付けていないPodの場合、先ほど作成したダミーファイルも一緒に消えます。

もう一度同じyamlでPodを作成しなおしてみましょう。


  kubectl apply -f nginx-pv.yaml


Podにログインしてlsで/pvを確認するとダミーファイルが残っていることが確認できるはずです。


今回はここまでとなります。

2021年8月31日火曜日

俺とkubernetesと時々vSphere -作ってみよう、PodとService-

このブログは、コンテナのオーケストレーターであるkubernetesについて

自分の知識をまとめることを目的として記事を書いています。

もともとなが~くvSphereのあれやこれやに携わってきたのでvSphereとの類似点や相違点についてもちょっと混ぜていけたりしたらいいかなぁとかも思っています。


今回は前回説明した、Pod、Service、Podへ外部ストレージ領域の追加を実際にどうやったらいいのかという説明をしたいと思います。

まずはPodとServiceについて解説します。


Kubernetesクラスタ内部で何かを作成するとき、コマンドラインでの作成も一応できるのですが基本はymalファイルというものを使います。

yamlファイルとはなにかというと、これから作りたいものの設計図です。


yamlには大きく分けて4つのセクションがあり、それぞれ以下のような役割を持ちます。


  apiVersion:リソース作成時に使用するAPIのバージョンの設定

  kind:どの種類のリソース(Pod、Service等)を作成するかの設定

  metadata:リソースを一意にするための設定(名前、namespace、UID等が該当)

  spec:リソースの状態を設定(Podなら開放するportやCPU、メモリのサイズ等)


実際のPod、Serviceのyamlの例を見てみましょう。

Pod用ymalファイルの例

==========

---

kind: Pod

apiVersion: v1

metadata:

  name: nginx-pod

  labels:

    app: wcp-demo

spec:

  containers:

  - image: nginx

    name: nginx-container

==========

Kind → Podを作成するのでPodを記載

apiVersion → Podが所属しているAPIがv1であるため、v1を記載

metadata → nameには一意となる名前を設定、labelsにはPodに付与するラベル(app: wcp-demo)を設定

spec → containersはコンテナに関する設定を行うフィールド

        imageで作成するコンテナのイメージを指定、nameにはコンテナの名前を設定


Service用ymalファイルの例

==========

---

kind: Service

apiVersion: v1

metadata:

  name: nginx-svc

spec:

  type: NodePort

  ports:

  - port: 80

    protocol: TCP

    targetPort: 80

  selector:

    app: wcp-demo


Kind → Serviceを作成するのでServiceを記載

apiVersion → Serviceが所属しているAPIがv1であるため、v1を記載

metadata → nameには一意となる名前を設定

spec → typeで作成するServiceのタイプを設定

           ※ここでは、クラスタのノード全てでアクセスを受け取れるNodePortを指定

        portsはポートに関する設定を行うフィールド

        portはportからtargetPortへのマッピングを行います。利便性のため基本的にはtargetPortと同じ値を入れます。

        protocolは使用する通信のプロトコルを指定

        targetPortはコンテナに転送するportを指定

        selectorは一致するラベルを持ったPodを探し転送先として認識します。

==========


このようなyamlを用意するわけですが、どのようにこのファイルからPodやServiceを作成するのかというと

以下のコマンドを使用します。


  kubectl apply -f <yamlファイルまでのパス>


ここではAdministratorのデスクトップに配置したyamlを使用して実行した例を紹介します。


■Podの作成

  PS C:\Users\Administrator> kubectl apply -f "C:\Users\Administrator\Desktop\nginx-pod.yml"

  pod/nginx-pod created


■Serviceの作成

  PS C:\Users\Administrator> kubectl apply -f "C:\Users\Administrator\Desktop\nginx-pod-svc.yml"

  service/nginx-svc created


作成したPodとServiceはkubectl get <確認したいリソース> で確認可能です。

複数のリソースを確認したい場合は、「,」で区切ります。


■Podの確認

  kubectl get pod

  NAME        READY   STATUS    RESTARTS   AGE

  nginx-pod   1/1     Running   0          14m


■Serviceの確認

  kubectl get service

  NAME        TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)        AGE

  service/nginx-svc    NodePort    10.108.236.173   <none>        80:32074/TCP   4s


■PodとService両方確認

  kubectl get pod,svc

  NAME            READY   STATUS    RESTARTS   AGE

  nginx-pod       1/1     Running   0          14m


  NAME                 TYPE        CLUSTER-IP       EXTERNAL-IP     PORT(S)        AGE

  service/nginx-svc    NodePort    10.108.236.173   <none>          80:32074/TCP   4s


ここで、Serviceの PORT(S) に表示されている80:32074が<Podへ転送するport>:<ユーザーがアクセスするport>

となります。

<ユーザーがアクセスするport>は自動で付与されるため環境によって異なります。


ServiceのタイプがNodePortというKubernetesクラスタを構成しているノードの、どのIPアドレスどれでも

アクセス可能なServiceとなっているため、どれか一台のIPアドレスに<ユーザーがアクセスするport>を

くっつけてブラウザからhttpでアクセスしてみましょう。


  例

   http://192.168.0.100:32074


nginxのページが確認できたと思います。


今回はここまでとなります。

次回は、このpodを削除してもデータが残せるよう永続ボリュームをくっつくけるための内容を説明したいと思います。


2021年7月30日金曜日

俺とkubernetesと時々vSphere ーKubernetesで扱うことになるPod、Service、StrageClassやPersistentVolume、PersistentVolumeClaimってなんでしょう?ー

このブログは、コンテナのオーケストレーターであるkubernetesについて

自分の知識をまとめることを目的として記事を書いています。

もともとなが~くvSphereのあれやこれやに携わってきたのでvSphereとの類似点や相違点についてもちょっと混ぜていけたりしたらいいかなぁとかも思っています。

今回は前回構築したkubernetesクラスターに構築するPod(コンテナ)、Service(Podのネットワーク)、

Podのストレージ(Strageclass、PersistentVolume、PersistentVolumeClaim)についての説明をしたいと思います。


1.Pod

 Podは実際にアプリケーションが動作する場所(vSphereで言うと仮想マシン)となりますが、Kubernetes上で動くコンテナといったところです。

 Pod中には複数のコンテナを展開することもできますが、基本系は1Pod1コンテナですので、最初はPod=コンテナと思っても大丈夫だと思います。

  Pod単体でアプリケーションを起動することはできますが、外部との通信はできません。

 また、Pod内部にデータが保存されている場合Podを停止(Kubernetesの世界ではPodの停止=Podの削除)すると保存していたデータも一緒に消えてしまいます。

 その問題点を解消するのが以下の2つになります。


2.Service

 ServiceはPodとPodを接続したり、Podと外部の接続を行うPod用のネットワークです。

 Kubernetes内部でのみ使用する場合(外部とのやり取りが発生しない)や外部と通信する場合等の用途に合わせてタイプを指定することができますが、外部と通信を行う場合はどのように外部との中継を行うか種類が選べます。


   内部通信用のService

    ClusterIP


  外部通信用のService

   ExternalIP →任意のマスターorワーカーを指定して外部からPodへ通信を行う

   NodePort →Kubernetesクラスタ内のノードどれにアクセスしても外部からPodへ通信が可能

   Loadbarancer →外部ロードバランサが利用できるクラウドプロバイダ用ですが、ロードバランサーを自動で作成して連携してくれます。※そのため自分で作成したKubernetesクラスタだとそのままでは使えません。


3.Podのストレージ

 Pod内の動作によって出力されたデータなどを保存しておきたい場合、Pod外部にデータを保存する必要があり、具体的には以下の作業が必要です。


     Podで使えるストレージを定義(vSphereで言うとデータストアに近い)

   →定義されたストレージにPod用の領域を作成(vSphereで言うと仮想ディスクに近い)

    →Pod用のの領域をPodに紐付ける(しいて言えば、仮想マシンの設定と編集でディスクを手動追加するイメージ)


 この作業はKubernetes的な言い方をすると以下の様になります。


   StrageClass(SC)を作成する。

    →PersistentVolume(PV)を作成する。

    →PersistentVolumeClaim(PVC)を作成する。


これらをくっ付けて、Pod内のアプリケーションへ外部からアクセスしたり行わせた処理を保存したりできるようになるのですが、PodもServiceも作成しただけでは、お互いに紐ついてくれません。

これらをくっ付けるために必要なラベルとラベルセレクターという存在があります。

また、ストレージもそのままでPodと紐ついてくれません。

こちらも、yamlというPodやServiceを作る際に使用する設計書の様なものを利用する必要があります。


というわけで、次回はこれらの作り方やお互いが利用しあえるための設定、yamlの書き方について説明したいと思います。


2021年6月25日金曜日

俺とkubernetesと時々vSphere ー構築完了時点でのkubernetesクラスターの状態についてー

このブログは、コンテナのオーケストレーターであるkubernetesについて

自分の知識をまとめることを目的として記事を書いています。


もともとなが~くvSphereのあれやこれやに携わってきたのでvSphereとの類似点や相違点についても

ちょっと混ぜていけたりしたらいいかなぁとかも思っています。


今回は、前回構築したkubernetesクラスターはどのような状態になっていて、何ができるのかについて

解説していこうと思います。


まず、前回マスターノードとワーカーノードを作成しました。

マスターノードとワーカーノードには、kubernetesクラスターを構成するためのコンポーネントが配置

されています。


どのようなものが配置されているかというと以下となります。


[マスターノード側]

 ・kube-apiserver

 ・etcd

 ・kube-Controller-manager

 ・kube-scheduler

 ・kube-proxy


[ワーカーノード側]

 ・kubelet

 ・kube-proxy


kube-apiserver

 kubernetesクラスターには当然ユーザーからの処理(API)を受け付けて指示を出してくれる存在です。

 すべてのコンポーネントの中心となっていて、その他のコンポーネントへ指示を出したりします。

 vSphereでいうとvCenterのvpxdみたいなやつですね。

 

etcd

 kubernetesクラスターのデータベース担当です


kube-scheduler

 Podをどこのワーカーノードで起動するか割り当ててくれます


kube-Controller-manager

 レプリケーションコントローラー等、kubernetesクラスターに存在する複数のコントローラーの

 プロセスを実行します。


kube-proxy

 各ノード上で動作するネットワークプロキシ


kubelet

 kube-apiserverから指示を受けてワーカーノード上で処理を実施するエージェント。

 vSphereでいうところのhostdみたいなやつですねこれも


上記のコンポーネント達がやり取りをしてkubernetesクラスターを成り立たせているわけですが、

これは基本中の基本操作ができるための機能しかありません。


Pod(コンテナ)やService(ネットワーク)等を作成することはできますが、Pod用のストレージとなる

PersistentVolumeを要求に従って自動で割り当てたり、外部と通信する際にロードバランサータイプの

Serviceが利用できなかったりします。


有料のサービスとして利用可能なマネージドkubernetesであれば上記の内容も利用できますが、

できれば、無料で使ってどんなものか自分で確認してみたいですよね・・・

それぞれ以下を導入すれば利用が可能となります。

 ・MetalLB

 ・Kubernetes NFS-Client Provisioner


なお、kubernetesにPodやServiceを作る際GUI操作という物はなく、基本コマンドになります。

実際にコマンドラインだけで作成することも可能ですが、ymalファイルというテキストベースの

設計書を事前に作成して、そのファイルを指定してコマンドを実行するという感じですね。


というわけで、次回はyamlの書き方や実際にPodやServiceを作成してそれをどう確認するのか

について解説したいと思います。


2021年5月31日月曜日

俺とkubernetesと時々vSphere ーkubernetesクラスターってどう組むのよ?ー

 このブログは、コンテナのオーケストレーターであるkubernetesについて

自分の知識をまとめることを目的として記事を書いています。

もともとなが~くvSphereのあれやこれやに携わってきたのでvSphereとの類似点や相違点についてもちょっと混ぜていけたりしたらいいかなぁとかも思っています。


今回はkubernetesクラスターの構築についてやっていこうと思います。


まず準備ですが、ESXiやWindowsのようにkubernetesのインストールイメージというものがあるわけではありません。

LinuxOSを用意して、そこにあれやこれやと設定を行いkubernetes用のノードとしていくことになります。


kubernetesクラスターはざっくり言ってしまうと、システムの管理を担当する役割(マスターノード)、ユーザーが作成したPod(コンテナ)を動かす役割(ワーカーノード)の2種類があります。

マスターノードがコントロールプレーン、ワーカーノードがデータプレーンというとイメージが付きやすいでしょうか。


どちらも同じものを入れて構築していくのですが、最後にマスターノードとして構築するコマンドを実行するかマスターノードにワーカーノードとして追加するコマンドを実行するかだけが違います。


では、どういう手順になるかを説明していきましょう。


1.まずLinuxOS


    ここは、好きなLinux系のOSを用意してください。

    私はCentOSの7を3台(マスターノード1台、ワーカーノード2台)使用して作っています。


2.Dockerの構築をする


    kubernetesではコンテナをPodという形で利用しますが、ではそのコンテナを動かすための技術はどうしているのかというと、Dockerを使います。

    というわけで、Dockerの構築+kubernetes用の追加構築という流れになります。

    

    2-1 SElinuxの無効化

    

      # setenforce 0

      # sed -i "s/SELINUX=enforcing/SELINUX=disabled/" /etc/selinux/config


    2-2 firewallの無効化


      # systemctl stop firewalld



    2-3 Dockerに必要なパッケージ喉乳


      # yum install -y yum-utils device-mapper-persistent-data lvm2


    2-4 Dockerのyumリポジトリ追加

    

      # yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo


    

    2-5 Dockerの導入

    

      # yum install -y docker-ce-19.03.5-3.el7.x86_64


    2-6 Docker起動

  

      # systemctl start docker

      # systemctl enable docker


3.kubernetesクラスターの構築


    マスターノードとワーカーノードを作成する。

    途中まで一緒。


    3-1 スワップを停止


     # swapoff -a

     # sed -i '/swap/s/^/#/' /etc/fstab


    3-2 kubernetesを構築するツールkubeadmのyumリポジトリを追加。


     # vi /etc/yum.repos.d/kubernetes.repo


     以下の内容を記述する


     [kubernetes]

     name=Kubernetes

     baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64

     enabled=1

     gpgcheck=1

     repo_gpgcheck=1

     gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg


    3-3 kubeadmを導入する


     # yum install -y kubeadm


    ここからマスターノードとワーカーノードで作業が変わる。

    まずはマスターノードから


    3-4 マスターノードとしての構築

   

     # kubeadm init --apiserver-advertise-address=マスターノードのIP --pod-network-cidr=10.244.0.0/16


       ※--pod-network-cidrはkubernetesで使用する、Pod用の内部ネットワークに

         使うものによって変わってくる。

         ここでは基本となるflannel用のレンジを指定している。


     コマンドの処理が終わると、ワーカーノードを追加するためのコマンド「kubeadm join ~」が

     表示されるのでメモ帳などにコピーしておく。

     あとから出力させるコマンドもあるが、面倒なのでここでちゃんとメモっておくのがおすすめ。


    3-5 kubernetes用コマンドkubectlを使うための処理


     # mkdir -p $HOME/.kube

     # sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

     # sudo chown $(id -u):$(id -g) $HOME/.kube/config


    これでマスターノードにはなった。

    それでは、マスターノードにワーカーノードを追加する

    マスターノード構築時に出力されたコマンドを使用する。

    

     # kubeadm join <マスターノードのIPアドレス>:6443 --token <トークン> --discovery-token-ca-cert-hash <証明書ハッシュ>    

    これでマスターノードとその管理下にワーカーノードが追加された。

    各ノードのステータスを見てみよう


     # kubectl get node


    状態がRedyとなっていないとおもう。

    これは、ノードとしては出来上がったけど、内部で使用するPod用のネットワークができていないため。

    先ほどの、--pod-network-cidr=10.244.0.0/16はあくまで「Pod用のネットワークとしてこのレンジを使います」

    という設定で、実際にそこを使ってPod用のネットワークを実装するところまではやらない。

    

    なので、以下のコマンドを使い、Pod用のネットワークを使えるようにします。


     # kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

    

    再度、以下のコマンドで状態を確認するとRedyとなっている。

    

     # kubectl get node


これでkubernetesクラスターの構築は一応完了です。

次回は、構築した状態のkubernetesはどういう状態になっているのかについて解説します。

2021年4月30日金曜日

俺とkubernetesと時々vSphere ーまずはコンテナについてからー

 このブログは、コンテナのオーケストレーターであるkubernetesについて

自分の知識をまとめることを目的として記事を書いています。

もともとはなが~くvSphereのあれやこれやに携わってきたのでvSphereとの類似点や相違点についてもちょっと混ぜていけたりしたらいいかなぁとかも思っています。


まずは基本的な解説から行っていこうと思いますが最終的には、ネットワークポリシー等にも触れていきたいと思います。


今回は、kubernetesに入る前にコンテナとは何かについて軽く解説します。

kubernetesはコンテナの技術を利用しているので、軽くでも知っておくと理解がしやすいかと思います。


◆コンテナについて


  まずコンテナですが、難しく言うとLinux OSのカーネルを使用して複数のアプリケーションを独立して利用する。

  こんな感じになると思います。


  『Linux OSのカーネルを使用して』ここは問題ないと思います。

  『複数のアプリケーションを』ここも問題ないと思います。

  『独立して利用する』ここです、『独立って』どういうこと? となると思います。私はそうなりました。


  実際に使ってみて理解した内容を簡単な言葉で表現すると以下になります。


  『LinuxOSのカーネルを分身させて、分身をアプリケーションに使わせる』


  どういうことかといいますと、ふつうのLinuxOSであればnginxを入れてSQLを入れると1つのLinuxOS上で2つの

  アプリケーションが動くことになります。

  当然、2つのアプリケーションは同じIPアドレスを共有する形となります。


  コンテナ技術を使うと、2つのアプリケーションは1つのLinuxOS上にで動いてはいるものの、お互いに一緒のLinuxOS

  ではなく別々のLinuxOS上で動いているとだまされるわけです。

  どうやってだましているのかというと、LinuxOSのカーネルを分身させてその分身をアプリケーションに使わせているとなります。


  なので、コンテナでnginx、SQLを使うとそれぞれIPアドレスを持つ独立したLinuxOS上で動作していると言えるわけです。


◆コンテナはどうやってLinuxOS上に展開されるのか


  コンテナはイメージという、LinuxOSとアプリケーションがセットになった状態を利用して展開します。

  普通のOSだとまずハードにインストールしてアプリケーションをインストールすることになると思いますが、

  そのOSインストールとアプリケーションインストールが終わった状態からはじめられるということです。

  

  LinuxOSとアプリケーションのセットというとそこそこ容量が大きいんじゃないの?

  と思うかもしれませんが、じつはLinuxOS部分はコンテナを動かすホストOSの物を利用して使うので

  イメージには含まれずとても軽量です。

  

  で、そのイメージってどこにあるのかというと、DockerHubというところにアプリの公式が用意してたり、

  個人がアップロードして公開しているものがあるのでそれを使うのが基本となります。

  もちろん、イメージを1から作って使うこともできます。

  

  なのでどこかしらからダウンロードしてくることになるのですが、1度ダウンロードしてローカルにあるものは

  ローカルから使うのでダウンロードも各イメージ毎に最初の一回のみとなります。

  


◆コンテナのネットワーク


  コンテナにもIPアドレスが付くと書きましたが、そのIPで通信できるのはあくまで内部。

  コンテナ同士でのみ有効となります。

  外部にある作業用の端末などからはそのIPアドレスではアクセスできません。

  

  ではどうするかというと、コンテナを起動するときにホストOSのポートとコンテナのポートをくっ付けて

  『ホストOSのポート8080に届いた通信はコンテナAのポート80に転送する』というルールを作成します。

  これはiptablesでNATをしようしています。

  なのでiptablesが動いてないとちゃんと動いてくれません。

  気を付けましょう(n敗


◆コンテナのストレージ


  コンテナを起動させてファイルを内部に作成したりすることは可能です、コンテナを削除すると当然その

  データも削除されます。

  そりゃぁそうでしょうということなのですが、コンテナって基本的には作って壊してを繰り返すものなので

  そのたびにデータがなくなってしまうと困ります。

  

  そこで、コンテナのデータを外部で保存しましょうという仕組みがあります。

  簡単に説明するとホストOSのローカル領域やストレージ装置のディレクトリをコンテナにくっ付けるイメージです。

  

以上でものすごく簡単にコンテナってどんな感じのものなのかの説明を終わります。

次回からは、コンテナオーケストレーターkubernetesって何なの? コンテナのオーケストレーションってどういうこと?

といった内容を書きたいと思います。

2019年12月9日月曜日

Kubernetesでマイクロサービスなアプリを作れるようになるため、ちょっと試した(自作Webアプリ+Kubernetes+負荷分散)

※このブログは、Advent Calendar 2019 大國魂(ITブログ)の9日目です。

最近、「Kubernetes(K8s)」と「マイクロサービスアーキテクチャ」に興味が湧いています。
いろいろな記事を見ているとどちらもメリット・デメリットがあったりしますが、自分で触れてみないとわからないこともあるため、触れてみることにしました。

触れてみるにあたって、現在は「Kubernetes」をまだ勉強中なのですが、とりあえずロードバランサを作って負荷分散させるところまで学んだため、今回は『自分が作ったWebアプリをKubernetesにデプロイして負荷分散する』ことにチャレンジしようと思います。

主に使うもの


本記事では Windows 10 で開発します。
主に使うものは以下になります。
(インストールが必要なものは事前に導入されていることを前提とします)
  • 開発面
    • Java (ver: openjdk 13.0.1)
      • Webアプリの開発言語として利用。
    • Spring Initializr
      • Spring のプロジェクトを簡単に作れるサービス。
      • Spring Boot のプロジェクト作成に利用。
    • Spring Boot
      • 最小限の手間でSpringベースのアプリを作れるようにしたJavaフレームワーク。
      • Webアプリの開発に利用。
    • Gradle (ver: 6.0)
      • ビルドツール。
      • Spring Boot の成果物(JAR)を作成するために利用。
    • Docker (ver: 19.03.5)
      • 非常に軽量なコンテナ型の仮想化環境。
      • Kubernetesにデプロイするために必要。
    • Docker Desktop for Windows
      • WindowsでDockerを実行できるようにするツール。
    • DockerHub
      • コンテナ化されたイメージをアップロードして公開・共有できるサービス。
  • インフラ面
    • GKE
      • GCPでKubernetesの環境を簡単に構築するためのサービス。
      • GCPのプロモーションクレジットが残ってたので今回はGKEを選びましたが、Kubernetesが使えれば何でもOKです。(AWSの「Amazon EKS」でもAzureの「AKS」でもOKです)
    • Kubernetes(K8s)
      • コンテナオーケストレーションツール。
      • コンテナ化したアプリケーションのデプロイ、スケーリング、および管理が行える。
    • gcloud
      • GCPを操作できるCLIツール。
    • kubectl
      • Kubernetesクラスタに対してコマンドを実行することができるツール。
        GKEではCloudShellでkubectlを使う方法もありますが、本記事ではローカルのgcloudのコンポーネントとしてインストールしたkubectlを使います。(コマンドプロンプトでkubectlを使います)

適当なWebアプリを作る


最初に適当なWebアプリを作ります。
  1. Spring Boot のプロジェクトを作成する

    Spring Initializr を開いて「Gradle Project」「Java」「Spring Web」を選択して『Generate』を押します。他は任意です。
    (今回作るWebアプリは一応BFFの役割なので、自分はArtifactを「bff」にしてます)



    するとZipファイルがダウンロードされるので、任意の場所に保存して展開します。
    展開したファイルが Spring Boot のプロジェクトになります。
    以下のようなディレクトリ構成になります。
    (自分は「C:\_work\」に展開しました)

    > tree C:\_work\Bff /f
    
    C:\_WORK\BFF
    │  .gitignore
    │  build.gradle
    │  gradlew
    │  gradlew.bat
    │  HELP.md
    │  settings.gradle
    │  
    ├─gradle
    │  └─wrapper
    │          gradle-wrapper.jar
    │          gradle-wrapper.properties
    │          
    └─src
        ├─main
        │  ├─java
        │  │  └─com
        │  │      └─example
        │  │          └─bff
        │  │                  BffApplication.java
        │  │                  
        │  └─resources
        │      │  application.properties
        │      │  
        │      ├─static
        │      └─templates
        └─test
            └─java
                └─com
                    └─example
                        └─bff
                                BffApplicationTests.java
    
  2. ソースを変更する

    以下のとおりソースを変更します。
    (お好きなエディタやIDEでどうぞ。自分は最近だと IntelliJ Community Edition を使ってます。無償です )

     ・環境変数「HOSTNAME」を返却するAPIを作成する。
     ・サーバはポート「80」でリクエストを受け付けるようにする。
      (今回はWebサーバとAPサーバで分けたりしないので)

    Application.java
    package com.example.bff;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.RequestMapping; // ←★追加
    import org.springframework.web.bind.annotation.RestController; // ←★追加
    
    @SpringBootApplication
    @RestController // ←★追加
    public class BffApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(BffApplication.class, args);
        }
        
        /* ↓★追加 ここから */
        @RequestMapping("/")
        public String index() {
            String hostname = System.getenv("HOSTNAME");
            return "HOSTNAME: " + hostname;
        }
        /* ↑★追加 ここまで */
    }
    

    application.properties

    application.yaml にファイル名を変更。
    server:
      port: 80
    

  3. ビルドしてJARファイルを作成する

    コマンドプロンプトで以下のコマンドを実行してJARファイルを作成します。
    (自分と同じディレクトリ構成であれば「C:\_work\bff\build\libs\」に『bff-0.0.1-SNAPSHOT.jar』が作成されます)

    > cd c:\_work\bff
    > gradle build
    

  4. 動作を確認する

    Webアプリが動くかどうか確認してみます。
    まずは、コマンドプロンプトで以下のコマンドを実行します。

    > cd c:\_work\bff
    > java -jar build\libs\bff-0.0.1-SNAPSHOT.jar
    


    実行結果:
      .   ____          _            __ _ _
     /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
     \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::        (v2.2.1.RELEASE)
    
    2019-11-23 07:02:13.850  INFO 1812 --- [           main] com.example.bff.BffApplication           : Starting BffApplication on DESKTOP-PITSELN with PID 1812 (C:\_work\bff\build\libs\bff-0.0.1-SNAPSHOT.jar started by SYamada in c:\_work\bff)
    … 省略 …
    2019-11-23 07:02:16.211  INFO 1812 --- [           main] com.example.bff.BffApplication           : Started BffApplication in 2.844 seconds (JVM running for 3.55)
    


    するとWebサーバが起動するので、ブラウザを開いて「http://localhost/」にアクセスします。



    『HOSTNAME: 〇〇』が表示されればOKです。
    (環境変数に「HOSTNAME」を定義していない場合は、『HOSTNAME: null』が表示されます)

WebアプリをDockerHubにプッシュする


次に、作ったWebアプリをDockerHubにプッシュします。
Dockerfileの作り方は以下を参考にしてます。

 【参考】

  1. Dockerfileを作成する

    Spring Boot のプロジェクトがあるディレクトリの直下(自分の場合は「c:\_work\bff」の直下)に『Dockerfile』というファイルを作成し、内容を以下のとおりにします。

    Dockerfile
    FROM openjdk:13-jdk-alpine
    VOLUME /tmp
    ARG JAR_FILE
    COPY ${JAR_FILE} app.jar
    ENTRYPOINT ["java","-jar","/app.jar"]
    

  2. Dockerのイメージを作成する

    コマンドプロンプトで以下のコマンドを実行し、Dockerのイメージを作成します。
    ※「ysmmt」はご自身のDockerHubのアカウント名にしてください。自分の場合は「ysmmt」になります。

    > cd c:\_work\bff
    > docker build --build-arg JAR_FILE=build/libs/bff-0.0.1-SNAPSHOT.jar -t ysmmt/bff-server:0.0.1 .
    


    Dockerのイメージ一覧を確認(以下のコマンドを実行)して、「ysmmt/bff-server:0.0.1」が表示されればOKです。

    > docker images
    

    実行結果:
    REPOSITORY                       TAG                 IMAGE ID            CREATED             SIZE
    ysmmt/bff-server                 0.0.1               25e3b883ceef        14 seconds ago      354MB
    openjdk                          13-jdk-alpine       c4b0433a01ac        3 months ago        336MB
    

  3. イメージをDockerHubにプッシュする

    コマンドプロンプトで以下のコマンドを実行し、DockerHubにイメージをアップロードします。

    > docker push ysmmt/bff-server:0.0.1
    

    DockerHubのリポジトリ一覧を見て、「ysmmt/bff-server」が表示されればOKです。



Kubernetesを準備してロードバランサを構築する


次に、Kubernetesの環境を準備して、ロードバランサの構築までやります。
  1. GKEでKubernetesのクラスタを作成する

    GCPにログインし、[Kubernetes Engine] > [クラスタ] > [クラスタを作成] を押下します。



    すると、クラスタテンプレートを選択する画面が表示されるので、[標準クラスタ] > [ゾーン]で[asia-northeast1-a (東京)]を選択 > [作成] を押下します。
    ※今回はそんなに凝ったものではないので、基本はデフォルトです。ゾーンはなんとなくで東京を選んでます。



    これで、クラスタの作成は完了です。
    クラスタサイズがノード数(VMインスタンス数)です。3台作成されており、クラスタに紐づけされてます。



    この状態でkubectlにアクセスできるようになるので、アクセスしてみます。
    上の画面の[接続]を押下すると、作成したクラスタにgcloudでアクセスするためのコマンドが表示されるので、コマンドプロンプトで実行します。



    すると、作成したクラスタをkubectlコマンドで操作できるようになるので、試しに以下のコマンドを実行してみます。
    「kubernetes」というサービスが一覧に表示されればOKです。

    > kubectl get services
    

    実行結果:
    NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
    kubernetes   ClusterIP   10.4.0.1     <none>        443/TCP   17m
    
  2. ロードバランサのマニフェストを作成する

    任意の場所(自分は「C:\_work\k8s-manifests」の直下)にロードバランサのマニフェストを作成します。
    内容は以下のとおりです。

    sample-lb.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: sample-lb
    spec:
      type: LoadBalancer
      ports:
        - name: "http-port"
          protocol: "TCP"
          port: 8080
          targetPort: 80
          nodePort: 30080
      selector:
        app: sample-app
    
  3. マニフェストをKubernetesに渡してロードバランサを構築する

    以下のコマンドを実行して、Kubernetesにロードバランサのマニフェストを適用させます。

    > cd c:\_work\k8s-manifests\
    > kubectl apply -f sample-lb.yaml
    

    以下のコマンドで、"sample-lb"というサービスが見えればOKです。
    これで、ロードバランサの構築は完了です。
    > kubectl get services
    

    実行結果:
    NAME         TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)          AGE
    kubernetes   ClusterIP      10.4.0.1      <none>         443/TCP          3d15h
    sample-lb    LoadBalancer   10.4.13.158   34.84.89.145   8080:30080/TCP   118s
    

    「EXTERNAL-IP」と「PORT」が外部に公開しているIPアドレスとポートになりますが、まだWebサーバの構築&Webアプリのデプロイをしてないので「http://34.84.89.145:8080/」をブラウザで開いても何も表示されません。

KubernetesにWebサーバを構築&Webアプリをデプロイする


最後に、Webサーバの構築&Webアプリのデプロイをやります。
Webサーバ(Tomcat)は Spring Boot に組み込まれているので、今回の場合はKubernetesのPodのコンテナイメージとして、作ったWebアプリを指定すればWebサーバの構築&Webアプリのデプロイができる形になります。
  1. Webサーバのマニフェストを作成する

    任意の場所(自分は「C:\_work\k8s-manifests」の直下)にWebサーバ&Webアプリのマニフェストを作成します。
    内容は以下のとおりです。

    sample-lb.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: sample-deployment
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: sample-app
      template:
        metadata:
          labels:
            app: sample-app
        spec:
          containers:
            - name: bff-server
              image: ysmmt/bff-server:0.0.1
              ports:
                - containerPort: 80
    
  2. マニフェストをKubernetesに適用してWebサーバを構築する

    以下のコマンドを実行して、KubernetesにWebサーバ&Webアプリのマニフェストを適用させます。

    > cd c:\_work\k8s-manifests\
    > kubectl apply -f sample-deployment.yaml
    

    以下のコマンドで、"sample-deployment-〇〇"というPodが3つ見えて、STATUSが「Running」になっていればOKです。

    > kubectl get pods -o wide
    

    実行結果:
    NAME                                READY   STATUS    RESTARTS   AGE   IP         NODE                                                NOMINATED NODE   READINESS GATES
    sample-deployment-cdf7d878d-2dv9w   1/1     Running   0          3m    10.0.0.2   gke-standard-cluster-1-default-pool-946a7330-2llj   <none>           <none>
    sample-deployment-cdf7d878d-l7pgd   1/1     Running   0          3m    10.0.1.3   gke-standard-cluster-1-default-pool-946a7330-34rm   <none>           <none>
    sample-deployment-cdf7d878d-q2w6n   1/1     Running   0          3m    10.0.1.2   gke-standard-cluster-1-default-pool-946a7330-34rm   <none>           <none>
    

    「NODE」が、実際にPodが配置されたノード(VMインスタンス)になります。
    ノードは全部で3つあるはずなのに、2つに対してだけPodが割り振られている理由は、割り振られなかった1つのノードで既にKubernetesが「システムで使うためのPod」を起動しており、リソースに空きがないためとなります。
    以下のコマンドで各ノードのリソース使用状況を確認できます。

    > kubectl top node
    

    実行結果:
    NAME                                                CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
    gke-standard-cluster-1-default-pool-946a7330-2llj   38m          4%     710Mi           26%
    gke-standard-cluster-1-default-pool-946a7330-34rm   41m          4%     832Mi           31%
    gke-standard-cluster-1-default-pool-946a7330-ggs9   126m         13%    873Mi           33%
    

    次のコマンドでKubernetesのシステムが起動しているPodが見れます。
    割り振られなかったノード「〇〇-ggs9」に大半が起動しています。
    > kubectl -n kube-system get pod -o wide
    

    実行結果:
    NAME                                                           READY   STATUS    RESTARTS   AGE     IP            NODE                                                NOMINATED NODE   READINESS GATES
    event-exporter-v0.2.4-5f88c66fb7-2ggqv                         2/2     Running   0          4d15h   10.0.2.5      gke-standard-cluster-1-default-pool-946a7330-ggs9   <none>           <none>
    fluentd-gcp-scaler-59b7b75cd7-l27k7                            1/1     Running   0          4d15h   10.0.2.2      gke-standard-cluster-1-default-pool-946a7330-ggs9   <none>           <none>
    fluentd-gcp-v3.2.0-dkjlq                                       2/2     Running   0          2d      10.146.0.29   gke-standard-cluster-1-default-pool-946a7330-34rm   <none>           <none>
    fluentd-gcp-v3.2.0-q7d9s                                       2/2     Running   0          2d      10.146.0.30   gke-standard-cluster-1-default-pool-946a7330-ggs9   <none>           <none>
    fluentd-gcp-v3.2.0-tbnh7                                       2/2     Running   0          2d      10.146.0.28   gke-standard-cluster-1-default-pool-946a7330-2llj   <none>           <none>
    heapster-75bc7bd966-ftqdp                                      3/3     Running   0          3d14h   10.0.2.6      gke-standard-cluster-1-default-pool-946a7330-ggs9   <none>           <none>
    kube-dns-79868f54c5-dm8hf                                      4/4     Running   0          4d15h   10.0.2.7      gke-standard-cluster-1-default-pool-946a7330-ggs9   <none>           <none>
    kube-dns-79868f54c5-zs47s                                      4/4     Running   0          4d15h   10.0.2.3      gke-standard-cluster-1-default-pool-946a7330-ggs9   <none>           <none>
    kube-dns-autoscaler-bb58c6784-smc62                            1/1     Running   0          4d15h   10.0.2.4      gke-standard-cluster-1-default-pool-946a7330-ggs9   <none>           <none>
    kube-proxy-gke-standard-cluster-1-default-pool-946a7330-2llj   1/1     Running   0          2d      10.146.0.28   gke-standard-cluster-1-default-pool-946a7330-2llj   <none>           <none>
    kube-proxy-gke-standard-cluster-1-default-pool-946a7330-34rm   1/1     Running   0          2d      10.146.0.29   gke-standard-cluster-1-default-pool-946a7330-34rm   <none>           <none>
    kube-proxy-gke-standard-cluster-1-default-pool-946a7330-ggs9   1/1     Running   0          2d      10.146.0.30   gke-standard-cluster-1-default-pool-946a7330-ggs9   <none>           <none>
    l7-default-backend-fd59995cd-rg6lh                             1/1     Running   0          4d15h   10.0.2.9      gke-standard-cluster-1-default-pool-946a7330-ggs9   <none>           <none>
    metrics-server-v0.3.1-57c75779f-tmlf4                          2/2     Running   0          4d15h   10.0.2.8      gke-standard-cluster-1-default-pool-946a7330-ggs9   <none>           <none>
    prometheus-to-sd-blkhv                                         2/2     Running   0          2d      10.146.0.29   gke-standard-cluster-1-default-pool-946a7330-34rm   <none>           <none>
    prometheus-to-sd-fz47w                                         2/2     Running   0          2d      10.146.0.28   gke-standard-cluster-1-default-pool-946a7330-2llj   <none>           <none>
    prometheus-to-sd-jzrs9                                         2/2     Running   0          2d      10.146.0.30   gke-standard-cluster-1-default-pool-946a7330-ggs9   <none>           <none>
    

    次のコマンドでKubernetesのシステムが起動しているPodのリソース使用量を確認できます。
    > kubectl -n kube-system top pod
    

    実行結果:
    NAME                                                           CPU(cores)   MEMORY(bytes)
    event-exporter-v0.2.4-5f88c66fb7-2ggqv                         1m           17Mi
    fluentd-gcp-scaler-59b7b75cd7-l27k7                            0m           40Mi
    fluentd-gcp-v3.2.0-dkjlq                                       5m           152Mi
    fluentd-gcp-v3.2.0-q7d9s                                       9m           152Mi
    fluentd-gcp-v3.2.0-tbnh7                                       5m           146Mi
    heapster-75bc7bd966-ftqdp                                      2m           42Mi
    kube-dns-79868f54c5-dm8hf                                      2m           31Mi
    kube-dns-79868f54c5-zs47s                                      2m           31Mi
    kube-dns-autoscaler-bb58c6784-smc62                            1m           7Mi
    kube-proxy-gke-standard-cluster-1-default-pool-946a7330-2llj   5m           13Mi
    kube-proxy-gke-standard-cluster-1-default-pool-946a7330-34rm   4m           14Mi
    kube-proxy-gke-standard-cluster-1-default-pool-946a7330-ggs9   5m           14Mi
    l7-default-backend-fd59995cd-rg6lh                             1m           1Mi
    metrics-server-v0.3.1-57c75779f-tmlf4                          3m           21Mi
    prometheus-to-sd-blkhv                                         0m           13Mi
    prometheus-to-sd-fz47w                                         1m           13Mi
    prometheus-to-sd-jzrs9                                         1m           13Mi
    

    とりあえず、これでWebサーバの構築&Webアプリのデプロイは完了です。

動作を確認する


ブラウザを開き、「http://34.84.89.145:8080/」にアクセスしてみます。
すると、先ほどと異なり今度はHOSTNAMEがきちんと表示されてます。
このHOSTNAMEはKubernetesが自動でつける環境変数であり、Podの名前が設定されます。
なので、どのPod(=Webサーバ)にアクセスされたかが判断できます。



定期的にブラウザを更新(=F5押下)してみると、アクセスされたHOSTNAMEが変わります。
問題なく負荷分散できてるようですね。



ブラウザだとなかなかアクセス先が変わらないので、linuxコマンド使えるアプリ等(=Gitbash等)で以下のコマンドを実行したほうが確認しやすいです。

$ curl -s http://34.84.89.145:8080/
HOSTNAME: sample-deployment-cdf7d878d-2dv9w
$ curl -s http://34.84.89.145:8080/
HOSTNAME: sample-deployment-cdf7d878d-q2w6n
$ curl -s http://34.84.89.145:8080/
HOSTNAME: sample-deployment-cdf7d878d-l7pgd


感想


実際に手を動かしてみても思いましたが、Kubernetesを使うとインフラ構築が圧倒的に楽ですね。
「やりたいこと」を少しの手間で実現できてしまうあたり、Spring Boot とかのフレームワークと同じだなと感じました。
Spring Boot とかは『アプリ開発のフレームワーク』とすると、Kubernetesは『インフラ構築のフレームワーク』というところでしょうか。

いろいろな記事を見てるとKubernetesは事前学習のコストがかかるというのがデメリットとして挙げられていますが、自分からすると、アプリ開発でフレームワークを使うのは当たり前なので、デメリットって感じはしないかなぁと。
事前学習した分、インフラ構築の実作業時間を削減できるので、事前学習で使った時間は取り戻せる気がします。
(急を要するプロジェクトだと使わない方がいいと思いますが。。)

あと、もう一ついいと思ったのは、やはり「インフラの構成をコードに残せる」ところですかね。
バージョン管理できますし、Kubernetesを知っている人がコード(マニフェスト)を見れば、どういう構成で成り立っているのか分かるので属人化の対策にもなります。Kubernetesを使わない場合でも地道に各サーバにアクセスして構成を見ればわかることかとは思いますが、「一つ一つのサーバにアクセスして確認する工数」と「コードを見て確認する工数」では、後者のほうが時間かからないと思いますし。

…と、ここまで学習&実装してみて感じたところはそんなところですかね。
今のままだとまだKubernetesやインフラの知識が浅いので、業務で使うかどうかはもっと色々と試してからにしようと思います。
業務で使えなくとも、個人で色々とアプリの動作を確認したいときでもKubernetesは便利なので、今後も個人的には使っていこうと思います。(よく、「負荷分散を意識したWebアプリ作って試したいけど、インフラ構築が面倒…」と思い、試せないまま終わることがあるので。。アプリの動作を見たいのに、インフラ構築に時間がかかるとなるとモチベーションが一気に下がっちゃいます)

今後は、BFFの後ろのリソースサーバ作ったり、作ったAPIをSPAから利用したり、openid_connectを使った認証を実装したり、セッションストレージを用意して負荷分散したBFFのセッション管理したりと、Kubernetesで色々と試して業務で使えそうか確認していこうと思ってます。

感想が長くなっちゃいましたが、以上!