ECS/Fargateでコンテナ起動時に初期処理でタスクメタデータを取得して、その値をもとにSSMパラメータストアおよびSecret Managerに格納された値を環境変数に設定する方法を確認したメモ。
コンテナイメージの作成
コンテナイメージを作成する。
サンプルアプリケーションの作成
環境変数を表示できるサンプルアプリケーションを作成する。以下のファイル群を作成する。
. ├── Dockerfile ├── app.py └── requirements.txt
app.py
import os from flask import Flask app = Flask(__name__) @app.route('/', methods=['GET']) def top(): return 'Hello World!' @app.route('/env', methods=['GET']) def env(): return dict(os.environ) if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=True)
requirements.txt
Flask
Dockerfile
FROM python:3-alpine WORKDIR /usr/src/app COPY requirements.txt ./ RUN pip install --no-cache-dir -r requirements.txt COPY app.py ./ ENV PYTHONUNBUFFERED 1 CMD [ "python", "./app.py" ]
パラメータの格納
SSMパラメータストアとSecret Managerにパラメータを格納する。
aws ssm put-parameter --name aurora-endpoint-ap-northeast-1a --type String --value aurora-ap-northeast-1a.example.com aws ssm put-parameter --name aurora-endpoint-ap-northeast-1c --type String --value aurora-ap-northeast-1c.example.com aws secretsmanager create-secret --name aurora-endpoint-ap-northeast-1a --secret-string aurora-ap-northeast-1a.example.local aws secretsmanager create-secret --name aurora-endpoint-ap-northeast-1c --secret-string aurora-ap-northeast-1c.example.local
初期処理スクリプトの作成
タスクメタデータを取得し、その値をもとにパラメータを取得するスクリプトを作成する。
python:3-alpine
のイメージをdocker inspect
で確認するとENTRYPOINT
は空になっている。
ENTRYPOINT
でスクリプトを実行し、このスクリプトに引数で渡されるCMD
の処理を最後にexec
で実行する。
entrypoint.sh
#!/bin/sh # 起動直後のためか統計情報がとれないことがあったので、sleepを入れている sleep 10 mkdir -p /usr/src/app/static/ curl ${ECS_CONTAINER_METADATA_URI} > /usr/src/app/static/container-metadata.txt curl ${ECS_CONTAINER_METADATA_URI}/task > /usr/src/app/static/task-metadata.txt curl ${ECS_CONTAINER_METADATA_URI}/stats > /usr/src/app/static/container-stats.txt curl ${ECS_CONTAINER_METADATA_URI}/task/stats > /usr/src/app/static/task-stats.txt MYIP=$(cat /usr/src/app/static/task-metadata.txt | jq -r '.Containers[0].Networks[0].IPv4Addresses[0]') # IPからAZを判断 # サブネットマスクが24でない場合は別のやり方を考える必要がある if echo ${MYIP} | grep 10.1.3. > /dev/null 2>&1; then AZ=ap-northeast-1a elif echo ${MYIP} | grep 10.1.4. > /dev/null 2>&1; then AZ=ap-northeast-1c else exit 1 fi # AWS CLIでSSMパラメータストアからパラメータを取得 AURORA_ENDPOINT_SSM=$(aws ssm get-parameters --name aurora-endpoint-${AZ} | jq -r '.Parameters[].Value') # Secret Managerからパラメータを取得 AURORA_ENDPOINT_SECRET_MANAGER=$(aws secretsmanager get-secret-value --secret-id aurora-endpoint-${AZ} | jq -r '.SecretString') export MYIP export AZ export AURORA_ENDPOINT_SSM export AURORA_ENDPOINT_SECRET_MANAGER exec "$@"
スクリプトに実行権限を付与する。
chmod +x entrypoint.sh
イメージのビルド
Dockerfile
にcurl
、jq
、awscli
のインストールとENTRYPOINT
を追加する。
FROM python:3-alpine RUN apk --no-cache add curl RUN pip install awscli WORKDIR /usr/src/app COPY requirements.txt ./ RUN pip install --no-cache-dir -r requirements.txt COPY app.py ./ COPY entrypoint.sh /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] ENV PYTHONUNBUFFERED 1 CMD [ "python", "./app.py" ]
イメージをビルドする。
docker build -t metadata-sample .
イメージのECRへの登録
イメージをECRに登録する。
aws ecr create-repository --repository-name metadata-sample repo=$(aws ecr describe-repositories --repository-names metadata-sample --query 'repositories[0].repositoryUri' --output text) aws ecr get-login-password | docker login --username AWS --password-stdin ${repo%%/*} docker tag metadata-sample ${repo} docker push ${repo}
ECS/Fargateへのデプロイ
ECS/Fargateでタスクを実行する。
VPCの作成
CloudFormationでパブリックサブネットとプライベートサブネットとを2つずつ持つVPCを作成する。
テンプレートを作成する。
AWSTemplateFormatVersion: "2010-09-09" Parameters: VPCCIDR: Type: String Default: 10.1.0.0/16 PublicSubnet1CIDR: Type: String Default: 10.1.1.0/24 PublicSubnet2CIDR: Type: String Default: 10.1.2.0/24 PrivateSubnet1CIDR: Type: String Default: 10.1.3.0/24 PrivateSubnet2CIDR: Type: String Default: 10.1.4.0/24 Resources: ########## # VPC ########## VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VPCCIDR EnableDnsHostnames: true EnableDnsSupport: true InstanceTenancy: default Tags: - Key: Name Value: !Sub ${AWS::StackName}-VPC InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Sub ${AWS::StackName}-IGW VPCGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway ########## # PublicSubnet1 ########## PublicSubnet1: Type: AWS::EC2::Subnet Properties: CidrBlock: !Ref PublicSubnet1CIDR VpcId: !Ref VPC AvailabilityZone: !Select [0, !GetAZs ""] MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub ${AWS::StackName}-PublicSubnet1 PublicSubnet1RouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${AWS::StackName}-PublicSubnet1 PublicSubnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicSubnet1RouteTable SubnetId: !Ref PublicSubnet1 PublicSubnet1DefaultRoute: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PublicSubnet1RouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway DependsOn: - InternetGateway NatGateway1EIP: Type: AWS::EC2::EIP Properties: Domain: vpc NatGateway1: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt NatGateway1EIP.AllocationId SubnetId: !Ref PublicSubnet1 Tags: - Key: Name Value: !Sub ${AWS::StackName}-PublicSubnet1 ########## # PublicSubnet2 ########## PublicSubnet2: Type: AWS::EC2::Subnet Properties: CidrBlock: !Ref PublicSubnet2CIDR VpcId: !Ref VPC AvailabilityZone: !Select [1, !GetAZs ""] MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub ${AWS::StackName}-PublicSubnet2 PublicSubnet2RouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${AWS::StackName}-PublicSubnet2 PublicSubnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicSubnet1RouteTable SubnetId: !Ref PublicSubnet2 PublicSubnet2DefaultRoute: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PublicSubnet2RouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway DependsOn: - InternetGateway NatGateway2EIP: Type: AWS::EC2::EIP Properties: Domain: vpc NatGateway2: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt NatGateway2EIP.AllocationId SubnetId: !Ref PublicSubnet2 Tags: - Key: Name Value: !Sub ${AWS::StackName}-PublicSubnet2 ########## # PrivateSubnet1 ########## PrivateSubnet1: Type: AWS::EC2::Subnet Properties: CidrBlock: !Ref PrivateSubnet1CIDR VpcId: !Ref VPC AvailabilityZone: !Select [0, !GetAZs ""] MapPublicIpOnLaunch: false Tags: - Key: Name Value: !Sub ${AWS::StackName}-PrivateSubnet1 PrivateSubnet1RouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${AWS::StackName}-PrivateSubnet1 PrivateSubnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PrivateSubnet1RouteTable SubnetId: !Ref PrivateSubnet1 PrivateSubnet1DefaultRoute: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateSubnet1RouteTable DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGateway1 ########## # PrivateSubnet2 ########## PrivateSubnet2: Type: AWS::EC2::Subnet Properties: CidrBlock: !Ref PrivateSubnet2CIDR VpcId: !Ref VPC AvailabilityZone: !Select [1, !GetAZs ""] MapPublicIpOnLaunch: false Tags: - Key: Name Value: !Sub ${AWS::StackName}-PrivateSubnet2 PrivateSubnet2RouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${AWS::StackName}-PrivateSubnet2 PrivateSubnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PrivateSubnet2RouteTable SubnetId: !Ref PrivateSubnet2 PrivateSubnet2DefaultRoute: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateSubnet2RouteTable DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGateway2 Outputs: VPC: Value: !Ref VPC Export: Name: !Sub ${AWS::StackName}-VPC PublicSubnet1: Value: !Ref PublicSubnet1 Export: Name: !Sub ${AWS::StackName}-PublicSubnet1 PublicSubnet2: Value: !Ref PublicSubnet2 Export: Name: !Sub ${AWS::StackName}-PublicSubnet2 PrivateSubnet1: Value: !Ref PrivateSubnet1 Export: Name: !Sub ${AWS::StackName}-PrivateSubnet1 PrivateSubnet2: Value: !Ref PrivateSubnet2 Export: Name: !Sub ${AWS::StackName}-PrivateSubnet2
パラメーターファイルを作成する。
[ { "ParameterKey": "VPCCIDR", "ParameterValue": "10.1.0.0/16" }, { "ParameterKey": "PublicSubnet1CIDR", "ParameterValue": "10.1.1.0/24" }, { "ParameterKey": "PublicSubnet2CIDR", "ParameterValue": "10.1.2.0/24" }, { "ParameterKey": "PrivateSubnet1CIDR", "ParameterValue": "10.1.3.0/24" }, { "ParameterKey": "PrivateSubnet2CIDR", "ParameterValue": "10.1.4.0/24" } ]
スタックを作成する。
aws cloudformation create-stack \ --stack-name MyVPCStack \ --template-body file://vpc.yaml \ --parameters file://vpc.parameter.json
VPCとサブネットのIDを確認する。
aws cloudformation describe-stacks --stack-name MyVPCStack | jq -r '.Stacks[].Outputs[]'
変数に入れておく。
VpcId=$(aws cloudformation describe-stacks --stack-name MyVPCStack | jq -r '.Stacks[].Outputs[] | select( .OutputKey | test("VPC") ) | .OutputValue') PrivateSubnet1Id=$(aws cloudformation describe-stacks --stack-name MyVPCStack | jq -r '.Stacks[].Outputs[] | select( .OutputKey | test("PrivateSubnet1") ) | .OutputValue') PrivateSubnet2Id=$(aws cloudformation describe-stacks --stack-name MyVPCStack | jq -r '.Stacks[].Outputs[] | select( .OutputKey | test("PrivateSubnet2") ) | .OutputValue') PublicSubnet1Id=$(aws cloudformation describe-stacks --stack-name MyVPCStack | jq -r '.Stacks[].Outputs[] | select( .OutputKey | test("PublicSubnet1") ) | .OutputValue') PublicSubnet2Id=$(aws cloudformation describe-stacks --stack-name MyVPCStack | jq -r '.Stacks[].Outputs[] | select( .OutputKey | test("PublicSubnet2") ) | .OutputValue')
セキュリティグループの作成
セキュリティグループを作成する。
aws ec2 create-security-group --group-name MyALBSecurityGroup --description MyALBSecurityGroup --vpc-id ${VpcId} ALBSecurityGroupId=$(aws ec2 describe-security-groups | jq -r '.SecurityGroups[] | select( .GroupName | test("MyALBSecurityGroup") ) | .GroupId'); echo ${ALBSecurityGroupId}
80番ポートへのアクセスを許可する。
aws ec2 authorize-security-group-ingress --group-id ${ALBSecurityGroupId} --protocol tcp --port 80 --cidr 0.0.0.0/0
デフォルトのセキュリティグループを取得する。
DefaultSecurityGroupId=$(aws ec2 describe-security-groups | jq -r '.SecurityGroups[] | select( ( .VpcId | test("'${VpcId}'") ) and ( .GroupName | test("default") ) ) | .GroupId'); echo ${DefaultSecurityGroupId}
ALBの作成
ALBを作成する。
aws elbv2 create-load-balancer --name MyALB \ --subnets ${PublicSubnet1Id} ${PublicSubnet2Id} --security-groups ${ALBSecurityGroupId} ${DefaultSecurityGroupId} LoadBalancerArn=$(aws elbv2 describe-load-balancers --name MyALB | jq -r '.LoadBalancers[].LoadBalancerArn'); echo ${LoadBalancerArn} DNSName=$(aws elbv2 describe-load-balancers --name MyALB | jq -r '.LoadBalancers[].DNSName'); echo ${DNSName}
ターゲットグループを作成する。
aws elbv2 create-target-group --name MyTargetGroup --protocol HTTP --port 80 \ --target-type ip --vpc-id ${VpcId} TargetGroupArn=$(aws elbv2 describe-target-groups --names MyTargetGroup | jq -r '.TargetGroups[].TargetGroupArn'); echo ${TargetGroupArn}
ターゲットグループにリクエストを転送するデフォルトルールを持つリスナーを作成する。
aws elbv2 create-listener --load-balancer-arn ${LoadBalancerArn} \ --protocol HTTP --port 80 \ --default-actions Type=forward,TargetGroupArn=${TargetGroupArn}
ECSクラスターの作成
Fargateクラスターを作成する。
aws ecs create-cluster --cluster-name fargate-cluster
タスクロールの作成
信頼ポリシーのjsonを作成する。
cat <<EOF > ecs-tasks-trust-policy.json { "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "ecs-tasks.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF
ロールを作成する。
aws iam create-role --role-name MetadataSampleTaskRole --assume-role-policy-document file://ecs-tasks-trust-policy.json
ポリシーの定義ファイルを作成する。
cat <<EOF > ecs-tasks-policy.json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["ssm:DescribeParameters"], "Resource": "*" }, { "Effect": "Allow", "Action": ["ssm:GetParameters"], "Resource": [ "arn:aws:ssm:ap-northeast-1:XXXXXXXXXXXX:parameter/aurora-endpoint-*" ] }, { "Effect": "Allow", "Action": "secretsmanager:ListSecrets", "Resource": "*" }, { "Effect": "Allow", "Action": "secretsmanager:GetSecretValue", "Resource": "arn:aws:secretsmanager:ap-northeast-1:XXXXXXXXXXXX:secret:aurora-endpoint-*" } ] } EOF
ポリシーを作成し、ロールにアタッチする。
aws iam create-policy --policy-name MetadataSampleTaskPolicy --policy-document file://ecs-tasks-policy.json PolicyArn=$(aws iam list-policies | jq -r '.Policies[] | select( .PolicyName | test("MetadataSampleTaskPolicy") ) | .Arn') aws iam attach-role-policy --role-name MetadataSampleTaskRole --policy-arn ${PolicyArn} RoleArn=$(aws iam list-roles | jq -r '.Roles[] | select( .RoleName | test("MetadataSampleTaskRole") ) | .Arn')
タスク定義の登録
タスク定義のjsonを作成する。
cat <<EOF > task-definition.json { "family": "metadata-sample", "taskRoleArn": "${RoleArn}", "executionRoleArn": "ecsTaskExecutionRole", "networkMode": "awsvpc", "containerDefinitions": [ { "name": "metadata-sample", "image": "${repo}", "portMappings": [ { "containerPort": 5000, "protocol": "tcp" } ], "essential": true, "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "/ecs/metadata-sample", "awslogs-region": "ap-northeast-1", "awslogs-stream-prefix": "ecs" } } } ], "requiresCompatibilities": ["FARGATE"], "cpu": "256", "memory": "512" } EOF
タスク定義を登録する。
aws ecs register-task-definition --cli-input-json file://task-definition.json
タスクが使用するロググループを作成する。
aws logs create-log-group --log-group-name "/ecs/metadata-sample"
サービスの作成
サービスのjsonを作成する。
cat <<EOF > service.json { "cluster": "fargate-cluster", "serviceName": "metadata-sample", "taskDefinition": "metadata-sample", "loadBalancers": [ { "targetGroupArn": "${TargetGroupArn}", "containerName": "metadata-sample", "containerPort": 5000 } ], "desiredCount": 2, "launchType": "FARGATE", "networkConfiguration": { "awsvpcConfiguration": { "subnets": ["${PrivateSubnet1Id}", "${PrivateSubnet2Id}"], "securityGroups": ["${DefaultSecurityGroupId}"], "assignPublicIp": "DISABLED" } } } EOF
サービスを作成する。
aws ecs create-service --cli-input-json file://service.json
稼働確認
環境変数出力ページを確認する。
$ curl -s http://${DNSName}/env { "AURORA_ENDPOINT_SECRET_MANAGER": "aurora-ap-northeast-1c.example.local", "AURORA_ENDPOINT_SSM": "aurora-ap-northeast-1c.example.com", "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI": "/v2/credentials/7e7d0c6e-7788-4c32-9b98-289866f8d150", "AWS_DEFAULT_REGION": "ap-northeast-1", "AWS_EXECUTION_ENV": "AWS_ECS_FARGATE", "AWS_REGION": "ap-northeast-1", "AZ": "ap-northeast-1c", "ECS_CONTAINER_METADATA_URI": "http://169.254.170.2/v3/875d420a-f2e5-494e-9284-0028203364bc", "GPG_KEY": "E3FF2839C048B25C084DEBE9B26995E310250568", "HOME": "/root", "HOSTNAME": "ip-10-1-4-45.ap-northeast-1.compute.internal", "LANG": "C.UTF-8", "MYIP": "10.1.4.45", "PATH": "/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "PWD": "/usr/src/app", "PYTHONUNBUFFERED": "1", "PYTHON_GET_PIP_SHA256": "421ac1d44c0cf9730a088e337867d974b91bdce4ea2636099275071878cc189e", "PYTHON_GET_PIP_URL": "https://github.com/pypa/get-pip/raw/d59197a3c169cef378a22428a3fa99d33e080a5d/get-pip.py", "PYTHON_PIP_VERSION": "20.0.2", "PYTHON_VERSION": "3.8.2", "SHLVL": "1", "WERKZEUG_RUN_MAIN": "true", "WERKZEUG_SERVER_FD": "3" }
MYIP
、AZ
、AURORA_ENDPOINT_SSM
、AURORA_ENDPOINT_SECRET_MANAGER
が環境変数にセットできている。
コンテナメタデータを確認する。違うタスクにロードバランスされるかもしれない。
$ curl -s http://${DNSName}/static/container-metadata.txt | jq . { "DockerId": "74e471293a55db5ce564bf1a3e6dfbf3a912ec1c389db5d2ff1fc8ce3b3da71e", "Name": "metadata-sample", "DockerName": "ecs-metadata-sample-2-metadata-sample-eed8d2e8ddd793825000", "Image": "XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/metadata-sample", "ImageID": "sha256:d971d80d96bcefd3b9b9f3529c661c880e2eae721796eebc81df63f98e73a22c", "Labels": { "com.amazonaws.ecs.cluster": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:cluster/fargate-cluster", "com.amazonaws.ecs.container-name": "metadata-sample", "com.amazonaws.ecs.task-arn": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:task/31d29581-4211-4c80-9a1c-62aff14e50ca", "com.amazonaws.ecs.task-definition-family": "metadata-sample", "com.amazonaws.ecs.task-definition-version": "2" }, "DesiredStatus": "RUNNING", "KnownStatus": "RUNNING", "Limits": { "CPU": 0, "Memory": 0 }, "CreatedAt": "2020-03-06T21:21:19.967864669Z", "StartedAt": "2020-03-06T21:21:23.462788118Z", "Type": "NORMAL", "Networks": [ { "NetworkMode": "awsvpc", "IPv4Addresses": [ "10.1.4.45" ] } ] }
タスクメタデータを確認。
$ curl -s http://${DNSName}/static/task-metadata.txt | jq . { "Cluster": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:cluster/fargate-cluster", "TaskARN": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:task/31d29581-4211-4c80-9a1c-62aff14e50ca", "Family": "metadata-sample", "Revision": "2", "DesiredStatus": "RUNNING", "KnownStatus": "RUNNING", "Containers": [ { "DockerId": "9471052b540ea3c6e38a3cc8d2a6036c8c77f66e7eab733f010236703da61121", "Name": "~internal~ecs~pause", "DockerName": "ecs-metadata-sample-2-internalecspause-84a9b0dbb4d0c09ba501", "Image": "fg-proxy:tinyproxy", "ImageID": "", "Labels": { "com.amazonaws.ecs.cluster": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:cluster/fargate-cluster", "com.amazonaws.ecs.container-name": "~internal~ecs~pause", "com.amazonaws.ecs.task-arn": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:task/31d29581-4211-4c80-9a1c-62aff14e50ca", "com.amazonaws.ecs.task-definition-family": "metadata-sample", "com.amazonaws.ecs.task-definition-version": "2" }, "DesiredStatus": "RESOURCES_PROVISIONED", "KnownStatus": "RESOURCES_PROVISIONED", "Limits": { "CPU": 0, "Memory": 0 }, "CreatedAt": "2020-03-06T21:21:12.895668525Z", "StartedAt": "2020-03-06T21:21:13.938484458Z", "Type": "CNI_PAUSE", "Networks": [ { "NetworkMode": "awsvpc", "IPv4Addresses": [ "10.1.4.45" ] } ] }, { "DockerId": "74e471293a55db5ce564bf1a3e6dfbf3a912ec1c389db5d2ff1fc8ce3b3da71e", "Name": "metadata-sample", "DockerName": "ecs-metadata-sample-2-metadata-sample-eed8d2e8ddd793825000", "Image": "XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/metadata-sample", "ImageID": "sha256:d971d80d96bcefd3b9b9f3529c661c880e2eae721796eebc81df63f98e73a22c", "Labels": { "com.amazonaws.ecs.cluster": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:cluster/fargate-cluster", "com.amazonaws.ecs.container-name": "metadata-sample", "com.amazonaws.ecs.task-arn": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:task/31d29581-4211-4c80-9a1c-62aff14e50ca", "com.amazonaws.ecs.task-definition-family": "metadata-sample", "com.amazonaws.ecs.task-definition-version": "2" }, "DesiredStatus": "RUNNING", "KnownStatus": "RUNNING", "Limits": { "CPU": 0, "Memory": 0 }, "CreatedAt": "2020-03-06T21:21:19.967864669Z", "StartedAt": "2020-03-06T21:21:23.462788118Z", "Type": "NORMAL", "Networks": [ { "NetworkMode": "awsvpc", "IPv4Addresses": [ "10.1.4.45" ] } ] } ], "Limits": { "CPU": 0.25, "Memory": 512 }, "PullStartedAt": "2020-03-06T21:21:14.066094891Z", "PullStoppedAt": "2020-03-06T21:21:19.961957201Z" }
コンテナ統計を確認する。起動直後に取ろうとすると値がnullになるかもしれない。
$ curl -s http://${DNSName}/static/container-stats.txt | jq . { "read": "2020-03-06T21:21:33.154199168Z", "preread": "2020-03-06T21:21:32.151581707Z", "pids_stats": { "current": 2 }, "blkio_stats": { "io_service_bytes_recursive": [], "io_serviced_recursive": [], "io_queue_recursive": [], "io_service_time_recursive": [], "io_wait_time_recursive": [], "io_merged_recursive": [], "io_time_recursive": [], "sectors_recursive": [] }, "num_procs": 0, "storage_stats": {}, "cpu_stats": { "cpu_usage": { "total_usage": 199585609, "percpu_usage": [ 13046685, 186538924, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], "usage_in_kernelmode": 10000000, "usage_in_usermode": 170000000 }, "system_cpu_usage": 175760000000, "online_cpus": 2, "throttling_data": { "periods": 0, "throttled_periods": 0, "throttled_time": 0 } }, "precpu_stats": { "cpu_usage": { "total_usage": 199585609, "percpu_usage": [ 13046685, 186538924, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], "usage_in_kernelmode": 10000000, "usage_in_usermode": 170000000 }, "system_cpu_usage": 173770000000, "online_cpus": 2, "throttling_data": { "periods": 0, "throttled_periods": 0, "throttled_time": 0 } }, "memory_stats": { "usage": 794624, "max_usage": 12771328, "stats": { "active_anon": 98304, "active_file": 0, "cache": 0, "dirty": 0, "hierarchical_memory_limit": 536870912, "hierarchical_memsw_limit": 9223372036854772000, "inactive_anon": 0, "inactive_file": 0, "mapped_file": 0, "pgfault": 1827, "pgmajfault": 0, "pgpgin": 3368, "pgpgout": 3344, "rss": 98304, "rss_huge": 0, "total_active_anon": 98304, "total_active_file": 0, "total_cache": 0, "total_dirty": 0, "total_inactive_anon": 0, "total_inactive_file": 0, "total_mapped_file": 0, "total_pgfault": 1827, "total_pgmajfault": 0, "total_pgpgin": 3368, "total_pgpgout": 3344, "total_rss": 98304, "total_rss_huge": 0, "total_unevictable": 0, "total_writeback": 0, "unevictable": 0, "writeback": 0 }, "limit": 4134825984 }, "name": "/ecs-metadata-sample-2-metadata-sample-eed8d2e8ddd793825000", "id": "74e471293a55db5ce564bf1a3e6dfbf3a912ec1c389db5d2ff1fc8ce3b3da71e" }
タスク統計を確認。
$ curl -s http://${DNSName}/static/task-stats.txt | jq . { "8e19921e19dcdc537d89758e56e1d5cab23265b0f709453b8daa5af41094ed38": { "read": "2020-03-06T21:21:27.704043015Z", "preread": "2020-03-06T21:21:26.701473202Z", "pids_stats": { "current": 2 }, "blkio_stats": { "io_service_bytes_recursive": [], "io_serviced_recursive": [], "io_queue_recursive": [], "io_service_time_recursive": [], "io_wait_time_recursive": [], "io_merged_recursive": [], "io_time_recursive": [], "sectors_recursive": [] }, "num_procs": 0, "storage_stats": {}, "cpu_stats": { "cpu_usage": { "total_usage": 201698665, "percpu_usage": [ 79079868, 122618797, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], "usage_in_kernelmode": 10000000, "usage_in_usermode": 170000000 }, "system_cpu_usage": 397570000000, "online_cpus": 2, "throttling_data": { "periods": 0, "throttled_periods": 0, "throttled_time": 0 } }, "precpu_stats": { "cpu_usage": { "total_usage": 201698665, "percpu_usage": [ 79079868, 122618797, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], "usage_in_kernelmode": 10000000, "usage_in_usermode": 170000000 }, "system_cpu_usage": 395590000000, "online_cpus": 2, "throttling_data": { "periods": 0, "throttled_periods": 0, "throttled_time": 0 } }, "memory_stats": { "usage": 774144, "max_usage": 12685312, "stats": { "active_anon": 94208, "active_file": 0, "cache": 0, "dirty": 0, "hierarchical_memory_limit": 536870912, "hierarchical_memsw_limit": 9223372036854772000, "inactive_anon": 0, "inactive_file": 0, "mapped_file": 0, "pgfault": 1603, "pgmajfault": 0, "pgpgin": 3156, "pgpgout": 3133, "rss": 94208, "rss_huge": 0, "total_active_anon": 94208, "total_active_file": 0, "total_cache": 0, "total_dirty": 0, "total_inactive_anon": 0, "total_inactive_file": 0, "total_mapped_file": 0, "total_pgfault": 1603, "total_pgmajfault": 0, "total_pgpgin": 3156, "total_pgpgout": 3133, "total_rss": 94208, "total_rss_huge": 0, "total_unevictable": 0, "total_writeback": 0, "unevictable": 0, "writeback": 0 }, "limit": 4134825984 }, "name": "/ecs-metadata-sample-2-metadata-sample-9c9caf838f84dbe8a301", "id": "8e19921e19dcdc537d89758e56e1d5cab23265b0f709453b8daa5af41094ed38" }, "9979db90a47dd9c7f89758f683da6f238ed4198486a84c6afa79c6cfb543fee0": { "read": "2020-03-06T21:21:27.702690833Z", "preread": "2020-03-06T21:21:26.70004246Z", "pids_stats": { "current": 7 }, "blkio_stats": { "io_service_bytes_recursive": [ { "major": 202, "minor": 26368, "op": "Read", "value": 5922816 }, { "major": 202, "minor": 26368, "op": "Write", "value": 12288 }, { "major": 202, "minor": 26368, "op": "Sync", "value": 5935104 }, { "major": 202, "minor": 26368, "op": "Async", "value": 0 }, { "major": 202, "minor": 26368, "op": "Total", "value": 5935104 } ], "io_serviced_recursive": [ { "major": 202, "minor": 26368, "op": "Read", "value": 343 }, { "major": 202, "minor": 26368, "op": "Write", "value": 3 }, { "major": 202, "minor": 26368, "op": "Sync", "value": 346 }, { "major": 202, "minor": 26368, "op": "Async", "value": 0 }, { "major": 202, "minor": 26368, "op": "Total", "value": 346 } ], "io_queue_recursive": [], "io_service_time_recursive": [], "io_wait_time_recursive": [], "io_merged_recursive": [], "io_time_recursive": [], "sectors_recursive": [] }, "num_procs": 0, "storage_stats": {}, "cpu_stats": { "cpu_usage": { "total_usage": 580043158, "percpu_usage": [ 230190180, 349852978, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], "usage_in_kernelmode": 250000000, "usage_in_usermode": 220000000 }, "system_cpu_usage": 397570000000, "online_cpus": 2, "throttling_data": { "periods": 0, "throttled_periods": 0, "throttled_time": 0 } }, "precpu_stats": { "cpu_usage": { "total_usage": 580013184, "percpu_usage": [ 230190180, 349823004, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], "usage_in_kernelmode": 250000000, "usage_in_usermode": 220000000 }, "system_cpu_usage": 395580000000, "online_cpus": 2, "throttling_data": { "periods": 0, "throttled_periods": 0, "throttled_time": 0 } }, "memory_stats": { "usage": 12083200, "max_usage": 13115392, "stats": { "active_anon": 4009984, "active_file": 4476928, "cache": 5992448, "dirty": 12288, "hierarchical_memory_limit": 536870912, "hierarchical_memsw_limit": 9223372036854772000, "inactive_anon": 0, "inactive_file": 1515520, "mapped_file": 2129920, "pgfault": 6227, "pgmajfault": 52, "pgpgin": 7564, "pgpgout": 5122, "rss": 4009984, "rss_huge": 0, "total_active_anon": 4009984, "total_active_file": 4476928, "total_cache": 5992448, "total_dirty": 12288, "total_inactive_anon": 0, "total_inactive_file": 1515520, "total_mapped_file": 2129920, "total_pgfault": 6227, "total_pgmajfault": 52, "total_pgpgin": 7564, "total_pgpgout": 5122, "total_rss": 4009984, "total_rss_huge": 0, "total_unevictable": 0, "total_writeback": 0, "unevictable": 0, "writeback": 0 }, "limit": 4134825984 }, "name": "/ecs-metadata-sample-2-internalecspause-eca9c2c1c88ed48f3200", "id": "9979db90a47dd9c7f89758f683da6f238ed4198486a84c6afa79c6cfb543fee0" } }