まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

これは自分のスキル不足が原因だと思っているのですが、Kubernetes や OpenShift といったコンテナクラスタ環境を使ったウェブアプリケーションのデプロイではトラブルシューティングに時間を費やすことが珍しくありません。過去に成功したのと同じようなパターンでデプロイすることばかりではなく、ストレージ含めた新しいチャレンジをすることが多く、一発で成功することはあまりありません。

この「トラブルシューティング」は、現象としては「デプロイしたが想定していた URL でウェブアプリが動いていない」ことで分かるのですが、この原因は(期待通りに動いていない箇所が)様々です。k8s の用語でいうと Pod, Deployment, Service, Ingress, ... といった構成要素があり、まずはこの中のどこで問題が発生しているのかを見極め、その上でその箇所で発生している問題の原因を特定して解決していく必要があります。

この「どの部分で問題が発生しているか」を特定する作業において、"port-forward" と呼ばれる機能に助けられています。この port-forward 機能について自分へのメモ目的も含めてまとめておきます。


【コンテナクラスタのトラブルシューティング】
k8s を使ったウェブアプリケーションのデプロイ作業は手動であったり(半)自動化されていたりしますが、リソースと呼ばれる以下のようなパーツの単位で作成され、これらが組み合わされて1つのウェブアプリケーションとなります(ウェブアプリケーションがうまく動かない場合は、このいずれか(または複数)が想定していたように動いていない、ということになります):
・デプロイメント(Deployment)
 - アプリケーションイメージを1つ以上インスタンス化し、クラスタ内で稼働しているもの
・ポッド(Pod)
 - インスタンス化されたアプリケーションイメージ1つ1つを指すもの
 - デプロイメントを作成した場合はデプロイメントに含まれる
・サービス(Service)
 - コンテナ内で稼働しているポッドやデプロイメントを外部公開方法を定義するもの
・イングレス(Ingress)
 - 複数のサービスを管理し、外部からのリクエストに対してロードバランサーとなるもの

2023090706


コンテナクラスタ環境にウェブアプリケーションが正しくデプロイされた場合、ユーザーはアプリケーションの URL にアクセスすると、まずイングレスがそのリクエストを受け取って正しいサービスに転送し、サービスを経由してアプリケーションインスタンスであるポッド(デプロイメント)にアクセスします(イングレス→サービス→ポッド)。そしてそのリクエストに対してポッドが返したレスポンスは逆の順序(ポッド→サービス→イングレス)を通って返される、ということになります。


「デプロイしたアプリケーションが期待していたように動かない」というのは、この中のどこかが期待していたように動いていなくて、全体として「動かない」ように見えていることになります。したがってトラブルシューティングにおいて、まずはどこで問題が発生しているのかを特定する必要があります。
2023090706


【port-forward 機能】
kubectl や oc といった CLI ツールの機能である port-forwarding を使うと、ポート番号を使ったフォワーディング機能によりイングレスを経由せずにコンテナクラスタ内に定義されているサービスやポッドに直接アクセスできるようになります。

例えばイングレスを経由せずにサービスにアクセスすると期待していた挙動になる(期待していた結果が返ってくる)のであればイングレスやその設定に問題がある可能性が高いことが考えられ、サービスにアクセスしても動かないがポッドに直接アクセスすれば期待していた挙動になるのであればサービスやその設定に問題がある可能性が高いことが考えられます(それでも動かない場合はポッドに問題があると考えられます)。 このような障害発生個所の見極めにおいては port-forwarding が便利に使えることになります。


【port-forward 機能を使ってみる】
試しにわざと正しく動かないことがわかっている以下のようなマニフェストファイル(deployment.yaml)を使ってアプリケーションをデプロイし、port-forward で確認する、ということをやってみます:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: guestbook
  labels:
    app: guestbook
spec:
  replicas: 1
  selector:
    matchLabels:
      app: guestbook
  template:
    metadata:
      labels:
        app: guestbook
    spec:
      containers:
      - name: guestbook
        image: ibmcom/guestbook:v1
        imagePullPolicy: Always
        env:
          - name: NODE_ENV
            value: production
---
apiVersion: v1
kind: Service
metadata:
  name: guestbook-svc
  labels:
    app: guestbook
spec:
  type: ClusterIP
  ports:
  - protocol: TCP
    port: 3000
    targetPort: 3000
  selector:
    app: guestbook
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: guestbook-route
  labels:
    app: guestbook
spec:
  host: guestbook.(アサインされた ingress サブドメイン)
  to:
    kind: Service
    name: guestbook-svc
    weight: 100
  port:
    targetPort: 4000 # 正しくは3000
  tls:
    termination: edge
    insecureEdgeTerminationPolicy: Redirect
  wildcardPolicy: None

ちなみに上記マニフェストの正しい記述は下から5行目の Route の spec.port.targetPort の値が 3000 になっているものです(今回はわざと 4000 を指定しています)。

なお以下の作業は IBM Cloud の Redhat OpenShift コンテナクラスタ環境を使って確認しました。なので Ingress 部分の定義は apiVersion が "route.openshift.io/v1" の Route というリソースを使って定義しています。またこの Route 内の spec.host の値には "guestbook.(アサインされた ingress サブドメイン)" と記載していますが、実行前にこの()内の部分を OpenShift 画面に表示されているサブドメイン名に置き換えて保存しておいてください:
2023090701


oc コマンドでログインし、このマニフェストファイルをデプロイ(oc apply)して、その結果を確認(oc get all)します:
$ oc apply -f deployment.yml

$ oc get all

NAME                             READY   STATUS    RESTARTS   AGE
pod/guestbook-59b85f9654-22wh5   1/1     Running   0          13m

NAME                                TYPE           CLUSTER-IP       EXTERNAL-IP                            PORT(S)    AGE
service/guestbook-svc               ClusterIP      172.21.150.230                                          3000/TCP   13m
service/kubernetes                  ClusterIP      172.21.0.1                                              443/TCP    6h7m
service/openshift                   ExternalName              kubernetes.default.svc.cluster.local                    5h46m
service/openshift-apiserver         ClusterIP      172.21.46.95                                            443/TCP    6h6m
service/openshift-oauth-apiserver   ClusterIP      172.21.98.204                                           443/TCP    6h6m

NAME                        READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/guestbook   1/1     1            1           13m

NAME                                   DESIRED   CURRENT   READY   AGE
replicaset.apps/guestbook-59b85f9654   1         1         1       13m

NAME                                       HOST/PORT                                                                 PATH   SERVICES        PORT   TERMINATION     WILDCARD
route.route.openshift.io/guestbook-route   guestbook.(ingress サブドメイン).jp-tok.containers.appdomain.cloud             guestbook-svc   4000   edge/Redirect   None

"oc get all" の結果は上からポッド、サービス、デプロイメント、レプリカセット、そしてイングレスになっています。ポッドのステータスは Running でちゃんと動いていて、サービスも ClusterIP を使って正しく公開され、イングレスもホスト名が割り当てられています。 この結果だけを見ると正しく動いてそうです。

でも実際にブラウザでイングレスの HOST 名に表示されているサーバーにアクセスするとこのように表示されます(知らない人もいるので補足すると、これは期待していたアプリ画面ではなく、アクセスできなかった場合のエラー画面です):
2023090702


エラー無くデプロイできたけどアプリにアクセスできない、、 こんな時に port-forward の出番です。

まずは(上述の結果で Pod が Running になってるので可能性は低そうですが)ポッドのレベルで正しく動いているかどうかを確認するため、port-forwarding でポッドに直結して動作を確認してみます。

ポッドに対して port-forwarding するには kubectl(または oc )コマンドで以下のように実行します:
$ kubectl port-forward (ポッド名) (ホストのポート番号):(ポッド上で動いているポート番号)

今回の例だと(上述の結果より)ポッド名は "guestbook-svc" だとわかります。また実行したマニフェストファイルより、このサービスは 3000 番ポートで動いているはずです(サービスの spec.ports.targetPort の値)。このポッドにホストの(何番でもいいのですが) 8000 番ポートからフォワーディングして接続させてみます。というわけで、今回のケースであれば以下のコマンドを実行します:
$ kubectl port-forward guestbook-59b85f9654-22wh5 8000:3000

コマンド実行後、ウェブブラウザから http://localhost:8000/ にアクセスしてみます:
2023090703


今回は期待通りの画面が表示されました。ということは「ポッドは正しく動いている」ことが推測できました。Ctrl+C で port-forwarding を解除します。


継はサービスのレベルで正しく動いているかどうかを確認してみます。イングレスを経由せずにサービスにアクセスするため、port-forwarding でサービスに直結して動作を確認してみます。この場合は以下のようなコマンドを実行します:
$ kubectl port-forward service/(サービス名) (ホストのポート番号):(サービスで公開しているポート番号)

今回の例だと(上述の結果より)サービス名は "guestbook-59b85f9654-22wh5" だとわかります。また実行したマニフェストファイルより、このポッド(デプロイメント)は 3000 番ポートで動いているはずです(サービスの spec.ports.port の値)。このポッドにホストの(何番でもいいのですが) 9000 番ポートからフォワーディングして接続させてみます。というわけで、今回のケースであれば以下のコマンドを実行します:
$ kubectl port-forward service/guestbook-svc 9000:3000

コマンド実行後、ウェブブラウザから http://localhost:9000/ にアクセスしてみます:
2023090704


今回は期待通りの画面が表示されました。ということは「サービスも正しく動いている」ことが推測できました。Ctrl+C で port-forwarding を解除します。

これらの結果から、
・ポッド(デプロイメント)は正しく動いていそう
・サービスも正しく動いていそう
・ということはイングレスの設定が間違っていそう?

という切り分けをすることができました。実際、マニフェストの Route 内をわざと間違った内容に弄ったことが分かっているので、正しい切り分けができていることになります。

このケースであればイングレスの設定内容を疑ってみることになります。試しにイングレスの設定名称を指定して describe するとこのようになりました(kubectl の場合は "kubectl describe ingress guestbook-route"):
$ oc describe route guestbook-route 

  :
  :
Path:                   
TLS Termination:        edge
Insecure Policy:        Redirect
Endpoint Port:          4000

Service:        guestbook-svc
Weight:         100 (100%)
Endpoints:      

接続先である Endpoints が空になっていて何も表示されていません。ということは設定内容になんらかの誤りがあってサービスに接続できていないのでは・・・ と考えることができます。実際、今回のマニフェストでは targetPort を 3000 と指定すべきところを 4000 と指定していたため接続できていませんでした。仮に 4000 を 3000 に変更して再度適用した上で接続を試みた所、今度は正しく接続できるようになりました:
2023090705


現実問題として、イングレス部分はポッドやサービスとは異なり Kubernetes からはサードパーティ製品となるので色々な実装があり、トラブルシューティングも実装ごとの方法が考えられるため比較的難しいトラブルシューティングとはなります。それでも「どの部分に設定ミスがあったか」を特定することで解決はしやすくなりますし、その特定において port-forwarding は有効な切り分け方であると思っています。




このお盆休みの期間を使って、久しぶりに XSL を再勉強しました。10年くらい前の以前に使っていたころと比べて事情も変わっていたようで、リスキリングという意味でもいい機会だったと思っています。改めて「そもそも XSL とは?」から「なんで XSL をやり直そうと思ったのか」という背景も含め、まとめておきます。実はこの背景部分が少々複雑で、眺めの導入説明になっている点をご了承ください。


【HTML と CSS の関係】
XSL のブログエントリでなんで HTML と CSS ? と感じる人もいると思いますが、実はこれが上述の背景部分に絡んできます。 ウェブのデザインをしたことがある人はわかっていることだと思いますが、ウェブページって、
・表示するデータを HTML で
・その見栄えは CSS で
定義することになっています。極端な言い方をすると HTML 内には見栄えに関連する要素を入れずに(HTML5 以降では見栄えに関する要素は排除される方向です)、見た目はすべて CSS で、というやり方。これはこれでメリット・デメリットある気がしますが、役割分担としてはシンプルで悪くないと感じています。

ただ、自分はこの考え方に少し違和感があります。「見栄えを CSS で」という点はいいのですが、「表示するデータを HTML で」という部分は現実と少し違っているように感じてしまうのでした。

例えばこんな HTML があったとします:
<html>
<head>
<title>成績表</title>
</head>
<body>
<h1>成績表</h1>
<table id="mytable">
<thead>
<tr><th>名前</th><th>国語</th><th>数学</th></tr>
</thead>
<tbody>
<tr><td>佐藤</td><td>50</td><td>90</td></tr>
<tr><td>鈴木</td><td>70</td><td>60</td></tr>
<tr><td>田中</td><td>80</td><td>40</td></tr>
</tbody>
</table>
</body>
</html>

一見なんの変哲もない、<h1> の見出しと成績表が定義された HTML です。これらの見出しや表部分、細かくは全体のフォントや背景色なども含めて具体的にどのような見栄えになるのかは別途 CSS で定義する、というものです。 ここで私が「表示するデータは HTML で定義」していることについて違和感を感じるのは「<title> と <h1> の両方で "成績表" が定義されていること」です。

これは HTML 的にはブラウザウィンドウのタイトル部分(<title>)と、ブラウザ内に表示されるウェブページとしての見出し部分(<h1>)なので別々に定義する必要があるものです(別々に定義しようと思えばできる、という点ではその通り)。一方で「データとして」考えるとどちらも「見出し」のデータであって、「別々に定義するつもりがないのであれば、データとしては1つ」が正しいものです。後者の考え方でウェブページを作ろうとすると、「データを定義するはずの HTML 内で <title> と <h1> の2か所で同じ内容を(2重に)定義している」とも感じます。これはもちろん HTML の仕様ともかかわる問題ではあるのですが、その HTML の仕様のせいでデータを2重管理する必要が生じてしまっているのでした。 

2重管理しないといけないものが「表示するデータを定義するもの」・・・これが私の感じた違和感でした。本来「表示データ」は2重、3重に定義せず正規化されているべきものであって、その内容を表示ページの内容に従って HTML に配置しなおして(ここで2重化されるのは理解できる)、最後に CSS で HTML の見栄えを定義する、という考え方がしっくりくるのでした。 要するに「HTML が表示データの定義」と呼ぶことに抵抗を感じていて、「表示データをウェブページの配置に沿って変換した結果が HTML」と考えるとすっきり理解しやすいのでした:
(表示データの定義(の XML 例))
<?xml version="1.0" encoding="Shift_JIS"?>
<成績表>
  <見出し>成績表</見出し>
  <結果 名前="佐藤" 国語="50" 数学="90"/>
  <結果 名前="鈴木" 国語="70" 数学="60"/>
  <結果 名前="田中" 国語="80" 数学="40"/>    
</成績表>

  ↓(変換)

(表示ウェブページの HTML) <html> <head> <title>成績表</title> </head> <body> <h1>成績表</h1> <table id="mytable"> <thead> <tr><th>名前</th><th>国語</th><th>数学</th></tr> </thead> <tbody> <tr><td>佐藤</td><td>50</td><td>90</td></tr> <tr><td>鈴木</td><td>70</td><td>60</td></tr> <tr><td>田中</td><td>80</td><td>40</td></tr> </tbody> </table> </body> </html>

(※この後 msxsl.exe というツールを使う関係でわざと XML に encoding="Shift_JIS" 指定を加えています。msxsl.exe を使わない場合は encoding 指定なしで(UTF-8 で)構いません)


【XSL とは】
XSL(eXtensible Stylesheet Language) は上述の「表示データをウェブページの配置に沿って変換した結果が HTML」の「変換ルール」に関わるものです。そして実際の変換処理そのものは XSLT(XSL Transform) と呼びます。

具体的に XML と XSL を用意して、XSLT を行ってみます。まず以下のような2つのテキストファイル data.xml と data.xsl を用意します(いずれもシフト JIS エンコードで保存してください):

(data.xml)
<?xml version="1.0" encoding="Shift_JIS"?>
<成績表>
  <見出し>成績表</見出し>
  <結果 名前="佐藤" 国語="50" 数学="90"/>
  <結果 名前="鈴木" 国語="70" 数学="60"/>
  <結果 名前="田中" 国語="80" 数学="40"/>    
</成績表>


(data.xsl)
<?xml version="1.0" encoding="Shift_JIS"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" encoding="Shift_JIS"/>
<xsl:template match="/">
<html>
<head>
<title><xsl:value-of select="成績表/見出し" /></title>
</head>
<body>
<h1><xsl:value-of select="成績表/見出し" /></h1>
<table id="mytable">
<thead>
<tr><th>名前</th><th>国語</th><th>数学</th></tr>
</thead>
<tbody>
<xsl:for-each select="成績表/結果">
<tr>
  <td><xsl:value-of select="@名前" /></td>
  <td><xsl:value-of select="@国語" /></td>
  <td><xsl:value-of select="@数学" /></td>
</tr>
</xsl:for-each>
</tbody>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>



【参照】
XSLTの使い方・入門チュートリアル


data.xml が表示データの定義ファイルで、data.xsl が data.xml を HTML に変換する際の変換ルールを定義しています。<xsl:template match="/"> と </xsl:template> の間で HTML が定義されていて、<xsl:value-of> と <xsl:for-each> を使って表示データ(data.xml)のテキスト値や属性値を HTML に変換しています。

XML と XSL を使って HTML に変換(= XSL Transform)する方法はいくつかありますが、比較的簡単なマイクロソフト製コマンドラインツール msxsl.exe を使った例を紹介します、、が、このツールは便利ではあるのですが、かなり古いものらしく、マイクロソフトのサイトには存在しておらず、インターネットアーカイブ上でしか見つけることができませんでした。というわけでこちらからダウンロードしてください:
http://web.archive.org/web/20140812045521/http://www.microsoft.com/en-us/download/details.aspx?id=21714


ダウンロードできたら Windows 上でコマンドプロンプトを開き、data.xml , data.xsl の存在するフォルダに移動します。そして msxsl.exe にパスを通すか、data.xml, data.xsl と同じフォルダに msxsl.exe をコピーしてください。

準備ができたら以下を実行します:
> msxsl.exe data.xml data.xsl

msxsl.exe は2つのパラメータを指定して XSLT 処理を実行します。最初のパラメータが XML ファイルのパス、2つ目のパラメータが XSL ファイルのパスです。正しく実行できた場合は XSLT の実行結果が画面上に表示されます:
2023082001

※このコマンドプロンプト画面ではシフト JIS でないと文字化けを起こしてしまいます。その理由もあって data.xml と data.xsl をシフト JIS で作ったという背景があるのでした。

個人的には XSLT 処理をプログラミング内で行うこともあるのですが、そこでうまくいかないケースに遭遇した場合、この msxsl.exe を使うとエラー発生時の内容や箇所をエラーメッセージとして表示してくれるので、主にデバッグ目的で今でもよく使っています。


この XSL(T) を使うことで、
・表示するデータは XML で、
・XML を XSL を使って変換した HTML を使って、
・HTML の見栄えは CSS で、
それぞれ役割分担して定義する、ということが可能になります。例えばデータベースから取り出した直後のデータは XML に近い形をしていることが多いので、そこから HTML を生成する際に XSL を使い、細かな見栄えは別途 CSS で定義する、という役割分担が、自分の理解の上でも腹落ちしやすいと考えています。


【ノーツのデータ構造に似ている】
ここまでに紹介してきた XML と XSL の関係というのが、HCL ノーツ/ドミノでいうところの「文書(document)」と「フォーム(form)」の関係に似ていると思っています。ノーツではデータそのものは文書として格納されていて、その見栄えは適用されるフォームによって定義されています。同じ文書でも適用さえるフォームによって見栄えが変わる点も含めて似ているのですが、加えてノーツのデータは DXL(Domino XML Language) という特殊な XML フォーマットでインポート/エクスポートできる機能があるので、XML/XSL との相性も悪くなかったりします。

まあ現実のノーツデータはそこまで単純ではありません。ノーツにはサブフォームや共有フィールドといった設計の再利用の仕組みがあったり、HTML とは異なる独特なリッチテキスト編集/保存機能があったり、細かな所では XSL のテンプレート名称に使ってよい文字とノーツのフォーム/サブフォーム名に使ってよい文字に違いがあったりして、単純に XML/XSL 対応ができるわけではなかったりします。

とはいえ、それでもノーツのデータをノーツ外で取り扱う(これ自体がすごくハードルの高いことだったりします)ことを目指そうとすると、 DXL にエクスポートした上で XML/XSL の仕組みをベースにすることでノーツ外でも取り扱いできるようにするための近道のようには感じています。どこまで実現できるかわからないのですが、個人的にそんなツールの開発を始めていて、いずれどこかで紹介できればと思っています。




 

ちょっとした UI 系トラブルに巻き込まれた結果とある機会に CLI 操作だけで IBM Cloud 上に Openshift クラスタ(いわゆる "ROKS")を作る必要が生じて、実際に試してみました。以下、その時に実行したコマンド群を順に紹介します。


【前提条件】
やりたかったことは単純に「VPC(Virtual Private Cloud)環境内に OpenShift クラスタを1つ作る」ことでした。既に VPC 自体はサブネット含めて作成済みで、バックアップストレージの Cloud Object Storage インスタンスも作成済みです。 後はこの VPC 内に OpenShift クラスタをスペックやワーカーノード数を指定して作るだけ、という状況です。


【CLI コマンド】
以下 CLI コマンドを記載します。ここまでに "ibmcloud login" は実行済みであるとします。

詳しくは下記参考ページを参照いただきたいのですが、VPC 内に OpenShift クラスタを作るための CLI コマンドは以下のようになります:
$ ibmcloud oc cluster create vpc-gen2 --name (クラスタ名) --zone (作成先ゾーン名) --vpc-id (作成先 VPC ID) --subnet-id (作成先サブネット ID)  --flavor (ワーカーノードのフレーバー) --version (OpenShift バージョン) --cos-instance (Cloud Object Storage の CRN) --workers (1ゾーンあたりのワーカーノード数)

で、このコマンドを実行するためには(上記コマンド内にも括弧がたくさんあるように)指定する必要がある多くのパラメータ情報を事前に集めておく必要があります。というわけでまずはパラメータ情報を収集するための CLI コマンドから説明します。

まず "--name" パラメータで指定する「クラスタ名」は自分で自由に指定することができるので説明は不要だと思います。次に "--zone" パラメータで指定する「作成先ゾーン名」ですが、これは目的のゾーンが例えば「大阪3」であったとして、この「大阪3」を指定するための文字列です。これを調べるには次のコマンドでゾーン一覧を取得して、そこから目的のゾーンの ID を取り出します(青字が入力コマンドです):
$ ibmcloud oc zone ls --provider vpc-gen2
OK
ID           Name         Metro             Flavors
au-syd-1     au-syd-1     Sydney            -
au-syd-2     au-syd-2     Sydney            -
au-syd-3     au-syd-3     Sydney            -
br-sao-1     br-sao-1     Sao Paulo         -
  :
eu-gb-3      eu-gb-3      London            -
jp-osa-1     jp-osa-1     Osaka             -
jp-osa-2     jp-osa-2     Osaka             -
jp-osa-3     jp-osa-3     Osaka             -
jp-tok-1     jp-tok-1     Tokyo             -
jp-tok-2     jp-tok-2     Tokyo             -
jp-tok-3     jp-tok-3     Tokyo             -
us-east-1    us-east-1    Washington D.C.   -
  :

この結果から「大阪3」を使う場合に指定するゾーン名が "jp-osa-3" であることが分かります。

次に作成先の「VPC ID」です。VPC が決まっていても、その ID を取り出して指定する必要があります。これは以下のコマンドを実行することで取り出せます:
$ ibmcloud oc vpcs --provider vpc-gen2
OK
Name              ID                                          Provider
xxxxxxx-vpc-osa   ****-********-****-****-****-************   vpc-gen2
  :

目的の VPC 名と照らし合わせることで ID を確認することができます("****-********-****-****-****-************" という値であったと仮定します)。

作成先の「サブネットID」も調べる必要があります。普段は名称で扱っていて、ID を意識することがあまりないのですが CLI 操作時には必要な情報です。これは以下のコマンドで "xxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" であることが確認できます:

$ ibmcloud oc subnets --provider vpc-gen2 --vpc-id (VPC ID) --zone (ゾーン名)
OK
Name                ID                                          Public Gateway Name                        Public Gateway ID                           IPv4 CIDR Block   Available IPv4 Addresses
sn-xxxxxxxxxxx-03   xxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx   pgw-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx   xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx   10.xxx.xxx.0/24   244

ワーカーノードのフレーバー(スペック)も実行時に指定する必要のある情報です。これは以下のコマンドでフレーバーの一覧を取得し、目的のフレーバーの ID を取り出します。今回は "bx2.16x64" というスペックのフレーバーを使うことにします:
$ ibmcloud oc flavors --zone (ゾーン名) --provider vpc-gen2
OK
For more information about these flavors, see 'https://ibm.biz/flavors'
Name           Cores   Memory   Network Speed   OS             Server Type   Storage
  Secondary Storage   Flavor Class   Provider
bx2.16x64      16      64GB     24Gbps          UBUNTU_20_64   virtual       100GB     0B, *               bx2            vpc-gen2
bx2.2x8†       2       8GB      4Gbps           UBUNTU_20_64   virtual       100GB     0B                  bx2            vpc-gen2
bx2.32x128     32      128GB    25Gbps          UBUNTU_20_64   virtual       100GB     0B, *               bx2            vpc-gen2
b
  :
  :

OpenShift のバージョンも指定する必要がある項目ですが、これは普通に "4.11_openshift" などと指定できます。またゾーンあたりのワーカーノード数も普通に "2" などと数字で指定可能です。

最後に Cloud Object Storage の CRN を取得します。これは取得が面倒なのですが、作成済みリソースの一覧を取得し、そこから目的の Cloud Object Storage サービスを探して、その ID を見つける、という方法で取得します:
$ ibmcloud resource service-instances --long
OK
   :
   :
ID:                 crn:v1:bluemix:public:cloud-object-storage:global:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx::

GUID:               xxxxxxxxxxxxxx


Name                Cloud Object Storage for me


Location            global
   :
   :

これで OpenShift クラスタを作成するために必要な最低限の情報が揃いました:
情報
ゾーン名jp-osa-3
VPC ID****-********-****-****-****-************
サブネット IDxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
ワーカーノードのフレーバーbx2.16x64
OpenShift バージョン4.11_openshift
1ゾーンあたりのワーカーノード数2
Cloud Object Storage の CRNcrn:v1:bluemix:public:cloud-object-storage:global:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx::



これらの情報を使って以下のコマンドを実行します:
$ ibmcloud oc cluster create vpc-gen2 --name (クラスタ名) --zone jp-osa-3 --vpc-id ****-********-****-****-****-************ --subnet-id xxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx  --flavor bx2.16x64 --version 4.11_openshift --cos-instance crn:v1:bluemix:public:cloud-object-storage:global:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:: --workers 2
Creating cluster...
OK
Cluster created with ID ***************************

成功すると上述のようにクラスタ ID("***************************")が表示され、「デプロイ中」のステータスとなります。


なお、マルチゾーンで作成する場合は上記の作業を行ってシングルゾーンでクラスタを作成した上で、追加するゾーンのゾーン名とサブネット ID を取得してから以下のコマンドを実行してワーカープールにワーカーノードを追加します:
$ ibmcloud oc zone add vpc-gen2 --zone (追加するゾーン名) -c (クラスタ名) --worker-pool (追加先のワーカープール名) --subnet-id (サブネットID)
OK

これで IBM Cloud のダッシュボード画面にアクセスできなくてもしなくても、CLI だけで Openshift クラスタを作ることができそうです。


【参考】
https://cloud.ibm.com/docs/openshift?topic=openshift-cluster-create-vpc-gen2&interface=cli


 

このページのトップヘ