ユニファ開発者ブログ

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

AWS ECSのserviceにアクセスする方法

こんにちは、プロダクトエンジニアリング部のちょうです。天気もすっかり春になった気分ですね。気温がさむくなったり暖かくなったりするので体調管理を十分気をつけましょう。

さて、コンテナ技術の流行りとともに、AWS ECSなどを利用して機能を提供するサービスが増えたと思います。ただ、EC2インスタンスからECS serviceに変わる際に、実際インフラレベルの内容が複雑になることが多く、いままでできたことをどうやってECSで実現できるかを調べないといけないです。その一つはサーバーに入って、調査したり、作業したりすることです。

ECSにはEC2とFargate二種類があります。EC2は名前通りEC2インスタンスです。既存のEC2インスタンスを再利用できます。特にSpot instanceなどです。Fargateはまったくインスタンスを管理しなくてもいいタイプです。EC2タイプはインスタンスがあるので、そのインスタンスに入って、ローカルと同じようにdockerのコマンドを使えば実行中のECS serviceにアクセスできます。Fargateになると、インスタンスがないので、簡単で入ることができません。

先月AWSからECS serviceにdocker execを実行できるニュースがあります。

Amazon ECS で、Amazon EC2 または AWS Fargate で実行されているコンテナでのコマンドの実行が可能に

いろいろ設定を変えれば、Fargateでも入れるようになります。先日弊社のブログにも書きました。

Amazon ECS Execを使ってrails consoleを動かしてみる - ユニファ開発者ブログ

でも、よく考えると、実行中のECS serviceに、docker execで入って、調査はまだいいですが、作業はやめたほうがいいかもしれません。実行中のサービスに影響があります。それと、Fargateを使ってインスタンスを管理しなくてもいい反面、ディスクのサイズは固定、プログラムが終わると消えるデメリットがあります。正直本番作業に向いていないです。いろいろ設定して、作業用に変えるより、素直にEC2タイプを使いましょう。

EC2タイプでしたら、AWS CloudFormationを使って一瞬まとめて作ることができます。おまけに、EC2インスタンスの種類などいろいろ指定できます。Terraformでも管理できますが、こういう一時的にリソースを作ってあとで消す作業はCloudFormationが向いています。

実際のCloudFormation定義を見ると、入力パラメータ

AWSTemplateFormatVersion: "2010-09-09"
Description: ECS EC2

Parameters:
  ImageUrl:
    Type: String
    Description: "Full image url"
  VpcId:
    Type: AWS::EC2::VPC::Id
    Description: "VPC to place EC2 and other resources"
  PrivateSubnet1:
    Type: AWS::EC2::Subnet::Id
    Description: "Private subnet to place EC2 and other resources"
  InstanceType:
    Description: "EC2 instance type"
    Type: String
    Default: t2.micro
    AllowedValues:
      - t2.micro
      - t2.small
      - t2.medium
      - t2.large
      - m3.medium
      - m3.large
      - m3.xlarge
      - m3.2xlarge
      - m4.large
      - m4.xlarge
      - m4.2xlarge
      - m4.4xlarge
      - m4.10xlarge
      - c4.large
      - c4.xlarge
      - c4.2xlarge
      - c4.4xlarge
      - c4.8xlarge
      - c3.large
      - c3.xlarge
      - c3.2xlarge
      - c3.4xlarge
      - c3.8xlarge
      - r3.large
      - r3.xlarge
      - r3.2xlarge
      - r3.4xlarge
      - r3.8xlarge
      - i2.xlarge
      - i2.2xlarge
      - i2.4xlarge
      - i2.8xlarge
    ConstraintDescription: "Please choose a valid instance type."
  TaskCpu:
    Type: Number
    Description: "CPU resource for the task, 1024 = 1vCPU"
    Default: 256
    AllowedValues:
      - 256
      - 512
      - 1024
      - 2048
      - 4096
  TaskMemory:
    Type: Number
    Description: "Memory for the task, 512 = 0.5GB"
    Default: 512
    AllowedValues:
      - 512
      - 1024
      - 2048
      - 4096
      - 8192
      - 16384
      - 30720

状況に応じてCPUやメモリを指定できます。実際の画面はこうなります。

f:id:unifa_tech:20210415145428p:plain
cloudformation-parameters

次はEC2インスタンスの設定です。

Resources:
  EcsInstanceRole:
    Type: "AWS::IAM::Role"
    Properties:
      RoleName: "ecsInstanceRole"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "ec2.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role"
        - "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"

  IamInstanceProfile:
    Type: "AWS::IAM::InstanceProfile"
    Properties:
      InstanceProfileName: "EcsInstance"
      Roles:
        - !Ref EcsInstanceRole

  EcsInstanceSecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      GroupName: ecs-ec2
      GroupDescription: "ecs ec2"
      VpcId: !Ref VpcId
      Tags:
        - Key: Name
          Value: ecs-ec2

  EcsInstance:
    Type: "AWS::EC2::Instance"
    CreationPolicy:
      ResourceSignal:
        Timeout: PT5M
    Properties:
      # https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-optimized_AMI.html
      # AWS ECS optimized AMI for ap-northeast-1(Tokyo)
      # https://ap-northeast-1.console.aws.amazon.com/systems-manager/parameters/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id/description?region=ap-northeast-1#
      ImageId: "ami-08aba6714243b1bf9"
      InstanceType: !Ref InstanceType
      IamInstanceProfile: !Ref IamInstanceProfile
      SubnetId: !Ref PrivateSubnet1
      SecurityGroupIds:
        - !Ref EcsInstanceSecurityGroup
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash -xe
          echo ECS_CLUSTER=my-cluster >> /etc/ecs/ecs.config
          yum install -y aws-cfn-bootstrap
          /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource EcsInstance --region ${AWS::Region}
      Tags:
        - Key: Name
          Value: ecs-ec2

ECS用のEC2インスタンスを作るには、ECS用のImageを指定するほか、ecs.configにクラスターの名前を指定する必要があります。最後はTaskDefinitionとECS Serviceです。

  TaskDefinition:
    Type: "AWS::ECS::TaskDefinition"
    Properties:
      Family: my-console
      Cpu: !Ref TaskCpu
      Memory: !Ref TaskMemory
      NetworkMode: "awsvpc"
      RequiresCompatibilities:
        - "EC2"
        - "FARGATE"
      ExecutionRoleArn: !ImportValue "EcsExecutionRoleArn"
      ContainerDefinitions:
        - Name: "console"
          Image: !Ref ImageUrl
          Essential: true
          # https://stackoverflow.com/questions/2935183/bash-infinite-sleep-infinite-blocking
          Command:
            - /bin/sh
            - -c
            - "while true; do sleep 3600; done"
          # ...

  EcsServiceSecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      GroupName: ecs-service-ec2
      GroupDescription: "ecs service on ec2"
      VpcId: !Ref VpcId
      SecurityGroupIngress:
        - SourceSecurityGroupId: !Ref EcsInstanceSecurityGroup
          SourceSecurityGroupOwnerId: !Ref AWS::AccountId
          IpProtocol: -1
      Tags:
        - Key: Name
          Value: ecs-service-ec2

  EcsServiceAPI:
    Type: "AWS::ECS::Service"
    DependsOn:
      - EcsInstance
    Properties:
      Cluster: my-cluster
      ServiceName: my-console
      DeploymentController:
        Type: "ECS" # rolling update
      DeploymentConfiguration:
        DeploymentCircuitBreaker:
          Enable: true
          Rollback: true
      LaunchType: "EC2"
      TaskDefinition: !Ref TaskDefinition
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: "DISABLED"
          SecurityGroups:
            - !Ref EcsServiceSecurityGroup
          Subnets:
            - !Ref PrivateSubnet1
      SchedulingStrategy: "REPLICA"

ECS Clusterは基本事前に作っていたので、ここで名前が一致すればいいです。作業用のTaskDefinitionは基本サービスと違います。自由で設定できればそれは一番いいですよね。そしてECS serviceにload balancerやservice registry一切ないのもすっきりですよね。

このCloudFormation設定を利用して、関連リソースを作れば、AWS System ManagerからEC2インスタンスにアクセスできれば、実行中のECS serviceにもアクセスできます。そしてEC2にいると、いろいろ作業しやすいです。

最後に、AWSが新しく発表したecs execですが、用途に応じて使うのがいいでしょう。例えば、調査や簡単な作業などです。長時間の作業や負荷をかける作業でしたら使わないほうがいいと思います。逆にEC2タイプとCloudFormationを利用して、簡単でスムーズに本番作業を対応できます。ぜひ使ってみましょう。

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

unifa-e.com