LoginSignup
3
9

More than 5 years have passed since last update.

CLI で学ぶAWSでのネットーワーク&サーバー構築

Last updated at Posted at 2019-02-17

概要

背景と目的

AWSの入門としてよく挙げられる「Amazon Web Services 基礎からのネットワーク&サーバー構築」を読んで、AWSマネージメントコンソール(GUI)から操作をして概要を理解しました。しかし、自分の頭の中にしっかりと定着したかというと、操作した経験が不足しており理屈を理解した程度だったので、今度はCLIから操作をしてより発展的なアークテクチャを設計することにしました。

ここでは、AWS CLI を使ってコマンドライン上からAWSを操作して、最終的にはNginxでS3にプロキシし、静的コンテンツを表示します。

個人的にはAWSマネージメントコンソールの画面を見ながらの説明だと、GUIのボタンをとりあえず押せば実現できるので、初学者には適切だと思います。

一方で、概要を知った上でCLIから操作すると、明示的にAWSサービスとの関係をコマンド引数に渡す必要があり、それぞれのAWSサービス間の関係や状態を決める属性などがより明らかになりました。また、コマンドを覚えることでGUI上の操作よりもはやく目的の操作が可能になったり、コマンドを組み合わせてスクリプトを作ったりできる利点もあります。

そのため以下のような方を対象に記事を書いています。

  • AWSのVPCやサブネット、S3などの概要はなんとなくわかる
  • 概要は理解したが、実際にAWSサービスを組み合わせてアーキテクチャを設計できるほどではない
  • 実際に手を動かしてAWSについて理解したい
  • AWS CLI を使ってAWSサービスを操作したい

目標となるアーキテクチャ

最終的にはEC2上のNginxが外部からのリクエストを受け付けて、S3にプロキシし、S3に配置した静的コンテンツを取得できるようにします。
そのため、以下のようなアークテクチャーをCLIからAWS上に作ることになります。

スクリーンショット 2019-02-17 20.40.02.png

これらを実現するためには、以下のような操作をAWS CLI から行うことになります。

  • VPCの作成
  • サブネットの作成
  • インターネットゲートウェイとルートテーブルの作成
  • EC2インスタンスの作成と外部ネットワークへの公開
  • EC2インスタンスのセキュリティグループへの所属
  • S3バケットの作成とポリシーの付与
  • EC2インスタンスからS3へアクセスできるようにVPCエンドポイントの作成

AWS CLI の接続設定

AWS CLI を利用するには、こちらからインストールが必要です。

次にAWS CLI が対象のAWSサービスに通信できるように接続設定をする必要があります。
これには、アクセスキーを作成し、接続時に参照するようにします。
アクセスキーは、アクセスキーIDとシークレットキーから成り、まだCLIの設定をしていないので、AWSマネジメントコンソールから作成することにします。

まず、ここからIAMユーザーを作成します。

スクリーンショット 2019-02-17 17.56.49.png

作成する際に、そのIAMユーザーに権限(IAMポリシー)を付与(アタッチ)します。
ここでは学習を目的とするので、AWSアカウントのルートユーザーと同等の管理者権限を付与します。
これで、接続設定ができれば、AWSマネージメントコンソールでできていたことがCUIからでも実行可能になります。

スクリーンショット 2019-02-17 17.59.21.png

作成するとアクセスキーIDとシークレットキーが生成されます。これを控えておきます。

では、先ほど生成したアクセスキーIDとシークレットキーを使って接続設定をしましょう。
c.f https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-files.html

~/.aws/credentialsがデフォルトのCLIが読み込む認証情報のファイルなので、ここに先ほどのアクセスキーを記述します。

[default]
aws_access_key_id=AAaAAAAAAAAAAAAAAAAAAAAAAAAAA
aws_secret_access_key=AAAAAAAAAaAAAAAaaBBBBbCCCC

また、~/.aws/configに接続先のリージョンや出力形式を指定しておきます。

[default]
region = ap-northeast-1
output = json

CLIの認証情報の設定についてはこの記事が分かりやすかったです。
公式Documentだとこちらで説明されています。

以下のコマンドで、接続に利用されているアカウント情報(IAM identity)が取得できれば接続できています。

$ aws sts get-caller-identity
{
    "UserId": "ABCDFGHIJKLMN",
    "Account": "1111111111111",
    "Arn": "arn:aws:iam::12345678:user/user1"
}

VPCとサブネットの作成

VPCの作成

スクリーンショット 2019-02-17 20.15.13.png

まずはVPC(Virtual Private Cloud)を作成します。VPCとは、以下の説明がわかりやすいです。
c.f https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/what-is-amazon-vpc.html

Virtual Private Cloud (VPC) は、AWS アカウント専用の仮想ネットワークです。VPC は、AWS クラウドの他の仮想ネットワークから論理的に切り離されており、AWS のリソース(例えば Amazon EC2 インスタンス)を VPC 内に起動できます。VPC の IP アドレス範囲を指定して、サブネットを追加し、セキュリティグループを関連付けて、ルートテーブルを設定できます。

VPCは上述の通り、IPアドレスの範囲を指定して、その範囲でネットワークを更に区切り、サーバーを立ち上げたりすることができます。
IPアドレスの範囲はCIDRブロックを指定する必要があります。ここでは10.0.0.0/16と指定します。
これによってネットワーク部は16ビットなので、10.0.0.0~10.0.255.255の範囲がVPC内に割り振られました。

$ aws ec2 create-vpc --cidr-block 10.0.0.0/16

c.f https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/vpc-subnets-commands-example.html

実際にVPCが作成されたか確認してみましょう。

$ aws ec2 describe-vpcs --filters Name=cidr,Values=10.0.0.0/16
{
    "Vpcs": [
        {
            "CidrBlock": "10.0.0.0/16",
            "DhcpOptionsId": "dopt-41256826",
            "State": "available",
            "VpcId": "vpc-03b2f9f9f97a38c41",
            "InstanceTenancy": "default",
            "CidrBlockAssociationSet": [
                {
                    "AssociationId": "vpc-cidr-assoc-05b4f8516eccd0c8c",
                    "CidrBlock": "10.0.0.0/16",
                    "CidrBlockState": {
                        "State": "associated"
                    }
                }
            ],
            "IsDefault": false
        }
    ]
}

ここで作ったVPCのIDは今後のコマンド引数に利用されることが多いので環境変数に格納します。

$ VPCID="vpc-03b2f9f9f97a38c41"

パブリックサブネットの作成

スクリーンショット 2019-02-17 20.17.24.png

次にサブネットを作成します。サブネットとは、以下の説明がわかりやすいです。

c.f https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/what-is-amazon-vpc.html

サブネットは、VPC の IP アドレスの範囲です。AWS リソースは、指定したサブネット内に起動できます。インターネットに接続する必要があるリソースにはパブリックサブネットを、インターネットに接続しないリソースにはプライベートサブネットを使用してください。

要はVPCのIPアドレスの範囲を分割したものがサブネットです。分割することでそれぞれのサブネットに用途に応じたルーティングをすることができます。
ここでは、VPCのCIDRブロックを10.0.0.0/16としましたが、それを更に区切って10.0.1.0/24とします。
これによってこのサブネットでは10.0.1.0 ~ 10.0.1.255の範囲でIPアドレスを利用することが可能になります。

$ aws ec2 create-subnet --vpc-id $VPCID --cidr-block 10.0.1.0/24
{
    "Subnet": {
        "AvailabilityZone": "ap-northeast-1a",
        "AvailableIpAddressCount": 251,
        "CidrBlock": "10.0.1.0/24",
        "DefaultForAz": false,
        "MapPublicIpOnLaunch": false,
        "State": "pending",
        "SubnetId": "subnet-04dbde66b2861c4bb",
        "VpcId": "vpc-03b2f9f9f97a38c41",
        "AssignIpv6AddressOnCreation": false,
        "Ipv6CidrBlockAssociationSet": []
    }
}

ここで取得したSubnetIdはこれからのコマンド引数に必要になるため、環境変数に格納しておきます。

$ SUBNETID="subnet-04dbde66b2861c4bb"

インスタンスへSSHする

サブネットが作成されたのでその中にインスタンスを立ち上げます。
インスタンスとは仮想サーバーのことです。

ここの説明は公式Documentでもされているので参考になります。
そこにもあるように、作成するには以下の前提条件が必要になります。

  1. セキュリティグループ
  2. キーペア

セキュリティグループとは、仮想ファイアウォールでインスタンスへの通信を送信元や送信先、ポートなどで制限することができるサービスです。
c.f https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/using-network-security.html

キーペアとは、インスタンスへアクセスするための公開鍵と秘密鍵のセットのことで、接続元に秘密鍵を配置し、インスタンスに公開鍵を登録します。
c.f https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-key-pairs.html

スクリーンショット 2019-02-17 20.23.00.png

セキュリティグループを作る

まずはセキュリティグループを作成します。
セキュリティグループは、インスタンス「へ」の通信許可(ingress)とインスタンス「から」の通信許可(engress)をそれぞれ設定できます。
それらの設定では、プロトコル(TCPやUDPなど)、ポート範囲、ingressの場合は送信元、engressの場合は送信先などを指定します。

ここでは、ingressの設定のみ行い、SSHでの22ポートとHTTPによる80ポートへの通信を送信元に関わらず許可します。

$ aws ec2 create-security-group --group-name SSHAccess --description "Security group for SSH access" --vpc-id $VPCID
{
    "GroupId": "sg-0dc191eb2b56d2ffc"
}
$ aws ec2 authorize-security-group-ingress --group-id sg-0dc191eb2b56d2ffc --protocol tcp --port 22 --cidr 0.0.0.0/0
$ aws ec2 authorize-security-group-ingress --group-id sg-0dc191eb2b56d2ffc --protocol tcp --port 80 --cidr 0.0.0.0/0

上記のコマンドではVPCのIDを引数に渡す必要があり、セキュリティグループはVPCごとに存在することがわかります。
そしてこの後見ていくように、そのセキュリティグループをインスタンスが参照するような関係になります。

ちなみに、後述するようにルートテーブルもVPCごとに存在し、それをサブネットが参照するような関係になり、引数の渡し方からAWSサービスの関係性が読み取れます。

では、実際にセキュリティグループが作成されたか確認してみましょう。
この後でも利用するため、セキュリティグループのIDを環境変数に格納しておきます。

$ SGID="sg-0dc191eb2b56d2ffc"

以下のように二つのルールが作成されたことが分かります。

$ aws ec2 describe-security-groups --group-ids $SGID --query 'SecurityGroups[*].IpPermissions'
[
    [
        {
            "FromPort": 80,
            "IpProtocol": "tcp",
            "IpRanges": [
                {
                    "CidrIp": "0.0.0.0/0"
                }
            ],
            "Ipv6Ranges": [],
            "PrefixListIds": [],
            "ToPort": 80,
            "UserIdGroupPairs": []
        },
        {
            "FromPort": 22,
            "IpProtocol": "tcp",
            "IpRanges": [
                {
                    "CidrIp": "0.0.0.0/0"
                }
            ],
            "Ipv6Ranges": [],
            "PrefixListIds": [],
            "ToPort": 22,
            "UserIdGroupPairs": []
        }
    ]
]

キーペアを作る

次に、以下のコマンドでキーペアを作成し、PrivateKeyを標準出力させたものを、ローカルのMyKeyPair.pemファイルに保存します。
そして、管理者に読み取り権限だけ付与します。

$ aws ec2 create-key-pair --key-name MyKeyPair --query 'KeyMaterial' --output text > MyKeyPair.pem
$ chmod 400 MyKeyPair.pem

インスタンスの作成

セキュリティグループとキーペアを作成したので、実際にインスタンスを作成します。
インスタンスとして利用するEC2 AIMを指定する必要があるのですが、これはAWSマネジメントコンソールから確認した方が分かりやすいです。
https://console.aws.amazon.com/ec2/ から「インスタンスの作成」を押すとAMIの一覧が確認でき、それぞれにIDがあることが確認できます。

スクリーンショット 2019-02-17 18.42.12.png

ここでは、ami-0d7ed3ddb85b521a6のIDである無償利用枠のAmazon Linuxを利用します。
以下のコマンドで、先ほど作成したキーペアの名前、セキュリティグループ、サブネットを指定してインスタンスを作成します。

$ aws ec2 run-instances --image-id ami-0d7ed3ddb85b521a6 --count 1 --instance-type t2.micro --key-name MyKeyPair --security-group-ids $SGID --subnet-id $SUBNETID

作成したインスタンスのパブリックIDアドレスを確認します。

$ aws ec2 describe-instances --filters Name=subnet-id,Values=$SUBNETID --query 'Reservations[*].Instances[*].PublicIpAddress'
[
    [
        "13.231.142.47"
    ]
]

これを利用して作成したインスタンスへローカルにあるPrivateKeyを利用し、SSHで入ります。
これは既にセキュリティグループの設定でSSHによる22ポートへのアクセスを許可しているため可能になっています。

$ ssh -i MyKeyPair.pem ec2-user@13.231.142.47
Warning: Permanently added '13.231.142.47' (ECDSA) to the list of known hosts.

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
3 package(s) needed for security, out of 3 available
Run "sudo yum update" to apply all updates.

DNSの設定

先ほどのセキュリティグループの設定でHTTPによる80番ポートへの通信も受け付けるようにしたので、パブリックIPアドレスを指定してHTTPで通信することが可能になりました。(80番ポートで待ち受けるアプリケーションはまだインストールしていません。)

しかし数字の羅列であるIPアドレスは視認性が低いのでドメイン名を用いてアクセスできるようにしておきます。
これをインスタンスに持たせるには、以下のVPCの属性をtrueにする必要があります。

c.f https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/vpc-dns.html#vpc-dns-viewing

  • enableDnsSupport: VPCのDNSサーバーを有効にするかどうか
  • enableDnsHostnames: VPC内に起動されるインスタンスがDNSホスト名を取得するかどうか

実際に以下のコマンドでtrueに更新すると、ドメイン名が付与されていることが分かります。

$ aws ec2 modify-vpc-attribute --vpc-id $VPCID --enable-dns-support "{\"Value\":true}"
$ aws ec2 modify-vpc-attribute --vpc-id $VPCID --enable-dns-hostname "{\"Value\":true}"
$ aws ec2 describe-instances --query 'Reservations[0].Instances[*].PublicDnsName'
[
    "ec2-13-231-142-47.ap-northeast-1.compute.amazonaws.com"
]
$ curl http://ec2-13-231-142-47.ap-northeast-1.compute.amazonaws.com

インスタンスからインターネットの接続する

インスタンスへSSHやHTTPで通信することが可能になりましたが、インスタンスからインターネットにアクセスすることはできません。
理由はVPC外部のネットワークへのパケットの送受信をするインターネットゲートウェイの作成と、そことサブネット内のインスタンスを繋ぐためのルートテーブルの作成がされていないからです。

ルーティングをする

そのため、やるべきことは以下の三つです。

  • VPC内にインターネットゲートウェイを作る
  • サブネット内にルートテーブルを作成する
  • ルートテーブルとインターネットゲートウェイがパケットを送受信できるようにする

まず、インターネットゲートウェイを作ります。

$ aws ec2 create-internet-gateway
{
    "InternetGateway": {
        "Attachments": [],
        "InternetGatewayId": "igw-0f8e69039f7ffbe33",
        "Tags": []
    }
}

そのインターネットゲートウェイをVPCに関連付けます。

$ aws ec2 attach-internet-gateway --vpc-id $VPCID --internet-gateway-id igw-0f8e69039f7ffbe33

スクリーンショット 2019-02-17 20.24.26.png

次にルートテーブルを作成します。

$ aws ec2 create-route-table --vpc-id $VPCID
{
    "RouteTable": {
        "Associations": [],
        "PropagatingVgws": [],
        "RouteTableId": "rtb-0484c8a5f9983fabe",
        "Routes": [
            {
                "DestinationCidrBlock": "10.0.0.0/16",
                "GatewayId": "local",
                "Origin": "CreateRouteTable",
                "State": "active"
            }
        ],
        "Tags": [],
        "VpcId": "vpc-03b2f9f9f97a38c41"
    }
}

上記のようにデフォルトでは10.0.0.0/16というVPC内のネットワークの範囲の宛先の場合は、VPC内のルーター(local)に転送されるようになっています。
つまり、現在のルートテーブルは以下のようになっています。

宛先のCIDRブロック 送られるルーター
10.0.0.0/16 local

このままでは、VPC内以外の宛先の指定をすると、そのパケットは全て破棄されてしまいます。
そのため、上記以外の宛先(0.0.0.0/0)は全てンターネットゲートウェイへを向けるルートをルートテーブルに追加します。

$ aws ec2 create-route --route-table-id rtb-0484c8a5f9983fabe --destination-cidr-block 0.0.0.0/0 --gateway-id igw-0f8e69039f7ffbe33
{
    "Return": true
}
宛先のCIDRブロック 送られるルーター
10.0.0.0/16 local
0.0.0.0/0 igw-0f8e69039f7ffbe33
$ aws ec2 describe-route-tables --route-table-id rtb-0484c8a5f9983fabe --query 'RouteTables[*].Routes'
[
    [
        {
            "DestinationCidrBlock": "10.0.0.0/16",
            "GatewayId": "local",
            "Origin": "CreateRouteTable",
            "State": "active"
        },
        {
            "DestinationCidrBlock": "0.0.0.0/0",
            "GatewayId": "igw-0f8e69039f7ffbe33",
            "Origin": "CreateRoute",
            "State": "active"
        }
    ]
]

しかし、このままでは、サブネットと作成したルートテーブルが関連付けられていないので、サブネットからのトラフィックはこのルートテーブルで処理されません。
そのため、サブネットとルートテーブルを関連付けます。これによって、このサブネットからのトラフィックは関連付けられたルートテーブルを利用するようになります。

$ aws ec2 associate-route-table --subnet-id $SUBNETID --route-table-id rtb-0484c8a5f9983fabe
{
    "AssociationId": "rtbassoc-024fbd16933a7171e"
}

スクリーンショット 2019-02-17 20.29.29.png

更に、サブネット内で起動されたインスタンスがパブリックIPアドレスに自動的で更新されるようにします。

$ aws ec2 modify-subnet-attribute --subnet-id $SUBNETID --map-public-ip-on-launch

これで、インスタンスからVPC外部のネットワークへ通信することができるようになりました。
実際に、インスタンスへSSHで入って、外部のネットワークへ通信してみます。

$ ssh -i MyKeyPair.pem ec2-user@13.231.142.47
$ curl https://aws.amazon.com/jp/

NginxでS3にプロキシする

これで、インスタンスからインターネットに接続できるようになったのでNginxをインストールすることができます。
そのあと、以下の手順で操作していきます。

  • Nginxのインストール
  • S3のバケットの作成
  • S3のポリシーの付与
  • VPCエンドポインtの作成
  • サブネットのルートテーブルへ追加
  • Nginxのプロキシの設定

Nginxのインストールと起動

SSHしてインタンスのコンソールに入り、Nginxをインストールします。

$ ssh -i MyKeyPair.pem ec2-user@13.231.142.47
$ amazon-linux-extras list | grep nginx
  4  nginx1.12=latest         enabled      [ =1.12.2 ]
$ sudo amazon-linux-extras install nginx1.12

そして、Nginxを起動します。

$ sudo systemctl start nginx.service

インスタンスからリクエストを送るとNgixのデフォルトのページが表示されることが確認できます。

$ curl http://localhost
...

S3の作成

スクリーンショット 2019-02-17 20.31.05.png

S3とは、AWSのストレージサービスです。他には静的ウェブサイトのホスティング機能も有します。
そしてS3に先ほど作成したインスタンスからアクセスし、S3にあるアセットを取得するようにします。

S3とインスタンスの通信にはVPCエンドポイントを用います。

c.f https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/vpc-endpoints.html
c.f https://dev.classmethod.jp/cloud/vpc-endpoint-for-s3/

VPC エンドポイントでは、PrivateLink を使用する AWS サービスや VPC エンドポイントサービスに VPC をプライベートに接続できます。インターネットゲートウェイ、NAT デバイス、VPN 接続、または AWS Direct Connect 接続は必要ありません。VPC のインスタンスは、サービスのリソースと通信するためにパブリック IP アドレスを必要としません。VPC と他のサービス間のトラフィックは、Amazon ネットワークを離れません。

これによって、VPC外部のあるAWSサービスへAWSのネットワークを介してアクセスすることが可能になります。
もちろんインターネットゲートウェイ経由でVPC外のAWSサービスと通信することもできますが、その場合よりAWS内のネットワークで通信が閉じるのでセキュアだったり、Privateなサブネットから外部ネットワークに通信するためにNATサーバーを構築する必要がなくなるなどの利点があります。

まず、S3にバケットを作成しましょう。リージョンは同じにしておく必要があります。

$ aws s3api create-bucket --bucket my-nginx-bucket --region ap-northeast-1 --create-bucket-configuration LocationConstraint=ap-northeast-1
{
    "Location": "http://my-nginx-bucket.s3.amazonaws.com/"
}

更に、そのバケットにポリシーを付与して指定のVPCからのみ読み取り専用にします。
c.f https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/example-bucket-policies-vpc-endpoint.html

$ cat << EOF > policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "GetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-nginx-bucket/*",
      "Condition": {
        "StringEquals": {
          "aws:sourceVpc": $VPCID 
        }
      }
    }
  ]
}
EOF

$ aws s3api put-bucket-policy --bucket my-nginx-bucket --policy file://policy.json

そして、表示するためのHTMLを配置します。

$ cat << EOF > sample.html
<html>
  <head>
    <title>タイトル</title>
  </head>
  <body>
    aws cli の練習
  </body>
</html>
EOF
$ aws s3 cp sample.html s3://my-nginx-bucket/
upload: ./sample.html to s3://my-nginx-bucket/sample.html

ポリシーを指定のVPCからのみ読み取り可能にしたので、ローカルから通信できないことが確認できます。

$ curl https://s3-ap-northeast-1.amazonaws.com/my-nginx-bucket/sample.html
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>0FFEB150E2721710</RequestId><HostId>fjGav1kPhVwtD6DZxBqiMW6YWwQkYz3xSN7YyVsbEANd7YC+io+u+1DXfKOaWf/jKw8ZbSGr+lE=</HostId></Error>%

インスタンスからS3に接続する

スクリーンショット 2019-02-17 20.34.12.png

次に、作成したS3バケットにVPCから接続できるようにエンドポイントを作成しましょう。
そして、サブネットが利用するルートテーブルからそのエンドポイントへトラフィックを向けます。

以下のコマンドで、対象のサブネットに関連付けられたルートテーブルのIDとVPCのIDを利用して、エンドポイントを作成します。

$ aws ec2 describe-route-tables --query 'RouteTables[*].RouteTableId' --filter Name=association.subnet-id,Values=$SUBNETID
[
    "rtb-0484c8a5f9983fabe"
]
$ aws ec2 create-vpc-endpoint --vpc-id $VPCID --service-name com.amazonaws.ap-northeast-1.s3 --route-table-ids rtb-0484c8a5f9983fabe
{
    "VpcEndpoint": {
        "VpcEndpointId": "vpce-0663e4cf6645ddfd0",
        "VpcEndpointType": "Gateway",
        "VpcId": "vpc-03b2f9f9f97a38c41",
        "ServiceName": "com.amazonaws.ap-northeast-1.s3",
        "State": "available",
        "PolicyDocument": "{\"Version\":\"2008-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":\"*\",\"Action\":\"*\",\"Resource\":\"*\"}]}",
        "RouteTableIds": [
            "rtb-0484c8a5f9983fabe"
        ],
        "SubnetIds": [],
        "Groups": [],
        "PrivateDnsEnabled": false,
        "NetworkInterfaceIds": [],
        "DnsEntries": [],
        "CreationTimestamp": "2019-02-16T15:50:54.000Z"
    }
}

サブネットのルートテーブルが以下のようになったことが確認できます。

$ aws ec2 describe-route-tables --filter Name=association.subnet-id,Values=$SUBNETID --query 'RouteTables[*].Routes'
[
    [
        {
            "DestinationCidrBlock": "10.0.0.0/16",
            "GatewayId": "local",
            "Origin": "CreateRouteTable",
            "State": "active"
        },
        {
            "DestinationCidrBlock": "0.0.0.0/0",
            "GatewayId": "igw-0f8e69039f7ffbe33",
            "Origin": "CreateRoute",
            "State": "active"
        },
        {
            "DestinationPrefixListId": "pl-61a54008",
            "GatewayId": "vpce-0663e4cf6645ddfd0",
            "Origin": "CreateRoute",
            "State": "active"
        }
    ]
]

つまり、以下のようなルーティングになりました。

宛先のCIDRブロック 送られるルーター
10.0.0.0/16 local
0.0.0.0/0 igw-0f8e69039f7ffbe33
pl-61a54008(S3のバケット) vpce-0663e4cf6645ddfd0(VPCエンドポイント)

インスタンスからS3へエンドポイント経由で通信できるか確認してみましょう。

$ ssh -i MyKeyPair.pem ec2-user@52.199.184.55
$ curl https://s3-ap-northeast-1.amazonaws.com/my-nginx-bucket/sample.html
<html>
  <head>
    <title>タイトル</title>
  </head>
  <body>
    aws cli の練習
  </body>
</html>

NginxからS3へプロキシする

最後に、VPC外部からインスタンス、インスタンスからS3へとそれぞれ通信ができるようになったのでインスタンス上のNginxからS3へプロキシするように設定します。

SSHしてインスタンスに入って、Nginxの設定ファイルを書き換えます。設定ファイルは/etc/nginx/nginx.confになります。

$ ssh -i MyKeyPair.pem ec2-user@13.231.142.47
$ sudo vim /etc/nginx/nginx.conf

以下のlocationの箇所にS3のバケットへプロキシするように設定します。


# /etc/nginx/nginx.conf
...

http {

    ...

    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        # ここを以下のように編集し、対象バケットのHTMLへプロキシされるようにする
        location / {
                proxy_pass      https://s3-ap-northeast-1.amazonaws.com/my-nginx-bucket/sample.html;
                proxy_intercept_errors on;
        }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }

    ...

}
$ sudo systemctl restart nginx.service
$ curl http://localhost
<html>
  <head>
    <title>タイトル</title>
  </head>
  <body>
    aws cli の練習
  </body>
</html>
$ ログアウト
$ curl http://ec2-13-231-142-47.ap-northeast-1.compute.amazonaws.com/
<html>
  <head>
    <title>タイトル</title>
  </head>
  <body>
    aws cli の練習
  </body>
</html>

これで以下のようなアークテクチャーが実現されました!

スクリーンショット 2019-02-17 20.40.02.png

最後に

料金が発生する可能性があるのでインスタンスの停止やVPCの削除など後片付けを忘れないようにしましょう。

3
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
9