20200227のAWSに関する記事は18件です。

Amazon Rekognition チュートリアルほんとに10分でできるか?

モチベーション

Amazon Rekognition チュートリアル
10 分間と書いてあるが、ほんとに10分でできるか検証したい。

結果→できた

チュートリアル:https://aws.amazon.com/jp/getting-started/tutorials/detect-analyze-compare-faces-rekognition/

23:24~23:32 約8分

「類似度」が 10 を超えていないことに注意してください。 と記載あるがsimilarityが13超えていたパターンがあったのはご愛敬w

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

aws-vault の登録内容から AWS CLI 設定ファイルを作成する

AWS CLI v2とaws-vaultとpecoを使ってプロファイルを選択方式にする で書いた、aws-vault の登録内容から AWS CLI 設定ファイル (~/.aws/config) を作成する shell を作ってみました。

aws_config_maker.sh
#!/bin/sh

# Variables
readonly TARGET_HONE=$HOME/.aws
readonly TARGET_FILE=$TARGET_HONE/config
readonly REGION=ap-northeast-1
readonly OUTPUT=json

# Initialize .aws/config
if [ ! -e "$TARGET_HONE" ]; then
  echo Create a config form folder.
  mkdir -p "$TARGET_HONE"
fi

# Back up .aws/config
if [ -e "$TARGET_FILE" ]; then
  echo Back up config.
  cp -p "$TARGET_FILE" "$TARGET_FILE".`date "+%Y%m%d%H%M%S"`
fi

# Create default profile
echo Register default settings.
cat <<EOF > "$TARGET_FILE"
[default]
credential_process=/usr/local/bin/credential-selector.sh
region=$REGION
output=$OUTPUT
EOF

# Added settings for each credential
for credential in ` aws-vault ls | awk 'NR>2 {if ($2 != "-") print $2}'`
do
  echo Register profile [$credential].
  cat <<EOF >> "$TARGET_FILE"

[profile $credential]
credential_process=aws-vault exec -j $credential --no-session
region=$REGION
output=$OUTPUT
EOF

done

これを実行すると

$ sh ./aws_config_maker.sh
Back up config.
Register default settings.
Register profile [prof1].
Register profile [prof2].
Register profile [prof3].
~/.aws/config
[default]
credential_process=/PATH/TO/credential-selector.sh
region=ap-northeast-1
output=json

[profile prof1]
credential_process=aws-vault exec -j prof1 --no-session
region=ap-northeast-1
output=json

[profile prof2]
credential_process=aws-vault exec -j prof2 --no-session
region=ap-northeast-1
output=json

[profile prof3]
credential_process=aws-vault exec -j prof3 --no-session
region=ap-northeast-1
output=json

って感じで既にファイルがあればバックアップして aws-vault の登録内容から config を生成します。
~/.aws/credentials の方はなんにもしません。

作ってみたものの、かなりの数のクレデンシャルを登録しないと shell の効果を感じることは無さそうな。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CloudFormationのテンプレートを分割して作成してみた。

はじめに

AWSでCloudFormationのサービスを利用すると、リソース(EC2やRDS等)をテンプレートから自動構築することができるようになり、同じインフラ構成をすぐに再現することができます。

AWS公式オンラインセミナーのスライド67枚目にあるように、テンプレートは分割して運用することがベストプラクティスのようです。今回、以下の3つのテンプレートに分割して、次の構成図をyamlで作成してみました。

構成図

完成図.png

Network Layer

VPC、Subnet、InternetGateway、RouteTable、VPCEndpointを作成します。

構成図でいうとここまで進みます。

Network_Layer.png

VPC

DNS系については、今回外部からは検索されても問題ないのでtrueにしています。あと、ハードウェア専用インスタンスは使用しないのでテナンシーはdefaultにしています。

Network_Layer.yml
AWSTemplateFormatVersion: 2010-09-09
Description: Network_Layer Template

Resources:
  SampleVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      InstanceTenancy: default
      Tags:
        - Key: name
          Value: SampleVPC

Subnet

PublicとPrivateそれぞれ2つずつ作成します。PublicSubnetのMapPublicIpOnLaunchをtrueに設定することでEC2のパブリックIPアドレスの自動割り当てを設定します。

Network_Layer.yml
  PublicSubnet1a:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref SampleVPC
      CidrBlock: 10.0.0.0/24
      MapPublicIpOnLaunch: true
      AvailabilityZone: ap-northeast-1a
      Tags:
      - Key: Name
        Value: PublicSubnet1a
  PrivateSubnet1a:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref SampleVPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: ap-northeast-1a
      Tags:
      - Key: Name
        Value: PrivateSubnet1a
  PublicSubnet1c:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref SampleVPC
      CidrBlock: 10.0.3.0/24
      MapPublicIpOnLaunch: true
      AvailabilityZone: ap-northeast-1c
      Tags:
      - Key: Name
        Value: PublicSubnet1c
  PrivateSubnet1c:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref SampleVPC
      CidrBlock: 10.0.2.0/24
      AvailabilityZone: ap-northeast-1c
      Tags:
      - Key: Name
        Value: PrivateSubnet1c

InternetGateway

作成したVPCとInternetGatewayをAttachmentで関連付けしておきます。

Network_Layer.yml
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: InternetGateway

  # InternetGatewayとVPCの接続
  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref SampleVPC

RouteTable

InternetGateway接続用(public)とVPCEndpoint接続用(Private)のRouteTableを作成します。

Network_Layer.yml
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref SampleVPC
      Tags:
        - Key: Name
          Value: PublicRouteTable
  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref SampleVPC
      Tags:
        - Key: Name
          Value: PrivateRouteTable

  # SubnetとRoutetableの関連付け
  PublicRouteTableAssociation1a:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnet1a
  PublicRouteTableAssociation1c:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnet1c
  PrivateRouteTableAssociation1a:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      SubnetId: !Ref PrivateSubnet1a
  PrivateRouteTableAssociation1c:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      SubnetId: !Ref PrivateSubnet1c

  # Routeの指定
  PublicRoute:
    Type: AWS::EC2::Route
    Properties:
      DestinationCidrBlock: 0.0.0.0/0
      RouteTableId: !Ref PublicRouteTable
      GatewayId: !Ref InternetGateway

VPCEndpoint

後で作成するS3はVPC外にあります。そのため、VPCEndpointを経由してPrivateRouteTableに設置するRDSと接続できるように設定します。

Network_Layer.yml
  VPCEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      RouteTableIds:
        - !Ref PrivateRouteTable
      ServiceName: com.amazonaws.ap-northeast-1.s3
      VpcEndpointType: Gateway
      VpcId: !Ref SampleVPC

Outputs

今回、テンプレートを3つに分割しますので、Security_LayerやApplication_LayerへリソースIDを渡す必要があるものをOutputsで作成します。

Network_Layer.yml
Outputs:
  SampleVPC:
    Value: !Ref SampleVPC
    Export:
      Name: NetworkLayer-SampleVPC
  PublicSubnet1a:
    Value: !Ref PublicSubnet1a
    Export:
      Name: NetworkLayer-PublicSubnet1a
  PublicSubnet1c:
    Value: !Ref PublicSubnet1c
    Export:
      Name: NetworkLayer-PublicSubnet1c
  PrivateSubnet1a:
    Value: !Ref PrivateSubnet1a
    Export:
      Name: NetworkLayer-PrivateSubnet1a
  PrivateSubnet1c:
    Value: !Ref PrivateSubnet1c
    Export:
      Name: NetworkLayer-PrivateSubnet1c

Security Layer

セキュリティグループ、IAMユーザ、IAMポリシー、の担当分野になりますが、今回セキュリティグループのみ作成します。送信元をALBに設定するため、SourceSecurityGroupIdを設定してEC2とALBのそれぞれのセキュリティグループを関連付けておきます。

SecurityGroup

セキュリティグループはEC2、RDS、ALB用に3つ作成します。同じテンプレート内でリソースの値を参照する際は、組み込み関数Refを使用しますが、別テンプレートでエクスポートされた値を参照する場合は組み込み関数ImportValueを使用します。

構成図でいうとここまで進みます。

スクリーンショット 2020-02-27 16.33.54.png

Security_Layer.yml
AWSTemplateFormatVersion: 2010-09-09
Description: Security_Layer Template

Resources:
  SecurityGroupEC2:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: SecurityGroupEC2
      GroupName: SecurityGroupEC2
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          SourceSecurityGroupId: !Ref SecurityGroupALB
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: SecurityGroupEC2
      VpcId: !ImportValue NetworkLayer-SampleVPC
  SecurityGroupRDS:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: SecurityGroupRDS
      GroupName: SecurityGroupRDS
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: SecurityGroupRDS
      VpcId: !ImportValue NetworkLayer-SampleVPC

  SecurityGroupALB:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: SecurityGroupALB
      GroupName: SecurityGroupALB
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: SecurityGroupALB
      VpcId: !ImportValue NetworkLayer-SampleVPC

Outputs

先程同様、Outputsを作成します。

Security_Layer.yml
Outputs:
  SecurityGroupEC2:
    Value: !Ref SecurityGroupEC2
    Export:
      Name: SecurityLayer-SecurityGroupEC2

  SecurityGroupRDS:
    Value: !Ref SecurityGroupRDS
    Export:
      Name: SecurityLayer-SecurityGroupRDS

  SecurityGroupALB:
    Value: !Ref SecurityGroupALB
    Export:
      Name: SecurityLayer-SecurityGroupALB

Application Layer

最後に、EC2、RDS、ALB、S3を作成します。

Parameters

Parametersを利用して、EC2のインスタンスタイプ等をスタック作成時に設定できるようにします。

Applicaiton_Layer.yml
AWSTemplateFormatVersion: 2010-09-09
Description: Application_Layer Template

Parameters:
  InstanceType:
    Type: String
    Default: t2.micro
    AllowedValues:
      - t2.micro
      - m1.small
      - m1.large
  DBInstanceIdentifier:
    Type: String
  DBInstanceType:
    Type: String
    Default: db.t2.micro
    AllowedValues:
      - db.t2.micro
      - db.t2.small
      - db.t2.medium
  DBSubnetGroupDescription:
    Type: String
  S3BucketName:
    Type: String

EC2

ALBを利用したロードバランシングの設定にしますので、EC2を2つ作成します。

Applicaiton_Layer.yml
  SampleEC21a:
    Type: AWS::EC2::Instance
    Properties:
      NetworkInterfaces:
        - SubnetId: !ImportValue NetworkLayer-PublicSubnet1a
          GroupSet:
            - !ImportValue SecurityLayer-SecurityGroupEC2
          DeviceIndex: 0
      InstanceType: !Ref InstanceType
      ImageId: ami-0af1df87db7b650f4
      Tags:
        - Key: Name
          Value: SampleEC21a
      KeyName: aws-test
  SampleEC21c:
    Type: AWS::EC2::Instance
    Properties:
      NetworkInterfaces:
        - SubnetId: !ImportValue NetworkLayer-PublicSubnet1c
          GroupSet:
            - !ImportValue SecurityLayer-SecurityGroupEC2
          DeviceIndex: 0
      InstanceType: !Ref InstanceType
      ImageId: ami-0af1df87db7b650f4
      Tags:
        - Key: Name
          Value: SampleEC21c
      KeyName: aws-test

RDS

今回RDSはマスターとスタンバイに分けるMulti-AZ構成にして、AZ-1aとAZ-1cに設置するようにします。

Applicaiton_Layer.yml
  SampleRDS:
    Type: AWS::RDS::DBInstance
    Properties:
      AllocatedStorage : 20
      DBInstanceClass: !Ref DBInstanceType
      Port: 3306
      StorageType: gp2
      BackupRetentionPeriod: 7
      MasterUsername: admin
      MasterUserPassword: MyPassword
      DBInstanceIdentifier: !Ref DBInstanceIdentifier
      DBName: SampleRDS
      Engine: mysql
      EngineVersion: 5.7.22
      DBSubnetGroupName: !Ref SampleRDSSubnetgroup
      MultiAZ: true
      VPCSecurityGroups:
        - !ImportValue SecurityLayer-SecurityGroupRDS

  SampleRDSSubnetgroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties:
      DBSubnetGroupDescription: !Ref DBSubnetGroupDescription
      DBSubnetGroupName: SampleRDSSubnetgroup
      SubnetIds:
        - !ImportValue NetworkLayer-PrivateSubnet1a
        - !ImportValue NetworkLayer-PrivateSubnet1c

ALB

Schemeは今回インターネット向けのALBですのでinternet-facingに設定します。

Applicaiton_Layer.yml
  SampleALB:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      IpAddressType: ipv4
      Name: SampleALB
      Scheme: internet-facing
      SecurityGroups:
        - !ImportValue SecurityLayer-SecurityGroupALB
      Subnets:
        - !ImportValue NetworkLayer-PublicSubnet1a
        - !ImportValue NetworkLayer-PublicSubnet1c
      Tags:
        - Key: Name
          Value: SampleALB

  # ALBのターゲットグループの指定
  ALBTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: ALBTargetGroup
      Port: 80
      Protocol: HTTP
      Targets:
        - Id:
            Ref: SampleEC21a
          Port: 80
        - Id:
            Ref: SampleEC21c
          Port: 80
      VpcId: !ImportValue NetworkLayer-SampleVPC

  # ALBのリスナーの指定
  ALBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn:
            !Ref ALBTargetGroup
      LoadBalancerArn:
        !Ref SampleALB
      Port: 80
      Protocol: HTTP

S3

PublicAccessBlockConfigurationの設定で全てtrueにするとパブリックアクセスが全てブロックされます。

Applicaiton_Layer.yml
  SampleS3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref S3BucketName
      AccessControl: Private
      PublicAccessBlockConfiguration:
        BlockPublicAcls: True
        BlockPublicPolicy: True
        IgnorePublicAcls: True
        RestrictPublicBuckets: True
      VersioningConfiguration:
        Status: Enabled

以上で3つのテンプレートが作成できました。

最後に

AWSのマネジメントコンソールのCloudFormationのスタック作成を①Network_Layer ②Security_Layer ③Application_Layerの順で作成すれば完成です。作成したリソースの削除は、スタックを削除することで可能ですが、削除の順番は依存関係が影響するためApplication_Layerのスタックから削除する必要があります。

ちなみにApplication_Layerで作成したParameterも機能してくれています。

スクリーンショット 2020-02-28 9.43.54.png

3つのスタック全てがCREATE_COMPLETEになりましたので、これで構成図で示すリソースが全て作成されました。
スクリーンショット 2020-02-27 15.23.33.png

作成時に対応したエラー&その対処

何分初心者ですので、このコードに至るまで数々のエラーと格闘いたしました。今回のテンプレート作成時に生じたエラーを備忘録として残します。使用できる文字や配置に細かく指定があるためそのエラーが多かった印象ですが勉強になりました。

・ テンプレートの検証エラー:[/Resources] 'null' values are not allowed in templates
  => インデントのズレ修正

・ テンプレートの検証エラー: Template format error: Resource name Sample-VPC is non alphanumeric.
  => リソース名に-(ハイフン)が使用不可のため名称変更

・テンプレートの検証エラー: Template format error: Output SampleVPC is malformed. The Name field of every Export member must be specified and consist only of alphanumeric characters, colons, or hyphens.
  =>  Outputsの名称で:「コロン」が使用不可のため名称変更

・テンプレートの検証エラー: Circular dependency between resources: [VPCEndpoint, PrivateRoute1c, PrivateRoute1a]
  => 循環依存関係によるエラーで、それぞれのリソースでRouteTableIdを設定していたため生じた。 ダブらないよう片方を削除

・テンプレートの検証エラー: No updates are to be performed.
  => 変更内容がないのに更新を実行すると生じるエラーのため修正なし

・Value of property ~~~~~~~~~ must be of type List of String
  => 表記ルール違反 ユーザーガイドの表記通りの書き方に変更
     ※『改行して-(ハイフン)使用』の書き方じゃないとエラーになることが多い

・テンプレートの検証エラー: Template format error: Unresolved resource dependencies [SecurityLayer-SecurityGroupRDS] in the Resources block of the template
  => outputした変数を別テンプレートで利用するためRef関数 => importvalue関数に変更

・Property DeviceIndex cannot be empty.
  => 「DeviceIndex: 0」を追加

・Property DBSubnetGroupDescription cannot be empty.
  => DBSubnetGroupDescriptionは必須項目だったためParameterで追加

・Bucket name should not contain uppercase characters
  => S3バケット名に大文字使用不可のため名称変更

・The gateway ID '~~~~~~~~~~~~' does not exist (Service: AmazonEC2; Status Code: 400; Error Code: InvalidGatewayID.NotFound; Request ID: ~~~~~~~~~~~~)
  => Route指定でVPCEndpointを設定していたため生じたエラーのためRoute指定のコードを修正

・Encountered unsupported boolean value ture
  => タイポ「ture」を「true」に修正

・Property AllocatedStorage cannot be empty.
  => AllocatedStorageが必須項目のためDBInstanceにデフォルト値の「AllocatedStorage : 20」 を追加

参考記事

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/template-reference.html
https://www.slideshare.net/AmazonWebServicesJapan/aws-black-belt-online-seminar-aws-cloudformation
https://dev.classmethod.jp/cloud/aws/cloudformation-beginner01/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

fargateとはなんぞや

調べてみた。

「AWS Fargate とは Amazon Elastic Container Services (Amazon ECS) でコンテナを実行する際の起動タイプのうちの1つです。お客様はEC2 起動タイプ(前述の様にホストマシン上でコンテナを実行する)とFargate 起動タイプから自社のワークロードに合ったものをお選びいただくことが出来ます。」 - 公式

つまりEC2と同じようにFargateでもアプリケーションサーバを立ち上げることができる!
EC2で起動するときのイメージは、
EC2インスタンスにイメージを載せて、一つ一つを個々に管理していた!
Fargateでは、EC2インスタンスは気にすることなく、
イメージを与えるだけで勝手にスケーリングの管理をしてくれる!

EC2からFargateに変えたい場合は、起動タイプを切り替えるだけでOK!

だからEC2のスケーリング機能を勝手にやってくれる!

ECSとは
「Amazon Elastic Container Service (Amazon ECS) により、Docker コンテナアプリケーションを AWS で簡単に実行、スケール、保護できます。コンテナとしてローカルでパッケージングされたアプリケーションは、Amazon ECS によって管理されるコンテナと同様にデプロイし、実行できます。Amazon ECS では、コンテナオーケストレーションおよびクラスター管理インフラストラクチャを自分でインストール、運用、スケールする必要がないため、コンテナ化されたアプリケーションのリソースニーズと可用性要件に集中することができます。

Amazon EC2 では、数百のインスタンス全体で 1 個から数千個までコンテナを拡張できます。アプリケーションの実行方法がこれまでより複雑になることはありません。アプリケーション、バッチジョブ、マイクロサービスなどをすべて実行できます。Amazon ECS では、インフラストラクチャの複雑さがすべて解消されるため、お客様はコンテナ化アプリケーションの設計、作成、実行に集中できます。

Amazon ECS では、AWS Fargate を使用することでインフラストラクチャを完全に管理できるため、コンテナのデプロイに集中できるようになります。または、Docker コンテナの作成と削除から詳細なクラスター情報の確認まで、基盤となるサーバークラスターを完全に確認および制御することもできます。独自のコンテナスケジューラを統合して使用することや、継続的インテグレーションおよび配信システムなどの既存のソフトウェア配信プロセスに Amazon ECS を接続することができます。」 - 公式

要は、
Dockerコンテナの管理ツール。
Docker用アプリケーションをそのままデプロイできる。
コンテナオーケストレーションやクラスター管理をECSがしてくれるので便利。
Fargateで使える。

「AWS Fargate テクノロジーは、Amazon ECS を使用することで利用可能になります。AWS Fargate により、Amazon EC2 インスタンスタイプの選択、クラスターのプロビジョニングとスケール、各サーバーのパッチ適用と更新を実施する必要がなくなります。ビンパッキングやホストスプレッドなどのタスク配置戦略を考える必要はなく、タスクは複数のアベイラビリティーゾーンを渡って自動的にバランスされます。Fargate がお客様に代わってコンテナのアベイラビリティーを管理します。アプリケーションの要件を定義し、コンソールまたは CLI で起動タイプとして Fargate を選択すると、コンテナの実行に必要なすべてのスケーリングとインフラストラクチャ管理が Fargate によって処理されます。
インフラストラクチャ全体で詳細なサーバーレベルの制御が必要な開発者の場合は、Amazon ECS の EC2 起動タイプを使用することで、サーバーのクラスターを管理し、サーバー上のコンテナ配置をスケジューリングできます。
」 - 公式
ムム?FargateとECSの関連性がはっきりとわからない…

もう少し読み進めてみる…
「AWS Fargate は、Amazon Elastic Container Service (ECS) と Amazon Elastic Kubernetes Service (EKS) の両方で動作する、コンテナ向けサーバーレスコンピューティングエンジンです。Fargate を使用すると、アプリケーションの構築に簡単に集中することができます。Fargate ではサーバーのプロビジョンと管理が不要となり、アプリケーションごとにリソースを指定してその分のみ料金を支払うことができ、設計段階からのアプリケーション分離によりセキュリティを強化します。
Fargate では、インスタンスの選択やクラスター容量のスケーリングなしに、適切なコンピューティング容量が割り当てられます。料金は、コンテナの実行に必要なリソースの分のみを支払うため、オーバープロビジョニングや追加のサーバー料金は一切発生しません。Fargate による各タスクおよび各ポッドの実行には、独自のカーネルとそれぞれ独立したコンピューティング環境が使用されます。これにより、お使いのアプリケーションでワークロードの分離と設計段階からのセキュリティの向上が実現します。そしてこれが、Vanguard、Accenture、Foursquare、Ancestry などのお客様がミッションクリティカルなアプリケーションの実行に Fargate を選ぶ理由です。
」 - 公式
要は、
ECSはFargateサービスの基盤となっている部分!
アプリケーションによって、CPリソースが最適化されるので、料金もコンテナ実行のリソースにより最適化されるので無駄がない!
アプリケーションで使うポッドはそれぞれ独立しているのでセキュリティが保たれる!

公式の「サービス概要」を読んでみる

「Amazon ECSは、コンテナを大規模に稼働させることを可能にします。また、このサービスは、VPC networking、load balancing、IAM、Amazon CloudWatch LogsやCloudWatch metricsといったAWSプラットフォームとネイティブに連携しています。これらの連携により、ECSタスクはAWSプラットフォームの中でファーストクラスオブジェクトとして扱うことができます。
タスクを起動するためには、適切なインスタンスタイプと数を選び、Auto Scalingを設定し、パフォーマンス向上のためにクラスターのサイジングを管理するといったクラスターの立ち上げが必要ですが、Fargateでは、それらを全て忘れることができ、アプリケーションの定義、権限やスケーリングについてのポリシー設定に専念することができます」 - 公式

これはECSがVPCやIAM、CloudWatchなどと連携しているのでECSでこれらを普通に使えるということ。
後タスクの起動時はEC2のようにインスタンスタイプ、数、AutoScalingを設定する必要がないので、ほかのことに時間がさける。

「Amazon ECSにおいて、Fargateはlaunch typeです。今までと同様にタスク定義を利用してアプリケーションを定義することができます。対照的に、EC2 launch typeでは、サーバクラスタの管理やそのカスタマイズを柔軟に行うことが可能です。」 - 公式

つまりFargateを起動タイプとして扱うことができる。
BashでFargateを指定して起動ができる。

終わり

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSにKubernetesクラスタをTerraformで構築する(デジャヴ)

AWS上にマスターnodeをマルチゾーン化したKubernetesクラスタを構築する

イメージ図
image.png

マスターnodeをマルチゾーン化し、LBで束ねて高可用性なKubernetesクラスタを構築するのを、Terraformで自動化する。
Kubernetesのnodeは、あらかじめkubeadm,kubectl,kubelet,docker-ceをインストールしたイメージを作成しておく。

作業場所

Teraformを実行する端末は何でもよく、手元のMacやLinux PC、Azure等パブリッククラウドのLinuxインスタンスでも構わない。今回は自宅のLinux PC(Ubuntu 18.04)から実行している。Terraformのバージョンは次の通り。

root@liva-z:~# terraform version
Terraform v0.12.21

各種tfファイル

main.tf
# AWS Providerの設定
provider "aws" {
  region = var.aws_region
}

# 有効なゾーンを問い合わせlocal.all_zonesで参照する
data "aws_availability_zones" "available" {
  state = "available"
}

# local変数の設定
locals {
  all_zones        = data.aws_availability_zones.available.names
}

# sshキーペアの登録
resource "aws_key_pair" "deployer" {
  key_name   = "${var.cluster_name}-deployer-key"
  public_key = file(var.ssh_public_key_file)
}

# セキュリティグループの作成(common)
resource "aws_security_group" "common" {
  name        = "${var.cluster_name}-common"
  description = "cluster common rules"
  vpc_id      = aws_vpc.vpc.id
  tags        = map("Name", "${var.cluster_name}-sg-common", )
  ingress {
    from_port   = var.ssh_port
    to_port     = var.ssh_port
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port = 0
    to_port   = 0
    protocol  = "-1"
    self      = true
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# セキュリティグループの作成(master)
resource "aws_security_group" "master" {
  name        = "${var.cluster_name}-masters"
  description = "cluster masters"
  vpc_id      = aws_vpc.vpc.id
  tags        = map("Name", "${var.cluster_name}-sg-master", )

  ingress {
    from_port   = 6443
    to_port     = 6443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# VPCの作成
resource "aws_vpc" "vpc" {
  cidr_block = var.vpc_cidr
  tags       = map("Name", "${var.cluster_name}-vpc", )
}

# Subnetの作成(public)
resource "aws_subnet" "public" {
  count                   = length(local.all_zones)
  vpc_id                  = aws_vpc.vpc.id
  cidr_block              = cidrsubnet(var.vpc_cidr, var.subnet_netmask_bits, var.subnet_offset + count.index)
  availability_zone       = local.all_zones[count.index]
  map_public_ip_on_launch = true
  tags                    = map("Name", "${var.cluster_name}_public_${local.all_zones[count.index]}", )
}

# Subnetの作成(private)
resource "aws_subnet" "private" {
  count                   = length(local.all_zones)
  vpc_id                  = aws_vpc.vpc.id
  cidr_block              = cidrsubnet(var.vpc_cidr, var.subnet_netmask_bits, var.subnet_offset + length(local.all_zones) + count.index)
  availability_zone       = local.all_zones[count.index]
  map_public_ip_on_launch = false
  tags                    = map("Name", "${var.cluster_name}_private_${local.all_zones[count.index]}", )
}

# eipの作成
resource "aws_eip" "nat" {
  vpc = true
}

# インターネットゲートウェイの作成
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc.id
  tags   = map("Name", "${var.cluster_name}_igw", )
}

# NATゲートウェイの作成
resource "aws_nat_gateway" "ngw" {
  allocation_id = aws_eip.nat.id
  subnet_id     = aws_subnet.public.0.id
  tags          = map("Name", "${var.cluster_name}_nat_gateway-ngw", )
}

# 以下ルートテーブルの作成
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.vpc.id
  tags   = map("Name", "${var.cluster_name}_public_route_table", )

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.igw.id
  }
}

resource "aws_route_table" "private" {
  vpc_id = aws_vpc.vpc.id
  tags   = map("Name", "${var.cluster_name}_private_route_table", )

  route {
    cidr_block     = "0.0.0.0/0"
    nat_gateway_id = aws_nat_gateway.ngw.id
  }
}

resource "aws_route_table_association" "public" {
  count          = length(local.all_zones)
  subnet_id      = element(aws_subnet.public.*.id, count.index)
  route_table_id = aws_route_table.public.id
}

resource "aws_route_table_association" "private" {
  count          = length(local.all_zones)
  subnet_id      = element(aws_subnet.private.*.id, count.index)
  route_table_id = aws_route_table.private.id
}

# ロードバランサーの作成
resource "aws_lb" "master" {
  name               = "${var.cluster_name}-api-lb"
  internal           = false
  load_balancer_type = "network"
  subnets            = aws_subnet.public.*.id
  tags               = map("Name", "${var.cluster_name}-master", )
}

# リスナーの作成
resource "aws_lb_listener" "master_api" {
  load_balancer_arn = aws_lb.master.arn
  port              = 6443
  protocol          = "TCP"

  default_action {
    target_group_arn = aws_lb_target_group.master_api.arn
    type             = "forward"
  }
}

resource "aws_lb_target_group" "master_api" {
  name     = "${var.cluster_name}-api"
  port     = 6443
  protocol = "TCP"
  vpc_id   = aws_vpc.vpc.id
}

# インスタンスのアタッチ
resource "aws_lb_target_group_attachment" "master_api" {
  count            = length(local.all_zones)
  target_group_arn = aws_lb_target_group.master_api.arn
  target_id        = element(aws_instance.master.*.id, count.index)
  port             = 6443
}

# Kubernetesマスターノードの作成(ゾーン数分)
resource "aws_instance" "master" {
  count                       = length(local.all_zones)
  tags                        = map("Name", "${var.cluster_name}-master-${count.index + 1}", )
  instance_type               = "t3.medium"
  ami                         = var.node_image
  key_name                    = aws_key_pair.deployer.key_name
  vpc_security_group_ids      = [aws_security_group.common.id, aws_security_group.master.id]
  availability_zone           = local.all_zones[count.index % length(local.all_zones)]
  subnet_id                   = element(aws_subnet.private.*.id, count.index % length(local.all_zones))
  associate_public_ip_address = false
  ebs_optimized               = true
  root_block_device {
    volume_type = "gp2"
    volume_size = 30
  }
}

# Kubernetesワーカーノードの作成(6つ)
resource "aws_instance" "workers" {
  count                       = 6
  tags                        = map("Name", "${var.cluster_name}-worker-${count.index + 1}", )
  instance_type               = "t3.medium"
  ami                         = var.node_image
  key_name                    = aws_key_pair.deployer.key_name
  vpc_security_group_ids      = [aws_security_group.common.id]
  availability_zone           = local.all_zones[count.index % length(local.all_zones)]
  subnet_id                   = element(aws_subnet.private.*.id, count.index % length(local.all_zones))
  associate_public_ip_address = false
  root_block_device {
    volume_type = "gp2"
    volume_size = 30
  }
}

# 踏み台サーバの作成
resource "aws_instance" "bastion" {
  tags                        = map("Name", "${var.cluster_name}-bastion", )
  instance_type               = "t3.nano"
  ami                         = var.bastion_image
  key_name                    = aws_key_pair.deployer.key_name
  vpc_security_group_ids      = [aws_security_group.common.id]
  availability_zone           = local.all_zones[0]
  subnet_id                   = aws_subnet.public.0.id
  associate_public_ip_address = true
  root_block_device {
    volume_type = "gp2"
    volume_size = 30
  }
}
variables.tf
# 共通設定
variable "cluster_name" {
  default = "fabric"
}

variable "ssh_public_key_file" {
  default = "~/.ssh/id_rsa.pub"
}

variable "ssh_port" {
  default = 22
}

variable "vpc_cidr" {
  default = "10.10.0.0/16"
}

variable "subnet_offset" {
  default = 0
}

variable "subnet_netmask_bits" {
  default = 8
}

# クラウドベンダー依存部分
variable "aws_region" {
  default = "ap-northeast-1"
}

variable "node_image" {
  default = "ami-05b96e7df14c3437a"  # kubernetes構築済みイメージ
}

variable "bastion_image" {
  default = "ami-07f4cb4629342979c"  # 素のUbuntu 18.04
}
output.tf
output "kubeadm_api" {
  value = {
    endpoint = aws_lb.master.dns_name
  }
}

output "kubernetes_bastion" {
  value = {
    bastion_ip = aws_instance.bastion.public_ip
  }
}

output "kubernetes_master" {
  value = {
    master_ip = aws_instance.master.*.private_ip
  }
}

output "kubernetes_worker" {
  value = {
    worker_ip = aws_instance.workers.*.private_ip
  }
}

Alicloudとの大きな違いは、LBのみだとendpointが作成できない点である。インターネットゲートウェイとNATゲートウェイを設定する必要がある。

terraform applyを実行

Apply complete! Resources: 37 added, 0 changed, 0 destroyed.

Outputs:

kubeadm_api = {
  "endpoint" = "fabric-api-lb-9ae06cf14dc4c15d.elb.ap-northeast-1.amazonaws.com"
}
kubernetes_bastion = {
  "bastion_ip" = "54.178.4.137"
}
kubernetes_master = {
  "master_ip" = [
    "10.10.3.147",
    "10.10.4.161",
    "10.10.5.111",
  ]
}
kubernetes_worker = {
  "worker_ip" = [
    "10.10.3.170",
    "10.10.4.192",
    "10.10.5.245",
    "10.10.3.182",
    "10.10.4.246",
    "10.10.5.244",
  ]
}

Alicloudのコンソールでインスタンスを確認。ちゃんとマスターnodeがゾーンで分かれている。
image.png

LB(NLB)にマスターnodeが3つぶら下がっているのがわかる。
image.png

Kubernetesの設定

これでインフラが構築できたので、ここからKubernetes環境を設定していく。基本的にはこのページのMaster nodes:以下を実行すれば良い。

あとすべてのnodeであらかじめ、

swapoff -a
export KUBECONFIG=/etc/kubernetes/admin.conf

してある。というかマシンイメージの.bashrcに書いてある。
1つのマスターnodeへ入って
/etc/kubernetes/kubeadm/kubeadm-config.yamlを次の通り記述。

kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
kubernetesVersion: stable
controlPlaneEndpoint: "fabric-api-lb-9ae06cf14dc4c15d.elb.ap-northeast-1.amazonaws.com:6443"

controlPlaneEndpointには、Outputs:のkubeadm_api.endpointを設定する。

kubeadm initを実行。

root@fabric-master-2:~# kubeadm init --config=/etc/kubernetes/kubeadm/kubeadm-config.yaml --upload-certs
- 途中のkubeadmのメッセージは省略 -
Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

You can now join any number of the control-plane node running the following command on each as root:

  kubeadm join fabric-api-lb-9ae06cf14dc4c15d.elb.ap-northeast-1.amazonaws.com:6443 --token 6cwazk.a4669gp7f4uj4srh \
    --discovery-token-ca-cert-hash sha256:75bf6bfbeb01315f7b4ddcd49e0569bcd0f86bde0a35d40531cf4c221dc2f1e2 \
    --control-plane --certificate-key 76e2af2667fdaf453312df5be62ad1622a77d0e3b1d8a9130e37741cbfa72a32

Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use
"kubeadm init phase upload-certs --upload-certs" to reload certs afterward.

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join fabric-api-lb-9ae06cf14dc4c15d.elb.ap-northeast-1.amazonaws.com:6443 --token 6cwazk.a4669gp7f4uj4srh \
    --discovery-token-ca-cert-hash sha256:75bf6bfbeb01315f7b4ddcd49e0569bcd0f86bde0a35d40531cf4c221dc2f1e2

残り2つのマスターnodeでは、kubeadm initの出力にあるcontrol-plane node用のjoinコマンドを実行する。
6つのワーカーnodeでは、worker node用のjoinコマンドをひたすら実行する。

できた環境を確認する

terraformを実行したLinux PCへ、Kubernetes環境を一式(たぶんkubectlだけで良いと思う)インストール。
最初にkubeadm initしたマスターnodeから/etc/kubernetes/admin.confをコピーする。
これでkubectlが利用できるようになる。

export KUBECONFIG=/etc/kubernetes/admin.conf

を忘れずに。

root@liva-z:fabric-dev# kubectl get node -o wide
NAME             STATUS   ROLES    AGE     VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION    CONTAINER-RUNTIME
ip-10-10-3-147   Ready    master   19m     v1.17.2   10.10.3.147   <none>        Ubuntu 18.04.3 LTS   4.15.0-1057-aws   docker://18.9.9
ip-10-10-3-170   Ready    <none>   13m     v1.17.2   10.10.3.170   <none>        Ubuntu 18.04.3 LTS   4.15.0-1057-aws   docker://18.9.9
ip-10-10-3-182   Ready    <none>   10m     v1.17.2   10.10.3.182   <none>        Ubuntu 18.04.3 LTS   4.15.0-1057-aws   docker://18.9.9
ip-10-10-4-161   Ready    master   16m     v1.17.2   10.10.4.161   <none>        Ubuntu 18.04.3 LTS   4.15.0-1057-aws   docker://18.9.9
ip-10-10-4-192   Ready    <none>   11m     v1.17.2   10.10.4.192   <none>        Ubuntu 18.04.3 LTS   4.15.0-1057-aws   docker://18.9.9
ip-10-10-4-246   Ready    <none>   9m46s   v1.17.2   10.10.4.246   <none>        Ubuntu 18.04.3 LTS   4.15.0-1057-aws   docker://18.9.9
ip-10-10-5-111   Ready    master   14m     v1.17.2   10.10.5.111   <none>        Ubuntu 18.04.3 LTS   4.15.0-1057-aws   docker://18.9.9
ip-10-10-5-244   Ready    <none>   8m58s   v1.17.2   10.10.5.244   <none>        Ubuntu 18.04.3 LTS   4.15.0-1057-aws   docker://18.9.9
ip-10-10-5-245   Ready    <none>   11m     v1.17.2   10.10.5.245   <none>        Ubuntu 18.04.3 LTS   4.15.0-1057-aws   docker://18.9.9

マスターnodeが3台、ワーカーnodeが6台確認でき、すべてReadyになっている。

root@liva-z:fabric-dev# kubectl get pod -A -o wide
NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE     IP              NODE             NOMINATED NODE   READINESS GATES
kube-system   calico-kube-controllers-5c45f5bd9f-ljq95   1/1     Running   0          2m25s   192.168.101.3   ip-10-10-3-147   <none>           <none>
kube-system   calico-node-6hpbg                          1/1     Running   0          2m25s   10.10.3.170     ip-10-10-3-170   <none>           <none>
kube-system   calico-node-9xmjj                          1/1     Running   0          2m25s   10.10.3.182     ip-10-10-3-182   <none>           <none>
kube-system   calico-node-h5xrp                          1/1     Running   0          2m25s   10.10.5.244     ip-10-10-5-244   <none>           <none>
kube-system   calico-node-jkkmb                          1/1     Running   0          2m25s   10.10.4.192     ip-10-10-4-192   <none>           <none>
kube-system   calico-node-jmxl4                          1/1     Running   0          2m25s   10.10.4.161     ip-10-10-4-161   <none>           <none>
kube-system   calico-node-lc7kt                          1/1     Running   0          2m25s   10.10.5.111     ip-10-10-5-111   <none>           <none>
kube-system   calico-node-njh55                          1/1     Running   0          2m25s   10.10.3.147     ip-10-10-3-147   <none>           <none>
kube-system   calico-node-pzr6q                          1/1     Running   0          2m25s   10.10.4.246     ip-10-10-4-246   <none>           <none>
kube-system   calico-node-sqhc8                          1/1     Running   0          2m25s   10.10.5.245     ip-10-10-5-245   <none>           <none>
kube-system   coredns-6955765f44-bxmtc                   1/1     Running   0          19m     192.168.101.2   ip-10-10-3-147   <none>           <none>
kube-system   coredns-6955765f44-l8rjh                   1/1     Running   0          19m     192.168.101.1   ip-10-10-3-147   <none>           <none>
kube-system   etcd-ip-10-10-3-147                        1/1     Running   0          20m     10.10.3.147     ip-10-10-3-147   <none>           <none>
kube-system   etcd-ip-10-10-4-161                        1/1     Running   0          17m     10.10.4.161     ip-10-10-4-161   <none>           <none>
kube-system   etcd-ip-10-10-5-111                        1/1     Running   0          15m     10.10.5.111     ip-10-10-5-111   <none>           <none>
kube-system   kube-apiserver-ip-10-10-3-147              1/1     Running   0          20m     10.10.3.147     ip-10-10-3-147   <none>           <none>
kube-system   kube-apiserver-ip-10-10-4-161              1/1     Running   0          17m     10.10.4.161     ip-10-10-4-161   <none>           <none>
kube-system   kube-apiserver-ip-10-10-5-111              1/1     Running   0          14m     10.10.5.111     ip-10-10-5-111   <none>           <none>
kube-system   kube-controller-manager-ip-10-10-3-147     1/1     Running   1          20m     10.10.3.147     ip-10-10-3-147   <none>           <none>
kube-system   kube-controller-manager-ip-10-10-4-161     1/1     Running   0          17m     10.10.4.161     ip-10-10-4-161   <none>           <none>
kube-system   kube-controller-manager-ip-10-10-5-111     1/1     Running   0          14m     10.10.5.111     ip-10-10-5-111   <none>           <none>
kube-system   kube-proxy-62zdx                           1/1     Running   0          12m     10.10.5.245     ip-10-10-5-245   <none>           <none>
kube-system   kube-proxy-dqb4v                           1/1     Running   0          19m     10.10.3.147     ip-10-10-3-147   <none>           <none>
kube-system   kube-proxy-ktpt8                           1/1     Running   0          14m     10.10.3.170     ip-10-10-3-170   <none>           <none>
kube-system   kube-proxy-mmfcr                           1/1     Running   0          11m     10.10.3.182     ip-10-10-3-182   <none>           <none>
kube-system   kube-proxy-nqjbj                           1/1     Running   0          9m54s   10.10.5.244     ip-10-10-5-244   <none>           <none>
kube-system   kube-proxy-rjdmw                           1/1     Running   0          15m     10.10.5.111     ip-10-10-5-111   <none>           <none>
kube-system   kube-proxy-sw7pg                           1/1     Running   0          10m     10.10.4.246     ip-10-10-4-246   <none>           <none>
kube-system   kube-proxy-t6km4                           1/1     Running   0          17m     10.10.4.161     ip-10-10-4-161   <none>           <none>
kube-system   kube-proxy-xn2nl                           1/1     Running   0          12m     10.10.4.192     ip-10-10-4-192   <none>           <none>
kube-system   kube-scheduler-ip-10-10-3-147              1/1     Running   1          20m     10.10.3.147     ip-10-10-3-147   <none>           <none>
kube-system   kube-scheduler-ip-10-10-4-161              1/1     Running   0          17m     10.10.4.161     ip-10-10-4-161   <none>           <none>
kube-system   kube-scheduler-ip-10-10-5-111              1/1     Running   0          14m     10.10.5.111     ip-10-10-5-111   <none>           <none>

kube-system podも問題なく動作している。
eipを3つ取ってゾーン毎にNATゲートウェイへ登録すれば、もっと可用性が上がるだろう(たぶん)。
↓変更例。

main.tf
# eipの作成
resource "aws_eip" "nat" {
  count = length(local.all_zones)
  vpc   = true
}

# NATゲートウェイの作成
resource "aws_nat_gateway" "ngw" {
  count         = length(local.all_zones)
  allocation_id = element(aws_eip.nat.*.id, count.index)
  subnet_id     = element(aws_subnet.public.*.id, count.index)
}

resource "aws_route_table" "private" {
  vpc_id = aws_vpc.vpc.id
  tags   = map("Name", "${var.cluster_name}_private_route_table", )
  route {
    cidr_block     = "0.0.0.0/0"
    nat_gateway_id = aws_nat_gateway.ngw.*.id
  }
}

先にAlicloudの記事を書いたのでAWSでも同等のことが出来ることを示してみた。デジャヴを感じたかもしれない。。

Azureでも出来ると思うがマルチゾーンの考え方が異なるので、その辺りのコードが違ってくるであろう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Terraform✖️CodePipeline でプルリクエストからのマージに対応する

はたです。最近TerraformでAWS構築する機会が増えています。
ついでにCI/CD環境をAWSのCode系サービスで実現しているのですが、プルリクエストからのマージをフックしてCodePipelineを走らせるにはどうすればいいのかな?を調べたので備忘録します。

https://www.terraform.io/docs/providers/aws/r/codepipeline_webhook.html
https://developer.github.com/v3/activity/events/types/#pullrequestevent

簡単に紹介するため aws_codepipeline_webhook の記述だけ記載します。
ポイントはfilterですね。
上記URLにGithubのpull request event詳細がわかるので、それを参考にfilterの設定をしています

任意のブランチ(今回はdevelop)のプルリクエストがマージされた(プルリクが閉じられmergedフラグがtrue)の場合のaws_codepipeline_webhookの書き方

resource "aws_codepipeline_webhook" "webhook" {
  name            = "test-webhook"
  target_pipeline = aws_codepipeline.codepipeline.name
  target_action   = "Source"
  authentication  = "GITHUB_HMAC"

  authentication_configuration {
    secret_token = "xxxxxxxxxxxxx"
  }

  filter {
    json_path    = "$.action"
    match_equals = "closed"
  }

  filter {
    json_path    = "$.pull_request.merged"
    match_equals = "true"
  }

  filter {
    json_path    = "$.pull_request.base.ref"
    match_equals = "develop"
  }
}

今回はここまで、良いTerraform生活を。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【boto3】EC2インスタンスをタグでフィルタリング

boto3のresourceでEC2をNameタグでフィルタリングしたい場合、
tag:(タグキー)という形式で指定する。

Nameタグがweb-server01のインスタンスは下記のように取得。

ec2_r = boto3.resource('ec2')
inst_resources = ec2_r.instances.filter(
        Filters=[
            {'Name': 'tag:Name', 'Values': 'web-server01' }
        ])

Systemタグがwebの場合は下記のように。

inst_resources = ec2_r.instances.filter(
        Filters=[
            {'Name': 'tag:System', 'Values': 'web' }
        ])
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【助けて】既存EC2インスタンスにCloud9インストールしたいけどInstalling Nakで止まる・・・

2020年2月27日 16時37分 追記

解決策ではないのですが追記します。

下記の通りInstalling Nakで停止→Cancelを押下。
その後、CreateEnvironment画面にて作成した環境を開く、または
同一インスタンスにもう一度Cloud9の環境を作成すると
Installing Nakから再開され問題なく成功します。
(最初に作成した環境は削除したほうがよいかも)

→Installing Nakを開始するタイミングが早い・・?

まだ気持ち悪いですが、一応進展ということで・・・

=====================================

ずっとググっているのですが解決策がわからないので・・・
解決できたら同じ問題に直面している人用にリライトしようと思います。

やっていること

1.EC2でインスタンスを作成
  すべて無料枠のデフォルト設定。

2.EIPでインスタンスにIPアドレスを割り当て

3.インスタンスにNode.jsをインストール

4.cloud9のインストール画面で既存EC2インスタンス(1で作成したもの)を選択

5.4で表示されたSSH KeyをEC2インスタンスの/authorized_keysに追記

6.cloud9インストール処理を開始

以下の画面で止まります・・・
CancelしてもCloud9は問題なく使えているように見えますが、気持ち悪い・・・
原因や解決策をご存知の方がいたらコメントにて教えてください・・・

252398.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CodeBuildでEKSへBuild&Deploy

はじめに

AWS CodeBuildを用いてDocker build および EKSヘのデプロイを行うサンプルです。
GitHub Enterprise(GHI)へのPushをトリガーにCodeBuildをkickしてみます。

※当初は、CodePiplelineでGHEへのPushトリガーを受けようと考えていたのですが、CodePipelineはGHEに対応していないらしく、CodeBuildのみでまかなうことにしました。

前提

  • Date : 2020/2 時点
  • EKS Kubernetes version: 1.14
  • ImageリポジトリはECRを利用し、かつセットアップ済み (ECRの設定は本記事には記載しない)
  • EKSはセットアップ済み(EKSの設定は本記事に記載しない)
  • GHEへアプリケーションソースコードおよびDockerfileを格納済み(すでに存在する前提)
  • リポジトリ直下に、Dockerfileが格納されている(docker buildで利用)
  • リリース対象のEKS(K8s)リソースは、Deploymentを想定

GHEのPersonal access tokenの作成

GHEの右上個人メニューからSeeting -> Developer settingsと遷移し、Personal access tokensタブから作成します。
scopeはrepoのみ選択すれば問題ありません。
作成されたトークンは控えておきましょう(再表示できません)。
image.png

CodeBuildプロジェクトの作成

マネジメントコンソールから、ビルドプロジェクトを作成します。
※なお、設定値に言及がない場合は、デフォルト値を採用しています。

プロジェクトの設定セクションは任意に入力してください。

送信元セクションでは、ソースプロバイダにGitHub Enterpriseを選択し、先ほど取得したPersonal access tokenを入力します。
image.png
トークンの保存後、リポジトリのURLを入力します。
image.png

ウェブフックイベントセクションでは、再構築にチェックを入れ、イベントタイプにはプッシュを選択します。
image.png

環境セクションは下図の通り入力します。
イメージ内でDockerを起動するため、特権付与にチェックを入れます。
ロール名は任意の名称を入力してください。
image.png

環境セクションの追加設定で、下図の環境変数を設定します。
この環境変数は、後続に記載するbuildspec.yamlで利用します。
image.png

IAMポリシー&ロールの編集

CodeBuildプロジェクト作成時に作成したサービスロールに、ECRおよびEKSへのアクセスを許可するポリシーを作成します。

policy
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "ecr:CompleteLayerUpload",
                "ecr:GetAuthorizationToken",
                "ecr:UploadLayerPart",
                "ecr:InitiateLayerUpload",
                "ecr:BatchCheckLayerAvailability",
                "ecr:PutImage"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "eks:DescribeCluster",
            "Resource": "arn:aws:eks:*:*:cluster/*"
        }
    ]
}

ポリシー作成後、サービスロールにアタッチします(スクショは割愛)。

IAM RoleとEKS RBACとの紐付け

外部からEKSのK8sリソースにアクセスする場合、IAMロールとKubernetesのユーザー/グループを紐づける必要があります(先達の投稿がよくまとまっていると思います)。

「aws-auth」というEKS固有のConfigMapを編集し、CodeBuild用サービスロールをK8sのsystem:mastersグループに紐付けます。
※system:mastersというグループは、いわゆるadmin的な権限を持つデフォで存在するグループです。

aws-auth
$ kubectl edit cm aws-auth -n kube-system

apiVersion: v1
data:
  mapRoles: |
    - groups:
      - system:bootstrappers
      - system:nodes
      rolearn: arn:aws:iam::xxxx:role/xxxx
      username: system:node:{{EC2PrivateDNSName}}
##add from
    - rolearn: arn:aws:iam::xxxxx:role/codebuild-hoge-service-role
      username: codebuild 
      groups:
      - system:masters 
##add to
kind: ConfigMap
metadata:
  creationTimestamp: null
  name: aws-auth
  selfLink: /api/v1/namespaces/kube-system/configmaps/aws-auth  

ここで、注意点です。
rolearnには、パスを含めてはいけません。

○: arn:aws:iam::xxxxx:role/codebuild-hoge-service-role
×: arn:aws:iam::xxxxx:role/service-role/codebuild-hoge-service-role

マネジメントコンソールに表示されるarnにはパスが含まれるのですが、これをコピペするとロールが正しく認識されず、you must login みたいなエラーになりました。

buildspec.yaml

buildspec.yamlの内容は以下の通りです。
簡単に処理内容を書くと、dockerを起動して、buildして、pushして、k8sのdeploymentをrolloutすることでPodを再作成し、イメージの変更を反映させています。
このファイルをGHEリポジトリの直下に配置します。

buildspec.yaml
version: 0.2 

phases: 
  install:
    runtime-versions:
        docker: 18
    commands:
      # start dockerd & start wait
      - nohup /usr/local/bin/dockerd --host=unix:///var/run/docker.sock --host=tcp://127.0.0.1:2375 --storage-driver=overlay2&
      - timeout 15 sh -c "until docker info; do echo .; sleep 1; done"
      # install kubectl
      - wget -O /usr/local/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/v1.17.0/bin/linux/amd64/kubectl
      - chmod +x /usr/local/bin/kubectl
  pre_build:
    commands:
    - echo "Logging in to Amazon ECR...."
    - aws --version
    - $(aws ecr get-login --no-include-email --region $CI_REGION)
    - echo "the repo/version now is ${REPO_URL}:${LATEST_VERSION}"

    - echo "Creating folders for pid files"
    - mkdir shared
    - mkdir shared/pids
    - mkdir shared/sockets
  build: 
    commands: 
    - echo "Build started on `date`"
    - echo "Building the Docker image.. ${REPO_URL}:${LATEST_VERSION}"

    # dokcer build & push
    - docker build -t tempimage:latest .
    - docker tag tempimage:latest ${REPO_URL}:${LATEST_VERSION}
    - echo "dokcer build completed on `date`" 
    - echo "pushing to repo ${REPO_URL}:${LATEST_VERSION}"
    - docker push ${REPO_URL}:${LATEST_VERSION}
  post_build: 
    commands: 
    - echo "Build completed on `date`"
    # rollout kubernetes(eks) deployment
    - echo "rollout eks deployment = ${K8S_DEPLOY_NAME} @ ${EKS_CLUSTER_NAME}"
    - aws eks update-kubeconfig --name ${EKS_CLUSTER_NAME} --verbose
    - kubectl rollout restart deployments/${K8S_DEPLOY_NAME} -n ${K8S_NAMESPACE}

CodeBuildにWebHookを追加

以下のコマンドでCodeBuildにWebHookを追加します。
--project-nameオプションは、CodeBuildプロジェクト名を設定します。

create-webhook
$ aws codebuild create-webhook --project-name hoge
{
    "webhook": {
        "payloadUrl": "https://codebuild.ap-northeast-1.amazonaws.com/webhooks?t=eyJlbmNyeXB...<省略>",
        "secret": "5ZUJKd8wA...<省略>",
        "lastModifiedSecret": 1595395732.558
    }
}    

GHEにWebhook URLを登録

GHEリポジトリのSettings画面からWebHookを追加します。
ここで、Payload URLとSecretには、先の手順コマンドで取得したURLとSecretを入力します。

image.png

以上で手順は終了です。
GHEリポジトリに変更をpushすることで自動的にBuild&Deployが開始されるはずです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RDS 拡張モニタリングの有効化

内容

RDSの拡張モニタリングを有効化

対象

無料枠RDS(MySQL)

拡張する前

拡張モニタリングを有効する前は何が監視されていて何を見ることができるかを確認します。
・[RDS]⇒[モニタリング]タブ
CPU使用率,DB接続,空きストレージ容量,書き込みIOPS,読み取りIOPS
キューの深さ,バイナリログのディスク使用状況,書き込みスループット,読み込みスループット
スワップの使用,書き込みレイテンシー,読み込みレイテンシー,ネットワーク受信スループット
ネットワーク送信スループット,CPUクレジット使用状況,CPUクレジット残高
ss_000.JPG
ss_001.JPG
ss_002.JPG

・[CloudWatch]⇒[メトリクス]⇒[RDS]
CPUUtilization,BurstBalance,ReadIOPS,DiskQueueDepth,WriteIOPS,ReadLatency
,ReadThroughput,WriteLatency,WriteThroughput,VMWriteIOPS,VMReadIOPS,NetworkReceiveThroughput
,NetworkTransmitThroughput,SwapUsage,BinLogDiskUsage,DatabaseConnections,FreeStorageSpace
FreeableMemory,CPUCreditBalance,CPUCreditUsage,CPUSurplusCreditBalance,CPUSurplusCreditsCharged
ss_003.JPG

そもそもで

RDSで拡張モニタリングを有効にすると何を確認することができるのか。
拡張モニタリング

Amazon RDS には、DB インスタンスが実行されているオペレーティングシステム (OS) のリアルタイムのメトリクスが用意されています。

...取り敢えず有効にしていきます。

手順

拡張モニタリングを有効にするためにはIAMロールで[AmazonRDSEnhancedMonitoringRole]を作成

拡張モニタリング有効化

[AWSコンソール]⇒[サービス]⇒[データベース]⇒[RDS]を選択してRDSダッシュボードへ移動します。
ss_004.JPG

左側メニューよりデータベースを選択します。
ss_005.JPG

対象のDBを選択して変更を押下します。
ss_006.JPG

DB インスタンスの変更画面のモニタリングにて、[拡張モニタリングを有効にする]を選択します。
ここで、IAMポリシーの"AmazonRDSEnhancedMonitoringRole"がアタッチされているIAMロールを作成していないと
1枚目のようにモニタリングロールでデフォルトが選択されてその下にRDSが...と薄く表示されます。
ss_007.JPG

IAMロールが作成されていると以下のように選択することができます。
必要であれば先にIAMロールを作成しておきます。
ss_008.JPG

有効化を選択後、画面下部の[次へ]を押下します。
ss_009.JPG

変更内容を確認後、変更のスケジュールを[すぐに適用]を選択して[DBインスタンスの変更]を押下します。
ss_010.JPG

変更後、対象RDSのステータスが[configuring-enhanced-monitoring]⇒[利用可能]となるのを待ちます。
ss_015.JPG

ステータスが利用可能になったのを確認します。
[対象RDS]⇒[モニタリングタブ]⇒[モニタリング▼]⇒[拡張モニタリング]を選択します。
ss_011.JPG

拡張モニタリングが有効となっており、以下を確認することができます。
未使用のメモリ,アクティブなメモリ,CPUユーザー,CPU合計
使用中のファイルシステム,ロード平均1分
ss_012.JPG

次は[OSプロセスリスト]を押下します。
ss_013.JPG

OSのプロセスリストを確認することができます。
ss_014.JPG

以上で拡張モニタリングを有効化することができます。
詳細は公式サイトをご確認ください。
拡張モニタリング

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

appsync subscriptionで引数使うときmutationの戻り値に含めないと動かない

Appsyncでsubscription使ったときにハマったので共有します。

例えば下記のsubscription定義があるとします。

type Subscription {
    subscribeToNewMessage(conversationId: ID!): Message
        @aws_subscribe(mutations: ["createMessage"])
}

"createMessage" Mutationが実行された、かつ、conversationIdがある値のときにsubscribeしたいって定義です。

これがNuxt.jsで作ったクライアントから上手く動かなかったのですが、クライアントから実行するMutationの書き方に問題がありました。

動かなかったときのMutationは次です。

const createMessage = /* GraphQL */ `
  mutation createMessage(
    $id: ID!
    $content: String
    $conversationId: ID!
    $s3Key: String
  ) {
    createMessage(
      content: $content
      conversationId: $conversationId
      id: $id
      s3Key: $s3Key
    ) {
      id
      content
      sender
    }
  }
`;

次に動いたときのMutationはコレです。

const createMessage = /* GraphQL */ `
  mutation createMessage(
    $id: ID!
    $content: String
    $conversationId: ID!
    $s3Key: String
  ) {
    createMessage(
      content: $content
      conversationId: $conversationId
      id: $id
      s3Key: $s3Key
    ) {
      id
      conversationId     ←ここ
      content
      sender
    }
  }
`;

subscriptionの引数に定義したconversationIdを戻り値に指定したら動きました。

どうやら、mutationの引数ではなく、戻り値を見て発火しているみたいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

S3にあるテキストファイルをサクッと編集するには

S3にあるテキストファイルを編集したいとき、都度ダウンロードして編集してアップロードするのは手間だし、ローカルにコピーがあるとローカルとS3上とでどっちが最新だったかわからなくなるときがあるし、S3を無理やりマウントする方法もありそうだけどそこまでしたくない場合です。

以下のワンライナーでできます。これでviが立ち上がります。

$ aws s3 cp s3://S3_BUCKET/S3_KEY - | vipe | aws s3 cp - S3_BUCKET/S3_KEY

vipeというコマンドを使っています。S3とのファイルやりとりはawscliを使っています。

S3のパスを2回書くのがダサい場合は、次のようにもできます。

$ S3_PATH=s3://S3_BUCKET/S3_KEY bash -c "aws s3 cp \$S3_PATH - | vipe | aws s3 cp - \$S3_PATH"

vipeコマンドはパイプの中にエディタを入れて、パイプを流れるデータをその場でエディタで編集できるものです。標準入力からデータをすべて読み込んだらそのデータを編集するエディタを起動し、エディタが終了したら編集結果を標準出力に流します。エディタはvimなどの環境変数 EDITOR で定義されたものが使用されるようです。

以下のように使用すると、command1が標準出力を出し切ったらエディタが立ち上がり、command1の出力内容を編集できる画面になり、エディタを終了すると編集結果がcommand2の標準入力として取り込まれます。

$ command1 | vipe | command2

vipeコマンドはmoreutilsというパッケージでインストールできます。

$ sudo apt install moreutils

CentOSでもたぶんmoreutilsという名前でインストールできるんじゃないかと思います。

既存のファイルを編集するつもりでS3のパスを間違えた場合に、間違えたパスに新規ファイルを生成してしまうことに注意です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS CLI v2

AWS CLI v2

$ aws logs tail --follow LOG-GROUP-NAME

ロググループを指定して、ログをリアルタイムでtailすることができるのっていいよね。

AWS CLI v2 install

とりあえずpipでinstall

$ pip install -e git://github.com/aws/aws-cli.git@v2#egg=awscli
pyenv: pip: command not found

えっ。そんなわけない。。

pyenvを確認

$ pyenv versions
  system
* 3.6.1 (set by ~~~~~)
  (省略)

うーん。とりあえず早く試したいので、別のバージョンならpip使えるので、バージョン切り替えて、とりあえずすすむ。

$ pyenv global 3.7.6
$ pip install -e git://github.com/aws/aws-cli.git@v2#egg=awscli
(省略)
ERROR: No matching distribution found for botocore==2.0.0dev5 (from awscli)

なんかまたエラー出てきた。
依存ライブラリのbotocoreがうんぬん。

awscliより先にbotocoreを入れてみる。

$ pip install https://github.com/boto/botocore/archive/v2.tar.gz
(省略)
Successfully installed botocore-2.0.0.dev5

よし、成功。

$ pip install https://github.com/boto/botocore/archive/v2.tar.gz
(省略)
Successfully installed awscli cffi-1.14.0 cryptography-2.8 prompt-toolkit-2.0.10 pycparser-2.19 ruamel.yaml-0.15.100 wcwidth-0.1.8

よし。成功。

確認。

$ aws --version
aws-cli/2.0.1 Python/3.7.6 Darwin/19.3.0 botocore/2.0.0dev5

おけおけ。

$ aws logs tail --follow LOG-GROUP-NAME

これで見れた!!

追記

python 3.6.1で pyenv: pip: command not foundって出てきたのが相当気持ち悪い。

結論

$ cd .anyenv/envs/pyenv/versions
$ rm -rf 3.6.1

一回消して

$ pyenv install 3.6.1

入れ直したら、大丈夫だった。なんか気持ち悪いけど、まぁおk。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

aws-sdkを使ってs3にあるjsonデータを取得する方法

aws-sdkを使ってs3にあるjsonデータを取得する方法をまとめました。
s3のjsonバケットのtest.jsonのデータ「{}」を取得します。

前提条件

  • npmがインストールされていること
  • aws側の認証情報設定を行っていること

インストール

$ npm i --save aws-sdk

使い方

ファイルの作成

touchコマンドでtest.jsファイルを作成

$ touch test.js

設定

test.js
認証情報とapiバージョン、リージョンを設定します。
s3のgetObjectメソッドでファイルデータを取得します。
aws-sdkでは処理をプロミス化するのに.promise()メソッドが使えます。

const AWS = require('aws-sdk')

const option = {
  credentials: new AWS.Credentials(
    'xxxxxxxxxxxxxxx', // AccessKeyIdが入ります
    'xxxxxxxxxxxxxxx' // SecretAccessKeyが入ります
  ),
  apiVersions: {
    s3: '2006-03-01'
  },
  region: 'ap-northeast-1'
}

AWS.config.update(option)

const s3 = new AWS.S3()

const param = {
  Bucket: 'json',
  Key: 'test.json'
};

(async function () {
  await s3.getObject(param).promise()
    .then(res => console.log(JSON.parse(res.Body.toString())))
    .catch(err => console.log(err))
  console.log('jsonを取得しました。')
}())

実行

nodeコマンドでtest.jsを実行する

node test

出力結果

{}
jsonを取得しました。

参考文献

この記事は以下の情報を参考にして執筆しました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CloudFormationのスタックを削除しようとしたらバケットの削除で「The following resource(s) failed to delete:」となりスタック削除が失敗する

事象

AWSコンソールからCloudFormationのスタックを削除しようとしたら、バケットの削除で「The following resource(s) failed to delete:」となりスタック削除が失敗する。
image.png

解決

再度削除を試みると以下のようなダイアログが表示された。[スタックの削除]をクリック。
image.png

すると、次は以下のようなエラーとなった。バケットが空ではないと言っている。

  • The bucket you tried to delete is not empty (Service: Amazon S3; Status Code: 409; Error Code: BucketNotEmpty; Request ID: BDABC5D46C982FDA; S3 Extended Request ID: lR2udDv6irz9E7qJ7iHS0qCNuQehUmn2r9Qt6ybdRAHXXBNjUS1MA62Jr0L4KsVcQAc5CxTWVm4=)

image.png

該当バケット内のオブジェクトをすべて削除して空にし、再度スタック削除を試みると、正常に削除することができた。
image.png

以上

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Lambda入門#3 API Gatewayとの連携

さぁ、今日もLambdaの勉強をしますかー!

参考URL

クラスメソッドさんの以下のURLを見て、学習しました。
https://dev.classmethod.jp/cloud/aws/version-management-with-api-gateway-and-lambda/

Lambdaのバージョン管理/エイリアス設定

上記のURLに沿って、関数を作っていきます。
もう、この辺りはもう前回までの操作で慣れた感じですね。

image.png

指定した文字を出力するだけの関数を作成します。

テストコード
import json

def lambda_handler(event, context):
    return "version1"

image.png

記事にも記載されている通り、関数は作成した段階では、バージョンは作成されていない状態になります。

image.png

バージョンの作成は以下のように[アクション]から[新しいバージョンを発行]を選択します。
作成したバージョンの内容は変更できない。

image.png

image.png

バージョンが作成されたことを以下のように確認できます。

image.png

特定のバージョンに対して、エイリアスを設定することができる。

image.png

エイリアスを設定することでバージョンに対する意味を定義することができる。

image.png

プルダウンメニューも[エイリアス:dev]で表示されるようになったことが確認できます。

image.png

先ほど作成したバージョン1をproductionとして、エイリアスを設定してみます。

image.png

バージョン1は変更できないし、本番設定という位置づけですね。
image.png

今日は疲れちゃったので、ここまで。
大したことはできていないですが、また明日も続きやります!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS educateのクレジットで新型コロナウイルスの感染者マップを作った(個人開発)

完成物

新型コロナウイルス感染マップ

Screen Shot 2020-02-26 at 23.09.43.png

使用した技術

  • フロンエンド
    • React
    • Typescript
    • Nginx
  • バックエンド
    • Golang (Gin)
    • PostgreSQL
  • インフラ
    • AWS (EC2, S3, Route53)
    • Docker (Compose)
  • API
    • Twitter

インフラコスト

学生であればAWS educateに登録すれば$40のクレジットがもらえます。無料利用期間であれば、EC2のt2microインスタンスであれば約一ヶ月間は無料で起動できます。またRDSに関しても同様に一ヶ月無料で利用可能です。今回、課金したのはRoute53で購入したドメイン名($13/year)とhttps化のためのALBの利用のみです(nginx側でLet's Encryptでやってもいいと思います)。

↓ AWS Account(赤枠)ってところからいけます。
Screen Shot 2020-02-26 at 23.36.14.png

関係ないですけど、Github Student Packも学生なら無料でたくさんのサービスが使えてすごいです!

デプロイ

デプロイはECSを試したんですが、うまくいかなかったので、全然スマートではないですが、EC2にDockerいれて、Git pullして、docker-compose upで終わらせました。

Dockerfileはフロント、バックエンドそれぞれこんな感じです。

開発環境

バンクエンド (Golang)

#build stage
FROM golang:latest
WORKDIR /go/src/app
COPY . .
RUN go get -d -v ./...

EXPOSE 8080

本番環境

フロント (React + Typescript -> Nginx) 

FROM node:12 as builder

WORKDIR /coronamap_japan_front
ADD . .
ENV NODE_ENV=production
RUN yarn install
RUN yarn build

FROM nginx:1.16.0-alpine
COPY --from=builder /coronamap_japan_front/build /usr/share/nginx/html
RUN rm /etc/nginx/conf.d/default.conf
ADD  nginx.conf /etc/nginx/conf.d
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]  
  • node-prune(使ってない.js, .tsのモジュールを消してくれるやつ)使う予定でしたが,yarn buildしたときにTypescriptのエラーが出てしまい断念しました。。。

バンクエンド (Golang)

#build stage
FROM golang:alpine AS builder
WORKDIR /go/src/app
COPY . .
RUN apk add --no-cache git
RUN go get -d -v ./...
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o /main .

#final stage
FROM alpine:latest
RUN apk --no-cache add ca-certificates
COPY --from=builder /main .
RUN chmod +x ./main
LABEL Name=coronamap_japan Version=0.0.1
ENTRYPOINT [ "./main" ]
EXPOSE 8080

サーバー落ちないように頑張ります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS educateのクレジットで新型コロナウイルスの感染者マップを作った

完成物

新型コロナウイルス感染マップ

Screen Shot 2020-02-26 at 23.09.43.png

使用した技術

  • フロンエンド
    • React
    • Typescript
    • Nginx
  • バックエンド
    • Golang (Gin)
    • PostgreSQL
  • インフラ
    • AWS (EC2, S3, Route53)
    • Docker (Compose)
  • API
    • Twitter

インフラコスト

学生であればAWS educateに登録すれば$40のクレジットがもらえます。無料利用期間であれば、EC2のt2microインスタンスであれば約一ヶ月間は無料で起動できます。またRDSに関しても同様に一ヶ月無料で利用可能です。今回、課金したのはRoute53で購入したドメイン名($13/year)とhttps化のためのALBの利用のみです(nginx側でLet's Encryptでやってもいいと思います)。

↓ AWS Account(赤枠)ってところからいけます。
Screen Shot 2020-02-26 at 23.36.14.png

関係ないですけど、Github Student Packも学生なら無料でたくさんのサービスが使えてすごいです!

デプロイ

デプロイはECSを試したんですが、うまくいかなかったので、全然スマートではないですが、EC2にDockerいれて、Git pullして、docker-compose upで終わらせました。

Dockerfileはフロント、バックエンドそれぞれこんな感じです。

開発環境

バンクエンド (Golang)

#build stage
FROM golang:latest
WORKDIR /go/src/app
COPY . .
RUN go get -d -v ./...

EXPOSE 8080

本番環境

フロント (React + Typescript -> Nginx) 

FROM node:12 as builder

WORKDIR /coronamap_japan_front
ADD . .
ENV NODE_ENV=production
RUN yarn install
RUN yarn build

FROM nginx:1.16.0-alpine
COPY --from=builder /coronamap_japan_front/build /usr/share/nginx/html
RUN rm /etc/nginx/conf.d/default.conf
ADD  nginx.conf /etc/nginx/conf.d
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]  
  • node-prune(使ってない.js, .tsのモジュールを消してくれるやつ)使う予定でしたが,yarn buildしたときにTypescriptのエラーが出てしまい断念しました。。。

バンクエンド (Golang)

#build stage
FROM golang:alpine AS builder
WORKDIR /go/src/app
COPY . .
RUN apk add --no-cache git
RUN go get -d -v ./...
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o /main .

#final stage
FROM alpine:latest
RUN apk --no-cache add ca-certificates
COPY --from=builder /main .
RUN chmod +x ./main
LABEL Name=coronamap_japan Version=0.0.1
ENTRYPOINT [ "./main" ]
EXPOSE 8080

サーバー落ちないように頑張ります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む