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

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

# 構築イメージ
今回構築した環境のイメージはこのような感じです。
![スクリーンショット 2020-10-28 18.24.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/aca1e7ba-7c05-aa3a-cae2-ea93fcad8ff9.png)



# 作業の流れ

1.VCNの構成
2.ネットワーク・セキュリティ・グループの作成
3.DBシステムの作成
4.Computeインスタンス（APサーバ）の作成
5.パブリックIPの作成
6.パブリックIPの割り当て
7.Oracle Instant Clientのインストールと設定
8.Apache/PHPのインストールと設定
9.firewalldの設定
10.SELinuxの設定
11.Apache/PHPの動作確認
12.DBシステム（DBサーバ）の設定
13.アプリケーションで使用するDBデータの準備
14.APサーバの設定
15.PHPアプリケーションの動作確認

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

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

# 2.ネットワーク・セキュリティ・グループの作成
APサーバ、DBサーバそれぞれに適用するネットワーク・セキュリティ・グループを作成します。

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

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

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

# 3.DBシステム（DBサーバ）の作成

*「コンソールメニュー」　→　「ベア・メタル、VM、Exadata」*

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

　DBシステム情報
　・コンパートメントの選択：「Compartment1」を選択
　・DBシステムの名前の指定：**DBSystem1**
　・可用性ドメインの選択：**任意の可用性ドメインを選択**
　・シェイプ・タイプの選択：**「仮想マシン」を選択**
　・シェイプの選択：**任意のシェイプを選択**
　・Oracle Database ソフトウェア・エディション：**任意のエディションを選択**
　・ストレージ管理ソフトウェアの選択：**任意のストレージ管理ソフトウェアを選択**
　・ストレージの構成　使用可能なストレージ（GB）：**任意のストレージサイズを選択**
　・公開SSHキーの追加：**「 SSHキー・ファイルのアップロード」を選択、「browse」をクリックして共有鍵ファイル（.pub）を選択**
　・ライセンス・タイプの選択：**「含まれるライセンス」を選択**
　・仮想クラウド・ネットワーク：**「VCN1」を選択**
　・クライアントのサブネット：**「Subnet1」を選択**
　・ネットワーク・セキュリティ・グループを使用してトラフィックを制御：**チェックをオン**
　・ネットワーク・セキュリティ・グループ：**「Network Security Group for DB」を選択**
　・ホスト名接頭辞：**db1**
　・「拡張オプションの表示」をクリック
　・フォルト・ドメイン オプション：**任意のフォルト・ドメインを選択**
　・タイム・ゾーン：**「Asia/Tokyo」を選択**　

・**「次」をクリック**

データベース情報
　・データベース名：**DB1**
　・データベースのバージョン：**「19c」を選択**
　・PDB名：**PDB1**
　・管理者資格証明の作成　パスワード：**Demo#1Demo#1**
　・管理者資格証明の作成　パスワードの確認：**Demo#1Demo#1**
　・自動バックアップの有効化：**チェックをオン**
　・バックアップ保持期間：**「7days」を選択**
　・バックアップスケジューリング：**「Anytime」を選択**
　・「拡張オプションの表示」をクリック
　　・文字セット：「AL32UTF8」を選択（デフォルト）
　　・各国語文字セット：「AL16UTF16」を選択（デフォルト）

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

# 4.Computeインスタンス（APサーバ）の作成
*「コンソールメニュー」　→　「コンピュート」　→ 「インスタンス」*

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

　・配置とハードウェアの構成
　　・可用性ドメイン：任意の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.予約済パブリックIPの割り当て

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

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

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

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

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

yumコマンドでOracle Instant Clientをインストールします。

```
sudo yum -y install oracle-release-el7

sudo yum install -y oracle-instantclient19.6-sqlplus.x86_64
```

/etc/profileを編集し、環境変数の設定を追加します。

```
sudo vi /etc/profile
```


以下の内容をファイルの末尾に追加して保存します。

```sh:/etc/profile
export ORACLE_HOME=/usr/lib/oracle/19.6/client64/lib
export NLS_LANG=Japanese_Japan.AL32UTF8
export LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH
export PATH=/usr/lib/oracle/19.6/client64/bin:$PATH
```

環境変数を適用します。

```
source /etc/profile
```

# 8.PHPとApache のインストールと設定
yumコマンドでPHPとApacheをインストールします。

```
sudo yum install -y oracle-php-release-el7

sudo yum -y install php php-oci8-19c
```

PHPとApacheの連携を設定します。

```
sudo vi /etc/httpd/conf/httpd.conf
```

以下の内容をファイルの末尾に追加して保存します。

```sh:/etc/httpd/conf/httpd.conf
<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>
```

Apacheを起動します。

```
sudo systemctl start httpd.service
```

OS起動時のApacheが自動的に起動するように設定します。

```
sudo systemctl enable httpd.service
```

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

```
sudo firewall-cmd --add-service=http --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 .Apache/PHPの動作確認
Apacheの接続テスト用HTMLを作成します。

```
sudo vi /var/www/html/index.html
```

以下の内容を入力して保存します。

```index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <title>test</title>
  </head>
  <body>
    <h1>やったぜ！</h1>
  </body>
</html>
```

Apache + PHPの連携テスト用PHPファイルを作成します。

```
sudo vi /var/www/html/info.php
```

以下の内容を入力して保存します。

```info.php
<?php
echo phpinfo();
?>
```

ブラウザから以下のURLにアクセスし、正しく表示されるかを確認します。

http://*\<AP1のパブリックIPアドレス\>*/index.html

http://*\<AP1のパブリックIPアドレス\>*/info.php

# 12.DBシステム（DBサーバ）の設定

秘密鍵を使って、SSHクライアントからDBシステムにopcユーザでログインします。

oracleユーザにスイッチします。

```
sudo su - oracle
```

SQL*Plusで管理者としてDBにログインします。

```
sqlplus / as sysdba
```

接続先を確認します。

```
SQL> show con_name

CON_NAME
------------------------------
CDB$ROOT
```

SQL*Plusを終了します。

```
SQL> exit
```

Oracle Net Listenerのステータスを確認し、DBシステム作成時に作成されたPDBに対応したサービス名を出力結果から確認します。

```
lsnrctl status

　LSNRCTL for Linux: Version 18.0.0.0.0 - Production on
　＜略＞
　Service "pdb1.subnet1.vcn1.oraclevcn.com" has 1 instance(s).
　  Instance "DB1204", status READY, has 1 handler(s) for this service...
```

tnsnames.oraの内容を確認します。

```
vi $ORACLE_HOME/network/admin/tnsnames.ora
```

```tnsnames.ora（編集前）
# tnsnames.ora Network Configuration File: /u01/app/oracle/product/19.0.0/dbhome_1/network/admin/
tnsnames.ora
# Generated by Oracle configuration tools.

DB1 =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = db1.subnet1.vcn1.oraclevcn.com)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = DB1.subnet1.vcn1.oraclevcn.com)
    )
  )
```

tnsnames.oraを編集し、PDB接続用のエイリアスを追加します。

```tnsnames.ora（編集後）
# tnsnames.ora Network Configuration File: /u01/app/oracle/product/19.0.0/dbhome_1/network/admin/
tnsnames.ora
# Generated by Oracle configuration tools.

DB1 =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = db1.subnet1.vcn1.oraclevcn.com)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = DB1.subnet1.vcn1.oraclevcn.com)
    )
  )

PDB1 =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = db1.subnet1.vcn1.oraclevcn.com)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = pdb1.subnet1.vcn1.oraclevcn.com)
    )
  )
```

# 13.アプリケーションで使用するDBデータの準備
tnsnames.oraに追加したエイリアス（PDB1）を使用して、SQL*PlusでPDB1に管理者としてログインします。

```
sqlplus sys/Demo#1Demo#1@PDB1 as sysdba
```

接続先を確認します。

```
SQL> show con_name

CON_NAME
------------------------------
PDB1
```

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

```
SQL> GRANT CONNECT,RESOURCE,UNLIMITED TABLESPACE TO test IDENTIFIED BY Test#1Test#1;
```

アプリケーションで使用するDBユーザ（test）としてPDB1に接続します。

```
SQL> CONNECT test/Test#1Test#1@PDB1
```

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

```
SQL> CREATE TABLE dept (
2 deptno NUMBER(2) CONSTRAINT PK_DEPT PRIMARY KEY,
3 dname VARCHAR2(14) ,
4 loc VARCHAR2(13) ) ;
```

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

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

SQL> COMMIT;

SQL> SELECT * FROM dept;
```

SQL*Plusを終了します。

```
SQL> exit
```

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

tnsnames.oraファイルを作成します。

```
sudo vi $ORACLE_HOME/network/admin/tnsnames.ora
```

DBサーバのtnsnames.oraの内容をコピー&ペーストして保存します。

```tnsnames.ora
DB1 =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = db1.subnet1.vcn1.oraclevcn.com)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = DB1.subnet1.vcn1.oraclevcn.com)
    )
  )
  
PDB1 =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = db1.subnet1.vcn1.oraclevcn.com)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = PDB1.subnet1.vcn1.oraclevcn.com)
    )
  )
```

SQL*PlusでAPサーバからDBシステムのPDB（PDB1）に接続します。

```
sqlplus test/Test#1Test#1@PDB1
```

接続先を確認します。

```
SQL> show con_name

CON_NAME
------------------------------
PDB1
```

SQL*Plusを終了します。

```
SQL> exit
```

アプリケーション用のPHPファイルを作成します。

```
sudo vi /var/www/html/test.php
```

下記の内容を入力して保存します。

```/var/www/html/test.php
<html>
<head><meta charset="UTF-8">
<title>PHP to Oracle Connection Test</title>
</head>
<body>
<?php
    error_reporting(E_ALL);
    ini_set('display_errors', '1');

    $conn = oci_connect('test', 'Test#1Test#1', 'PDB1');
    $stid = oci_parse($conn, 'SELECT deptno,dname,loc FROM dept ORDER BY deptno');
    oci_execute($stid);
    echo "<table border='1'>\n";
    echo "<caption>DEPT Table</caption>\n";
    echo "<tr><th>Dept No.</th><th>Dept Name</th><th>Location</th></tr>\n";
    while ($row = oci_fetch_array($stid, OCI_ASSOC+OCI_RETURN_NULLS)) {
        echo "<tr>\n";
        foreach ($row as $item) {
            echo " <td>" . ($item !== null ? htmlentities($item, ENT_QUOTES) : "&amp;nbsp;") . "</td>\n";
        }
        echo "</tr>\n";
    }
    echo "</table><br>\n";
    echo "Response from ".gethostname();
?>
</body>
</html>
```

# 15.PHPアプリケーションの動作確認

ブラウザから以下のURLにアクセスし、正しく表示されるかを確認します。

http://*\<AP1のパブリックIPアドレス>\*/test.php