以前のブログエントリで OpenShift 関連の以下2つの紹介をしていました:
IBM Cloud の VPC(Virtual Private Cloud) でプライベート OpenShift クラスタ環境を構築する
IBM Cloud の仮想プライベートクラウド OpenShift 上にデプロイしたコンテナアプリに HTTP パブリックアクセスを許可する


前者は IBM Cloud の VPC(Virtual Private Cloud) 環境を使って、プライベートな OpenShift クラスタ環境を作る手順(と VPN を使ったプライベート OpenShift へのアクセス手順)を紹介しました。 また後者ではこのプライベート環境を使ってデプロイしたプライベートなアプリケーションに対して、VPN なしでパブリックインターネットアクセスを(HTTPS ではなく、HTTP で)行うための設定手順を紹介しました。

今回のブログエントリではこの最終形ともいえる「デプロイしたアプリケーションに対する HTTPS によるアクセス」を実現するための手順を紹介します。上で紹介した2つのエントリの、後者に近い内容ではありますが、純粋な続きというわけではありません。前者の環境が構築済みであるという前提のもとで、oc CLI を使ったアプリケーションのデプロイと、プライベートアクセスを可能にするための手順を紹介していきます。


【3通りの方法】
今回のブログエントリの結論めいたことを最初に紹介します。この「プライベートクラウドにデプロイしたアプリケーションにパブリックにアクセスする」には目的や制約に応じた3通りの方法があります(うち(1)は前回説明済み):
(1)HTTP でパブリックアクセスする(前回説明
(2)HTTPS でパブリックアクセスする(自己証明書を使う場合)
(3)HTTPS でパブリックアクセスする(有効な証明書を使う場合)

要は「HTTP でいいのか? HTTPS が必要か?」「HTTPS の場合、自己証明書でいいか?NGか?」という2つの考慮点があり、その要件によって選択肢を選ぶ必要がある、ということです。「この中でどれか?と言われたら(3)でしょ?」と思うかもしれませんが、それぞれに制約事項があったりして(例えば(1)、(2)は IBM Cloud 内の設定のみで実現できますが、(3)の場合はカスタムドメインが別途必要になります)、検証目的なのか本運用なのか、といった背景によっても選択肢は変える必要が生じるものだと思います。

以下では、最終的には(3)を実現する前提として、(1)から順に実現手順を紹介します。なお(1)と同じことを前回紹介しているのですが、(3)まで行うことを考えると(1)も少し手順を変える必要があるので、改めて(1)から実現手順を、以下で順に紹介します。


【0. 事前準備】
まず事前準備としてプライベートクラウドでの OpenShift クラスタ環境と、同環境にアクセスするための VPN が必要です。これらの構築手順はシリーズ初回で紹介しているので、こちらの手順を参照してプライベートクラウドの OpenShift クラスタと、同クラスタにアクセスするための VPN 環境を作っておいてください。

ここまでが完了している前提で以下の説明を続けます。


【1. プライベート OpenShift クラスタにアプリケーションをデプロイし、パブリックアクセスのパスを定義する】

2023020205


以前にも紹介した内容ですが、今回は HTTPS でのアクセスまでを考慮した手順を紹介します。そのため、HTTP でアクセスするこの部分から以前とは異なる、oc CLI コマンドと yaml ファイルを使ってアプリケーションをデプロイする手順を紹介します。

まず前提として、以下のようなプライベート OpenShift クラスタ環境が IBM Cloud 内に作られているものと仮定します:

OpenShift クラスタ名: kkimura-mycluster-jp-osa-2-priv
2023020101


Ingress が定義したサブドメイン名: kkimura-mycluster-jp-osa-6fe57c7eaf38abe6232341d97eae54c0-i000.jp-osa.containers.appdomain.cloud
2023020102


アプリケーションをデプロイする OpenShift プロジェクト(ネームスペース): default

OpenShift にデプロイするアプリ:DockerHub 上の ibmcom/guestbook:v1
2023020103


※ちなみにこの ibmcom/guestbook をデプロイしてウェブブラウザでアクセスするとこのような↓画面が表示されます。この画面が表示されればデプロイとアクセスが成功している、と判断してください:
2023020101



以下では上述の名称や設定を前提として説明します。適宜自分の環境での名称や設定に読み替えてください。

では実際に oc CLI を使って、アプリケーションをプライベート OpenShift クラスタにデプロイします。まずはプライベート環境へアクセスする VPN を有効にした上で「OpenShift Web コンソール」を開きます(VPN が有効でないと開けません):
2023020104


OpenShift Web コンソールが開きます。今回は oc CLI と呼ばれるコマンドラインツールを使ってアプリケーションのデプロイや設定変更を行うので、まだこのツールをインストールしていない場合は導入が必要です。OpenShift Web コンソール画面上部のクエスチョンマークをクリックし、コンテキストメニューから「コマンドラインツール」を選択して、自分の PC 環境にあった oc CLI ツールをダウンロード&インストールしておいてください:
2023020108


同様にして ibmcloud CLI コマンドも(未導入の場合は)インストールしておきます:
https://cloud.ibm.com/docs/cli?topic=cli-install-ibmcloud-cli&locale=ja


oc CLI ツールと ibmcloud CLI ツールがインストールできている状態で、改めて OpenShift Web コンソール画面右上の名前部分をクリックしてコンテキストメニューを開き、「ログインコマンドのコピー」を選択します:
2023020105


新しいウィンドウが開くと、"Display Token" とだけ表示されているので、この部分をクリックしてトークン情報を参照します:
2023020106


するとトークン情報が書かれたページが表示されます。この中の "Log in with this token" で書かれた部分を(この後ペーストするので)コピーします:
2023020107


ターミナルを開き、さきほどコピーした内容をペーストして Enter キーを押すと、ターミナル画面で IBM Cloud の OpenShift 環境にログインできます:
2023020109


同様にして ibmcloud CLI ツールからも IBM Cloud へのログインを行っておきます:
$ ibmcloud login


ではここからプライベート OpenShift クラスタ内にアプリケーションをインストールします。改めて以下のような内容の yaml ファイル(guestbook_deployment.yaml)を用意します:
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:
  - port: 3000
    protocol: TCP
    targetPort: 3000
  selector:
    app: guestbook
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: guestbook-route
  labels:
    app: guestbook
spec:
  host: guestbook.kkimura-mycluster-jp-osa-6fe57c7eaf38abe6232341d97eae54c0-i000.jp-osa.containers.appdomain.cloud
  to:
    kind: Service
    name: guestbook-svc
    weight: 100
  port:
    targetPort: 3000
  tls:
    termination: edge
    insecureEdgeTerminationPolicy: Redirect
  wildcardPolicy: None


この yaml ファイルは Deployment, Service, Route を1つずつ含んでいて、これ一つでアプリケーションをデプロイして、クラスタ外に公開して、ホスト名でアクセスできるようなルーティングを設定しています。数か所ある太字部分を補足します。

まず Deployment 内の image 名で ibmcom/guestbook:v1 と記載している部分、これがデプロイするアプリケーションのイメージです。別のイメージを使う場合はここを変えてください。

また数か所ある 3000 という数字、これは ibmcom/guestbook アプリが内部的に待ち受けるポート番号です。使うアプリイメージによって変わるので、ここもそのアプリ向けの正しい値を指定してください。

最後に Route 内の host 名、ここは (アプリ固有の名).(Ingress サブドメイン) を指定します。今回の例ではアプリ固有の名として guestbook とし、Ingress サブドメインは上記で調べた値(kkimura-mycluster-jp-osa-6fe57c7eaf38abe6232341d97eae54c0-i000.jp-osa.containers.appdomain.cloud)を使っています。

では用意した yaml ファイルを使って実際にプライベート OpenShift にデプロイします:
$ oc apply -f guestbook_deployment.yaml

成功したら上述の host 名に HTTPS でアクセスし、期待通りに動作することを確認します(この時点でプライベートクラウドへはデプロイできました):
2023020101


次にこのアプリケーションをパブリッククラウドから(最初は HTTP で)アクセスできるように設定します。大まかな手順としては以下のことを行います:
・OpenShift 内にパブリック・ルーター(の Pod)とパブリック・ロードバランサーを作成し、
・パブリック・ロードバランサー → パブリック・ルーター を経由して、アプリケーションだけにアクセスできるようなパスを通し、
・パブリック・ロードバランサーの外部ホスト名でアプリケーションを公開できるよう DNS を変更する


では順に実行していきます。ロードバランサーを OpenShift のパブリックネットワーク側に作りたいのですが、その際の(パブリックネットワーク用の)サブドメインを決める必要があります。まずは以下の ibmcloud コマンドを実行します:
$ ibmcloud oc nlb-dns ls --cluster kkimura-mycluster-jp-osa-2-priv
(最後のパラメータは OpenShift クラスタ名)

(以下、実行結果例)
OK
Subdomain                                                                                          Target(s)                            SSL Cert Status   SSL Cert Secret Name                                             Secret Namespace    Status
kkimura-mycluster-jp-osa-6fe57c7eaf38abe6232341d97eae54c0-i000.jp-osa.containers.appdomain.cloud   59aa36c3-jp-osa.lb.appdomain.cloud   created           kkimura-mycluster-jp-osa-6fe57c7eaf38abe6232341d97eae54c0-i000   openshift-ingress   OK

この実行結果例では1行しか表示されていませんが、複数行表示されることもあります。で、この結果の Subdomain を見ると "i000" と表示されている部分があります。この "i" で始まって数字が3桁続くサブドメインはプライベートネットワークであることを示しています。

新たにパブリックなサブドメインを追加したいのですが、その名称は、
・↑の方法でプライベートネットワークのサブドメインのうち、"i" 以降の数字が最も大きいもの(今回であれば "000")を探して、
・その数字に1を追加し、"i" をゼロ(0)にしたもの(今回であれば "0001")
にします。つまり今回の例であれば、
kkimura-mycluster-jp-osa-6fe57c7eaf38abe6232341d97eae54c0-0001.jp-osa.containers.appdomain.cloud

をパブリック用のサブドメインとします。

パブリック用のサブドメインが決まったら、以下のような yaml ファイル(ingresscontroller.yaml)を作って実行し、パブリックネットワークにパブリックルーターとパブリックロードバランサーを作ります(太字部分はパブリック用サブドメイン):
apiVersion: operator.openshift.io/v1
kind: IngressController
metadata:
  name: public
  namespace: openshift-ingress-operator
spec:
  replicas: 2
  domain: kkimura-mycluster-jp-osa-6fe57c7eaf38abe6232341d97eae54c0-0001.jp-osa.containers.appdomain.cloud
  endpointPublishingStrategy:
    loadBalancer:
      scope: External
    type: LoadBalancerService
$ oc apply -f ingresscontroller.yaml

そして以下を実行し、結果の "EXTERNAL-IP" を参照します:
$ oc get svc router-public -n openshift-ingress

NAME            TYPE           CLUSTER-IP       EXTERNAL-IP                          PORT(S)                      AGE
router-public   LoadBalancer   172.21.191.252   5ca5ada9-jp-osa.lb.appdomain.cloud   80:31127/TCP,443:30992/TCP   32h

この例では EXTERNAL-IP は "5ca5ada9-jp-osa.lb.appdomain.cloud" となっています。これがパブリックロードバランサーのホスト名となります。

このサービスのパブリック VPC ホスト名を DNS に登録します。以下のコマンドを実行します:
$ ibmcloud oc nlb-dns create vpc-gen2 --cluster (OpenShiftクラスタ名) --lb-host (ロードバランサーホスト名) --type public

※今回の例だと、
 OpenShift クラスタ名: kkimura-mycluster-jp-osa-2-priv
 ロードバランサーホスト名: 5ca5ada9-jp-osa.lb.appdomain.cloud

最後にアプリのサービスをパブリックルーターで expose します:
$ oc expose svc/guestbook-svc --name guestbook-public --hostname guestbook.kkimura-mycluster-jp-osa-6fe57c7eaf38abe6232341d97eae54c0-0001.jp-osa.containers.appdomain.cloud

これでサービス(guestbook.kkimura-mycluster-jp-osa-6fe57c7eaf38abe6232341d97eae54c0-0001.jp-osa.containers.appdomain.cloud)がパブリックネットワーク上で HTTP で公開されました。いったん VPN を切ってから、パブリックホスト名(http://guestbook.kkimura-mycluster-jp-osa-6fe57c7eaf38abe6232341d97eae54c0-0001.jp-osa.containers.appdomain.cloud)に HTTP でアクセスできることを確認してみましょう:
2023020201


【2. プライベート OpenShift クラスタにアプリケーションをデプロイし、自己証明書の HTTPS アクセスができるよう定義する】

2023020206


1. で説明した作業の続きとして、パブリックロードバランサー名(今回であれば "5ca5ada9-jp-osa.lb.appdomain.cloud")で自己証明書を使った HTTPS アクセスを可能にします。

そのためにはアプリケーションのデプロイ時に使った yaml ファイル(guestbook_deployment.yaml)を少し改良します。具体的には以下の青字部分を(自分の環境のホスト名やパブリックロードバランサー名を使って)追加します:
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:
  - port: 3000
    protocol: TCP
    targetPort: 3000
  selector:
    app: guestbook
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: guestbook-route
  labels:
    app: guestbook
spec:
  host: guestbook.kkimura-mycluster-jp-osa-6fe57c7eaf38abe6232341d97eae54c0-i000.jp-osa.containers.appdomain.cloud
  to:
    kind: Service
    name: guestbook-svc
    weight: 100
  port:
    targetPort: 3000
  tls:
    termination: edge
    insecureEdgeTerminationPolicy: Redirect
  wildcardPolicy: None
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: guestbook-route
  labels:
    app: guestbook
spec:
  host: guestbook.kkimura-mycluster-jp-osa-6fe57c7eaf38abe6232341d97eae54c0-0001.jp-osa.containers.appdomain.cloud
  to:
    kind: Service
    name: guestbook-svc
    weight: 100
  port:
    targetPort: 3000
  tls:
    termination: edge
    insecureEdgeTerminationPolicy: Redirect
  wildcardPolicy: None
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: guestbook-route
  labels:
    app: guestbook
spec:
  host: 5ca5ada9-jp-osa.lb.appdomain.cloud
  to:
    kind: Service
    name: guestbook-svc
    weight: 100
  port:
    targetPort: 3000
  tls:
    termination: edge
    insecureEdgeTerminationPolicy: Redirect
  wildcardPolicy: None

これによりパブリックロードバランサー(5ca5ada9-jp-osa.lb.appdomain.cloud)への HTTPS アクセスが可能になります。ただ証明書が自己証明書のため、アクセス制約がかかります。この yaml ファイルでデプロイしなおします(VPN を切ったままの場合は再接続してから):
$ oc apply -f guestbook_deployment.yaml


そしてブラウザでアクセスしてみます。具体的には以下のようになります。VPN を切断後にブラウザで https://5ca5ada9-jp-osa.lb.appdomain.cloud にアクセスすると、以下のような画面になります。「詳細設定」をクリックします:
2023020202


証明書が自己証明書なので安全ではない、というメッセージが表示されます。安全ではないことを理解した上でアクセスしてみます:
2023020203


すると、(保護はされていないけれど)一応 HTTPS でアクセスできることが確認できます:
2023020204


このパブリックロードバランサーのドメインは OpenShift 環境から自動発行されたもので、内部的に使うぶんにはこれで問題ないのですが、ユーザーが直接使う場合はちょっと気になる部分ではあります:
2023020205


後述の手順で正しい証明書を使った HTTPS アクセス方法を紹介しますが、こちらにも別の制約事項があるので、両方理解した上でどちらを使うべきか検討してください。


【3. プライベート OpenShift クラスタにアプリケーションをデプロイし、カスタムドメインの証明書を使って HTTPS アクセスができるよう定義する】

2023020207


最後のケースは HTTPS としては完成形のような位置づけですが、これまでのケースにはない制約事項が1つあります。それは「カスタムドメインを使う」必要がある点です。2. では IBM Cloud 発行のドメインを使って HTTPS ができなかったのを、自前のドメインを使うことで回避する方法になります。

例えば "pi314.jp" というカスタムドメインを使うことにして、2. までに説明してきたアプリケーションを "guestbook.pi314.jp" というホスト名で HTTPS アクセス可能にする、という想定で以下の説明を行います。

まずカスタムドメインの DNS を設定します。契約したドメイン会社や DNS 移管先によって具体的な設定手順は異なりますが、guestbook という CNAME に対して、パブリックロードバランサー名を設定します(下図は CloudFlare.com を使った場合のスクリーンショット):
2023020206


更にデプロイ用の guestbook_deployment.yaml をもう一度改良して、赤字部分を更に追加します:
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:
  - port: 3000
    protocol: TCP
    targetPort: 3000
  selector:
    app: guestbook
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: guestbook-route
  labels:
    app: guestbook
spec:
  host: guestbook.kkimura-mycluster-jp-osa-6fe57c7eaf38abe6232341d97eae54c0-i000.jp-osa.containers.appdomain.cloud
  to:
    kind: Service
    name: guestbook-svc
    weight: 100
  port:
    targetPort: 3000
  tls:
    termination: edge
    insecureEdgeTerminationPolicy: Redirect
  wildcardPolicy: None
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: guestbook-route
  labels:
    app: guestbook
spec:
  host: guestbook.kkimura-mycluster-jp-osa-6fe57c7eaf38abe6232341d97eae54c0-0001.jp-osa.containers.appdomain.cloud
  to:
    kind: Service
    name: guestbook-svc
    weight: 100
  port:
    targetPort: 3000
  tls:
    termination: edge
    insecureEdgeTerminationPolicy: Redirect
  wildcardPolicy: None
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: guestbook-route
  labels:
    app: guestbook
spec:
  host: 5ca5ada9-jp-osa.lb.appdomain.cloud
  to:
    kind: Service
    name: guestbook-svc
    weight: 100
  port:
    targetPort: 3000
  tls:
    termination: edge
    insecureEdgeTerminationPolicy: Redirect
  wildcardPolicy: None
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: guestbook-route
  labels:
    app: guestbook
spec:
  host: guestbook.pi314.jp
  to:
    kind: Service
    name: guestbook-svc
    weight: 100
  port:
    targetPort: 3000
  tls:
    termination: edge
    insecureEdgeTerminationPolicy: Redirect
  wildcardPolicy: None

この yaml ファイルを(VPN が切れている場合は再接続してから)再度適用します:
$ oc apply -f guestbook_deployment.yaml

そして VPN を切断し、ブラウザでカスタムドメイン側に登録した名前(guestbook.pi314.jp)に HTTPS アクセスしてみましょう:
2023020207


警告などが表示されることなく、ちゃんと HTTPS でパブリックアクセスできることが確認できるはずです。


以上、コンテナ環境を運用する上で
・コンテナ管理はプライベートネットワークで運用し、
・デプロイしたアプリはパブリックネットワークから利用する

という要件はあってもおかしくなさそうですが、今回紹介したような方法で実現できそうです。自己証明書を使うページはスマホから利用するのが難しいのですが、カスタムドメインという高めのハードルを越えることができればその問題もなくなります。利用環境や目的に応じて検討してください。