0
0

More than 1 year has passed since last update.

学習用Kubernetes環境を作る2 動的PVが使えない環境でKubernetes管理WebUIのPortainer環境を作る/データ永続化/NodePortについて

Last updated at Posted at 2021-09-02

はじめに

注意:今回作る環境は,初心者が学習用に作成したものです.
決して本番環境等,外部に公開するような重要な環境ではそのままの手順通りで行わないで下さい.
また,insecureな設定やベストプラクティスから外れた運用をしている箇所があります.

学習用Kubernetes環境を作るの第2回です.

Part 1 学習用Kubernetes環境を作る1 Ubuntu 20.04 LTS+kubeadm+containerd+CalicoなKubernetes環境をHyper-V上にTailscaleの固定IPで構築

Part 2 学習用Kubernetes環境を作る2 動的PVが使えない環境でKubernetes管理WebUIのPortainer環境を作る/データ永続化/NodePortについて

Part 3 学習用Kubernetes環境を作る3 Kubernetes上にKubernetes用プライベートDockerレジストリHarbor環境を作る/httpなDockerレジストリをDocker・containerdで使う

Kubernetes管理WebUIのPortainerをNodePortで公開,PersistentVolume(PV)のlocalでデータ永続化を行いHelmでデプロイします.

前提となるNodePortやデータ永続化の話は雑にざっくりとしますが,詳しくは他の記事を調べて下さい.

Kubernetesの環境は,前回構築した環境を前提としています.

NodePortについて

Kubernetesで,ホストの外部にサービスを公開する方法は,NodePort/LoadBalancer/Ingressの3つがあります.

この内,NodePortとLoadBalancerはサービスタイプであり,Ingressはサービスの外側で動きます.

NodePort

NodePort.png

NodePortは,30000~32767番号を割り当てることができ,デプロイされたPodがあるノードで指定されたポート番号がリッスンされます.

NodePort-No-Access.png

マルチノードでスケジューラー等によりPodが別のノードにデプロイされた場合,アクセスするためのIPアドレスが変更しなければならない,負荷分散し辛い等のデメリットがあります.

接続方法はデプロイされたPodがあるノードのIP(またはDNS名):ポート番号です.おそらく最も,簡単な公開方法であり,Dockerのように利用出来ます.

LoadBalancer

LoadBalancer.png

LoadBalancerは,Kubernetesで最も標準的な公開方法です.クラウド環境では簡単に利用でき,ハンズオン等でも出てきます.オンプレな環境では,MetalLBがよく利用されます.サービスに対してExternal IPが割り当てられ,そのIPアドレスを利用して外部から接続が可能になります.

Ingress

Ingress.png

Ingressはサービスタイプではなく,全サービスの外側で動きます.様々なコントローラーがあり,コントローラーにより動作が異なります.

Ingressには,公開する複数のサービスを,パスでマッピングする事で公開可能になります.

公開するサービスのPod内も,アクセスのために指定されたパスと同じパスで転送されるので,Podもそれに合わせて変更する必要があるというデメリットがあります.

コントローラー自体にも,サービスが存在し,このサービスの公開方法をNodePort/LoadBalancer等にすることによってアクセス方法が異なります.

NodePortのサンプルを動かす

サンプルのサービスをNodePortでデプロイします.

以下のファイルをtest.ymlとして保存します.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
        - name: nginx
          image: nginx
---
apiVersion: v1
kind: Service
metadata:
  name: test-service
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 80
      nodePort: 32767
      protocol: TCP
  selector:
    app: test

以下のコマンドでファイルの内容をデプロイします.

kubectl apply -f test.yml

以下のコマンドで,deploymentによりデプロイされたPodが正常に動作をしているか確認します.

kubectl get pod

以下のように,test-deploymentから始まるPodのSTATUSがRunningであれば,正常にPodが稼働しています.

NAME                               READY   STATUS    RESTARTS   AGE
test-deployment-5f6778868d-4zw82   1/1     Running   0          3m32s

次に,サービスを確認します.

kubectl get svc test-service 

以下のような,結果になります.

NAME           TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
test-service   NodePort   10.106.223.45   <none>        80:32767/TCP   14m

NodePortで設定したポート番号が割り当てられていることがわかります.

最後に実際に,ノードのIP:32767へ実際にブラウザでアクセスして確かめます.

nginx-result.png

アクセスして,上記のようになればOKです.

curlで確認する場合は,以下のようなコマンドになります.

curl ノードのIP:32767

以下のような結果になれば,OKです.

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

データ永続化について

Kubernetesでは様々なデータ永続化方法がありますが,今回はPersistentVolume(PV)のlocalを利用したデータ永続化を行います.

PVを利用するには,PV以外にもStorage Class(SC),Persistent Volume Claim(PVC)が必要です.

それぞれ何かを説明するよりもサンプルを出した方が早いと思うのでサンプルを出して説明します.

以下のファイルをtest-pv.ymlとして保存します.

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: test-sc
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: test-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: test-sc
  local:
    path: /mnt/kubernetes/test
  nodeAffinity:
    required:
      nodeSelectorTerms:
        - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
                - ノード名
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: test-sc
  resources:
    requests:
      storage: 1Gi

先程作成したtest.ymlのdeploymentを以下のように変えます.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
        - name: nginx
          image: nginx
          volumeMounts:
            - mountPath: "/usr/share/nginx/html"
              name: test-data
      volumes:
        - name: test-data
          persistentVolumeClaim:
            claimName: test-pvc

PVCは本来どちらかというとtest.yml側に書くべきですが,都合上こうしています.

サンプルを見ればわかりますが,構造としては,アプリケーション(Deployment)側が,PVCを割り当て,PVCはSCにPVを要求し,SCは要求(PVC)に対して最適なPVを与え,PVはデータを保存する実体を指すものです.

PVは,動的プロビジョニングにより自動生成する方が一般的なようですが,今回採用したlocalでは動的プロビジョニングをサポートしていないため,手動で作成する必要があります.

オンプレ環境では,local以外だと動的プロビジョニングが利用可能なNFS等を使うことになると思いますが,面倒なので一番楽なlocalを使用します.

また,localの制限として他には,1つのPVに対して1つのPodにしか割り当て出来ず,アクセスモードは常にReadWriteOnce固定であるということです.

このため,kindをPodにして使うか,DeploymentとStatefulSetではreplicasを1にして使わないといけません.

尚,DeploymentでPodを削除して,Podが再作成された場合は,特に問題なく動きます.

なぜ,このような回りくどい割り当て方をしているのかは,Kubernetes管理者とアプリケーション開発者を考えるとわかりやすいです.

PV.png

5GBのPVをPodに割り当てることを考えるとこうなります.

ex-PV.png

このように抽象化していれば,管理者はSCと複数のPV(動的プロビジョニングが使えない環境等)を用意するだけでよく,開発者はデータ永続化をしたいアプリケーションがあれば,それをSCに要求するPVCとアプリケーションに永続化するPVCの設定をするだけでいいのです.

そうすれば,要求された容量以上で一番近い容量のPVをSCが自動的に割り当ててくれます.

では,applyにして実際にデプロイします.

まずは,実体のディレクトリを作成します.

sudo mkdir -p /mnt/kubernetes/test

sudo chmod 777 /mnt/kubernetes/test

test-pv.ymlをapplyします.

kubectl apply -f test-pv.yml

デプロイ出来たか確認します.

SCを確認します.

kubectl get sc test-sc

以下のようになっていれば,問題ありません.

NAME                 PROVISIONER                    RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
test-sc              kubernetes.io/no-provisioner   Delete          WaitForFirstConsumer   false                  2m19s

PVを確認します.

kubectl get pv test-pv

以下のようになっていれば,問題ありません.

STATUSはAvailableです.

NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS       CLAIM              STORAGECLASS   REASON   AGE
test-pv   1Gi        RWO            Retain           Available    default/test-pvc   test-sc                 24m

PVCを確認します.

kubectl get pvc test-pvc

STATUSはPendingです.

NAME       STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
test-pvc   Pending                                      test-sc        5m7s

test.ymlをapplyして更新します.

kubectl apply -f test.yml

Podが正常に再作成され動いているか確認します.

kubectl get pod

Pod名が変更されているか,AGEがリセットされているか確認します.

NAME                               READY   STATUS    RESTARTS   AGE
test-deployment-56bddb69d5-rc7c9   1/1     Running   0          53s

PVCの状態を確認します.

kubectl get pvc test-pvc

PendingからBoundに変わりました.

NAME       STATUS   VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
test-pvc   Bound    test-pv   1Gi        RWO            test-sc        20m

PVの状態を確認します.

kubectl get pv test-pv

AvailableからBoundに変わりました.

NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM              STORAGECLASS   REASON   AGE
test-pv   1Gi        RWO            Retain           Bound    default/test-pvc   test-sc                 24m

マウントされているか確認するために,実体のディレクトリ(/mnt/kubernetes/test)にindex.htmlを作成し,変化を確認します.

htmlファイルは以下のようにします.

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Hello</title>
</head>

<body>
    Hello PV!!
</body>

</html> 

実際にブラウザでアクセスして,Hello PV!!と表示されるか,curlコマンドで上記htmlと同じ結果が帰って来れば成功です.

テストが完了すれば,これらは不要なので,削除します.

kubectl delete -f test.yml

kubectl delete -f test-pv.yml

sudo rm -rf /mnt/kubernetes/test

Portainerをデプロイ

これらを理解したところで,本題のPortainerをデプロイします.

基本的に,公式の手順通りですが,公式の手順通りでは,この環境ではデプロイ出来ません.

公式では,デフォルトのSCと諸アクセス権限があれば良いというように書かれていますが,これは正確ではなく,動的プロビジョニングが有効なSCが必要です(指定すれば,デフォルトである必要もない).

動的プロビジョニングが有効でない場合は,10GB以上ののPVが必要です.

データの保存先を作成

上記を踏まえて,まずPortainerのデータを保存ディレクトリを作成します.

mkdir /mnt/kubernetes/portainer

chmod 777 /mnt/kubernetes/portainer

SC・PVのymlを作成

次に,SCとPVを作成します.

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: portainer-sc
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: portainer-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: portainer-sc
  local:
    path: /mnt/kubernetes/portainer
  nodeAffinity:
    required:
      nodeSelectorTerms:
        - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
                - ノード名

今回このSCは,Portainer専用としています.

必要であれば,名前を変えたり,PVと別ファイルに分けて下さい.

デフォルトSCを利用する場合

ここで,デフォルトのSCを利用したい場合,SCの部分を以下のようにするか,

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: portainer-sc
  annotations: { "storageclass.kubernetes.io/is-default-class": "true" }
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

公式順のように,以下のようなコマンド等で,デフォルトSCにして下さい.

kubectl patch storageclass portainer-sc -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

以下のようなコマンドで,

kubectl get sc portainer-sc

以下のように,defaultとなっていれば問題ありません.

NAME                      PROVISIONER                    RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
portainer-sc (default)   kubernetes.io/no-provisioner   Delete          WaitForFirstConsumer   false                  15s

SC・PVのymlをapply

先程作成したymlをデプロイします.

kubectl apply -f portainer-vol.yml

正常にデプロイできたか確認します.

SCを確認します.

kubectl get sc portainer-sc

以下のようになっていれば,問題ありません.

NAME                 PROVISIONER                    RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
portainer-sc              kubernetes.io/no-provisioner   Delete          WaitForFirstConsumer   false                  2m19s

PVを確認します.

kubectl get pv portainer-pv

以下のようになっていれば,問題ありません.

STATUSはAvailableです.

NAME           CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS       CLAIM                 STORAGECLASS   REASON   AGE
portainer-pv   10Gi       RWO            Retain           Available    portainer/portainer   portainer-sc            3m7s

Helmを利用してインストール

Helmリポジトリを追加してインストールします.

helm repo add portainer https://portainer.github.io/k8s/

helm install --create-namespace -n portainer portainer portainer/portainer --set persistence.storageClass=portainer-sc

デフォルトSCを使用する場合,--set persistence.storageClass=portainer-scは不要です.

また,service.typeでサービスタイプを指定できます.

Portainerはportainerのnamespaceにデプロイされます.

Podが正常に稼働しているか確認します.

kubectl -n portainer get pod

以下のように,READYが1/1で,STATUSがRunningであれば,問題ありません.

NAME                         READY   STATUS    RESTARTS       AGE
portainer-59f798c579-pdhm9   1/1     Running   0              2m19s

一応,PVも確認します.

kubectl get pv portainer-pv

Availableが,Boundに変わりました.

NAME           CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                 STORAGECLASS   REASON   AGE
portainer-pv   10Gi       RWO            Retain           Bound    portainer/portainer   portainer-sc            4m7s

後は,

http://ノードIP(orDNS):30777

にブラウザでアクセスできれば,成功です.

アクセスすれば,アカウント作成->接続方法の選択(今回はKubernetes)->設定になると思います.

設定でmetrics-serverと連携すれば,リソースの監視等も強化出来ます.

Dockerも管理出来るので,Dockerを使っている人はTLSでDockerソケットを公開するなどして,エンドポイントに追加するといいと思います. (Dockerの管理UIとしての方が優秀)

Next

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0