先日AWSの新しいLoadBalancer NLBが出ましたね.
おそらく便利なので,色んな場面で使えるかとは思いますが,「HTTP以外もECSの組み合わせで動的ポートマッピングできるのでは?」というのが気になったので,使ってみます.
今回はgRPCをECS上に立てて,それを動的ポートマッピングさせて,NLBでバランシングしてみます. 実はNLBが発表された直後からこれは試していましたが,リリース直後ECS絡みにバグが合ったのか,しばらくECSのサービスにNLBが登録できなくなっていました.
最近解消されたらしく,正常に動作するようになった模様.
NLBを作る
何はともあれ,NLBを作ってみる.
今回は手元から試すので internet-facing
を選択したけど,あまりおすすめはしません.
できれば internal
にしたい.理由は後述.
Listenersは適当なポートにしておく.
初回なのでTarget groupの作成を促される. ここで,ALB時代に作成したtarget groupは選択肢に上がってこなかった.APIをちゃんと見てないので,確かなことは言えないけれど,おそらくALB用のtarget groupとNLB用のtarget groupは区別されている.
また,Healthcheckについては,traffic port
指定にしておく.
特定のポートを開けてもいいけれど,どうせ動的ポートマッピングしてしまうので,マッピングされたポートを見つけ出して欲しい.
ECRの準備
あまり本題ではないのだが,Docker imageはECRに登録しておく.
ECSの準備
ECSクラスタ作成
まず,ECSのクラスタを作成する.
TaskDefinitionの作成
次に,先ほど作ったECRのimageを動かすための,TaskDefinitionを作る.
ContainerDefinitionを追加する際に,注意すべきなのは,動的ポートマッピング用に,コンテナポートは動かすDocker imageに応じたポートを書くが,Host portは空にしておく. こうすることで動的ポートマッピングしてくれるようになる.
ECSサービスの作成
先ほど作成したECSクラスタの下にサービスを作る. 作成したTaskDefinitionもここで紐付ける.
ここでNLBとの紐付けを行う.
Add to ELBを押す.
すると,先ほど作成したtarget groupが選択できる.
これでサービスを作成すると, target groupの画面に,新たなインスタンスが登録されている.
Portを見ると,ちゃんと動的ポートマッピングされている模様.
Status: initial
が healthy
になれば問題ない.そのへんはHealthcheckの設定あたりを見直すと良い.
このへんのは後述するSecurityGroupとの兼ね合いも大事になってくる.
SecurityGroupについて
ここが今までのLBとは少し違う点だ.
ELB(Classic)やALBとは違い,NLBはLB自身にSecurityGroupの設定はできない.
そのため internet-facing
なNLBはSecurityGroupを挟まずに,外部からの接続を受け付ける.
ではアクセス制限はどうやってやるかというと,NLBの下にぶら下がるEC2インスタンスのSecurityGroupでコントロールする. そして,紹介記事にあるように,NLBはアクセス元のIPを維持したまEC2インスタンスに投げる.
HealthCheckはどうするの?
HealthCheckは,NLBが存在するVPCからのアクセスとなる.
そのため,先ほどの traffic port
でのHealthCheckを許可するためには,以下のような設定が必要になる.
IPは隠しているが,CustomでVPCのIPを入れ,VPCからの接続を全て許可している.
外部からのアクセスはどうなるの?
先程も書いたように,NLBはアクセス元のIPを維持したまま接続してくる.
つまり,例えばEC2上の8080ポートでサービスを提供し,NLBで外部に公開する場合,8080ポートに,全てのIPからのアクセスを開放してやらなければならない.
更に言うなら,今回の例のように動的ポートマッピングしたサービスを公開するのであれば,EC2上のどのポートにマッピングされているかは,SecurityGroupからは知るすべもないので,使われそうなポートを全て開放する必要がある.
大げさに言うとこうなる(厳密には,動的ポートマッピングは30000付近の使われていないポートを使っているため,若い番号のポートを開放する必要はない).
しかしこんな過激なSecurityGroupをinternet-facingにしておくことはできないので,やっぱりinternalで作るなり,SecurityGroupでかなり厳密にIP制限するなり,あとはLBの前段にちゃんと何か置くと良いかもしれない.
ちなみにgRPCはできた
こんな設定をしたところ,見事ECS上にgRPCサーバが立ち上がり,手元からアクセスすることができた. 今までgRPCしたかったけど,やっぱdockerで運用するならECSはきついかなーkubernetes使うかなーとか思ってた.
無事ECSだけでできるようになって,やったね!