3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Kubernetesでコンテナを削除しても消えないPersistentVolumeを作る

Last updated at Posted at 2018-12-07

この記事は、「オンプレミス、Kubernetesで、マイクロサービスを意識したWebアプリをデプロイするまでの軌跡」の一部です。

はじめに

DockerをはじめとするコンテナにはImmutable(不変)であるべき、という思想があり、各インスタンスは立ち上がるごとに初期化され、綺麗な状態に戻ります。
ここで一点困るのが、ファイルサーバーやデータベースなど、永続的に保持しておきたい情報をどうしておくか?という事です。

KubernetesにはPersistentVolumeという機能があって、これを使う事でコンテナとは独立したボリュームを作ることが出来ます。

今回は、このPersistentVolumeの使い方を紹介します。

NFSサーバーをセットアップする

PersistentVolumeで使えるボリュームの形態はいくつかあるようなのですが、今回は手軽そうなNFSを使う事にします。
まずは任意のサーバーにNFSをインストールする必要があるので、用意します。専用であれば良いでしょうが、僕は以前の記事で構築したKubernetesのWorkerノードをNFSサーバーとしてセットアップしました。

Ubuntuであれば、以下のコマンドでインストール可能です。

$ sudo apt-get install nfs-kernel-server

共有するフォルダを作成し、権限を設定します。

$ sudo mkdir -p /export/nfs
$ sudo chmod 1777 /export/nfs/.
$ sudo nano /etc/exports

...略

/export/nfs xxx.xxx.xxx.0/24(rw,async,no_root_squash)

$ sudo service nfs-server restart
$ sudo service rpcbind restart

参考サイトにあるように、複数のサービスで同じフォルダを共有する事は難しいようです。
必要に応じて、サブフォルダを作成しておきます。

$ sudo mkdir -p /export/nfs/serviceA
$ sudo mkdir -p /export/nfs/serviceB

今回はテストのため、serviceAの方に以下のようなファイルを仕込んでおきます。

$ nano /export/nfs/serviceA/index.html

hello world!

NFSマウント準備

クライアント側も準備が必要です。
全てのノードで以下を実行して、NFSが使えるようにしておきます。

sudo apt install nfs-common

PeersistentVolumeを設定する

NFSサーバーは設定できたので、PeersistentVolumeを設定します。

service-a-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: service-a-pv
  namespace: some-name-space
  annotations:
    volume.beta.kubernetes.io/storage-class: "slow"
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  nfs:
    server: 192.168.0.xxx        <-- 実際のipアドレス 
    path: /export/nfs/serviceA   <-- 共有したいNFSサーバー上のフォルダ 

設定の中でnamenamespacestorageaccessMode等、必要であれば適宜変更してください。

設定を元に、PersistentVolumeを作成します。

kubectl apply -f service-a-pv.yaml

これで作成できました。
確認します。

$ kubectl get pv

NAME             CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM     STORAGECLASS   REASON   AGE
service-a-pv     5Gi        RWO            Retain           Available          slow                    1h

問題がある場合はStatusがAvailableにならないので、設定を見直してください。

PersistentVolumeClaimを設定する

間違い探しみたいですが、PersistentVolume Claim です。
この設定で、PersistentVolumeを実際のアプリに紐づけます。

service-a-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: service-a-pvc
  namespace: some-name-space
  labels:
    app: service-a            <-- ボリュームを紐づけるデプロイメント
  annotations:
    "volume.beta.kubernetes.io/storage-class": "slow"
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi

これで作成する準備は出来ましたが、今回はnamespaceを指定しているので、namespaceが無い状態ではエラーが出ます。

$ kubectl create namespace some-name-space

namespaceを作成したら、pvcを作成しましょう。

$ kubectl apply -f service-a-pvc.yaml

改めて状態を確認します。

$ kubectl get pv

NAME           CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM           STORAGECLASS   REASON   AGE
service-a-pv   5Gi        RWO            Retain           Bound    service-a-pvc   slow                    32h

service-a-pvcにバインドされていますね。
PersistentVolumeClaimの状態も確認します。

$ kubectl get pvc -n some-name-space

NAME            STATUS   VOLUME         CAPACITY   ACCESS MODES   STORAGECLASS   AGE
service-a-pvc   Bound    service-a-pv   5Gi        RWO            slow           32h

これで、ボリュームの準備は完了しました。

一点注意ですが、今回の設定ではnamespaceを分けているので単にkubectl get pvcではNo resources found.となってしまいます。オプションでnamespaceを指定してください。

コンテナに紐づける

いよいよ、実際のコンテナに紐づけていきます。
以下のようなyamlファイルで、サービスとデプロイメントを定義します。

service-a.yaml
apiVersion: v1
kind: Service
metadata:
  name: service-a
  namespace: some-name-space
  labels:
    app: service-a
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
  selector:
    app: service-a
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: service-a
  namespace: some-name-space
spec:
  replicas: 1
  revisionHistoryLimit: 3
  template:
    metadata:
      namespace: some-name-space
      labels:
        app: service-a
        version: latest
    spec:
      containers:
      - name: service-a
        image: nginx:latest
        ports:
        - containerPort: 80
        volumeMounts:
        - name: service-a-storage   <-- ※ 同じ名前を指定する
          mountPath: /usr/share/nginx/html
      volumes:
    app: service-a
      - name: service-a-storage     <-- ※ 同じ名前を指定する
        persistentVolumeClaim:
          claimName: service-a-pvc

この例ではnginxのコンテナを起動して、デフォルトの公開ディレクトリである/usr/share/nginx/htmlに先ほど作ったボリュームをマウントしています。
これにより、サービスにアクセスした際に先ほど作ったindex.htmlが見えるようになります。

$ kubectl apply -f service-a.yaml

デプロイ後、このサービスが起動しているポートを調べます。

$ kubectl get services -n some-name-space
NAME        TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
service-a   NodePort   10.107.212.223   <none>        80:30380/TCP   71m

この例では30380で起動しているようなので、以下のコマンドで内容を確認できます。

$ curl <サーバーのip>:30380
hello world!

無事に確認できれば、全てうまく設定できています。
お疲れさまでした!

注意

今回はデモのためにindex.htmlをPersistentVolumeの中にいれてnginxで参照しましたが、この使い方では、ポッドをたくさん作ってスケールしても結局単一のファイルを見に行くので、Kubernetesの恩恵もあまり受けられないと思われます。検証等はしていないですが、ご注意ください。

参考

「Docker」を全く知らない人のために「Docker」の魅力を伝えるための「Docker」入門
KubernetesでNFSを利用してPersistentStorageを準備する

3
4
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
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?