AWSを使ってWebスクレイピング用の環境を構築する
モチベーション
前回の記事で、データ収集の環境をAWSを使った方がコストを抑えられそうであることがわかったので、今回は0から実際に環境を構築してみる。
AWS初心者なので構築中に色々トラブったが、最後まで構築できたのでそこで得た知見をまとめてみる。
ゴール
今回作る環境は以下。インターネットからEC2に接続できるようにすること、EC2にスクレイピング用のPython3、Gitをインストールすること、EC2からRDBに接続できることが今回のゴール。
なお、2020年12月に公開されたAWS CloudShellを使ってコマンドベースで環境を構築していく。
(新しいサービスが出たら使ってみようと試みるのが私の流儀)
AWS CloudShellの導入
- AWSマネジメントコンソールにログインし、リージョンをCloudShellが利用できるところ[1]に設定し、ヘッダーにある以下の赤文字で囲ったアイコンをクリックする。
- アイコンクリック後、CloudShellのページに遷移する。デフォルトでAWSCLI、Python、Node.jsなどが使えるようだ。
事前準備はこれだけ。インストールもしなくていいしブラウザだけで準備が終わるのは素晴らしいと思う。
試しにコマンドを打ってみる
お試しで一つコマンドを打ってみる。
CLIのバージョンを確認する
$ aws --version
aws-cli/2.0.58 Python/3.7.3 Linux/4.14.209-160.335.amzn2.x86_64 exec-env/CloudShell exe/x86_64.amzn.2
CLIのバージョンは2のようだ。
実装手順
細かい実装に入る前に、手順を記載する。
- VPCを作成する
- パブリックサブネット、プライベートサブネットを2つずつ作成する
- パブリックサブネットにEC2を構築する
- インターネットゲートウェイを作成する
- VPCにインターネットゲートウェイをアタッチする
- パブリックサブネットのルートテーブルを編集する
- サブネットグループを作成する
- RDSを作成する
- EC2からRDSに接続できるか確認する
- PythonとGitをインストールする
構築
何をするかイメージがついたので、実行していく。
VPCの作成
まずはVPCを作成する。今回は、CIDRブロック10.0.0.0/21を使用する。
(余談だが、AWSのブロックサイズ(/数字の部分)は16~28までなので注意すること。)
aws ec2 create-vpc --cidr-block 10.0.0.0/21
このコマンドを打つと以下のようなJSON形式で出力が返ってくる。その中から、「VpcId」の値をメモしておく。
{
"Vpc": {
"VpcId": "vpc-XXXXXXXXXX"
}
}
パブリックサブネット、プライベートサブネットを2つずつ作成
以下のようなパブリックサブネットとプライベートサブネットを作成する。
サブネット | アベイラビリティゾーン(以下、AZ) | CIDR |
---|---|---|
publicSubnet01 | ap-northeast-1a | 10.0.0.0/24 |
publicSubnet02 | ap-northeast-1c | 10.0.1.0/24 |
privateSubnet01 | ap-northeast-1a | 10.0.2.0/24 |
privateSubnet02 | ap-northeast-1c | 10.0.3.0/24 |
サブネットを作成するコマンド
aws ec2 create-subnetコマンドを使う。その時に指定するパラメータは以下。
パラメータ名 | 意味 |
---|---|
vpc-id | VPCのID |
cidr-block | CIDRブロック |
availability-zone | サブネットの所属先AZ |
例として先ほど作成したVPCに対して、CIDRブロック「10.0.0.0/24」、所属先AZ「ap-northeast-1a」のサブネットを作成する
aws ec2 create-subnet --vpc-id vpc-XXXXXXXXXX --cidr-block 10.0.0.0/24 --availability-zone ap-northeast-1a
作成したサブネットに名前「publicSubnet01」をつけておく
aws ec2 create-tags --resources subnet-XXXXXXXXXX --tags Key=Name,Value=publicSubnet01
ここまででできた構成図は以下。ここまででEC2やRDSを入れるための箱が出来上がったイメージ。
パブリックサブネットにEC2を構築する
ここから実際にEC2の構築を行っていく。
キーペアを作成する
EC2に接続するための鍵を作成する。
aws ec2 create-key-pair --key-name MyKeyPair --query 'KeyMaterial' --output text > MyKeyPair.pem
他のユーザーが読み書きできないようにするため、作成した鍵の権限を変更する。
chmod 400 MyKeyPair.pem
セキュリティグループを作成する
以下のようなセキュリティグループ(以下SG)を作成する。
名前 | タイプ | ポート範囲 | プロトコル | ソース |
---|---|---|---|---|
SSH-SG-1 | SSH | 22 | TCP | 0.0.0.0/0 |
aws ec2 create-security-group --group-name SSH-SG-1 --vpc-id vpc-XXXXXXXXXX
作成に成功したら「GroupId」が返ってくるのでメモする。
{
"GroupId": "sg-XXXXXXXXXX"
}
上のコマンドを叩いただけではSSH接続はできないのでアクセスできるようにルートを追加する。
ルートを追加する
SSHでどこからでもアクセスできるようにする。
--group-idのところは事前に作成したSGのGroupIdを指定する。
aws ec2 authorize-security-group-ingress --group-id sg-XXXXXXXXXX --protocol tcp --port 22 --cidr 0.0.0.0/0
もしHTTPで通信したい場合は--portを80に変更する。
EC2インスタンスを起動する
キーペアとSGを作成したのでEC2を起動してみる。
少しパラメータが複雑なので補足。
パラメータ名 | 意味 |
---|---|
image-id | AMIイメージのID |
count | 起動するインスタンス数 |
instance-type | 起動するインスタンスのタイプ |
key-name | キーペアの名前 |
security-group-ids | 適用するSG |
subnet-id | 起動先のサブネット |
aws ec2 run-instances --image-id ami-0992fc94ca0f1415a --count 1 --instance-type t3a.medium --key-name MyKeyPair --security-group-ids sg-XXXXXXXXXX --subnet-id subnet-XXXXXXXXXX
起動完了に時間がかかるので、完了するまで待つ。
(コマンドを叩くとJSON形式で値が返ってくるのでインスタンスIDを探してメモしておく。)
完了したか確認するためには以下のコマンドを叩いてインスタンスの状態を確認する。
aws ec2 describe-instances --instance-id i-XXXXXXXXXX
ちょっと寄り道
image-idの探し方
マネジメントコンソールから探すやり方とコマンドを叩いて探すやり方がある。私はなんとなく画面から見た方が楽そうだと思ったのでマネジメントコンソールから探した。
マネジメントコンソールから探す
- EC2ダッシュボードの左メニューから「インスタンス」を選択する。
- 画面右上の「インスタンスを起動」を選択する。
- AMIの選択ページに遷移する。image-idがAMI名の横に記載されている。
コマンドで探す
describe-imagesコマンドを叩くことで確認できる。
色々オプションを指定できる。よく使うと思われるオプションの説明を以下に記入する。
パラメータ名 | 意味 |
---|---|
region | リージョン |
owners | イメージのオーナー |
filters | 抽出条件。アーキテクチャやAMIの名前を指定することで特定のAMIを検索できる |
output | 検索結果の出力形式 |
aws ec2 describe-images --region [region] --owners [owner] --filters '[condition]' --output [output]
インターネットゲートウェイを作成する
EC2を起動させることに成功したからと言って安心してはいけない。SSHでEC2に接続するためには、インターネットゲートウェイを使ってインターネットからの接続を受け入れるようにしないといけないからだ。これからインターネットゲートウェイを作成し、インターネットからの接続を受け入れられるようにする。
作り方
create-internet-gatewayコマンドを叩く。
aws ec2 create-internet-gateway
これでインターネットゲートウェイが作成できた。返される出力からInternetGatewayIdをメモしておく。
{
"InternetGateway": {
"InternetGatewayId": "igw-XXXXXXXXXX",
}
}
VPCにアタッチする
最初に作ったVPCにインターネットゲートウェイをアタッチする。
aws ec2 attach-internet-gateway --vpc-id vpc-XXXXXXXXXX --internet-gateway-id igw-XXXXXXXXXX
ルートテーブルを作成する
aws ec2 create-route-table --vpc-id vpc-XXXXXXXXXX
VPC以外の通信の向き先をインターネットゲートウェイにする
aws ec2 create-route --route-table-id rtb-XXXXXXXXXX --destination-cidr-block 0.0.0.0/0 --gateway-id igw-XXXXXXXXXX
ルートテーブルをパブリックサブネットに関連づける
aws ec2 associate-route-table --subnet-id subnet-XXXXXXXXXX --route-table-id rtb-XXXXXXXXXX
Elastic IPアドレスを作成し、EC2に関連づける
IPアドレスを取得する
aws ec2 allocate-address
返ってくる「AllocationId」をメモする。
Elastic IPアドレスを付与する
aws ec2 associate-address --instance-id i-XXXXXXXXXX --allocation-id eipalloc-XXXXXXXXXX
OKだとAssociationIdが返ってくる。
EC2インスタンスに接続する
ssh -i "作成したキーペア" ec2-user@EC2に紐づけられたパブリックIPアドレス
成功したら以下が表示される。
__| __|_ )
_| ( / Amazon Linux 2 AMI
___|\___|___|
https://aws.amazon.com/amazon-linux-2/
これでEC2インスタンスをパブリックサブネット上に起動し、インターネットゲートウェイを経由して自分のPCからSSH接続ができるようになった。現段階の構成図は以下。残るはRDS。
RDSを作成する
構築もいよいよ大詰め。これからRDSを作成する。
サブネットグループを作成する
RDSを作るときにはサブネットグループが必要なので作成する。
aws dax create-subnet-group --subnet-group-name my-subnet-group --subnet-ids subnet-XXXXXXXXXX subnet-XXXXXXXXXX
セキュリティグループを作成する
RDS用のSGを作成する。
aws ec2 create-security-group --group-name RDS-SG-1 --vpc-id vpc-XXXXXXXXXX --description "RDS"
次にインバウンドルールを変更する。
aws ec2 authorize-security-group-ingress --group-id sg-XXXXXXXXXX --protocol tcp --port 3306 --cidr 0.0.0.0/0
RDSインスタンスを作成する
今回作成するRDSの設定は以下。
パラメータ名 | 意味 | 今回設定する値 |
---|---|---|
db-instance-identifier | DB インスタンス識別子 | my-scraping-db-instance |
db-instance-class | 起動するDBインスタンスのクラス | db.t2.micro |
engine | 起動するDBエンジン | MySQL |
engine-version | 起動するDBエンジンのバージョン | 8.0.11 |
allocated-storage | ストレージ容量 | 20 |
master-username | マスターユーザー名 | root |
master-user-password | マスターユーザーのパスワード | password |
backup-retention-period | バックアップ保持期間 | 3 |
engine-version | 起動するDBエンジンのバージョン | 8.0.21 |
vpc-security-group-ids | SG | 上で作成したSG |
availability-zone | AZ | ap-northeast-1a |
publicly-accessible | 外部からのアクセスを許可するか | 許可しない(空白) |
db-subnet-group-name | DBを起動するサブネットグループ名 | my-subnet-group |
aws rds create-db-instance \
--db-instance-identifier my-scraping-db-instance \
--db-instance-class db.t2.micro \
--engine MySQL \
--engine-version 8.0.21 \
--allocated-storage 20 \
--master-username root \
--master-user-password password \
--backup-retention-period 3 \
--vpc-security-group-ids sg-XXXXXXXXXX \
--availability-zone ap-northeast-1a \
--publicly-accessible \
--db-subnet-group-name my-subnet-group
実行してみたらエラーになった。
An error occurred (InvalidVPCNetworkStateFault) when calling the CreateDBInstance operation: Cannot create a publicly accessible DBInstance. The specified VPC does not support DNS resolution, DNS hostnames, or both. Update the VPC and then try again
エラー文言みる限り、DNS名前解決かDNSホスト名が無効になっているっぽいので確認する。
まずはDNS名前解決が有効になっているか確認する。
aws ec2 describe-vpc-attribute --region ap-northeast-1 --vpc-id vpc-XXXXXXXXXX --attribute enableDnsSupport
有効になっていることを確認できた。
{
"VpcId": "vpc-XXXXXXXXXX",
"EnableDnsSupport": {
"Value": true
}
}
DNSホスト名はどうだろうか。
aws ec2 describe-vpc-attribute --region ap-northeast-1 --vpc-id vpc-XXXXXXXXXX --attribute enableDnsHostnames
こちらは無効になっていたのでこれが犯人っぽい。
{
"VpcId": "vpc-XXXXXXXXXX",
"EnableDnsHostnames": {
"Value": false
}
}
犯人がわかったので、DNSホスト名を有効に変更する。
aws ec2 modify-vpc-attribute --region ap-northeast-1 --vpc-id vpc-XXXXXXXXXX --enable-dns-hostnames '{"Value":true}'
有効になったことを確認してから、再度RDSを作成コマンドを打ったら成功した。
これで全てのピースが揃った。あとは疎通確認と必要なツールをインストールする。
EC2からRDSに接続できるか確認する
EC2にログインし、mysqlをインストールする
-- 先にアップデートする。
sudo yum update
sudo yum install mysql
インストールが完了したら末尾に「Complete!」が出てくる。
ログインしてみる
mysql -h <RDSエンドポイント名> -P 3306 -u <マスターユーザ名> -p
無事に接続できた。一安心。
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 17
Server version: 8.0.21 Source distribution
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MySQL [(none)]>
PythonとGitをインストール
総仕上げにPython3とGitをインストールする。
-- Python3のインストール。
sudo yum install python3 -y
-- インストールできたか確認。
python3 --version
-- Gitのインストール。
sudo yum install git
-- インストールできたか確認。
git --version
二つともインストールできたことを確認できたのでこれにて環境構築は終了。
お疲れ様でした!
構築してみた所感
マネジメントコンソールから環境を作っていた時はあまり意識していなかったことがCLIで作った時は考慮しないといけなかったので、かなり大変だったが勉強になった。
また、CLIのエラー文がわかりやすかったため、エラーが出ても特につまづくことなく原因をサクッと掴むことができた。自分はマネジメントコンソールからよりもコマンドを使って環境構築する方が向いているかもしれない。
次回はWebサービスのインフラを構築しようと思う。コマンド叩くのも大変なのでCloudFormationを使って自動化したい。
友人にできたことを伝えてみた
私「前話してたやつ、ちゃんとできたで!」
友人「おぉ、やるやん、ありがとう」
なんかちょっと腹がたったけど「どうも」とだけ返しておいた。
おわり。
-
利用可能なリージョンはUS East(バージニア), US East(オハイオ), US West(オレゴン), Europe(アイルランド),Asia Pacific(東京)の5つ。 ↩︎
Discussion