- 投稿日:2020-02-27T23:37:06+09:00
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
- 投稿日:2020-02-27T21:57:45+09:00
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 の効果を感じることは無さそうな。
- 投稿日:2020-02-27T21:22:41+09:00
CloudFormationのテンプレートを分割して作成してみた。
はじめに
AWSでCloudFormationのサービスを利用すると、リソース(EC2やRDS等)をテンプレートから自動構築することができるようになり、同じインフラ構成をすぐに再現することができます。
AWS公式オンラインセミナーのスライド67枚目にあるように、テンプレートは分割して運用することがベストプラクティスのようです。今回、以下の3つのテンプレートに分割して、次の構成図をyamlで作成してみました。
構成図
Network Layer
VPC、Subnet、InternetGateway、RouteTable、VPCEndpointを作成します。
構成図でいうとここまで進みます。
VPC
DNS系については、今回外部からは検索されても問題ないので
true
にしています。あと、ハードウェア専用インスタンスは使用しないのでテナンシーはdefault
にしています。Network_Layer.ymlAWSTemplateFormatVersion: 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: SampleVPCSubnet
PublicとPrivateそれぞれ2つずつ作成します。PublicSubnetの
MapPublicIpOnLaunch
をtrueに設定することでEC2のパブリックIPアドレスの自動割り当てを設定します。Network_Layer.ymlPublicSubnet1a: 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: PrivateSubnet1cInternetGateway
作成したVPCとInternetGatewayをAttachmentで関連付けしておきます。
Network_Layer.ymlInternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: InternetGateway # InternetGatewayとVPCの接続 InternetGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: InternetGatewayId: !Ref InternetGateway VpcId: !Ref SampleVPCRouteTable
InternetGateway接続用(public)とVPCEndpoint接続用(Private)のRouteTableを作成します。
Network_Layer.ymlPublicRouteTable: 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 InternetGatewayVPCEndpoint
後で作成するS3はVPC外にあります。そのため、VPCEndpointを経由してPrivateRouteTableに設置するRDSと接続できるように設定します。
Network_Layer.ymlVPCEndpoint: Type: AWS::EC2::VPCEndpoint Properties: RouteTableIds: - !Ref PrivateRouteTable ServiceName: com.amazonaws.ap-northeast-1.s3 VpcEndpointType: Gateway VpcId: !Ref SampleVPCOutputs
今回、テンプレートを3つに分割しますので、Security_LayerやApplication_LayerへリソースIDを渡す必要があるものをOutputsで作成します。
Network_Layer.ymlOutputs: 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-PrivateSubnet1cSecurity Layer
セキュリティグループ、IAMユーザ、IAMポリシー、の担当分野になりますが、今回セキュリティグループのみ作成します。送信元をALBに設定するため、
SourceSecurityGroupId
を設定してEC2とALBのそれぞれのセキュリティグループを関連付けておきます。SecurityGroup
セキュリティグループはEC2、RDS、ALB用に3つ作成します。同じテンプレート内でリソースの値を参照する際は、組み込み関数
Ref
を使用しますが、別テンプレートでエクスポートされた値を参照する場合は組み込み関数ImportValue
を使用します。構成図でいうとここまで進みます。
Security_Layer.ymlAWSTemplateFormatVersion: 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-SampleVPCOutputs
先程同様、Outputsを作成します。
Security_Layer.ymlOutputs: SecurityGroupEC2: Value: !Ref SecurityGroupEC2 Export: Name: SecurityLayer-SecurityGroupEC2 SecurityGroupRDS: Value: !Ref SecurityGroupRDS Export: Name: SecurityLayer-SecurityGroupRDS SecurityGroupALB: Value: !Ref SecurityGroupALB Export: Name: SecurityLayer-SecurityGroupALBApplication Layer
最後に、EC2、RDS、ALB、S3を作成します。
Parameters
Parametersを利用して、EC2のインスタンスタイプ等をスタック作成時に設定できるようにします。
Applicaiton_Layer.ymlAWSTemplateFormatVersion: 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: StringEC2
ALBを利用したロードバランシングの設定にしますので、EC2を2つ作成します。
Applicaiton_Layer.ymlSampleEC21a: 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-testRDS
今回RDSはマスターとスタンバイに分けるMulti-AZ構成にして、AZ-1aとAZ-1cに設置するようにします。
Applicaiton_Layer.ymlSampleRDS: 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-PrivateSubnet1cALB
Schemeは今回インターネット向けのALBですのでinternet-facingに設定します。
Applicaiton_Layer.ymlSampleALB: 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: HTTPS3
PublicAccessBlockConfiguration
の設定で全てtrueにするとパブリックアクセスが全てブロックされます。Applicaiton_Layer.ymlSampleS3Bucket: 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も機能してくれています。
3つのスタック全てが
CREATE_COMPLETE
になりましたので、これで構成図で示すリソースが全て作成されました。
作成時に対応したエラー&その対処
何分初心者ですので、このコードに至るまで数々のエラーと格闘いたしました。今回のテンプレート作成時に生じたエラーを備忘録として残します。使用できる文字や配置に細かく指定があるためそのエラーが多かった印象ですが勉強になりました。
・ テンプレートの検証エラー:[/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/
- 投稿日:2020-02-27T17:50:23+09:00
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を指定して起動ができる。終わり
- 投稿日:2020-02-27T16:50:32+09:00
AWSにKubernetesクラスタをTerraformで構築する(デジャヴ)
AWS上にマスターnodeをマルチゾーン化したKubernetesクラスタを構築する
マスター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.tfoutput "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がゾーンで分かれている。
LB(NLB)にマスターnodeが3つぶら下がっているのがわかる。
Kubernetesの設定
これでインフラが構築できたので、ここからKubernetes環境を設定していく。基本的にはこのページのMaster nodes:以下を実行すれば良い。
あとすべてのnodeであらかじめ、
swapoff -a export KUBECONFIG=/etc/kubernetes/admin.confしてある。というかマシンイメージの.bashrcに書いてある。
1つのマスターnodeへ入って
/etc/kubernetes/kubeadm/kubeadm-config.yamlを次の通り記述。kubeadm-config.yamlapiVersion: 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でも出来ると思うがマルチゾーンの考え方が異なるので、その辺りのコードが違ってくるであろう。
- 投稿日:2020-02-27T15:22:14+09:00
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生活を。
- 投稿日:2020-02-27T14:59:00+09:00
【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' } ])
- 投稿日:2020-02-27T14:24:48+09:00
【助けて】既存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は問題なく使えているように見えますが、気持ち悪い・・・
原因や解決策をご存知の方がいたらコメントにて教えてください・・・
- 投稿日:2020-02-27T14:06:36+09:00
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のみ選択すれば問題ありません。
作成されたトークンは控えておきましょう(再表示できません)。
CodeBuildプロジェクトの作成
マネジメントコンソールから、ビルドプロジェクトを作成します。
※なお、設定値に言及がない場合は、デフォルト値を採用しています。プロジェクトの設定セクションは任意に入力してください。
送信元セクションでは、ソースプロバイダにGitHub Enterpriseを選択し、先ほど取得したPersonal access tokenを入力します。
トークンの保存後、リポジトリのURLを入力します。
ウェブフックイベントセクションでは、再構築にチェックを入れ、イベントタイプにはプッシュを選択します。
環境セクションは下図の通り入力します。
イメージ内でDockerを起動するため、特権付与にチェックを入れます。
ロール名は任意の名称を入力してください。
環境セクションの追加設定で、下図の環境変数を設定します。
この環境変数は、後続に記載するbuildspec.yamlで利用します。
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.yamlversion: 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を入力します。以上で手順は終了です。
GHEリポジトリに変更をpushすることで自動的にBuild&Deployが開始されるはずです。
- 投稿日:2020-02-27T12:40:22+09:00
RDS 拡張モニタリングの有効化
内容
RDSの拡張モニタリングを有効化
対象
無料枠RDS(MySQL)
拡張する前
拡張モニタリングを有効する前は何が監視されていて何を見ることができるかを確認します。
・[RDS]⇒[モニタリング]タブ
CPU使用率,DB接続,空きストレージ容量,書き込みIOPS,読み取りIOPS
キューの深さ,バイナリログのディスク使用状況,書き込みスループット,読み込みスループット
スワップの使用,書き込みレイテンシー,読み込みレイテンシー,ネットワーク受信スループット
ネットワーク送信スループット,CPUクレジット使用状況,CPUクレジット残高
・[CloudWatch]⇒[メトリクス]⇒[RDS]
CPUUtilization,BurstBalance,ReadIOPS,DiskQueueDepth,WriteIOPS,ReadLatency
,ReadThroughput,WriteLatency,WriteThroughput,VMWriteIOPS,VMReadIOPS,NetworkReceiveThroughput
,NetworkTransmitThroughput,SwapUsage,BinLogDiskUsage,DatabaseConnections,FreeStorageSpace
FreeableMemory,CPUCreditBalance,CPUCreditUsage,CPUSurplusCreditBalance,CPUSurplusCreditsCharged
そもそもで
RDSで拡張モニタリングを有効にすると何を確認することができるのか。
拡張モニタリングAmazon RDS には、DB インスタンスが実行されているオペレーティングシステム (OS) のリアルタイムのメトリクスが用意されています。
...取り敢えず有効にしていきます。
手順
拡張モニタリングを有効にするためにはIAMロールで[AmazonRDSEnhancedMonitoringRole]を作成
拡張モニタリング有効化
[AWSコンソール]⇒[サービス]⇒[データベース]⇒[RDS]を選択してRDSダッシュボードへ移動します。
DB インスタンスの変更画面のモニタリングにて、[拡張モニタリングを有効にする]を選択します。
ここで、IAMポリシーの"AmazonRDSEnhancedMonitoringRole"がアタッチされているIAMロールを作成していないと
1枚目のようにモニタリングロールでデフォルトが選択されてその下にRDSが...と薄く表示されます。
IAMロールが作成されていると以下のように選択することができます。
必要であれば先にIAMロールを作成しておきます。
変更内容を確認後、変更のスケジュールを[すぐに適用]を選択して[DBインスタンスの変更]を押下します。
変更後、対象RDSのステータスが[configuring-enhanced-monitoring]⇒[利用可能]となるのを待ちます。
ステータスが利用可能になったのを確認します。
[対象RDS]⇒[モニタリングタブ]⇒[モニタリング▼]⇒[拡張モニタリング]を選択します。
拡張モニタリングが有効となっており、以下を確認することができます。
未使用のメモリ,アクティブなメモリ,CPUユーザー,CPU合計
使用中のファイルシステム,ロード平均1分
以上で拡張モニタリングを有効化することができます。
詳細は公式サイトをご確認ください。
拡張モニタリング
- 投稿日:2020-02-27T11:17:39+09:00
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の引数ではなく、戻り値を見て発火しているみたいです。
- 投稿日:2020-02-27T09:07:42+09:00
S3にあるテキストファイルをサクッと編集するには
S3にあるテキストファイルを編集したいとき、都度ダウンロードして編集してアップロードするのは手間だし、ローカルにコピーがあるとローカルとS3上とでどっちが最新だったかわからなくなるときがあるし、S3を無理やりマウントする方法もありそうだけどそこまでしたくない場合です。
以下のワンライナーでできます。これでviが立ち上がります。
$ aws s3 cp s3://S3_BUCKET/S3_KEY - | vipe | aws s3 cp - S3_BUCKET/S3_KEYvipeというコマンドを使っています。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 | command2vipeコマンドは
moreutils
というパッケージでインストールできます。$ sudo apt install moreutilsCentOSでもたぶん
moreutils
という名前でインストールできるんじゃないかと思います。既存のファイルを編集するつもりでS3のパスを間違えた場合に、間違えたパスに新規ファイルを生成してしまうことに注意です。
- 投稿日:2020-02-27T04:49:48+09:00
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。
- 投稿日:2020-02-27T02:56:06+09:00
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を取得しました。
参考文献
この記事は以下の情報を参考にして執筆しました。
- 投稿日:2020-02-27T00:48:38+09:00
CloudFormationのスタックを削除しようとしたらバケットの削除で「The following resource(s) failed to delete:」となりスタック削除が失敗する
事象
AWSコンソールからCloudFormationのスタックを削除しようとしたら、バケットの削除で「The following resource(s) failed to delete:」となりスタック削除が失敗する。
解決
再度削除を試みると以下のようなダイアログが表示された。[スタックの削除]をクリック。
すると、次は以下のようなエラーとなった。バケットが空ではないと言っている。
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=)
該当バケット内のオブジェクトをすべて削除して空にし、再度スタック削除を試みると、正常に削除することができた。
以上
- 投稿日:2020-02-27T00:16:28+09:00
Lambda入門#3 API Gatewayとの連携
さぁ、今日もLambdaの勉強をしますかー!
参考URL
クラスメソッドさんの以下のURLを見て、学習しました。
https://dev.classmethod.jp/cloud/aws/version-management-with-api-gateway-and-lambda/Lambdaのバージョン管理/エイリアス設定
上記のURLに沿って、関数を作っていきます。
もう、この辺りはもう前回までの操作で慣れた感じですね。指定した文字を出力するだけの関数を作成します。
テストコードimport json def lambda_handler(event, context): return "version1"記事にも記載されている通り、関数は作成した段階では、バージョンは作成されていない状態になります。
バージョンの作成は以下のように[アクション]から[新しいバージョンを発行]を選択します。
作成したバージョンの内容は変更できない。バージョンが作成されたことを以下のように確認できます。
特定のバージョンに対して、エイリアスを設定することができる。
エイリアスを設定することでバージョンに対する意味を定義することができる。
プルダウンメニューも[エイリアス:dev]で表示されるようになったことが確認できます。
先ほど作成したバージョン1をproductionとして、エイリアスを設定してみます。
バージョン1は変更できないし、本番設定という位置づけですね。
今日は疲れちゃったので、ここまで。
大したことはできていないですが、また明日も続きやります!
- 投稿日:2020-02-27T00:05:17+09:00
AWS educateのクレジットで新型コロナウイルスの感染者マップを作った(個人開発)
完成物
使用した技術
- フロンエンド
- React
- Typescript
- Nginx
- バックエンド
- Golang (Gin)
- PostgreSQL
- インフラ
- AWS (EC2, S3, Route53)
- Docker (Compose)
- API
インフラコスト
学生であればAWS educateに登録すれば$40のクレジットがもらえます。無料利用期間であれば、EC2のt2microインスタンスであれば約一ヶ月間は無料で起動できます。またRDSに関しても同様に一ヶ月無料で利用可能です。今回、課金したのはRoute53で購入したドメイン名($13/year)とhttps化のためのALBの利用のみです(nginx側でLet's Encryptでやってもいいと思います)。
関係ないですけど、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サーバー落ちないように頑張ります。
- 投稿日:2020-02-27T00:05:17+09:00
AWS educateのクレジットで新型コロナウイルスの感染者マップを作った
完成物
使用した技術
- フロンエンド
- React
- Typescript
- Nginx
- バックエンド
- Golang (Gin)
- PostgreSQL
- インフラ
- AWS (EC2, S3, Route53)
- Docker (Compose)
- API
インフラコスト
学生であればAWS educateに登録すれば$40のクレジットがもらえます。無料利用期間であれば、EC2のt2microインスタンスであれば約一ヶ月間は無料で起動できます。またRDSに関しても同様に一ヶ月無料で利用可能です。今回、課金したのはRoute53で購入したドメイン名($13/year)とhttps化のためのALBの利用のみです(nginx側でLet's Encryptでやってもいいと思います)。
関係ないですけど、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サーバー落ちないように頑張ります。