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 は、大きくストレージ領域を確保しておいて、必要に応じてボリュームを切り出してアプリケーションに割り当てます。
ホールケーキとピースのケーキみたいなイメージとか、袋菓子と小分包装のお菓子みたいなイメージと勝手に思ってる。。。


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になります。

- ボリュームを追加するVirtual Machineを選択
- Disksを選択
- Attach Newでディスクの追加
- 必要なパラメータを設定して「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の場合
- プロジェクトの作成
oc new-project [プロジェクト名] - Secretの登録
oc create -f eap7-app-secret.json - アプリケーションのデプロイ
oc new-app eap70-mysql-storageclass-s2i
WebUIの場合
- プロジェクトの作成
「New Project」ボタンをクリックしてウィザードを開始します。ウィザードの「Name」フィールドにプロジェクト名を入力します。 - Secretの登録
CLIの場合と同様にSecretを作成します。oc create -f eap7-app-secret.json - テンプレートの選択
カタログから「Java」–> 「Red Hat JBoss EAP」–> 「eap70-mysql-storageclass-s2i」 を選択 - アプリケーションのデプロイ
「Create」ボタンをクリックしてアプリケーションのデプロイを開始します。
アプリケーションのデプロイの確認
oc get routeで接続先URLを確認しブラウザでアクセスします。
ToDoアプリケーションの画面で、「Summary」と「Description」を入力します。

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」が表示されていることを確認します。