SMARTCAMP Engineer Blog

スマートキャンプ株式会社(SMARTCAMP Co., Ltd.)のエンジニアブログです。業務で取り入れた新しい技術や試行錯誤を知見として共有していきます。

AWS Fargateで動いているコンテナにログインしたくて Systems Manager の Session Manager を使ってみた話

こんにちは!スマートキャンプの21卒の内定者としてエンジニアインターンをしている関口です!

私はBOXIL開発チームに所属しており、現在BOXILのインフラ基盤をAWS EC2からAWS ECS/Fargateへ移行するプロジェクトを行っています。

この記事ではそのプロジェクトを通して得た技術的な知見を共有していきます。

移行前、移行後のインフラ基盤の紹介

現在のBOXILのインフラ基盤はEC2で運用が行われています。 EC2インスタンスはOpsWorksで管理しているものの、自動でのスケールには対応しておらず、アクセスが急増した際などは手動での対応が必要です。 また、スケールが柔軟にできないためにサーバーのコストが最適化できず、サーバーの管理にもエンジニアの工数がかかっています。

今回の移行の一環としてECSでコンテナを運用することにしたため、スケールの柔軟性をあげることができます。 加えて、Fargateを利用することでEC2インスタンスの管理を手動で行う必要がなくなります。 そのためエンジニアがアプリケーション開発により集中できるようになります。

ECSとFargateの概要

ECSとはフルマネージド型のコンテナオーケストレーションサービスで,コンテナをスケーラブルに運用、管理できるサービスです。 ECSにはタスクとサービスという概念があります。 タスクとはECS上で実行するコンテナを定義したもので、1つのタスクの中にコンテナを複数束ねることもできます。 サービスとはそれぞれのタスクをいくつ起動するかを定義したものになります。

サービスを実行するためのインフラストラクチャの選択肢として、EC2とFargateを選ぶことができます。 FargateとはEC2インスタンスを管理することなくコンテナを実行できるサービスです。

ECSとFargateについての詳しい説明はAWSの公式ドキュメントをご覧ください。

docs.aws.amazon.com

docs.aws.amazon.com

今回ECSに移行することによってオートスケールができるようになります。

これによって、アプリケーションのアクセスがあまりない平日の夜間や休日に起動するサーバーの台数を自動で減らすことができ、インフラコストを削減することができます。

基盤構築の際に詰まったこととその解決策

Fargate運用することの課題

ECSの移行作業を進めていく中で詰まったことの1つに、Fargateで動かされているコンテナにログインができないという問題があります。
2021年2月現在、公式でFargateで動かしているコンテナにログインする機能はありません。

コンテナにログインができないため、既存のEC2運用でサーバーへログインして行っているリリースバッチの実行や障害調査ができなくなる懸念があります。 そのためFargateで実行されているコンテナにログインする方法を模索しました。

Fargateのコンテナへログインするための概要

前述した通り、現時点で公式の機能としてFargateコンテナにログインする方法はありません。 その代替案としてSystems Managerの機能である Session Manager を使って実現することにしました。

本来、Session ManagerはAWSのアカウント内にあるインスタンスに対してアクセスすることができるサービスですが、 エージェントをインストールし、AWSのアカウント外で管理しているものに対して、アクティベーションを設定することでアクセスすることができるようになります。 ただし、AWSのアカウント外で管理しているものに対してエージェントを経由してログインすることは料金が発生します。

この仕組を使うことでFargateで動いているコンテナにもログインすることが可能になりますが、エージェントが起動している時間分、料金がかかってしまいます。

Session Managerを使いコンテナにログインする流れは以下のとおりです。

  1. Systems Managerのエージェント(以下SSMエージェント)をFargateで動かすコンテナにインストール
  2. Systems Managerのアクティベーションを使ってコンテナをマネージドインスタンスに登録
  3. コンテナ内でSSMエージェントを起動
  4. マネージドインスタンスのコンソール画面やSession Managerのコンソール画面からセッションを開始

アクティベーションを使ったコンテナのマネージドインスタンスへの登録、SSMエージェントの起動はコンテナを立ち上げた際に実行されるエントリーポイントのシェルの中で行います。

アクティベーションはSystems Managerのコンソール画面で設定するかAWS CLIを通して作成することができます。

f:id:daichi1998928:20210216175826p:plain

今回アクティベーションの作成は、以下の理由からコンテナをマネージドインスタンスに登録するタイミングで作成します。

  • アクティベーションには期限があるため
  • 必要なときだけログインできるようにしたいため
  • 管理者側でアクティベーションを取得更新したくないため

アクティベーションはAWS CLIを通して利用するため、DockerfileでAWS CLIのインストールも行います。 またSSMエージェントのインストールもDockerfileで行います。

保険的に既存の運用と同じようにコンテナにログインできる仕組みはつくったものの、 コンテナの実行環境にログインすることはあまり好ましくないため、本番環境の運用では基本的にコンテナにはログインできない構成にしました。 そのため、コンテナのログイン可否についてはSSM-ACTIVATEという環境変数で管理することにしました。

具体的なコンテナログインのやり方

amazon-ssm-agent、AWS CLIのインストール

まず、Fargateで実行されるコンテナのDockerfileにamazon-ssm-agentをインストールします。 agentのインストールの仕方はOSごとに異なっているため、OSごとのインストールの仕方は下記のドキュメントを参照してください。 docs.aws.amazon.com

今回Fargateで動かすコンテナはRubyのDockerイメージを利用しているため、そのイメージとあわせてサンプルコードはDebianにします。

#ssm-agentのインストール
RUN wget https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/debian_amd64/amazon-ssm-agent.deb && \
    dpkg -i amazon-ssm-agent.deb && \
    rm -f amazon-ssm-agent.deb && \
    cp /etc/amazon/ssm/seelog.xml.template /etc/amazon/ssm/seelog.xml

#AWS CLIのインストール
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && \
    unzip awscliv2.zip && \
    ./aws/install && \
    rm -rf ./aws && \
    rm -f ./awscliv2.zip
アクティベーションの作成、コンテナのマネージドインスタンスへの登録、SSMエージェントの起動

アクティベーションの作成、コンテナのマネージドインスタンスへの登録、SSMエージェントの起動はコンテナを立ち上げた際に実行されるエントリーポイントのシェルで行います。 シェルファイルは以下のようになります。

if [ "$SSM_ACTIVATE" = "true" ]; then
 # アクティベーションの作成
  ACTIVATE_PARAMETERS=$(aws ssm create-activation \
    --default-instance-name "${SSM_INSTANCE_NAME}" \
    --description "${SSM_INSTANCE_NAME}" \
    --iam-role "service-role/AmazonEC2RunCommandRoleForManagedInstances" \
    --region "ap-northeast-1")
   
  export ACTIVATE_CODE=$(echo $ACTIVATE_PARAMETERS | jq -r .ActivationCode)
  export ACTIVATE_ID=$(echo $ACTIVATE_PARAMETERS | jq -r .ActivationId)

  # コンテナのマネージドインスタンスへの登録
  amazon-ssm-agent -register -code "${ACTIVATE_CODE}" -id "${ACTIVATE_ID}" -region "ap-northeast-1" -y

  # ssm-userからrootユーザーにスイッチするための権限付与
  echo "ssm-user ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/ssm-agent-users

  # SSMエージェントの登録
  nohup amazon-ssm-agent > /dev/null &
fi

アクティベーションを作成するコマンドのオプションでインスタンスの名前やIAMのRole、Regionの指定をします。 インスタンスの名前はSSM_INSTANCE_NAMEという環境変数で管理しており、この環境変数の定義はECSのタスク定義でおこなっています。

デフォルトではSSMエージェントを起動した場合、コンテナにSSMユーザーとしてログインしますが、SSMユーザーは権限が限られているため、rootユーザーにスイッチできるように設定しています。

以上より、SSMエージェントが起動しました。マネージドインスタンスのコンソール画面かSession Managerのコンソール画面からセッションを開始することができ、Fargateで動かされているコンテナへのログインができるようになります。

f:id:daichi1998928:20210216181940p:plain

f:id:daichi1998928:20210218000043p:plain

おわりに

本番環境での運用は基本的にコンテナにログインはせず、 障害対応などの場合に限りコンテナにログインする方法をとっていく方針です。 既存のEC2運用でおこなっていることをコンテナで運用した際にも実現しようとしたところ、実現したいことをまとめている記事が少なく、調査に困ったため、今回の記事を書きました。

昨年の9月から行っていた移行プロジェクトも終わりを迎えつつあります。新しい基盤の負荷テストがおわり、いよいよ新しいインフラ基盤でBOXILが動こうとしています。 コンテナでBOXILが運用されていくことが楽しみで仕方ありません!