AWSの基本であるEC2 (Elastic Compute Cloud) について学んでいきましょう! あわせて権限管理で使うIAM (Identity and Access Management) のポリシーとロールについても触れます。
1. 解説動画
2. 概要
【EC2】
EC2はAWSの基本中の基本、バーチャルマシン(簡単に言えばクラウドに置かれたサーバ=コンピュータ)のサービスです。
AWSではS3が2006年3月にリリースされたのに続いて、EC2が2006年8月にリリースされました。歴史あるサービスで、実は当初VPCも存在していませんでした。2009年9月にVPCもリリースされ、度重なる機能拡張のため関連するリソースや設定値が多く、基本のリソースながらやや複雑になっています。ただEC2インスタンスを作る際に必要な項目はそれほど多くないので、CFnテンプレートを読み解きながら作っていきましょう!
【IAM Role】
(EC2の前に作る)IAMロールと管理ポリシーは権限を付与するための仕組みで、今後使う予定のものを事前にまとめて作っておきます。
個人的には「IAMを使いこなせるようになれば、AWS一人前」と考えています。それほど大事だけど難しめで、ググっても情報が少なく、奥が深いサービスです。IAMの基本だけでも、EC2を使ってできるだけ分かりやすく解説させて頂きます!
EC2インスタンス作成後に実例で確認しますが、権限の付与は以下の2種類あります。
- IAM User:AWS外から接続して使う場合(例:AWSコンソール画面に接続、AWS CLIでPCから接続)。IAM GroupにIAM Managed Policyをアタッチするか、Inline Policyで直接書いて権限を付与します。
- IAM Role:AWS内のリソースが使う場合(例:EC2など)。IAM RoleにIAM Managed Policyをアタッチするか、Inline Policyで直接書いて権限を付与します。ちなみに Role=役割
権限を持つ者 | 使い分け | 権限の付け先 | 権限の付け方① | 権限の付け方② |
---|---|---|---|---|
IAM User | AWS外から | IAM Groupに | IAM Managed Policyをアタッチ | Inline Policyで書く |
IAM Role | AWS内から | IAM Roleに | IAM Managed Policyをアタッチ | Inline Policyで書く |
構成図
Webサーバとして公開するEC2インスタンスをPublic Subnet Cに作ります。EIPでIPアドレスを固定して、Route 53でドメイン(=ec2.[ご自身のドメイン名])のAレコードを追加することで、ドメインでアクセスできるようになります。
今回作成するEC2の構成図はこちらです。 ※小さくて見づらいので、右クリックして新しいタブで開いてください。
リソース一覧
リソース | 目的 | 備考 |
---|---|---|
IAM: ManagedPolicy | 権限の内容を書いた「管理ポリシー」 | ①AWSが作ったもの ②自分で作ったもの の2種類ある |
IAM: Role | ECS, EC2などへ権限付与するための「ロール」 | ManagedPolicyとInlinePolicyを両方使う。InlinePolicyはロールの中に直接権限の内容を書いてしまうので「インライン」ポリシーと呼ばれている |
IAM: InstanceProfile | 「ロール」をEC2にアタッチするために必要な「インスタンスプロファイル」 | CFnでは「インスタンスプロファイル」を「ロール」と別に作る。一方、画面上では明示的に作る必要はなく、EC2のロールを作ると勝手に作られ、設定値の一つとして表示されるだけ |
EC2: SecurityGroup, SecurityGroupIngress | EC2に対するInbound(Ingress)=内向きOutbound(Outgress)=外向きの通信を許可する「セキュリティグループ」 | 内向きは許可するものだけルールを追加していく。今回はHTTP(TCP 80番ポート)をフルオープンにする。 外向きは絞っても良いが、面倒なので通常はデフォルトのフルオープンのままで使うことが多い |
EC2: Instance | バーチャルマシン(仮想サーバ)=「インスタンス」 | AMIのイメージID、インスタンスタイプ、インスタンスプロファイル、サブネットID、セキュリティグループIDなどを指定して作成する |
EC2: EIP (Elastic IP Address) | 固定IPアドレス「EIP」 | Public Subnet内のリソースがインターネットと通信するためにはパブリックIPアドレス(グローバルIPアドレス)が必須。固定(EIP)か、自動割り当てを選べる。今回はEC2インスタンスで固定(EIP)を使う |
Route53: RecordSet | Route 53のHostedZone(簡単に言うとドメイン)に追加する「レコードセット」 | ドメイン→IPv4アドレス に変換するためのAレコードを追加する。追加するとブラウザ等からEIPだけでなくドメインでもアクセスできるようになる |
リソース | 目的 | 備考 |
---|---|---|
AMI (Amazon Machine Images) | EC2インスタンスを起動するのに必要な「マシンイメージ」※CFn未対応 | ①AWSが作成したもの ②Red Hatなどの第三者が作ったりライセンス付きで販売しているもの ③自分でEC2インスタンスから作ったもの など様々ある。必ず何かのAMIを元にEC2インスタンスを起動する |
EC2: Volume = EBS(Elastic Block Store) Volume | EC2インスタンスにアタッチするストレージ「EBSボリューム」 | 昔はHDDを使っていたが、今は汎用SSD(Volume Type: gp2, gp3)を使う。AMIイメージに含まれているので、EC2インスタンスを作ると自動でアタッチされている。 CFnで追加して作る場合は「VolumeAttachment」でアタッチする |
EBS Snapshot | EBSボリュームの「スナップショット」を作成することでS3にバックアップできる。※CFn未対応 | AMIの実態はEC2インスタンス起動時の設定値+EBSスナップショット。なのでAMIからEC2インスタンスを作ると、EBSボリュームが自動的に作られる |
EC2: NetworkInterface (ENI) | EC2インスタンスの「ネットワークインターフェイス」→物理マシンで言うところの NIC (Network Interface Card)。簡単に言えばLANケーブルを挿す口の部品 | これもEC2インスタンスを作ると自動的にアタッチされている。ただし厳密に言えば、EIPやSecurityGroupやSubnetはEC2インスタンスではなく、このENIに関連づけられている。 この理解はCFnを読み解く際に重要になってくるので頭の片隅に置いておいてください。CFnで追加して作る場合は「NetworkInterfaceAttachment」でアタッチする |
KeyPair | EC2インスタンスにSSH接続する場合に使うec2-userのSSH「キーペア」※CFn未対応 | 他の教材・書籍・ガイド記事・Qiita投稿などでは当たり前のようにキーペアを作成して、EC2インスタンスにSSH接続している。 実はSSM(Systems Manager)のSession Managerを使うとSSH接続しなくてもAWS管理画面やAWS CLIでログインができるので、私はキーペアを使っていない。 SSHポートを空ける必要がないのでセキュリティ的にも非常に安全で、ProtectedSubnetのインスタンスにも接続が可能なのでキーペアは必要ない(ただしPrivateSubnetは接続不可) |
命名規則
Classmethodさんの命名規則 https://dev.classmethod.jp/articles/aws-name-rule/ に準拠します。
公式URL
EC2
- Docs: Amazon EC2 とは - Amazon Elastic Compute Cloud
- CFn: EC2 リソースタイプのリファレンス - AWS CloudFormation
- CLI: ec2 — AWS CLI v2 Command Reference
IAM
- Docs: IAM とは - AWS Identity and Access Management
- CFn: IAM リソースタイプのリファレンス - AWS CloudFormation
- CLI: iam — AWS CLI v2 Command Reference
3. 解説手順
- CFnでIAM Role関連のリソースを作成する
- CFnでEC2関連のリソースを作成する
- 動作確認を実施する。ブラウザでアクセス、下記コマンドの実行、両方お試しください
※Macの場合はターミナルで、Windowsの場合はコマンドプロンプトかAWS CloudShellで実行してください
curl -v http://ec2.[ご自身のドメイン名]/
※応答内容はどこかにコピペして保存しておいてください 👉 宿題に出ます - (ブラウザ AWSコンソール画面で) EC2に接続して、Dockerの実行状況を確認する
EC2管理画面 > Instances > インスタンスを選択 > (上にある)Connectボタンをクリック > Session Managerタブをクリック > Connectボタンをクリック
id
※ユーザーの確認bash
※bashに変更pwd
※現在のパスを確認cd
※ホームディレクトリに移動pwd
※現在のパスを確認sudo docker container ls
※動いているDockerコンテナを確認 - (AWS CLIでも) EC2に接続して、同じくDockerの実行状況を確認する
※Macの場合はターミナルで、Windowsの場合はコマンドプロンプトかWindows PowerShellで実行してください
aws ssm start-session --target [i-から始まるInstanceID]
※AWSCLIでStart Session (※もしSessionManagerPlugin is not found.
と表示された場合は (オプション) AWS CLI 用の Session Manager plugin をインストールする - AWS Systems Manager を参照して、プラグインをインストールしてください。それでも接続できない場合は、6. FAQ「Session Managerを使って「Connect to instance」できないのはなぜですか?」を参照ください)bash
※bashに変更cd
※ホームディレクトリに移動sudo docker container ls
※動いているDockerコンテナを確認 - (PCから) 権限確認、権限テスト ※IAMユーザーで実行
▼5.の続きとならないよう、新しくターミナルを開いて実行してください
aws sts get-caller-identity
※どの権限で実行しているか確認aws s3 ls
※s3:ListAllMyBucketsの操作aws s3 ls cf-[AccountIDの12桁]-ap-northeast-1
※s3:ListBucketの操作aws s3 cp s3://cf-[AccountIDの12桁]-ap-northeast-1/iam-role.yml ./iam-role.yml.temp
※s3:GetObjectの操作aws s3 cp ./iam-role.yml.temp s3://cf-[AccountIDの12桁]-ap-northeast-1/
※s3:PutObjectの操作aws s3 rm s3://cf-[AccountIDの12桁]-ap-northeast-1/iam-role.yml.temp
※s3:DeleteObjectの操作rm ./iam-role.yml.temp
※Windowsの場合はdel iam-role.yml.temp
- (EC2から) 権限確認、権限テスト ※IAMロールで実行
※4.または5.の手順でEC2に接続し、
bash
cd
aws sts get-caller-identity
※どの権限で実行しているか確認aws s3 ls
※s3:ListAllMyBucketsの操作aws s3 ls cf-[AccountIDの12桁]-ap-northeast-1
※s3:ListBucketの操作aws s3 cp s3://cf-[AccountIDの12桁]-ap-northeast-1/iam-role.yml ./iam-role.yml.temp
※s3:GetObjectの操作aws s3 cp ./iam-role.yml.temp s3://cf-[AccountIDの12桁]-ap-northeast-1/
※s3:PutObjectの操作→エラーになるはずrm ./iam-role.yml.temp
- 使わない時はEC2インスタンスを停止する EC2管理画面 > Instances > インスタンスを選択 > (上にある)Instance stateボタンをクリック > Stop instance をクリック
4. CFnテンプレート
IAM Role
今後作るリソースのために、AWSアカウント全体で共通して使うIAM Managed Policy, Roleをまとめて作成します。AWSアカウント内、複数のシステムで共通して使うので、CFnスタック名やファイル名に[SystemName]は敢えて書いていません。
【注意】作ったものは後からImportValueして使いますので、下記のCFnスタック名は変えないでください。テンプレのYAMLファイルはスタックを作る時しか使わないので、ファイル名は任意です(お好きな場所に動かして頂いてかまいません)
【注意】IAM Managed Policy, Roleは同じ名前のものを重複して作成できません。既に作られている場合はエラーになりますので、一度削除して頂く必要があります。ご注意ください。手で作る際はCFnで作るものと別名でお願いします!
CFn Stack Name: iam-role S3 File Name: iam-role.yml
---
AWSTemplateFormatVersion: "2010-09-09"
Description: Create IAM Role etc.
Resources:
## IAM: Managed Policy (AmazonSSMGetParametersPolicy)
AmazonSSMGetParametersPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: AmazonSSMGetParametersPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action: ssm:GetParameters
Resource: '*'
## IAM: Managed Policy (SecretsManagerGetSecretValuePolicy)
SecretsManagerGetSecretValuePolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: SecretsManagerGetSecretValuePolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action: secretsmanager:GetSecretValue
Resource: '*'
## IAM: Managed Policy (AmazonECSExecuteCommandPolicy)
## Amazon ECS task IAM role - Amazon Elastic Container Service
## Ref. https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html#ecs-exec-required-iam-permissions
AmazonECSExecuteCommandPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: AmazonECSExecuteCommandPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- ssmmessages:CreateControlChannel
- ssmmessages:CreateDataChannel
- ssmmessages:OpenControlChannel
- ssmmessages:OpenDataChannel
Resource: '*'
## IAM: Role (AmazonECSTaskExecutionRole)
## Amazon ECS Task Execution IAM Role - Amazon Elastic Container Service
## Ref. https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_execution_IAM_role.html
AmazonECSTaskExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: AmazonECSTaskExecutionRole
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
- Ref: AmazonSSMGetParametersPolicy
- Ref: SecretsManagerGetSecretValuePolicy
## IAM: Role (AmazonSSMManagedECSInstanceRole)
## Amazon ECS Container Instance IAM Role - Amazon Elastic Container Service
## Ref. https://docs.aws.amazon.com/AmazonECS/latest/developerguide/instance_IAM_role.html
## Step 2: Verify or Create an IAM Instance Profile with Session Manager Permissions - AWS Systems Manager
## Ref. https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-getting-started-instance-profile.html
AmazonSSMManagedECSInstanceRole:
Type: AWS::IAM::Role
Properties:
RoleName: AmazonSSMManagedECSInstanceRole
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
## Default policy for the Amazon EC2 Role for Amazon EC2 Container Service.
- arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role
## To use the Session Manager
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
## IAM: Instance Profile (AmazonSSMManagedECSInstanceRole)
AmazonSSMManagedECSInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
InstanceProfileName: !Ref AmazonSSMManagedECSInstanceRole
Roles:
- Ref: AmazonSSMManagedECSInstanceRole
## IAM: Role (AmazonRDSEnhancedMonitoringRole)
## Ref. https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_Monitoring.OS.html
AmazonRDSEnhancedMonitoringRole:
Type: AWS::IAM::Role
Properties:
RoleName: AmazonRDSEnhancedMonitoringRole
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: monitoring.rds.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole
Outputs:
## IAM: Managed Policy (AmazonSSMGetParametersPolicy)
AmazonSSMGetParametersPolicy:
Value: !Ref AmazonSSMGetParametersPolicy
Export:
Name: !Sub ${AWS::StackName}-AmazonSSMGetParametersPolicy
## IAM: Managed Policy (SecretsManagerGetSecretValuePolicy)
SecretsManagerGetSecretValuePolicy:
Value: !Ref SecretsManagerGetSecretValuePolicy
Export:
Name: !Sub ${AWS::StackName}-SecretsManagerGetSecretValuePolicy
## IAM: Managed Policy (AmazonECSExecuteCommandPolicy)
AmazonECSExecuteCommandPolicy:
Value: !Ref AmazonECSExecuteCommandPolicy
Export:
Name: !Sub ${AWS::StackName}-AmazonECSExecuteCommandPolicy
## IAM: Role (AmazonECSTaskExecutionRole)
AmazonECSTaskExecutionRole:
Value: !Ref AmazonECSTaskExecutionRole
Export:
Name: !Sub ${AWS::StackName}-AmazonECSTaskExecutionRole
AmazonECSTaskExecutionRoleArn:
Value: !GetAtt AmazonECSTaskExecutionRole.Arn
Export:
Name: !Sub ${AWS::StackName}-AmazonECSTaskExecutionRoleArn
## IAM: Role (AmazonSSMManagedECSInstanceRole)
AmazonSSMManagedECSInstanceRole:
Value: !Ref AmazonSSMManagedECSInstanceRole
Export:
Name: !Sub ${AWS::StackName}-AmazonSSMManagedECSInstanceRole
AmazonSSMManagedECSInstanceRoleArn:
Value: !GetAtt AmazonSSMManagedECSInstanceRole.Arn
Export:
Name: !Sub ${AWS::StackName}-AmazonSSMManagedECSInstanceRoleArn
## IAM: Instance Profile (AmazonSSMManagedECSInstanceRole)
AmazonSSMManagedECSInstanceProfile:
Value: !Ref AmazonSSMManagedECSInstanceProfile
Export:
Name: !Sub ${AWS::StackName}-AmazonSSMManagedECSInstanceProfile
AmazonSSMManagedECSInstanceProfileArn:
Value: !GetAtt AmazonSSMManagedECSInstanceProfile.Arn
Export:
Name: !Sub ${AWS::StackName}-AmazonSSMManagedECSInstanceProfileArn
## IAM: Role (AmazonRDSEnhancedMonitoringRole)
AmazonRDSEnhancedMonitoringRole:
Value: !Ref AmazonRDSEnhancedMonitoringRole
Export:
Name: !Sub ${AWS::StackName}-AmazonRDSEnhancedMonitoringRole
AmazonRDSEnhancedMonitoringRoleArn:
Value: !GetAtt AmazonRDSEnhancedMonitoringRole.Arn
Export:
Name: !Sub ${AWS::StackName}-AmazonRDSEnhancedMonitoringRoleArn
【変更履歴】
- 2021-09-04:
AmazonECSExecuteCommandPolicy
管理ポリシーの追加 - 2023-04-14:コメント文を全般的に修正
- 2024-09-04:
AmazonSSMGetParametersPolicy
管理ポリシーからssm:GetParameter
を削除
EC2
前述の「今回作るリソース」に記載した
- IAM: Role, InstanceProfile
- EC2: SecurityGroup, SecurityGroupIngress(インバウンドルール), Instance, EIP
- Route 53: RecordSet
をまとめて作成します。
【注意】下記テンプレの冒頭でコメントしている通り、[SystemName]=awsmaster
はお好きなシステム名に置換してください(毎回同じでお願いします!)。また vpc, route53 のスタックから Output 値をインポートしますので、それらのスタック名が指定されたものでないとエラーになります。ご注意ください。
【意図】一つのシステムの中で複数種類のEC2を作成できるように、今回は notvia(ELBやCloudFrontを経由=viaしないという意味)という名前を、CFnスタック名・S3ファイルパス(ディレクトリ)に加えてください。下記の通りです。
CFn Stack Name: [SystemName]-prod-notvia-ec2 S3 File Name: [SystemName]/notvia/ec2.yml
---
### [Change System Name] awsmaster
## The following CFn stack must be created first in order to be referenced by the ImportValue function.
## 1. ${SystemName}-${Environment}-route53
## 2. ${SystemName}-${Environment}-vpc
AWSTemplateFormatVersion: "2010-09-09"
Description: Create EC2 Instance etc.
Parameters:
SystemName:
Description: System Name
Type: String
Default: awsmaster ### [Change System Name]
Environment:
Description: Environment
Type: String
Default: prod
AllowedValues:
- prod
- stg
- dev
SubDomain:
Description: Sub Domain
Type: String
Default: ec2
AllowedPattern: ^[^.]*$
ResourceName:
Description: Resource Name
Type: String
Default: notvia
EC2ImageId:
Description: >
Amazon Linux 2023 on Amazon EC2 - Amazon Linux 2023
https://docs.aws.amazon.com/ja_jp/linux/al2023/ug/ec2.html#launch-via-aws-cli
https://ap-northeast-1.console.aws.amazon.com/systems-manager/parameters/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64/description
e.g. al2023-ami-2023.3.20240122.0-kernel-6.1-x86_64
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "Environment Configuration"
Parameters:
- SystemName
- Environment
- SubDomain
- ResourceName
- EC2ImageId
Resources:
## IAM: Role
IAMRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub ${SystemName}-${Environment}-${ResourceName}-ec2-role
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
## To use the Session Manager
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
Policies:
- PolicyName: AmazonS3CfGetObjectPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action: s3:ListAllMyBuckets
Resource: "*"
- Effect: Allow
Action: s3:ListBucket
Resource: !Sub arn:aws:s3:::cf-${AWS::AccountId}-${AWS::Region}
- Effect: Allow
Action: s3:GetObject
Resource: !Sub arn:aws:s3:::cf-${AWS::AccountId}-${AWS::Region}/*
## IAM: Instance Profile
IAMInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
InstanceProfileName: !Ref IAMRole
Roles:
- !Ref IAMRole
## EC2(VPC): Security Group
EC2SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub ${SystemName}-${Environment}-${ResourceName}-ec2-sg
GroupDescription: !Sub ${SystemName}-${Environment}-${ResourceName}-ec2-sg
VpcId:
Fn::ImportValue: !Sub ${SystemName}-${Environment}-vpc-VPC
Tags:
- Key: Name
Value: !Sub ${SystemName}-${Environment}-${ResourceName}-ec2-sg
## EC2(VPC): Security Group Inbound Rule From Any (HTTP)
EC2SecurityGroupIngressHttp:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref EC2SecurityGroup
IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
Description: any
## EC2: Instance
Instance:
Type: AWS::EC2::Instance
## To retain the instance to be replaced when updating the instance
UpdateReplacePolicy: Retain
Properties:
ImageId: !Ref EC2ImageId
InstanceType: t2.micro
IamInstanceProfile: !Ref IAMInstanceProfile
SubnetId:
Fn::ImportValue: !Sub ${SystemName}-${Environment}-vpc-SubnetPublicC
SecurityGroupIds:
- !Ref EC2SecurityGroup
Monitoring: false
UserData:
Fn::Base64: !Sub |
#!/bin/bash
dnf -y update
aws configure set default.region ${AWS::Region}
## Install Docker Engine
dnf install -y docker
systemctl enable --now docker
## Install Docker Compose
CLI_DIR=/usr/local/lib/docker/cli-plugins
LATEST_RELEASE=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep browser_download_url | grep -i $(uname -s)-$(uname -m) | grep -v sha256 | cut -d : -f 2,3 | tr -d \")
mkdir -p ${!CLI_DIR}
curl -sL ${!LATEST_RELEASE} -o ${!CLI_DIR}/docker-compose
chmod +x ${!CLI_DIR}/docker-compose
ln -s ${!CLI_DIR}/docker-compose /usr/bin/docker-compose
## Run Docker Container
docker container run --name nginx --restart=always -d -p 80:80 nginx
## Required in Amazon Linux 2, but no longer required in Amazon Linux 2023
# BlockDeviceMappings:
# - DeviceName: /dev/xvda
# Ebs:
# VolumeSize: 8
# VolumeType: gp3
# # Encrypted: true
Tags:
- Key: Name
Value: !Sub ${SystemName}-${Environment}-${ResourceName}
PropagateTagsToVolumeOnCreation: true
## EC2(VPC): EIP
EIP:
Type: AWS::EC2::EIP
Properties:
InstanceId: !Ref Instance
Tags:
- Key: Name
Value: !Sub ${SystemName}-${Environment}-${ResourceName}-ec2
## Route 53: Record Set (IPv4)
Route53RecordSetIPv4:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneId:
Fn::ImportValue: !Sub ${SystemName}-${Environment}-route53-HostedZone
Name: !Sub
- "${SubDomain}.${DomainName}."
- DomainName:
Fn::ImportValue: !Sub ${SystemName}-${Environment}-route53-HostedZoneDomainName
Type: A
ResourceRecords:
- !Ref EIP
TTL: "300"
Outputs:
## IAM: Role
IAMRole:
Value: !Ref IAMRole
Export:
Name: !Sub ${AWS::StackName}-IAMRole
IAMRoleArn:
Value: !GetAtt IAMRole.Arn
Export:
Name: !Sub ${AWS::StackName}-IAMRoleArn
## IAM: Instance Profile
IAMInstanceProfile:
Value: !Ref IAMInstanceProfile
Export:
Name: !Sub ${AWS::StackName}-IAMInstanceProfile
IAMInstanceProfileArn:
Value: !GetAtt IAMInstanceProfile.Arn
Export:
Name: !Sub ${AWS::StackName}-IAMInstanceProfileArn
## EC2(VPC): Security Group
EC2SecurityGroup:
Value: !Ref EC2SecurityGroup
Export:
Name: !Sub ${AWS::StackName}-EC2SecurityGroup
EC2SecurityGroupVpcId:
Value: !GetAtt EC2SecurityGroup.VpcId
Export:
Name: !Sub ${AWS::StackName}-EC2SecurityGroupVpcId
## EC2: Instance
Instance:
Value: !Ref Instance
Export:
Name: !Sub ${AWS::StackName}-Instance
InstanceAvailabilityZone:
Value: !GetAtt Instance.AvailabilityZone
Export:
Name: !Sub ${AWS::StackName}-InstanceAvailabilityZone
InstancePrivateDnsName:
Value: !GetAtt Instance.PrivateDnsName
Export:
Name: !Sub ${AWS::StackName}-InstancePrivateDnsName
InstancePrivateIp:
Value: !GetAtt Instance.PrivateIp
Export:
Name: !Sub ${AWS::StackName}-InstancePrivateIp
InstancePublicDnsName:
Value: !GetAtt Instance.PublicDnsName
Export:
Name: !Sub ${AWS::StackName}-InstancePublicDnsName
InstancePublicIp:
Value: !GetAtt Instance.PublicIp
Export:
Name: !Sub ${AWS::StackName}-InstancePublicIp
## EC2(VPC): EIP
EIP:
Value: !Ref EIP
Export:
Name: !Sub ${AWS::StackName}-EIP
## Route 53: Record Set (IPv4)
Route53RecordSetIPv4:
Value: !Ref Route53RecordSetIPv4
Export:
Name: !Sub ${AWS::StackName}-Route53RecordSetIPv4
【変更履歴】
- 2022-04-04:EBS VolumeTypeを
gp2
からgp3
に変更 - 2022-05-23:EC2ImageIdをAmazon Linux 2のKernel 4.14から5.10に変更、EBS Volumeから
DeleteOnTermination: true
とEncrypted: false
を削除、EIPからDomain: vpc
を削除 - 2022-06-03:UserDataのコマンドを
docker run
からdocker container run
に変更 - 2022-06-04:docker-composeのバージョンを
1.27.4
から2.6.0
に変更 - 2023-04-06:冒頭でImportValueについてのコメント補足追加
- 2023-04-14:コメント文を全般的に修正
- 2023-04-23:AMIのParameter変更、UserDataでdocker-composeのバージョンを自動で最新版になるように変更
- 2023-10-30:
PropagateTagsToVolumeOnCreation: true
を追加 - 2023-11-15:EC2インスタンスのOSをAmazon Linux 2からAmazon Linux 2023に変更
5. 予習
- CFnでIAM RoleとEC2インスタンスを作成してください ※CFnでエラーになった場合は、EventsタブのスクリーンショットをSlackでください (AWSの画面が変わっている場合は同じ設定項目を探してください)
- CFnで作成したリソースを全て、手でも作ってください。作成中に分からなかった設定項目については調べたり、質問のためにメモしておいてください ※順番も大事なので、CFnの記載順を参考にしてください
- 【宿題】下記の項目について調べて、次回のZoomで説明してください (公式の情報が優先で、分からない場合はブログ等を参照ください)
- EC2の設定と挙動を理解するために、解説手順の動作確認でアクセスした1回のリクエストについて、応答結果を上記の表にまとめてください。①HTTPリクエストはAWSの中でどう通って、②最終的に誰(=Server)が、③どんなHTTP応答(=HTTPステータスコード)を返したか? ④それらの設定箇所はAWSコンソール画面でどこにあるか? を調べてください。分かりづらいかもしれないので、一部だけ答えを書いておきました
- EC2インスタンスの料金体系。今回作ったEC2インスタンスを1ヶ月連続で動かした場合はいくらかかるか? 逆に1ヶ月連続で止めていた場合はいくらかかるか?(EC2インスタンス、EBSボリューム、EIPの3点について計算ください。計算上、1ヶ月=30日×24時間とする)※12か月無料利用枠も気になる場合は調べてみてください
- 今回は「オンデマンド」インスタンスを使っていますが、それ以外に「リザーブド」インスタンス、「Savings Plans」、「スポット」インスタンスという種類もあります。t2.micro の場合、それぞれ「オンデマンド」と比較して割引率はどれくらいか?(リザーブドは複数パターンありますのでご注意ください)
- EC2インスタンスをProtected Subnetに作ると、インターネットに公開できません。なぜか?
- 今回作ったWebサイトをインターネットに公開するために、セキュリティグループではTCPの何番ポートを公開したか? そのポート番号のプロトコル名は何か? 同様にしてSSH・DNS・HTTPS・MySQL・PostgreSQLを公開する場合は、何番ポートを公開すれば良いか? TCPかUDPかもあわせてお答えください ※インターネット(TCP/IP)で使われるプロトコルを詳しく知りたい方は https://ja.wikipedia.org/wiki/インターネット・プロトコル・スイート に概要がまとめられています。これだけで数ヶ月の学習量がありますので、ほんの触りだけ補足させて頂きます。
- EC2のグローバルIPアドレスをEIPで固定しました。動的な割り当ても可能ですが、固定にこだわる理由は?
- EC2にログインしてS3ファイル操作をすると、ダウンロードはできますが、アップロードはエラーが出てできません。もしアップロードしたくなった場合はどこ(どのリソース)に、どのような権限を追加すれば、できるようになりますか?(お答えは想定でかまいません)
- EC2インスタンスの再起動と停止→開始の違いは?
- T系のインスタンスだけ存在する「CPUクレジット」とは何か?「無制限モード(Unlimited)」とは何か? 現在の「クレジット残高」の見方について調べてください(概要レベルでかまいません。詳細レベルは応用課題の3.へ)
- EBS最適化とは何か? t2.microは有効にできるか? t3.microは有効にできるか?
- EBSボリュームタイプの種類は何があるか? 特にSSDの種類の違いについて調べてください
- EC2にはスペックが異なる多様な「インスタンスタイプ」が存在します。2023年7月時点で600種類以上で、2019年6月時点で170種類以上でした。たった4年で430種類も増えるという驚異的な進化を遂げています。詳しくは2023年7月のプレゼン資料 まずは基本のおさらい! Amazon EC2 の概要と インスタンスタイプの選び方 (PDF) をご覧ください。下記の動画かPDFを熟読しておいてください。
- 【応用課題】余裕のある方は実際に挑戦して頂くと勉強になると思います! ※時間の都合でZoomで解説はしませんので、答え合わせをされたい方はSlackでDMください
curl -IXGET http://ec2.[ご自身のドメイン名]/
でHTTPヘッダを確認できます。各項目の意味を調べてみてください。この後、ELBやCloudFrontを作っていきますので、それぞれにHTTPヘッダの内容が若干変わってくるはずです- docker-compose コマンドもインストールしていますので、ご自身で作られたものやお好きなDockerコンテナを起動してみてください。 【重要】UserDataはEC2インスタンスを最初に起動した時しか動作しませんので、UserDataに書き加えて動作を試したい場合はCFnスタック(EC2などのリソース)を一度削除した上で、再度CFnスタックを作り直して頂く必要があります
- T系のインスタンスだけ存在する「CPUクレジット」について深く考えてみましょう
- t2.microは1時間あたりいくつのCPUクレジットを獲得できるか?
- t2.microが蓄積可能なCPUクレジットの上限は?
- t2.microのvCPUを100%稼働できるのは最大何分間か?
- t2.microのCPUクレジットを使い切ったらどうなるか?
- t2.microのインスタンスを停止したら、蓄積したCPUクレジットはどうなるか?
- t2.microは起動時にいくつのCPUクレジットからスタートするか?
- t3.microは1時間あたりいくつのCPUクレジットを獲得できるか?
- t3.microが蓄積可能なCPUクレジットの上限は?
- t3.microのvCPUを100%稼働できるのは最大何分間か?
- t3.microのCPUクレジットを使い切ったらどうなるか?
- t3.microのインスタンスを停止したら、蓄積したCPUクレジットはどうなるか?
- t3.microは起動時にいくつのCPUクレジットからスタートするか?
- t3.microで余剰クレジットにより料金が発生するケースはどういう場合か?
- EC2起動時のシステムログ(コンソール出力)を画面上で確認してください。起動に失敗した場合や初回起動時のデバッグなどに確認できます
- 料金計算の詳細が気になる方は、公式ドキュメントの説明を熟読されることをオススメします。そうすると、次のような質問にも答えられるようになります。※なお無料利用枠は適用されないものとする。1か月は30日と仮定する
- Amazon Linux 2のEC2インスタンス(t2.micro@東京リージョン)を6分間だけ起動したらいくら?
- Windows Server 2019のEC2インスタンス(t2.micro@東京リージョン)を6分間だけ起動したらいくら?
- EBS(gp3@東京リージョン)240GBを作って6分後に消したらいくら?
- 前述の宿題7.でEC2からS3バケット内へファイルをアップロードする権限を尋ねましたが、実際のその権限を追加してアップロードできるか試してください。同様にファイルの削除も権限を追加して試してください。
## 動作確認(3.解説手順の3番目)の結果
$ curl -v http://ec2.[ご自身のドメイン名]/
(中略)
< HTTP/1.1 200 OK
< Server: nginx/1.27.3
< Date: Thu, 12 Dec 2024 15:03:36 GMT
< Content-Type: text/html
< Content-Length: 615
< Last-Modified: Tue, 26 Nov 2024 15:55:00 GMT
< Connection: keep-alive
< ETag: "6745ef54-267"
< Accept-Ranges: bytes
段階 | URL | HTTP応答 | Server | 経路 | 設定箇所 |
---|---|---|---|---|---|
EC2作成後 |
| 200 ※上記(中略)の下 | nginx/1.23.4 ※上記(中略)の下 | (リクエストがServerにたどり着くまでの流れは?) | (左記の経路にするための設定はどこに?) |
以下は補足です。時間に余裕があれば、ご覧ください。 上記プレゼンに続く動画やPDF資料 【開催報告】「夏の Amazon EC2 祭り 2023 最新インスタンス活用編」セミナー | Amazon Web Services ブログ も参考になります。 以前の説明で使っていた、2019年6月のプレゼン資料 Amazon EC2 インスタンスタイプの選び方ガイド (PDF) も載せておきます。
6. FAQ(随時追加)
「AWSのユーザーがたくさんの要望を言ったから」というのが理由のようです。詳しくはAWS Summit Tokyo 2019(2019年6月開催)のプレゼン資料 Amazon EC2の進化の歴史から学ぶ EC2入門 2019年版 (PDF 55ページ) と下記の動画をご覧ください。これを見る限り、今後も増え続けることは間違いないでしょう。
セキュリティグループと似たようなネットワークのフィルタ設定に「ネットワークアクセスコントロールリスト(略してネットワークACL)」があります。違いや使い分けを表でまとめておきます。
ただ両方使うと、通信できなかった時の問題切り分けが面倒になりますし、ネットワークACLはインスタンス個別設定ができないので、現場では使わないことが大半です。
観点 | セキュリティグループ | ネットワークACL |
---|---|---|
オンプレで言えば | OSのファイアウォール | ルーターのACL |
適用場所 | 正確にはENIだが、EC2, ELB, RDSなどのリソースごとという認識でOK | サブネット(つまりサブネット内の全てのリソースに自動適用される) |
複数適用可能か | 1つのリソースで複数適用可能(ただし分かりづらくなるので複数適用はオススメしない) | 1つのサブネットで複数適用不可(1つのみ適用可能) |
ルールの許可/拒否 | 許可ルールのみ追加 | 許可/拒否ルールの両方組み合わせ可能 |
ルールのチェック | 通信が許可されるかどうか、全てのルールがチェックされる | 通信が許可されるかどうか、番号の小さい順にルールがチェックされる(該当したらそれ以降は無視) |
インバウンドルールのデフォルト(セキュリティグループは新規作成を使い、ネットワークACLはデフォルトのまま使うと想定) | 新規作成すると、全ての通信を拒否(許可ルールが1つもないので、暗黙のDenyで全て拒否) | デフォルトのは、全ての通信を許可(ルール番号100)(ちなみに新規作成すると、許可設定がないので全て拒否) |
アウトバウンドルールのデフォルト(同上) | 新規作成すると、全ての通信を許可(全て許可するルールが入っている) | デフォルトのは、全ての通信を許可(同上) |
戻りの通信は許可されるか | ステートフル(行き(=Request)の通信がルールで許可されれば、戻り(=Response)の通信も自動的に許可される) | ステートレス(通信の行き戻り関係なく、許可/拒否のルールが厳密に適用される) |
良くある使い方(本教材でも同じ) | デフォルトのは使わず、リソースごとに新規作成する。インバウンドで必要な許可ルールのみ追加、アウトバウンドはデフォルトのまま全て許可 | デフォルトのまま使う。インバウンドもアウトバウンドもデフォルトのまま全て許可 |
参考(1) AWS公式ドキュメント
- Amazon VPC でのインターネットワークトラフィックのプライバシー - Amazon Virtual Private Cloud
- VPC のセキュリティグループ - Amazon Virtual Private Cloud
- ネットワーク ACL - Amazon Virtual Private Cloud
参考(2) Classmethod
どちらでも動きに違いはなく、正直どちらが良いかは私も毎回悩みます。
AWS公式ドキュメントでは管理ポリシーを推奨していましたが、[アンケートプレゼント]で登場するServerless Frameworkではインラインポリシーで作成されます。
一概には言えないとはいえ、一応どちらかが向いているケースはあり、下記のケースに該当する場合はそちらを選択ください。
- 管理ポリシーが向いているケース:
Resource: *
など特定のリソースに限定せず、数多くのリソースで共通して使われることが想定される場合。今回 iam-role.yml のスタックで作った管理ポリシーが一例です - インラインポリシーが向いているケース:特定のロールでしか使われない/使って欲しくない場合や、ロールが削除されたときに一緒に削除されてほしい場合。今回 ec2.yml のスタックで作ったロールのインラインポリシーが一例です
問題はどちらにも該当しないケース(共通で使われるかもしれないし、個別で使って終わりになるかもしれないし、というケース)です。正直どちらにするかは現場で前例に習ったり、周囲の人に相談したり、とりあえず迷ったら管理ポリシーと決めておいたり、要は「決めの問題」になります。
※「決めの問題」=IT業界で良く使われる用語の一つ。メリット・デメリットを全部挙げてもどちらが良いか決められず、意思決定者が「決め」たらそれで決着がつく問題。
ちなみに「ロールにアタッチできる管理ポリシーの数」と「ロールに書けるインラインポリシーの文字数」には上限がありますのでご注意ください。
やむを得ないので、次の手順でリソースをCFnスタックごと削除後、再作成してください。
[SystemName]-prod-notvia-ec2
スタックを削除する[SystemName]-prod-vpc
スタックを削除する[SystemName]-prod-certificatemanager
スタックを削除する[SystemName]-prod-route53
スタックを削除する[SystemName]-prod-route53
スタックを再作成する- ドメインを購入されたところで、ネームサーバの設定を変更する(DNSキャッシュのため、すぐに変更が反映されない場合もあります)
[SystemName]-prod-certificatemanager
スタックを再作成する- Route 53 HostedZoneの中の(既存で該当する)CNAMEレコードを削除し、レコードを再作成する
[SystemName]-prod-vpc
スタックを再作成する[SystemName]-prod-notvia-ec2
スタックを再作成する
うまくいかない場合はSlackの個別チャンネルでお問い合わせください。
WHOIS情報(ドメイン所有者・管理者の住所や連絡先の公開情報)を匿名や秘密にしていますか? WHOIS情報を代理で、バリュードメインなどドメインを管理している会社の所在地や連絡先にした場合、「メールアドレスの有効性認証」が必要になります。
バリュードメインなどからメールが届いていると思いますので、再度ご確認ください。もし期限が切れてリンクが使えない場合は、バリュードメインなどに直接お問い合わせください。
- バリュードメインの場合のメールサンプル:WHOIS情報確認メールについて | お知らせ | バリュードメイン
- 私が良く使うWHOISはこちら:ドメイン名・IPアドレス検索 (ANSI Whois) - Asuka.IO
→ Domain Status: clientHold
となっていれば「メールアドレスの有効性認証」ができていない可能性が高いです。
EC2インスタンス(以下、EC2と表記)でSystems Manager(SSM)のSession Managerを使うためには、EC2側で3つの条件、接続するMacやWindows側で2つの条件を満たす必要があります。
【EC2側】
- SSM Agentがインストールされていること(Amazon Linuxはデフォルトでインストール済みなので対応不要)
- 起動時にSession Managerを使うために必要な権限が与えられていること(具体的には、EC2にアタッチしたIAMロールに
AmazonSSMManagedInstanceCore
ポリシーが含まれていればOK) - EC2からインターネットに接続できること
【MacやWindows側】※AWSマネジメントコンソールを使う場合は不要
- AWS CLI(awsコマンド)がインストールされていて、初期設定が完了していること(心配な場合は
aws sts get-caller-identity
を実行して、AWSアカウントID・IAMユーザー名が普段使っているものと一致することを確認してください。初期設定の手順は「②ルートユーザー・IAMユーザー」教材の「3. 解説手順」をご覧ください) - Session Managerプラグインがインストールされていること(
SessionManagerPlugin is not found.
というエラーが表示された場合は (オプション) AWS CLI 用の Session Manager plugin をインストールする - AWS Systems Manager を参照して、プラグインをインストールしてください)
「Connect to instance」ができないのは、いずれかの条件が満たされていないのだと思います。
特に3.については下記のパターンいずれもインターネットに接続できないので、ご注意ください。
- Public Subnetに作ったのに、Public IPアドレス(EIPや自動割当)がない
- Protected Subnetに作ったのに、NATゲートウェイがない
- Private Subnetに作った
※なぜインターネットに接続できないのかはぜひ考えてみてください。もし分からない場合は、遠慮なくZoomやSlackにてお尋ねください。
参考:Session Manager のセットアップ - AWS Systems Manager https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager-getting-started.html
以上、お疲れさまでした!