0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

EC2, RDS, ALBを用いて、マルチAZ構造を作る。AWSで典型的なVPCを構築して、ウェブアプリを立ち上げる。

Posted at

注意

練習のためにウェブサイトを構築する場合、使い終わったら、EC2インスタンスなどは削除しておきましょう。

環境

  • EC2, RDS, ALB, Multi AZ
  • ubuntu 22.04
  • Flask 2.1.2
  • Docker-compose v2.22.0

背景

典型的なウェブアプリのVPCを構築する練習をしたい。

結論

図のようなアーキテクチャを構築する。Multi AZ構成にすることで、可用性を高めることができる。

7.drawio.png

EC2, RDS, ALBを使って動的ウェブアプリをホストする

今回のウェブアプリの概要

初回アクセスの時に、web(Flask)コンテナが、DBにアクセスしてテーブルを作成します。

ウェブサイトへのアクセスがあったら、DBから適当なデータを取得して、それをブラウザに表示する。

docker-composeを用いることで、EC2インスタンスにnginxコンテナとwebコンテナを構築して、webコンテナからRDS(DB)にアクセスする。

注意

以下で説明する手順について、AWSコンソールからGUIの操作で行う部分については、細かい説明は省略してあります。

手順(GUIでアーキテクチャを構築)

東京リージョンで全ての作業を行うので、東京リージョンを選択してください。

(1) VPCを作る

VPCを作るときに、上のアーキテクチャの図のように、二つのAZそれぞれにpublic subnet 1つとprivate subnet 1つが作られるように設定する。今回はS3は使ってないので、作成しなくてもいいです。

(2) EC2インスタンスを立てる

二つのパブリックサブネットそれぞれに、一台ずつのEC2インスタンスを立てる。EC2作成時に、先ほど作ったVPCを選択すると、そのVPC内のパブリックサブネットが選択できるようになります。Auto-assign public IPをEnableにすることによって、グローバルIPアドレスが割り当てられるようにしてください。

セキュリティグループについて、全てのIPアドレス(0.0.0.0/0)からのhttp, https通信を許可してください。また、My IPからのssh通信を許可してください。

(3) ALBを立てる

ALBを作成する時、今回使用するVPCを選択する。サブネットのMappingsとして、VPC内の二つのパブリックサブネットを選択する。

セキュリティグループは、EC2インスタンスと同じでいいと思います。

そして、先ほど作った二つのEC2インスタンスをルーティングのターゲットとします。ルーティングのターゲットとなるTarget Groupは、あらかじめ作成しておいてください。Target Group作成時に選択するTarget Typeは、instancesでいいと思います。二つのEC2インスタンスを選択して、Target Groupを作成してください。

(4) RDSを立てる

Engine TypeはMySQLでいいと思います。

今回は、Multi-AZ DB instanceを選択します。

ユーザ名とマスターパスワードは、EC2インスタンスからRDSにアクセスする時に必要になります。

Connectivityのcompute resourceの選択で、EC2インスタンスを一つ選択します。EC2インスタンス二つと接続したいですが、一つしか選べないので、とりあえず、一つ目のEC2インスタンスを選択します。後で、もう一つのEC2インスタンスがRDSへ接続できるように、一つ目のEC2インスタンスが持っているセキュリティグループを加えます。

手順(EC2インスタンスにSSH接続をして、ウェブAPIを構築する)

(1) EC2インスタンスにSSH接続する

下記のコマンドで、SSH接続をする。

yourkey.pemは、鍵のパスです。xxx.xxx.xxx.xxxは、EC2インスタンスのグローバルIPアドレスです。

sudo ssh -i yourkey.pem ubuntu@xxx.xxx.xxx.xxx

(2) dockerをインストールする。

下記のように、dockerをインストールする。上記の公式ドキュメントに書いてあるコマンドをそのまま使った。

Add Docker's official GPG key:

$ sudo apt-get update
$ sudo apt-get install ca-certificates curl gnupg
$ sudo install -m 0755 -d /etc/apt/keyrings
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
$ sudo chmod a+r /etc/apt/keyrings/docker.gpg

Add the repository to Apt sources:

$ echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

下記で正常にインストールされたことを確認する。

$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
...
Hello from Docker!
This message shows that your installation appears to be working correctly.

(3) docker-composeをインストールする。

下記のように、docker-composeをインストールする。上記のリンクに書いてあるコマンドと基本的には同じで、バージョンだけ変更した。今回は、v2.22.0をインストールする。

下記がうまくいかなかったら、下記を実行する前に、「sudo -i」を実行して、次に下記からsudoを抜いたコマンドを実行してください。

$ sudo curl -L "https://github.com/docker/compose/releases/download/v2.22.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose

下記で、docker-composeが正常にインストールされているかどうかを確認する。

$ docker-compose --version
Docker Compose version v2.22.0

(4) プロジェクトをgit cloneする

docker-composeのプロジェクトがGitHubにある前提で話を進める。下記のようにgit cloneする。

今回は、「/var/www」フォルダを作り、そこにプロジェクトを配置する。

「YourName」はあなたのGithubアカウントの名前、「VPC-RDS-Test」は今回使うプロジェクトのレポジトリの名前を書いてください。

/var$ sudo mkdir www
/var$ cd www
/var/www$ sudo git clone https://github.com/YourName/VPC-RDS-Test
...

(5) プロジェクトの中身を確認

今回、プロジェクトの階層構造や、ファイルの中身は下記のようになっている

ubuntu@ip-10-0-9-22:/var/www/VPC-RDS-Test$ ls -l
total 20
... Dockerfile
... app.py
... docker-compose.yml
... nginx.conf
... requirements.txt
app.py
from flask import Flask, jsonify
from flask_sqlalchemy import SQLAlchemy
import os

app = Flask(__name__)

# RDSデータベース設定
db_user = 'YourName'
db_password = 'YourPassword'
db_host = 'YourRdsEndpoint'
db_name = 'test_db'
app.config['SQLALCHEMY_DATABASE_URI'] = f'mysql+pymysql://{db_user}:{db_password}@{db_host}/{db_name}'

db = SQLAlchemy(app)

# モデル定義
class Item(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), nullable=False)

    def __repr__(self):
        return '<Item %r>' % self.name

# データベース初期化とサンプルデータの追加
@app.before_first_request
def create_tables():
    db.create_all()
    # データが存在しない場合のみ追加
    if not Item.query.first():
        db.session.add(Item(name="Sample Item 1"))
        db.session.add(Item(name="Sample Item 2"))
        db.session.commit()

# ルートエンドポイント
@app.route('/')
def index():
    items = Item.query.all()
    return jsonify([item.name for item in items])

if __name__ == '__main__':
    app.run(host='0.0.0.0')
docker-compose.yml
version: '3.8'
services:
  app:
    build: .
    ports:
      - "5000:5000"
  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
# Dockerfile
FROM python:3.8-slim
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
CMD ["flask", "run"]
nginx.conf
events {}
http {
    server {
        listen 80;
        location / {
            proxy_pass http://app:5000;
        }
    }
}
requirements.txt
Flask==2.1.2
pymysql==1.0.2
SQLAlchemy==1.4
flask_sqlalchemy==2.5.1
Werkzeug==2.2.2
cryptography==3.4.7

(6) RDSに今回使うDBを作成する

今回使うDBの名前は「test_db」です。EC2インスタンスからRDSにアクセスして、DBを作成します。下記はEC2インスタンスで実行するコマンドです。

「YourRdsEndpoint」は、RDSのドメイン名(Endpoint)を書いてください。「YourName」には、RDSを作成したときに決めた名前を書いてください。パスワードの入力が求められますが、RDSを作成したときに決めたパスワードを書いてください。

$ sudo apt update
$ sudo apt install mysql-server 
$ systemctl status mysql
...
Active: active (running) 
...
$ mysql -h YourRdsEndpoint -P 3306 -u YourName -p
Enter password:
mysql> create database test_db;
Query OK, 1 row affected (0.04 sec)
...

MySQLから抜けるには、exitコマンドを使います。

(7) docker-composeでビルドして、ウェブサイトにアクセスする

下記でwebコンテナを起動させている間、このEC2インスタンスのグローバルIPアドレスにアクセスすると、ブラウザに["Sample Item 1", "Sample Item 2"]という文字列が表示されると思います。これは、webコンテナがDBにアクセスして、データを取得できていることを示します。

/var/www/VPC-RDS-Test$ sudo docker-compose build
...
/var/www/VPC-RDS-Test$ sudo docker-compose up
...
vpc-rds-test-app-1    |  * Running on all addresses (0.0.0.0)
vpc-rds-test-app-1    |  * Running on http://127.0.0.1:5000
vpc-rds-test-app-1    |  * Running on http://172.18.0.2:5000
vpc-rds-test-app-1    | Press CTRL+C to quit
...

下記のようなウェブ画面が表示されると思います。下記は、EC2インスタンスに直接アクセスしています。

Untitled (2).png

ctrl+cでwebコンテナの実行を止めて、下記を改めて実行すると、バックグラウンドでの実行ができます

/var/www/VPC-RDS-Test$ sudo docker-compose up -d
...

(8) もう一つのEC2インスタンスをセットアップ

次に、もう一つのEC2インスタンスに対して同じことを実行します。セキュリティグループが、一つ目のEC2インスタンスと同じものを持っているようにしてください。これにより、もう一つのEC2インスタンスがRDSにアクセスすることが可能になるはずです。

ALBのDNS NAME(ドメイン名)にアクセスすると、EC2インスタンスにルーティングされて、上記の画像と同じ表示になるはずです。

(9) ALBがロードバランスしていることを確かめる

Multi AZ構成を採用しているので、ALBを使っているが、ALBが正常に機能していることを確かめたい。ALBのルールに、「/path1」でアクセスされたら1つ目のEC2インスタンスにルーティングして、「/path2」でアクセスされたら2つ目のEC2インスタンスにルーティングするというルールを加える。GUIでALBの設定を変更してください。ALBのAdd listenerから条件を加えることができます。

スクリプトは以下のように変更します。

1つ目のEC2インスタンスにあるapp.pyに下記を追加して再ビルドする。/path1でアクセスされたら、ALBによって1つ目のEC2インスタンスにルーティングされて、そのwebコンテナはDBの1行目を取得して表示する。

app.py
@app.route('/path1')
def path1():
    item = Item.query.filter_by(id=1).first()
    return item.name

2つ目のEC2インスタンスにあるapp.pyに下記を追加して再ビルドする。/path2でアクセスされたら、ALBによって2つ目のEC2インスタンスにルーティングされて、そのwebコンテナはDBの2行目を取得して表示する。

app.py
@app.route('/path2')
def path2():
    item = Item.query.filter_by(id=2).first()
    return item.name

"/path1", "/path2"にアクセスして、意図通りのデータがブラウザに表示されていれば、ALBのルーティングが機能していることが分かる。"/path1"にアクセスすると、"Sample Item 1"が表示されて、"/path2"にアクセスすると、"Sample Item 2"が表示されるようになっているはず。

①"{ALBのドメイン名}" にアクセスしたときのウェブ画面は下図です。この時、ALBを介して、どちらかのEC2インスタンスに到達している。

Untitled (2).png

②"{ALBのドメイン名}/path1" にアクセスしたときのウェブ画面は下図です。この時、ALBを介して、一つ目のEC2インスタンスに到達している。

Untitled (3).png

③"{ALBのドメイン名}/path2" にアクセスしたときのウェブ画面は下図です。この時、ALBを介して、二つ目のEC2インスタンスに到達している。

Untitled (4).png

今後の展望

典型的なウェブアプリのVPC構造を構築できたと思うので、次は、Terraformとかを使ってみる。

参考

  • https://www.rworks.jp/cloud/aws/aws-column/aws-entry/22067/
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?