Terraformを使ってAWS上にCOVID-19 追跡Web Appをデプロイしてみました

2022年8月31日掲載

キービジュアル

皆さんこんにちは。クラウドエンジニアのKangです。

この記事では、Terraformを利用して必要なリソースをAWS上で構築し、EC2、NodeJS、RDS-MySQLを組み合わせることで、クラウドネイティブCovid19追跡 Webアプリをデプロイする方法を紹介していきます。

目次

  • この記事では、ステップバイステップで解説する初心者向けの記事です
  • AWS EC2にTerraformを使ってアプリケーションをデプロイする方法を紹介します
  • アプリケーションは Covid-19 Tracker を使用します。


依然、新型コロナが猛威を振るっていますね。記事執筆時の2022年8月末現在でも、新型コロナ感染者数が日々増加し続いており、感染者数が気になる方は多くいらっしゃると思います。一方でタイムリーに感染者数の情報が入手できないこともあると思います。

この情報収集に関する課題をクラウドサービスを使って解決できたらと思い、「Covid-19 Tracker」をAWSにデプロイ、感染者数情報の収集する手順をご紹介したいと思います。

この「Covid-19 Tracker」は、有志の方たちがGitHubで公開している感染者数を収集・閲覧するためのウェブアプリケーションです。COVID-19 の拡散と影響を視覚化し、毎日の更新を購読し、統計を表示することができます。

これを利用すれば、すぐに最新の感染者数状況を把握できます。また、日本国内だけではなく、世界中の感染データも簡単に手に入れることができます。

また、デプロイにはTerraformを使い、「IaC (Infrastructure as Code)」の便利さ・素晴らしさも体感してもらいたいと思います。

構成図

実現するにあたって、Terraformを利用して必要なリソースをAWS上で構築し、EC2、NodeJS、RDS-MySQLを組み合わせることで、クラウドネイティブCovid19追跡 Webアプリをデプロイする方法を紹介させていただきます。

1. Terraform によるリソースの作成

1.1 Terraform をインストールする

(Terraform がすでにインストールされている場合は、この手順をスキップしてください)

デスクトップに terraform CLI 環境をセットアップします。 Terraform CLI のセットアップ方法に関するチュートリアルについては下記のドキュメントを参照してください。

Install and configure Terraform on your computer

 

Terraform を初めて使用する場合は、Githubの alibabacloud-howto  /  terraform-templates を参照して、さまざまなオペレーティング システムに Terraform のインストール方法及び使い方を確認してください。 (どちらもAlibabaCloudのドキュメントで、今回の手順と直接関係ありませんが、とても参考になりました。)

1.2 アクセスキーの作成

以下に示すように、AWSコンソールにログインし、[セキュリティ認証情報] をクリックします。

[新しいアクセス キーの作成] をクリックします。 AccessKey が正常に作成されると、[アクセス キーの表示]により、アクセスキー IDとシークレットアクセスキーを確認できます。AWSAccessKeyID と AWSSecretKey は後で使用するので、メモしておいてください。

1.3 秘密鍵・公開鍵を作成する

Terraform がインストールされている環境で以下のコマンドで2つのファイルが作成されます。
EC2にssh接続する際に必要になるので、先に作成しておきましょう。

  • covid19
  • covid19.pub
$ ssh-keygen -t rsa -f covid19 -N ''

出力

Generating public/private rsa key pair.
Your identification has been saved in covid19.
Your public key has been saved in covid19.pub.
The key fingerprint is:
SHA256:DeQAbvjw3YynDp417c9DALmVWjiEsEoP4Tf80g68g1c 
root@ip-172-31-3-200.ap-northeast-1.compute.internal
The key's randomart image is:
+---[RSA 2048]----+
| ....+oo..       |
|. o+. =++        |
| +++o  Bo        |
|..==+.o+.o       |
|.  =oEo S..      |
|  . *  +  .      |
| . +..+ ..       |
|  ...= o ..      |
|    o . ..o.     |
+----[SHA256]-----+

1.4 AWS CLIのprofile追加

$ aws configure --profile covid19 

先程メモしたAWSAccessKeyID と AWSSecretKeyを入力します。

1.5 Terraform設定ファイルを作成する

はじめに任意の作業ディレクトリに移動します。本記事は下記ディレクトリ構成で作成しています。

  • ディレクトリ構成

.
|-- terraform
|   |-- provider.tf
|   |-- vpc.tf
|   |-- ec2.tf
|   |-- terraform.output.tf
|   |-- rds.tf
`-- ssh
    |-- covid19
    |-- covid19.pub

 

  • 各種ファイル説明

ファイル名

役割

provider.tf

プロバイダーや、AccessKeyなどの定義ファイル

ec2.tf

EC2の定義ファイル

vpc.tf

VPCネットワークの定義ファイル

terraform.output.tf

EC2のパブリックIPを出力するファイル

rds.tf

RDSインスタンスの定義ファイル

covid19

SSH秘密鍵

covid19.pub

SSH公開鍵

provider.tf

# ====================
#                                          
# Provider  
#                                                    
# ====================                                          
provider "aws" {                                                
  profile = "covid19"                                           
  region  = "ap-northeast-1"                                    
}

ec2.tf

# ====================
#
# AMI
#
# ====================

# 最新版のAmazonLinux2のAMI情報

data "aws_ami" "covid19" {
  most_recent = true
  owners      = ["amazon"]
  filter {
    name   = "architecture"
    values = ["x86_64"]
  }
  filter {
    name   = "root-device-type"
    values = ["ebs"]
  }
  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*"]
  }
  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
  filter {
    name   = "block-device-mapping.volume-type"
    values = ["gp2"]
  }
  filter {
    name   = "state"
    values = ["available"]
  }
}

# ====================
#
# EC2 Instance
#
# ====================
resource "aws_instance" "covid19" {
  ami                    = data.aws_ami.covid19.image_id
  vpc_security_group_ids = [aws_security_group.covid19.id]
  subnet_id              = aws_subnet.covid19.id
  key_name               = aws_key_pair.covid19.id
  instance_type          = "t2.micro"
  tags = {
    Name = "covid19"
  }
}

# ====================
#
# Elastic IP
#
# ====================
resource "aws_eip" "covid19" {
  instance = aws_instance.covid19.id
  vpc      = true
}

# ====================
#
# Key Pair
#
# ====================
resource "aws_key_pair" "covid19" {
  key_name   = "covid19"
  public_key = file("./covid19.pub")
 # 先程`ssh-keygen`コマンドで作成した公開鍵を指定
}


vpc.tf

# ====================
#
# VPC
#
# ====================

resource "aws_vpc" "covid19" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true # DNS解決を有効化
  enable_dns_hostnames = true # DNSホスト名を有効化
  tags = {
    Name = "covid19"
  }
}
# ====================
#
# Subnet
#
# ====================

# Public
resource "aws_subnet" "covid19" {
  cidr_block        = "10.0.1.0/24"
  availability_zone = "ap-northeast-1a"
  vpc_id            = aws_vpc.covid19.id
  # trueにするとインスタンスにパブリックIPアドレスを自動的に割り当ててくれる
  map_public_ip_on_launch = true
  tags = {
    Name = "covid19"
  }
}
# Private
resource "aws_subnet" "private-db1" {
  vpc_id            = aws_vpc.covid19.id
  cidr_block        = "10.0.2.0/24"
  availability_zone = "ap-northeast-1a"
  tags = {
    Name = "private-db1"
  }
}
resource "aws_subnet" "private-db2" {
  vpc_id            = aws_vpc.covid19.id
  cidr_block        = "10.0.3.0/24"
  availability_zone = "ap-northeast-1c"
  tags = {
    Name = "private-db2"
  }
}

# ====================
#
# Internet Gateway
#
# ====================
resource "aws_internet_gateway" "covid19" {
  vpc_id = aws_vpc.covid19.id
  tags = {
    Name = "covid19"
  }
}

# ====================
#
# Route Table
#
# ====================
resource "aws_route_table" "covid19" {
  vpc_id = aws_vpc.covid19.id
  tags = {
    Name = "covid19"
  }
}
resource "aws_route" "covid19" {
  gateway_id             = aws_internet_gateway.covid19.id
  route_table_id         = aws_route_table.covid19.id
  destination_cidr_block = "0.0.0.0/0"
}
resource "aws_route_table_association" "covid19" {
  subnet_id      = aws_subnet.covid19.id
  route_table_id = aws_route_table.covid19.id
}
# ====================
#
# Security Group
#
# ====================
resource "aws_security_group" "covid19" {
  vpc_id = aws_vpc.covid19.id
  name   = "covid19"
  tags = {
    Name = "covid19"
  }
}

# インバウンドルール(ssh接続用)
resource "aws_security_group_rule" "in_ssh" {
  security_group_id = aws_security_group.covid19.id
  type              = "ingress"
  cidr_blocks       = ["0.0.0.0/0"]
  from_port         = 22
  to_port           = 22
  protocol          = "tcp"
}

# インバウンドルール(pingコマンド用)
resource "aws_security_group_rule" "in_icmp" {
  security_group_id = aws_security_group.covid19.id
  type              = "ingress"
  cidr_blocks       = ["0.0.0.0/0"]
  from_port         = -1
  to_port           = -1
  protocol          = "icmp"
}

# アウトバウンドルール(全開放)
resource "aws_security_group_rule" "out_all" {
  security_group_id = aws_security_group.covid19.id
  type              = "egress"
  cidr_blocks       = ["0.0.0.0/0"]
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
}


terraform.output.tf

# ====================
#
# Output
#
# ====================
# apply後にElastic IPのパブリックIPを出力する

output "public_ip" {
  value = aws_eip.covid19.public_ip
}

rds.tf

# ====================
#
# RDS
#
# ====================
resource "aws_db_subnet_group" "praivate-db" {  
    name        = "praivate-db"  
    subnet_ids  = ["${aws_subnet.private-db1.id}", "${aws_subnet.private-db2.id}"]  
    tags = {  
        Name = "praivate-db"  
    }  
}  

# DBエンジン、バージョン、DB名、ユーザ名、パスワードなどの情報を定義する
resource "aws_db_instance" "covid19" {  
  identifier           = "covid19"  
  allocated_storage    = 20  
  storage_type         = "gp2"  
  engine               = "mysql"  
  engine_version       = "5.7.23"  
  instance_class       = "db.t3.micro"  
  name                 = "covid19db"  
  username             = "covid19"  
  password             = "covid19test!"  
  vpc_security_group_ids  = ["${aws_security_group.covid19.id}"]  
  db_subnet_group_name = "${aws_db_subnet_group.praivate-db.name}"  
  skip_final_snapshot = true  
}

1.6 Terraformコマンドを実行しAWSリソースを作成する

次のコマンドを入力し、terraformプラグインを初期化します。

$ terraform init

次のコマンドを入力し、terraformの構文・パラメータチェックを行います。

$ terraform plan

次のコマンドを入力し、terraformを実行します。

$ terraform apply

途中で入力を求められるため、yesと入力してEnterキーを押しましょう。

これでリソースの作成が完了します。

2. NodeJSのインストール

今回はCovid-19追跡WebAppを動作させる為のプラットフォームとして、NodeJSとSparkpostを利用しております。

AWS EC2コンソールに戻ると、先程Terraformで作成した新しい EC2インスタンスが表示され、インスタンスにリモートでログインします。

先程作成した秘密鍵でEC2にログインします。

# ssh -i covid19 ec2-user@xxx.xxx.xxx.xxx -p22

次のコマンドを入力して、nodejs インストール パッケージをダウンロードします。

wget https://nodejs.org/dist/v14.17.1/node-v14.17.1-linux-x64.tar.xz

次のコマンドを入力して、ダウンロードされた パッケージを展開します。

tar -xf node-v14.17.1-linux-x64.tar.xz

次のコマンドを入力して、コマンド ソフト リンクを作成します。

sudo ln -s /home/ec2-user/node-v14.17.1-linux-x64/bin/node /usr/bin/
sudo ln -s /home/ec2-user/node-v14.17.1-linux-x64/bin/npm /usr/bin/

次のコマンドを入力して、ノードのバージョンを確認します。

node -v
npm -v

3. WebAPPプロジェクトのインストール

3.1 プロジェクトのダウンロード

次のコマンドを入力して、git をインストールします。

sudo yum update && yum -y install git

次のコマンドを入力して、サンプル プロジェクトをプルします。

git clone https://github.com/yankidank/covid-19-tracker.git

次のコマンドを入力して、プロジェクト ディレクトリに入ります。

cd covid-19-tracker

次のコマンドを入力して、プロジェクトの依存関係をインストールします。

sudo npm install --unsafe-perm

3.2 データのインポート

次の図を参照して、AWS RDS コンソールに移動します。

DB識別子である「covid19」のリンクをクリックして、データベースの接続エンドポイント及びポートなどの情報を確認できます。

EC2 コマンド ラインに戻り、 mysql clientコマンドをインストールします。

インストール方法に手間取ってしまったので、筆者は以下の記事を参考にさせていただきました。

【AWS EC2】Amazon Linux2にMySQLのclientだけをインストールしてRDSに接続する方法 (Qiita @tamorieeeen)

次のコマンドを入力して、RDSインスタンス データベースにログインします。 YOUR-RDS-ENDPOINT をユーザ自身の RDS インスタンスの接続エンドポイントに置き換えるように注意してください。

mysql -hYOUR-RDS-ENDPOINT -ucovid19 -pcovid19test! 

次のコマンドを入力して、先程作成したcovid19dbに切り替えます。

mysql> use covid19db;

次のコマンドを入力して、「stats」テーブルを作成します。

CREATE TABLE stats
(
    id int NOT NULL AUTO_INCREMENT,
    FIPS INTEGER NULL,
    Admin2 VARCHAR(100) NULL,
    city VARCHAR(100) NULL,
    province VARCHAR(500) NULL,
    country VARCHAR(100) NULL,
    confirmed INTEGER default 0,
    deaths INTEGER default 0,
    recovery INTEGER default 0,
    last_update datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
    latitude Decimal(18,15) NULL,
    longitude Decimal(18,15) NULL,
    active INTEGER NULL,
    combined_key VARCHAR(500) NULL,
    primary key(id)
);

次のコマンドを入力して、データベース接続を終了して、EC2のコマンドラインに戻ります。

exit

次のコマンド を入力して構成ファイルを開き、次の図を参照してデータベースの接続構成を変更します。

 vim config/config.json

次のコマンドを入力して構成ファイルを開き、データベースの接続構成も変更します。

vim csv_to_mysql/read-file-4.js

次のコマンドを入力してスクリプト ファイルを実行し、データをデータベースにインポートします。

cd csv_to_mysql
node read-file-4.js

3.3 Sparkpost Keyを取得する

SparkPost は開発者中心のメール配信サービスです。 全てのメール送受信は API を使用して行うことができます。

今回はSparkpos 公式 Web サイトにアカウントを登録してログインする必要があります。

https://www.sparkpost.com/

ログインした後、[Configuration]をクリックして KEY を作成してください。

3.4 Web Appを実行する

EC2 コマンドラインに戻ります。コマンド「vim /etc/profile」を入力し、ファイルの末尾に次の内容を追加します。 YOUR-API-KEY と YOUR-SECRET を自分のものに置き換えるように注意してください。

sudo vim /etc/profile
export SPARKPOST_API_KEY=YOUR-API-KEY
export LOGIN_SECRET=YOUR-SECRET

次のコマンドを入力して、変更を有効にします。

source /etc/profile

次のコマンドを入力して、アプリケーションを起動します。

cd /root/covid-19-tracker
node server.js

EC2の パブリック IP アドレスを使用してブラウザにアクセスします。

http://<EC2_IP>:8080

上記の画面が表示されたら起動に成功したことを示しています。

日本のヒートマップも表示することが可能です。

4.さいごに

AWS環境におけるリソース作成時の留意事項を少し纏めました。

・AWSの認証情報

provider.tf設定ファイルに、AWSのアクセスキーID・シークレットアクセスキーを直接指定しているサンプルコードをたまに見かけますが、流出の危険等もあるため、基本的には`aws configure`コマンドでprofileを設定して使うようにしましょう。

・アベイラビリティゾーン

RDSの作成には複数のアベイラビリティゾーンの指定が必要です。単一では作成できません。本記事執筆時点で日本リージョンの場合、以下から2つのアベイラビリティゾーンを指定する必要があります。

zones: ap-northeast-1c, ap-northeast-1a, ap-northeast-1d.

・RDSへのアクセス

MySQLコマンドによりRDSデータベースに接続時及びデータをRDSにインポートする前に、RDSのセキュリティグループ設定で、該当IPからのアクセス許可設定が必要です。そうしないと、タイムアウトエラーが発生してしまい前に進められません。

Terraformは本当に便利なツールですね。最初はリソースを追加で作成する時、前利用していた*.tfファイルをそのまま利用すると、セキュリティグループidやVPC idなどと重複してしまい、エラーが発生するのではないかと心配したんですが、試してみたら、新規リソースを追加時、Terraformは前作成したリソースの差分と比較しているようで、前のtfファイルをそのまま利用しても全然問題なかったです。一度Terraformを利用すると離れられなくなりますね。

 

本記事ではTerraformにより簡単にAWS上でEC2とRDSを作成し、Covid19追跡のWebアプリケーションのデプロイ方法を纏めました。興味を持っている方はぜひお試しいただければ幸いです。

関連サービス

Amazon Web Services (AWS)

ソフトバンクはAWS アドバンストティアサービスパートナーです。「はじめてのAWS導入」から大規模なサービス基盤や基幹システムの構築まで、お客さまのご要望にあわせて最適なAWS環境の導入を支援します。

MSPサービス

MSP(Managed Service Provider)サービスは、お客さまのパブリッククラウドの導入から運用までをトータルでご提供するマネージドサービスです。

おすすめの記事

条件に該当するページがございません