Open8

AWS入門記録(できるだけテキストベースの資料、論より動いているもの)

mr_ozinmr_ozin

前提

  • 特定の誰か向けではなく、自分が理解するまでの記録です
    • 資格の習得は目的にしていません
  • AWSを仕事でちょっと触ったが、0ベースで始動する際の設定が理解できていない前提です
    • 仕事でEC2インスタンスにゴニョゴニョアクセスした程度でAWS経験あります、と言いたくない
  • macOS(Apple Silicon)前提
  • 資料はできるだけテキストベースで理解したい
    • 初心者向けは動画の方が多いが、読んだ方が早く理解できるため
  • とにかく動かしているという実感を得たい、IaCできるならIaCすることを前提にしたい
  • 仮の最終目的は超基礎的なサービス+フロントエンド向けのサービス(AWS Amplify等)
mr_ozinmr_ozin

AWSアカウント開設とロールアカウント作成

AWSアカウントを0から開設。過去に使ったメールアドレスだとダメだったのでAWS学習用のGmailを取得した。

https://aws.amazon.com/jp/getting-started/guides/setup-environment/module-one/

普段使い用のアカウントを作成。ルートアカウントじゃなくてログイン用のアカウントを作成。

https://aws.amazon.com/jp/getting-started/guides/setup-environment/module-two/

ログイン用アカウントが作成されると、Invitation to join AWS IAM Identity Center (successor to AWS Single Sign-On)というメールが来るので、そのリンクからパスワード設定、ログインを行う。

mr_ozinmr_ozin

AWS CLI設定

AWS CLI v2 Apple Silicon向け設定(注意点あり)

公式通り入れたい…のだが、公式のインストーラーだとAWS CLI v2のApple Silicon向け(ARM64)ビルドをインストールする手順が少々面倒らしい。
ビルドすればできないことはないらしいが、流石に面倒臭い。

https://github.com/aws/aws-cli/issues/7252

コマンドを使ってみて、正直どちらでも問題なさそうとは思うが、自分はHomebrew経由で入れた。

$ brew install awscli

公式のGUIインストーラーとHomebrewで入れた際の違いは source/arm64の箇所。

# from Homebrew
$ aws --version
aws-cli/2.13.32 Python/3.11.6 Darwin/23.0.0 source/arm64 prompt/off
# from GUI installer
$ aws --version
aws-cli/2.13.32 Python/3.11.6 Darwin/23.0.0 exe/x86_64 prompt/off

AWS CLIインストール完了後、AWS管理コンソールにてCommand line or programmatic accessをクリックするとAWSの認証情報が表示される。

screenshot-AWS-console

aws configure ssoコマンドで設定していく。 最後に聞かれるCLI profile nameは毎回打つことになるので自分で打ちやすいものにする。

CLI profile name [***]: my-dev-profile

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/sso-configure-profile-token.html

設定ができたか確認する。アカウント作りたてで何もしていない場合、下記のコマンド実行結果は何も出力されない。

$ aws s3 ls --profile my-dev-profile

毎度--profileを聞かれるのが面倒な場合は、CLI profile nameにてdefaultと入力するか、~/.aws/configにて設定を書き換える。

-[profile my-dev-profile]
+[default]
sso_session = my-sso

設定ができると--profileなしで[default]の設定が使われる。

$ aws s3 ls
mr_ozinmr_ozin

AWS CLIの挙動確認

公式通り確認する。ただし現時点の日本語ガイドの手順だけだとエラーが起きることがある。
これはaws configure ssoで認証する方法が紹介されていないため。

https://aws.amazon.com/jp/getting-started/guides/setup-environment/module-three/

英語版では解決しているので、翻訳待ちかと思われる。(フィードバックは送信済み)

https://aws.amazon.com/getting-started/guides/setup-environment/module-three/

エラーが起きた場合は下記のように対処する。

エラー(AuthFailure)

$ aws ec2 describe-vpcs

An error occurred (AuthFailure) when calling the DescribeVpcs operation: AWS was not able to validate the provided access credentials

aws configureで対話的に設定したため、aws_session_tokenの設定がされていないと思われる。

対応は間違って入力された~/.aws/credentials~/.aws/configの中身を削除後、aws configure sso で設定しなおす。

エラー(RequestExpired)

$ aws ec2 describe-vpcs

An error occurred (RequestExpired) when calling the DescribeVpcs operation: Request has expired.

そもそもとして、環境変数でexportするか、または~/.aws/credentialsにて手動で書き込む設定は、短期的な認証設定であるため、認証が切れてしまう。

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-authentication-short-term.html

対応は同じく、aws configure sso の方が推奨であるため、そちらで設定する。

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/sso-configure-profile-token.html#sso-configure-profile-token-auto-sso

mr_ozinmr_ozin

EC2の起動とAWS CLIでの確認

EC2起動はチュートリアル通りに管理画面から作成、EC2 Instance Connect、終了を経験しておく。

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/EC2_GetStarted.html

EC2インスタンスについて実感がつかめたら、CLIでもやってみる。

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-services-ec2-instances.html

自分が建てたEC2インスタンスについて確認する。そのまま出力すると大量に表示されるので、表示を絞ることも可能。

# 終了後はqキーで抜ける
$ aws ec2 describe-instances
# instance idのみ
$ aws ec2 describe-instances --query "Reservations[].Instances[].InstanceId"

AWS CLIでのEC2の起動と終了

EC2インスタンスを起動する。先ほどと同じような条件で起動する。

$ aws ec2 run-instances --image-id ami-098940df4d3292e9a --instance-type t2.micro

※余談だがCLI経由での起動時、インスタンス種別を指定しない場合m1.smallでインスタンスが起動した。

起動完了後、EC2の管理画面にて、インスタンスが起動している旨が確認できる。

EC2インスタンスは削除されるまで使用料が発生するので、確認が済んだら「終了」を行う。
(誤解しやすいが、停止と終了は違う状態なので注意する)

管理画面でインスタンスのIDを確認して実行する。i-XXXXXXは自分のインスタンスに読み替えてください。

$ aws ec2 terminate-instances --instance-ids i-XXXXXX

完了後、管理画面で「インスタンスの状態」が「終了済み」になっていることを確認する。

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-services-ec2-instances.html#terminating-instances

課金回避のため、全てのリージョンでEC2が停止していることを確認する

慣れていない内は複数のリージョンでEC2を立てっぱなしにしてしまうことがあるので、Amazon EC2 グローバルビューで起動しているインスタンスがないか確認しておく。

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/WindowsGuide/global-view.html

mr_ozinmr_ozin

AWS CDKを使ってみる

AWS CDK CLI設定

AWS CDK CLIはnpm経由でインストールする。自分はpnpmを使っているのでpnpm i -g aws-cdkでインストール。

https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/cli.html

正常にインストールできると下記のような表示になる。

$ pnpm i -g aws-cdk
$ cdk --version
2.104.0 (build 3b99abe)

https://aws.amazon.com/jp/getting-started/guides/setup-cdk/

個人的なハマりどころ

cdk bootstrap aws://ACCOUNT-NUMBER/REGION

特にポリシーを指定しない場合、アカウントはAdministratorAccessを用いる必要がある
PowerUserAccessでも良さそうと思えたが、IAMのロール作成も行われるため、これではエラーが出る

Using default execution policy of 'arn:aws:iam::aws:policy/AdministratorAccess'. Pass '--cloudformation-execution-policies' to customize.

https://docs.aws.amazon.com/ja_jp/aws-managed-policy/latest/reference/AdministratorAccess.html

aws configure ssoにて設定されたRoleがsso_role_name = AdministratorAccessであるか確認する
間違っている場合は再設定を行う

途中で失敗した時は作成されたS3バケットとCloudFormationを削除する
S3バケットはcdk-で始まるもの。CloudFormationはスタック名がCDKToolkitのスタック。

CDKのリージョン設定はAWS CLIで設定しているのと同じにしておく

チュートリアル上ではus-east-1 か eu-west-1にすると記載があるが、失敗したので、cdk bootstrapで設定した東京リージョン設定だとうまくいった。

bin/cdk-demo.ts
const app = new cdk.App();
new CdkDemoStack(app, 'CdkDemoStack', {
  env: { account: 'ACCOUNT-NUMBER', region: 'ap-northeast-1' },
});

https://aws.amazon.com/jp/getting-started/guides/setup-cdk/module-three/

余談

AdministratorAccessはかなり強い権限であり、日常遣いするには強すぎるのでせめてPowerUserAccessでできないか考慮する

mr_ozinmr_ozin

AWS CDK でEC2インスタンスを立ててみる

チュートリアルから発展して、とりあえずEC2インスタンスをCDKで定義してみる。

$ mkdir cdk-demo
$ cd cdk-demo
$ cdk init --language typescript

YOUR_ACCOUNT_NUMBERは自分のアカウントナンバーに読み替えてください。

bin/cdk-demo.ts
#!/usr/bin/env node
import 'source-map-support/register'
import { App } from 'aws-cdk-lib'
import { CdkDemoStack } from '../lib/cdk-demo-stack'

const app = new App()
new CdkDemoStack(app, 'CdkDemoStack', {
  env: { account: 'YOUR_ACCOUNT_NUMBER', region: 'ap-northeast-1' },
})

PrivateなVPCとEC2インスタンスを定義する。

lib/cdk-demo-stack.ts
import {Stack, StackProps} from 'aws-cdk-lib'
import { Construct } from 'constructs'
import * as ec2 from 'aws-cdk-lib/aws-ec2'

export class CdkDemoStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props)

    const vpc = new ec2.Vpc(this, `demo-VPC`, {
      subnetConfiguration: [
        {
          cidrMask: 24,
          name: 'private-subnet',
          subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
        },
      ],
    })

    new ec2.Instance(this, `demo-EC2`, {
      instanceType: ec2.InstanceType.of(
        ec2.InstanceClass.T2,
        ec2.InstanceSize.NANO
      ),
      machineImage: new ec2.AmazonLinuxImage({
        generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2,
      }),
      vpc: vpc,
    })
  }
}

new ec2.VpcがVPCを定義しているコード。今回は外部向けに後悔するわけではないのでPrivateなサブネットを定義。

new ec2.InstanceがEC2がインスタンスを定義しているコード。インスタンスのタイプやインスタンスのAMI、VPCをPropsとして渡す必要がある。
ec2.InstanceType.ofにてマシンのサイズとクラスを定義できる。ここで存在しないタイプを定義すると、デプロイ時にエラーになる。

環境のデプロイ

定義ができたらデプロイする。途中でYes/Noで聞かれるのでyで実行。

$ cdk deploy

デプロイできたらコンソール画面で下記が作成されていることが確認できる。

  • EC2インスタンスCdkDemoStack/demo-EC2
  • VPCCdkDemoStack/demo-VPC

環境とコードの差分チェック

現在デプロイされている環境と、定義しているコードの差を確認するためのコマンドがある。試しにインスタンスのタイプを変えてみる。

lib/cdk-demo-stack.ts
      instanceType: ec2.InstanceType.of(
        ec2.InstanceClass.T2,
-       ec2.InstanceSize.NANO
+       ec2.InstanceSize.SMALL
      ),

この状態で差分を確認してみる。コードの変更箇所とデプロイされている差分が出力される。

$ cdk diff
Stack CdkDemoStack
Resources
[~] AWS::EC2::Instance demo-EC2 demoEC2ADA90D49 may be replaced
 └─ [~] InstanceType (may cause replacement)
     ├─ [-] t2.nano
     └─ [+] t2.small


✨  Number of stacks with differences: 1

環境を更新するには再度デプロイします。デプロイ後、インスタンスタイプがt2.smallであることを確認できます。

$ cdk deploy

環境の破棄

一通り学習が終わったら環境を破棄してお片付けします。途中でYes/Noで聞かれるのでyで実行。
今回の場合は定義したVPC、EC2インスタンスが破棄されます。

$ cdk destroy

CDKコマンド実行時には自動的にtscされる

TypeScriptに慣れ親しんだ人ならcdkコマンドを打つ前にコンパイルしないの?と疑問に思われたかもしれないが、AWS CDKでは自動的にTypeScript→JavaScriptのコンパイルを自動で行ってくれる模様。tscは型チェックを手動を行うためにある模様。

The AWS CDK automatically does this whenever it needs to run your app.

https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-typescript.html#typescript-running

CDK参考例

https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.Instance.html#example

mr_ozinmr_ozin

CDKのテスト

CDKで定義したリソースがCloudformationのテンプレートに変換されるので、その値が想定通りになっているかをテストする。

とはいえ初見だと実際にどんなテンプレートが吐き出されているかわからないのでconsole.log(template.toJSON())で中身を見てみるとどんなテストが書けるかわかってくる。

CDKのテスト用にaws-cdk-lib/assertionsがあり、テンプレートにどんな値があるか確認できる。

import * as cdk from "aws-cdk-lib";
import { Template } from "aws-cdk-lib/assertions";
import * as CdkDemo from "../lib/cdk-demo-stack";

test("VPC, EC2 instance Created", () => {
  const app = new cdk.App();
  const stack = new CdkDemo.CdkDemoStack(app, "MyTestStack");
  const template = Template.fromStack(stack);
  // 実際にどんな形で出力されるのか確認できる
  console.log(template.toJSON())

  // 出力されたテンプレートが前回のスナップショットから変更点がないか
  expect(template.toJSON()).toMatchSnapshot();

  // VPCが1件作成されている
  template.resourceCountIs("AWS::EC2::VPC", 1);
  // EC2インスタンスが1件作成されている
  template.resourceCountIs("AWS::EC2::Instance", 1);
  // EC2インスタンスのタイプは"t2.nano"である
  template.hasResourceProperties("AWS::EC2::Instance", {
    "InstanceType": "t2.nano",
  });
});

CIと組み合わせれば想定外のインスタンスが作られて重課金される、無駄なリソースを定義していないか、確認ができそう。

https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.assertions-readme.html#special-matchers

https://pages.awscloud.com/rs/112-TZM-766/images/CDKでもテストがしたい.pdf

余談

TypeScriptのCDKが独自の継承クラスベースの設計なのも癖が強いが、テストのモジュールも独自のやり方を強いる点でだいぶ癖が強いと思います