読者です 読者をやめる 読者になる 読者になる

OpenShift 3 Online がリリース

OpenShift Online が v3 に対応し、無償で OpenShift の最新版が使えるようになりました。ということで、今回はエントリ方法を紹介します。

OpenShift Onlineとは

OpenShift Onlineは、Red Hat が管理運用している Public な OpenShift Container Platform の環境です。Free Plan も用意されているので、OpenShift を開発者として利用したい場合には非常に便利です。

利用プラン

まずは、Free Planがリリースされました。 Free Plan では、Project(Kubernetes の Namespace を拡張した概念)を一つ作成することができます。Web App, DB, Jenkins を使ったCI/CDを試すには十分でしょう。今後、有償プランもリリースされていく予定です。

使えるアプリケーション

アプリケーションの実行環境を選択するテンプレートがカテゴリ別に用意されています。テンプレートでは、プログラミング言語の単体の実行環境や、Data Store と連携させるテンプレートなどが提供されています。

プログラミング言語

Java
OpenJDK1.8、Red Hatエンタープライズ向けに提供しているTomcat 7/8 であるRed Hat JBoss Web Server、Red Hat JBoss EAP のアップストリーム版である WildFly
Java Script
Node.jsの実行環境と、Node.js + MongoDB の実行環境
.NET
.NET Core 1.1
Perl
Perl5の実行環境と、Dancer サンプルアプリケーション + MySQL の実行環境
PHP
PHP7の実行環境と、CakePHPサンプルアプリケーション + MySQLの実行環境、Laravel サンプルアプリケーション + MySQL の実行環境
Python
Python3.5の実行環境と、Djangoサンプルアプリケーション + PostgreSQLの実行環境
Ruby
Ruby2.3の実行環境と、Railsサンプルアプリケーション+ PostgreSQLの実行環境

テクノロジ

CI/CD
Jenkins2.0の実行環境
Data Store
MariaDB、MongoDB、MySQLPostgreSQL、Redisの実行環境

f:id:akubicharm:20170507151950p:plain

ユーザ認証

ユーザ認証は、Red Hat Customer Portal のアカウントの他に、Github.com、JBoss Developerといった開発者系のWebアカウントのほか TwitterFacebookなどのSNSでの認証も可能になっています。

使ってみよう

パート1 エントリ

(1)OpenShift OnlineのURLにアクセス

https://www.openshift.com/にアクセスし、画面右上部のSIGN UP FOR FREEをクリックします。

f:id:akubicharm:20170508025139p:plain

(2)ログイン画面からサインアップ

画面中央のLOGIN WITH RED HATをクリックしサインアップ画面に遷移します。

f:id:akubicharm:20170508025153p:plain

(3)認証方式を選択します

Red Hatのカスタマーポータルのアカウントでログインする場合

f:id:akubicharm:20170508025544p:plain

 

フィールド名 説明
Email address or other Red Hat Login ID Red Hatのカスタマポータルで利用しているE-Mailアドレス
Password パスワード

SNSのアカウントなどで認証を行う場合は、画面を下にスクロールし連携させたい外部のサービスを選択します。

f:id:akubicharm:20170508025227p:plain

ここからプラン選択のウィザードでプランを選択していきます。

(4)プラン選択

FREE プランなので、画面下部のFREEボタンをクリックします。

f:id:akubicharm:20170508025243p:plain

(5)リージョン選択

ここも選択肢がないので、画面下部のUS East (Virginia)ボタンをクリックします。

f:id:akubicharm:20170508025252p:plain

(6)プランの確認

選択したプランの内容を確認し、画面下部のConfirm subscriptionボタンをクリックします。

f:id:akubicharm:20170508025303p:plain

アカウントプロビジョニング中の画面が表示されます。

f:id:akubicharm:20170508025330p:plain

少し待ってからリロードし、Open Web Consoleボタンをクリックして、OpenShift OnlineのWebコンソール画面に遷移します。

f:id:akubicharm:20170508025644p:plain

 

 

Azure Container RegistryのDocker Imageを指定してデプロイ

せっかくOpenShiftをAzureにデプロイしているので、Azureのサービスを活用した仕組みを作ってみました。

f:id:akubicharm:20170127194249p:plain

Azure Container Registryからコンテナイメージを取得するようにしておけば、危険かもしれない野良コンテナを持ち込まれないようにすることも可能になります。 また、社内のコンテナリポジトリで標準化されたコンテナイメージを配布する仕組みがあれば、OpenShift上でもローカルで実行する場合でも環境を統一することができます。

Azure Container Registry に Wildfly イメージを登録

docker hub から wildfly のコンテナイメージを取得して、Azure Container Repository に pushします。

docker pull docker.io/jboss/wildfly 
docker tag docker.io/jboss/wildfly xxxregistry-on.azurecr.io/komizoregistry/wildfly
docker login xxxregistry-on.azurecr.io
docker push xxxregistry-on.azurecr.io/komizoregistry/wildfly

OpenShift にアプリケーションをデプロイ

今回デプロイする Wildfly のコンテナイメージは、root ユーザーで実行されるようになっているので、特権コンテナとして実行するための設定と、Azure Container Registry へのアクセスに認証が必要になるのでsの設定も必要です。

プロジェクトの作成

oc new-project extrepo

Secret の作成

Azure Container Registory にアクセスするための認証情報を登録します。 docker login すると、ホームディレクトリの配下に認証情報のファイルが作成れます。 Docker version 1.12.5, build 047e51b/1.12.5 では、~/.docker/config.json ファイルです。

この認証情報を利用して、OpenShift から Azure Container Registry にアクセスするためのSecretを作成します。

oc secrets new external-registry .dockerconfigjson=docker-config.json

特権コンテナの実行を許可

OpenShiftのMasterサーバーで、クラスタ管理者(system:admin)でポリシーを設定します。

oadm policy add-scc-to-group anyuid system:serviceaccounts:extrepo

Secret を設定

oc secrets add serviceaccount/default secrets/external-registry --for=pull

コンテナイメージのpullにsecretが設定されたことを確認します。

$ oc describe serviceaccount/default
Name:       default
Namespace:  extrepo
Labels:     <none>

Image pull secrets: default-dockercfg-8tmb3
                    external-registry

Mountable secrets:  default-token-miful
                    default-dockercfg-8tmb3

Tokens:             default-token-c36r2
                    default-token-miful

コンテナイメージを指定してデプロイ

アプリケーションをデプロイして、URL でアプリケーションを公開できるようにRouteを作成します。

oc new-app --docker-image=xxxregistry-on.azurecr.io/komizoregistry/wildfly:latest
oc expose wildfly

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

OpenShift を活用してデリバリのリードタイムの短縮した事例

The fast-moving monolith: how we sped-up delivery from every three months, to every week – RHD Blog で紹介されている KeyBankでのリードタイム短縮のチャレンジを要約してみました。

リリースサイクルを3ヶ月から1週間へ

ここで紹介されているのは、KeyBankのリリースサイクルが四半期ごとから毎週になったという話です。

  • リリースサイクルを短縮するにあたっては、WebSphereからTomcatへの移行と、コンテナのランタイムとしてOpenShiftの採用

  • これらの変革を最重要プロジェクト(The digital channel modernization)の一環として実施

課題

  • SLAを満たすようにメンテナンスするにはコストがかかる、典型的なモノリシックなアプリケーション
  • 四半期リリースは、コストが高いしリスクも高く、週末の一大イベント (もちろん月曜日にはちゃんと使える状態になっていなくてはならなりません!!)

Motivation

担当者が色々と調べているときに、カンファレンスで Netflixのプレゼンを見て、自分たちよりも2-3倍の規模なのに、リリースに関わるメトリックは自分たちのそれをはるかに超えていることを知りました。 そして、銀行のDigital Channel にはウィークリのリリースは合理的であると考えました。

このプロジェクトでやったこと

  • 古いアプリケーションをモダンなモバイルでも利用可能なウェブアプリケーションにすること
  • プレゼンテーションレイヤとビジネスロジックレイヤを分離して、CI/CD が実現しやすいアーキテクチャにすること
  • 自動化を推し進めてリードタイムを短縮すること
  • 時間を浪費していた承認プロセスを削減すること

アプリケーションアーキテクチャ

対象のアプリケーション

かつて流行っていた構成でした。

新しいアーキテクチャ

  • AngularJS と Ionic を採用

このプロジェクトを進めていく過程で直面した課題

Ops との戦い

アーキテクチャを変更しJAX-RS を使うためには、JDK1.7が必要でした。しかし、Ops チームはやりたがりません(寝た子は起こすななので)。しかし、 JDK1.6のサポートライフサイクルが半年で終わってしまうとサポートされた環境でシステムを運用したい Ops もやらざるを得なくなりました。

Dev vs Ops

Dev は正しい方法で自分たちのニーズを伝えられず、Opsはシステムがサービスを継続できる状態を保つことが気がかりで、新しいことにチャレンジしたがりません。 この板挟みでモデレートすることに苦労したようです。

必要なプラットフォーム

デリバリチームは、自分で必要なインフラはセルフサービスでプロビジョニングできるべきと悟り、それを実現するにはプライベートなクラウドインフラが必要という結論に達し、それには Kubernetes が最適となりました。

最適なプラットフォームはOpenShift

WebSphere で動いている古いMVCモデルのアプリケーションをモダンな技術に移行することは技術的には問題ありませんでした。しかし、以前として課題は、週次のリリースとインフラのセルフプロビジョニングと普遍のインフラの実現をどうするかということでした。

Opsチームはセルフサービスでプロビジョニングされた環境を保証しなくてはならないので、サポートのあるOpenShiftを採用しました。

自動化の促進

Jenkinsのパイプラインを活用して CI を実現し、QA環境でのテストが終わったらプロダクションにリリースできるようにしました。 しかし、プロダクションに持ち込むために、たくさんの承認プロセスがありましたが、これは時間を浪費する作業だったので、OpenShiftの中だけで済むようなコンポーネントのリリースは、承認プロセスを不要にしました。 ここまで自動化とプロセスの見直しを行いましたが、最後に残った課題は、リグレッションテストの自動化です。手動でのテストでは毎週のリリースには間に合わないので、テストツールを導入して自動化を可能としました。

まとめ

このプロジェクトを実施した結果、毎週のリリース時にサービスを止めることなく、ローリングアップデートが可能となりました。 サービスの提供環境としても、オートスケールの機能も活用して、アクセスが急激に増えた場合にも対応できるようになりました。

OpenShift の導入によって、リリースサイクルの短縮とサービス提供のSLAの向上が両方できた良い事例でした。

Horizontal Pod Autoscaler

Kubernetes Advent Calendar 2016。投稿が遅れてしまいましたが、コンテナを本番サービスで利用する場合にすごく便利ではないかなと思われる Horizontal Pod Autoscaler について紹介します。

Horizontal Pod Autoscalerとは

f:id:akubicharm:20161216145111p:plain

Horizontal Pod Autoscaler(HPA)はPodに割り当てられた CPU の使用率にしたがって、Pod の数を増減させる仕組みです。この仕組みを使うと Pod として動かしているアプリケーションが高負荷になった場合に、スケールアウトして負荷分散が可能になります。 デフォルトでは 30 秒ごとに負荷状況がチェックされ、スケールアウト/ダウンが実行されます。

ここまでで想像ができるかもしれませんが、CPU の使用率にしたがってPodを増減させるということは、CPU のメトリクスを収集する機能が実装されていなければいけません。Kubernetes では Heapster を使って CPU の使用を収集します。

OpenShift でのメトリクス収集とHPAの仕組み

メトリクス収集の仕組み

OpenShiftでは、Heapsterを使ったメトリクスの収集に加えて、Hawkular MetricsCassandra を利用してメトリクスの蓄積と可視化を行っています。 Heapster, Hawkular Metrics, Cassandra もそれぞれコンテナとして OpenShift 上で実行されます。

f:id:akubicharm:20161216144645p:plain

メトリクス収集の仕組みを有効にしておくと、OpenShift 管理コンソールではCPU, Memory, Network IO の状況を図のような折れ線グラフで参照することが可能になります。 f:id:akubicharm:20161216144634p:plain

HPA の仕組み

OpenShift は Kubernetes を活用した Container 型のアプリケーションプラットフォームですので、HPA の仕組みも Kubernetes の HPA と同様です。

HPA が Heapster から CPU の利用状況を、Replication Controller から稼働中のレプリカ数を取得します。CPU の使用率が閾値を超えている場合にはレプリカ数を増やし、CPU の使用率が閾値を下回った場合にはレプリカ数を減らします。また、レプリカ数が変更された場合には、 Replication Controller のステータスもアップデートされます。

f:id:akubicharm:20161216144639p:plain

OpenShift では、CPU、Memory のリソース割り当ては、Pod のデプロイ方式を定義した Deployment Config で行います。例えば、CPU の割り当てが 50m 〜 100m、メモリの割り当てが 100Mi 〜 200Mi の場合には、Deployment Config は次のようになります。

        resources:
          limits:
            cpu: 100m
            memory: 200Mi
          requests:
            cpu: 50m
            memory: 100Mi

レプリカ数を 1 〜 4 個、CPU 使用率の閾値を 80% とした場合、HPA は次のようになります。

spec:
  maxReplicas: 4
  minReplicas: 1
  scaleTargetRef:
    apiVersion: extensions/v1beta1
    kind: DeploymentConfig
    name: php
  targetCPUUtilizationPercentage: 80

OpenShift での設定

OpenShift でメトリクス収集を有効にする場合は、Heapster, Hawkular Metrics, Cassandra をそれぞれデプロイするのではなく、Metrics Deployer という、Metrics収集プラグインをセットアップするためのコンテナに環境設定を任せてしまうことができます。

設定方法を紹介する前に、ちょっとはまったことを...

今回は OpenShift Origin で環境構築をしたので、Kubernetes と Heapster のバージョンの組み合わせには注意が必要でした。

Metrics Deployer は Docker Hub から origin-metrics-deloyer のコンテナイメージ(docker.io/openshift/origin-metrics-deployer)を Pull してきて利用するのですが、latest のイメージだと、Kubernetes と Heapster のAPIバージョンが不一致となってしまい、Metrics 収集機能はりようできるけれでも HPA がちゃんと動作しませんでした。正しい組み合わせは、

Kubernetes Heapster
ver 1.3 ver 1.1
ver 1.4 ver 1.2

Kubernetes 1.3 で heapster 1.2 を使った場合には、ログ(journal)に以下のように unmarshall できないというエラーメセージが出ていました。

W1214 05:04:48.140190  112006 horizontal.go:99] Failed to reconcile hello: failed to compute desired number of replicas based on CPU utilization for DeploymentConfig/test/hello: failed to get CPU utilization: failed to get CPU consumption and request: failed to unmarshall heapster response: json: cannot unmarshal object into Go value of type []v1alpha1.PodMetrics

メトリクスプラグインの設定

OpenShift Originのインストールは https://docs.openshift.org/latest/install_config/install/advanced_install.html に従って実施します。

メトリクス収集機能は openshift-infra というProjectにデプロイします。

Project : Kubernetes の Namespace を拡張した概念

1. Metrics URL の追加

OpenShift の Master サーバの定義ファイル /etc/origin/master/master-config.yamlに metricsPublicURL を追加します。 Hawkular のコンテナも他のアプリケーションと同様に OpenShift にデプロイされるので、他のアプリケーションと同様に OpenShift の Route 経由でアクセス可能な URL を指定します。

assetConfig:
  < 中 略 >
  metricsPublicURL: "https://hawkular-metrics.192.168.1.1.xip.io/hawkular/metrics"
  < 中 略 >
routingConfig:
  subdomain:  "192.168.1.1.xip.io"

2. Service Account の作成

Metrics 収集のデプロイと実行に必要な Service Accountを作成します。

oc project openshift-infra
oc create -f - <<API
apiVersion: v1
kind: ServiceAccount
metadata:
  name: metrics-deployer
secrets:
- name: metrics-deployer
API

3. ポリシーの設定

先ほど作成した metrics-deployer、heapster, hawkular 用の Service Account に権限を付与します。

Metrics Deployer 用の Service Account に、openshift-infra プロジェクトの edit 権限を付与します。

oadm policy add-role-to-user \
    edit system:serviceaccount:openshift-infra:metrics-deployer

Heapster 用の Service Account に、cluster-reader 権限を付与します。

oadm policy add-cluster-role-to-user \
    cluster-reader system:serviceaccount:openshift-infra:heapster

Hawkular 用の Service Account に openshift-infra プロジェクトの view 権限を付与します。

oadm policy add-role-to-user view \
        system:serviceaccount:openshift-infra:hawkular \
        -n openshift-infra

4. metrics-deployer の secrets を作成

oc secrets new metrics-deployer nothing=/dev/null -n openshift-infra

5. metrics-deployer の準備

kubernetes v1.3 を使っている場合には、heapster の最新版を使ってしまうと、API バージョンが不整合になってしまいます。 そこで、既存のテンプレートを少し修正して利用します。

まず、既存のテンプレートを使って metrics-deployer をデプロイするための yaml ファイルを生成します。ここでは、簡易的にデプロイするために永続化ストレージを使わないオプション USE_PERSISTENT_STORAGE=false もつけておきます。

oc get templates -n openshift
oc process metrics-deployer-template -v HAWKULAR_METRICS_HOSTNAME=hawkular-metrics.192.168.1.1.xip.io -v USE_PERSISTENT_STORAGE=false -n openshift > metrics.yaml

Template : OpenShift にアプリケーションをデプロイするための雛形。OpenShift の Cluster 全体で利用するものは openshift プロジェクトに保持されている。

6. YAML ファイルの編集

生成された metrics.yaml ファイルを編集します。 IMAGE_VERSION を latest から v1.3.1 に変更します。

{
    "name": "IMAGE_VERSION",
    "value": "v1.3.1"
},

利用する metrics-deployer の Image Tag を latest から v1.3.1 に変更します。

"image": "openshift/origin-metrics-deployer:v1.3.1",

7. Metrics プラグインのデプロイ

編集した YAML ファイルを利用して、metrics-deployer をデプロイします。

oc create -f metric.yaml

あとは、気長に待ちましょう。。。

8. アプリケーションの設定

https://github.com/akubicharm/OpenShiftv3HandsOn/blob/master/3.3/autoscale/autoscale.md を参考に、やってみてください。

HPA で CPU の使用率を見ていくと、こんな風に使用率が表示されます。

oc get hpa -n test -w
NAME      REFERENCE              TARGET    CURRENT   MINPODS   MAXPODS   AGE
php       DeploymentConfig/php   10%       0%        1         4         21h

NAME      REFERENCE              TARGET    CURRENT   MINPODS   MAXPODS   AGE
php       DeploymentConfig/php   10%       168%      1         4         21h
php       DeploymentConfig/php   10%       168%      1         4         21h
php       DeploymentConfig/php   10%       700%      1         4         21h
php       DeploymentConfig/php   10%       700%      1         4         21h

終わりに

HPA のような仕組みで簡単にアプリケーションをスケールアウトできるのは、Container & Kubernetes だからこそですね。HPA を設定しておけば、急なアクセス過多になった場合でも滞りなくサービスを持続することができますので、運用の利便性も高くなりますので、ぜひ、試してみてください。

OpenShift Online Next Generationがやってきたー

Red Hatが管理・運営をしているPublicなPaaS環境であるOpenShift Onlineに、待望のOpenShift v3対応のプレビュー版がリリースされました。 環境があったらOpenShift v3 を試してみたい!と考えている方必見です。

利用方法

前提条件

  • Github.com のアカウントがあること。

Github.comのアカウントがない方はまずアカウントを登録しましょう。

利用登録登録

  1. https://www.openshift.com/devpreview/register.html にアクセスします f:id:akubicharm:20160617140444p:plain
  2. Login with GitHub ボタンをクリックします f:id:akubicharm:20160617134419p:plain

  3. github.com のアプリケーション認証サイトで認証可能にします f:id:akubicharm:20160617134607p:plain

  4. OpenShift Onlineの登録フォームで必要事項を入力して「REGISTER」ボタンをクリックします f:id:akubicharm:20160617134732p:plain このとき、Github Username, Github ID はプリセットされています。

  5. あとはアカウント作成完了のメールを待ちましょう f:id:akubicharm:20160617134900p:plain

メールに、OpenShift Online (v3 版)のURLがあるのでアクセスしましょう。

アプリケーションをデプロイしよう

利用登録ができたら、早速アプリケーションをデプロイしてみましょう。ここではWebUIを使ったアプリケーションのデプロイ方法をご紹介します。

OpenShiftのクラスタ内では、プロジェクト名が一意である必要があります。もしもすでに他の人が使っている名前を指定すると、こんな風にエラーになります。 f:id:akubicharm:20160617134945p:plain

OpenShiftは、テンプレートを使って簡単にアプリケーションの実行環境を構築することができます。テンプレートはベースとなるコンテナイメージ、ビルド方式、デプロイ方式などを定義することができます。 ここでは、JBoss EAPのテンプレートを使って、JBoss のサンプルアプリケーションをデプロイします。

https://github.com/jboss-developer/jboss-eap-quickstarts/tree/6.4.x/kitchensink

  1. 「LOGIN WITH GITHUB」ボタンをクリックしてログイン f:id:akubicharm:20160617140444p:plain

2.「New Project」ボタンをクリックして、プロジェクト作成を開始 f:id:akubicharm:20160617135013p:plain

  1. Nameでプロジェクト名を指定して「Create」ボタンをクリック f:id:akubicharm:20160617135032p:plain

  2. テンプレート一覧から「jboss-eap64-openshift:1.3」を選択 f:id:akubicharm:20160617140947p:plain

  3. Nameにアプリケーション名を入力、「Try it」をクリックして、Git Repository URLのテキストフィールドにGithubリポジトリを指定 f:id:akubicharm:20160617135245p:plain ※アプリケーション名はプロジェクト内で一意であれば良いので、好きな名前をつけましょう。

  4. 「Create」ボタンをクリックして、アプリケーションのビルド&デプロイの開始 f:id:akubicharm:20160617135317p:plain

  5. 「Continue to deploy」をクリックして Overview 画面を表示 f:id:akubicharm:20160617135441p:plain f:id:akubicharm:20160617135645p:plain

  6. デプロイが終わったら、アプリケーションへのリ ンクをクリックしてアプリケーションを利用 f:id:akubicharm:20160617135722p:plain

f:id:akubicharm:20160617135742p:plain

FAQ(抜粋)

https://www.openshift.com/devpreview/register.htmlにFAQがありますので、詳細はそちらを参照してください。

  • 30日でアカウントは失効しデプロイしたアプリケーションも消滅します。再び利用したい場合は、再度、登録フォームで登録します。
  • 1プロジェクトにつき 2GiBメモリ、4CPU Core、 1GiBの永続化ストレージx2 のリソースが利用可能です。
  • 2016/6/16 時点で、利用できる言語やミドルウェアは Node.js(0.10)、 PHP(5.5, 5.6)、Python(2.7, 3.3, 3.4)、Ruby(2.0, 2.2)、 Perl(5.16, 5.20), Java(6, 7, 8, EE)とJBoss EAPJBoss Web Server が利用可能です。 利用できるデータベースは、MongoDB(2.4, 2.6)、MySQL(5.5, 5.6)と PostgreSQL(9.2, 9.4)です。
  • コンテナ内のプロセスを root ユーザ(PID=1)で実行するコンテナは、セキュリティの制限により利用できません。

OpenShift Enterprise 3 on Microsoft Azure - RHELインストール編 -

準備するもの

  • Azure のアカウント
  • Red Hat Network ID
  • RHEL 7.2 KVM イメージ

準備

1.Cloud Accessの登録

(1)azureのサブスクリプションの確認

f:id:akubicharm:20160114233028p:plain

(2)Red Hat Cloud Accessのエンロールを開始

http://www.redhat.com/en/technologies/cloud-computing/cloud-access にアクセスして、Cloud Access の登録をします。 画面左下の "ENROLL" をクリックします。 f:id:akubicharm:20160114225017p:plain

(3)登録

CloudProviderとMicrosoftSubscriptionNumberを入力します。

|Name|Value| |---|---| |CloudProvicer|Microsoft Azure| |MicrosoftSubscriptionNumber|(3)で確認したazureのサブスクリプション番号| |ProductName|azureで利用するRed Hatサブスクリプションを選択| |Quantity|導入するサブスクリプションの本数を入力| f:id:akubicharm:20160114233203p:plain

(4)登録完了

f:id:akubicharm:20160115012823p:plain

VDH イメージ

Linux VHD の作成とアップロード | Microsoft Azure に従って、アップロードするイメージの作成。

Kickstartを使いたかったのですが、Hyper-V Manager の使い方がわからないので断念。

(1)KVMイメージをダウンロード

https://access.redhat.com/downloads/content/69/ver=/rhel---7/7.2/x86_64/product-software から、KVM イメージをダウンロードします。

(2)qcow2からvdhの変換

Linux VHD の作成とアップロード | Microsoft Azure に従って guestfish で、root パスワードをchangemeに変更後、VDHへ変換。

virt-installKVM イメージをインポート

sudo virt-install \
--connect qemu:///system \
--ram 1024 -n rhel_72_azure -r 2048  \
--os-type=linux \
--os-variant=rhel5  \
--disk path=/home/komizo/azure/rhel-guest-image-7.2-20151102.0.x86_64.qcow2,device=disk,bus=virtio,format=qcow2
  \
--vcpus=2 \
--vnc \
--noautoconsole  \
--import

virsh で仮想OSの起動

virsh -c qemu:///system
console rhel_72_azure

Azure CLIのイストール

Azure SDK とツールのダウンロード | Azure からAzure CLI ツールをダウンロード

RHELVM作成

(1)VDHイメージのアップロード

Linux VHD の作成とアップロード | Microsoft Azure の手順2に従って、イメージをアップロード

azure vm image create rhel-7.2 --location "Japan East" --os Linux rhel-guest-image-7.2-20151102.0.x86_64.vhd 

1回目は container がないとエラーになるので、もう一度やったら出来ているっぽい。

azure vm image list で一覧を表示すると、rhel-7.2 が表示されます。WebUIでは表示されないっぽい。

$ azure vm image list |grep rhel-7.2
data:    rhel-7.2                                                                                                              User      Linux    undefined 

(2)仮想OSの作成

azure vm create <仮想マシン名>.cloudapp.net rhel-7.2 --vm-size "Medium" guest --location "Japan East"
info:    Executing command vm create
+ Looking up image rhel-7.2                                                    
Enter VM 'guest' password:******** ← @Dmin123
Confirm password: ********
+ Looking up cloud service                                                     
info:    cloud service <仮想マシン名> not found.
+ Creating cloud service                                                       
+ Creating VM                                                                  
info:    vm create command OK

ここで、location か affinity-group の指定が必要なので、azure vm location listazure account affinity-group list で確認します。

(3) SSH の有効化

仮想OS起動したのに、SSHできないーと悩んでいたら、SSHのエンドポイントがありませんでした。自分で追加する必要があります。

Webコンソールで「仮想マシン(クラッシック) > [仮想サーバ名] > 設定 > エンドポイント」を指定し、エンドポイントに SSH ようの 22 番ポートを指定。

f:id:akubicharm:20160114232628p:plain

(4)追加ユーザの作成

Webコンソールで「仮想マシン(クラッシック) > [仮想サーバ名] > 設定 > ユーザ」を指定し、ユーザと認証方式を設定します。

(5)ログイン

パスワード認証にした場合は、ユーザと仮想マシンを指定して ssh を実行します。

ssh -l <ユーザ名> <仮想マシン名>.cloudapp.net>

参考

1.Linux VHD の作成とアップロード | Microsoft Azure 2.Create and upload a Linux VHD | Microsoft Azure 3.Use the Azure CLI with Service Management | Microsoft Azure 4.Use SSH on Linux and Mac | Microsoft Azure