最近、OpenShift と Kubernetes の違いを尋ねられた私は、Kubernetes にとっての Red Hat OpenShift は、Linux カーネルにとっての Red Hat Enterprise Linux に例えられると思いつきました。これらのテクノロジーに根本的な違いはありません。むしろ、大体において一方のテクノロジーはもう一方のテクノロジーに包含されます。
具体的に言うと、いくつかの重要で有用な違いがあるものの、Red Hat OpenShift は分散型の Kubernetes とみなせます。このチュートリアルではこうした違いを指摘して説明している優れたブログ記事を蒸し返すのではなく (例えば、「10 most important differences between OpenShift and Kubernetes」、「What’s the difference between Kubernetes and OpenShift?」といったブログ記事があります)、いくつかの相違点を際立たせるような演習を行います。これらの相違点とは、ルートとルーター、そしてシンプルながらも有用なタッチレス・パイプラインを可能にする BuildConfig
/ImageStream
/DeploymentConfig
の三要素です。このチュートリアルの例では Red Hat OpenShift on IBM Cloud を使用します。
前提条件
このチュートリアルでは、読者に Kubernetes の基礎知識があり、OpenShift クラスターを作成済みであることを前提とします。チュートリアルの例で使用するクラスターは Red Hat OpenShift on IBM Cloud 上に作成されているものです。また、サンプル・アプリケーションを構成するファイルが GitHub リポジトリー内に保管されていて、Webhook を追加できることも前提とします。さらに、コマンド・ライン・インターフェースからターゲット OpenShift クラスターを制御できるよう、ローカル環境に Calico をインストールできることも前提条件となります。
まず、アプリケーションをデプロイする OpenShift クラスターを作成しておいてください。このチュートリアルには、1 つのゾーン内で 3 つのワーカー・ノードを使用できる基本的なクラスターが作成されていれば十分です。クラスターにアクセスした後、OpenShift Web コンソールのボタン (右上にある青色のボタン) をクリックすると、クラスターの Web コンソールが開くはずです。以下に、Red Hat OpenShift on IBM Cloud で開いたクラスター Web コンソールのスクリーン・キャプチャーを示します。
クラスター Web コンソールの「Access (アクセス)」タブに、OpenShift CLI ツールのセットアップ方法に関する情報と手順も記載されています。OpenShift CLI ツールは、クラスターにログオンする際や、クラスターの機能を制御する各種のコマンドを実行する際に使用します 。
所要時間
「前提条件」に記載されている OpenShift クラスターの作成、GitHub リポジトリーの準備、Calico のインストールのすべてが完了していれば、このチュートリアルの手順は約 30 分で完了できます。チュートリアルを読むだけであれば、所要時間は 10 ~ 15 分です。
シンプルなパイプラインを作成する
サンプル・アプリケーションの単純なシナリオで、ルートとルーターの仕組みと、OpenShift の BuildConfig
/ImageStream
/DeploymentConfig
機能を説明します。このシナリオで必要となるのは、GET REST
リクエストを取り、シンプルなメッセージで応答するシンプルな HTTP サーバーです。この HTTP サーバーには外部からパブリック URL でアクセスできる必要があります。また、このサーバーの Git リポジトリーに変更をプッシュするだけで、サーバーのコードを更新して実行中のインスタンスに反映できるようでなければなりません。
このチュートリアルでは、サーバーのコードが格納されている Git リポジトリーが準備されていることを前提とします。リポジトリーに格納するファイルは少なくとも 3 つあります。ファイルのうちの 1 つは、以下に示すようなサーバーの実際のコードが含まれているものです。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Refreshes the k8s config, obtains the id-token, and automates the following:
# curl -X POST -H "Kube-Id-Token: <token> -d payload --resolve httpserver.npspoc.com:443:169.48.64.46 <url> --cacert <sslcertfile>
# Notice that as long as the host/ip-address pair is in /etc/hosts, --resolve is not needed, and requests does not need to deal with it
import logging
import argparse
import json
import subprocess
import requests
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('--url', default='https://simple-http-server-route-default.voc-sandbox-cluster-7d4bdc08e7ddc90fa89b373d95c240eb-0001.us-east.containers.appdomain.cloud', help='url is set to (default: %(default)s)')
parser.add_argument('--sslcertfile', default='/Users/isilval/Devt/ssl-cert/CertBundle.p7b', help='sslcertfile is set to (default: %(default)s)')
return parser.parse_args()
if __name__ == '__main__':
config = vars(parse_args())
logger.info(json.dumps(config))
headers = {'Content-Type' : 'application/json'}
response = requests.get(config['url'], headers=headers, verify=False)
logger.info('response code: {}, message: {}'.format(str(response.status_code), response.text))
他の 2 つのファイルには、OpenShift がアプリの Docker イメージを作成する際に使用する Dockerfile、HTTP サーバーを起動するスクリプトをそれぞれ含めます。以下に例を示します。
FROM python:3
COPY simple_http_server.py .
COPY start_simple_http_server.sh .
COPY ssl ./ssl
CMD [ "sh", "./start_simple_http_server.sh" ]
#!/usr/bin/sh
python simple_http_server.py
アプリを管理するパイプラインは、Git リポジトリーから OpenShift の Kubernetes ポッド内で実行中のインスタンスにシームレスにコードを渡す必要があります。このパイプラインを作成するには、まず、リポジトリー内の 3 つのファイルを基に Docker イメージをビルドする BuildConfig
を作成します。
BuildConfig
では各種のトリガー (Generic、GitHub、ConfigChange など) を 1 つ以上使用することができます。このチュートリアルで必要となるのは、GitHub トリガーです。GitHub トリガーは、リポジトリーに対して (プッシュなどによって) 新しいコミットが行われるたびに、イメージのビルドを開始します 。この例では、GitHub サーバー、プロジェクト、アプリケーションのコードがあるリポジトリーを指定する BuildConfig
オブジェクトのソースも Git です。
OpenShift が Git リポジトリーに接続するために必要となる認証情報を格納する sourceSecret
も用意する必要があります。認証情報一式を指定するには BuildConfig
タイプの .yaml
ファイルを使用できます。それとは別に、OpenShift CLI では、必要となる重要な値を取って .yaml
ファイルを作成する new-build
コマンドも使用できます。このコマンドの例を以下に示します。
oc new-build --name=simple-http-server-bc git@github.ibm.com:MarketingSystems/OpenShiftTest.git --source-secret gitsecret
上記のコマンドに含まれる gitsecret は、以下のコマンドを使用して作成します。
oc create secret generic gitsecret --from-file=ssh-privatekey=<ssh-private-key-file> --type=kubernetes.io/ssh-auth
GitHub が実際に BuildConfig
に通知して目的のビルドをトリガーさせるには、GitHub に Webhook も用意する必要があります。この Webhook を使用して、OpenShift と BuildConfig
への接続を確立するという仕組みです。Webhook 内で使用する特定の URL は、BuildConfig
に対応する OpenShift コンソール・ページから取得できます (以下の例を参照)。
作成される BuildConfig
からは、ImageStream
が出力されます。デフォルトのタグは、new-build
コマンドで BuildConfig
に指定した名前です。もう 1 つ注目する点として、OpenShift は BuildConfig
のストラテジーを dockerStrategy
に定義するために、ベース・イメージのソースとして、Dockerfile で指定されている ImageStream
を使用します。この追加の ImageStream
も作成されて、Dockerfile 内のベース (つまり FROM
) イメージの名前でタグ付けされます。作成された ImageStreams
イメージを確認するには、CLI を使用することができます (以下の例を参照)。
使用される Docker リポジトリーは、OpenShift によって管理される、クラスター内部のリポジトリーです。
ここまでのところで、ImageStream
が何を表すのかについて概要をつかめたことでしょう。ImageStream は内部 Docker レジストリーまたはリポジトリーに格納された一連のイメージ・バージョンであり、BuildConfig
でも DeploymentConfig
でもシンクおよびソースとして使用できます。パイプラインの 2 番目のステップはこのオブジェクトによって処理されるため、明示的に作成しなければならないものはありません。
パイプラインの 3 番目のステップでは、管理可能なポッドにアプリをデプロイして実行します。ただし、通常の Kubernetes でのように通常の Deployment
オブジェクトを使用してポッドへのアプリのデプロイを管理するのではなく、OpenShift では DeploymentConfig タイプのオブジェクトを使用できるようになっています。Tomasz Cholewa 氏が指摘しているように、「OpenShift では Kubernetes とは異なるデプロイメントの管理方法を選択」し、「コントローラーではなく、プロセス全体を制御する専用のポッドに基づく高度なロジックによって」その管理方法を実装しています。
YAML 内で指定される DeploymentConfig
は、通常の Deployment
とかなり似ていて、同じく containers セクション内でアプリのイメージへの Docker レジストリーでのパスを指定します。このアプリのイメージへの Docker レジストリーでのパスを指定するのは、BuildConfig
の出力として作成された ImageStream
に含まれる Docker リポジトリー・アイテムです。ただし、DeploymentConfig
内の triggers
要素には重要な違いがあります。トリガーには ConfigChange
や ImageChange
といったさまざまなタイプがありますが、このチュートリアルで重要となるトリガー・タイプは ImageChange
です。
DeploymentConfig
に含まれる要素のうち、重要なのは labels
要素です (メタデータの一部となっています)。この要素は、Deployment
を含む他のアーティファクト・タイプにも共通します。どのラベルを使用するかに関わらず、そのラベルが、アプリを公開するために使用する Service
に対して DeploymentConfig
を特定する際の鍵となります。このチュートリアルでは例として、以下の DeploymentConfig
を使用します。
apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
name: simple-http-server-dep
namespace: default
labels:
app: simple-http-server-dep
spec:
template:
metadata:
labels:
name: simple-http-server-dep
app: simple-http-server-dep
spec:
containers:
- name: simple-http-server-ctr
image: 'docker-registry.default.svc:5000/default/simple-http-server-bc:latest'
ports:
- containerPort: 80
protocol: TCP
replicas: 1
triggers:
- type: "ConfigChange"
- type: "ImageChange"
imageChangeParams:
automatic: true
containerNames:
- "simple-http-server-ctr"
from:
kind: "ImageStreamTag"
name: "simple-http-server-bc:latest"
strategy:
type: Rolling
paused: false
revisionHistoryLimit: 2
minReadySeconds: 0
以下のコマンドを使用して、DeploymentConfig
ファイルを適用します。
oc apply -f simple-http-server-dc.yaml
このコマンドによって、アプリ用の実行中コンテナーを格納するポッドが作成されます。作成されたポッドを確認するには、デプロイメントのレプリカに関するページの下部を見てください。
アプリを外部に公開する
ここまでの手順でシンプルな HTTP サーバーが稼働中の状態になりました。けれどもこのサーバーには、サーバーのコンテナーを実行するポッドに接続されたターミナルから内部でアクセスすることしかできません。
アプリを外部に公開するのは同じく簡単なことです。Service
を使用してアプリを公開し、実行中のコンテナーにトラフィックを転送するルーターにアプリを接続するルートを作成するだけで、外部からでもアプリに接続できるようになります。Service
を作成するには、通常の Kubernetes で行う場合と同じ方法で YAML ファイルを定義できます。この YAML ファイルは、以下のような内容になります。
apiVersion: v1
kind: Service
metadata:
name: simple-http-server-service
namespace: default
labels:
name: simple-http-server-service
spec:
ports:
- name: http
port: 80
targetPort: 8089
selector:
app: simple-http-server-dep
ここには注目すべき重要なアイテムがいくつかあります。具体的には、外部ポートを定義する ports
要素と、アプリがコンテナー内で listen する targetPort
要素です。また、実行中のアプリを管理する DeploymentConfig
を宣言型で参照する selector
要素も重要です。この selector は、DeploymentConfig
のメタデータ内のラベルと、名前および値の両方で一致していなければなりません。以下の例に、単一のラベルを示します。
app: simple-http-server-dep
この Service
を使用して、トラフィックを転送するルートを作成できます。ルートにはルーターを割り当てる必要があるので、そのルーターも作成する必要があります。(このチュートリアルの単純な例と同じような) デフォルトのプロジェクトまたは名前空間を使用するのでかまわなければ、OpenShift に用意されているデフォルトのルーターを使用できるので、作成する必要はありません。
補足すると、このチュートリアルでは プロジェクト と 名前空間 を同義語として使用しています。これも OpenShift と Kubernetes の相違点の 1 つですが、OpenShift でのプロジェクトは基本的に、いくつかのアドオンを追加した名前空間です。プロジェクトと名前空間の違いについて詳しくは、セクション「9. OpenShift projects are more than Kubernetes namespaces」を参照してください。
ルートの作成に話を戻すと、デフォルト・ルーターのページを使用することもできます。
「Create route (ルートを作成) 」をクリックし、ルートの名前、アプリの外部 URL のホスト名とパスを入力し、アプリを公開するために定義した Service を選択します。ホスト名を入力するには、2 つの方法があります。1 つは、フィールドを空白のままにして、ルートに指定した名前、プロジェクトの名前、クラスター名、生成された一意の ID に基づいて OpenShift にホスト名を生成させることです。 このチュートリアルの例では、以下のホスト名が生成されます。
simple-http-server-route-default.voc-sandbox-cluster-7d4bdc08e7ddc90fa89b373d95c240eb-0001.us-east.containers.appdomain.cloud
長々としたホスト名であることは認めますが、もう一方の方法では、OpenShift に構成する独自のホスト名を入力してから、そのホスト名を適用するように DNS 構成に関するすべての作業を行わなければなりません。このチュートリアルの単純な例には、生成されたホスト名を使用します。こうすれば、ホスト名を有効にするために必要な作業がなくなります。
ルートの定義に指定できるアイテムには、ルートのセキュリティー・レベルもあります。「Secure route (セキュア・ルート)」チェックボックスをオンにすると、TLS レベルのセキュリティーを有効にして、URL で HTTPS プロトコルを使用できるようになります。このチュートリアルではエッジや再暗号化ではなく、パススルー・レベルの TLS 終端を使用して、OpenShift にデフォルトの証明書を使用させます。
OpenShift のルートは Kubernetes の Ingress や Istio ゲートウェイにかなり似ています。
アプリへの外部アクセスを可能にするために最後に必要な作業は、適切なファイアウォール・フローを開始することです。インストール済み環境内で Calico を使用してファイアウォール・フローを管理します。Calico がインストールされていれば、OpenShift CLI で以下のコマンドを使用することによって、対応する Calico 構成を生成できます。
ibmcloud oc cluster config --cluster <cluster-id> --admin --network
<cluster-id>
は、メインの OpenShift クラスターの「Overview (概要)」タブで確認できます。
Calico でクラスターの構成を指すために、以下のようにして対応するファイルを移動します。
mv ~/.bluemix/plugins/container-service/clusters/<cluster-id>-admin/calicoctl.cfg /etc/calico
これで、YAML ファイルを使用して Calico フローを定義できます。以下に例を示します。
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: allow-simple-http-server
spec:
applyOnForward: true
ingress:
- action: Allow
destination:
nets:
- 169.63.135.10/32
ports:
- 443
protocol: TCP
source: {}
preDNAT: true
selector: ibm.role=='worker_public'
order: 1800
types:
- Ingress
この例での nets
IP アドレスは、前に記載したデフォルト・ルーターのページ内に示されている「Ingress Points (Ingress ポイント)」項目から取得できます。443
ポートを使用している点に注目してください。慣習として、HTTPS トラフィックには、このポートを使用します。
この YAML を適用するには、OpenShift CLI ではなく Calico CLI を使用して、以下のコマンドを実行します。
calicoctl apply -f allow-http-simple-server.yaml
これで、生成されたホスト名を含む URL を使用するだけで、curl を使ってアプリを呼び出すことができます。
まとめ
GET
REST リクエストを受け取ってシンプルなメッセージで応答するシンプルな HTTP サーバーが完成し、この HTTP サーバーにパブリック URL を使用して外部からアクセスできるようになりました。
また、サーバーの Git リポジトリーに変更をプッシュするだけで、サーバーのコードを更新して実行中のインスタンスに反映できることも確認できます。
私が作成した動画「OpenShift exercise recording」で、ローカルでコードを変更して Git にプッシュする方法をデモしてあり、以降の手順の流れを確認できます。前に実行したのと同じ curl コマンドを実行すると、新しい出力メッセージが表示されることを確認できます。この動画を参考に、独自の環境でこの手順を試してください。