OpenShiftで独自ドメインを使ったWeb アプリを公開する


1.はじめに

OpenShift で独自ドメインのアプリを公開してみます。

この手順では、シンプルな HTTP アプリケーション(Apache のデモアプリ) を公開してみます。

2. OpenShift のドメインでアプリをデプロイする

まずは普通に、OpenShift が持っているドメインを使って、アプリをデプロイしてみます。
(その後、独自ドメインに変更します)

この OpenShift 環境は
rosa-cluster.3fof.p1.openshiftapps.com

というベースのドメインを使用しています。
OpenShift は、アプリケーション用にはapps というドメインを自動的に足し、

*.apps.rosa-cluster.3fof.p1.openshiftapps.com
というサブ・ドメインが使われるようになっています。

*の所は作成されるアプリ毎に変わります。

が、IPアドレスは同じものが使われます。
同じIPアドレスで一旦受けて、後述するHostヘッダーでどこ行きのトラフィックかを見分けて、Podにトラフィックを振り分けています。

2.1 Project を作成する

作業用の project を作成します。(Kubernetesnamespaceを拡張したリソースです。)

oc new-project myapp1

これで作業用のmyapp1 という project ができました。

ちなみにこのprojectというリソースは、kubectl get namespace でも oc get project でもどちらでも表示されます。

OpenShiftprojectは、kubernetesnamespaceとしても取り扱う事ができるコンバーチブルなKubernetesリソースです。

2.2 Apache アプリを作成する

centos/httpd-24-centos8 というCentOS8S2I builder imagehttps://github.com/sclorg/httpd-ex というGitHub上のソースコードを足して新しいイメージをビルドします。

OpenShift独自の方法ですが、Dockerfile無しでカスタマイズされたコンテナイメージを作成できます。

S2Iとは、Source to Imageの略です。
S2I builder imageとは、ベースイメージの中に、コンテナのビルド処理をするS2Iスクリプトが中に入ったイメージです。

コマンドは以下のようになります。これでhttps://github.com/sclorg/httpd-exというソースコード (単純な html ファイルです)を使った新しいイメージがビルドされ、クラスタ内でClusterIPサービスとして公開されます。

$ oc new-app centos/httpd-24-centos8~https://github.com/sclorg/httpd-ex

# GitHub 上にある 「S2I builder image」 の 「centos/httpd-24-centos8」  に
# 「https://github.com/sclorg/httpd-ex」をコピーして
#  新しいイメージをビルドしている。

できたClusterIPサービスを確認してみます。

ClusterIPは、Clusterの別のPodからアクセスできるIPアドレスなので、この時点では、このサービスは、OpenShiftクラスタの内部にしか公開されていません。

$ oc get svc
NAME       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
httpd-ex   ClusterIP   172.30.139.58   <none>        8080/TCP,8443/TCP   75s

このClusterIPサービスであるhttpd-ex を今度は、Clusterの外の世界に公開exposeします。

$ oc expose service httpd-ex
route.route.openshift.io/httpd-ex exposed

exposeにより、クラスター外部からアクセスするためのrouteというリソースが作成されます。
これで OpenShfitクラスター外部に、ClusterIPサービスが公開されました。

作成された route リソースを確認すると、アクセスURLが分かります。

$ oc get route
NAME       HOST/PORT                                                     PATH   SERVICES   PORT       TERMINATION   WILDCARD
httpd-ex   httpd-ex-myapp1.apps.rosa-cluster.3fof.p1.openshiftapps.com          httpd-ex   8080-tcp                 None

2.3 アクセス確認

このサービス httpd-ex-myapp1.apps.rosa-cluster.3fof.p1.openshiftapps.com にアクセスできるかブラウザで確認しみてみます。

無事アクセスできました。

3.独自ドメインに変更する

さて、このアプリを独自ドメインに変更してみます。

3.1 Route を編集する

oc edit route で、この Webアプリの Route リソースである httpd-ex を編集します。

独自ドメインは myapp1.ocp4.work とします。

spec.hosthttpd-ex-myapp1.apps.rosa-cluster.3fof.p1.openshiftapps.com から myapp1.ocp4.work に変更します。

$  oc edit route httpd-ex
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  annotations:
    openshift.io/host.generated: "true"
  creationTimestamp: "2021-06-14T09:33:13Z"
  labels:
    app: httpd-ex
    app.kubernetes.io/component: httpd-ex
    app.kubernetes.io/instance: httpd-ex
  name: httpd-ex
  namespace: myapp1
  resourceVersion: "66041"
  uid: 7372eb12-4cb2-4ec6-a38c-c91ce505e8c4
spec:
  host: httpd-ex-myapp1.apps.rosa-cluster.3fof.p1.openshiftapps.com →  myapp1.ocp4.work に変更                                            
  port:
    targetPort: 8080-tcp
  to:
    kind: Service
    name: httpd-ex
    weight: 100
  wildcardPolicy: None

# 保存して exit

# 設定を確認します。
$ oc get route/httpd-ex -o jsonpath='{.spec.host}{"\n"}'
myapp1.ocp4.work
$ 

3.2 CNAMEを行う

独自ドメインの ocp4.work ゾーンを管理している DNS 権威サーバーにアクセスします。

独自ドメインの myapp1.ocp4.work から、元元のドメインの httpd-ex-myapp1.apps.rosa-cluster.3fof.p1.openshiftapps.comCNAMEをしてあげます。

この例は Route 53 を使用しましたが、以下のような感じのDNSレコードを作ります。

CNAMECは、Canonicalの意味で、正規の等と訳されます。 myapp1.ocp4.work の正規の名前はhttpd-ex-myapp1.apps.rosa-cluster.3fof.p1.openshiftapps.comと指定するのがCNAMEです。

以上で独自ドメイン化の作業としては完了です。

この CNAMEという作業をすると、クライアントから myapp1.ocp4.workの IPアドレスの解決の問い合わせが来た時に、「実は、私の正規の名前はhttpd-ex-myapp1.apps.rosa-cluster.3fof.p1.openshiftapps.com です。IPアドレスは、そちらにおたずね下さい。」とクライアントに応答が返されます。

その応答を受け取った、IPアドレスの問い合わせをしに来たクライアントは、「なるほど」と、今度は、httpd-ex-myapp1.apps.rosa-cluster.3fof.p1.openshiftapps.comDNSレコードを管理するDNSサーバーに IPアドレスを尋ねにいきます。

httpd-ex-myapp1.apps.rosa-cluster.3fof.p1.openshiftapps.comのドメインを管理しているDNSサーバーは、IPアドレスを持っているので、そのIPアドレスを問い合わせ元のクライアントに返却します。以上でドメインの名前解決が完了する。という動きになります。

結果として、myapp1.ocp4.workIPアドレスは、httpd-ex-myapp1.apps.rosa-cluster.3fof.p1.openshiftapps.comIPアドレスが使用される事になります。

3.3 アクセス確認

無事にアクセスできました。

4.OpenShift の アプリケーション用のドメイン

ここでクラスター外部から来たトラフィックが、どうやってアプリケーションのPodまで到達するのかを、ここまで行った作業を交えながら考えて見ます。

今回の例では、AWSの上に構築した、標準的なOpenShiftを利用しました。

OpenShiftを構築した場合、外部に公開するアプリケーションに対しては、*.apps.<クラスター名>.<OpenShift 作成時に与えたドメイン名> のドメイン名が自動的に割り当てられます。

今回の例ではアプリケーションドメイン名は下の図の赤枠の部分で示している*.apps.rosa-cluster.3fof.p1.openshiftapps.comでした。

外部に公開するアプリケーションは、*.apps.rosa-cluster.3fof.p1.openshiftapps.comのワイルドカード部分を変更したドメイン名が割り当てられます。

今回の例では、*の部分がhttpd-ex-myapp1でした。apps.rosa-cluster.3fof.p1.openshiftapps.com

複数のアプリを公開した場合でも*の部分が別名に替わるだけで、同じIPアドレスに誘導されます。

今回のケースの場合、誘導されたIPアドレスはAWS環境なのでちょっと特殊な記述方法になっていますが、a8fa5687ee7a34cfc900bb242f25747e-368521378.ap-northeast-1.elb.amazonaws.com. というELB(Elastic Load Balancer)IPになっています。(通常のDNSは、ここには数字のIPアドレスが記載されます)

4.1 Host ヘッダー

全てのアプリケーションが同じIPアドレス(この例の場合はELBIP)に解決されるのに、どうやってOpenShiftは、それぞれのPodにトラフィックを誘導しているのでしょうか。

これは、全てのHTTPリクエストは、その中にHTTP Host ヘッダーと呼ばれる、ヘッダーを持っていて、そのHostヘッダーの値を利用しています。Host ヘッダーの値は、ブラウザーのURLとして打ち込んだドメインの名が渡されます。

ですので、今回の場合は、myapp1.ocp4.workHostヘッダーにセットされています。

HTTPリクエスト時にどんな Hostヘッダーが送られているかは、ブラウザーのDeveloperツールで確認する事ができます。(以下のHost:の部分)

OpenShiftの標準構成では、HTTPアプリケーションへのリクエストはRouterと呼ばれる Podが受け取ります。

以下は、2つのRouter Podが稼働している例です。インターネットから、外部のロードバランサー(ELB)に到達したトラフィックは、この2つのPodに割り振られます。(Routerの数は、負荷を考えて増やす事ができるので、3つの構成もあります)

$ oc get pods -n openshift-ingress
NAME                              READY   STATUS    RESTARTS   AGE
router-default-5577468466-cjmm2   1/1     Running   0          3h19m     ### router-default-xxxx という名前になります。
router-default-5577468466-gdd7w   1/1     Running   0          3h19m     ### これらの router は通常 Node に分散されて配置されています。
$ 

このRouterHostヘッダーの値を見て、どの Podに来たリクエストなのか。を判別して割り振っています。

この時にどのHostヘッダーの値が、どのPodに行くべきか。を判断するのに参照するのが、3.1 Route を編集するで編集したRouteになります。

ここまでの話を図示すると以下のようになります。

RouterRouteと似たようなリソース名があるので、少し混乱しますが、Routerが実際に動いているPodRouteRouterが参照している設定ファイルのように考えると良いと思います。

一つのRouterは、複数のRouteを取り扱う事ができるので、一つのIPで複数のドメインを運用できます。

今回はAWS環境なので上の図のLoad Balancerは、ELBになっていますが、オンプレ環境ではELBの部分がオンプレで用意したLoad Balancerになります。

5.参考資料

カスタムドメインの仕組みについて P.24から解説があります。

メモ:標準で生成されるembed 用の script タグを使っても P.24から表示しないので data-idの最後に?slide=24を追加。data-slideが無視されているように見える。