ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

Amazon ECS Execを使ってrails consoleを動かしてみる

人生初の某春のパン祭りに参加中のWebエンジニアの本間です。早くゴールしてご飯に戻りたい...。

さて、弊社のRailsアプリケーションの多くは、Amazon ECS + AWS Fargateの組み合わせで稼働しています。 過去はEC2上で動かしていたのですが、ECS + Fargateに移行したことで様々なメリットがありました。

しかし、ECS + Fargateに移行したことでデメリットもあります。 EC2でRailsを動かしていた時代では、作業用のEC2にsshで接続し、そこでrails consoleを動かして作業、ということが簡単にできていました。 ECS + Fargateに移行してからはこの方法が使えなくなってしまったため、データ修復やジョブリトライの作業を行うのが難しくなりました。 DBに直接接続したり、ECSのRun taskを使ったり、SREチームに特別な環境を用意してもらったりとだましだましやってきたのですが、この部分はEC2自体の方がやりやすかったと思っています。

そのような中、先日 Amazon ECS Exec が発表されました。 詳細は割愛しますが、ECS Execを使うことで 稼働中のDockerコンテナに接続してコマンドを実行する ことができるようになります。 (詳細は クラスメソッドさんの解説記事 が詳しいです)

この機能のリリースを聞いたとき「EC2時代と同じ感覚でrails consoleが使えるのではないか?」という期待が頭に浮かびました。 今回はこれができるかどうか確認するため、ECS Execを有効にした作業用のDockerコンテナを立ち上げて接続し、rails consoleを動かしてみようと思います。

前提として、すでにRailsアプリケーションがECS + Fargateの環境で動かしていることを想定しています。

準備

ECS Execを使うためには、ローカルPCに最新のAWS CLIをインストールする必要があります。 インストールしていない方は 公式ガイド に従い、インストールします。 すでにインストール済みの方も、バージョンが古いと使用できないので最新バージョンにアップデートします。

$  aws --version
aws-cli/2.1.31 Python/3.9.2 Darwin/19.6.0 source/x86_64 prompt/off

またAWS CLIのオプションのSession Manager pluginもインストールする必要があります。 インストールしていない方は、公式ガイドに従いインストールしてください。

作業

それではECS Execを使うための設定を行っていきます。

IAM

ECS Execを使うためには、「ECSタスクロール(≠ECSタスク実行ロール)」に ssmmessages 関連のpolicyを追加する必要があります。 下記のpolicyを追加します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssmmessages:CreateControlChannel",
                "ssmmessages:CreateDataChannel",
                "ssmmessages:OpenControlChannel",
                "ssmmessages:OpenDataChannel"
            ],
            "Resource": "*"
        }
    ]
}

ECSタスク定義

既存のECSタスク定義をそのまま使っても問題ないのですが、今回は実行するコマンドをtail -f /dev/null に変えた新しいタスク定義を作りました。 無駄なリソースを使わないようにするためです。

ECSサービス

今回は、ECS Exec専用のECSサービスを作成します。 現在稼働中のコンテナでもECS Execで接続してrails consoleできるはずですが、既存サービスに影響が出てしまう可能性があるため作業専用のコンテナで実行します。

作成はAWS管理コンソールから行いました。 基本的にはすでに動いているECSサービスと同じ設定ですが、以下の設定は既存サービスから変更しています。

  • (重要) Fargateのplatform versionが 1.4.0 になっていることを確認。ECS Execは1.4.0でないと利用できないため。
  • 新しく作成したタスク定義を使用する。
  • Load balancerは「None」を選択。

そしてサービス作成後、追加で行和なければいけない作業があります。 ECS Execを利用するためには、ECSサービスの enableExecuteCommand を有効にする必要があります。 この設定は、現在(2021年04月01日)、AWS管理コンソール上から設定はできないようです。 AWS CLIからは設定できるため、こちらを使って設定を有効化します。

# enableExecuteCommandはfalse
$ aws ecs describe-services \
  --cluster $your_ecs_cluster_name \
  --services $your_ecs_service_name | jq .
{
  "services": [
    {
      "enableExecuteCommand": false
    }
  ]
}

$ aws ecs update-service \
  --cluster $your_ecs_cluster_name \
  --service $your_ecs_service_name \
  --enable-execute-command

# enableExecuteCommandがtrueになった!
$ aws ecs describe-services \
  --cluster $your_ecs_cluster_name \
  --services $your_ecs_service_name | jq .
{
  "services": [
    {
      "enableExecuteCommand": true
    }
  ]
}

上記の設定後、動いているタスクをstopして、新しいタスクを起動させます。 するとECSタスクの enableExecuteCommand がtrueになり、 ExecuteCommandAgent がRUNNINGになります。

$ aws ecs describe-tasks \
  --cluster $your_ecs_cluster_name \
  --tasks $your_ecs_task_id | jq .
{
  "tasks": [
    {
      "containers": [
        {
          "managedAgents": [
            {
              "lastStartedAt": "2021-04-01T18:28:57.249000+09:00",
              "name": "ExecuteCommandAgent",
              "lastStatus": "RUNNING"
            }
          ]
        }
      ],
      "enableExecuteCommand": true
    }
  ]
}

ここまでで準備完了です!タスクIDをメモします。 次にECS Execを使ってコンテナに接続し、rails consoleを動かしてみます。

利用可能チェック

弊社Webエンジニアの杉本より、ECS Exceが使える環境になっているか確認できるツールがあると情報をもらいました。

GitHub - aws-containers/amazon-ecs-exec-checker: 🚀 Pre-flight checks for ECS Exec

上記の設定をしてもつながらなかった場合、このツールを使って何が足りていないかチェックするのが良いと思います。

実行

それではAWS CLIを使って /bin/sh コマンドを実行することで、稼働中のコンテナに接続してみます。

$ aws ecs execute-command \
       --cluster $your_ecs_cluster_name \
       --task $your_ecs_task_id \
       --container $your_ecs_task_def_container_name \
       --command "/bin/sh" --interactive

The Session Manager plugin was installed successfully. Use the AWS CLI to start a session.


Starting session with SessionId: ecs-execute-command-xxxxxxxxxxxxxxx

/app $

/app $ echo "Hello world!"
Hello world!

/app $ date
Thu Apr  1 18:49:09 JST 2021

無事接続して、コマンドを実行できるようになったようです。 次にここでrails consoleが動かせるか確認してみます。

/app $ bin/rails c

Loading staging environment (Rails 6.1.3)

irb(main):001:0> Rails.env
=> "staging" # 本番は怖いので、stagingで試してます...

irb(main):002:0> Time.current
=> Thu, 01 Apr 2021 18:49:34.230074083 JST +09:00

irb(main):003:0> user = User.find(1000)
=> ...

irb(main):004:0> user.id
=> 1000

irb(main):005:0> quit

/app $ exit

Exiting session with sessionId: ecs-execute-command-xxxxxxxxxxxxxxx.

画像で見るとこんな感じです。

f:id:ryu39:20210401192858p:plain

すごい!無事rails consoleを立ち上げることができ、アプリケーションのコードを使ってRubyのコードを実行できることも確認できました。 この環境が利用できれば、過去EC2でrails consoleを使って実施していた作業と同等のことができそうです。

まとめ

今回は新しく発表されたAmazon ECS Execを使って、稼働中のコンテナでrails consoleを動かしてみました。 いくつかの設定を加えるだけで簡単にrails consoleを使えることがわかりました。 今後は本番環境でも利用できるようにしていきたいです。

今後の課題としては、まずコンソールの入出力のロギングです。 公式のガイドを見ると、ECS Execで入力したコマンドや出力結果をS3やCloudwatchにログとして保存する例が紹介されています。 この設定を取り入れることができると、作業の履歴が簡単に残せるので是非実施したいです。

また、弊社では最近Terraformを使ってインフラをコードで管理しています。 今回、手動でインフラの設定を変更しましたが、この変更をTerraformでもできるようにしたいです。 (2021-04-01現在ですが、 terraformからも設定できる ようになっているみたいです。対応が早い!)

以上になります。 最後までご覧いただきありがとうございました。


ユニファでは一緒に働く仲間を募集しています!よかったらこちらのページもご覧ください。 unifa-e.com