EC2からプライベートなRDSに接続する方法

## 内容
- RDSを立ち上げてEC2からDB操作する手順をまとめています
- RDSはプライベートサブネットに設定し、外部からのアクセスができないようにします
- パブリックサブネットにあるEC2からRDSにアクセスしてDBを操作します
- webサーバーで画面に表示したページからDBを操作します

↓完成形
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/e3d8c300-c35a-a038-6d25-22b6b61609fb.png)


↓の記事の続きとなっています。
webサーバーから立ち上げたい方はご覧ください。

https://qiita.com/shogo30/items/d2e0fa2e7ecafc690952

## 目次
- [ネットワークの作成](https://qiita.com/shogo30/items/d43c281512bf321f4f66#%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%81%AE%E4%BD%9C%E6%88%90)
- [RDSを立ち上げる](https://qiita.com/shogo30/items/d43c281512bf321f4f66#rds%E3%82%92%E7%AB%8B%E3%81%A1%E4%B8%8A%E3%81%92%E3%82%8B)
- [EC2からアクセスする](https://qiita.com/shogo30/items/d43c281512bf321f4f66#ec2%E3%81%8B%E3%82%89%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B)

## ネットワークの作成
まずはRDSを設置するネットワークを作成します。
今回の要件としては、「外部からのアクセスを制限する」です。
外部からのアクセスというのはインターネットからのアクセスのことです。
前回立ち上げたEC2のパブリックサブネットはインターネットゲートウェイと通信ができる、つまりインターネットからアクセスすることができました（なのでローカルからダイレクトでssh接続できるのです）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/b239810b-e41b-443f-eff1-1f988ece0a87.png)

しかしDBは外部からアクセスされると、データが不正に操作される恐れがあるため、プライベートなネットワークに置くことがセキュリティ上推奨されています（Webサーバーもそうなのですが今回は無視します）。

そのため、AWSでプライベートなネットワークを実現させます。
そのためにはプライベートサブネットというものを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/4d34fe95-d021-e459-f911-76451183d8d2.png)

### プライベートサブネットの作成
プライベートサブネットを作成します。
VPC > Subnets > サブネットを作成をクリックします。
![スクリーンショット 2023-10-23 19.34.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/c28f938a-87ed-5fe4-af2c-a182b73ba2d7.png)


後ほどご説明しますが、RDSを立ち上げるために、異なるアベイラビリティゾーンにサブネットを１つずつ作成します。
すでに作成しているサブネットのCIDRに被らないように設定します。

↓サブネット１つ目
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/157f7eca-c134-691d-503d-934fae86ede1.png)

↓サブネット２つ目
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/31e0f164-cd5d-84d8-0508-f197757b414e.png)

作成したサブネットにルートテーブルを設定します。
パブリックサブネットを作成したときは、インターネットゲートウェイへの通信もルートテーブルに設定していました。
しかし今回はプライベートにしたいので、インターネットゲートウェイへの通信は設定せずに作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/4d060368-a776-53b4-660e-400489e8fed2.png)

ルートテーブルを作成すると、「明示的な関連付けがないサブネット」に先ほど作成した２つのサブネットが表示されます。
これら２つを選択して「サブネットの関連付けを編集」します。
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f323933353730302f31326130386461662d393530302d333034312d386161382d6361666663323436643365322e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/e200e2ff-be2d-6cdf-9b8f-2032e5efb07a.png)


対象のサブネット２つを選択し「関連付けの保存」をします。
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f323933353730302f64326166663831322d326431332d313165342d646132632d3765313935326164376539372e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/a18872d5-e3b4-95e2-2ff6-262126436b32.png)


これでインターネットに繋がらないプライベートサブネットが作成できました。
次にこれらのサブネットをサブネットグループにまとめます。


サブネットグループとは、RDSインスタンスが使用するサブネットのことで、
RDSインスタンスは複数のアベイラビリティゾーンのサブネットにまたがって作成する必要があります。
一方のアベイラビリティゾーンなどに異常が起きた時に、もう一方のアベイラビリティゾーンでインスタンスを立ち上げることで、サービスの停止を防ぐのです。（冗長化と言います）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/41a6f93b-00b1-127a-e9c1-c1cb239307c7.png)

今回はRDS用に２つのプライベートサブネットを作成したので、これらをサブネットグループとします。

RDSのダッシュボードから「サブネットグループ」を選択します。
![スクリーンショット 2023-10-23 19.39.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/20b4acf3-c734-0065-4ab7-af0874c933a8.png)

先ほど作成したサブネットを選択します。
サブネットグループの作成には、複数のアベイラビリティゾーンからサブネットを１つ以上選択する必要があります。
![スクリーンショット 2023-10-23 19.44.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/8514800a-df81-7130-04a6-634c7250a6b9.png)

これでプライベートサブネットで構成されたサブネットグループが作成されました。

### セキュリティグループの作成
続いてセキュリティグループを作成します。
RDSにもセキュリティグループを設定するのですが、今回はパブリックサブネットのEC2からのアクセスだけを許可するようにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/9666e76c-35cb-2aa9-c1d9-a6f7f3a94539.png)

RDS用のセキュリティグループを設定します。
後にEC2から接続するので、EC2にアタッチされているセキュリティグループからのアクセスを許可します。
![スクリーンショット 2023-10-23 20.55.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/be027046-0c0b-a41f-57f5-513c5785c6a7.png)
これでパブリックサブネットに設置したEC2からのみアクセスすることができました。

## RDSを立ち上げる
### パラメータグループの作成
パラメータグループを作成します。
パラメータグループとは、RDSの設定情報をテンプレートとして保存するもので、
同じパラメータグループに属するRDSインスタンスにまとめて設定を反映させることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/08a8d31b-24fc-fd1a-39e7-4d69ba2564c4.png)

後ほどRDSインスタンスを立ち上げるときに選択します。

### オプショングループの作成
オプショングループも、グループに属するインスタンスにオプションをまとめて反映させることができるものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/df647b27-1f9f-acb5-27df-d8f63534ce0c.png)

これもRDSインスタンスを立ち上げる時に選択します。

### RDSインスタンスの作成
いよいよRDSを立ち上げます。
RDSダッシュボードから「データベースの作成」をクリックします。

「標準作成」を選択して今回はエンジンを「MySQL」にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/2958f91e-10cd-dc8e-f77b-44f6de8a9324.png)

今回はテスト用なので「無料利用枠」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/b1cf0a72-e344-7203-6acd-134537f7d700.png)

「DBインスタンス識別子」, 「マスターユーザー名」, 「パスワード」はご自身で決めてください。
DBに接続をするときに必要になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/0be812d7-6193-4945-4e7d-1d0c7bc22ec1.png)

DBインスタンスクラスとはいわばDBのスペックで、スペックが良いほど料金も高くなります。
今回はテスト用なので安い「db.t3.micro」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/a81a5c53-d7e1-2c9a-acfd-78c3c0ae9455.png)

ネットワークは先ほど作成した、VPC内のプライベートサブネットを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/37e5da6e-ef0e-ef46-7958-f75c3e60bbef.png)

セキュリティグループは先ほど作成した、EC2からのアクセスのみを許可したものを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/e2c79223-aa48-45aa-fe95-ab13dd219f14.png)

そのほかの設定はデフォルトでOKです。
これで「データベースの作成」をすると、数分後にRDSインスタンスが立ち上がります。
立ち上がったらWEBサーバーからアクセスしてみましょう。

## EC2からアクセスする
### EC2から接続する
立ち上げたRDSにEC2から接続します。
まずはEC2にssh接続します。
```
~ %ssh -i ~/.ssh/test-key.pem ec2-user@[EC2のパブリックIP]
```
MySQLコマンドをインストールします
```
[ec2-user@ip-10-0-0-102 ~]$ sudo yum -y install mysql
Last metadata expiration check: 0:03:43 ago on Mon Oct 23 11:17:43 2023.
No match for argument: mysql
Error: Unable to find a match: mysql
```
おっとエラーが起きました。
どうもAmazon linux 2023でこのエラーが起きるようです。
そんな時は
```
[ec2-user@ip-10-0-0-102 ~]$ sudo dnf -y localinstall https://dev.mysql.com/get/mysql80-community-release-el9-1.noarch.rpm
[ec2-user@ip-10-0-0-102 ~]$ sudo dnf -y install mysql mysql-community-client
```
とします。
正直何しているかわかりませんがスルーします。
そして再度mysqlコマンドのインストールを試みます。
```
[ec2-user@ip-10-0-0-102 ~]$ sudo yum install mysql -y
Last metadata expiration check: 0:00:06 ago on Mon Oct 23 11:22:09 2023.
Package mysql-community-client-8.0.34-1.el9.x86_64 is already installed.
Dependencies resolved.
Nothing to do.
Complete!
```
無事インストールができました！
ではRDSに接続しましょう。
EC2に接続した状態で``mysql -h [エンドポイント]  -P 3306 -u admin -p``と叩きます。

```
[ec2-user@ip-10-0-0-102 ~]$ mysql -h [エンドポイント] -P 3306 -u admin -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 17
Server version: 8.0.33 Source distribution

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

```
接続に成功しました！

ついでにテーブルを作成しておきましょう。
```
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| testdb             |
+--------------------+
5 rows in set (0.01 sec)

mysql> use testdb;
Database changed

mysql> CREATE TABLE Post ( post_id INT PRIMARY KEY AUTO_INCREMENT, post VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);
Query OK, 0 rows affected (0.03 sec)
```
``testdb``というデータベースに↓のような``Post``テーブルを作成しました。
```
CREATE TABLE Post (
post_id INT PRIMARY KEY AUTO_INCREMENT,
post VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
);
```
これで準備は整いました。
ではEC2のウェブサーバーからこのデータベースに接続しましょう。

### ウェブサーバーからDBを操作する
今回はPHPでデータベースを操作します。
なのでウェブサーバーのディレクトリインデックスをPHPファイルに変えておきましょう。
```
[ec2-user@ip-10-0-0-102 conf]$ sudo vi /etc/httpd/conf/httpd.conf

...

<IfModule dir_module>
    DirectoryIndex index.php index.html
</IfModule>

...

```

そしてindex.phpファイルを↓のようにします
※データベースの接続情報をベタかきしていますが、セキュリティガバガバなので、実際は.envに書くなどしましょう。
```
[ec2-user@ip-10-0-0-102 ~]sudo vi /var/www/html/index.php
<?php
$dsn = "mysql:host=[エンドポイント];dbname=[データベース名（今回はtestdb）]";
$username = "ユーザー名(今回はadmin)";
$password = "パスワード";
$dbh = new PDO($dsn, $username, $password);

if ($post_message) {
    $query = "INSERT INTO post (post) VALUES ('" . $post_message  . "')";
    $stmt = $dbh->query($query);
}

// クエリの実行
$query = "SELECT post FROM post ORDER BY created_at DESC";
$stmt = $dbh->query($query);
$post_data = $stmt->fetchAll(PDO::FETCH_BOTH);
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>sqs</title>
</head>
<body>
    <form action="" method="post">
        <input name="post">
	<button>送信</button>
    </form>
    <p>↓ここにメッセージが表示されます↓</p>
    
    <?php foreach($post_data as $post): ?>
    <p><?php echo($post['post']); ?></p>
    <?php endforeach; ?>
</body>
</html>
```
php-mysqlパッケージをインストールします。
```
[ec2-user@ip-10-0-0-102 html]$ sudo yum install php-mysqlnd
```

これでWEBサーバーにブラウザからアクセスしてみましょう。

EC2のパブリックIPをブラウザに打ち込むとページが表示されます。
メッセージを送信すると...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/11580a51-aaa9-0e50-b6c6-39dd3774daad.png)

データベースに保存されました！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/ee4c9deb-a1c4-fdd9-cf0e-c72d3943d4e1.png)

無事RDSインスタンスのDBの操作を行うことができました！！