Japan Tour in Summer: Java & k8s on Azure まつり に参加してきたのでその感想

寺田佳央さんが主宰する Japan Tour in Summer: Java & k8s on Azure まつり に参加してきましたのでその感想を書いてみます。
# 具体的な内容とかは別の場所で開催された際の他の方のブログがありましたので最後にリンクを置いておきます。

connpass
jazug.connpass.com

connpass にもある通り、2 日間で k8s の基礎操作からアプリのデプロイ、CI/CD までの流れを試してみようというイベントです。
ちなみに場所は福岡で関東からだと結構距離はあるのですが、週休三日のお休みも使いつつ、博多への旅行がてら参加してみました。
また最近よく AKS の案件の話しが来ることもあり一人でモクモクやってたのですが、疑問な点も出てきたし聞けちゃえるかなという期待もありました。

1 日目は、寺田さんが用意された↓のアプリケーションをモブプロ形式で AKS 上へデプロイしていきます。
github.com

今回 k8s 経験者があまりいなかったということもありチーム形式ではなく、一人ずつ前に出て、発表者がドライバー、寺田さんがナビゲーターという形で進めました。
ハンズオンラボの資料をベースに、Microsoft アカウントの作成から Azure の無料試用版サブスクリプションの準備、踏み台サーバーの展開まで一通りすすめて、そのあと AKS の展開と kubectl でのオペレーションを持ち回りでやっていきます。
Cloud Shell 使うとこういう時環境依存が出ないのでいいですね。

また、他の人のオペレーションを見ながらやっていくと、一人で進めるよりは進みは確かに遅いのですがいろんな気づきがあるのでモブプロ形式はそういう点でもよかったです。

そして 2 日目は、1 日目と同じ内容を今度は参加者のみで進めていくというスタイル。
1 日目はサクサク進んでいたものでも、やっぱり聞き逃していたところやちゃんと整理できていない点は躓きポイントとして出てくるので、それをみんなであーだこーだ言いながら解決していくという感じでした。

最後の方で、実際 k8s ってどうバージョンアップすればいいの?とか、リソース制限の考え方等、導入した後も含めて寺田さんのご経験上からの Tips のレクチャーがありました。
このあたりのお話し。

www.slideshare.net

実際手を動かしてやってみることができたという点も当然ながらよかったのですが、サポートという普段の業務上、やはり実際導入するまでにどうなのか、導入してからはどうなのかという点を聞けたのはとても良かったですね。

また、最初に書いたように本を片手に一人で進めると、本当にこの機能が必要なのか?なんで必要なのか?どう使うのか?というのを一つ一つ考えていかないといけないですが、エッセンスを教えてもらえたという点で今後の学習コストを大幅に削減できた気がします。
仕事柄、普段圧倒的に参加者よりもトレーナー側の機会が多いのですが、そういう意味でもこういう風に伝えればいいんだなぁーとかいろいろな学びがありました。


ということで、まとめるととてもいいイベントでした!


最後に寺田さんからのキーワードのメモ。

  • k8s のすべての機能を使う必要はない。シンプルイズベスト
    • その構成、その規模、障害が起きたときや頻繁なバージョンアップに耐えられるの?
  • k8s はあくまでもツール。ほかの選択肢があるということは忘れない
    • k8s は特にサービスが多く変更が頻繁にあるアプリケーションに向く
    • k8s は Dev と Ops をつなげるツール。Dev も Ops のことを、Ops も Dev のことを知っておく必要がある
  • マイクロサービスなのか、ウォーターフォールなのか、IaaS / PaaS なのか k8s なのかを考える前に、なぜそれが必要なのか?を考える
    • 今のやり方でビジネスは伸ばせるのか?今のやり方で技術者として成長できるのか?

参考リンク

過去に開催されたイベントに関する記事

syobochim.hatenablog.com
blog.okazuki.jp

寺田さんのブログ

yoshio3.com

App Service on Linux で .htaccess を使ってアクセス制御する

備忘&ちょっとでもインターネット上に App Service on Linux の情報を流しておきたいので大した内容ではないですが書いておきます(

Front Door のバックエンドに App Service を置く場合、Front Door の IP アドレスはユーザーごとに違うわけではないため、App Service の機能としてある、IP アドレスによるアクセス制御では、アクセス元を制限することができません。
IPアドレスのレンジは公開されているため、(特定ではなく)Front Door サービスからのアクセスのみ許可、ということは可能です。以下ドキュメントより。

使用するバックエンドが、Azure Front Door のバックエンド IP アドレス空間と Azure のインフラストラクチャ サービスからのトラフィックのみを受け入れるように IP ACL 処理を構成します。 Microsoft は Azure IP 範囲およびサービス タグとの統合に向けて作業を進めていますが、現在のところ、IP 範囲は次のように参照することができます。
Front Door のIPv4 バックエンド IP 空間: 147.243.0.0/16
Front Door のIPv6 バックエンド IP 空間: 2a01:111:2050::/44
仮想化されたホスト IP アドレスを通した Azure の基本的なインフラストラクチャ サービス: 168.63.129.16 および 169.254.169.254

docs.microsoft.com


これがどういうときに問題かというと、Front Door の WAF を使って、バックエンドに App Service を置いた場合、悪意のある第三者が別の Front Door を置くことで WAF をスルー出来る可能性があります。もちろん、App Service 側のホスト名がわからないとたどり着けないのですが、可能性はゼロではありません。

こういうこと↓
f:id:mitsuki0820:20190808012943p:plain

で、どうするかというと、上のドキュメントにもある通り、X-Forwarded-Host に Front Door のホスト名がのってくるため、それをチェックする必要があります。
では、App Service on Linux ではどうするかですが、アプリ側で見なくても普通に .htaccess を置けばアクセス制御ができました。
こんな感じ。

SetEnvIf X-Forwarded-Host "www\.contoso\.com" allowed_fd
Order Deny,Allow
Deny from all
Allow from env=allowed_fd

ちょっとここで不安だったのが .htaccess でヘッダーのアクセス元チェック(要はApache のモジュール)を使うのって App Service の世界で一般的なんだろうか、ということでした。なんとなくつぶやいていたら、なんと中の方から返信いただけました。

ということで安心して使っていきます。おそらく他のモジュールも特に問題なく使えるでしょう。
ドキュメントをよく読むと、Laravel のデプロイのところでも .htaccess が書かれていました。
docs.microsoft.com

最後に phpinfo から抜いてきた Loaded Modules の一覧です。(今回は PHP アプリの話しでした)
mod_rewrite、mod_auth* も使えます。

core
mod_so
mod_watchdog
http_core
mod_log_config
mod_logio
mod_version
mod_unixd
mod_access_compat
mod_alias
mod_auth_basic
mod_authn_core
mod_authn_file
mod_authz_core
mod_authz_host
mod_authz_user
mod_autoindex
mod_deflate
mod_dir
mod_env
mod_expires
mod_filter
mod_include
mod_mime
prefork
mod_negotiation
mod_php7
mod_reqtimeout
mod_rewrite
mod_setenvif
mod_status

何でもかんでも .htaccess にするとあとで地獄を見ることになりますが、どうしてもという最後の隙間を埋める部分で使っていけそうです。

いまさらだけど Azure の Load Balancer のことをちょっと調べてみた

Standard Load Balancer が登場してからずーっと検証しようと思っていた NAT(SNAT)周りですが必要に迫られたのでついでにまとめました。

Azure の NAT まわりのこと

Load Balancer の話をする前に、まず、Azure の NAT の観点でネットワークまわりの現状をまとめます。

いまとなっては当たり前のことですが Azure の VM から直接見える IP アドレスは、192や10から始まるプライベート IP アドレスです。NIC に対して、グローバル IP アドレスが割り当てられているわけではありません。

つまりどういうことかというと、インターネットへの通信を行うには何らかの方法で、プライベート IP アドレスをグローバル IP アドレスに変換してあげる必要があります。

ここで、Azure の仮想マシンにパブリック IP アドレスを割り当てる場合(正確には仮想マシンの持つ NIC に割り当てる)と、割り当てない場合に、どのような NAT がされるかを考えます。

パブリック IP を割り当てる場合

パブリック IP アドレスを割り当てる場合は簡単です。単純に、割り当てたパブリック IP アドレスが外側のアドレスとして使われて、NAT 変換が行われます。
ドキュメントはこちら。

シナリオ 1:インスタンス レベルのパブリック IP アドレスがある VM
このシナリオでは、VM にはインスタンス レベルのパブリック IP (ILPIP) が割り当てられています。 送信接続に関する限り、VM が負荷分散されているかどうかは関係ありません。 このシナリオは他のシナリオよりも優先されます。 ILPIP が使用される場合、すべての送信フローで VM によって ILPIP が使用されます。
VM に割り当てられたパブリック IP は (1 対多ではなく) 1 対 1 の関係であり、1 対 1 のステートレス NAT として実装されます。 ポート マスカレード (PAT) は使用されず、VM は使用可能なすべてのエフェメラル ポートを備えます。
Azure の送信接続 | Microsoft Docs

パブリック IP を割り当てない場合

一方、パブリック IP アドレスを割り当てない場合どうなるかというと、Azure が暗黙のうちに用意してくれる NAT 機能が、これまた暗黙のうちに用意してくれているグローバルの IP アドレスに変換します。
ドキュメントはこちら。

シナリオ 3:インスタンス レベルのパブリック IP アドレスがないスタンドアロン VM
VM が送信フローを作成すると、Azure が、送信フローのプライベート ソース IP アドレスをパブリック ソース IP アドレスに変換します。 この送信フローで使用されるパブリック IP アドレスは構成不可能であり、サブスクリプションのパブリック IP リソースの制限に対してカウントされません。 このパブリック IP アドレスはユーザーのものではなく、予約することはできません。 VM、可用性セット、または仮想マシン スケール セットを再デプロイすると、このパブリック IP アドレスは解放され、新しいパブリック IP アドレスが要求されます。 IP アドレスをホワイトリストに登録する場合は、このシナリオを使用しないでください。 代わりに、送信シナリオと、送信接続で使用されるパブリック IP アドレスを明示的に宣言する他の 2 つのシナリオのいずれかを使用します。
Azure の送信接続 | Microsoft Docs

上記のドキュメントの通り、通常は課金されるパブリック IP アドレスですが、Azure が勝手に用意してくれるリソースなので当然課金は発生しません。

ここで問題がひとつ
エンタープライズでよくあるシナリオで、VM にはパブリックの IP アドレスを付与しないことで外部からのアクセスはさせず、ただ VM からはインターネットに接続させたいというケースがあります。さらに、これもよくあるのですが、他の Azure のサービスやアプリケーション等で送信元をホワイトリスト化したい、というケースです。

これまで説明してきた内容からは、送信元パブリック IP アドレスを固定化するには、VM にパブリック IP アドレスを割り当てる必要がありました。ただそうするとインターネット上にエンドポイントを晒してしまうということになってしまい、要件が満たせなくなります。

これを回避する1つの方法としては、プロキシサーバーを立てる方法です。ただ、単純にパブリック IP アドレスを固定化するのに、プロキシサーバーを立てるというのは、仮想マシンのコストや管理の工数を考えるとあまりやりたくはありません。
そこでもう1つの方法として、Azure の Load Balancer を使う方法があります。

ドキュメントのシナリオ2の部分です。

負荷分散 VM が送信フローを作成すると、Azure が、送信フローのプライベート ソース IP アドレスをパブリック ロード バランサー フロントエンドのパブリック IP アドレスに変換します。 Azure は、SNAT を使用してこの機能を実行します。 また、Azure は、PAT を使用して、複数のプライベート IP アドレスをパブリック IP アドレスでマスカレードします。
Azure の送信接続 | Microsoft Docs

AWS だと NAT ゲートウェイというのがあるらしいのですが、Azure の場合はそういうサービスがなく、その代わりに Load Balancer を使うと同じようなことが実現できます。
※ただ、負荷分散はいらないのに Load Balancer のサービスを作らないといけないのはいまいちな点もあるので、おそらくたぶんきっと、NAT ゲートウェイがそろそろ出てくるに違いありません。

Azure の Load Balancer まわりのこと

Azure には、いわゆる L4 のロードバランサーとして、Basic Load Balancer と Standard Load Balancer があります。Standard Load Balancer はそれなりに最近出てきたサービスです。

何が違うの?という具体的な内容は↓の公式ドキュメントに譲りますが、大きな違いとしてはざっくり、AZに対応していること、バックエンドプールとして仮想マシンが指定できること(Basic は原則可用性セットのみ)、その他いろいろ機能が追加されていること、です。
docs.microsoft.com

ちなみに、お金の話をすると、Basic Load Balancer は無料で使えていましたが、Standard Load Balancer は有料です。

azure.microsoft.com

とは言え、機能や今後の方向性を考えると、Standard を使うのがいいと思います。

検証

ようやくここからが今回の記事の本題です。

上記のドキュメントを読むと、Standard Load Balancer については、アウトバウンドの通信を明示的に作ってあげる必要がある、という記述があります。

仮想マシン、可用性セット、仮想マシン スケール セットが送信接続 (アウトバウンド接続) を使用するためには、送信シナリオを明示的に作成する "必要があります"。

送信シナリオは明示的であり、発信接続は指定されるまで存在しません。

実際、Standard Load Balancer のバックエンドにパブリック IP アドレスが割り当てられていない仮想マシンを展開して、インターネットに接続しようとすると、SYN_SENT の状態でとまってしまい通信ができません。

[tsunomur@VM ~]$ netstat -an --tcp | grep 13.71
tcp        0      1 10.8.0.4:37436          13.71.134.177:80        SYN_SENT

ということで、送信規則を作って割り当ててみました。

送信規則を作ってみる

ざっくりとした流れとしては、

  1. Standard Load Balancer を作る
  2. バックエンドプールを作って仮想マシンを指定する
  3. 送信規則を作る

という感じです。

バックエンドプールを作って仮想マシンを指定するところまでは、ポータルからできます。
現状、送信規則を作るには、Azure PowerShell/Azure CLI を使う必要があります。

こんな感じ。

# az network lb outbound-rule create  --resource-group rg  --lb-name lb  --name outboundrule  --frontend-ip-configs LoadBalancerFrontEnd  --protocol All  --idle-timeout 15  --outbound-ports 10000  --address-pool bepooloutbound
AllocatedOutboundPorts    EnableTcpReset    IdleTimeoutInMinutes    Name          Protocol    ProvisioningState    ResourceGroup
------------------------  ----------------  ----------------------  ------------  ----------  -------------------  ---------------
10000                     False             15                      outboundrule  All         Succeeded            rg

あとからパラメーターを変える時はこんな感じ。

az network lb outbound-rule update -g rg --lb-name lb --name outboundrule --enable-tcp-reset true --idle-timeout 4 --protocol tcp --outbound-ports 10000
NAT の割り当てポートを変えてみる

本当にAllocatedOutboundPortsが効いているのか?という疑問がふと出て来たので、実験してみました。


ポート割り当ての数を 8 に

# az network lb outbound-rule update -g rg --lb-name lb --name outboundrule --outbound-ports  8
AllocatedOutboundPorts    EnableTcpReset    IdleTimeoutInMinutes    Name          Protocol    ProvisioningState    ResourceGroup
------------------------  ----------------  ----------------------  ------------  ----------  -------------------  ---------------
8                         True              4                       outboundrule  Tcp         Succeeded            rg

VM からコネクションを 8 本張ってみる。

[tsunomur@VM ~]$ for i in `seq 8`; do nc nomupro.com 80&  done
[tsunomur@VM ~]$ netstat -an --tcp | grep 13.71
tcp        0      0 10.8.0.4:41290          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:41276          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:41288          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:41286          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:41282          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:41284          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:41277          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:41280          13.71.134.177:80        ESTABLISHED

9本目のコネクションを張ってみる。

[tsunomur@VM ~]$ nc nomupro.com 80
Ncat: Connection timed out.
[tsunomur@VM ~]$
[tsunomur@VM ~]$ netstat -an --tcp | grep 13.71
tcp        0      0 10.8.0.4:41290          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:41276          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:41288          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:41286          13.71.134.177:80        ESTABLISHED
tcp        0      1 10.8.0.4:41398          13.71.134.177:80        SYN_SENT
tcp        0      0 10.8.0.4:41282          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:41284          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:41277          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:41280          13.71.134.177:80        ESTABLISHED
[tsunomur@VM ~]$

Standard Load Balancer では、メトリックを見ることができるので変化を見てみました。

f:id:mitsuki0820:20190730232528p:plain

f:id:mitsuki0820:20190730232718p:plain

ちゃんと割り当てポートが8になり、使用済みも8になってますね。
※ちなみに Allocated SNAT Portsは、プロトコル毎(TCPUDP)でそれぞれ設定できるのですが、今回はあらかじめ TCP のみにしています。なので、メトリックの値は 8 になります。

ポート割り当ての数を 16 に

# az network lb outbound-rule update -g rg --lb-name lb --name outboundrule --outbound-ports  16
AllocatedOutboundPorts    EnableTcpReset    IdleTimeoutInMinutes    Name          Protocol    ProvisioningState    ResourceGroup
------------------------  ----------------  ----------------------  ------------  ----------  -------------------  ---------------
16                        True              4                       outboundrule  Tcp         Succeeded            rg

VM からコネクションを 16 本張ってみる。

[tsunomur@VM ~]$ for i in `seq 16`; do nc nomupro.com 80&  done
[tsunomur@VM ~]$ netstat -an --tcp | grep 13.71
tcp        0      0 10.8.0.4:45922          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45934          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45930          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45918          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45936          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45914          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45932          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45912          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45916          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45928          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45908          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45910          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45920          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45906          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45926          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45924          13.71.134.177:80        ESTABLISHED

17 本目のコネクションを張ってみる。

[tsunomur@VM ~]$ nc nomupro.com 80
Ncat: Connection timed out.
[tsunomur@VM ~]$
[tsunomur@VM ~]$ netstat -an --tcp | grep 13.71
tcp        0      0 10.8.0.4:45922          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45934          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45930          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45918          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45936          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45914          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45932          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45912          13.71.134.177:80        ESTABLISHED
tcp        0      1 10.8.0.4:46108          13.71.134.177:80        SYN_SENT
tcp        0      0 10.8.0.4:45916          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45928          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45908          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45910          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45920          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45906          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45926          13.71.134.177:80        ESTABLISHED
tcp        0      0 10.8.0.4:45924          13.71.134.177:80        ESTABLISHED
[tsunomur@VM ~]$

f:id:mitsuki0820:20190730234326p:plain

f:id:mitsuki0820:20190730234213p:plain

あたり前ですが16本まで張れましたね。

まとめ

ということで、ドキュメントに書かれていることができるよね、というあたり前のことを試しただけですが Azure の NAT の理解が少し深まりました。
それにしてもネットワーク周りの検証ってやっぱり地味w

また今度機会と時間があれば

  • 複数のフロントエンド、複数の VM を設定した時にどういう動きになるか
  • Azure Firewall の SNAT の動きってどうなってるのか

のあたりを試してみようと思います。