AWS FargateでEC2レスなPrivateLinkサービスを提供する #reinvent

ども、大瀧です。
本記事はAWS Fargate Advent Calendar 2017の5日目です。

PrivateLinkは、インターネットを通らないプライベートなネットワーク接続をAWSアカウントやVPCをまたいで提供する仕組みです。ネットワーク機能なのでその接続先はEC2インスタンスに限定されると思いきや、ELB(ロードバランササービス)を利用するため、AWSの様々なサービスを組み合わせられます。そこで今回は、EC2を使わないピュアコンテナサービスであるFargateをPrivateLinkのバックエンドとする構成をご紹介します。それぞれの機能についての詳細は、以下の記事を参照してください。

組み合わせのイメージは以下です。

PrivateLinkで複数AWSアカウントと接続する例で、用途としてはサービスプロバイダが複数のユーザーアカウントにPrivateLinkを提供してSaaSサービスを提供するケースが挙げられます。インターネットを介さず、かつ許可したアカウントに対してマルチテナントなサービス構成ができるわけですね。Marketplaceによるマネタイズの仕組みも完備されており、既にCisco StealWatchなど複数のAWSパートナーからPrivateLinkによるサービス提供が発表されています。

今回はFargateをバックエンドにすることで、EC2インスタンスの運用に必要なOSのセキュリティパッチや仮想マシンのリソース使用率監視などを省略できます。

一方で注意点もあります。PrivateLinkはいくつかあるロードバランサのタイプのうちNLB(Network Load Balancer)が必須であり、他のロードバランサでは代替できないため以下の制約に気をつけてください。

  • プロトコルはTCPのみで、UDPは通さない
  • ロードバランサによるスティッキーセッションのハンドルやSSL Terminationは提供されない
  • FargateタスクからクライアントIPアドレスを知るためには、ひと工夫必要

NLBについては、以下の記事を参考にしてください。

では、設定していきましょう。今回作成する構成は以下の通りです。

今回は同アカウントの別VPCで試したので、VPCの指定でエンドポイントサービスとは異なるVPCを選択しています。

1. セキュリティグループの作成

まずは正しくアクセスを制御するためにセキュリティグループを準備しておきましょう。以下2つを用意します。

  • [ユーザーアカウント] VPCエンドポイント(Privateの一部)のセキュリティグループ
  • [サービスプロバイダアカウント] ECSサービス(Fargateの一部)のセキュリティグループ

VPCエンドポイントのセキュリティグループではクライアントのIPアドレス(またはCIDR)とポート番号、ECSサービスでは連携するNLBからのアクセスを許可します。今回は例としてNginx(nginx:alpineイメージ)をサーブするので、任意のアドレスのTCP:80ポートを許可します。(手間を減らすために、今回は同一AWSアカウントの別VPCで構成します。)

これでOKです。

2. NLBの作成

続いて、今回の構成の中核となるNLBを作成します。通常のNLB作成手順と特に変わりませんが、PrivateLink経由でVPCから利用するため内部向けにするのと...

ターゲットグループのタイプをIPにしつつ...

IPアドレスは登録しないで空にするのがポイントです(Fargateをターゲットにする場合の既定の設定)。

作成したLBのステータスがactiveになったらOKです。

3. Fargateクラスタ、タスク、サービスの作成

続いて、WebサーバーとなるNginxコンテナをFargateで実行しNLBと繋ぎます。

FargateはAmazon ECSの一機能として動作するので、まずはECSのWebコンソールからECSクラスタを作成します。今回はFargate構成なので「Powered by AWS Fargate」と示される[Networking only]を選択し、クラスタ名 default で作成しました。

続いて、Fargate用のタスク定義を作成します。

コンテナ定義は一般的なNginxコンテナとして

  • イメージ : nginx:alpine
  • エントリポイント : sh,-c
  • コマンド : exec nginx -g "daemon off;"

として、最小のvCPU、メモリで作成しました。

続いて、クラスタの設定画面からECSサービスを作成し、タスク定義とNLBを紐づけます。

今回はお試しなのでタスク数1、AutoScalingなしでしたが、複数タスク構成で高可用性、高パフォーマンスを検討するのも良いでしょう。

ネットワーク構成では、先ほど作成したセキュリティグループを指定します。

また、re:InventのCON333セッションで聞いたところによると、NLBのVPCサブネットのAZ(Availability Zone)はFargateのVPCサブネットのAZを含んでいる必要があるとのことなので、サービス構成でエラーになる場合はVPCサブネットを確認しましょう。

続いて、NLBを選択し、手順2で作成したNLBを指定します。

そのすぐ下にある[ELBへの追加]ボタンのクリックを忘れないようにしましょう。

NLB-コンテナ間のポート転送設定として、NLBのリスナーポートTCP:80とターゲットグループを選択します。

しばらく待ち、実行中のタスクの数のFargateが1になればOKです。

最後に、PrivateLinkで異なるVPC(およびAWSアカウント)にFargateサービスをプライベート接続します。手順自体はこちらの記事と特に変わりません。

まずはサービスプロバイダアカウントVPCのWebコンソールの[エンドポイントのサービス]メニューから、作成したNLBを指定したエンドポイントサービスを新規作成します。

続いてユーザーアカウントの同じくVPCのWebコンソールの[エンドポイント]メニューから、エンドポイントサービスを指定してエンドポイントを作成します。

あとは必要に応じてエンドポイントサービス側で承諾処理を行えばOKです。承諾には少し時間がかかるので、のんびり待ちましょう。

動作確認

では、作成したエンドポイントのDNS名に、ユーザー側VPCのEC2からcurlコマンドでアクセスしてみます。

$ curl vpce-0242f8e324f586f73-hygezc9n.vpce-svc-0fe364fa56178d099.us-east-1.vpce.amazonaws.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
$

Nginxからのレスポンスが正しく返ってきました!FargateのタスクのCloudWatch Logsを確認してみると...

きちんとアクセスログが残っていますね。ちなみにこの場合のリモートアドレスはNLBのPrivate IPということに注意してください。クライアントIPが欲しいのであれば、Proxy Protocolなどの一工夫が必要になります。

まとめ

EC2なしでDockerコンテナを実行できるAWS Fargateを、アカウントをまたいでプライベート接続できるPrivateLinkと組み合わせる様子を紹介しました。運用負荷を下げつつSaaSサービスを提供できる実用的な構成ではないでしょうか。