[OCI] Computeインスタンス上にNode.jsのWebアプリケーション環境を構成して、MySQL Database ServiceのDBシステムにアクセスしてみた

# はじめに
Computeインスタンス上に構成したNode.jsのWebアプリケーションから、MySQL Database ServiceのDBシステムにアクセスしてみた時の手順です。
（2020年10月現在）

# 構築イメージ
![スクリーンショット 2020-10-28 19.50.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/37d26078-8856-e250-1c61-c6511e47e027.png)

# 作業の流れ
1.VCNの構成
2.ネットワーク・セキュリティ・グループの作成
3.MySQL DBシステムの作成
4.Computeインスタンス（APサーバ）の作成
5.パブリックIPの作成
6.ComputeインスタンスへのパブリックIPの割り当て
7.MySQLクライアントのインストールと設定
8.Node.jsのインストールと設定
9.firewalldの設定
10.SELinuxの設定
11.MySQL DBシステムの接続情報の確認
12.アプリケーションで使用するDBの準備
13.Node.jsアプリケーションの作成
14.Node.jsアプリケーションの動作確認

# 1.VCNの構成
こちらの記事を参考に、仮想クラウド・ネットワークを構成します。

[OCIのネットワークを構成する際に手戻りの少ない手順を考えてみる（初心者向け）](https://qiita.com/500InternalServerError/items/ce8aaf7d1c249126d345)

ここでは、以下の理由からMySQL DBシステムを独立したプライベート・サブネットに配置します。
**・MySQL DBシステムはプライベート・エンドポイントのみを持つ。**
**・MySQL DBシステムにはネットワーク・セキュリティ・グループを適用できない。**

そのため、参考記事のネットワーク構成に対して、以下の部分を変更します。

**・Subnet2のセキュリティ・リスト（Security List for Subnet2）**
APサーバを配置するサブネット（Subnet1:10.0.1.0/24）からのみ、MySQLへの接続で使用するTCP 3306、33060へのアクセスを許可します。

*「コンソールメニュー」　→　「ネットワーキング」　→ 「仮想クラウド・ネットワーク」　
　→　「仮想クラウドネットワークの詳細」　→　「セキュリティ・リスト」*

・**「セキュリティ・リストの作成」をクリック**
　・ 名前：**Security List for Subnet2**
　・コンパートメントに作成：「Compartment1」を選択
　　・**「+追加のイングレス・ルール」をクリック**
　　　・ステートレス：チェックをオフ（デフォルト）
　　　・ソース・タイプ：**「CIDR」**を選択
　　　・ソースCIDR：**10.0.1.0/24**
　　　・IPプロトコル：**「TCP」を選択**
　　　・ソース・ポート範囲：入力しない
　　　・宛先ポート範囲：**3306**
　　・**「+追加のイングレス・ルール」をクリック**
　　　・ステートレス：チェックをオフ（デフォルト）
　　　・ソース・タイプ：**「CIDR」**を選択
　　　・ソースCIDR：**10.0.1.0/24**
　　　・IPプロトコル：**「TCP」を選択**
　　　・ソース・ポート範囲：入力しない
　　　・宛先ポート範囲：**33060**
　　・**「+追加のエグレス・ルール」をクリック**
　　　・ステートレス：チェックをオフ（デフォルト）
　　　・宛先タイプ：**「CIDR」**を選択
　　　・宛先CIDR：**0.0.0.0/0**
　　　・IPプロトコル：**「全てのプロトコル」を選択」**
　・**「セキュリティ・リストの作成」をクリック**

# 2.ネットワーク・セキュリティ・グループの作成

今回作成するNode.jsアプリケーションでTCP 8080でリクエストを受けるので、すべての場所からTCP 8080へのアクセスを許可するネットワーク・セキュリティ・グループを作成します。

*「コンソールメニュー」　→　「ネットワーキング」　→ 「仮想クラウド・ネットワーク」　→　「仮想クラウドネットワークの詳細」　→　「ネットワーク・セキュリティ・グループ」*

・**「ネットワーク・セキュリティ・グループの作成」をクリック**
　・名前：**Network Security Group for AP**
　・コンパートメントに作成：「Compartment1」を選択
　・**「次」をクリック**
　・セキュリティ・ルールの追加
　　ルール
　　　ステートレス：チェックをオフ（デフォルト）
　　　方向：**「イングレス」を選択**
　　　ソースタイプ：**「CIDR」を選択**
　　　ソース：**0.0.0.0/0**
　　　IPプロトコル：**「TCP」を選択**
　　　ソース・ポート範囲：デフォルトのまま（入力しない）
　　　宛先ポート範囲：**8080**
  　  説明：**Security Rule for TCP 8080 **
　・**「作成」をクリック**

# 3.MySQL DBシステムの作成

*「コンソールメニュー」　→　「MySQL」 → 「DBシステム」*

**・「MySQL DBシステムの作成」をクリック**

　DBシステムの基本情報情報
　・コンパートメントの選択：「Compartment1」を選択
　・DBシステムの名前の指定：**MySQL1**
　・可用性ドメインの選択：**任意の可用性ドメインを選択**
　・フォルト・ドメインの選択：**任意のフォルト・ドメインを選択**
　・シェイプの選択：**任意のシェイプを選択**
　・データ・ストレージ・サイズ（GB）：**任意のサイズを入力**
　・メンテナンス・ウィンドウの開始時間：入力しない
　・**「次」をクリック**

　データベースの基本情報の指定
　・管理者資格証明の作成
　　・ユーザー名：**admin**
　　・パスワード：**Demo#1Demo#1**
　　・パスワードの確認：**Demo#1Demo#1**
　・ネットワーク情報の指定
　　・仮想クラウドネットワーク：**「VCN1」を選択**
　　・サブネット：**「Subnet2」を選択**
　　・ホスト名：**mysql1**
　　・MySQLポート：3306（デフォルト）
　　・MYSQL Xプロトコル・ポート：33060（デフォルト）
　　・**「次」をクリック**

　DBシステム・バックアップの基本情報の指定
　・バックアップの構成
　　・自動バックアップの有効化：チェックをオン（デフォルト）
　　・バックアップ保持期間：7（デフォルト）
　　・バックアップ・ウィンドウの開始時間：デフォルト・バックアップ・ウィンドウ（デフォルト）
　
　　・**「作成」をクリック**

# 4.Computeインスタンス（APサーバ）の作成

*「コンソールメニュー」　→　「コンピュート」　→ 「インスタンス」*

**・「インスタンスの作成」をクリック**
　・名前：**AP1**
　・コンパートメントに作成：「Compartment1」を選択

　・配置とハードウェアの構成
　　・可用性ドメイン：任意のADを選択
　　・イメージ：**「Oracle Linux 7.8」を選択**
　　・シェイプ：任意のシェイプを選択

　・ネットワーキングの構成　
　　・ネットワーク：**「既存の仮想クラウド・ネットワークを選択」を選択し、「VCN1」を選択**
　　・サブネット：**「既存のサブネット」を選択し、「Subnet 1」を選択**
　　・ネットワーク・セキュリティ・グループを使用してトラフィックを制御：**チェックをオン**
　　・ネットワーク・セキュリティ・グループ：**「Network Security Group for AP」を選択**
　　・パブリックIPアドレス：**「パブリックIPアドレスを割り当てないでください」を選択**
　
　・SSHキーの追加
　　・**「公開キー・ファイルの選択」を選択し、「または場所を参照します」をクリックして公開キー・ファイルをアップロードします**
　
　・ブートボリュームの構成
　　・全てデフォルトのまま

　・「拡張オプションの表示」をクリック
　　・「管理」タブ
　　　・全てデフォルトのまま
　　・「ネットワーキング」タブ
　　　・プライベートIPアドレス：**10.0.1.100**
　　　・ホスト名：**ap1**
　　　・起動オプション：デフォルトのまま
　　・「イメージ」タブ
　　　・デフォルトのまま
　　・「配置」タブ
　　　・デフォルトのまま
 ・**「作成」をクリック**

# 5.パブリックIPの作成
*「コンソールメニュー」　→　「ネットワーキング」　→ 「IP Management」*

・**「パブリックIPアドレスの予約」をクリック**

　・予約済パブリックIPアドレス名：**PublicIP1**
　・コンパートメントに作成：「Compartment1」を選択
　・IPアドレスのソース：**「Oracle」を選択**

　・**「パブリックIPアドレスの予約」をクリック**

# 6.ComputeインスタンスへのパブリックIPの割り当て

「コンソールメニュー」　→　「コンピュート」　→ 「インスタンス」　→　「インスタンスの詳細」

・リソース欄の**「アタッチされたVNIC」をクリック**
・**VNIC名（AP1）をクリック**
・リソース欄の**「IPアドレス」をクリック**
・**IPアドレスの欄の「:」をクリックし、「編集」をクリック**
　・パブリックIPタイプ：**「予約済パブリックIP」を選択**
　・**「既存の予約済パブリックIPの選択」を選択**
　・RESERVED IP ADDRESS：**「PublicIP1」を選択**
 ・**「更新」をクリック**

# 7.MySQLクライアントのインストールと設定
秘密鍵を使って、SSHクライアントからComputeインスタンス（AP1）にopcユーザでログインします。

タイムゾーンとロケールを設定します。

```
sudo timedatectl set-timezone Asia/Tokyo
sudo localectl set-locale LANG=ja_JP.utf8
```

yumコマンドでMySQLクライアントをインストールします。

```
sudo yum install -y https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
sudo yum install -y mysql-community-client
```

# 8.Node.jsのインストールと設定

yumコマンドでNode.jsインストールをインストールします。

```
sudo yum install -y oracle-release-el7 oracle-nodejs-release-el7
sudo yum install -y --disablerepo=ol7_developer_EPEL nodejs
```

npmコマンドで使用するNode.jsモジュール（expressフレームワーク、ejs）をインストールします。

```
sudo npm install -g --save express-generator
sudo npm install -g --save ejs
```

# 9.firewalldの設定

firewall-cmdコマンドでfirewalldにTCP8080の通信を許可する設定を追加します。

```
sudo firewall-cmd --add-port 8080/tcp --zone=public --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --list-all --zone=public
```

# 10.SELinuxの設定

SELinuxの設定を変更します。

```
sudo setenforce 0
```
 
再起動後にSELinuxが有効にならないように設定ファイルを変更します。

```
sudo vi /etc/selinux/config
```

```sh:/etc/selinux/config
SELINUX=enforcing
```

の部分を以下のように変更して保存します。

```sh:/etc/selinux/config
SELINUX=permissive
```

# 11.MySQL DBシステムの接続情報の確認

*「コンソール」　→ 「MySQL DBシステム」　→ 「MySQL DBシステム」*

リソース欄の「エンドポイント」をクリックし、MySQL DBシステムのエンドポイント（ホスト、ポート）を確認します。
![スクリーンショット 2020-10-28 21.00.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/435cb4f1-6018-254f-ea79-d4f09929e992.png)

# 12.アプリケーションで使用するDBの準備
DB接続情報を含む、MySQLクライアントの設定ファイルを作成します。

```
vi /home/opc/.my.cnf
```
```/home/opc/.my.cnf
[client]
user=admin
password="Demo#1Demo#1"
host="mysql1.subnet2.vcn1.oraclevcn.com"
 ```

mysqlコマンドででMySQLに接続に接続します。

```
mysql
```

アプリケーションで使用するDBを作成します。

```
mysql> CREATE DATABASE testdb;
```

アプリケーションで使用するDBユーザを作成します。

```
mysql> CREATE USER 'test' IDENTIFIED BY 'Demo#1Demo#1';
```

アプリケーションで使用するDBユーザに権限を付与します。

```
mysql> GRANT ALL ON testdb.* TO 'test';
```


アプリケーションで使用するDBに接続します。

```
mysql> USE testdb
```

アプリケーションで使用するテーブルを作成します。

```
mysql> CREATE TABLE dept (
    -> deptno INT ,
    -> dname VARCHAR(14),
    -> loc VARCHAR(13) ,
    -> PRIMARY KEY  (deptno) 
    -> );
```

アプリケーションで使用するテーブルにデータを挿入します。

```
mysql> INSERT INTO dept VALUES (10,'ACCOUNTING','NEW YORK');
mysql> INSERT INTO dept VALUES (20,'RESEARCH','DALLAS');
mysql> INSERT INTO dept VALUES (30,'SALES','CHICAGO');
mysql> INSERT INTO dept VALUES (40,'OPERATIONS','BOSTON');
mysql> COMMIT;
```

アプリケーションで使用するテーブルのデータを確認します。

```
mysql> SELECT * FROM dept;
+--------+------------+----------+
| deptno | dname      | loc      |
+--------+------------+----------+
|     10 | ACCOUNTING | NEW YORK |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
+--------+------------+----------+
```

mysqlコマンドを終了します。

```
mysql> exit
```

# 13.Node.jsアプリケーションの作成
今回はexpressフレームワークを使用してNode.jsアプリケーションを作成します。

opcユーザのホームディレクトリ直下に、expressコマンドでNode.jsアプリケーション環境を作成します。

```
cd　/home/opc
express --view=ejs app
```

アプリケーション環境のディレクトリに移動し、npmコマンドで依存関係のあるモジュールをインストールします。

```
cd app
npm install
```

npmコマンドでMySQLにアクセスするために使用する@mysql/xdevapiモジュールをインストールします。

```
npm install --save @mysql/xdevapi 
```

app.jsを編集します。

```
vi /home/opc/app/app.js
```

末尾に以下の内容を追加します。

```/home/opc/app/app.js
app.listen(8080);
```

routes/index.jsを編集します。

```
vi /home/opc/app/routes/index.js
```

以下の内容に書き換えます。

```/home/opc/app/routes/index.js
var express = require('express');
var mysqlx = require('@mysql/xdevapi');
var router = express.Router();
var os = require('os');

mysqlx
  .getSession({
   user: 'test',
   password: 'Demo#1Demo#1',
   host: 'mysql1.subnet2.vcn1.oraclevcn.com',
   port: '33060'
   })
    .then(function (session) {
      var db = session.getSchema('testdb');
      var myTable = db.getTable('dept');
      var rows =  myTable
         .select()
         .execute()
         .then(res => {
           dept = res.fetchAll();
           hostname = os.hostname();
           console.log(dept);
		   console.log(hostname);
         });
      router.get('/', function(req, res, next) {
        res.render('index',{dept: dept, hostname: hostname});
      });
    })
    .catch(function (err) {
       console.log('error: ' + err.stack);
            return;
    });

module.exports = router;
```

views/index.ejsを編集します。

```
vi /home/opc/app/views/index.ejs
```

以下の内容に書き換えます。

```/home/opc/app/views/index.ejs
<html>
<head>
<meta charset="UTF-8">
<title>Node.js to MySQL DS Connection Test</title>
</head>
<body>
<table border='1'>
<caption>DEPT Table</caption>
<tr><th>Dept No.</th><th>Dept Name</th><th>Location</th></tr>
  <% dept.forEach(function(deptItem) { %>
    <tr>
    <td><%- deptItem[0] %></td>
    <td><%- deptItem[1] %></td>
    <td><%- deptItem[2] %></td>
    </tr>
  <% }); %>
</table><br>
Response from <%- hostname %>
</body>
</html>
```

# 14.Node.jsアプリケーションの動作確認

nodeコマンドでアプリケーションを実行します。

```
cd /home/opc/app
node app.js
```

PCのブラウザからアクセスして、アプリケーションの動作を確認します。

http://*\<AP1のグローバルIP\>*:8080

![スクリーンショット 2020-10-28 21.21.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/31207111-ccfc-294b-9d71-488fcb2bf384.png)