このブログを検索
個人の責任において情報活用をお願いします。
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回 ユーザーの作成とクラスタメンバーへの追加
今回は、作業用のユーザーをデフォルトの設定で作成してクラスタが操作できるようにクラスタのメンバーに追加する作業を行ってみます。
まずは、ユーザーの作成を行います。
「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の追加』
早速導入ですが、これは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+負荷分散)
最近、「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アプリを作ります。
- 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
- ソースを変更する
以下のとおりソースを変更します。
(お好きなエディタやIDEでどうぞ。自分は最近だと IntelliJ Community Edition を使ってます。無償です )
・環境変数「HOSTNAME」を返却するAPIを作成する。
・サーバはポート「80」でリクエストを受け付けるようにする。
(今回はWebサーバとAPサーバで分けたりしないので)
Application.javapackage 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
- ビルドしてJARファイルを作成する
コマンドプロンプトで以下のコマンドを実行してJARファイルを作成します。
(自分と同じディレクトリ構成であれば「C:\_work\bff\build\libs\」に『bff-0.0.1-SNAPSHOT.jar』が作成されます)
> cd c:\_work\bff > gradle build
- 動作を確認する
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の作り方は以下を参考にしてます。
【参考】
- Dockerfileを作成する
Spring Boot のプロジェクトがあるディレクトリの直下(自分の場合は「c:\_work\bff」の直下)に『Dockerfile』というファイルを作成し、内容を以下のとおりにします。
DockerfileFROM openjdk:13-jdk-alpine VOLUME /tmp ARG JAR_FILE COPY ${JAR_FILE} app.jar ENTRYPOINT ["java","-jar","/app.jar"]
- 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
- イメージをDockerHubにプッシュする
コマンドプロンプトで以下のコマンドを実行し、DockerHubにイメージをアップロードします。
> docker push ysmmt/bff-server:0.0.1
DockerHubのリポジトリ一覧を見て、「ysmmt/bff-server」が表示されればOKです。
Kubernetesを準備してロードバランサを構築する
次に、Kubernetesの環境を準備して、ロードバランサの構築までやります。
- 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
- ロードバランサのマニフェストを作成する
任意の場所(自分は「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
- マニフェストを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アプリのデプロイができる形になります。
- 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
- マニフェストを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で色々と試して業務で使えそうか確認していこうと思ってます。
感想が長くなっちゃいましたが、以上!