Amazon VPCを使ったサーバ環境をコマンドラインツールで構築する

2013.05.13

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは植木和樹です。5月8日よりクラスメソッドでの業務を開始しました。これからよろしくお願いします。

さてAWSが提供する各種サービスについていろいろ試していくにあたり、まずは実験できるサーバ環境を作っておくと便利です。というわけで今回はVPCでサーバ環境を構築してみたいと思います。

VPCを使ったサーバ構築手順については、すでに弊社ブログ「Amazon VPCを使ったミニマム構成のサーバ環境を構築する」でAWS Management Consoleによる手順を取り上げています。これではネタがかぶってしまいますので、今回コマンド操作が大好きな私はAmazon EC2 Command Line Tools(以下CLIツール)を使ってコマンドラインで環境構築してみたいと思います。実験環境なので作っては破棄しまた作り直し・・・を何度もすることになると思うので再利用性の高いやり方にしておきたいところです。

今回の構成

VPC内にパブリックとプライベート、2つのサブネットを作成します。

今回は特にミニマム構成を想定していませんので、プライベートサブネットにEC2を1つRDSを1つ、パブリックサブネットにはEC2を1つとプライベートEC2のNAT用インスタンスを1つ、計4インスタンスを作成します。

20130426_vpc_nodes

上の図で青い線がインターネットからPublic Server上のアプリケーションを介してMySQLに接続するまでの通信の流れを表しています。また緑色の線はPrivate ServerがNATインスタンスを通じてインターネットと接続する際の通信の流れを表しています。

環境構築にあたっては以下のブログを参考にしました。先に目を通していただければ、より理解が深まると思いますので是非ご参照ください。("PrivateServer"へは"Public Server"を踏み台にしてssh接続します)

いきなりの結論

具体的な構築手順は後ほどご説明するとして、今回はいきなり結論です。

CLIツールで環境構築はしないことがオススメ

CLIツールでの構築は正直とても面倒でした。構築するだけならManagement Consoleの使用を「強く、強く」オススメします。特にAWSが初めての方はAWS Management Consoleを使ってください。Management ConsoleのGUIはとても良くできていますので、CLIツールよりも早く簡単に構築できるはずです。

なにが面倒だったといいますとVPCやEC2インスタンス作成ごとに生成される各種IDの把握が手間でした。例えばVPCとサブネット、サブネットとEC2インスタンスなど各種リソースを関連づけるときにはコマンドラインオプションでリソースのIDを指定する必要があります。が、このIDは環境を構築する際に決まるため、CLIツールを使った場合にはリソースを作成するたびにIDを調べメモに控えておく作業が必要になります。さらに今回は複数のサブネットやEC2インスタンスを作成したので、どのIDがどのリソースに対応しているかを別途Excelで管理・参照しながら進めていました。
Management ConsoleだとタグやIPアドレスなどメタ情報が表示された項目をプルダウンメニューで選択できるので、この手間を省くことができます。

目的別のツール使い分け

目的別に次のようにツールを使い分けるのが良いかと思います。

とにかく環境を構築したい
・・・AWS Management Consoleを使う
再利用できる環境構築手段を用意したい
・・・CloudFormationのテンプレートを作成する
障害発生時などシェルから部分的に構成を変更したい
・・・シェルからCLIツールを実行する

学習教材としてCLIツールでの環境構築はオススメ

Management Consoleだと初期値になっていたり自動的に関連づけがされている画面でも、CLIツールでは明示的に指定しなければいけません。そのため、その設定にどんな意味があるのか、なにをパラメータで指定してあげなければならないのかを考えるいい機会になったと思います。

設定が足りなかったり、間違っていたりした場合には当然通信できませんので、うまくいかない原因を考える良い訓練にもなります。コマンドでの作業のため、実行したコマンドや実行結果などの作業記録はターミナルのログとして保存しておけますから、後から識者にレビューしてもらいやすい点もメリットです。AWS学習教材の一つとしてコマンドラインでの構築訓練はアリだと感じました。

CLIツールでの環境構築

さて、ここまでで本ブログでやりたかったことと結論はすでに述べました。以降はVPC上でのサーバ環境構築をCLIツールでやる場合はこういう風にするんだよ、という作業記録をご紹介していきます。なにかの機会にみなさまの参考になれば幸いです。

CLIツールの環境準備

CLIツールを使うには環境設定が必要です。今回は作業用EC2インスタンスを別途用意して作業を行いました。Amazon Linuxならツール(Java版)が最初からインストール済みですので、環境変数 AWS_ACCESS_KEY と AWS_SECRET_KEY を設定するだけで始められます。
(IAMユーザの場合は適切な権限を与えておいてください)

以降、特に断りがなければ作業はこの作業用EC2インスタンスで行っています。

作業の流れ

作業自体は結構なボリュームがあるので、最初に全体の流れを把握しておきましょう。

  1. VPCとサブネットの作成
    1. VPCを作成する
    2. サブネットを作成する
    3. Network ACLを設定する
    4. プライベートサブネット用のルートテーブルを作成する
    5. パブリックサブネット用のルートテーブルを作成する
    6. インターネット・ゲートウェイを作成する
    7. パブリックサブネット用ルートテーブルにインターネット・ゲートウェイを設定する
  2. Public Serverの構築
    1. セキュリティグループを作成する
    2. EC2インスタンスを起動する
    3. インスタンスにタグで名前をつける
    4. Elastic IPアドレスを割り当てる
    5. sshで接続できることを確認する
  3. Private Serverの構築
    1. セキュリティグループを作成する
    2. EC2インスタンスを起動する
    3. インスタンスにタグで名前をつける
    4. Public Server経由でsshで接続できることを確認する
  4. NAT Serverの構築
    1. セキュリティグループを作成する
    2. EC2インスタンスを起動する
    3. インスタンスにタグで名前をつける
    4. Elastic IPアドレスを割り当てる
    5. プライベートサブネット用ルートテーブルにNATインスタンスを設定する
    6. Public Server経由でsshで接続できることを確認する
    7. Private Serverでyumが使えることを確認する
  5. RDSインスタンスの起動
    1. セキュリティグループを作成する
    2. DB用パラメータグループを作成する
    3. DB用サブネットグループを作成する
    4. RDSインスタンスを起動する
    5. Public Serverからmysqlで接続できることを確認する

VPCとサブネットの作成

VPCを作成する

CIDR形式で使用するネットワークアドレスを指定します。コマンド実行結果としてVPC IDが表示されます。後々のコマンドでVPCを指定する際に使用しますのでvpc-で始まるIDをメモしておきましょう。

$ ec2-create-vpc 10.0.0.0/16
VPC     vpc-fdf9e794     pending     10.0.0.0/16     dopt-f1f9e798     default

サブネットを作成する

サブネットを3つ作成します。コマンド実行結果としてSUBNET IDが表示されます。後々のコマンドでサブネットを指定する際に使用しますのでsubnet-で始まるIDをメモしておきましょう。

「今回の構成」でも書きましたが3つ目のサブネットはRDS用に使いますので、プライベートサブネットとは異なるAZを指定してあげる必要があります。

$ ec2-create-subnet --vpc vpc-fdf9e794 --cidr 10.0.0.0/24
SUBNET     subnet-2af6e843     pending     vpc-fdf9e794     10.0.0.0/24     251     ap-northeast-1a         
$ ec2-create-subnet --vpc vpc-fdf9e794 --cidr 10.0.1.0/24
SUBNET     subnet-22f6e84b     pending     vpc-fdf9e794     10.0.1.0/24     251     ap-northeast-1a         
$ ec2-create-subnet --vpc vpc-fdf9e794 --cidr 10.0.2.0/24 --availability-zone ap-northeast-1c
SUBNET     subnet-c08f91a9     pending     vpc-fdf9e794     10.0.2.0/24     251     ap-northeast-1c

Network ACLを設定する

Network ACLはVPC作成時に自動的に作成されます。このデフォルトのACLは全てのInbound/Outboundの通信を許可します。今回通信の可否はセキュリティグループで設定しますので、このままデフォルトのACLを使用することにします。

プライベートサブネット用のルートテーブルを作成する

ルート・テーブルもACLと同様、自動的に1つ作成されます。これはメイン・ルート・テーブルになっていて、サブネットに対して明示的にルート・テーブルを指定しなかった場合にデフォルトで使用されます。

今回はこのメイン・ルート・テーブルをプライベートネットワーク用として使用することにします。なおルート・テーブルIDが後々必要になりますので以下のコマンドで確認し、rtb-で始まるIDをメモしておいてください。

$ ec2-describe-route-tables

パブリックサブネット用のルートテーブルを作成する

パブリックサブネット用のルートテーブルを作成し、パブリック・サブネットに紐付けます。対象のVPCやサブネットには先ほどメモしておいたIDを指定してください。

$ ec2-create-route-table vpc-fdf9e794
ROUTETABLE     rtb-bd9a84d4     vpc-fdf9e794
ROUTE     local          active     10.0.0.0/16          CreateRouteTable
$ ec2-associate-route-table  rtb-bd9a84d4 --subnet subnet-2af6e843
ASSOCIATION     rtbassoc-c19b85a8     rtb-bd9a84d4     subnet-2af6e843

インターネット・ゲートウェイを作成する

インターネット・ゲートウェイを作成し、VPCに紐付けます。igw-で始まるIDをメモしておきましょう。

$ ec2-create-internet-gateway
INTERNETGATEWAY     igw-27f0ee4e
$ ec2-attach-internet-gateway igw-27f0ee4e --vpc vpc-fdf9e794
ATTACHMENT     vpc-fdf9e794     attaching

パブリックサブネット用ルートテーブルにインターネット・ゲートウェイを設定する

作成したインターネット・ゲートウェイをパブリック・サブネットのデフォルト・ゲートウェイ(0.0.0.0/0)に設定します。

$ ec2-create-route rtb-bd9a84d4 --gateway igw-27f0ee4e --cidr 0.0.0.0/0
ROUTE     igw-27f0ee4e               0.0.0.0/0

ここまででVPCと各サブネットの作成は完了です、次に各サブネットにEC2インスタンスを作成していきます。

Public Serverの構築

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

インターネットからSSH(tcp/22), HTTP(tcp/80)の接続を許可します。セキュリティグループ作成時に表示されるID(sg-7bced717)は、後ほど他のセキュリティグループを設定する際にも使用しますのでメモしておいてください。

$ ec2-create-group my-sg-test-pub --vpc vpc-fdf9e794 -d "SG for public server"
GROUP     sg-7bced717     my-sg-test-pub     SG for public server
$ ec2-authorize sg-7bced717 -P tcp -p 22
GROUP     sg-7bced717                   
PERMISSION               ALLOWS     tcp     22     22     FROM     CIDR     0.0.0.0/0     ingress
$ ec2-authorize sg-7bced717 -P tcp -p 80
GROUP     sg-7bced717                   
PERMISSION               ALLOWS     tcp     80     80     FROM     CIDR     0.0.0.0/0     ingress

EC2インスタンスを起動する

Public ServerのOSにはAmazon Linuxを使用しました。インスタンスタイプはt1.microです。

EC2インスタンスをVPC内に作成するので --subnet でVPCサブネットを指定します。VPCを利用する場合セキュリティグループ(--group)には名前でなくID(sg-XXXX)で指定する必要がありますので注意してください。

コマンドの実行結果は載せていませんが、インスタンスの作成が成功するとインスタンスIDが表示されます。i-で始まるIDをメモしておいてください。

$ ec2-run-instances \
  --subnet subnet-2af6e843 \
  --group sg-7bced717 \
  --instance-type t1.micro \
  --instance-count 1 \
  --key <MY_KEYNAME> \
  ami-173fbf16

インスタンスにタグで名前をつける

あとでAWS Management Consoleなどを見たときに区別しやすいよう、EC2インスタンスには名前をつけておきましょう。

$ ec2-create-tags i-3f1fcb3d --tag Name=public
TAG     instance     i-3f1fcb3d     Name     public

Elastic IPアドレスを割り当てる

Elastic IPはVPCで使用する場合 --domain vpc の指定が必要です。またIP発行結果として eipalloc-XXXXXXXX というIDが表示されます。このIDをEC2インスタンスに割り当てる際に --allocation-id で指定します。

$ ec2-allocate-address --domain vpc
ADDRESS     54.249.XXX.XXX          vpc     eipalloc-fff3ed96     
$ ec2-associate-address --instance  i-3f1fcb3d --allocation-id eipalloc-fff3ed96
ADDRESS          i-3f1fcb3d     eipalloc-fff3ed96     eipassoc-d6f0eebf

sshで接続できることを確認する

ここまででPublic Serverの構築は完了です。Elastic IPを指定してsshでログインできることを確認しましょう。

Private Serverの構築

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

Public ServerからのみSSH(tcp/22), SNMP(udp/161)の接続を許可します。接続元をPublic Serverからのみに限定するには、Public Server作成時に指定したセキュリティグループID(sg-7bced717)を利用します。

$ ec2-create-group my-sg-test-pri --vpc vpc-fdf9e794 -d "SG for private server"
GROUP     sg-75ced719     my-sg-test-pri     SG for private server

$ ec2-authorize sg-75ced719 -P tcp -p 22 --source-or-dest-group sg-7bced717
GROUP     sg-75ced719                   
PERMISSION               ALLOWS     tcp     22     22     FROM     USER               ID sg-7bced717     ingress
$ ec2-authorize sg-75ced719 -P udp -p 161 --source-or-dest-group sg-7bced717 
GROUP     sg-75ced719                   
PERMISSION               ALLOWS     udp     161     161     FROM     USER               ID sg-7bced717     ingress

EC2インスタンスを起動する

Public Serverと同じくAmazon Linuxを使用します。異なる点はサブネット(--subnet)とセキュリティグループ(--group)の2カ所です。

$ ec2-run-instances \
  --subnet subnet-22f6e84b \
  --group sg-75ced719 \
  --instance-type t1.micro \
  --instance-count 1 \
  --key <MY_KEYNAME> \
  ami-173fbf16

インスタンスにタグで名前をつける

あとでAWS Management Consoleなどを見たときに区別しやすいよう、EC2インスタンスには名前をつけておきましょう。

$ ec2-create-tags i-2118cc23 --tag Name=private
TAG     instance     i-2118cc23     Name     private

Public Server経由でsshで接続できることを確認する

ここまででPrivate Serverの構築は完了です。Public Serverを踏み台にしてsshでログインできることを確認しましょう。

【参考】Amazon VPC環境にメンテナンス用の踏み台サーバを構築する

NATサーバの構築

Private ServerはElastic IPを持たないため外部と通信できずyumなどが使用できません。NATサーバ経由で通信できるようにしましょう。

【参考】Amazon VPCでELBとNATを使ってよりセキュアな環境を作る【5日目】

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

NATサーバは次の2つの通信のみ許可します。

  • Private ServerからのHTTP(tcp/80) ... yumのため
  • Public ServerからのSSH(tcp/22)

それぞれ接続元を限定するためにSUBNET IDを指定します。

$ ec2-create-group my-sg-test-nat --vpc vpc-fdf9e794 -d "SG for NAT (public subnet)"
GROUP     sg-c9c0d9a5     my-sg-test-nat     SG for NAT (public subnet) 

$ ec2-authorize sg-c9c0d9a5 -P tcp -p 80 --source-or-dest-group sg-75ced719
GROUP   sg-c9c0d9a5
PERMISSION                      ALLOWS  tcp     80      80      FROM    USER               ID sg-75ced719     ingress
$ ec2-authorize sg-c9c0d9a5 -P tcp -p 22 --source-or-dest-group sg-7bced717
GROUP     sg-c9c0d9a5                   
PERMISSION               ALLOWS     tcp     22     22     FROM     USER                ID sg-7bced717     ingress

EC2インスタンスを起動する

NATサーバ用のインスタンスにはAmazonで提供しているNAT用AMI(ami-12d86d13)を使用します。Public Server用EC2インスタンスの作成コマンドと異なる点はセキュリティグループ(--group)とAMIの2カ所です。

$ ec2-run-instances \
  --subnet subnet-2af6e843 \
  --group sg-c9c0d9a5 \
  --instance-type t1.micro \
  --instance-count 1 \
  --key <MY_KEYNAME> \
  ami-12d86d13

インスタンスにタグで名前をつける

あとでAWS Management Consoleなどを見たときに区別しやすいよう、EC2インスタンスには名前をつけておきましょう。

$ ec2-create-tags i-fdf92eff --tag Name=nat
TAG     instance     i-fdf92eff     Name     nat

Elastic IPアドレスを割り当てる

Public Serverの時と同様の手順で、Elastic IPをNATサーバに割り当てます。

$ ec2-allocate-address --domain vpc
ADDRESS     54.249.XXX.XXX          vpc     eipalloc-1339217a              
$ ec2-associate-address --instance   i-fdf92eff --allocation-id eipalloc-1339217a
ADDRESS          i-fdf92eff     eipalloc-1339217a     eipassoc-f1392198

プライベートサブネット用ルートテーブルにNATインスタンスを設定する

Private Serverが外部と接続する際に、NATインスタンスを経由するようプライベートサブネット用ルートテーブルを設定します。--gateway でなく --instance で指定するところがポイントです。

$ ec2-create-route rtb-fff9e796 --instance i-fdf92eff --cidr 0.0.0.0/0
ROUTE		i-fdf92eff		0.0.0.0/0

Public Server経由でsshで接続できることを確認する

これでNATサーバの準備ができました。Public Serverを踏み台にしてsshでログインできることを確認しましょう。

Private Serverでyumが使えることを確認する

NATサーバが起動していれば、Private ServerもVPCの外部に接続できるようになっているはずです。Private Serverにsshでログインしyumが使えるか確認しましょう。

RDSインスタンスの起動

プライベートサブネット内にRDS(MySQL)インスタンスを作成します。

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

Public ServerからのみMySQL(tcp/3306)の接続を許可します。

$ ec2-create-group my-sg-mysql --vpc vpc-fdf9e794 -d "SG for mysql (private subnet)"
GROUP     sg-1bc1d877     my-sg-mysql     SG for mysql (private subnet)

$ ec2-authorize sg-1bc1d877 -P tcp -p 3306 --source-or-dest-group sg-7bced717
GROUP     sg-1bc1d877                   
PERMISSION               ALLOWS     tcp     3306     3306     FROM     USER               ID sg-7bced717     ingress

DB用パラメータグループを作成する

$ rds-create-db-parameter-group my-dbpg-test-mysql55 \
  --db-parameter-group-family mysql5.5 \
  -d "DB ParameterGroup for testdb(mysql-5.5)"
DBPARAMETERGROUP  my-dbpg-test-mysql55  mysql5.5  DB ParameterGroup for testdb(mysql-5.5)

DB用サブネットグループを作成する

RDSをMulti-AZ構成にする場合にレプリケーションが作成される複数のAZを「サブネットグループ」として定義します。--db-subnet-list にVPCサブネットのIDを最低2つ以上指定してください。

$ rds-create-db-subnet-group \
  --db-subnet-group-name my-dsg-test \
  --db-subnet-group-description "DB SubnetGroup for test" \
  --db-subnet-list subnet-22f6e84b,subnet-c08f91a9
SUBNETGROUP  my-dsg-test  DB SubnetGroup for test  Complete  vpc-fdf9e794
      SUBNET  subnet-c08f91a9  ap-northeast-1c  Active
      SUBNET  subnet-22f6e84b  ap-northeast-1a  Active

RDSインスタンスを起動する

MySQLのサーバ名は testsv、MySQLデータベース名は testdb にします。今回はテストのためバックアップはひとまず無効にしています。

$ rds-create-db-instance testsv \
  --db-subnet-group-name my-dsg-test \
  --vpc-security-group-ids sg-1bc1d877 \
  --db-instance-class db.t1.micro \
  --engine mysql \
  --db-parameter-group-name my-dbpg-test-mysql55 \
  --db-name testdb \
  --master-username testuser \
  --master-user-password testuser \
  --allocated-storage 5 \
  --backup-retention-period 0
DBINSTANCE  testsv  db.t1.micro  mysql  5  testuser  creating  0  ****  n  5.5.27  general-public-license  n
      VPCSECGROUP  sg-1bc1d877  active
SUBNETGROUP  my-dsg-test  DB SubnetGroup for test  Complete  vpc-fdf9e794
      SUBNET  subnet-c08f91a9  ap-northeast-1c  Active
      SUBNET  subnet-22f6e84b  ap-northeast-1a  Active
      PARAMGRP  my-dbpg-test-mysql55  in-sync
      OPTIONGROUP  default:mysql-5-5  in-sync

Public Serverからmysqlで接続できることを確認する

Public Serverにsshでログインして、mysqlコマンドで接続できるか確認します。

$ sudo yum -y install mysql
$ mysql -u testuser -ptestuser -h testsv.c9cxowny4ezp.ap-northeast-1.rds.amazonaws.com testdb