- 投稿日:2020-08-09T21:38:32+09:00
ECSなコンテナにSSM Parameter Storeの値を渡して保持させる
はじめに
ECSの環境変数機能のちょっとニッチな使い方。
コンテナに固め込んで起動することから、動的に変更することができなくなるので注意。環境情報はコンテナから切り離すというプラクティスから離れるアンチパターンであることを意識して、コンテナ化するプロダクトがクラウドにリフトするだけのケース等やむを得ない場合だけ利用することを推奨。SSM Parameter Storeの参照方法
コンテナのアプリケーションからSDKを使って参照するという方法もあるが、もっとお手軽に実装するのが、ECSの(正確にはタスク定義の)環境変数を使うのが良い。
以前の記事で書いた「コンテナの編集」⇒「環境変数」から設定可能だ。プルダウンで「ValueFrom」を選択して、Parameter StoreのARNを指定する。
TerraformでIaCで記述するのであれば、
aws_ssm_parameter
リソースをresource "aws_ssm_parameter" "test" { name = "/${var.environment}/teststring" description = "Test for SSM Parameter Store" type = "SecureString" value = "this-is-test-string" tags = { environment = var.environment } }な感じで定義し、これを
aws_ecs_task_definition
リソースの中でresource "aws_ecs_task_definition" "ecsfargate" { : (中略) : container_definitions = <<EOF [ { "name" : "${local.container_name}", "image": "${data.aws_ecr_repository.my_image.repository_url}:latest", "cpu": 0, "memoryReservation": 256, "secrets": [ { "name": "TESTSTRING", "valueFrom": "${aws_ssm_parameter.test.arn}" } ], : (以下略)として参照する。
あとは、アプリケーションの中で環境変数で参照するなり、Dockerの起動コマンドの中で参照するなりしてあげれば期待通りのことができるようになる。
ただし、上記の通り、
aws_ssm_parameter
のtype
プロパティがSecureString
であるにもかかわらず、.tfファイル中の文字列は平文になってしまっている。チームで作業する場合なんかは、非常によろしくないのではなかろうか……。
ちなみに、Terraformの公式ドキュメントでは、「Terraform Cloud使うかリモートステートでちゃんと暗号化してね!」と書いてある。terraform.stateファイルはともかくとして、ローカル情報を暗号化したまま渡すことはできないのだろうか……。
- 投稿日:2020-08-09T16:34:44+09:00
AWS EC2 Linuxにオプションモジュールをインストール
症状
WordPressの管理者画面のサイトヘルスに「1件の致命的な問題」が出てる><
内容は、以下の通り。1つ以上の必須モジュールが存在しません
PHP モジュールはサイトの稼働に必要なほとんどのタスクをサーバー上で実行します。変更はサーバー管理者が実施する必要があります。
- オプションのモジュール dom がインストールされていないか、無効化されています。
- オプションのモジュール mbstring がインストールされていないか、無効化されています。
- オプションのモジュール imagick がインストールされていないか、無効化されています。
- 必須モジュール gd がインストールされていないか、無効化されています。環境
- AWS Amazon EC2 Linux 2
- php 7.4.7
- WordPress
対処法
上で「インストールされていないか、無効化されています」と言われているものをインストールして、httpd.serviceを再起動する。
$ sudo yum install -y php php-dom $ sudo yum install -y php php-mbstring $ sudo yum install -y php php-imagick $ sudo yum install -y php php-gd $ sudo systemctl restart httpd.servicewordpressのダッシュボードに行くと、致命的な問題が消えた。よかったよかった。
- 投稿日:2020-08-09T15:29:47+09:00
テクトロジーによる実践的組織構造学
今回の記事では、ソ連の革命家、医師、哲学者、小説作家であったアレクサンダーボグダノフが提唱したテクトロジーと呼ばれる実践的組織構造学について紹介する。
テクトロジーでは組織が安定、成長、破綻する環境、条件について詳細に解説し、安定した組織を生成する手法について解説している。
テクトロジーの概念を拝借し、創造的な組織創造の手法を紹介したいと思う。テクトロジーにおける組織の定義
テクトロジーでは、組織をオープンクローズ型の成長する有機体システムと定義している。
組織とは以下の要素で構成されている。
ビジョン・・・組織の目指すべき方向性。
経済・・・組織のボディ。巨大であるほど収容できる人の人数が増加する
金融・・・組織を循環する血液。
生産・・・もの、サービスを生産し、組織の経済を巨大化する手段。これらの有機的な要素が相互作用し、成長することで組織という有機体が構成されていると考える。
テクトロジーにおける成長する有機体システムとは
テクトロジーでは、組織をオープンクローズ型の成長する有機体システムと定義している。
テクトロジーにおける組織の定義を中国の陰陽論によって説明することができる。
陰陽論とは、原初は混沌(カオス)の状態であると考え、この混沌の中から光に満ちた明るい澄んだ気、すなわち陽の気が上昇して天となり、重く濁った暗黒の気、すなわち陰の気が下降して地となった。この二気の働きによって万物の事象を理解し、また将来までも予測しようというのが陰陽思想である。
組織が外部からエネルギーを取り入れ、出力するインプット、アウトプットの運動を陰陽論における陽の気と捉えることができる。
逆に組織内部に沈殿し、成長し、ヒエラルキーを形成する秩序生成を担う運動を陰陽論における陰の気と捉えることができる。テクトロジーにおける生産の定義
テクトロジーでは、組織における生産活動は以下の3つに分類されている。
人の生産・・・人に教育を施し、組織活動に従事する生産者を作成する
モノ、サービスの生産・・・外部から取得した資材を用いて、モノ、サービスの生産を行う。
アイデア・・モノ、サービスを生成するための知識、アイディアを作成する。
組織における生産活動を高めることで、組織の経済を成長させることができる。テクトロジーにおける組織が不安定化する条件
テクトロジーにおける組織が不安定化する条件として以下の2点が挙げられる。
・外部からのエネルギー取得の減少・・外部から人、モノ、金の循環が減少することで組織のサイズ、経済を維持することできなくなる。
・ヒエラルキーシステムの固定化・・・ヒエラルキーシステムが巨大化し、組織が硬直化してしまう。
組織不安定化を回避する手法として以下の手段が有効とされている。
生産手段を研究、開発、更新を行い、組織の経済成長のスピードを増加させる。
組織が硬直化の原因になっているヒエラルキーシステムを解体し、適切なサイズに組み替える。まとめ
アレクサンダーボグダノフがテクトロジーに関するアイディアを発表した時期は1920年代である。
独学で組織が破綻する条件、環境を発見し、持続可能な成長のコンセプトを提唱したアレクサンダーボグダノフの先見性は恐るべきものである。
ソ連は軍事、IT、経済においてアメリカと張り合うことができた超大国だった。
ソ連時代に考えられたアイディア、思想などは現代においても見直されるべきものだと思われる。
- 投稿日:2020-08-09T15:18:45+09:00
AWS-SAA試験勉強メモ3
CIDR表記
X.Y.Z.W/24
なら、X.Y.Z.Wと255.255.255.0をそれぞれ2進数にあらわしたものの積を取る☆「/24」の部分が、2進数表記のサブネットマスクで頭からの1の個数
Auto ScalingグループへのEC2インスタンスへのアタッチ可能になる条件
- インスタンスがrunnning
- インスタンス起動時のAMIが存在する
- インスタンスが他のauto scalingグループに属していないこと
- インスタンスがAuto Scalingと同じAZにあること
補足:Auto Scalingグループは複数のリージョンにまたがることは出来ない
CloudTrailログファイル
アカウントのAPIアクティビティログファイルをS3に送信
S3Glacier無料取り出し枠
無料取り出し枠=10GB/月
S3のオブジェクト削除
DELETE API
→単一のオブジェクト削除Multi-Object Delete API
→複数のオブジェクト(1つのHTTPリクエストで最大1000のオブジェクト削除)CloudWatchのメトリクスの保管期間
基本メトリクス、カスタムメトリクス問わず15か月
DynamoDB
- NoSQLDB
- キャパシティユニットでスループットを指定(書き込み&読み込み)
- データ容量制限なし
- スケールアウトが良い鵜
- 高速パフォーマンス、シームレスな拡張性
フロントエンドリスナーにHTTPSまたはSSLを使用する場合
ELBにSSL証明書のインストールが必要
- 投稿日:2020-08-09T15:11:21+09:00
AWS Redshiftでテーブルとそのカラム、データ型の一覧を抽出するメモ
この記事について
Redshift上に格納している複数のテーブルについて、まとめてドキュメント化する必要があり、こういうの↓がCSVで欲しかったのでそのためのクエリをまとめた。
ほぼ参考記事のクエリを改変しただけです(@foursue 様ありがとうございます)がメモまで
table_id schema_name table_name column_number column_name column_datatype 1 user demographic 1 uuid VARCHAR 1 user demographic 2 age INT 1 user demographic 3 gender VARCHAR 1 user demographic 4 country VARCHAR 2 order order_detail 1 order_id BIGINT 2 order order_detail 2 timestamp TIMESTAMP 2 order order_detail 3 uuid VARCHAR 2 order order_detail 4 type VARCAHR 2 order order_detail 5 price NUMERIC 実際の方法
対象のredshiftクラスタにadminでログインして下記を実行しましょう。
dump_table_column_datatype.sqlSELECT table_id, schema_name, table_name, column_number, column_name, column_datatype FROM ( SELECT c.oid::BIGINT AS table_id, n.nspname AS schema_name, c.relname AS table_name, a.attnum AS column_number, QUOTE_IDENT(a.attname) AS column_name, CASE WHEN STRPOS( UPPER(format_type(a.atttypid, a.atttypmod)), 'CHARACTER VARYING' ) > 0 THEN REPLACE( UPPER(format_type(a.atttypid, a.atttypmod)), 'CHARACTER VARYING', 'VARCHAR' ) WHEN STRPOS( UPPER(format_type(a.atttypid, a.atttypmod)), 'CHARACTER' ) > 0 THEN REPLACE( UPPER(format_type(a.atttypid, a.atttypmod)), 'CHARACTER', 'CHAR' ) ELSE UPPER(format_type(a.atttypid, a.atttypmod)) END AS column_datatype FROM pg_namespace AS n INNER JOIN pg_class AS c ON n.oid = c.relnamespace INNER JOIN pg_attribute AS a ON c.oid = a.attrelid LEFT OUTER JOIN pg_attrdef AS adef ON a.attrelid = adef.adrelid AND a.attnum = adef.adnum WHERE c.relkind = 'r' AND a.attnum > 0 ORDER BY a.attnum ) ORDER BY schema_name, table_name, column_number参考記事
- 投稿日:2020-08-09T11:30:43+09:00
クロスアカウント・クロスリージョンなCodePipelineを実行する
はじめに
以前の記事で、クロスアカウントなパイプラインを実行するコツをまとめてみた。
今回は、さらにこの2つのイベント連携部分をクロスリージョンにするにはどうしたら良いかを考えた。
最初に結論を書いておくと、CodePipelineのクロスリージョンアクションを使うのが良い、ということだ。
【AWS公式】CodePipeline でクロスリージョンアクションを追加する
検討経緯
以下の記事を参考にして、CodePipelineの完了時にS3にファイルを突っ込んでトリガしたり、サービス側アカウントにSNSトピックを置いて、CodePipelineの完了時にビルドアカウント側からPublishしてリージョン跨ぎのLambdaを起動したりした。
【参考】【Developers.IO】S3 Event Notificationを別アカウントのリージョンの異なるAmazon SNSに送信し、Lambdaを発火させる
多少強引ではあるが、これなら別リージョンのCodePipelineに着火することはできそうだった。
だがしかし、結局はCodePipelineのソースステージがクロスリージョン対応していなくて、別リージョンのCodeCommitを参照できないので、どうにもならなかった。S3でソース連携とか、あまりに泥臭すぎる。
素直にCodePipelineとソースステージは同一リージョンに置いて、ビルド・デプロイステージをクロスリージョンアクションを使うのが良いだろう。
クロスリージョンアクションのためのIaC(Terraform)
マネージメントコンソールでの実施方法はAWS公式にもあるので、ここではTerraformの書き方を残しておく。
と言っても、そんなに難しいことではない。
以下のように、2つのリージョンのアーティファクトストアを用意して、★の箇所にregion
のプロパティを設定すれば良い。このケースでは、以前の記事のビルド側アカウントをap-northeast-1
、サービス側アカウントのクロスリージョン対応をus-east-2
で行っている例だ。S3はグローバルサービスのはずなのに、クロスリージョンで動かす先のリージョンに作っておかなければいけないという制約は謎……。resource "aws_codepipeline" "service_account" { : (中略) : artifact_store { region = "ap-northeast-1" ★ type = "S3" location = aws_s3_bucket.service_artifact1.bucket encryption_key { id = aws_kms_key.cross_account.arn type = "KMS" } } artifact_store { region = "us-east-2" ★ type = "S3" location = aws_s3_bucket.service_artifact2.bucket } : (中略) : stage { name = "Build" action { run_order = 2 name = "Build" category = "Build" owner = "AWS" provider = "CodeBuild" version = "1" input_artifacts = ["SourceArtifact"] output_artifacts = ["BuildArtifact"] region = "us-east-2" ★ configuration = { ProjectName = aws_codebuild_project.service_account.name } }
- 投稿日:2020-08-09T11:08:07+09:00
俺のAWSセキュリティ管理
個人的にAWSのセキュリティ管理のためにつかっているものをザっと並べてみました。
セキュリティ管理に終わりはないので、随時アップデートや新サービスが登場したら利用していこうとおもいます。使用サービス一覧
アカウント管理
・IAM(ユーザー、ロール、グループ、ポリシー)
履歴の記録
・Cloud Trails
・AWS Config
ログ(履歴)の保存
・S3
検知
・Guard Duty
・IAM Access Analyzer
・Security Hub
通知
・SNS
・CloudFormation
請求系
・Cost Explorer
・AWS Budgets
AWS CLI
・AWS Vault
外部アプリ
・spark
・1password
・Authy各詳細
アカウント管理
・IAMはrootユーザーを使わないでIAMユーザーを使用。権限は最小限に。
履歴の保存
・Cloud Trailsですべての証跡ログを記録する。
・AWS Configで特定のリソースの変更履歴を記録する。
ログ(履歴)の保存
・S3にてログの履歴を保存して、ライフサイクルルールで管理。
検知
・Guard Dutyで不審な操作や悪意のある操作を検知。
・IAM Access Analyzerで自アカウント以外からアクセスできるリソースがないかを検知。
・Security Hubで複数のセキュリティサービスを統合して見やすく。
通知
・SNSで異常な操作、変更などをEメールにて知らせる。
・CloudFormationで通知の型を参考。
請求系
・Cost Explorerで月額の利用料金を予想。
・AWS Budgetsで月額の上限を設定。
AWS CLI
・AWS Vaultでアクセスキーをローカル環境で安全に保管。暗号化。
外部アプリ
・sparkでメール管理を見やすく。
・1passwordでパスワード管理、自動入力。
・Authyで仮想MFA、二段階認証。個人的なオススメ
・起きたらMY請求ダッシュボード→Guard Duty→Security Hub→IAM Access Analyzerと必ず目を通す習慣をつけておく。
・AWSのMY請求ダッシュボードはドルを円に変換して、最初の方は必ず毎日頻繁にチェックしておくこと。とにかくここは見慣れておくことが精神的にも大切。
・メールの通知を見逃さないためにもsparkアプリを入れて、AWSの通知専用のメールアドレスを作っておく。そうすることで他のメールと混在しなくて見逃しにくい。
・SNSで飛んでくるメールの説明には日本語で説明を補足しておくと、通知が来た時に見やすく対処しやすい(基本英語)。
・100%の安全は100%ありえないと自覚すること。
・セキュリティ関係が面倒なら、AWSは利用しないほうがいい。必読
・AWSが不正利用され300万円の請求が届いてから免除までの一部始終
・初心者がAWSでミスって不正利用されて$6,000請求、泣きそうになったお話。
・AWS初学者が「うっかり課金」されがちなポイントとその対策まとめ
・AWSで不正利用され80000ドルの請求が来た話
- 投稿日:2020-08-09T10:17:44+09:00
IAMユーザーとIAMロールは似ていることのメモ
なぜIAMユーザーとIAMロールを比べるか
IAMの勉強をしていると、概念が多いことやAWS独自の用語、位置関係と複雑なことが多くいつも混乱しがちです。特にIAMのユーザー、ポリシー、ロールの概念は非常に初心者にとっては難しいと思います。そしていつもポリシーに注目がいきがち。ただ、IAMユーザーとIAMロールが非常に似ているということを理解してからだいぶIAMあたりの概念の理がしやすくなったのでメモとして。
IAMユーザーとIAMロールは似ている
自分なりにIAMユーザーとロールについて表現してみました。
IAMユーザーとは、IAMアイデンティティでありアクセス許可ポリシーをもつAWS IDである。(以下細かい説明)
アクセス許可ポリシー = ポリシーによって付与されるアクセス許可(IAMユーザーよりIAMグループに付与することが推奨)
AWS ID = 「そのユーザーはだれか」IAMロールとは、IAMユーザーと同様にIAMアイデンティティであり特定のアクセス権限(アクセス許可ポリシー)をもつAWS IDであり、 AWSサービスやアプリケーションに対して、AWS操作の権限を与える仕組みである。(以下細かい説明)
AWSサービスやアプリケーションに対して = ロールを使用できるもの・ロールと同じ AWS アカウントの IAM ユーザー
・ロールとは異なる AWS アカウントの IAM ユーザー
・AWS が提供するウェブサービス (Amazon EC2)
・その他→IAMロールの概念仕組みである = IAMロールはIAMユーザーと違って関連付けが任意であるため(だからヘルメットという特定のものでなく色んなものにつけることのできるイメージ)、あらゆるもの(ロールを使用できる色んなもの)に付与できる。
IAMロールはリソースに付与するもののイメージが強く、IAMユーザーの付与したりするイメージが湧きにくかったりします。AssumeRoleとかをやるとユーザーに付与したりするイメージが湧きやすくなると思います。
IAMユーザーとIAMロールの違い
IAMユーザー IAMロール 関連付け 一意 任意 長期認証情報 passwordやアクセスーなど 一時的なセキュリティ認証情報 参照
・IAMロールの概念(公式)
・IAMロールの細かいところ(Developers.IO)
・IAMユーザーの概念(公式)
・IMAロールとポリシーの違い(Qiita)
IAM難しいので誤解を生むような理解であれば、是非ご指摘してくださると嬉しいです!
- 投稿日:2020-08-09T03:24:14+09:00
AWS CopilotでSpringBootアプリケーション(Kotlin)をECSにデプロイする
概要
AWS Copilotを使い、AWS ECS x Fargateへアプリケーションをデプロイしてみます。
AWS Copilotとは?
- 「Copilot」を和訳すると「副操縦士」
- AWSが提供するECS CLIの後継
- 従来のECS CLIより簡単にFargateへのコンテナデプロイを実現できる
- 詳しくはAWSのブログを参照
- AWS Copilotのソースコードはgithubに公開されている
簡単に言うと、「ちゃんと動くDockerfile」があれば、
$ copilot init
とか$ copilot deploy
といった簡単なコマンドだけでECSにアプリケーションをデプロイできるよ!というツールです。モチベーション
- 従来であれば、こうしたECS環境を使った公開アプリケーションを開発しようとしたとき、ある程度のネットワーク構成なども同時に構築する必要があり、手間がかかるもの (ポート設定、ロードバランサー、サービスディスカバリ etc...)
- Copilotがイケてると思ったのはそのあたりの低レイヤの構築をいい感じにやってくれる、という点 (その恩恵としてアプリケーションエンジニアはより開発に集中できる)
- PaaSに近い感覚で、さっと小さなコンテナベースのアプリケーションを公開するのに使えそう、と思い基本的な使い方を学習しておこうと
環境概要
- Mac OS Catalina
- Dockerインストール済
- AWS CLI v2インストール済
なので、ここではCopilotのインストールから実行していきます。
AWS Copilotのインストール
インストール方法はAWS Copilotのドキュメントに記載されています。
https://github.com/aws/copilot-cli/wiki$ brew install aws/tap/copilot-cliサンプルアプリケーションの作成
Dockerfileで構築可能なアプリケーションであればなんでも良いのですが、
ここではタイトルの通り、Kotlinで単純なSpringBootアプリケーションを作成し、それをECS上に構築してみます。利用したJavaとGradleのバージョンは以下。
(ちなみに、jenvとsdkmanで入れたもの)$ java --version openjdk 13.0.1 2019-10-15 OpenJDK Runtime Environment (build 13.0.1+9) OpenJDK 64-Bit Server VM (build 13.0.1+9, mixed mode, sharing) $ gradle -v ------------------------------------------------------------ Gradle 6.5 ------------------------------------------------------------ ...ディレクトリ構造
最終的にこんな感じになります。
$ tree aws-copilot-app-example/ aws-copilot-app-example/ ├── Dockerfile ├── README.md ├── build.gradle.kts ├── copilot │ └── aws-copilot-app-example-service │ └── manifest.yml ├── gradle │ └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle.kts └── src ├── main │ ├── kotlin │ │ └── com │ │ └── example │ │ ├── ExampleApplication.kt │ │ └── ExampleController.kt │ └── resources │ └── application.yml └── test ├── kotlin │ └── com │ └── example │ └── ExampleControllerTest.kt └── resources 15 directories, 14 filesSpringBootプロジェクト作成
Spring Initializrを使ってもいいですが、自分の場合
$ gradle init
で作りました。$ gradle init Select type of project to generate: 1: basic 2: application 3: library 4: Gradle plugin Enter selection (default: basic) [1..4] 2 Select implementation language: 1: C++ 2: Groovy 3: Java 4: Kotlin 5: Swift Enter selection (default: Java) [1..5] 4 Select build script DSL: 1: Groovy 2: Kotlin Enter selection (default: Kotlin) [1..2] 2 Project name (default: foo): aws-copilot-app-example Source package (default: aws.copilot.app.example): com.example BUILD SUCCESSFUL in 33s 2 actionable tasks: 2 executedその後、各種ファイルを作成・修正していきます。
build.gradle.kts
ビルド設定です。
こんな感じ。build.gradle.ktsimport org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { id("org.springframework.boot") version "2.3.2.RELEASE" id("io.spring.dependency-management") version "1.0.8.RELEASE" kotlin("jvm") version "1.3.72" kotlin("plugin.spring") version "1.3.72" } group = "com.example" version = "0.0.1-SNAPSHOT" repositories { mavenCentral() } dependencies { implementation(platform("org.jetbrains.kotlin:kotlin-bom")) implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") // SpringBoot implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.11.2") // Testing testImplementation("org.springframework.boot:spring-boot-starter-test") { exclude(group = "org.junit.vintage", module = "junit-vintage-engine") } testImplementation("io.mockk:mockk:1.10.0") } tasks.withType<Test> { useJUnitPlatform() } tasks.withType<KotlinCompile> { kotlinOptions { freeCompilerArgs = listOf("-Xjsr305=strict") jvmTarget = "1.8" } }ExampleApplication.kt
SpringBootアプリケーションの起動部です。
ExampleApplication.ktpackage com.example import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication @SpringBootApplication class ExampleApplication fun main(args: Array<String>) { runApplication<ExampleApplication>(*args) }ExampleController.kt
Hello AWS Copilot!!!
というメッセージを返すGET
のAPIを作成します。ExampleController.ktpackage com.example import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RestController @RestController class ExampleController { @GetMapping("/") fun get(): ResponseEntity<Result> = ResponseEntity(Result(message = "Hello AWS Copilot!!!"), HttpStatus.OK) data class Result( val message: String ) }ExampleControllerTest.kt
こちらはコントローラのテストコードです。
ExampleControllerTest.ktpackage com.example import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import org.junit.jupiter.api.extension.ExtendWith import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.context.junit.jupiter.SpringExtension @ExtendWith(SpringExtension::class) @SpringBootTest @AutoConfigureMockMvc class ExampleControllerTest { @Autowired private lateinit var mockMvc: MockMvc @Autowired private val mapper = jacksonObjectMapper() @Test fun `response data contains welcome message`() { val expected = ExampleController.Result( message = "Hello AWS Copilot!!!" ) mockMvc.perform(MockMvcRequestBuilders.get("/")) .andExpect(status().isOk) .andExpect(content().json(mapper.writeValueAsString(expected))) } }Dockerfileの作成
上記で作成したSpringBootアプリケーションをコンテナ化するために、以下のようなDockerfileを作成します。
FROM openjdk:jdk-alpine VOLUME /tmp RUN mkdir /aws-copilot-app-example WORKDIR /aws-copilot-app-example ENV JAVA_OPTS="" ENV APP_VERSION=0.0.1-SNAPSHOT COPY ./build/libs/aws-copilot-app-example-$APP_VERSION.jar /aws-copilot-app-example EXPOSE 8080 ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar ./build/libs/aws-copilot-app-example-$APP_VERSION.jar" ]試しにローカルで起動してみます。
# アプリケーションのビルド(jarを生成) $ gradle clean build # Dockerイメージのビルド $ docker build -t aws-copilot-app-example:latest ./ # Dockerイメージを起動 $ docker run --rm -it -p 80:8080 --name aws-copilot-app-example aws-copilot-app-example:latest動作確認
$ curl http://localhost {"message":"Hello AWS Copilot!!!"}成功すると上記のようにメッセージが返ってきます。
AWS Copilotを使ってECSに上記のSpringBootアプリケーションをデプロイ
Dockerfileがあるディレクトリで以下のコマンドを実行します。
$ copilot init
すると、作成したいアプリケーションについて順に聞かれるので、対話式に入力していきます。
ここでは以下のように入力しました。
項目 入力内容 Application name aws-copilot-app-example Service type Load Balanced Web Service Service name aws-copilot-app-example-service Dockerfile ./Dockerfile 動作確認を簡単化するため、公開サービスを想定した
Load Balanced Web Service
として立ち上げていますが、Backend Service
も試してみたところ、Cloud Map上にネームスペースもきちんと作成されていました(サービスディスカバリもバッチリ。しゅごい)その後、以下のようにtest環境にデプロイしてよいか聞かれるので「y」と入力しEnter
Would you like to deploy a test environment? [? for help] (y/N) y諸々回答していくと、出力は以下のようになります。
$ copilot init Note: It's best to run this command in the root of your Git repository. Welcome to the Copilot CLI! We're going to walk you through some questions to help you get set up with an application on ECS. An application is a collection of containerized services that operate together. Application name: aws-copilot-app-example Service name: aws-copilot-app-example-service Dockerfile: ./Dockerfile Ok great, we'll set up a Load Balanced Web Service named aws-copilot-app-example-service in application aws-copilot-app-example listening on port 8080. ✔ Created the infrastructure to manage services under application aws-copilot-app-example. ✔ Manifest file for service aws-copilot-app-example-service already exists at copilot/aws-copilot-app-example-service/manifest.yml, skipping writing it. Your manifest contains configurations like your container size and port (:8080). ✔ Created ECR repositories for service aws-copilot-app-example-service. All right, you're all set for local development. Deploy: Yes ⠹ Proposing infrastructure changes for the test environment.さすがに環境をまるっと一式作るのでけっこう時間がかかる。しばらく待つ。
ちゃんと処理が進んでいるのか気になるようであれば、AWSコンソールよりCloudFormationのイベントなどを参照すると進捗状況を確認できる。✔ Deployed aws-copilot-app-example-service, you can access it at http://aws-c-Publi-xxx-xxx.ap-northeast-1.elb.amazonaws.com.AWSにデプロイしたアプリケーションの動作確認
$ curl http://aws-c-Publi-xxx-xxx.ap-northeast-1.elb.amazonaws.com {"message":"Hello AWS Copilot!!!"}すげぇ、マジでできてしまった(当たり前ですが)
実質、$ copilot init
しか打ってないんだがw (神なの)特に面白いと思ったのは、
Dockerfile
上でEXPOSE 8080
と指定し、コンテナの8080ポートを公開しているのですが、
これを解釈してELBの80ポートからコンテナの8080ポートまでのルートをマッピングしてくれているところです。これは本当に気が利いているw
作成したサービスの削除
放っておくとお金もかかるので、作成したサービスを削除します。
$ copilot app ls aws-copilot-app-example $ copilot app delete aws-copilot-app-exampleAWSのprofileが複数ある場合、「この環境ではどのプロファイルを使って消します?」と聞かれるので、自身の環境に合わせて削除用のprofileを選ぶ。(ここでは
default
を選択)Which named profile should we use to delete test? default
今回作成したサンプルコード
※執筆時点から変更される可能性もあります
https://github.com/otajisan/aws-copilot-app-example
- 投稿日:2020-08-09T03:12:42+09:00
Terraform で AWS VPC の環境づくり[入門]
やりたいこと
terraform の大まかな流れが知りたい。
とりあえず AWS VPC の環境を作成して、確認後廃棄。各種ファイルの用意
VPC 本体
vpc.tf
variable "aws_region" {} provider "aws" { version = "~> 3.1" region = var.aws_region } variable "project_prefix" {} variable "vpc_cidr" {} resource "aws_vpc" "vpc" { cidr_block = var.vpc_cidr instance_tenancy = "default" enable_dns_support = true enable_dns_hostnames = true tags = { Name = "${var.project_prefix}-vpc" } }変数の設定
test.tfvars
project_prefix = "tftest" vpc_cidr = "10.0.0.0/16" aws_region = "ap-northeast-1"Git ignore
ref: https://github.com/github/gitignore/blob/master/Terraform.gitignore
.gitignore
# Local .terraform directories **/.terraform/* # .tfstate files *.tfstate *.tfstate.* # Crash log files crash.log # Exclude all .tfvars files, which are likely to contain sentitive data, such as # password, private keys, and other secrets. These should not be part of version # control as they are data points which are potentially sensitive and subject # to change depending on the environment. # *.tfvars # Ignore override files as they are usually used to override resources locally and so # are not checked in override.tf override.tf.json *_override.tf *_override.tf.json # Include override files you do wish to add to version control using negated pattern # # !example_override.tf # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan # example: *tfplan* # Ignore CLI configuration files .terraformrc terraform.rc実行
init
$ terraform init
差分の確認
$ terraform plan -var-file=test.tfvars適用
$ terraform apply -var-file=test.tfvarsAWS Console 上からでもリソースが確認できる。
実行結果の表示
$ terraform show
破棄
$ terraform destroy -var-file=test.tfvarsおまけ
Makefile
今回は env という変数で呼び出すファイルを制御したが、workspace を使った方が良さそう(?)
env=test clean: rm -rf ./.terraform init: terraform init plan: terraform plan -var-file=$(env).tfvars apply: terraform apply -var-file=$(env).tfvars show: terraform show deploy: init plan apply show destroy: terraform destroy -var-file=$(env).tfvars次やりたいこと
- Docker 化
- リソース間連携
- VPC に IGW 生やして Attach みたいな
- module 分割
- workspace の活用
- 投稿日:2020-08-09T02:50:06+09:00
AWS VPC の設定を terraform init
terraform init
に成功するまでに少し詰まったので、構文理解のためにも成功前後のファイル差分と解決までの道程を残しておく。やること
terraform init
まずはこれだけ。init 成功ファイル
vpc.tf
provider "aws" { version = "~> 3.1" } variable "project_prefix" {} variable "vpc_cidr" {} resource "aws_vpc" "vpc" { name = "${var.project_prefix}-vpc" cidr_block = var.vpc_cidr instance_tenancy = "default" enable_dns_support = true enable_dns_hostnames = true tags = { Name = var.project_prefix } }エラー解決の道程
元ファイル
provider "aws" {} variable "project_prefix" {} variable "vpc_cidr" {} resource "aws_vpc" "${var.project_prefix}-vpc" { cidr_block = "${var.vpc_cidr}" instance_tenancy = "default" enable_dns_support = true enable_dns_hostnames = true tags = { Name = "${var.project_prefix}" } }The following providers do not have any version
該当箇所
provider "aws" {}warning
The following providers do not have any version constraints in configuration, so the latest version was installed. To prevent automatic upgrades to new major versions that may contain breaking changes, it is recommended to add version = "..." constraints to the corresponding provider blocks in configuration, with the constraint strings suggested below. * provider.aws: version = "~> 3.1"修正後
バージョンが上がった時に再現性がないから、指定しとけよってことらしい。
provider "aws" { version = "~> 3.1" }Interpolation-only expressions are deprecated
該当箇所
cidr_block = "${var.vpc_cidr}"warning
Warning: Interpolation-only expressions are deprecated on vpc.tf line 9, in resource "aws_vpc" "${ ... }-vpc": 9: cidr_block = "${var.vpc_cidr}" Terraform 0.11 and earlier required all non-constant expressions to be provided via interpolation syntax, but this pattern is now deprecated. To silence this warning, remove the "${ sequence from the start and the }" sequence from the end of this expression, leaving just the inner expression. Template interpolation syntax is still used to construct strings from expressions when the template includes multiple interpolation sequences or a mixture of literal strings and interpolations. This deprecation applies only to templates that consist entirely of a single interpolation sequence.修正後
普通に変数使うときは、わざわざ
""
で囲わんでもええで、ってことらしい。cidr_block = var.vpc_cidrInvalid resource name
該当箇所
resource "aws_vpc" "${var.project_prefix}-vpc" {Error
Error: Invalid resource name on vpc.tf line 8, in resource "aws_vpc" "${ ... }-vpc": 8: resource "aws_vpc" "${var.project_prefix}-vpc" { A name must start with a letter or underscore and may contain only letters, digits, underscores, and dashes. Error: Invalid string literal on vpc.tf line 8, in resource "aws_vpc" "${ ... }-vpc": 8: resource "aws_vpc" "${var.project_prefix}-vpc" { Template sequences are not allowed in this string. To include a literal "$", double it (as "$$") to escape it.修正後
ここは AWS 上の名前ではなく、 Terraform 都合の名前を置く場所らしい。
名前は tags のプロパティを用いて指定する。resource "aws_vpc" "vpc" { tags = { Name = "${var.project_prefix}-vpc" }successed!
$ terraform init
Initializing the backend... Initializing provider plugins... Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary.次やりたいこと
- plan, apply
- 投稿日:2020-08-09T02:50:06+09:00
AWS VPC の設定を terraform init [入門]
terraform init
に成功するまでに少し詰まったので、構文理解のためにも成功前後のファイル差分と解決までの道程を残しておく。やること
terraform init
まずはこれだけ。init 成功ファイル
vpc.tf
provider "aws" { version = "~> 3.1" } variable "project_prefix" {} variable "vpc_cidr" {} resource "aws_vpc" "vpc" { name = "${var.project_prefix}-vpc" cidr_block = var.vpc_cidr instance_tenancy = "default" enable_dns_support = true enable_dns_hostnames = true tags = { Name = var.project_prefix } }エラー解決の道程
元ファイル
provider "aws" {} variable "project_prefix" {} variable "vpc_cidr" {} resource "aws_vpc" "${var.project_prefix}-vpc" { cidr_block = "${var.vpc_cidr}" instance_tenancy = "default" enable_dns_support = true enable_dns_hostnames = true tags = { Name = "${var.project_prefix}" } }The following providers do not have any version
該当箇所
provider "aws" {}warning
The following providers do not have any version constraints in configuration, so the latest version was installed. To prevent automatic upgrades to new major versions that may contain breaking changes, it is recommended to add version = "..." constraints to the corresponding provider blocks in configuration, with the constraint strings suggested below. * provider.aws: version = "~> 3.1"修正後
バージョンが上がった時に再現性がないから、指定しとけよってことらしい。
provider "aws" { version = "~> 3.1" }Interpolation-only expressions are deprecated
該当箇所
cidr_block = "${var.vpc_cidr}"warning
Warning: Interpolation-only expressions are deprecated on vpc.tf line 9, in resource "aws_vpc" "${ ... }-vpc": 9: cidr_block = "${var.vpc_cidr}" Terraform 0.11 and earlier required all non-constant expressions to be provided via interpolation syntax, but this pattern is now deprecated. To silence this warning, remove the "${ sequence from the start and the }" sequence from the end of this expression, leaving just the inner expression. Template interpolation syntax is still used to construct strings from expressions when the template includes multiple interpolation sequences or a mixture of literal strings and interpolations. This deprecation applies only to templates that consist entirely of a single interpolation sequence.修正後
普通に変数使うときは、わざわざ
""
で囲わんでもええで、ってことらしい。cidr_block = var.vpc_cidrInvalid resource name
該当箇所
resource "aws_vpc" "${var.project_prefix}-vpc" {Error
Error: Invalid resource name on vpc.tf line 8, in resource "aws_vpc" "${ ... }-vpc": 8: resource "aws_vpc" "${var.project_prefix}-vpc" { A name must start with a letter or underscore and may contain only letters, digits, underscores, and dashes. Error: Invalid string literal on vpc.tf line 8, in resource "aws_vpc" "${ ... }-vpc": 8: resource "aws_vpc" "${var.project_prefix}-vpc" { Template sequences are not allowed in this string. To include a literal "$", double it (as "$$") to escape it.修正後
ここは AWS 上の名前ではなく、 Terraform 都合の名前を置く場所らしい。
名前は tags のプロパティを用いて指定する。resource "aws_vpc" "vpc" { tags = { Name = "${var.project_prefix}-vpc" }successed!
$ terraform init
Initializing the backend... Initializing provider plugins... Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary.次やりたいこと
- plan, apply
- 投稿日:2020-08-09T02:30:03+09:00
Amazon Personalize では Role だけではなく S3 バケットにもポリシーを書く必要がある
概要
Amazon Personalize にデータをインポートするときに S3 のバケットポリシーも記載する必要があり、少しはまったので共有します。
やり方
Role のポリシー
{ "Version": "2012-10-17", "Statement": [ { "Action": [ "s3:ListBucket" ], "Effect": "Allow", "Resource": [ "arn:aws:s3:::バケット名" ] }, { "Action": [ "s3:GetObject", "s3:PutObject" ], "Effect": "Allow", "Resource": [ "arn:aws:s3:::バケット名/*" ] } ] }バケットポリシー
{ "Version": "2012-10-17", "Id": "PersonalizeS3BucketAccessPolicy", "Statement": [ { "Sid": "PersonalizeS3BucketAccessPolicy", "Effect": "Allow", "Principal": { "Service": "personalize.amazonaws.com" }, "Action": [ "s3:GetObject", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::バケット名", "arn:aws:s3:::バケット名/*" ] } ] }参考
https://docs.aws.amazon.com/personalize/latest/dg/data-prep-upload-s3.html
- 投稿日:2020-08-09T01:43:58+09:00
AWSのt2.2xlargeをhibernationしながら常用する
AWSは、2018年末辺りから、インスタンスの休止(ハイバネーション)ができるようになりました。
しばらくは、Amazon Linuxでしか使えなかったのですが、2019年にUbuntuでも使えるようになり、必要な時だけ立ち上げ、終わったら休止というのができるようになりました。たとえば、時間のかかるビルドをするときに、ビルドが終わったら休止しておけば、コストを抑えられますし、シャットダウンと違って、エラーの確認も再開後すぐにできます。
しかし、休止をAWS Consoleからするのでは面倒です。そのため、実行中のインスタンスから休止できるコマンドを作成します。
hibernate.sh#!/bin/sh aws ec2 stop-instances --instance-ids `curl -s 169.254.169.254/latest/meta-data/instance-id/` --hibernate上記を実行中のインスタンスに置いて、パスを通してください。そして、
hibernate.sh
を実行すると休止します。これで、例えば、
$ make; hibernate.shなどとすれば、ビルド後、休止します。
make && hibernate.sh
とすると成功時にしか休止しないので、make; hibernate.sh
とすべきです。ただ、上記だと、makeが一瞬で失敗してしまったときも、休止します。そのため、sleepを入れましょう。単にsleepを入れると分かりにくいのでカウントダウンのコマンドを作ります。
countdown.shsecs=$1 while [ $secs -gt 0 ] do sleep 1 & printf "\r%02d:%02d:%02d" $((secs/3600)) $(( (secs/60)%60)) $((secs%60)) secs=$(( $secs - 1 )) wait done echoそして、hibernate.sh でcountdown.shを呼びですようにします。以下では10分待っています。
hibernate.sh#!/bin/sh countdown.sh 600 && aws ec2 stop-instances --instance-ids `curl -s 169.254.169.254/latest/meta-data/instance-id/` --hibernate