Azure Kubernetes Serviceにオンプレミスのローカル環境からアクセスしてみる

Qiitaで<font color="red">A</font>zure <font color="red">K</font>ubernetes <font color="red">S</font>ervice(以下、<font color="red">AKS</font>)の記事を書きましょうキャンペーンのようなことを開催してるようなので参加してみます。
先月はAzure IoTでも同じようなキャンペーンを開催していたと思うのですが、10月10日はIPA主催の情報処理試験があり、その勉強のために泣く泣く参加できませんでした。
IoTも大したことないですが、Kubernetesはもう一つ何も知らないので生暖かい目で見てくだされば幸いです。

#プライベートIPアドレスでオンプレミスからアクセスできるように構築してみる
[公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/aks/intro-kubernetes)をざっと読みつつ、仮想化、コンテナと一通り知ってるつもりではあるのですが昔仮想化技術の区分けにあった[完全仮想化]と[準仮想化]の違いと今の仮想化とコンテナの違いがいまいちわからず読み進めていました。
行きついた先は「とりあえずデモ環境を作ってみよう」という思いつきなのですが、進めていきます。
ただ普通に構築しては面白くないのと、[公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/aks/intro-kubernetes)にあった[ネットワーク トポロジ](https://docs.microsoft.com/ja-jp/azure/architecture/reference-architectures/containers/aks/secure-baseline-aks?WT.mc_id=AKSDOCSPAGE#network-topology)を読む限り、なんとなくネットワークに難しい点があるように見えたので、今回は全てプライベートネットワーク＋Hub Vnet無しでオンプレミスから直接AKSにアクセスできる環境を構築してみようと思います。

#プライベート環境にAKSを閉じ込める理由
##想定されるエンドユーザーからの要望
日本国内のお客様はVPN神話と揶揄されるように、<font color="red">「たとえ如何なる通信だろうとインターネットを経由することは言語道断。なので専用線もしくはVPNを必ず経由するようにしなさい。」</font>という不文律のポリシー(？)が非常に強い傾向があるので、今後こういった案件が出てきた時もプライベート空間に閉じ込めた環境下でAKSを構築できるようになればそれなりに役に立つかな、という観点もあります。

#公式ドキュメントのネットワークトポロジに逆らう理由
##課金
また課金の観点からも、Hub Vnetを経由してのオンプレミスの通信が発生する公式の[ネットワーク トポロジ](https://docs.microsoft.com/ja-jp/azure/architecture/reference-architectures/containers/aks/secure-baseline-aks?WT.mc_id=AKSDOCSPAGE#network-topology)では、AKSのあるVnetからオンプレミスにデータを返す際、Hub VnetとAKSのあるVnet間を接続するVnet Peeringを経由するのですが、このVnet Peeringは通信のIn/Out両方に課金がかかります。
Hub Vnetを見ると[以前の記事](https://qiita.com/hidekko/items/9351f56a512bf193071b)で触れたAzure Firewallがあったり、Azure Bastionがあったり、Gateway Subnetがあったりしてネットワーク関連サービスがまとまっているだけです。
今回私が構築した方法であれば少なくともAzure Bastionは不要になり、Azure FirewallとGateway SubnetはAKSのあるVnetに構築できます。
Azure FirewallはAKSのOutBound方向の通信を制御するために必須のリソース、Gateway Subnet(というかVirtual Network Gateway)はオンプレミスとの接続に必須のリソースなのでこれらは省略できません。
Microsoftの公式ドキュメントに従って構築すると、私の感覚では<font color="red">「不要な通信コストが発生する」</font>環境になってしまいます。
ご存知の通りAzureは通信量も従量課金で青天井(実際は31日×24時間×60分×60秒×最大通信速度(bps)ですので上限はある)となるので、これでは「課金が怖くて利用の促進が進まないのではないか？」と少々疑問を持ってしまいます。
<font color="red">非常に不遜な発言なのは重々承知の上なので、私の認識が間違えているのであればお手数ですがご指摘ください。</font>

能書きはこれくらいにして、それではいってみましょう。

#とりあえずいきなりデプロイする
既存環境にデプロイすることも考えましたが、ネットワーク調整が難しかったので新規でリソースグループを作成し、そこにAKSをデプロイします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/4917db20-13d9-67d0-ba27-7597f9db97ba.png)
もういきなりAKSを新規で作りましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/6e353485-db0a-f906-7e51-fa1623459817.png)
初期設定ではこんな感じですが
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/d95760ec-2e33-4b9b-df68-46409d3a33ef.png)
こんな感じに設定変更しました。
MSDNのサブスクリプションを利用しているのでリージョンに縛りがあることと、CPUコア数に上限があること、当然課金に制限があることからこのような設計です。
[ノードプール]をクリックすると以下の画面になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/db32536e-2a46-291a-eefc-d28eb9f7b571.png)
実際のノードプールは<font color="red">赤枠</font>の部分なので、ここもクリックしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/ebe56d74-ec69-18cc-52c5-3c3beb3c3f79.png)
ほとんど前項の設定値を引き継いでいるので問題ないと判断しました。
本格的に利用するなら[ノード当たりの最大ポッド数]は調整した方が良いかもしれません。
具体的な設定値は利用用途によりけりだと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/527b658d-7153-1b68-3303-3b34b887d23d.png)
[ノードプール]の画面に戻ってきました。
画面中ほどの[仮想ノードを有効にする]にチェックを入れます。
この説明文、凄いことが書いてあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/4244ddff-46e1-3728-fb10-4f297e4446a3.png)
[仮想ノードでは、サーバレスのAzure Container Instanceを活用してバースト可能なスケーリングが可能になります。]
[仮想ノードでは、サーバレスのAzure Container Instanceを活用して<font color="red">バースト可能なスケーリングが可能になります。</font>]
え？
[<font color="red">バースト可能なスケーリングが可能になります。</font>]
非常にPublic Cloudっぽいですね。
心強い反面、課金が怖いです・・・
サーバレスなのでSpot InstanceやReserved Instanceの対象から外れると思うのですが、どうなんでしょうか。
この点は調べて後日追記します。
続いて[認証]へ進みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/3be30445-4cb6-4c0d-0380-711b42ce969e.png)
ここはいったんこのままいきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/39347455-05a7-1fe0-b864-aef4b0c74b6d.png)
ネットワークレンジが広いのが気になりますが、コンテナたくさん立てるのに必要なのかと思うのでこのままにします。
セキュリティの項目も気になるので確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/5cab8738-2865-7ed7-b207-293d7a6201d4.png)
[プライベート クラスターの有効化]の情報ボタンにホバーすると、大事な一文が出てきました。
[<font color="red">プライベートクラスタは、APIサーバとノード プール間のネットワークトラフィックがプライベート ネットワークのみ保持されるようにするために、内部アドレスを使用します。</font>]
もう<font color="red">全文赤字</font>です。
ここは今回の想定構成だとチェックが必須ですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/f1cf10c8-b55d-a08e-3ec8-ce58bfee10eb.png)
[承認されたIP範囲の設定]がグレーアウトしました。
[プライベートクラスタの有効化]と二者択一の構成なのでしょう。
恐らくパブリック環境からアクセス可能な状態でAKSを構成した際に、アクセス元IPアドレスを絞る設定だと思います。
今回の想定構成から外れるので今回は検証しません。
そして最後の[ネットワークポリシー]の[なし]が気になります。
情報ボタンにホバーしてみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/62c00d72-6b53-0d6e-7bd0-653ceaaf37b0.png)
記載内容を要約すると、ポッド間のInbound(イングレス)OutBound(エグレス)通信の制御を行うか行わないかの設定で、かつLinuxのノードプール(設定画面上で2つ前のタブ)に対してのみ制御を加えるものということです。
CalicoネットワークポリシーもAzureネットワークポリシーも存じ上げませんが、とりあえず[Azure]を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/96149239-7fc5-c871-9ec2-a630c27f0940.png)
つづいてAKS内でデプロイされるコンテナーをどこのイメージから呼び出すのかの設定、コンテナレジストリの設定です。
新規作成で、どのようなパラメーターが選択できるのか確認しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/c86505ae-7e21-720e-d513-31f5d0f2ae6e.png)
コンテナレジストリのFQDNの指定とデプロイリージョンの指定、管理者ユーザとSKUの指定です。
ここはリソースグループとリージョンはデフォルト値でそのままとし、管理者ユーザもそのままにし、SKUはStandardから料金低減の観点でBasicに選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/823d11c6-8d87-b5c6-1e5a-efa52ed22ba0.png)
今回検証ですので監視も無効にします。
タグは不要なのでこのままデプロイしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/ac851cfc-a8f6-1fb2-533f-c0ef71d5b3a1.png)
しばらく待つと無事デプロイが終りました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/56f87438-c383-1abd-b372-953fae6f33f6.png)

#AKSにアクセスできない
とりあえず何もわからないので[Kubernetesリソース]を確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/42f89ad1-ebbf-b8c3-c497-38d4672abb1a.png)
え！？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/34e47501-e6a3-f919-e670-de16daf08a1c.png)
アクセスできないだと・・・！？
よく読んでみたらそりゃそうですね。
プライベート環境に通信を閉じ込めたので、Azure内のリソースからかプライベートIPアドレス同士でリーチする環境からでないと無理です。
更に[ネットワーク トポロジ](https://docs.microsoft.com/ja-jp/azure/architecture/reference-architectures/containers/aks/secure-baseline-aks?WT.mc_id=AKSDOCSPAGE#network-topology)にも記載のネットワーク関連のURLにある他の記述からもAKSのリソースへプライベートIPアドレスで名前解決できる環境を構築しないといけませんと書いてあります。
Azure Bastionがあればこの手間は削減できるのですが、Azure BastionはAzureポータルにログインしないと利用できないという弱点もあります。
これは何が弱点かというと、AKSの利用ユーザとAzure Portalを利用できるユーザとが必ずしも一致しないことが考えられるからです。
Azure Bastionは確かに情報システム部やSIerにすれば便利な機能ですが、一般ユーザに開放する機能ではないかなというのが個人の見解です。
現状のIAMだとAzure Portalにログインできてしまうと、他のリソースやサービスの有無まで見えてしまいます。
Azure Blueprintを使い[拒否]のIAMを構成すれば制御も可能なのですが、そこまで手間をかけて一般ユーザにAzure BastionのためだけにAzure Portalを開放するメリットが私には見出せません。
またAzure Bastionも存在するだけで課金のかかるサービスですしね。

何より手元のクライアントマシンから利用できれば、それに越したことはありません。

#解決策
今回[公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/aks/intro-kubernetes)に則ってAzure上にDNSサーバを構築し、手元のマシンが参照するルーターでDNS Recursive機能を有効にして対応しました。
構成図としてはこうなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/bd0beaad-271a-0e74-0eaa-2fc7672ca7ce.png)
Azure DNS Private ZoneがAzure上のリソースからのDNSリクエストしか受け付けてくれないので、泣く泣くAzure上にServer(10.242.0.132)を構築し、DNS Recursive構成にしています。
名前解決の経路としては<font color="red">赤矢印</font>のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/bf03d827-081f-8a8d-b215-4e80059eb62d.png)
このような多段式のDNS Request/Responceとなります。
この構成にするために、AKSのあるVnet(仮想ネットワーク)に冒頭に記載してある通りGateway Subnetを構築します。

#解決策実装
さっそくAKSのあるVnetにGateway Subnetを構築しましょう。

##Vnetの設定確認
AKSの[概要]画面にも[サービスCIDR]とあったので、恐らく[10.0.0.0/16]くらいで切られているのであろう、とタカを括っていたのですが・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/bd416955-0bca-e183-90bf-93fc5a9e8035.png)
先ほど新規で構築した実際のVnetは以下のようになっていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/2c31d59c-64de-00b7-17e4-9b013bb8a968.png)
いやいや・・・
10.0.0.0/8って・・・
クラスA全部ですやん・・・
そんな大雑把な切り方あります？
・・・しかもデプロイ中にこのVnetに関する設定パラメータ無かったですやん・・・
何か色々おかしくないですかね？
我が家(弊社)はネットワーク機器がたくさんあるんで、それぞれのネットワーク機器のバックボーンネットワークとしてクラスAの一部を切り出して使っています。
まぁ重複してますよね。
結果ルーティングできないのでネットワーク切りなおします。
これは敢えてサクッと行くように、さもここで気付いたかのようにしてますが、実際はGateway Subnetを切って、仮想ネットワークゲートウェイも作成して、サーバ専用セグメント切って、DNSサーバも日本語化してDNS機能も追加して、VPNも結べてからから気付いたんで、ネットワークの再構築にめちゃめちゃ時間かかりました。
まぁ最初にVnet確認しとけよって話なんですけどね。
いや、まさかクラスA全部とか大きすぎでしょ？(2回目)
しかも設定途中でパラメータ指定出てきませんし。(2回目)
ご存知の方は多いと思いますが念のために記載しておくと、仮想ネットワークゲートウェイはデプロイするのに最大45分かかります。
最近早くなったとはいえ、それでも結構時間かかります。
しかも仮想ネットワークゲートウェイ構築中は対象のネットワークに変更は一切かけれなくなります。

はい。
それでは気を取り直してVPN張りつつDNSサーバ構築しましたが、この辺はASKに直接関係ないので省略します。

#解決策実装後、Azure Portal上のAKSの画面にアクセスできるのか？
できました。
そりゃそうですよね。

名前空間(Namespaceですね。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/7891d287-ae73-5acd-7abb-4d3cfbcb8f09.png)
ワークロード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/88d060d1-91ef-7014-6c31-af8f604f2f6b.png)
サービスとイングレス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/6e939d5e-2386-5597-c3c5-8d385ecec2b5.png)
ストレージ(未構成)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/8bd60c38-994f-f924-7331-e4e63218aaa8.png)
構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/ba8b9d20-6236-f1d6-5498-c35edc772839.png)


あ、いつの間にか日付が変わっている。

今回はここまで。