Amazon RDS for Oracle と Amazon Elastic File System (EFS) 統合を試してみた

# はじめに
2022/11/14に[「Amazon RDS for Oracle が Amazon Elastic File System (EFS) 統合のサポート」](https://aws.amazon.com/jp/about-aws/whats-new/2022/11/amazon-rds-oracle-amazon-elastic-file-system-integration/)が発表された。

RDS for Oracleにおいて、今までexpdp/impdpは基本的にはS3統合を利用した形でしか行えなかったが、このアップデートを受けて直接ファイルシステムに出力ができるようになり、ダンプファイルの他サーバとの受け渡しが容易に行えるようになった。

# RDSとEFSとの統合
RDSをEFSと統合するためには、いくつか制限がある。
制限等についての詳細は[ユーザガイド](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/oracle-efs-integration.html)に記載があるが、以下となる。
1. Oracle Database 19c - July 2022 Patch Set Update (PSU) 19.0.0.0.ru-2022-07.rur-2022-07.r1 以降でのみサポートされる
1. RDSとEFSは、同じリージョン・同じVPCにある必要がある
1. VPC でenableDnsSupport属性が有効になっている必要がある
1. EFSはStandard または Standard-IA のクラスを使用する必要がある

RDSとEFSを統合するために必要な設定は以下となる。
1. ネットワークアクセス許可の設定
1. IAMアクセス許可の設定
1. RDSオプショングループの設定
1. EFSファイルシステムのアクセス許可の設定
1. EFS上のディレクトリをOracle上のディレクトリオブジェクトとして作成

## [1. ネットワークアクセス許可](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/oracle-efs-integration.html#oracle-efs-integration.network)
セキュリティグループ設定とEFSのファイルシステムポリシーの両方で許可されている必要がある。
### セキュリティグループ設定
RDSからEFSへのアクセスが可能である必要があるのと同時に、以下の要件がある。
1. すべてのアベイラビリティーゾーンにマウントターゲットが存在すること
1. マウントターゲットにセキュリティ グループが関連付けられていること
1. セキュリティグループには、TCP/2049 (タイプ NFS) で RDS for Oracle DB インスタンスのネットワークサブネットまたはセキュリティグループを許可するインバウンドルールがあること

### ファイルシステムポリシー設定
デフォルトのファイルシステムポリシーは空であり、そのまま接続は可能となる。
ファイルシステムポリシーを設定することで、IAMのアクセス許可を構成することが可能となる。

## [2. IAMアクセス許可設定](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/oracle-efs-integration.html#oracle-efs-integration.iam)
以下の流れでの設定が必要となる。
なお、ファイルシステムポリシーでの制限を実施しない場合には、IAMアクセス許可設定は不要となる。
1. EFSへ接続するためのIAMロールを作成する
1. EFS側に「1.」で作成したIAMロールを許可するようファイルシステムポリシーを設定する
1. 「1.」で作成したIAMロールをRDSに関連付ける

## [3. オプショングループ設定](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/oracle-efs-integration.html#oracle-efs-integration.adding)
オプショングループに「EFS_INTEGRATION」を設定し、RDSに関連付ける必要がある。
EFS_INTEGRATIONの設定では、IAM利用の有無やファイルシステムIDを設定する。

## [4. EFSファイルシステムのアクセス許可の設定](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/oracle-efs-integration.html#oracle-efs-integration.file-system)
EFSはデフォルトではroot ユーザー (UID 0) のみがアクセス許可を持っているため、RDS側がアクセスできるように設定する必要がある。
EFS内のファイルシステムのアクセス許可は、EC2等でマウントして手動で設定する必要がある。

## [5. EFS上のディレクトリをOracle上のディレクトリオブジェクトとして作成](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/oracle-efs-integration.html#oracle-efs-integration.transferring.od)
EFS上のディレクトリをOracle上のディレクトリオブジェクトとして作成するには、**rdsadmin.rdsadmin_util.create_directory_efs** プロシージャを利用する。
rdsadmin.rdsadmin_util.create_directory_efsプロシージャは以下の二つのパラメータを持つ。
ディレクトリオブジェクトを作成することで、expdp/impdpがDBMS_DATAPUMPプロシージャを利用して実行可能となる。

|パラメータ名 |データ・タイプ |デフォルト |必須 |説明 |
|-|-|-|-|-|
|p_directory_name |VARCHAR2 |なし |YES |ディレクトリオブジェクトの名前 |
|p_path_on_efs |VARCHAR2 |なし |YES |ファイルシステムのパス<br> /rdsefs- という接頭辞が必須となる <br> /rdsefs-\<filesystem-id\>/\<path\> という形式で設定する|

# RDSからEFSへのexpdpを試してみた

### 環境
RDS for Oracle(t3.small)に約3GBのテストテーブルを作成し、EFSにexpdpを行う。
![画像の貼り付け先_ 2022-11-24 20-09-1923876232.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2313926/67b32325-bdcf-e3c0-2cc6-d5a2907874f0.png)



EFS統合するための手順は上記の通り、流れは以下となる。
1. ネットワークアクセス許可の設定
1. IAMアクセス許可の設定
1. RDSオプショングループの設定
1. EFSファイルシステムのアクセス許可の設定
1. EFS上のディレクトリをOracle上のディレクトリオブジェクトとして作成

## 1. ネットワークアクセス許可の設定
今回はRDSとEFSを同じサブネットに設定し、サブネット内の通信は制限しないセキュリティグループを設定する。

## 2. IAMアクセス許可の設定
今回でデフォルトのEFSポリシーを使用するため、設定しない。
(EC2からマウントする設定とほぼ同様なので、それらの記事等を参照いただければと。。)

## 3. RDSオプショングループの設定
RDS for OracleのオプショングループにEFS_INTEGRATIONを追加し、USE_IAM_ROLEとEFS_IDを設定する。
- USE_IAM_ROLE
    - IAM ROLEを使用してEFSにアクセスする場合にはTRUE、今回はIAM ROLEを利用しないので **FALSE** を設定
- EFS_ID
    - 利用するEFSのFILESYSTEM IDを設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2313926/43ce4b51-d921-cfea-1015-456e2480405f.png)


## 4. EFSファイルシステムのアクセス許可の設定

EFS上のディレクトリをRDSからマウントして利用するため、利用するディレクトリにRDSからマウントできるパーミッションを設定する必要がある。
今回は **datapump** というディレクトリを利用するため、いったんEC2からEFSを/efsとしてマウントし、datapumpディレクトリのパーミッションを777に設定する。
```shell
$ sudo mount -t nfs -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport fs-xxxxxxxxxxxxxxxxx.efs.ap-northeast-1.amazonaws.com:/ /efs
$ sudo mkdir /efs/datapump
$ sudo chmod 777 /efs/datapump
$ ls -d /efs/datapump
drwxrwxrwx 2 root root 6144 Nov 22 02:02 /efs/datapump
```


## 5. EFS上のディレクトリをOracle上のディレクトリオブジェクトとして作成
EFS上の **datapump** ディレクトリをOracle上の **DPDIR_EFS** というディレクトリオブジェクトとして作成する。作成には **rdsadmin.rdsadmin_util.create_directory_efs** パッケージを利用する。

```SQL
SQL> exec rdsadmin.rdsadmin_util.create_directory_efs('DPDIR_EFS','/rdsefs-fs-xxxxxxxxxxxx/datapump');

PL/SQL procedure successfully completed.

SQL> select * from dba_directories;
OWNER      DIRECTORY_NAME                 DIRECTORY_PATH                                                         ORIGIN_CON_ID
---------- ------------------------------ ---------------------------------------------------------------------- -------------
<略>
SYS        DPDIR_EFS                      /rdsefs-fs-xxxxxxxxxxxxxxxx/datapump                                              0
<略>
```

## RDSからEFSへのexpdp
#### DBMS_DATAPUMPプロシージャの利用
RDS上の TESTUSR.TESTTBL をEFS上へDBMS_DATAPUMPプロシージャを利用してexpdpする。今まではexpdpするディレクトリが固定の DATA_PUMP_DIR となっていたが、EFSは自身で作成したディレクトリ(今回は作成した DPDIR_EFSディレクトリ)を指定する。

```SQL
SQL> DECLARE
  v_hdnl NUMBER;
BEGIN
  v_hdnl := DBMS_DATAPUMP.OPEN(operation => 'EXPORT', job_mode => 'TABLE', job_name=>null);
  DBMS_DATAPUMP.ADD_FILE(
    handle    => v_hdnl,
    filename  => 'exp-efs-01.dmp',
    directory => 'DPDIR_EFS',
    filetype  => dbms_datapump.ku$_file_type_dump_file);
  DBMS_DATAPUMP.ADD_FILE(
    handle    => v_hdnl,
    filename  => 'exp-efs-01.log',
    directory => 'DPDIR_EFS',
    filetype  => dbms_datapump.ku$_file_type_log_file);
  DBMS_DATAPUMP.METADATA_FILTER(v_hdnl,'SCHEMA_EXPR','IN (''TESTUSR'')');
  DBMS_DATAPUMP.METADATA_FILTER(v_hdnl,'NAME_EXPR','IN(''TESTTBL'')');
  DBMS_DATAPUMP.START_JOB(v_hdnl);
END;
/

PL/SQL procedure successfully completed.

SQL> select * from table(rdsadmin.rds_file_util.listdir('DPDIR_EFS')) order by mtime;
FILENAME             TYPE         FILESIZE MTIME
-------------------- ---------- ---------- ---------
exp-efs-01.dmp       file       3160178688 22-NOV-22
exp-efs-01.log       file              711 22-NOV-22
datapump/            directory        6144 22-NOV-22
```

ログからも正常にexpdpが終了したことが確認できる。
```SQL
$ cat /efs/datapump/exp-efs-01.log
Starting "ADMIN"."SYS_EXPORT_TABLE_02":
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
Processing object type TABLE_EXPORT/TABLE/TABLE
. . exported "TESTUSR"."TESTTBL"                         2.942 GB 10000001 rows
Master table "ADMIN"."SYS_EXPORT_TABLE_02" successfully loaded/unloaded
******************************************************************************
Dump file set for ADMIN.SYS_EXPORT_TABLE_02 is:
  /rdsefs-fs-xxxxxxxxxxxxxxxx/datapump/exp-efs-01.dmp
Job "ADMIN"."SYS_EXPORT_TABLE_02" successfully completed at Tue Nov 22 20:42:21 2022 elapsed 0 00:03:01
```

#### expdpユーティリティの利用
expdpユーティリティを利用してのエクスポートの実施は以下となる。(接続するユーザにディレクトリのread,write権限のgrantが必要)
```SQL
$ expdp testusr/xxxxxxxx@testdb01.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com:1521/TESTDB01 TABLES='TESTTBL' DIRECTORY='DPDIR_EFS' DUMPFILE='expdp-efs-02.dmp' LOGFILE='expdp-efs-02.log'

Export: Release 21.0.0.0.0 - Production on Sat Nov 26 06:53:37 2022
Version 21.8.0.0.0

Copyright (c) 1982, 2022, Oracle and/or its affiliates.  All rights reserved.

Connected to: Oracle Database 19c Standard Edition 2 Release 19.0.0.0.0 - Production
Starting "TESTUSR"."SYS_EXPORT_TABLE_01":  testusr/xxxxxxxx@testdb01.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com:1521/TESTDB01 TABLES=TESTTBL DIRECTORY=DPDIR_EFS DUMPFILE=expdp-efs-02.dmp LOGFILE=expdp-efs-02.log
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
Processing object type TABLE_EXPORT/TABLE/TABLE
. . exported "TESTUSR"."TESTTBL"                         2.942 GB 10000001 rows
Master table "TESTUSR"."SYS_EXPORT_TABLE_01" successfully loaded/unloaded
******************************************************************************
Dump file set for TESTUSR.SYS_EXPORT_TABLE_01 is:
  /rdsefs-fs-xxxxxxxxxxxxxxxxx/datapump/expdp-efs-02.dmp
Job "TESTUSR"."SYS_EXPORT_TABLE_01" successfully completed at Sat Nov 26 15:56:32 2022 elapsed 0 00:02:51
```

# まとめ
RDS for OracleにおいてEFS統合を利用することで、以下の利点があると考えている。
- 従来オンプレで利用していた運用スクリプトがそのまま利用できる可能性があり、移行が比較的容易となる
    - S3上のファイルのやり取り等を新たに追加する必要がない
    - ログの確認が容易
- エクスポート／インポートの実施時にRDSのローカルボリュームのリソースが消費されない

また、EFSを利用するための追加の設定としては、Oracle内部の設定はディレクトリオブジェクト作成程度となり、影響は少ない。
RDS側の設定としてもIAMやSecurityGroup・オプショングループの設定となるため、設定にあたっての影響は限定的といえる。
一点、厳密に確認したわけではないがEFSへのエクスポートと、ローカルへのエクスポート＆S3へのアップロードを比較すると、後者のほうが合計時間としても若干性能が良かった。
利用する場合には性能要件も確認したうえで選択することが必要といえる。


| |エクスポート所要時間(※)|
|-|-|
|EFS統合|159秒|
|S3統合|152秒  (63秒:expdp + 89秒:s3_Upload)|

※3回実施した平均、RDSはt3.small、ローカルストレージは20GB(gp2)、EFSはスタンダード汎用、データサイズ 2.942GB

###### EFSファイルシステムのアクセス許可について
RDS for Oracleからdatapumpしたファイルのオーナは **3001:101** になっていた。
datapump用のディレクトリのオーナ、パーミッションも **3001:101 775** に設定しても正常にexpdpが可能であった。

```SQL
$ sudo chown 3001:101 /efs/datapump
$ sudo chmod 775 /efs/datapump
$ ll -d /efs/datapump/
drwxrwxr-x 2 3001 101 6144 Nov 26 07:03 /efs/datapump/
$ expdp testusr/xxxxxxxx@testdb01.xxxxxxxxxx.ap-northeast-1.rds.amazonaws.com:1521/TESTDB01 TABLES='TESTTBL' DIRECTORY='DPDIR_EFS' DUMPFILE='expdp-efs-05.dmp' LOGFILE='expdp-efs-05.log'

Export: Release 21.0.0.0.0 - Production on Mon Nov 28 02:03:11 2022
Version 21.8.0.0.0

Copyright (c) 1982, 2022, Oracle and/or its affiliates.  All rights reserved.

Connected to: Oracle Database 19c Standard Edition 2 Release 19.0.0.0.0 - Production
Starting "TESTUSR"."SYS_EXPORT_TABLE_01":  testusr/xxxxxxxx@testdb01.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com:1521/TESTDB01 TABLES=TESTTBL DIRECTORY=DPDIR_EFS DUMPFILE=expdp-efs-05.dmp LOGFILE=expdp-efs-05.log
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
Processing object type TABLE_EXPORT/TABLE/TABLE
. . exported "TESTUSR"."TESTTBL"                         2.942 GB 10000001 rows
Master table "TESTUSR"."SYS_EXPORT_TABLE_01" successfully loaded/unloaded
******************************************************************************
Dump file set for TESTUSR.SYS_EXPORT_TABLE_01 is:
  /rdsefs-fs-xxxxxxxxxxxxxxxxx/datapump/expdp-efs-05.dmp
Job "TESTUSR"."SYS_EXPORT_TABLE_01" successfully completed at Mon Nov 28 11:06:29 2022 elapsed 0 00:03:15

```


RDS Custom for Oracleの検証の際に、ファイルのオーナは **rdsdb:database** となっていたので、RDS for Oracleでも同様になると考えられる。ただ、現時点ではガイド等にも記載がないため、都度確認しておくのが良いと思われる。

ちなみに、オーナ、パーミッションを **root:root 775**に設定すると当然だがexpdpは権限不足で失敗した。
```SQL
$ sudo chown root:root /efs/datapump
$ ll -d /efs/datapump/
drwxrwxr-x 2 root root 6144 Nov 28 02:03 /efs/datapump/

$ expdp testusr/xxxxxxx@testdb01.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com:1521/TESTDB01 TABLES='TESTTBL' DIRECTORY='DPDIR_EFS' DUMPFILE='expdp-efs-06.dmp' LOGFILE='expdp-efs-06.log'

Export: Release 21.0.0.0.0 - Production on Mon Nov 28 02:07:36 2022
Version 21.8.0.0.0

Copyright (c) 1982, 2022, Oracle and/or its affiliates.  All rights reserved.

Connected to: Oracle Database 19c Standard Edition 2 Release 19.0.0.0.0 - Production
ORA-39002: invalid operation
ORA-39070: Unable to open the log file.
ORA-29283: invalid file operation: cannot open file [29435]
```


## 参考(RDSからS3へのexpdp)
S3統合機能を利用する場合には、一度ローカルの **DATA_PUMP_DIR** ディレクトリに出力後、S3にuploadを行う必要がある。
![画像の貼り付け先_ 2022-11-24 20-09--1965348285.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2313926/2dc48fa9-9bff-f264-6cba-40f374a04cb0.png)


###### DATA_PUMP_DIRへのexpdp
まずはローカルのDATA_PUMP_DIRにexpdpを行う。
以下ではDBMS_DATAPUMPを利用しているがEC2インスタンス等の外部からexpdpユーティリティを利用して実行することも可能。
```SQL
SQL> DECLARE
hdnl NUMBER;
BEGIN
hdnl := DBMS_DATAPUMP.open( operation => 'EXPORT', job_mode => 'TABLE', job_name=>null);
DBMS_DATAPUMP.ADD_FILE( handle => hdnl, filename => 'exp-s3-03.dmp', directory => 'DATA_PUMP_DIR', filetype => dbms_datapump.ku$_file_type_dump_file);
DBMS_DATAPUMP.ADD_FILE( handle => hdnl, filename => 'exp-s3-03.log', directory => 'DATA_PUMP_DIR', filetype => dbms_datapump.ku$_file_type_log_file);
DBMS_DATAPUMP.METADATA_FILTER(hdnl,'SCHEMA_EXPR','IN (''TESTUSR'')');
DBMS_DATAPUMP.METADATA_FILTER(hdnl,'NAME_EXPR','IN(''TESTTBL'')');
DBMS_DATAPUMP.start_job(hdnl);
END;
/

PL/SQL procedure successfully completed.

SQL> select * from table (rdsadmin.rds_file_util.listdir(p_directory => 'DATA_PUMP_DIR')) order by mtime;

FILENAME             TYPE         FILESIZE MTIME
-------------------- ---------- ---------- -------------------
exp-s3-03.log        file              273 2022/11/22 21:00:45
datapump/            directory        4096 2022/11/22 21:01:09
exp-s3-03.dmp        file       2720284672 2022/11/22 21:01:09
```

expdp実施時のログ(exp-s3-03.log)は以下。
```SHELL
Starting "ADMIN"."SYS_EXPORT_TABLE_01":  
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
Processing object type TABLE_EXPORT/TABLE/TABLE
. . exported "TESTUSR"."TESTTBL"                         2.942 GB 10000001 rows
Master table "ADMIN"."SYS_EXPORT_TABLE_01" successfully loaded/unloaded
******************************************************************************
Dump file set for ADMIN.SYS_EXPORT_TABLE_01 is:
  /rdsdbdata/datapump/exp-s3-03.dmp
Job "ADMIN"."SYS_EXPORT_TABLE_01" successfully completed at Tue Nov 22 21:01:18 2022 elapsed 0 00:01:03
```

###### DATA_PUMP_DIRからS3へのupload
**rdsadmin.rdsadmin_s3_tasks.upload_to_s3** プロシージャを利用して、S3へのアップロードを行う。(dmpファイルとlogファイルの両方をアップロードする) 
```SQL
SQL> SELECT rdsadmin.rdsadmin_s3_tasks.upload_to_s3(
   p_bucket_name    =>  'asahitest-s3-bucket',
   p_prefix         =>  'exp-s3-03.dmp',
   p_s3_prefix      =>  'datapump/',
   p_directory_name =>  'DATA_PUMP_DIR')
AS TASK_ID FROM DUAL;

TASK_ID
---------------------------------------------------------------------------
1669118515058-205

SQL> SELECT rdsadmin.rdsadmin_s3_tasks.upload_to_s3(
   p_bucket_name    =>  'asahitest-s3-bucket',
   p_prefix         =>  'exp-s3-03.log',
   p_s3_prefix      =>  'datapump/',
   p_directory_name =>  'DATA_PUMP_DIR')
AS TASK_ID FROM DUAL;

TASK_ID
---------------------------------------------------------------------------
1669118517490-205
```

**rdsadmin.rds_file_util.read_text_file**プロシージャを利用すると、S3へのアップロードのログを確認できる。
無事アップロードが完了していることがわかる。
```SQL
SQL> SELECT text FROM table(rdsadmin.rds_file_util.read_text_file('BDUMP','dbtask-1669118515058-205.log'));
TEXT
--------------------------------------------------
2022-11-22 12:01:57.198 UTC [INFO ] File #1: Uploading the file /rdsdbdata/datapump/exp-s3-03.dmp to Amazon S3 with bucket name asahitest-s3-bucket and key datapump/exp-s3-03.dmp.
2022-11-22 12:03:23.848 UTC [INFO ] The file /rdsdbdata/datapump/exp-s3-03.dmp was uploaded to Amazon S3 with bucket name asahitest-s3-bucket and key datapump/exp-s3-03.dmp.
2022-11-22 12:03:23.851 UTC [INFO ] The task finished successfully.

SQL> SELECT text FROM table(rdsadmin.rds_file_util.read_text_file('BDUMP','dbtask-1669118517490-205.log'));

TEXT
--------------------------------------------------
2022-11-22 12:03:24.024 UTC [INFO ] File #1: Uploading the file /rdsdbdata/datapump/exp-s3-03.log to Amazon S3 with bucket name asahitest-s3-bucket and key datapump/exp-s3-03.log.
2022-11-22 12:03:24.113 UTC [INFO ] The file /rdsdbdata/datapump/exp-s3-03.log was uploaded to Amazon S3 with bucket name asahitest-s3-bucket and key datapump/exp-s3-03.log.
2022-11-22 12:03:24.114 UTC [INFO ] The task finished successfully.
```