FargateのコンテナでOSコマンドやsshで入りたい!! それssm-agentで解決できます
Fargate便利ですよね。煩わしいインスタンス管理から開放させて素早く環境が用意できます。
ですがECSと違って一点大きな問題があります。
docker exec や SSH が実行できない!!
EC2に慣れている人にはSSHで調べられないのはちょっとうっ。。。。って思います。(少なからず自分はそうでした)
ではできないのか?というとそうでもないらしくいくつか方法はあるようです。
- SSHの環境を設定してそこからコンテナに入る
- ssm-agent経由でコンテナに入る
SSHの環境を整えても良いのですが、それだとせっかくのセキュアな環境が勿体ないので今回はssm-agentを経由したコンテナの入り方を構築したのでメモ代わりに残しておきます。
環境
- AWS Fargate
参考にした記事
-
[AWS ECS]Fargateのcontainerにシェルで入りたい(sshd無しで!)
- これしかまともな情報がなかったので助かりました!!
やること
- DockerImageにssm-agentをインストールする
- Systems managerのハイブリッドアクティベーションの機能を使ってコンテナをmanagedする
- ssm-agentの起動コマンドを使ってマネージド化する
- Systems Managerのセッションスタート及びRun Commandができるか確認する
Dockerfileにssm-agentをインストールする処理を追加する
今回のコンテナはnodeJSのコンテナでPythonがなかったのでPythonのインストールも含めています(ssm-agentがPythonを使用するため)
FROM node:10.16.3-stretch-slim
RUN apt-get update && apt-get install -y \
curl \
&& apt-get clean \
# Python Install
RUN apt-get update && apt install -y \
zlib1g-dev \
libssl-dev \
libreadline-dev \
libsqlite3-dev \
libbz2-dev \
libncurses5-dev \
libgdbm-dev \
liblzma-dev \
tk-dev zlibc \
libffi-dev \
zip \
unzip \
&& apt-get clean \
&& curl https://www.python.org/ftp/python/3.7.5/Python-3.7.5.tgz | tar zx -C /usr/local/src/ \
&& cd /usr/local/src/Python-3.7.5 \
&& ./configure \
&& make && make install \
&& ln -s /usr/local/bin/python3 /usr/local/bin/python
RUN curl https://s3.ap-northeast-1.amazonaws.com/amazon-ssm-ap-northeast-1/latest/debian_amd64/amazon-ssm-agent.deb -o /tmp/amazon-ssm-agent.deb \
&& dpkg -i /tmp/amazon-ssm-agent.deb \
&& cp /etc/amazon/ssm/seelog.xml.template /etc/amazon/ssm/seelog.xml
AWS Systems Managerのアクティベーションを使用してコンテナインスタンスをマネージドインスタンスにする
このアクティベーションという機能がよくできているやつで物理のオンプレミスインスタンスやラズパイ、ローカルのdocker等ssm-agentがあればssm-agent経由でSystems Managerの機能が使用できます。
ただし注意事項でEC2等はAWSの管理化に置かれているインスタンスなので料金はかかりませんが
それ以外のサーバーを登録すると時間当たりの料金が発生します。
Systems Manager#オンプレミスインスタンス管理
試算するとssm-agent経由でマネージドインスタンスに登録した時点で
【計算式】料金 = (マネージドインスタンス管理時間単価 x 24(時間)× 日数
【コスト】5.004 USD = (0.00695 x 24) x 30
となって1コンテナタスクあたり月額約5 USD程かかるのでご注意してください。
起動スクリプトを記載する
こんな感じの起動スクリプトを記載します
#! /usr/bin/env bash
set -e
if [ "$SSM_ACTIVATE" = "true" ]; then
ACTIVATE_PARAMETERS=$(aws ssm create-activation \
--default-instance-name "$RESOURCE_STAGE-$SERVICE_NAME-$RESOURCE_VERSION" \
--description "$RESOURCE_STAGE-$SERVICE_NAME-$RESOURCE_VERSION" \
--iam-role "service-role/AmazonEC2RunCommandRoleForManagedInstances" \
--registration-limit 5)
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
nohup amazon-ssm-agent > /dev/null &
fi
.
.
## この後にコンテナで実行したい処理を記載する
インストールしたssm-agentのコマンドでマネージド化しますとこんな形で登録済みインスタンスとして登録されます
ECS Task Definitionsの修正
TaskRoleには
- AmazonSSMManagedInstanceCore
- AmazonSSMAutomationRole
- AmazonSSMDirectoryServiceAccess
が最低限必要になります
CloudFormationで記載していますがお好きな形で適宜修正してください
Parameters:
TaskDefinitionEnvSSMActivate:
Type: String
Description: true is ssma-agent start mode task definitions
Default: true
Resources:
ECSTaskRole:
Type: AWS::IAM::Role
Properties:
RoleName: "{your role name}"
Path: /
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ "ecs-tasks.amazonaws.com" ]
Action: sts:AssumeRole
- Effect: Allow
Principal:
Service: [ "ssm.amazonaws.com" ]
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonSSMAutomationRole
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
- arn:aws:iam::aws:policy/AmazonSSMDirectoryServiceAccess
ECSTaskDefinition:
Type: "AWS::ECS::TaskDefinition"
Properties:
Cpu: {your vCPU}
Memory: {your Memory}
ExecutionRoleArn: {yourExecutionRoleArn}
TaskRoleArn: !GetAtt ECSTaskRole.Arn
Family: {Your family name}
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
ContainerDefinitions:
- Name: {your container name}
Image: !Sub
- "${AWS::AccountId}.dkr.ecr.ap-northeast-1.amazonaws.com/${ECRRepository}"
Environment:
- Name: SSM_ACTIVATE
Value: !Ref TaskDefinitionEnvSSMActivate
- Name: SERVICE_NAME
Value: !Ref ServiceName
- Name: RESOURCE_STAGE
Value: !Ref Prefix
- Name: RESOURCE_VERSION
Value: !Ref CFVersion
- Name: SERVICE_STAGE
Value: !Ref ServiceStage
Command: [ "sh", "start.sh" ]
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref ECSTaskLogGroup
awslogs-region: !Ref AWSLogRegion
awslogs-stream-prefix: "ecs"
MemoryReservation: 128
PortMappings:
- HostPort: 80
Protocol: tcp
ContainerPort: 80
- HostPort: 10443
Protocol: tcp
ContainerPort: 10443
抜粋していますが
- Environment SSM_ACTIVATEのフラグで起動コンテナのssm-agentモードでの起動か否かをハンドリングしています。
デフォルトはfalseで運用してトラブルシューティングをしたい場合はtrueにフラグを立てて実行する戦略です。
繋いで見る
ではこの状態で
- セッションマネージャー
- コマンドの実行
をやってみましょう
登録したインスタンスはハイブリッドアクティベーションからアクティベーションIDをコピーして
検索をかけるとわかります。
これで接続ができます。
補足: テストが終わった後のマネージドインスタンスの掃除
aws-cliでいけます
aws ssm delete-activation --activation-id {ActivateId}
aws ssm deregister-managed-instance --instance-id "mi-12345abcd"
最後に
最後の手段で使う処理なので常時。というよりかはどうしても困ったら実行する手段として覚えて置くとよいですね。
Discussion