OpenShiftのDynamic Storage Provisioning環境の構築 (containerized gluster on azure)

OpenShift 3.4 からDynamic Storage Provisioningが利用可能になったので、GlusterFSを使って試してみました

PersistentVolume(PV) と Persistent Volume Claim(PVC) を利用する仕組みでは、OpenShiftのクラスタ管理者が事前に Persistent Volumeという形でStoragePoolを準備しておき、アプリケーション側の要求(PVC)にマッチするものが関連づけられて、永続化ストレージが利用可能になる仕組みでした。 それに対して、Dynamic Storage Provisioning は、大きくストレージ領域を確保しておいて、必要に応じてボリュームを切り出してアプリケーションに割り当てます。

ホールケーキとピースのケーキみたいなイメージとか、袋菓子と小分包装のお菓子みたいなイメージと勝手に思ってる。。。 f:id:akubicharm:20170127122904p:plain

f:id:akubicharm:20170127121219p:plain

OpenShift 3.4 を Azure 上にデプロイ

Master サーバー(InfraNode, etcd も同居) 1台、Node サーバー 3台の構成で GlusterFSコンテナは3台のNodeサーバーにデプロイします。

事前準備

/etc/hosts に各サーバーのFQDNを含むIPアドレスを登録

52.175.xxx.yyy komizo-master.japanwest.cloudapp.azure.com
72.247.116.251 cdn.redhat.com

10.0.1.4 master master.r5xks4ipxxxxxxxxxxxxxxxxxxx.mx.internal.cloudapp.net
10.0.1.5 node01 node01.r5xks4ipxxxxxxxxxxxxxxxxxx.mx.internal.cloudapp.net
10.0.1.6 node02 node02.r5xks4ipxxxxxxxxxxxxxxxxxx.mx.internal.cloudapp.net
10.0.1.7 node03 node03.r5xks4ipxxxxxxxxxxxxxxxxxx.mx.internal.cloudapp.net

必要なパッケージのインストール

USER=`cat rhn-user`
PASSWORD=`cat rhn-password`
POOL_ID=`cat rhn-poolid`

subscription-manager register --username $USER --password $PASSWORD
subscription-manager attach --pool=$POOL_ID

subscription-manager repos --disable="*"
subscription-manager repos \
    --enable="rhel-7-server-rpms" \
    --enable="rhel-7-server-extras-rpms" \
    --enable="rhel-7-server-ose-3.4-rpms"


yum -y install wget git net-tools bind-utils iptables-services bridge-utils bash
-completion
yum -y update
yum -y install atomic-openshift-utils
yum -y install atomic-openshift-excluder atomic-openshift-docker-excluder
atomic-openshift-excluder unexclude

yum -y install docker

sed -i '/OPTIONS=.*/c\OPTIONS="--selinux-enabled --insecure-registry 172.30.0.0/16"' /etc/sysconfig/docker

Ansible プレイブック実行ユーザーの公開鍵を配置

drwx------. 2 ansible ansible 29 Jan 26 10:29 /home/ansible/.ssh
-rw-------. 1 ansible ansible 396 Jan 26 10:29 /home/ansible/.ssh/authorized_keys

Ansible インベントリファイルの準備

サーバーに割り振られたサブネットが、dockerのデフォルトのサブネットと重複するのでosm_cluster_network_cidrで、dockerのサブネットを指定します。

# Create an OSEv3 group that contains the masters and nodes groups
[OSEv3:children]
masters
nodes

# Set variables common for all OSEv3 hosts
[OSEv3:vars]
# SSH user, this user should allow ssh based auth without requiring a password
ansible_ssh_user=ansible

# If ansible_ssh_user is not root, ansible_become must be set to true
ansible_become=true

deployment_type=openshift-enterprise

openshift_master_default_subdomain=52.175.xxx.yyy.xip.io
osm_cluster_network_cidr=10.128.0.0/14

os_sdn_network_plugin_name=redhat/openshift-ovs-multitenant 


# uncomment the following to enable htpasswd authentication; defaults to DenyAllPasswordIdentityProvider
openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true', 'challenge': 'true', 'kind': 'HTPasswdPasswordIdentityProvider', 'filename': '/etc/origin/master/htpasswd'}]

# host group for masters
[masters]
komizo-master.japanwest.cloudapp.azure.com

# host group for nodes, includes region info
[nodes]
komizo-master.japanwest.cloudapp.azure.com openshift_node_labels="{'region': 'infra', 'zone': 'default'}" openshift_public_hostname=komizo-master.japanwest.cloudapp.azure.com openshift_schedulable=true
node01 openshift_node_labels="{'region': 'primary', 'zone': 'east'}"
node02 openshift_node_labels="{'region': 'primary', 'zone': 'west'}"
node03 openshift_node_labels="{'region': 'primary'}"

OpenShift のインストール

 ansible-playbook /usr/share/ansible/openshift-ansible/playbooks/byo/config.yml

Containerized Gluster のデプロイ

事前準備

必要なパッケージのインストール

Masterサーバーに必要なパッケージをインストールします。

subscription-manager repos --enable=rh-gluster-3-for-rhel-7-server-rpms
yum -y install cns-deploy heketi-client

iptables の編集

以下のルールを /etc/sysconfig/iptables に登録します。

-A OS_FIREWALL_ALLOW -p tcp -m state --state NEW -m tcp --dport 24007 -j ACCEPT
-A OS_FIREWALL_ALLOW -p tcp -m state --state NEW -m tcp --dport 24008 -j ACCEPT
-A OS_FIREWALL_ALLOW -p tcp -m state --state NEW -m tcp --dport 2222 -j ACCEPT
-A OS_FIREWALL_ALLOW -p tcp -m state --state NEW -m multiport --dports 49152:49664 -j ACCEPT

変更を反映します。

systemctl reload iptables
iptables -L

GlusterFS用のディスクを追加

3台のNodeサーバーにディスクを追加します。 /dev/sda, /dev/sdb はすでにできているので、新たに追加したボリュームは /dev/sdcになります。

f:id:akubicharm:20170127103111p:plain

  1. ボリュームを追加するVirtual Machineを選択
  2. Disksを選択
  3. Attach Newでディスクの追加
  4. 必要なパラメータを設定して「OK」をクリック

※ここで、Locationは同一リソースグループ内のStorageAccountを選択すること!!

GlusterFSのデプロイ

トポロジーファイルの作成

/usr/share/heketi/topology-sample.json をコピーして今回の環境に合うように編集します。

[topology.json]

{
    "clusters": [
        {
            "nodes": [
                {
                    "node": {
                        "hostnames": {
                            "manage": [
                                "node01.r5xks4ipxxxxxxxxxxxxxxxxxx.mx.internal.cloudapp.net"
                            ],
                            "storage": [
                                "10.0.1.5"
                            ]
                        },
                        "zone": 1
                    },
                    "devices": [
                        "/dev/sdc"
                    ]
                },
                {
                    "node": {
                        "hostnames": {
                            "manage": [
                                "node02.r5xks4ipxxxxxxxxxxxxxxxxxx.mx.internal.cloudapp.net"
                            ],
                            "storage": [
                                "10.0.1.6"
                            ]
                        },
                        "zone": 2
                    },
                    "devices": [
                        "/dev/sdc"
                    ]
                },
                {
                    "node": {
                        "hostnames": {
                            "manage": [
                                "node03.r5xks4ipxxxxxxxxxxxxxxxxxx.mx.internal.cloudapp.net"
                            ],
                            "storage": [
                                "10.0.1.7"
                            ]
                        },
                        "zone": 1
                    },
                    "devices": [
                        "/dev/sdc"
                    ]
                }
            ]
        }
    ]
}

GlusterFSコンテナのデプロイ

GlusterFS のコンテナをデプロイするためのプロジェクトを作成し、特権コンテナとして実行するための権限設定などを行います。

以下の作業はMasterサーバーにてsystem:adminユーザで実行します。

oc new-project storage-project
oadm policy add-scc-to-user privileged -z default

コンテナ版のGlusterFSをデプロイします。

cns-deploy -n storage-project -g topology.json

デプロイの実行結果は https://access.redhat.com/documentation/en/red-hat-gluster-storage/3.1/single/container-native-storage-for-openshift-container-platform/#idm140637724619968を参照してください。

※ここで何かエラーがあって、再実行する場合はoc delete all --allで作成済みPodなどを削除してから再実行します。

Glusterのトポロジを確認します。

export HEKETI_CLI_SERVER=http://heketi-storage-project.52.175.148.91.xip.io
heketi-cli topology info

NodeサーバーでVolumeができていることを確認します。

[root@node01 ~]# pvs
  PV         VG                                  Fmt  Attr PSize PFree
  /dev/sdc   vg_b3dfc1b27ddc928dfe5dab9855d234d7 lvm2 a--  9.87g 6.84g

Dynamic Stroge Provisioningの利用

StorageClassの作成

StorageClassとSecretの定義ファイルを作成します。

[glusterfs-storageclass.yaml]

apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
  name: gluster-container
provisioner: kubernetes.io/glusterfs
parameters:
  resturl: "http://heketi-storage-project.52.175.xxx.yyy.xip.io"
  restuser: "admin"
  secretNamespace: "default"
  secretName: "heketi-secret"

[glusterfs-secret.yaml]

apiVersion: v1
kind: Secret
metadata:
  name: heketi-secret
  namespace: default
data:
  # base64 encoded password. E.g.: echo -n "mypassword" | base64
  key: bXlwYXNzd29yZA==
type: kubernetes.io/glusterfs

StorageClassとSecretを作成します。

oc project storage-project
oc create -f glusterfs-storageclass.yaml
oc create -f glusterfs-secret.yaml

Persistent Storageを利用するアプリケーションのデプロイ

JBoss EAP7 とMySQLを使ったToDoアプリケーションをデプロイします。OpenShiftのインストール時に用意されているテンプレートは、StaticなPersistent Volumeを利用するようになっているので、少し編集してDynamic Persistent Volumeを利用するテンプレートを新しく準備してアプリケーションをデプロイします。

テンプレートの作成

既存の eap70-mysql-persistent-s2i テンプレートをエクスポートします。

oc get templates -n openshift |grep eap70-mysql
oc export templates eap70-mysql-persistent-s2i -n openshift -o json > eap70-mysql-storageclass-s2i.json

metadata.nameをeap70-mysql-persistent-s2iからeap70-mysql-storagclass-s2iに変更します。
labels.templateをeap70-mysql-persistent-s2iからeap70-mysql-storagclass-s2iに変更します。
PersistentVolumeClaimにannotationを追加します。

    "metadata": {
        "name": "eap70-mysql-storageclass-s2i",
        "creationTimestamp": null,
        "annotations": {
            "description": "Application template for EAP 7 MySQL applications with persistent storage built using S2I.",
            "iconClass": "icon-jboss",
            "tags": "eap,mysql,javaee,java,database,jboss,xpaas",
            "version": "1.3.2"
        }
    },

>>> 中略 <<<
        {
            "apiVersion": "v1",
            "kind": "PersistentVolumeClaim",
            "metadata": {
                "labels": {
                    "application": "${APPLICATION_NAME}"
                },
                "name": "${APPLICATION_NAME}-mysql-claim",
                "annotations": {
                    "volume.beta.kubernetes.io/storage-class": "gluster-container"
                }
            },
            "spec": {
                "accessModes": [
                    "ReadWriteOnce"
                ],
                "resources": {
                    "requests": {
                        "storage": "${VOLUME_CAPACITY}"
                    }
                }
            }
        }

>>> 中略 <<<

    "labels": {
        "template": "eap70-mysql-storageclass-s2i",
        "xpaas": "1.3.2"
    }

テンプレートを登録します。

oc create -f eap70-mysql-storageclass-s2i.json -n openshift

ここで、-n openshiftオプションを指定することで、OpenShiftのユーザー全員がこのテンプレートを利用可能になります。このオプションを指定しない場合は、作業中のプロジェクトのみでこのテンプレートが利用可能になります。

アプリケーションのデプロイ

Secretの準備

[eap7-app-secret.json]

{
    "kind": "List",
    "apiVersion": "v1",
    "metadata": {
        "annotations": {
            "description": "Examples that can be installed into your project to allow you to test the EAP template. You should replace the contents with data that is more appropriate for your deployment."
        }
    },
    "labels": {
        "template": "eap7-app-secret"
    },
    "items": [
        {
            "kind": "ServiceAccount",
            "apiVersion": "v1",
            "metadata": {
                "name": "eap7-service-account"
            },
            "secrets": [
                {
                    "name": "eap7-app-secret"
                }
            ]
        },
        {
            "kind": "Secret",
            "apiVersion": "v1",
            "metadata": {
                "annotations": {
                    "description": "Default secret file with name 'jboss' and password 'mykeystorepass'"
                },
                "name": "eap7-app-secret"
            },
            "data": {
                "keystore.jks": "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"
            }
        }
    ]
}

CLIの場合

  1. プロジェクトの作成 oc new-project [プロジェクト名]
  2. Secretの登録 oc create -f eap7-app-secret.json
  3. アプリケーションのデプロイ oc new-app eap70-mysql-storageclass-s2i

WebUIの場合

  1. プロジェクトの作成
    「New Project」ボタンをクリックしてウィザードを開始します。ウィザードの「Name」フィールドにプロジェクト名を入力します。
  2. Secretの登録
    CLIの場合と同様にSecretを作成します。 oc create -f eap7-app-secret.json
  3. テンプレートの選択
    カタログから「Java」–> 「Red Hat JBoss EAP」–> 「eap70-mysql-storageclass-s2i」 を選択
  4. アプリケーションのデプロイ
    「Create」ボタンをクリックしてアプリケーションのデプロイを開始します。

アプリケーションのデプロイの確認

oc get routeで接続先URLを確認しブラウザでアクセスします。 ToDoアプリケーションの画面で、「Summary」と「Description」を入力します。 f:id:akubicharm:20170127114829p:plain

PVの確認

$ oc get pv
NAME                                       CAPACITY   ACCESSMODES   RECLAIMPOLICY   STATUS    CLAIM                      REASON    AGE
pvc-d8621646-e437-11e6-abba-000d3a4075fa   1Gi        RWO           Delete          Bound     app/eap-app-mysql-claim              2m
$ oc get pvc
NAME                  STATUS    VOLUME                                     CAPACITY   ACCESSMODES   AGE
eap-app-mysql-claim   Bound     pvc-d8621646-e437-11e6-abba-000d3a4075fa   1Gi        RWO           4m

Podを再起動して永続化されていることを確認

MySQLのPodを削除し、再起動されるのを待ちます。

$ oc get pods
NAME                    READY     STATUS      RESTARTS   AGE
eap-app-1-0etnn         1/1       Running     0          6h
eap-app-1-build         0/1       Completed   0          6h
eap-app-mysql-1-a16oe   1/1       Running     0          6h
$ oc delete pod eap-app-mysql-1-a16oe 

MySQLのPodが再起動された、再び ToDo アプリケーションにアクセスし、先ほど入力した「Summary」と「Description」が表示されていることを確認します。