NRIネットコム社員が様々な視点で、日々の気づきやナレッジを発信するメディアです

注目のタグ

    インフラ編Part2 ~ECS+ALBで実現するLINE Botサーバー構築

    こちらの記事の続きとなります。

    tech.nri-net.com

    本シリーズのトップページはこちら!!

    tech.nri-net.com

    本記事では、メッセージに応じたニュース通知機能のインフラ部分の設定をお話ししていきます。

    本機能におけるアーキテクチャは以下の通りです。

    LINEとAWS間の通信

    LINE Botサーバーを構築する前に、まずLINEユーザーとAWS間の通信環境を整えていきましょう。通信にはWebhookという技術が使用されます。Webhookとは、特定のイベントが発生した際に、指定されたURLにリクエストを送信する仕組みのことです。

    この「イベント」というのが、今回の場合「メッセージ送信」にあたり、指定されたURL(図で言うとexample.com)へリクエストが送信されます。リクエストを受けたサーバーが処理を実行し、ユーザーに対して自動的に返信を行います。 本章ではWebhookにおける通知先に関する設定をAWS側で実施していきます。具体的な設定内容は以下の通りです。

    • リクエスト先の「本体」: ALB

    • 本体に紐づくURL関連の設定(DNSや証明書発行): Route53とAWS Certificate Manager

    • 実際に処理を行うサーバー群: Amazon ECS

    ALB

    ALB(Application Load Balancer)は、アプリケーションへのトラフィックを効率的に分散し、各トラフィック先のヘルスチェックを行う重要な役割を担っています。ALBは以下の3つの主要なコンポーネントで構成されています。

    • ターゲットグループ:トラフィックを分散する先のサーバーやインスタンス群のこと。

    • セキュリティグループ:ALBへのアクセスを制御し、ネットワークトラフィックを管理します。

    • リスナー・リスナールール:リスナーはALBが受け取るトラフィックを監視し、リスナールールはそのトラフィックをどのターゲットグループにルーティングするかを決定します。

    では、それぞれのコンポーネントを設定していきます。

    ターゲットグループ

    まずはターゲットグループの設定から始めましょう。ターゲットグループは、ALB側とAmazon ECS両方での設定が必要で、具体的には、ALB側で「インスタンスやコンテナを格納するための箱」を作成し、Amazon ECSで「アプリケーションコンテナ群を箱に入れる」といった作業を実施します。

    ターゲットグループの作成イメージ

    ではALB側での設定を見ていきましょう。
    まず、ターゲットグループの作成画面で、ターゲットタイプとして「IPアドレス」を選択します。

    次にターゲットを登録の画面で自身が作成したVPCを選択し、IPアドレス入力欄横の「削除」ボタンを押して、ターゲットグループにIPアドレスが登録されていない状態にします。空のターゲットグループにはECSで起動されたコンテナのIPアドレスが動的に追加されていきます。
    ポート番号は任意の数字で構いませんが、コンテナ側で設定するポート番号と同じ値にする必要があります。

    以上で、「インスタンスやコンテナを格納するための箱」が完成しました。ECS側の設定は、後述するLINE Botサーバー構築編で説明していきます。

    セキュリティグループ

    ALBに対する通信許可を設定します。LINE Developersの公式サイトによると、Webhookの送信元であるLINEプラットフォームと、Webhook URL(ボットサーバー)との通信はHTTPSで行う必要があると記されています。
    よってALBに設定するセキュリティグループのインバウンドルールは、HTTPS通信を許可し、設定する必要があります
    また、スマホなどがインターネットに接続する際には、動的グローバルIPアドレスが割り当てられるため、セキュリティを特に気にしない場合は、ソースIPアドレスとして「0.0.0.0/0」を指定しましょう。

    リスナー・リスナールール

    リスナーでは、リクエストを受け取るプロトコル(HTTP/HTTPS)・ポートを設定し、リスナールールでは、リスナーが受け取ったリクエストのトラフィック先を指定します。今回は

    • ALBにHTTPS通信(証明書の発行が必要です。詳しい手順は後述します。)

    • ALBはコンテナと通信する

    の要件を満たす必要があるため、リスナーにHTTPS・443番ポート、リスナールールに上記で作成したターゲットグループへの転送を設定します。

    Route53 & AWS Certificate Manager

    ALBに紐づけるURLを発行するために、Route53とAWS Certificate Managerを使用してスキームとドメインの設定を行います。
    URLの構造

    Route53でホストゾーン作成

    まずRoute53で、ホストゾーンを作成していきます。ホストゾーンとは、ドメイン名に関する問い合わせに対して、どのように応答するかを定義した「設定書」のようなものです
    いわゆるドメイン名とIPアドレスの関連付けをこのホストゾーン内で定義していきます。(ドメインは発行済みとして話を進めます)


    では、発行したドメインをホストゾーンに登録していきましょう。ホストゾーンが作成されると、NSレコード(ネームサーバーレコード)が発行されます。NSレコードには、ドメイン名のDNS情報を管理するネームサーバー名が記載されています。下記画像で説明すると、aaaa.comというドメインのDNS情報は、

    • ns-1570.awsdns-04.co.uk.
    • ns-801.awsdns-36.net.
    • ns-85.awsdns-10.com.
    • ns-1239.awsdns-26.org

    の4つのネームサーバーで管理されているということになります。

    ネームサーバーの変更

    次にドメインを発行したサイトに登録されているネームサーバーをAWSのネームサーバに変更していきます。
    デフォルトでは、ドメイン発行サイトのネームサーバーが設定されていますが、今回はRoute53で管理を実施するため、上記4つのネームサーバーをドメイン発行サイトに登録する必要があります。登録が完了することで、名前解決をAWSのネームサーバー経由で実施できるようになります。

    Aレコードの作成

    次にAレコードを作成することで、ドメイン名とALBのIPアドレスを関連付けます。

    トラフィックのルーティング先に作成済みのALBを選択することで関連付けは完了です。

    証明書の発行

    クライアント⇔ALB間通信の暗号化(HTTPS化)を実施するために、SSL/TLS証明書をAWS Certificate Managerで発行します。取得したドメイン名を入力し、検証方法はDNS検証を選択します。

    ドメインに対する検証用のCNAMEが発行されるため、Route53でCNAMEレコードを作成します。 しばらくすると証明書のステータスが「発行済み」になります。

    この証明書を先ほど作成した、HTTPSリスナーにインポートしましょう。これにより、クライアントとALB間でHTTPS通信が可能になります。

    以上でURLの設定のうち、スキームの設定(HTTPS)、及びドメインとIPアドレスの関連付けが終了しました。この後、アプリ編で詳しく説明しますが、 パスの設定を実施することでURLがいよいよ完成します。

    LINE Bot サーバー構築

    URLの設定が終わった後は、LINEへの返信処理を行うBOTサーバーを構築していきましょう。このサーバーを構築するにあたり、先ほどからちょくちょく出ているコンテナと呼ばれる技術を活用していきます。

    コンテナって何?という人はこちらのサイトを参照してみてください。

    www.docker.com

    Amazon ECS

    Amazon ECSは簡単に言うと、「コンテナをいい感じに管理してくれるサービス」です。
    ECSは、クラスター、タスク、タスク定義、サービスと呼ばれる4つのコンポーネントで構成されます。

    ECSコンポーネント

    • クラスター
      クラスターは後述するタスクとサービスを実行する基盤を指します。

    • タスク
      起動しているコンテナの集まりのことで、後述するタスク定義をもとに起動されます。

    • タスク定義
      タスクを構成するコンテナの起動設定、テンプレートを記述したものです。 タスク定義では、実行プラットフォームやOS、CPUやメモリ、使用するコンテナイメージ等を指定します。今回の設定値は以下の通りです。

    設定内容 設定値 備考
    起動タイプ AWS Fargate コンテナランタイムやOSの管理をAWS側が担ってくれる
    OS Linux/X86_64
    CPU .25 vCPU
    メモリ 2 GB
    タスクロール ecsTaskExecutionRole コンテナ内のアプリからAWSサービスを使用するときに設定するロール
    タスク実行ロール ecsTaskExecutionRole コンテナを起動するときに必要なロール
    コンテナイメージ Amazon ECR に格納しているコンテナイメージURI ECRはコンテナイメージを格納するリポジトリ
    ポートマッピング コンテナポート : ターゲットグループに設定したポート
    プロトコル : HTTP

    注意点として、コンテナ内のアプリケーションでS3とAWS Systems ManagerのParameter Storeへのアクセスが生じるため、デフォルトのタスクロールにS3バケットアクセス許可ポリシー、AWS Systems Manager内のParameter Storeアクセス許可ポリシーを追加でアタッチする必要があります。

    Parameter Storeアクセス許可ポリシーは以下の通りです。

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "VisualEditor0",
                "Effect": "Allow",
                "Action": [
                    "ssm:GetParameters",
                    "ssm:Getparameter"
                ],
                "Resource": [
                    "arn:aws:ssm:ap-northeast-1:アカウントID:parameter/ACCESS_TOKEN",
                    "arn:aws:ssm:ap-northeast-1:アカウントID:parameter/CHANNEL_SECRET"
                ]
            }
        ]
    }
    

    なお、S3バケットアクセス許可ポリシーはニュース定期通知機能と同様のものを使用します。

    • サービス

      サービスは、実行中のタスクを管理する機能で、タスクのデプロイ・スケーリング・再起動を自動的に行います。
      例えば、タスクが終了した場合、サービスは新しいタスクを自動的に起動し、CPU使用率が高まればAutoScalingを実行してタスクの数を増やします。このようにサービスは、アプリケーションの可用性とパフォーマンスを維持する、まさに「いい感じに」コンテナを管理するコンポーネントと言えます。

    設定内容 設定値 備考
    コンピューティングオプション キャパシティプロバイダー戦略 ECSクラスタの中で、FargateやFaragte Spotをどのくらいの割合で起動するか
    キャパシティプロバイダー FARGATE_SPOT
    ベース: 0 ウェイト : 1
    コスト最小化のためFARGATE_SPOTを選択
    タスク定義 作成したタスク定義
    必要タスク数 1 タスク数1を維持してくれる。ただし、SPOTが余っていない場合はタスクは起動しない
    VPC 作成したVPC
    サブネット パブリックサブネット3つ
    セキュリティグループ ALBのセキュリティグループからの通信のみ許可
    ロードバランサー 作成したALB
    リスナー 作成したリスナー
    ターゲットグループ 作成したターゲットグループ
    サービスの自動スケーリング なし

    サービスでは、必要なタスク数や実際にタスクを配置するVPCやサブネットを選択していきます。
    ここで注目してほしいのは、ロードバランサーやターゲットグループの設定が含まれることです。ここでの設定がいわゆる「アプリケーションコンテナ群を箱に入れる」作業に該当しています。サービス内でロードバランサーを設定することで、空のターゲットグループにコンテナのIPアドレスが登録されていきます。

    コンテナ起動・停止切り替えバッチ

    コンテナの起動・停止バッチをAWS Lambda と EventBridgeを用いて実装していきます。

    AWS Lambda & EventBridge

    (※ この処理はEventBridgeのスケジューラーのみで実現可能です。筆者の知識不足によりLambdaを使用しましたが、実際には必要ありません。いい学びになりました。)

    • EventBridgeの設定
      • ECS起動、ECS停止スケジュールを作成し、Lambdaと関連付けます。またそれぞれのイベントデータに以下を記述することで、スケジュール実行時にイベントデータがLambdaに引き渡されます。
    # ECS起動スケジュール(土日の午前8時に指定)
    {
      "tasknumber": "0"
    }
    
    # ECS停止スケジュール(土日の午前9時に指定)
    {
      "tasknumber": "1"
    }
    

    Lambda関数は以下の通りです。

    import boto3
    
    ecs_client = boto3.client("ecs")
    cluster_name = "クラスター名"
    service_name = "サービス名"
    response = ecs_client.list_tasks(cluster=cluster_name)
    current_task_number = len(response['taskArns']) # 現在のタスク数
    
    def lambda_handler(event,context):
        event_task_nmber = int(event["tasknumber"]) # EventBridgeのデータを呼び出し
        if current_task_number == event_task_nmber:
    
            #サービスタスク数を変更するための関数
            def update_service(cluster_name,service_name,desired_count):
                change_task = ecs_client.update_service(
                    cluster = cluster_name,
                    service = service_name,
                    desiredCount = desired_count
                )
            if current_task_number == 1:
                update_service(cluster_name,service_name,0)
            else:
                update_service(cluster_name,service_name,1)
        else:
            return "Error"
    

    上記の関数では、EventBridgeで設定したタスク数とECS内の現在のタスク数が等しい場合、update_serviceメソッドを用いて必要タスク数の更新処理を実施しています。

    以上でLINE Botサーバー関連の設定は終了です! 次回は、AWSにおけるCI/CDパイプラインの構築、及びアラート通知機能の実装方法について紹介していきます。

    tech.nri-net.com

    執筆者:井手 亮太
    職種:インフラエンジニア
    推しのサッカー選手:ケビン・デブライネ
    執筆記事一覧:https://tech.nri-net.com/archive/author/r-ide-ryota