RDSのOracleでdumpファイルを扱う

RDS Oracleにて、dumpを扱う方法が随分簡単になっていたので、試したときのメモです。

設定

まずは利用するための設定を実施。以下が公式マニュアル。

Amazon S3 の統合

S3Bucketの作成

dumpファイルを置くためのS3Bucketを作成しておきます。今回は oracle-dump-zunda という名前のBucketを作成しています。

RDS用のIAM Roleの作成

dumpファイルを置くことになるS3Bucketへのアクセス権限をもった、RDS向けのIAM Roleを作成します。CloudFormationテンプレートでは、こんな感じです。

AWSTemplateFormatVersion: "2010-09-09"
Description: "IAM Role for RDS Oracle Integration with Amazon S3"
Resources:
  IamRole:
  # https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html
    Type: "AWS::IAM::Role"
    DeletionPolicy: "Delete"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "rds.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      # Description: String
      # ManagedPolicyArns:
        # - String
      # MaxSessionDuration: Integer
      Path: "/role/"
      # PermissionsBoundary: String
      Policies:
        - PolicyName: "S3-Bucket-Access"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Action:
                  - "s3:GetObject"
                  - "s3:ListBucket"
                  - "s3:PutObject"
                Resource:
                  - "arn:aws:s3:::oracle-dump-zunda"
                  - "arn:aws:s3:::oracle-dump-zunda/*"
      RoleName: "ForOracleDump"
      # Tags:
        # - Tag

RDS Option Groupの変更

RDSで利用するOption Groupに、Option S3_INTEGRATION を追加します。

f:id:goodbyegangster:20191115022746p:plain

RDSインスタンスにRoleを付与

RDSインスタンスにIAM Roleを付与するには、RDSのコンソールの Connectivity & security タブの Manage IAM roles セクションを変更することになります。下の画面です。

f:id:goodbyegangster:20191115022756p:plain

dumpのエクスポート&インポート

設定は完了しましたので、実際にdumpを試してみます。以下が公式マニュアル。

Amazon RDS での Oracle へのデータのインポート

後述作業、全てRDS masteruserで接続して実行しています。

dumpのエクスポート

RDSにおいても、dump処理用のDATA_PUMP_DIRディレクトリオブジェクトが用意されており、dumpファイルにてこのOS領域を利用できます。ちなみに、DATA_PUMP_DIRディレクトリのOS上パスはこちらですが、OS層にアクセスできないRDSでは、AWS側で用意されたプロシージャを利用することになります。

> column owner format a10
> column directory_name format a20
> column directory_path format a30
> select * from dba_directories;

OWNER      DIRECTORY_NAME       DIRECTORY_PATH
---------- -------------------- ------------------------------
SYS        RDS$DB_TASKS         /rdsdbdata/dbtasks
SYS        BDUMP                /rdsdbdata/log/trace
SYS        ADUMP                /rdsdbdata/log/audit
SYS        DATA_PUMP_DIR        /rdsdbdata/datapump

DBA_DIRECTORIES

dumpの取得には、Oracle DBに最初からIncludeされているPL/SQLDBMS_DATAPUMP というパッケージを利用します。dumpエクスポート処理時のジョブを作成するサンプルは、以下となります。スキーマ zunda のdaumpファイルを、 ディレクトDATA_PUMP_DIR 上でにエクスポートする処理となっています。ダンプファイルのほか、処理実行時のログ・ファイルも出力しています。

DECLARE
hdnl NUMBER;
status VARCHAR2(20);
BEGIN
hdnl := DBMS_DATAPUMP.OPEN(
  operation => 'EXPORT',
  job_mode => 'SCHEMA',
  job_name => null
);

DBMS_DATAPUMP.ADD_FILE(
  handle => hdnl,
  filename => 'zunda-20191114.dmp',
  directory => 'DATA_PUMP_DIR',
  filetype => dbms_datapump.ku$_file_type_dump_file,
  reusefile => 0
);

DBMS_DATAPUMP.ADD_FILE(
  handle => hdnl,
  filename => 'zunda-export-20191114.log',
  directory => 'DATA_PUMP_DIR',
  filetype => dbms_datapump.ku$_file_type_log_file,
  reusefile => 0
);

DBMS_DATAPUMP.METADATA_FILTER(hdnl,'SCHEMA_EXPR','IN (''ZUNDA'')');
DBMS_DATAPUMP.START_JOB(handle => hdnl);
DBMS_DATAPUMP.WAIT_FOR_JOB(handle => hdnl, job_state => status);
END;
/

実行されているDBMS_DATAPUMPパッケージの各プロシージャ詳細は、以下より確認できます。

DBMS_DATAPUMPサブプログラムの要約

なお、RDSで利用できるdumpの対象は、スキーマまたはテーブルとなります。fullモードのdumpは利用しては駄目とのこと。

特定のスキーマやオブジェクトをインポートするには、schema または table モードでインポートを実行します。

インポートするスキーマをアプリケーションに必要なスキーマに制限します。

full モードではインポートしないでください。Amazon RDS for Oracle では、管理ユーザー SYS または SYSDBA へのアクセスは許可されていないため、full モードでインポートしたり、Oracle 管理のコンポーネントスキーマをインポートしたりすると、Oracle データディレクトリが損傷し、データベースの安定性に影響を及ぼす可能性があります。

エクスポートされたdumpファイルは、RDSにて用意された RDSADMIN.RDS_FILE_UTIL.LISTDIR プロシージャを利用することで確認できます。

> column filename format a30
> column type format a10
> column mtime format a10
> select * from table(RDSADMIN.RDS_FILE_UTIL.LISTDIR(p_directory => 'DATA_PUMP_DIR')) order by mtime;

FILENAME                       TYPE         FILESIZE MTIME
------------------------------ ---------- ---------- ----------
datapump/                      directory        4096 14-NOV-19
zunda-20191114.dmp             file           188416 14-NOV-19
zunda-export-20191114.log      file              967 14-NOV-19

DB インスタンスディレクトリ内のファイルの一覧表示

ディレクトリオブジェクト上に存在するファイルは、RDSにて用意された RDSADMIN.RDS_FILE_UTIL.LISTDIR プロシージャを利用することで参照することができるので、以下にて今回処理のログ・ファイルを参照可能です。

> select * from table
>   (rdsadmin.rds_file_util.read_text_file(
>     p_directory => 'DATA_PUMP_DIR',
>     p_filename  => 'zunda-export-20191114.log'));

TEXT
--------------------------------------------------------------------------------
Starting "ADMIN"."SYS_EXPORT_SCHEMA_08":
Estimate in progress using BLOCKS method...
Processing object type SCHEMA_EXPORT/TABLE/TABLE_DATA
Total estimation using BLOCKS method: 64 KB
Processing object type SCHEMA_EXPORT/USER
Processing object type SCHEMA_EXPORT/SYSTEM_GRANT
Processing object type SCHEMA_EXPORT/ROLE_GRANT
Processing object type SCHEMA_EXPORT/DEFAULT_ROLE
Processing object type SCHEMA_EXPORT/TABLESPACE_QUOTA
Processing object type SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
Processing object type SCHEMA_EXPORT/TABLE/TABLE

TEXT
--------------------------------------------------------------------------------
. . exported "ZUNDA"."SAMPLE"                            5.492 KB       7 rows
Master table "ADMIN"."SYS_EXPORT_SCHEMA_08" successfully loaded/unloaded
******************************************************************************
Dump file set for ADMIN.SYS_EXPORT_SCHEMA_08 is:
  /rdsdbdata/datapump/zunda-20191114.dmp
Job "ADMIN"."SYS_EXPORT_SCHEMA_08" successfully completed at Thu Nov 14 15:14:05
 2019 elapsed 0 00:00:02

17 rows selected.

DB インスタンスディレクトリ内のファイルの読み取り

ディレクトリオブジェクト上のファイルは、RDSにて用意された rdsadmin.rdsadmin_s3_tasks.upload_to_s3 プロシージャを利用することで、S3へアップロードすることが可能です。以下の例は、 DATA_PUMP_DIR にある zunda-20191114.dmp ファイルを、 s3://oracle-dump-zunda/zunda/20191114/zunda-20191114.dmp というS3オブジェクトしてアップロードする処理となっています。

> SELECT rdsadmin.rdsadmin_s3_tasks.upload_to_s3(
>     p_directory_name => 'DATA_PUMP_DIR',
>     p_prefix => 'zunda-20191114.dmp',
>     p_bucket_name => 'oracle-dump-zunda',
>     p_s3_prefix => 'zunda/20191114/')
>   AS TASK_ID FROM DUAL;

TASK_ID
--------------------------------------------------------------------------------
1573713349502-624

Oracle DB インスタンスから Amazon S3 バケットにファイルをアップロードする

実行処理はBDUMディレクトリにログを出力してくれます。upload処理を実行した際にTASK_IDを返されるので、ファイル名を dbtask-(TASK_ID).log として、以下のSQLにて確認できます。

> SELECT text FROM table(
>   rdsadmin.rds_file_util.read_text_file(
>     p_directory => 'BDUMP',
>     p_filename  => 'dbtask-1573713349502-624.log'));

TEXT
--------------------------------------------------------------------------------
2019-11-14 06:35:49.556 UTC [INFO ] File #1: Uploading the file /rdsdbdata/datap
ump/zunda-20191114.dmp to Amazon S3 with bucket name oracle-dump-zunda and key z
unda/20191114/zunda-20191114.dmp.

2019-11-14 06:35:49.706 UTC [INFO ] The file /rdsdbdata/datapump/zunda-20191114.
dmp was uploaded to Amazon S3 with bucket name oracle-dump-zunda and key zunda/2
0191114/zunda-20191114.dmp.

2019-11-14 06:35:49.706 UTC [INFO ] The task finished successfully.

S3上にアップロードできたことを確認できた後、 DATA_PUMP_DIR 上にあるdumpファイルは削除してしまいます。削除には UTL_FILE.FREMOVE プロシージャを利用します。

exec utl_file.fremove( location => 'DATA_PUMP_DIR', filename => 'zunda-20191114.dmp');
exec utl_file.fremove( location => 'DATA_PUMP_DIR', filename => 'zunda-export-20191114.log');

UTL_FILE.FREMOVEプロシージャ

dumpのインポート

続いてdumpのインポート処理です。

S3上にあるdumpファイルは、RDSにて用意された rdsadmin.rdsadmin_s3_tasks.download_from_s3 プロシージャを利用することでRDSのディレクトリオブジェクト上にダウンロードすることができます。

> SELECT rdsadmin.rdsadmin_s3_tasks.download_from_s3(
>     p_bucket_name => 'oracle-dump-zunda',
>     p_s3_prefix => 'zunda/20191114/zunda-20191114.dmp',
>     p_directory_name => 'DATA_PUMP_DIR')
>   AS TASK_ID FROM DUAL;

TASK_ID
--------------------------------------------------------------------------------
1573713541244-624

Amazon S3 バケットから Oracle DB インスタンスにファイルをダウンロードする

ダウンロードされたことを確認します。

> column filename format a30
> column type format a10
> column mtime format a10
> select * from table(RDSADMIN.RDS_FILE_UTIL.LISTDIR(p_directory => 'DATA_PUMP_DIR')) order by mtime;

FILENAME                       TYPE         FILESIZE MTIME
------------------------------ ---------- ---------- ----------
zunda-20191114.dmp             file           188416 14-NOV-19
datapump/                      directory        4096 14-NOV-19

dumpをぶち込む前に、既存であるスキーマを削除してしまいます。

DROP USER ZUNDA CASCADE;

DBへのインポート処理も、DBMS_DATAPUMP パッケージを利用します。以下がサンプルとなります。

DECLARE
hdnl NUMBER;
status VARCHAR2(20);
BEGIN
hdnl := DBMS_DATAPUMP.OPEN(
  operation => 'IMPORT',
  job_mode => 'SCHEMA',
  job_name => null);

DBMS_DATAPUMP.ADD_FILE(
  handle => hdnl,
  filename => 'zunda-20191114.dmp',
  directory => 'DATA_PUMP_DIR',
  filetype => dbms_datapump.ku$_file_type_dump_file);

DBMS_DATAPUMP.ADD_FILE(
  handle => hdnl,
  filename => 'zunda-import-20191114.log',
  directory => 'DATA_PUMP_DIR',
  filetype => dbms_datapump.ku$_file_type_log_file
);

DBMS_DATAPUMP.METADATA_FILTER(hdnl,'SCHEMA_EXPR','IN (''ZUNDA'')');
DBMS_DATAPUMP.START_JOB(handle => hdnl);
DBMS_DATAPUMP.WAIT_FOR_JOB(handle => hdnl, job_state => status);
END;
/

実行ログを確認します。

select * from table
  (rdsadmin.rds_file_util.read_text_file(
    p_directory => 'DATA_PUMP_DIR',
    p_filename  => 'zunda-import-20191114.log'));

dump対象のスキーマ内にあるテーブルにアクセスして、インポートされていることを確認します。最後に DATA_PUMP_DIR 上のファイルを削除しておきます。

exec utl_file.fremove( location => 'DATA_PUMP_DIR', filename => 'zunda-20191114.dmp');
exec utl_file.fremove( location => 'DATA_PUMP_DIR', filename => 'zunda-import-20191114.log');