[ 言語選択: English ]
目次

1. ユーザーリスト

学内からゼミ室内で稼動しているKubernetes上のアプリケーションにアクセスするための仕組みを準備しています。

利用には事前の設定が必要ですので、下記のユーザーリストに自分のNamespace(AINS-ID)が存在するか確認してください。

2. 基本的なReverse Proxyの利用

この環境で準備されているIngressの構成では、各ユーザーに対応するServiceオブジェクト、"<namespace名>-svc"に接続します。

setupk8s centos.20210531 SCCP IngressNetwork

この構成では、1つのServiceにだけ接続するため、nginx, dvwaなど複数のWebアプリケーションに外部からアクセスするには工夫が必要です。

そのためIngressからの接続をReverse Proxy(nginx)サーバーで受けて、自分が外部に公開したいサーバーにリクエストを転送します。

ingress proxy.20210531 SCCP IngressNetwork Advanced

ここでは <namespace名>-svc という命名規則(Naming Rule)でServiceを定義する点に注意してください。

2.1. テスト用のnginxを構築する

今回利用するテスト用のnginxを構築します。

まず pod/my-nginx を構成します。 設定するのは、Deploymentオブジェクトですが、deploymentreplicasetpod の順番に自動的に pod/my-nginx が作成されます。

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: my-nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-nginx
  template:
    metadata:
      labels:
       app: my-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        imagePullPolicy: "Always"
        ports:
        - containerPort: 80

このコードは次のように適用できます。

$ kubectl -n $(id -un) apply -f "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/ingress-proxy.deploy-nginx.yaml"

次に svc/my-nginx を作成します。

---
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    app: my-nginx
spec:
  type: ClusterIP
  ports:
     -  port: 80
        protocol: TCP
        targetPort: 80
  selector:
    app: my-nginx
$ kubectl -n $(id -un) apply -f "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/ingress-proxy.svc-nginx.yaml"

この時点ではWebブラウザから、nginxに接続することはできません。 外形的にpodservice が構成されているか確認していきます。

2.1.1. テスト用nginxの確認作業

次のように作成されているか確認します。

$ kubectl -n $(id -un) get pod,svc -l app=my-nginx -o wide

次のように表示されるはずです。

NAME                         READY   STATUS    RESTARTS   AGE    IP               NODE       NOMINATED NODE   READINESS GATES
pod/nginx-64b9f4f665-bc7ls   1/1     Running   0          114s   10.233.112.236   u109ls03   <none>           <none>
pod/nginx-64b9f4f665-mrbcv   1/1     Running   1          28d    10.233.105.21    u109ls04   <none>           <none>

NAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE     SELECTOR
service/my-nginx   ClusterIP   10.233.44.114   <none>        80/TCP    2m19s   app=my-nginx

ここでは、次のことを確認してください。

  1. pod/my-nginx で始まるPodオブジェクトが2つ作成されていること

  2. service/my-nginx という名前でServiceオブジェクトが作成されていること

  3. service/my-nginx の SELECTOR が app=my-nginx を指していること

この状態では service/my-nginx は外部から接続するためのEXTERNAL-IPを持っていないため、Webブラウザからアクセスすることはできません。

次に inovtst9.u-aizu.ac.jp を経由して、このNginxにアクセスするためのProxyサーバーを構築していきます。

2.2. NginxによるReverse Proxyサーバーを構築する

これまで利用してきたnginxを利用して、Reverse Proxyサーバーを構成します。

                                                 +-------------+       +---------+       +-----------+
https://inovtst9.u-aizu.ac.jp/<namespace>/ ----> |   ingress   | ----> |  proxy  | ----> |  dvwa 等  |
                                                 +-------------+       +---------+       +-----------+
                             context_root:       /<namespace名>/       /<namespace名>/    /
                                      url:       http://inovtst9.u-aizu.ac.jp/<namespace>/
                                                                       http://<namespace>-svc/<namespace>/
                                                                                          http://<cluster-ip>/

Reverse Proxyサーバーと呼んでいますが、利用するイメージは my-nginx で利用しているものと同じです。

今回は次のような設定ファイルを /etc/nginx/conf.d/proxy.conf の名前で配置するPodを作成することにします。 この設定により、context_rootは /yasu-abe/ から / に変換されます。

server {
    listen 80;
    location /yasu-abe/ {
        proxy_pass    http://my-nginx/;
    }
}

このような設定を行なうために、次のような configmap-proxy.yaml ファイルを適用します。

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-conf
  labels:
    app: my-proxy
data:
  proxy.conf: |
    server {
      listen 80;
      location /s12xxxxx/ {
        proxy_pass    http://my-nginx/;
      }
    }

このファイルを先ほどと同じように適用します。

$ curl "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/ingress-proxy.configmap-proxy.yaml" | sed -e "s/s12xxxxx/$(id -un)/" | kubectl -n $(id -un) apply -f -

このConfigMapに設定した設定ファイルを利用する、nginxをmy-proxyの名前で作成します。

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: proxy
  labels:
    app: my-proxy
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-proxy
  template:
    metadata:
      labels:
       app: my-proxy
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        imagePullPolicy: "Always"
        ports:
        - containerPort: 80
        volumeMounts:
        - name: config
          readOnly: true
          mountPath: /etc/nginx/conf.d/
      volumes:
      - name: config
        configMap:
          name: nginx-conf
          items:
           - key: proxy.conf
             path: proxy.conf

このファイルの内容は、特別変更する箇所はないので、URLを指定して直接実行します。

$ kubectl -n $(id -un) apply -f https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/ingress-proxy.deploy-proxy.yaml

次に、service/<namespace>-svc の名称で、pod/my-proxy に接続するためのServiceオブジェクトを作成します。

---
apiVersion: v1
kind: Service
metadata:
  name: s12xxxxx-svc
  labels:
    app: my-proxy
spec:
  type: ClusterIP
  ports:
     -  port: 80
        protocol: TCP
        targetPort: 80
  selector:
    app: my-proxy

次のような手順で、これを適用します。

$ curl "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/ingress-proxy.svc-proxy.yaml" | sed -e "s/s12xxxxx/$(id -un)/" | kubectl -n $(id -un) apply -f -

2.2.1. my-proxy の確認手順

ここで作成したオブジェクトを次の手順で確認します。

$ kubectl -n $(id -un) get pod,svc,cm -l app=my-proxy

次のような結果が出力されているはずです。

NAME                         READY   STATUS    RESTARTS   AGE
pod/proxy-755bf9945f-bptfs   1/1     Running   0          19h
pod/proxy-755bf9945f-xm885   1/1     Running   0          16m

NAME                   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/yasu-abe-svc   ClusterIP   10.233.10.107   <none>        80/TCP    3m30s

NAME                   DATA   AGE
configmap/nginx-conf   1      42d

ここまでの手順が成功していれば、Webブラウザを通して次の自分用のURLからアクセスできるはずです。

2.3. Reverse Proxy (my-proxy) を経由して、Webサーバー(my-nginx)にアクセスする

ここまでで、最初に構成したnginxサーバーに、Proxyサーバーを経由してアクセスする準備が整いました。

下記のユーザーリストから自分のURLに数回アクセスし、各サーバーのログファイルを確認してください。

## Proxyサーバーの通信ログを確認する手順
$ kubectl -n $(id -un) logs -l app=my-proxy
## Nginxサーバーの通信ログを確認する手順
$ kubectl -n $(id -un) logs -l app=my-nginx

'-f’オプションを追加したり、パイプ("|")とtailコマンドを組み合せるなどして出力を調整してください。

2.3.1. ユーザーリスト

2.4. 【解説】設定で利用している sed コマンドの目的について

ここでは、同じ作業手順で、ユーザーIDの違いを吸収する必要があります。 BASHコマンドラインでは、$(id -un) を利用することで、ユーザーIDに変換しています。

svc-proxy.yaml 等のYAMLファイルを利用する際には、metadataなどの部分で指定している名前(s12xxxxx)を各自のユーザーIDに変更しています。

svc-proxy.yamlを例として、変換の方法を説明します。

metadata:
  name: s12xxxxx-svc

このname:の部分は、自分のID(namespace名)に一致させる必要があります。 svc-nginx.ymalファイルは、先ほどど同様に apply します。

この作業には、次のように2つの方法が考えられます。

2.4.1. 方法1: ここでは利用していないが、一般的な方法

一般的な方法ですが、方法2と比較すると、少し難易度が上がったり、間違いが入り込む余地があります。

## 設定ファイルをダウンロードします
$ wget "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/ingress-proxy.svc-proxy.yaml"

## name:〜を変更するため、適当なEditor(emacs/vim/nano/etc.)で編集します
$ emacs svc-proxy.yaml

## 変更したsvc-nginx.yamlファイルの内容を反映させます。
$ kubectl -n $(id -un) apply -f svc-proxy.yaml

2.4.2. 方法2: このSCCPで利用している、実行時に変換する方法

あるいは、もう一つの方法として、エディタを使わない方法もあります。 次の1行を実行すれば、内容は反映されるので、こちらの方法が間違いが入り込む可能性は、かなり下がります。

$ curl "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/ingress-proxy.svc-proxy.yaml" | sed -e "s/s12xxxxx/$(id -un)/" | kubectl -n $(id -un) apply -f -

この方法を主に採用していますが、教育的ではないかもしれません。

仕事で他人にコマンドの実行を依頼するような場合には、このような工夫をすることで編集ミスなどが入り込む余地をなくし、エラーが発生する可能性を下げることができます。

このコマンドの中で何をやっているか、echoコマンドを効果的に利用したり、パイプの途中まで実行して、どのような処理を行なっているのか分析したり、自分なりに理解するようにしてください。

ステップ1. echoコマンドを利用する例: $(id -un) がどう処理されているのか確認する

$ echo kubectl -n $(id -un) apply -f -
kubectl -n yasu-abe apply -f -

次にステップ2. パイプの途中まで実行する

$ curl "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/ingress-proxy.svc-proxy.yaml" | sed -e "s/s12xxxxx/$(id -un)/"
---
apiVersion: v1
kind: Service
metadata:
  name: yasu-svc
...

2.4.3. nginx設定ファイルについて

自分で簡単なWebサーバーを構成するために、nginxやApache httpdの設定ファイルの概要は把握しておくと便利です。

目的にもよりますが、ドキュメントを全て読むことは現実的ではありません。

サーバーソフトウェアの使い方よりも、HTTPプロトコル(HTTP/2, QUIC, etc.)について学ぶようにしてください。

3. コンテキスト・ルート (context_root) について

Webアプリケーションにおいて、トップディレクトリから始まるpath、このSCCPの場合は /s12xxxxx/, /yasu-abe/ のように自分のIDから始まる部分をコンテキスト・ルート (以下、context_root) と呼びます。

主にJavaEEで利用される用語ですが、一般的なWebアプリケーションを作成・利用する際にも重要な概念です。

3.1. コンテキスト・ルートを変更できないアプリケーション

一般に公開・市販されているアプリケーションの中には、特定のcontext_rootでしか動作しないものがあります。 そのようなアプリケーションの多くはcontext_rootとして、"/" を使用するため、専用のホスト名を必要とする事が一般的です。

アプリケーション毎にcontext_rootを分けることで、単一のホスト名の元に複数のアプリケーションを含めることが可能となります。

技術的にはホスト名を複数準備しても、VirtualHostというHTTPヘッダのHost:行を見て挙動を変更する機能を利用すれば、物理的なサーバーは1台で対応可能で、必ずしもホスト名を割り当てなればいけない事が問題になるとは限りませんが、以下のような問題があります。

  • ブランディングのため単一のホスト名の元にコンテンツを集約することができない

    • ドメイン名まで含めてホスト名を変更した場合、偽造サイトなのか、正規のサイトなのか判断が難しくなる

    • 暗号化通信を行なうTLSの証明書を取得するための費用が必要となる場合がある (⇔ Wildcard証明書)

  • 主にDNSの利用制限により、VirtualHostの利用が容易でない場合には、サービスの利用そのものが難しくなる

    • 会津大学では基本的に、1つのIPアドレスに1つのホスト名がDNSに登録されています

コンピュータプログラムにおいては、再配置可能(relocatable)である事は意識されますが、Webアプリケーションの場合にはJ2EEアプリケーションであっても無視されることがあります。

Proxyを利用することによって、これらの問題をある程度は解決できますが、アプリケーションが'/'とは異なるcontext-rootで動くことを想定していない場合には、特定の操作ができないといった不具合に遭遇することになります。

3.2. 具体的な問題の例

例えば、2018年後期に、第9回目のSCCPで取り上げたdvwaをK8sにデプロイする場合を例に説明します。

まずpodを稼動させます。これは2018年に提供したYAMLファイルをそのまま利用します。

$ kubectl -n $(id -un) apply -f "https://web-int.u-aizu.ac.jp/%7Eyasu-abe/ja/sccp/edwi/2018/AY20182H_No09/01.deploy-dvwa.yaml.txt"

この `pod/dvwa にアクセスするために次のようなServiceオブジェクトを作成します。

---
apiVersion: v1
kind: Service
metadata:
  name: dvwa-svc
spec:
  type: ClusterIP
  ports:
     -  port: 80
        protocol: TCP
        targetPort: 80
  selector:
    app: dvwa

以下のように適用します。

$ kubectl -n $(id -un) apply -f https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/ingress-proxy.svc-dvwa.yaml

Proxyから、このサービスにアクセスするために、次のように変更した、ConfigMapオブジェクトを登録します。

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-conf
  labels:
    app: my-proxy
data:
  proxy.conf: |
    server {
      listen 80;
      location /s12xxxxx/ {
        proxy_pass    http://dvwa-svc/;
      }
    }

editコマンドで cm/nginx-conf を編集し、my-nginxdvwa-svc に変更するだけでも良いのですが、次の方法でも cm/nginx-conf を変更できます。

$ curl "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/ingress-proxy.configmap-proxy-dvwa.yaml" | sed -e "s/s12xxxxx/$(id -un)/" | kubectl -n $(id -un) apply -f -

このように設定を変更したら、反映させるために、pod/my-proxy を削除します。

$ kubectl -n $(id -un) delete pod -l app=my-proxy

ここまでの操作が完了すると、以下のURLからdvwaアプリにアクセスできるようになっています。

次のリストから自分のURLlにアクセスし、確認してください。 最初はブラウザのキャッシュ(cache)からNginxのページが見えるかもしれないので、Shiftキーを押下しながら再読み込みしてください。

3.2.1. ユーザーリスト

3.3. DVWAアプリの操作とcontext-rootについて

無事に成功すると、次のような画面が表示されるはずです。

ingress proxy.20210601 SCCP dvwa login

このアプリケーションの次の情報を利用してログインしてください。

  • ID: admin

  • Password: password

以下の手順で、初回操作を完了します。

  • admin/passwordを入力し、ログインする

  • Create / Reset Database ボタンを押す

  • 正常に動作せず、数秒後に、https://inovtst9.u-aizu.ac.jp/ にリダイレクトされるので、タブを消す

  • 再びユーザーリストの一覧から、自分のIDのリンク (e.g. https://inovtst9.u-aizu.ac.jp/s12xxxxx/) に進み、改めてログインする

これで、一応アプリケーションを利用することができるようになります。

3.3.1. 具体的な不具合

まずCreate / Reset Databaseボタンを押して、まったく関係のないページにリダイレクトされた事に気がついているはずです。

この他に、アプリケーションにログインし、View SourceView Help といったボタンが反応しないことを確認してください。

これはボタンが単純なHTMLではなく、JavaScriptで記述されていて、この部分では相対パスではなく、'/'からの絶対パスで作られている事が原因です。

<!-- 問題を起こしているコードの例 -->
<script src='/dvwa/js/add_event_listeners.js'></script>

指定された /dvwa/js/add_event_listeners.js にアクセスしようとしても、このファイルには到達できません。

inovtst9.u-aizu.ac.jp の nginx の access.log には、次のようなアクセスログが残されています。

163.143.xxx.xxx - - [13/Jul/2021:14:29:33 +0900] "GET /dvwa/js/add_event_listeners.js HTTP/2.0" 200 449 "-" "Mozilla/5.0 (X11; Ubun
tu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0" "-"

add_event_listeners.js の内容は次のような内容になっていて、ボタンが押下された時に反応するようになっています。

// These functions need to be called after the content they reference
// has been added to the page otherwise they will fail.

function addEventListeners() {
        var source_button = document.getElementById ("source_button");

        if (source_button) {
                source_button.addEventListener("click", function() {
                        var url=source_button.dataset.sourceUrl;
                        popUp (url);
                });
        }

        var help_button = document.getElementById ("help_button");

        if (help_button) {
                help_button.addEventListener("click", function() {
                        var url=help_button.dataset.helpUrl;
                        popUp (url);
                });
        }
}

他のフィアルと同様に、相対パスで、JavaScriptファイルを指定していれば、このような問題は発生しません。 なぜかこの場所だけが、絶対パスで記述されていたため、不具合を引き起す原因となっていました。

4. 【補足】Dockerを利用したDVWAの完全な利用

今回の例は不完全なdvwaの紹介だったので、もしちゃんとdvwaを起動させたいという場合には、Dockerが稼動しているThinkPadや自分のPCなどで次のコマンドを実行してください。

ThinkPadなどのrootless-modeを利用している場合には、まずdockerdを自分用に起動します。

$ export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock
$ mkdir -p ~/.config/docker
$ echo "{ \"data-root\":\"/var/tmp/$(id -un)\" }" | tee ~/.config/docker/daemon.json
$ dockerd-rootless.sh &

続いて、dockerコマンドを実行します。

$ docker run --rm -it -p 8080:80 --name dvwa vulnerables/web-dvwa

Webブラウザでlocalhostに接続してください。

利用が終ったら、C-d (Controlキーを押しながら、dキーを押下) で終了できます。

他の人が既に試してバックグランドで動いている場合には、次の要領で停止してください。

$ sudo killall dockerd docker

自分が動作しているdockerプロセスを停止する場合には、Controlキー + c や killallコマンドを利用してください。

このDockerの利用は、Kubernetesではなく、Dockerが動いているゼミ室のThinkPadや自分のPCで実行している点に注意してください。

5. 復習編

ここまで無事に進めてきたら、記録(ログ)を利用してProxyを利用した構成を確認しましょう。

まず ユーザーリスト から、自分のURLにアクセスして、ログを残します。 この時に、Proxyとその先のdvwaやmy-nginxのpodの両方にアクセスした記録が残っているので、これをログします。

5.1. Proxyのログを確認する

$ kubectl -n $(id -un) logs -l app=my-proxy

日付から自分がアクセスした際の記録を確認します。

10.233.105.16 - - [17/Jun/2021:09:21:51 +0000] "GET /yasu-abe/login.php HTTP/1.1" 200 699 "https://web-int.u-aizu.ac.jp/"
 "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0" "10.233.112.0"

5.2. 自分のProxy設定から接続先のアプリケーション(pod)を確認する

Proxyがmy-nginx, dvwaのうち、どのアプリケーションに向いているか設定を確認しておきます。

$ kubectl -n $(id -un) get cm nginx-conf -o yaml | grep proxy_pass:

次のような出力を確認します。

proxy_pass    http://dvwa-svc/;
...

このような状況であれば、dvwa-svcに向いていることが分かるので、dvwaアプリの出力を確認します。

5.3. DVWAのログを確認する

$ kubectl -n $(id -un) logs -l app=dvwa

次のようなログが確認できると思います。

10.233.105.20 - - [21/Jun/2021:06:57:40 +0000] "GET /favicon.ico HTTP/1.0" 200 1670 "https://inovtst9.u-aizu.ac.jp/yasu-a
be/" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0"

5.3.1. Proxy(nginx)/DVWAのログ(apache2)を解析する

先ほど表示したDVWAのログはApache HTTP Serverが出力した形式のログになっています。 詳しい説明は以下のテーブルを確認してください。

No. 内容 説明

1

10.233.105.20

接続元のIPアドレス (今回はmy-proxyのpodのIPのはず)

2

-

リモートログ名 (いまはほんど利用されないidentを利用する場合)

3

-

リモートユーザー名 (Apacheが認証して把握してるユーザー名)

4

[21/Jun/2021:06:57:40 +0000]

アクセスした時刻

5

"GET /favicon.ico HTTP/1.0"

HTTPリクエストの1行目

6

200

ステータスコード (200は成功、400番台はエラー)

7

1670

返信する内容のバイト数

8

"https://inovtst9.u-aizu.ac.jp/yasu-abe/"

Refererヘッダがあれば内容を表示 (通常はリンクをクリックした(つまり、1つ前の)ページのURL)

9

"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0"

User-Agentヘッダがあれば内容を表示 (Webブラウザの種類)

"10.233.105.20" がmy-proxyのIPアドレスであるのかどうか、次のようなコマンドで確認できます。

$ kubectl -n $(id -un) get pod -l app=my-proxy -o wide

このコマンドを実行すると、次のような出力が得られます。

NAME                     READY   STATUS    RESTARTS   AGE     IP              NODE       NOMINATED NODE   READINESS GATES
proxy-755bf9945f-87x2z   1/1     Running   2          6d21h   10.233.105.20   u109ls04   <none>           <none>

このIPの列をみると、"10.233.105.20"となっていて、ProxyサーバーのPodが10.233.105.20で動いていて、これを経由してDVWAのアプリケーション(Pod)にアクセスしていることが分かります。

6. Proxyの設定を改めて確認する

KubernetsのConfigMapという仕組みで、Proxyサーバー上に設定フィアルを配置し、動作を制御しています。 ここまでで利用してきた設定を改めて確認します。

6.1. configmap-proxy.yaml (cm/nginx-conf) 設定の確認

まずテンプレートとして利用したYAMLファイルの内容は次のようになっています。

$ curl "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/setupk8s-centos.configmap-proxy.yaml"
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-conf
data:
  proxy.conf: |
    server {
      listen 80;
      location /s12xxxxx/ {
        proxy_pass    http://dvwa-svc/;
      }
    }

ここで、"s12xxxxx"を自分のAINS-ID(namespace)に変更していて、、"dvwa-svc"というホスト名を指定することで、my-nginxのpodにアクセスさせていました。

これらの変換を行なった、実際の設定は次のようになっています。

$ kubectl -n $(id -un) get cm/nginx-conf -o yaml
apiVersion: v1
data:
  proxy.conf: |
    server {
      listen 80;
      location /yasu-abe/ {
        proxy_pass    http://dvwa-svc/;
      }
    }
kind: ConfigMap
metadata:
...

このホスト名を含む http://dvwa-svc/ の部分を、http://my-nginx/ とすることで、当初はnginxに接続していました。

6.2. Services定義の確認

これまで利用してきたService定義を確認してみます。

$ kubectl -n $(id -un) get svc

例えば次のようにServiceに設定した項目が表示されるはずです。

NAME           TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
dvwa-svc       ClusterIP   10.233.27.4     <none>        80/TCP    14m
my-nginx       ClusterIP   10.233.44.200   <none>        80/TCP    84m
yasu-abe-svc   ClusterIP   10.233.50.71    <none>        80/TCP    78m

Ingressのリクエストを処理する <your namespace>-svc (e.g. yasu-abe-svc and s13xxxxxx-svc) の定義を確認します。

$ kubectl -n $(id -un) get svc "$(id -un)-svc" -o yaml

出力から .spec.selector の内容を確認します。 次のように app: my-proxy となっていると、https://inovtst9.u-aizu.ac.jp/s13xxxxxx/ のようなURLでアクセスした際にReverse Proxyサーバーに接続します。

...
  selector:
    app: my-proxy
...

この内容が app: harbor-nginx のように他のアプリケーションを示していると、直接アプリケーションに接続している状況になります。 Reverse Proxyサーバーに接続するためには、次のコマンドを実行してください。

$ curl "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/ingress-proxy.svc-proxy.yaml" | sed -e "s/s12xxxxx/$(id -un)/" | kubectl -n $(id -un) apply -f -

利用しているテンプレートファイルは次のような内容になっていて、"s12xxxxx" の部分を自分のnamespace名(AINS ID)に変更するためにsedコマンドを利用しています。

6.3. Reverse Proxyで複数のサービスを公開する

例えば、次のような cm/nginx-conf を定義すれば、両方のサービスに接続することができます。

dvwaの方はあいかわらず正しく動作しないことに注意してください。
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-conf
data:
  proxy.conf: |
    server {
      listen 80;
      location /s12xxxxx/nginx/ {
        proxy_pass    http://my-nginx/;
      }
      location /s12xxxxx/dvwa/ {
        proxy_pass    http://dvwa-svc/;
      }
    }

このファイルを次のような手順で反映させます。

$ curl "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/ingress-proxy.configmap-proxy-dvwa-nginx.yaml" | sed -e "s/s12xxxxx/$(id -un)/" | kubectl -n $(id -un) apply -f -

これで先ほど確認した cm/nginx-conf が更新されました。

DVWA用に cm/nginx-conf を設定した際のように、設定を反映するためには、pod/my-proxy を再起動します。

$ kubectl -n $(id -un) delete pod -l app=my-proxy

これによって、例えば次のようなURLで両方のサービスにアクセスすることができるようになります。

それぞれにアクセスをして挙動を確認してください。

6.4. cm/nginx-conf に対する基本操作

Reverse Proxyサーバーを設定するためのcm(ConfigMap)/nginx-confオブジェクトに対する基本的な操作についてまとめます。

6.4.1. 内容を確認する(get)

$ kubectl -n $(id -un) get cm/nginx-conf

6.4.2. 内容を変更する(edit)

$ kubectl -n $(id -un) edit cm/nginx-conf

6.4.3. 変更を反映する

$ kubectl -n $(id -un) delete pod -l app=my-proxy

7. Proxyを利用して自分のサービスに接続する

ここから先の説明では、基本的に svc/s12xxxxx-svc を上書きする形で説明をしていきます。

もし自分で pod/my-proxy に複数のサービスを含めたい場合には、ここで利用したような方法で設定フィアルを管理してください。

7.1. 追加したサービス用に configmap/nginx-conf を変更する

次のような方法で、任意のEditorを指定して configmap/nginx-conf を変更することができます。

$ env EDITOR=emacs kubectl -n $(id -un) edit cm/nginx-conf

ここで開いたEditorの中で、追加したサービス用に次のような location セクションを他と並列に配置します。

"newapp-svc"の部分は、適宜、書き換えてください。

      location /yasu-abe/new-app/ {
        proxy_pass    http://newapp-svc/;
      }

http://newapp-svc/ のように書くことができるのは、kubectl -n $(id -un) get svc で確認できるService名に "newapp-svc" が登録されている場合です。

画面に表示されたService名の中から適切な名前を選択して書き換えるか、(LoadBalancerを利用している場合は)IPアドレスを利用して、http://192.168.100.xx/ のように書き換えてください。

最後に必ず変更した後で、ProxyのPodを再起動してください。

$ kubectl -n $(id -un) delete pod -l app=my-proxy

8. PV & PVCで作成したNginxにProxy経由でアクセスする

PV & PVCのページで準備したNginxでは、LoadBalancerを使用して、"192.168.100.163" のようなIPアドレス経由でアクセスしました。

ここでは、このNginxにこのセクションで構成したReverse-Proxyを経由してアクセスするための方法について説明します。

8.1. BlockStorage用Webサーバーにアクセスする

最初に利用した configmap-proxy.yaml を利用して、BlockStorage用のWebサーバーにアクセスできるように cm/nginx-conf を編集します。

$ curl "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/ingress-proxy.configmap-proxy.yaml" | sed -e "s/s12xxxxx/$(id -un)/" -e "s/my-nginx/nginx-block-storage/" | kubectl -n $(id -un) apply -f -

ここで設定した cm/nginx-conf の内容は次のようなコマンドで確認してください。

$ kubectl -n $(id -un) get cm/nginx-conf -o yaml

nginxは設定ファイルを自動的に読み込まないので、pod/my-proxy を一度削除します。

$ kubectl -n $(id -un) delete pod -l app=my-proxy

8.2. FileStorage用Webサーバーにアクセスする

BlockStorageと同じ方法で変更が可能です。

コマンドラインの"block"の文字列を"file"に置き換えて実行してみてください。

8.3. my-nginx/dvwa-svc/nginx-block-storage/nginx-file-storageの各サービスにアクセスする

例えば configmap-proxy.yaml を元に、次のようなYAMLファイルを準備します。

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-conf
  labels:
    app: my-proxy
data:
  proxy.conf: |
    server {
      listen 80;
      location /s12xxxxx/nginx/ {
        proxy_pass    http://my-nginx/;
      }
      location /s12xxxxx/dvwa/ {
        proxy_pass    http://dvwa-svc/;
      }
      location /s12xxxxx/block/ {
        proxy_pass    http://nginx-block-storage/;
      }
      location /s12xxxxx/file/ {
        proxy_pass    http://nginx-file-storage/;
      }
    }

my-proxyの設定ファイルを変更したら、必ずmy-proxyのプロセス(pod)を再起動してください。

$ kubectl -n $(id -un) delete pod -l app=my-proxy

この内容を適当なファイル名のファイルに作成し、次のようなURLでアクセスできることを確認してください。

9. トップページの作成

複数のlocationルールをproxyに追加していくと、個別のURLに直接アクセスする方法では不便になってきます。

Reverse Proxyを効果的に利用するには、トップページを作成したくなってきますが、静的Webページの作成方法については、別の記事にまとめています。

ここでは簡単にnginxのコンテナを作成する方法について説明します。

9.1. 静的コンテンツを提供するNginxコンテナの作成

方法はいろいろありますが、ここでは自分のWebページを提供するDockerコンテナを作成します。

この他には次のような方法が考えられます。

  • コンテナはそのままnginxを利用して、コンテンツを配置したPVCを/var/www/htmlにマウントする

  • コンテナはそのままnginxを利用して、index.htmlをConfigMapオブジェクトとして作成し、/var/www/html/index.html に配置する

  • 静的コンテンツを生成するDockerコンテナを作成し、定期的にPVC(RWX)に書き出す (Hugoを利用する方法の例)

これらの方法の利点は、コンテンツを更新する度にコンテナを再作成・再登録する必要がない点です。

以下の作業は、適当な作業用ディレクトリ内で移動(cd)せずに行います。

9.1.1. はじめに

ThinkPadなどのrootless-modeを利用している場合には、dockerdプロセスを起動します。 Docker Desktopなどを利用している場合には、このコマンドは実行しないでください。

$ export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock
$ mkdir -p ~/.config/docker
$ echo "{ \"data-root\":\"/var/tmp/$(id -un)\" }" | tee ~/.config/docker/daemon.json
$ dockerd-rootless.sh &

9.1.2. Dockerfile

次のようなDockerfileを準備します。

FROM nginx:latest
ADD html /usr/share/nginx/html

9.2. html/ディレクトリ

次のようにhtmlディレクトリを作成し、静的コンテンツを配置します。

$ mkdir -p html
$ cat > html/index.html <<EOF
<html>
<body>
  <ul>
    <li><a href="nginx/">nginx/</a></li>
    <li><a href="dvwa/">dvwa/</a></li>
    <li><a href="block/">block/</a></li>
    <li><a href="file/">file/</a></li>
  </ul>
</body>
</html>
EOF

9.2.1. コンテナのビルド

次のようにコンテナをビルドします。

## Intelアーキテクチャで実行可能なシンプルな方法
$ docker build . --tag inovtst9.u-aizu.ac.jp/$(id -un)/my-top-page:1.0.0

## macOS環境の場合はbuildxを利用します
$ docker login inovtst9.u-aizu.ac.jp
$ docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --tag inovtst9.u-aizu.ac.jp/$(id -un)/my-top-page:1.0.0 --no-cache --push .
$ docker logout inovtst9.u-aizu.ac.jp

エラーがなければ、これを自分のコンピュータで実行し、動作を確認します。

$ docker run --rm -dit -p 8080:80 --name my-top-page inovtst9.u-aizu.ac.jp/$(id -un)/my-top-page:1.0.0

起動した後は手元のWebブラウザから動作を確認します。 次のリンクをClickするか、Shellからコマンドを実行します。

$ browse http://localhost:8080/
## or
$ google-chrome http://localhost:8080/

問題があれば、やり直しが可能ですが、1度停止してから再度作業を繰り返します。

$ docker stop my-top-page

9.3. コンテナのHarborへの登録

もし始めてHarborを利用する場合には、最初に自分ID名でプロジェクトを登録してください。

この作業が完了していれば、次の要領でコンテナにタグを付けて、pushします。 なお macOS環境などで、buildxを利用している場合には既に操作は完了していますので、実施する必要はありません。

//## 作成したイメージに、inovtst9.u-aizu.ac.jpで始まるTAGを追加
//$ docker tag my-top-page:1.0.0 inovtst9.u-aizu.ac.jp/$(id -un)/my-top-page:1.0.0

## Harborにログインするための認証情報を付与
$ docker login inovtst9.u-aizu.ac.jp

## TAG名を利用して、Harbar(inovtst9.u-aizu.ac.jp)で登録
$ docker push inovtst9.u-aizu.ac.jp/$(id -un)/my-top-page:1.0.0

## 認証情報を~/.docker/configから削除
$ docker logout inovtst9.u-aizu.ac.jp

9.4. Kubernetesでのコンテナの実行

例えば次のようなYAMLファイルを配置します。

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-top
  labels:
    app: nginx-top
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-top
  template:
    metadata:
      labels:
        app: nginx-top
    spec:
      containers:
      - name: nginx-top
        image: inovtst9.u-aizu.ac.jp/yasu-abe/my-top-page:1.0.0
        ports:
         - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-top-service
  labels:
    app: nginx-top
spec:
  type: ClusterIP
  selector:
    app: nginx-top
  ports:
  - port: 80
    targetPort: 80

9.5. my-proxyへの登録

いままでは、cm/nginx-confの内容は次のようになっていました。

data:
  proxy.conf: |
    server {
      listen 80;
      location /<your namespace>/nginx/ {
          proxy_pass http://my-nginx/;
      }
      location /<your namespace>/dvwa/ {
          proxy_pass http://dvwa-svc/;
      }
      location /<your namespace>/block/ {
          proxy_pass http://nginx-block-storage/;
      }
      location /<your namespace>/file/ {
          proxy_pass http://nginx-file-storage/;
      }
      ## ここに追加したnginx-top-serviceをトップページに表示するよう設定を加えます。
      location /<your namespace>/ {
          proxy_pass http://nginx-top-service/;
      }
}

nginxのlocation命令は長さ優先でマッチするため、先頭に記述する必要はありません。

9.6. URL List

10. Proxy設定のファスト・パス

とにかく早くProxyサーバーを構築するために、実行するべきコマンドだけをまとめました。

$ kubectl -n $(id -un) apply -f "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/ingress-proxy.deploy-nginx.yaml"

$ kubectl -n $(id -un) apply -f "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/ingress-proxy.svc-nginx.yaml"

$ kubectl -n $(id -un) exec -it "$(kubectl -n $(id -un) get pod -l app=my-nginx -o jsonpath={.items[0].metadata.name})" -- bash -c "echo Hello World, $(id -un) at $(date) > /usr/share/nginx/html/index.html"

$ curl "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/ingress-proxy.configmap-proxy.yaml" | sed -e "s/s12xxxxx/$(id -un)/" | kubectl -n $(id -un) apply -f -

$ kubectl -n $(id -un) apply -f https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/ingress-proxy.deploy-proxy.yaml

$ curl "https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/ingress-proxy.svc-proxy.yaml" | sed -e "s/s12xxxxx/$(id -un)/" | kubectl -n $(id -un) apply -f -

10.1. 現在のConfigMapオブジェクトの確認

Proxyサーバーの設定は、Nginxに対する設定ファイルの一部です。

ファイルの内容については、次のコマンドで確認してください。

$ kubectl -n $(id -un) get cm nginx-conf -o yaml

10.2. Proxy設定の反映

configmapオブジェクトを頻繁に変更することになりますが、その時にPodの再起動が必要です。

$ kubectl -n $(id -un) delete pod -l app=my-proxy

10.3. 稼動確認

ここまでで問題なければ、次の中から自分のIDが含まれているURLにアクセスしてコンテンツが表示されます。