Amazon RDS for OracleのRMANでバックアップを取得してS3に転送してみた
コンバンハ、千葉(幸)です。
Amazon RDS for Oracleの利用を検討する機会がありました。わたしは他のDBエンジンでAmazon RDSを使ったことはありますが、for Oracleは初めてです。
Oracleデータベースには RMAN(Recovery Manager) というバックアップ・リカバリのための仕組みがあります。
Amazon RDSではスナップショットという仕組みがある中で、どのような機会にRMANを使うのか?使うとしたらどのような設定や操作が必要になるのか?が気になりました。
実際に動かしてイメージを掴みたいと思い、簡単な構成を作ってバックアップ取得までの一連の流れを試してみました。
この記事は、RDSは使い慣れているけれどOracleやRMANはあまり触ったことがない方、あるいは逆に OracleやRMANは分かるけれどRDSでどう扱うのかが気になる方を想定して書いています。わたしが前者の立場なのでRDSやAWSまわりの説明がサラッとになってしまうかもしれませんが、なるべく補足しながら書いていきます。
先にまとめ

-
Amazon RDSではRMANをOSのコマンドラインから直接実行できない
rdsadmin.rdsadmin_rman_utilパッケージのPL/SQLプロシージャを呼び出して操作する(SQL*PlusなどのSQLクライアントから実行する)rdsadmin.rdsadmin_rman_utilパッケージのインストールなどを利用者側で意識する必要はない
-
DBインスタンスでバックアップ保持期間を0日以外にすることでRMANが利用可能となる
-
RMANによるバックアップはDBインスタンスのローカルEBSに保存される。下記に保存することも可能
- DBインスタンスに統合されたEFSファイルシステム(外部ディレクトリとして指定可能)
- DBインスタンスに統合されたS3バケット(別途アップロードが必要)
-
RMANバックアップをRDS DBインスタンスにリストアすることはできない
- オンプレミスやEC2インスタンスなどのセルフマネージドな環境へのリストアは可能
そもそもRMANとは何か
RMANはOracle Databaseに付属するバックアップ・リカバリツールです。Oracleデータベースの管理者が日常的に使うもので、主に以下のような操作に使われます。
- フルバックアップ: データベース全体をバックアップする
- インクリメンタルバックアップ: 前回のバックアップ以降に変更されたブロックだけをバックアップする
- アーカイブログのバックアップ: トランザクションログを別途保管する
- バックアップの検証: バックアップファイルが正しく取れているか確認する
- リストア・リカバリ: バックアップからデータベースを復元する
従来のオンプレミス環境ではテープやディスクへの書き出しが一般的でした。
Amazon RDSでのRMANはオンプレミスと何が違うのか?
オンプレミスではRMANをコマンドラインで直接実行できますが、RDSはマネージドサービスのためOSへのアクセスができません。AWSはrdsadminスキーマに管理用パッケージを用意しており、RMANもその一つrdsadmin_rman_utilパッケージのPL/SQLプロシージャを呼び出す形で操作します。プロシージャを実行するクライアントはSQL DeveloperやSQLclなどOracleに接続できるツールであれば何でも構いません(本記事ではSQL*Plusを使います)。
| オンプレミス | Amazon RDS | |
|---|---|---|
| 実行方法 | rmanコマンドを直接実行 |
rdsadmin.rdsadmin_rman_utilのPL/SQLプロシージャを呼び出す(SQLクライアントから実行) |
| RMANバックアップ先(Oracle Directory) | テープ・ディスク・NFSなど | ローカルEBSもしくはEFS。S3へのアップロードも可 |
| リストア | 同インスタンスまたは別インスタンスに可 | DBインスタンス上では不可。EC2/オンプレミスなどのインスタンスへリストア可能 |
| ARCHIVELOG | 手動で有効化が必要 | バックアップ保持期間を1日以上に設定すれば自動で有効 |
Amazon RDSではオプショングループ、パラメータグループという概念がありますが、RMANの利用そのものではこれらを意識する必要はありません。EFSやS3との統合を行う際にはオプショングループを意識する必要があります。
RDSでのRMANは、従来のrmanと全く同じ操作が可能なわけではありません。詳細は Amazon RDS for OracleでのRMANの使用 を参照してください。
RDSでのバックアップにRMANは必要?
Amazon RDSには自動バックアップの仕組みが標準で備わっています。
個々のデータベースだけでなく、ストレージボリューム全体のスナップショットを自動もしくは手動で取得できます。
スナップショットからの復元として、新たなRDS DBインスタンスを作成できます。スナップショット取得時点に復元することも、ポイントインタイムリカバリ機能によって期間内の任意の時点に復元することもできます。
詳細は以下の公式ドキュメントにまとまっています。
Oracle DBインスタンスをRDSで運用し続けていくのであれば、これらの標準機能を用いる形で問題ないでしょう。RMANで取得したバックアップはRDS DBインスタンスに復元できません。
別の環境でリストアする必要が生じた場合や、将来的な別環境でのリストアを見越して長期保存する必要がある、といった場合にはRMANを使う機会があります。セルフマネージドインスタンスへのリストアを伴うユースケースは下記ブログで紹介されています。
Amazon RDSでのRMANを試してみる
今回は下記の構成で試してみます。

- EC2にOracle接続のクライアントであるSQL*Plusをインストールし、そこからRDS DBインスタンスに接続、操作する
- PL/SQLプロシージャでRMAN操作を実施し、バックアップを取得する
- 取得したRMANバックアップをS3にアップロードする
CloudFormationで環境一式を構築します。一連の操作はAWS CloudShell経由で行います。
確認シナリオ
EC2からDBインスタンスに接続したあと、以下の流れで進めます。
- 事前準備:アーカイブログをバックアップに含めるための保持期間を設定し、テストデータを投入する
- 健全性の検証:
validate_databaseでソースデータベースに破損がないか確認する - フルバックアップ:アーカイブログを含むフルバックアップをDBインスタンスのローカルに取得する
- S3へ転送:取得したバックアップをS3へアップロードする
- ローカルバックアップ削除:ローカルのバックアップファイルを削除する
あわせて、各ステップでDBインスタンスの空き容量(CloudWatchのFreeStorageSpace)がどう増減するかも確認し、バックアップがローカルストレージを消費する様子を見ていきます。
検証環境のバージョン
今回の検証環境の各種バージョンは以下のとおりです。
| 項目 | バージョン |
|---|---|
| AWS CLI(AWS CloudShell) | aws-cli/2.34.54 Python/3.14.5 Linux/6.1.166-197.305.amzn2023.x86_64 exec-env/CloudShell exe/x86_64.amzn.2023 |
| AWS CLI(EC2) | aws-cli/2.33.15 Python/3.9.25 Linux/6.1.172-216.329.amzn2023.x86_64 source/x86_64.amzn.2023 |
| EC2 AMI | al2023-ami-2023.11.20260526.0-kernel-6.1-x86_64 (ami-0b53194d9d4d5cfea) |
| Oracle Database | Standard Edition 2 (SE2) / 19c |
| Oracle Instant Client / SQL*Plus(クライアント) | Release 19.0.0.0.0 / Version 19.27.0.0.0 |
| RDS Oracleエンジン | 19.0.0.0.ru-2026-01.rur-2026-01.r3(DB本体はVersion 19.30.0.0.0) |
実行環境ごとのコマンド
操作は AWS CloudShell(手元のターミナルでも可) と EC2 の2か所で行います。今回は作業の流れでEC2上でいくつかのAWS CLIコマンドを実行していますが、これはAWS CloudShell(もしくは手元のターミナル)から実行しても問題ありません。好みです。
AWS CloudShell
| 用途 | コマンド |
|---|---|
| 利用可能なOracleバージョン確認 | aws rds describe-db-engine-versions |
| スタックのデプロイ | aws cloudformation deploy |
| Outputs(エンドポイント・インスタンスID等)取得 | aws cloudformation describe-stacks |
| EC2へ接続 | aws ssm start-session |
| S3バケットを空にする(削除前) | aws s3 rm --recursive |
| スタック削除 | aws cloudformation delete-stack |
EC2シェル(sh-5.2$)— AWS CLI
| 用途 | コマンド |
|---|---|
| DBインスタンスの設定確認 | aws rds describe-db-instances |
| パスワード取得 | aws secretsmanager get-secret-value |
| 空き容量の確認 | aws cloudwatch get-metric-statistics |
| S3上のバックアップ確認 | aws s3 ls |
EC2上のSQL*Plus(SQL>)
| 用途 | 呼び出し |
|---|---|
| DBインスタンスへ接続 | sqlplus "admin/${DB_PASS}@${DB_HOST}:1521/ORCL" |
| アーカイブログ保持期間の設定 | rdsadmin.rdsadmin_util.set_configuration |
| 設定値の確認 | rdsadmin.rds_configurationをSELECT |
| テストデータ作成 | CREATE TABLE test_large ... |
| テストデータ投入(ベース1,000行) | INSERT INTO test_large ... |
| テストデータ投入(99.9万行) | INSERT /*+ APPEND */ INTO test_large ... |
| セグメントサイズ確認 | user_segmentsをSELECT |
| データベースの健全性検証 | rdsadmin.rdsadmin_rman_util.validate_database |
| バックアップ用ディレクトリ作成 | rdsadmin.rdsadmin_util.create_directory |
| ディレクトリの中身確認 | rdsadmin.rds_file_util.listdir |
| フルバックアップ取得 | rdsadmin.rdsadmin_rman_util.backup_database_full |
| S3へ転送 | rdsadmin.rdsadmin_s3_tasks.upload_to_s3 |
| 転送ログ確認 | rdsadmin.rds_file_util.read_text_file |
| ローカルバックアップ削除 | utl_file.fremove |
CloudFormationで環境を構築する
検証用の構成をCloudFormationでまとめて構築します。作成されるリソースは以下のとおりです。
| リソース種別 | 名前 | 用途 |
|---|---|---|
| VPC | rman-lab-vpc | ネットワーク |
| サブネット(パブリック) | rman-lab-public-1a | EC2配置用 |
| サブネット(プライベート) | rman-lab-private-1a / 1c | DBインスタンス配置用 |
| セキュリティグループ | rman-lab-ec2-sg | EC2用(インバウンドなし) |
| セキュリティグループ | rman-lab-rds-sg | DBインスタンス用(1521のみ許可) |
| S3バケット | rman-backup-{アカウントID}-ap-northeast-1 | RMANバックアップ転送先 |
| IAMロール | rman-lab-ec2-role | EC2用(SSM接続+ AWS CLI用の参照権限) |
| IAMロール | rman-lab-rds-s3-role | RDS S3統合用 |
| Secrets Manager | rman-lab-db-secret | DBパスワード自動生成 |
| RDSサブネットグループ | rman-lab-subnet-group | DBインスタンス配置先 |
| DBインスタンス | rman-lab-oracle | Oracle SE2 19c |
| EC2インスタンス | rman-lab-ec2 | Oracleクライアント |
CloudFormationテンプレート
今回作成する環境を、あまりお行儀良くないですがひとつのテンプレートに詰め込みました。
折りたたみ
AWSTemplateFormatVersion: '2010-09-09'
Description: 'RMAN on RDS Oracle SE2 - Lab Environment'
Parameters:
LatestAL2023AMI:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64
OracleEngineVersion:
Type: String
Description: >
oracle-se2 engine version. Check available versions with:
aws rds describe-db-engine-versions --engine oracle-se2 --region ap-northeast-1
--query 'DBEngineVersions[*].[EngineVersion]' --output text --no-cli-pager
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: rman-lab-vpc
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: rman-lab-igw
IGWAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.1.0/24
AvailabilityZone: ap-northeast-1a
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: rman-lab-public-1a
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: rman-lab-public-rtb
PublicDefaultRoute:
Type: AWS::EC2::Route
DependsOn: IGWAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnetRTBAssoc:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet
RouteTableId: !Ref PublicRouteTable
PrivateSubnet1a:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.2.0/24
AvailabilityZone: ap-northeast-1a
Tags:
- Key: Name
Value: rman-lab-private-1a
PrivateSubnet1c:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.3.0/24
AvailabilityZone: ap-northeast-1c
Tags:
- Key: Name
Value: rman-lab-private-1c
EC2SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: EC2 client - SSM only, no inbound
VpcId: !Ref VPC
SecurityGroupEgress:
- IpProtocol: -1
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: rman-lab-ec2-sg
RDSSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: RDS Oracle - allow 1521 from EC2
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 1521
ToPort: 1521
SourceSecurityGroupId: !Ref EC2SecurityGroup
Tags:
- Key: Name
Value: rman-lab-rds-sg
RMANBackupBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub 'rman-backup-${AWS::AccountId}-${AWS::Region}'
LifecycleConfiguration:
Rules:
- Id: DeleteOldBackups
Status: Enabled
ExpirationInDays: 7
Tags:
- Key: Name
Value: rman-backup-bucket
EC2Role:
Type: AWS::IAM::Role
Properties:
RoleName: rman-lab-ec2-role
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
Policies:
- PolicyName: RMANLabEC2Policy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- secretsmanager:GetSecretValue
Resource: !Ref DBSecret
- Effect: Allow
Action:
- cloudwatch:GetMetricStatistics
- rds:DescribeDBInstances
Resource: '*'
- Effect: Allow
Action:
- s3:ListBucket
- s3:GetObject
Resource:
- !GetAtt RMANBackupBucket.Arn
- !Sub '${RMANBackupBucket.Arn}/*'
EC2InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
InstanceProfileName: rman-lab-ec2-profile
Roles:
- !Ref EC2Role
RDSOracleS3Role:
Type: AWS::IAM::Role
Properties:
RoleName: rman-lab-rds-s3-role
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: rds.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: RMANBackupS3Policy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- s3:PutObject
- s3:GetObject
- s3:DeleteObject
- s3:ListBucket
Resource:
- !GetAtt RMANBackupBucket.Arn
- !Sub '${RMANBackupBucket.Arn}/*'
DBSecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: rman-lab-db-secret
Description: RDS Oracle master password
GenerateSecretString:
SecretStringTemplate: '{"username": "admin"}'
GenerateStringKey: password
PasswordLength: 16
ExcludeCharacters: '"@/\;+%{}[]&'
DBSubnetGroup:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: rman-lab subnet group
SubnetIds:
- !Ref PrivateSubnet1a
- !Ref PrivateSubnet1c
Tags:
- Key: Name
Value: rman-lab-subnet-group
RMANOptionGroup:
Type: AWS::RDS::OptionGroup
Properties:
EngineName: oracle-se2
MajorEngineVersion: '19'
OptionGroupDescription: RMAN lab S3 integration
OptionConfigurations:
- OptionName: S3_INTEGRATION
Tags:
- Key: Name
Value: rman-lab-og
OracleDB:
Type: AWS::RDS::DBInstance
DeletionPolicy: Delete
Properties:
DBInstanceIdentifier: rman-lab-oracle
DBInstanceClass: db.t3.medium
Engine: oracle-se2
EngineVersion: !Ref OracleEngineVersion
LicenseModel: license-included
MasterUsername: !Sub '{{resolve:secretsmanager:${DBSecret}:SecretString:username}}'
MasterUserPassword: !Sub '{{resolve:secretsmanager:${DBSecret}:SecretString:password}}'
DBName: ORCL
AllocatedStorage: 50
StorageType: gp3
MultiAZ: false
DBSubnetGroupName: !Ref DBSubnetGroup
VPCSecurityGroups:
- !Ref RDSSecurityGroup
OptionGroupName: !Ref RMANOptionGroup
AssociatedRoles:
- FeatureName: S3_INTEGRATION
RoleArn: !GetAtt RDSOracleS3Role.Arn
DeletionProtection: false
Tags:
- Key: Name
Value: rman-lab-oracle
EC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref LatestAL2023AMI
InstanceType: t3.small
SubnetId: !Ref PublicSubnet
SecurityGroupIds:
- !Ref EC2SecurityGroup
IamInstanceProfile: !Ref EC2InstanceProfile
UserData:
Fn::Base64: |
#!/bin/bash
set -e
dnf install -y libaio
tee /etc/yum.repos.d/oracle-instantclient.repo << 'EOF'
[oracle-instantclient]
name=Oracle Instant Client
baseurl=https://yum.oracle.com/repo/OracleLinux/OL9/oracle/instantclient/x86_64/
gpgkey=https://yum.oracle.com/RPM-GPG-KEY-oracle-ol9
gpgcheck=1
enabled=1
EOF
# 最新の Instant Client 19.x を自動選択(マイナーバージョン決め打ちを避ける)
# RPM が /usr/bin/sqlplus へのシンボリックリンクと ld.so.conf.d への
# ライブラリ登録まで行うため、PATH / LD_LIBRARY_PATH の設定は不要
BASIC=$(dnf -q repoquery --qf '%{name}' 'oracle-instantclient19.*-basic' | sort -V | tail -1)
SQLPLUS=$(dnf -q repoquery --qf '%{name}' 'oracle-instantclient19.*-sqlplus' | sort -V | tail -1)
dnf install -y "$BASIC" "$SQLPLUS"
Tags:
- Key: Name
Value: rman-lab-ec2
Outputs:
RDSEndpoint:
Description: RDS Oracle endpoint
Value: !GetAtt OracleDB.Endpoint.Address
RDSPort:
Description: RDS Oracle port
Value: !GetAtt OracleDB.Endpoint.Port
DBName:
Description: Oracle DB name (SID)
Value: ORCL
BackupBucketName:
Description: S3 bucket name for RMAN backups
Value: !Ref RMANBackupBucket
EC2InstanceId:
Description: EC2 instance ID for SSM Session Manager
Value: !Ref EC2Instance
SecretARN:
Description: Secrets Manager ARN for DB password
Value: !Ref DBSecret
いくつかポイントを挙げます。
① EngineVersionはパラメータで指定
RDS Oracleではバージョン文字列をフルで指定する必要があります。確認手順を後述します。
② Secrets Managerでパスワードを自動生成
ExcludeCharactersで@ / ;などを除外しています。これらはOracleの接続文字列で区切り文字として使われるため、含まれるとDBインスタンス作成時にエラーになります。
③ オプショングループにS3_INTEGRATIONを追加し、IAMロールを紐付ける
rdsadmin.rdsadmin_s3_tasksパッケージ(S3転送に使用)は、オプショングループにS3_INTEGRATIONオプションを追加しないとインストールされません。オプション自体にIAMロールの設定はなく、IAMロールはAssociatedRolesで別途DBインスタンスに紐付けます。
④ Oracle Instant ClientをUserDataでインストール
UserDataではInstant Clientのマイナーバージョンを直接書かず、repoqueryでリポジトリにある最新の19.xを選んでインストールしています。
⑤ EC2ロールにはEC2上で叩くAWS CLIの参照権限を付与
先述の通りいくつかのAWS CLIコマンドをEC2上で実行するので、必要な権限を付与しています(RMANLabEC2Policy)。不要であれば、このポリシーは省略できます。
デプロイされる費用の目安
この構成を稼働させると主に以下のコストが発生します(東京リージョン、オンデマンド料金)。
| リソース | スペック | 時間単価(目安) |
|---|---|---|
| EC2 | t3.small | $0.021/hr |
| RDS Oracle SE2 | db.t3.medium / ライセンス込み / シングルAZ | $0.32/hr |
| EBS(RDSストレージ) | gp3 50GB | $0.007/hr |
| 合計 | $0.35/hr |
24時間で8.4ドル、1ドル160円換算で1340円程度のコスト感です。素早く試して削除すると良いでしょう。
使用するOracleバージョンを確認する
利用可能なエンジンバージョンをAWS CloudShellで確認します。
aws rds describe-db-engine-versions \
--engine oracle-se2 \
--region ap-northeast-1 \
--query 'DBEngineVersions[*].[EngineVersion]' \
--output text \
--no-cli-pager
19.0.0.0.ru-2020-04.rur-2020-04.r1
19.0.0.0.ru-2020-07.rur-2020-07.r1
19.0.0.0.ru-2020-10.rur-2020-10.r1
19.0.0.0.ru-2021-01.rur-2021-01.r1
中略
19.0.0.0.ru-2023-01.rur-2023-01.r2
19.0.0.0.ru-2024-10.rur-2024-10.r1
19.0.0.0.ru-2025-01.rur-2025-01.r1
19.0.0.0.ru-2025-01.spb-1.r1
19.0.0.0.ru-2025-01.rur-2025-01.r2
19.0.0.0.ru-2025-04.rur-2025-04.r1
19.0.0.0.ru-2025-04.spb-1.r1
19.0.0.0.ru-2025-07.rur-2025-07.r1
19.0.0.0.ru-2025-07.spb-1.r1
19.0.0.0.ru-2025-10.rur-2025-10.r1
19.0.0.0.ru-2025-10.spb-1.r1
19.0.0.0.ru-2026-01.rur-2026-01.r1
19.0.0.0.ru-2026-01.spb-1.r1
19.0.0.0.ru-2026-01.rur-2026-01.r2
19.0.0.0.ru-2026-01.spb-1.r2
19.0.0.0.ru-2026-01.rur-2026-01.r3
19.0.0.0.ru-2026-01.spb-1.r3
バージョン名の読み方は以下の通りです。
19.0.0.0 . ru-2026-01 . rur-2026-01 . r3
↑ ↑ ↑ ↑
Oracle 19c Release Release AWS側の
ベース版 Update Update リビジョン
(四半期ごとの Revision
パッチバンドル) (RUへの追加修正)
spbはSecurity Patch Bundleの略で、セキュリティ修正のみを軽量に適用したものです。今回は執筆時点の最新の通常パッチ19.0.0.0.ru-2026-01.rur-2026-01.r3を使用します。
CloudFormationのデプロイ
AWS CloudShellにテンプレートファイルをアップロードの上、下記コマンドを実行します。
aws cloudformation deploy \
--template-file template.yaml \
--stack-name rman-lab \
--region ap-northeast-1 \
--capabilities CAPABILITY_NAMED_IAM \
--parameter-overrides \
OracleEngineVersion=19.0.0.0.ru-2026-01.rur-2026-01.r3
実行すると以下のように表示されます。
~ $ aws cloudformation deploy \
> --template-file template.yaml \
> --stack-name rman-lab \
> --region ap-northeast-1 \
> --capabilities CAPABILITY_NAMED_IAM \
> --parameter-overrides \
> OracleEngineVersion=19.0.0.0.ru-2026-01.rur-2026-01.r3
Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - rman-lab
接続情報の取得
スタックのデプロイが完了したら、Outputsから各種情報を確認します。
aws cloudformation describe-stacks \
--stack-name rman-lab \
--region ap-northeast-1 \
--query 'Stacks[0].Outputs' \
--output table \
--no-cli-pager
--------------------------------------------------------------------------------------------------------------------------------------------------------
| DescribeStacks |
+------------------------------------------+-------------------+---------------------------------------------------------------------------------------+
| Description | OutputKey | OutputValue |
+------------------------------------------+-------------------+---------------------------------------------------------------------------------------+
| Secrets Manager ARN for DB password | SecretARN | arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxxxx:secret:rman-lab-db-secret-aAdxw9 |
| RDS Oracle endpoint | RDSEndpoint | rman-lab-oracle.cluh7scr0und.ap-northeast-1.rds.amazonaws.com |
| RDS Oracle port | RDSPort | 1521 |
| Oracle DB name (SID) | DBName | ORCL |
| EC2 instance ID for SSM Session Manager | EC2InstanceId | i-0ebb95ead4466722d |
| S3 bucket name for RMAN backups | BackupBucketName | rman-backup-xxxxxxxxxxxx-ap-northeast-1 |
+------------------------------------------+-------------------+---------------------------------------------------------------------------------------+
これらの情報は、以降の操作で利用する際は動的に取得する前提になっていますが、何かうまくいかなった時のためにどこかにメモっておくと役立つかもしれません。
EC2インスタンスに接続する(SSM Session Manager)
まずEC2インスタンスに接続します。インスタンスIDはOutputsに出ているので、describe-stacksの結果を--targetに直接渡します。
aws ssm start-session \
--target $(aws cloudformation describe-stacks \
--stack-name rman-lab \
--region ap-northeast-1 \
--query 'Stacks[0].Outputs[?OutputKey==`EC2InstanceId`].OutputValue' \
--output text)
Starting session with SessionId: cm-chiba.yukihiro-47s9eriz8liff4o9cfiny8kfoa
sh-5.2$
以降の操作は、このEC2セッション上で実行します。SQL(SQL>)とEC2シェル(sh-5.2$)を行き来する場面があるので、プロンプトで現在地を確認しながら進めてください。SQL*PlusからEC2シェルに戻るときはexitを実行します。
DBインスタンスの設定とRMANの前提条件を確認する
EC2シェル(sh-5.2$)で実行します。
せっかくなのでまず今回作成したDBインスタンスの主要な設定を確認しておきます。
aws rds describe-db-instances \
--db-instance-identifier rman-lab-oracle \
--region ap-northeast-1 \
--query 'DBInstances[0].{Engine:Engine,EngineVersion:EngineVersion,LicenseModel:LicenseModel,AllocatedStorage:AllocatedStorage,StorageType:StorageType,AssociatedRoles:AssociatedRoles,OptionGroupMemberships:OptionGroupMemberships,DBParameterGroups:DBParameterGroups,MultiAZ:MultiAZ,StorageEncrypted:StorageEncrypted}' \
--output json \
--no-cli-pager
{
"Engine": "oracle-se2",
"EngineVersion": "19.0.0.0.ru-2026-01.rur-2026-01.r3",
"LicenseModel": "license-included",
"AllocatedStorage": 50,
"StorageType": "gp3",
"AssociatedRoles": [
{
"RoleArn": "arn:aws:iam::xxxxxxxxxxxx:role/rman-lab-rds-s3-role",
"FeatureName": "S3_INTEGRATION",
"Status": "ACTIVE"
}
],
"OptionGroupMemberships": [
{
"OptionGroupName": "rman-lab-og",
"Status": "in-sync"
}
],
"DBParameterGroups": [
{
"DBParameterGroupName": "default.oracle-se2-19",
"ParameterApplyStatus": "in-sync"
}
],
"MultiAZ": false,
"StorageEncrypted": false
}
いくつか補足します。
AllocatedStorage/StorageType: ストレージはgp3の50GBです。RMANバックアップはこのローカルストレージに書き出されるため、空き容量を意識する必要がありますAssociatedRoles:S3_INTEGRATIONの機能名でIAMロールrman-lab-rds-s3-roleがACTIVEで紐づいています。これがDBインスタンスからS3へバックアップを転送するための権限です- オプショングループ / パラメータグループ: オプショングループは独自のもの(
rman-lab-og)を作成して関連づけ、パラメータグループはデフォルトのものを関連づけています
オプショングループも確認しておきます。
aws rds describe-option-groups \
--option-group-name rman-lab-og \
--region ap-northeast-1
{
"OptionGroupsList": [
{
"OptionGroupName": "rman-lab-og",
"OptionGroupDescription": "RMAN lab S3 integration",
"EngineName": "oracle-se2",
"MajorEngineVersion": "19",
"Options": [
{
"OptionName": "S3_INTEGRATION",
"OptionDescription": "Enables S3_INTEGRATION for data ingestion",
"Persistent": false,
"Permanent": false,
"OptionVersion": "1.0",
"OptionSettings": [],
"DBSecurityGroupMemberships": [],
"VpcSecurityGroupMemberships": []
}
],
"AllowsVpcAndNonVpcInstanceMemberships": false,
"VpcId": "vpc-072422105bd14b671",
"OptionGroupArn": "arn:aws:rds:ap-northeast-1:xxxxxxxxxxxx:og:rman-lab-og"
}
]
}
OptionsにS3_INTEGRATIONが入っていることが確認できました。
RMANバックアップの前提条件
RMANバックアップの前提条件を確認します。RMANバックアップの前提条件 では以下の3点が挙げられています。
① ARCHIVELOGモードが有効であること
Amazon RDSではBackupRetentionPeriodがゼロ以外であれば自動的にARCHIVELOGモードが有効になります。
aws rds describe-db-instances \
--db-instance-identifier rman-lab-oracle \
--region ap-northeast-1 \
--query 'DBInstances[0].BackupRetentionPeriod' \
--output text \
--no-cli-pager
1
今回は1日に設定されているので問題ありません。CloudFormationテンプレートで明示していませんが、Amazon RDSのデフォルト値が1日のためです。
② REDOログ保持期間が設定されていること
アーカイブREDOログをバックアップに含める場合に必要です。今回はアーカイブログも含める構成にするため、DBインスタンスに接続してからSQL*Plusで設定します(後述)。
③ バックアップを保持できる空き容量があること
もちろん現状は空き容量が十分あります。これからの操作で、CloudWatchのFreeStorageSpaceメトリクスを随時確認して意識します。
DBインスタンスに接続する(SQL*Plus)
エンドポイントとパスワードを環境変数に設定してから接続します。どちらもEC2上で動的に取得します。エンドポイントはdescribe-db-instancesから、パスワードはSecrets Managerから取得します。
export DB_HOST=$(aws rds describe-db-instances \
--db-instance-identifier rman-lab-oracle \
--query 'DBInstances[0].Endpoint.Address' \
--output text)
export DB_PASS=$(aws secretsmanager get-secret-value \
--secret-id rman-lab-db-secret \
--query 'SecretString' \
--output text | jq -r '.password')
sqlplus "admin/${DB_PASS}@${DB_HOST}:1521/ORCL"
AWS CLIをEC2シェル上で実行する場合にはDBへ接続したり抜けたりを繰り返すことになるので、このコマンドを何度も叩くことになります。控えておいてください。
`sqlplus: command not found` が出た場合
CloudFormationのUserDataによるOracle Instant Clientのインストールが失敗しています。/var/log/cloud-init-output.logでエラー内容を確認できます。
手動でインストールする際のコマンド例です。
BASIC=$(dnf -q repoquery --qf '%{name}' 'oracle-instantclient19.*-basic' | sort -V | tail -1)
SQLPLUS=$(dnf -q repoquery --qf '%{name}' 'oracle-instantclient19.*-sqlplus' | sort -V | tail -1)
sudo dnf install -y "$BASIC" "$SQLPLUS"
SQL*Plus: Release 19.0.0.0.0 - Production on Thu May 28 14:29:06 2026
Version 19.27.0.0.0
Copyright (c) 1982, 2024, Oracle. All rights reserved.
Connected to:
Oracle Database 19c Standard Edition 2 Release 19.0.0.0.0 - Production
Version 19.30.0.0.0
SQL>
例えば、後述する複数行のSELECTを(コピー&ペーストで)入力すると、継続行の番号(2、3)が末尾にまとまって出て、次のような表示になります。(少なくとも今回のわたしの環境ではなりました。)
SQL> SELECT value
FROM rdsadmin.rds_configuration
WHERE name = 'archivelog retention hours'; 2 3
本記事のコードブロックでは、この行番号とSQL>プロンプトを省いて以下のように記載しています。
SELECT value
FROM rdsadmin.rds_configuration
WHERE name = 'archivelog retention hours';
RMANバックアップの事前準備をする
バックアップを取る前に、アーカイブログの設定とテストデータの投入などの事前準備をしておきます。
アーカイブログの保持期間を設定する
前提条件で確認したとおり、アーカイブログをバックアップに含めるには保持期間の設定が必要です。rdsadmin_util.set_configurationでarchivelog retention hoursを設定します。
この値はRDSがアーカイブREDOログをローカルに保持する時間数で、バックアップに含めるには0より大きい値を設定する必要があります。今回は24時間に設定します。set_configurationはrdsadminスキーマが管理する設定テーブルへの書き込みです。トランザクション操作のため、COMMITを忘れずに実行します。
EXEC rdsadmin.rdsadmin_util.set_configuration('archivelog retention hours', 24);
COMMIT;
PL/SQL procedure successfully completed.
rdsadmin.rds_configurationビューで設定値を確認します。
SELECT value
FROM rdsadmin.rds_configuration
WHERE name = 'archivelog retention hours';
VALUE
--------------------------------------------------------------------------------
24
1 row selected.
24時間に設定できました。
テストデータを用意する
空のデータベースではバックアップのサイズや所要時間の変化が見えにくいため、一定量のデータをあらかじめ投入しておきます。
まずテストデータを格納するテーブルを作成します。valカラムはCHAR(2000)、つまり固定長2,000バイトの文字列型です。1行あたり約2,000バイトになるので、行数からデータ量を見積もりやすくしています。
CREATE TABLE test_large (
id NUMBER,
val CHAR(2000)
);
Table created.
次にデータを投入します。大量の行を1回のINSERTで一気に作ろうとするとメモリに負荷がかかることがあるため、まず1,000行のベースデータを作ります。RPAD('X', 2000, 'X')で2,000バイト分の文字列を埋めています。
INSERT INTO test_large
SELECT ROWNUM, RPAD('X', 2000, 'X')
FROM dual CONNECT BY LEVEL <= 1000;
COMMIT;
1000 rows created.
Commit complete.
このベースを自己結合(直積)して一気に膨らませます。1,000行 × 1,000行 = 100万通りの組み合わせのうち999,000行を追加し、テーブルの合計を100万行にします。/*+ APPEND */はダイレクトパスインサートを指示するヒントで、通常のINSERTより高速です。100万行 × 2,000バイトで、約2GBぶんのデータになる想定です。
INSERT /*+ APPEND */ INTO test_large
SELECT ROWNUM + 1000, RPAD('X', 2000, 'X')
FROM test_large a, test_large b
WHERE ROWNUM <= 999000;
COMMIT;
999000 rows created.
Commit complete.
最後にuser_segmentsで実際のセグメントサイズを確認します。
SELECT
segment_name,
ROUND(SUM(bytes) / 1024 / 1024 / 1024, 2) AS size_gb
FROM user_segments
WHERE segment_name = 'TEST_LARGE'
GROUP BY segment_name;
SEGMENT_NAME
--------------------------------------------------------------------------------
SIZE_GB
----------
TEST_LARGE
2.57
計算上は約2GBでしたが、実際のセグメントは2.57GB(GiB)でした。ブロックのヘッダーや空き領域(PCTFREE)などのオーバーヘッドの分、見積もりより少し大きくなります。
データベースの健全性を確認する
バックアップを取る前に、ソースとなるデータベースに破損がないかを確認しておきます。
rdsadmin_rman_util.validate_databaseはRMANのVALIDATE DATABASEを実行し、データベースを構成するファイル(データファイル・制御ファイル・SPFILE)をブロック単位で読み込んで破損の有無をチェックします。
チェックの種類はp_validation_typeで指定でき、デフォルトは物理破損のみのPHYSICALです。論理破損まで含めて確認したい場合はp_validation_type => 'PHYSICAL+LOGICAL'を指定します。今回はデフォルトのまま(物理破損のチェック)で実行します。
なお、粒度に応じた検証プロシージャが用意されています。
validate_database(データベース全体)validate_tablespace(表領域単位)validate_datafile(データファイル単位)validate_current_controlfile(制御ファイル)validate_spfile(SPFILE)
p_rman_to_dbms_output => TRUEでRMANの検証ログを画面に流すため、SET SERVEROUTPUT ONを先に実行しておきます。
SET SERVEROUTPUT ON
BEGIN
rdsadmin.rdsadmin_rman_util.validate_database(
p_rman_to_dbms_output => TRUE
);
END;
/
実行完了まで数十秒かかりました。待ちましょう。
検証結果の全文
RUN_RMAN_CMD: /rdsdbbin/oracle/bin/rman TARGET / LOG
/rdsdbdata/log/trace/rds-rman-validate-DATABASE-2026-05-29.12-50-12.085772000.tx
t @/rdsdbdata/tmp/rds-rman-validate-DATABASE-2026-05-29.12-50-12.085772000.input
Recovery Manager: Release 19.0.0.0.0 - Production on Fri May 29 12:50:12 2026
Version 19.30.0.0.0
Copyright (c) 1982, 2019, Oracle and/or its affiliates. All rights reserved.
connected to target database: ORCL (DBID=1755266044)
RMAN> run {
2> ALLOCATE CHANNEL d1 DEVICE TYPE DISK ;
3> VALIDATE DATABASE;
4> RELEASE CHANNEL d1;
5> }
6>
using target database control file instead of recovery catalog
allocated channel: d1
channel d1: SID=338 device type=DISK
Starting validate at 2026-05-29 12:50:13
channel d1: starting validation of datafile
channel d1: specifying datafile(s) for validation
input datafile file number=00004
name=/rdsdbdata/db/ORCL_A/datafile/o1_mf_users_ntyr84vn_.dbf
input datafile file number=00001
name=/rdsdbdata/db/ORCL_A/datafile/o1_mf_system_ntyr81hy_.dbf
input datafile file number=00002
name=/rdsdbdata/db/ORCL_A/datafile/o1_mf_sysaux_ntyr83sw_.dbf
input datafile file number=00003
name=/rdsdbdata/db/ORCL_A/datafile/o1_mf_undo_t1_ntyr84nv_.dbf
input datafile file number=00005
name=/rdsdbdata/db/ORCL_A/datafile/o1_mf_rdsadmin_ntysp43v_.dbf
channel d1: validation complete, elapsed time: 00:00:45
List of Datafiles
=================
File Status Marked Corrupt Empty Blocks Blocks Examined High SCN
---- ------ -------------- ------------ --------------- ----------
1 OK 0 18249 89600 648808
File Name: /rdsdbdata/db/ORCL_A/datafile/o1_mf_system_ntyr81hy_.dbf
Block Type Blocks Failing Blocks Processed
---------- -------------- ----------------
Data 0 28715
Index 0 8194
Other 0 34442
File Status Marked Corrupt Empty Blocks Blocks Examined High SCN
---- ------ -------------- ------------ --------------- ----------
2 OK 0 27896 76800 648796
File Name: /rdsdbdata/db/ORCL_A/datafile/o1_mf_sysaux_ntyr83sw_.dbf
Block Type Blocks Failing Blocks Processed
---------- -------------- ----------------
Data 0 2293
Index 0 3591
Other 0 43020
File Status Marked Corrupt Empty Blocks Blocks Examined High SCN
---- ------ -------------- ------------ --------------- ----------
3 OK 0 897 40960 648808
File Name: /rdsdbdata/db/ORCL_A/datafile/o1_mf_undo_t1_ntyr84nv_.dbf
Block Type Blocks Failing Blocks Processed
---------- -------------- ----------------
Data 0 0
Index 0 0
Other 0 40063
File Status Marked Corrupt Empty Blocks Blocks Examined High SCN
---- ------ -------------- ------------ --------------- ----------
4 OK 0 28317 371200 605668
File Name: /rdsdbdata/db/ORCL_A/datafile/o1_mf_users_ntyr84vn_.dbf
Block Type Blocks Failing Blocks Processed
---------- -------------- ----------------
Data 0 333370
Index 0 0
Other 0 9513
File Status Marked Corrupt Empty Blocks Blocks Examined High SCN
---- ------ -------------- ------------ --------------- ----------
5 OK 0 8219 9088 647615
File Name: /rdsdbdata/db/ORCL_A/datafile/o1_mf_rdsadmin_ntysp43v_.dbf
Block Type Blocks Failing Blocks Processed
---------- -------------- ----------------
Data 0 25
Index 0 9
Other 0 835
channel d1: starting validation of datafile
channel d1: specifying datafile(s) for validation
including current control file for validation
including current SPFILE in backup set
channel d1: validation complete, elapsed time: 00:00:01
List of Control File and SPFILE
===============================
File Type Status Blocks Failing Blocks Examined
------------ ------ -------------- ---------------
SPFILE OK 0 2
Control File OK 0 610
Finished validate at 2026-05-29 12:51:00
released channel: d1
Recovery Manager complete.
PL/SQL procedure successfully completed.
各データファイルがStatus OK、Marked Corruptが0になっており、破損ブロックがないことが確認できました。コントロールファイル・SPFILEも問題ありません。
結果の見方のポイントは以下です。
- Status:
OKなら検証成功。FAILEDだと破損あり - Marked Corrupt: 破損として記録されたブロック数。
0が正常 - Blocks Failing: 検証に失敗したブロック数。
0が正常 - Empty Blocks / Blocks Examined: 空きブロック数と検査したブロック数
空きストレージ容量を確認する
この段階で空きストレージ容量をCloudWatchで確認します。(今回は)SQL*Plusからexitし、EC2シェル(sh-5.2$)からAWS CLIを実行します。
直近10分のメトリクスを1分刻みで取得し、jqでタイムスタンプと空き容量(GB換算)の2列に整形して時系列に並べます。作業タイミングによって取得時間は調整してください。
aws cloudwatch get-metric-statistics \
--namespace AWS/RDS \
--metric-name FreeStorageSpace \
--dimensions Name=DBInstanceIdentifier,Value=rman-lab-oracle \
--start-time $(date -u -d '10 minutes ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
--period 60 \
--statistics Average \
--no-cli-pager \
| jq -r '.Datapoints | sort_by(.Timestamp)[] | [.Timestamp, (.Average / 1073741824 * 10 | floor / 10)] | @tsv'
2026-05-28T14:34:00+00:00 46
2026-05-28T14:35:00+00:00 46
2026-05-28T14:36:00+00:00 45.6
2026-05-28T14:37:00+00:00 43.1
2026-05-28T14:38:00+00:00 41
2026-05-28T14:39:00+00:00 40.9
2026-05-28T14:40:00+00:00 40.9
2026-05-28T14:41:00+00:00 40.7
2026-05-28T14:42:00+00:00 40.7
2026-05-28T14:43:00+00:00 40.7
テストデータの投入にあわせて、空き容量が 46GBから約40.7GB へ減っているのが分かります。
減少幅(約5GB)が投入したテーブル本体(2.57GB)より大きいのは、データ投入時に生成される アーカイブREDOログなどもローカルストレージを消費するためと考えられます。
RMANでフルバックアップを取得しS3バケットにアップロードしてみる
いよいよメインディッシュの部分です。
RMANバックアップ先についておさらい
RMANのバックアップ先は Oracle Directory Object というデータベースオブジェクトです。ディレクトリ名(論理名)をファイルシステムのパスにマッピングする仕組みで、p_directory_nameパラメータで指定します。
ディレクトリは下記から選択できます。
- ローカルEBS
- デフォルトディレクトリ
- カスタムディレクトリ
- 統合したEFSファイルシステム上のディレクトリ
RDS RMANの機能としてはバックアップの出力先にできるのは上記のいずれかです。そこから別のS3統合機能を利用し、バックアップファイルをS3バケットにアップロードすることができます。
特にローカルEBSにバックアップを長期保存するとストレージを圧迫することになるため、S3への退避を意識する機会が多いでしょう。
今回はバックアップを取得してS3に転送したのち、ローカルからは削除する流れを確認してみます。
① ディレクトリを作成する
SQL*PlusでDBに接続ができている状態からスタートです。
バックアップの書き出し先となるOracleディレクトリを作成します。
EXEC rdsadmin.rdsadmin_util.create_directory(p_directory_name => 'RMAN_PUMP_DIR');
PL/SQL procedure successfully completed.
作成後に中身が空であることを確認します。
SELECT * FROM table(rdsadmin.rds_file_util.listdir(p_directory => 'RMAN_PUMP_DIR'));
FILENAME
--------------------------------------------------------------------------------
TYPE FILESIZE MTIME
---------- ---------- ---------
01/
directory 4096 10-MAR-26
01/はディレクトリ作成時にOracleが自動生成するサブディレクトリです。バックアップファイルはまだありません。
② フルバックアップを実行する
backup_database_fullを呼び出します。Oracle SE2は並列チャネルが1固定のためp_parallelは指定しません。p_include_archive_logs => TRUEでアーカイブログも含め、p_rman_to_dbms_output => FALSEで非同期実行にします。完了はログで確認します。
BEGIN
rdsadmin.rdsadmin_rman_util.backup_database_full(
p_owner => 'SYS',
p_directory_name => 'RMAN_PUMP_DIR',
p_include_archive_logs => TRUE,
p_rman_to_dbms_output => FALSE
);
END;
/
PL/SQL procedure successfully completed.
完了後にディレクトリを確認するとバックアップファイルが作成されています。
SELECT * FROM table(rdsadmin.rds_file_util.listdir(p_directory => 'RMAN_PUMP_DIR'));
FILENAME
--------------------------------------------------------------------------------
TYPE FILESIZE MTIME
---------- ---------- ---------
01/
directory 4096 29-MAY-26
BACKUP-2026-05-29-01-15-28-backup-20260529-014p9idr_1_1_1
file 1020957184 29-MAY-26
BACKUP-2026-05-29-01-15-28-backup-20260529-044p9ifj_4_1_1
file 31630848 29-MAY-26
BACKUP-2026-05-29-01-15-28-backup-20260529-024p9iea_2_1_1
file 1019396608 29-MAY-26
BACKUP-2026-05-29-01-15-28-backup-20260529-054p9ifk_5_1_1
file 1294848 29-MAY-26
BACKUP-2026-05-29-01-15-28-backup-20260529-034p9if4_3_1_1
file 802140160 29-MAY-26
BACKUP-2026-05-29-01-15-28-c-1755266044-20260529-00
file 10125312 29-MAY-26
BACKUP-2026-05-29-01-15-28-backup-20260529-074p9ii1_7_1_1
file 158720 29-MAY-26
BACKUP-2026-05-29-01-15-28-backup-20260529-064p9ifm_6_1_1
file 3837739008 29-MAY-26
9 rows selected.
ファイル名の先頭はBACKUP-YYYY-MM-DD-HH-MI-SS-というタイムスタンプです。その後ろで種別が分かれます。
backup-YYYYMMDD-XXXX_N_1_1:バックアップピース。_N_はRMANが振る連番c-XXXXXXXXXX-YYYYMMDD-NN:コントロールファイルのバックアップ(c-プレフィックスが目印)
backup_database_fullは データファイル・アーカイブログ・コントロールファイルをすべてバックアップします。RMANは表領域単位でバックアップセットを作成するため、表領域の数+アーカイブログ+コントロールファイルの分だけファイルが生成されます。今回は8本でした。
_6_のピース(約3.8GB)が突出して大きいのは、今回作成したTEST_LARGEテーブルが格納されているUSERS表領域のバックアップだからです。
👀ふたたび空きストレージ容量を確認する
ここでまたDBインスタンスの空きストレージ容量を確認します。今回はEFSではなくローカルにバックアップファイルを作成したため、そのぶん空きは減っているはずです。
AWS CLIを実行可能な場所から下記コマンドを実行します。
aws cloudwatch get-metric-statistics \
--namespace AWS/RDS \
--metric-name FreeStorageSpace \
--dimensions Name=DBInstanceIdentifier,Value=rman-lab-oracle \
--start-time $(date -u -d '10 minutes ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
--period 60 \
--statistics Average \
--region ap-northeast-1 \
--no-cli-pager \
| jq -r '.Datapoints | sort_by(.Timestamp)[] | [.Timestamp, (.Average / 1073741824 * 10 | floor / 10)] | @tsv'
2026-05-29T01:13:00+00:00 40.6
2026-05-29T01:14:00+00:00 40.6
2026-05-29T01:15:00+00:00 40.6
2026-05-29T01:16:00+00:00 38.7
2026-05-29T01:17:00+00:00 35.9
2026-05-29T01:18:00+00:00 34.3
2026-05-29T01:19:00+00:00 34.3
2026-05-29T01:20:00+00:00 34.3
2026-05-29T01:21:00+00:00 34.3
2026-05-29T01:22:00+00:00 34.3
やはりバックアップを作成した分、空き容量が減少していますね。
③ バックアップをS3に転送する
S3へのファイルの転送にはrdsadmin.rdsadmin_s3_tasks.upload_to_s3を使います。オプショングループにS3_INTEGRATIONを追加すると、rdsadminスキーマにRDSADMIN_S3_TASKSパッケージがインストールされます。転送前に確認しておきます。
ふたたびSQL*Plusでの操作です。
SELECT object_name FROM all_objects
WHERE owner = 'RDSADMIN' AND object_type = 'PACKAGE'
ORDER BY object_name;
OBJECT_NAME
--------------------------------------------------------------------------------
MANAGE_TRACEFILES
MANAGE_TRACEFILES_CTX
RDSADMIN
RDSADMIN_ADRCI_UTIL
RDSADMIN_ARCHIVE_LOG_DOWNLOAD
RDSADMIN_DBMS_GOLDENGATE_AUTH
RDSADMIN_DBMS_IJOB
RDSADMIN_DBMS_REPAIR
RDSADMIN_DBMS_SCHEDULER
RDSADMIN_DIAGNOSTIC_UTIL
RDSADMIN_KERBEROS_AUTH_TASKS
RDSADMIN_MASTER_UTIL
RDSADMIN_OSWBB_UTIL
RDSADMIN_PASSWORD_VERIFY
RDSADMIN_PATCH_UTIL
RDSADMIN_PRIVILEGES_UTIL
RDSADMIN_PUB_UTIL
RDSADMIN_RMAN_SCHEDULER_TASKS
RDSADMIN_RMAN_UTIL
RDSADMIN_S3_TASKS
RDSADMIN_TRANSPORT_UTIL
RDSADMIN_TRIGGER_UTIL
RDSADMIN_TRIGGER_UTIL2
RDSADMIN_UTIL
RDS_FILE_UTIL
RDS_XS_ACL
26 rows selected.
RDSADMIN_S3_TASKSがリストに含まれていることが確認できます。もしない場合、S3への転送が行えません。設定を見直してください。
upload_to_s3は非同期で動作するので、戻り値のTASK_IDを使って完了を確認します。TASK_IDは後続のログ確認でも使うため、SQL*Plusのバインド変数に受けておくと便利です。VARIABLEで宣言したバインド変数は同一セッション中 保持されます。
VARIABLE task_id VARCHAR2(100)
BEGIN
:task_id := rdsadmin.rdsadmin_s3_tasks.upload_to_s3(
p_bucket_name => 'rman-backup-xxxxxxxxxxxx-ap-northeast-1',
p_directory_name => 'RMAN_PUMP_DIR',
p_s3_prefix => 'backup/',
p_prefix => ''
);
END;
/
PRINT task_id
PL/SQL procedure successfully completed.
TASK_ID
--------------------------------------------------------------------------------
1780058325277-20
転送は非同期で進むため、実行直後はまだログが揃っていないことがあります。少し待ってから、バインド変数:task_idを使ってログを確認します。
SELECT text FROM table(
rdsadmin.rds_file_util.read_text_file('BDUMP', 'dbtask-' || :task_id || '.log')
);
TEXT
--------------------------------------------------------------------------------
2026-05-29 12:38:45.625 UTC [INFO ] File #1: Uploading the file /rdsdbdata/userd
irs/01/BACKUP-2026-05-29-01-15-28-backup-20260529-014p9idr_1_1_1 to Amazon S3 wi
th bucket name rman-backup-xxxxxxxxxxxx-ap-northeast-1 and key backup/BACKUP-202
6-05-29-01-15-28-backup-20260529-014p9idr_1_1_1.
2026-05-29 12:39:01.608 UTC [INFO ] The file /rdsdbdata/userdirs/01/BACKUP-2026-
05-29-01-15-28-backup-20260529-014p9idr_1_1_1 was uploaded to Amazon S3 with buc
ket name rman-backup-xxxxxxxxxxxx-ap-northeast-1 and key backup/BACKUP-2026-05-2
9-01-15-28-backup-20260529-014p9idr_1_1_1.
(中略:File #2 〜 #7 も同様にアップロード)
2026-05-29 12:39:29.433 UTC [INFO ] File #8: Uploading the file /rdsdbdata/userd
irs/01/BACKUP-2026-05-29-01-15-28-backup-20260529-064p9ifm_6_1_1 to Amazon S3 wi
th bucket name rman-backup-xxxxxxxxxxxx-ap-northeast-1 and key backup/BACKUP-202
6-05-29-01-15-28-backup-20260529-064p9ifm_6_1_1.
2026-05-29 12:40:16.485 UTC [INFO ] The file /rdsdbdata/userdirs/01/BACKUP-2026-
05-29-01-15-28-backup-20260529-064p9ifm_6_1_1 was uploaded to Amazon S3 with buc
ket name rman-backup-xxxxxxxxxxxx-ap-northeast-1 and key backup/BACKUP-2026-05-2
9-01-15-28-backup-20260529-064p9ifm_6_1_1.
2026-05-29 12:40:16.486 UTC [INFO ] The task finished successfully.
17 rows selected.
8本のバックアップファイルが順番にS3へアップロードされ、最後のThe task finished successfully.で完了が確認できます。ログにはローカルパス(/rdsdbdata/userdirs/01/...)とS3のキー(backup/...)の対応が出るので、どのファイルがどこに上がったか追えます。
👀S3にアップロードされたファイルの確認
S3にはどのような形で格納されているか、AWS CLIで確認します。一度SQL*Plusから抜けてEC2シェルからaws s3 lsで確認しました。
aws s3 ls s3://rman-backup-xxxxxxxxxxxx-ap-northeast-1/backup/ \
--recursive \
--human-readable \
--summarize \
--region ap-northeast-1
2026-05-29 12:38:46 973.7 MiB backup/BACKUP-2026-05-29-01-15-28-backup-20260529-014p9idr_1_1_1
2026-05-29 12:39:03 972.2 MiB backup/BACKUP-2026-05-29-01-15-28-backup-20260529-024p9iea_2_1_1
2026-05-29 12:39:15 765.0 MiB backup/BACKUP-2026-05-29-01-15-28-backup-20260529-034p9if4_3_1_1
2026-05-29 12:39:02 30.2 MiB backup/BACKUP-2026-05-29-01-15-28-backup-20260529-044p9ifj_4_1_1
2026-05-29 12:39:15 1.2 MiB backup/BACKUP-2026-05-29-01-15-28-backup-20260529-054p9ifk_5_1_1
2026-05-29 12:39:30 3.6 GiB backup/BACKUP-2026-05-29-01-15-28-backup-20260529-064p9ifm_6_1_1
2026-05-29 12:39:30 155.0 KiB backup/BACKUP-2026-05-29-01-15-28-backup-20260529-074p9ii1_7_1_1
2026-05-29 12:39:30 9.7 MiB backup/BACKUP-2026-05-29-01-15-28-c-1755266044-20260529-00
Total Objects: 8
Total Size: 6.3 GiB
ローカルのlistdirで見た8本がすべてS3に揃っており、合計サイズも約6.3 GiBと一致しています。_6_のピース(USERS表領域)が3.6 GiBと最も大きいのもlistdirの結果どおりです。
④ ローカルのバックアップファイルを削除する
S3への転送が完了したら、DBインスタンスのローカルバックアップファイルを削除します。ふたたびSQL*Plusでの操作です。
BEGIN
FOR f IN (
SELECT filename FROM table(rdsadmin.rds_file_util.listdir('RMAN_PUMP_DIR'))
WHERE type = 'file'
)
LOOP
utl_file.fremove('RMAN_PUMP_DIR', f.filename);
END LOOP;
END;
/
PL/SQL procedure successfully completed.
削除後にlistdirで確認すると、バックアップファイルが消えて01/ディレクトリだけが残っています。
SELECT * FROM table(rdsadmin.rds_file_util.listdir(p_directory => 'RMAN_PUMP_DIR'));
FILENAME
--------------------------------------------------------------------------------
TYPE FILESIZE MTIME
---------- ---------- ---------
01/
directory 4096 29-MAY-26
削除できていそうです。
👀みたび空きストレージ容量を確認する
ローカルからのファイル削除が完了したので、EC2シェルから先ほどと同じCloudWatchコマンドで確認します。
aws cloudwatch get-metric-statistics \
--namespace AWS/RDS \
--metric-name FreeStorageSpace \
--dimensions Name=DBInstanceIdentifier,Value=rman-lab-oracle \
--start-time $(date -u -d '10 minutes ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
--period 60 \
--statistics Average \
--region ap-northeast-1 \
--no-cli-pager \
| jq -r '.Datapoints | sort_by(.Timestamp)[] | [.Timestamp, (.Average / 1073741824 * 10 | floor / 10)] | @tsv'
...略
2026-05-29T12:39:00+00:00 34.3
2026-05-29T12:40:00+00:00 34.3
2026-05-29T12:41:00+00:00 34.3
2026-05-29T12:42:00+00:00 40.6
2026-05-29T12:43:00+00:00 40.6
2026-05-29T12:44:00+00:00 40.6
バックアップファイルが占めていた容量が解放されました。
検証用の環境一式を削除する
一連の流れの検証が終わったので、CloudFormationスタックごと削除します。
S3バケットにオブジェクトが残っているとバケットの削除に失敗するため、先に空にしておきます。
aws s3 rm s3://rman-backup-xxxxxxxxxxxx-ap-northeast-1/ \
--recursive
delete: s3://rman-backup-xxxxxxxxxxxx-ap-northeast-1/backup/BACKUP-2026-05-29-01-15-28-backup-20260529-074p9ii1_7_1_1
delete: s3://rman-backup-xxxxxxxxxxxx-ap-northeast-1/backup/BACKUP-2026-05-29-01-15-28-c-1755266044-20260529-00
delete: s3://rman-backup-xxxxxxxxxxxx-ap-northeast-1/backup/BACKUP-2026-05-29-01-15-28-backup-20260529-054p9ifk_5_1_1
delete: s3://rman-backup-xxxxxxxxxxxx-ap-northeast-1/backup/BACKUP-2026-05-29-01-15-28-backup-20260529-014p9idr_1_1_1
delete: s3://rman-backup-xxxxxxxxxxxx-ap-northeast-1/backup/BACKUP-2026-05-29-01-15-28-backup-20260529-024p9iea_2_1_1
delete: s3://rman-backup-xxxxxxxxxxxx-ap-northeast-1/backup/BACKUP-2026-05-29-01-15-28-backup-20260529-064p9ifm_6_1_1
delete: s3://rman-backup-xxxxxxxxxxxx-ap-northeast-1/backup/BACKUP-2026-05-29-01-15-28-backup-20260529-034p9if4_3_1_1
delete: s3://rman-backup-xxxxxxxxxxxx-ap-northeast-1/backup/BACKUP-2026-05-29-01-15-28-backup-20260529-044p9ifj_4_1_1
その後、スタックを削除します。
aws cloudformation delete-stack \
--stack-name rman-lab
削除コマンドの結果は返ってきません。スタックの削除状況はコンソールで見たり、下記のコマンドで確認しましょう。
aws cloudformation describe-stacks \
--stack-name rman-lab \
--query 'Stacks[0].StackStatus' \
--output text
削除中はDELETE_IN_PROGRESSが返り、削除が完了するとスタック自体が存在しなくなるためStack with id rman-lab does not existというエラーになります(このエラーが出れば削除完了の合図です)。5分程度かかりました。
改めてまとめ

- Amazon RDSではRMANをOSのコマンドラインから直接実行できない
rdsadmin.rdsadmin_rman_utilパッケージのPL/SQLプロシージャを呼び出して操作する(SQL*PlusなどのSQLクライアントから実行する)rdsadmin.rdsadmin_rman_utilパッケージのインストールなどを利用者側で意識する必要はない
- DBインスタンスでバックアップ保持期間を0日以外にすることでRMANが利用可能となる
- RMANによるバックアップはDBインスタンスのローカルEBSに保存される。下記に保存することも可能
- DBインスタンスに統合されたEFSファイルシステム(外部ディレクトリとして指定可能)
- DBインスタンスに統合されたS3バケット(別途アップロードが必要)
- RMANバックアップをRDS DBインスタンスにリストアすることはできない
- オンプレミスやEC2インスタンスなどのセルフマネージドな環境へのリストアは可能
終わりに
Amazon RDS for OracleでRMANを実際に動かし、フルバックアップの取得からS3転送、ローカル削除までの一連の流れを試してみました。
わたしはRMANそのものが初めてだったので単純に新鮮でしたが、コマンドラインからのrman操作に慣れ親しんだ方にとっては、どこか違いや共通点が見出せたかもしれません。
繰り返しになりますがRDSで取得したRMANバックアップはRDS DBインスタンスへのリストアには使用できませんので、使い道を意識してください。また、使用する場合はローカルEBSに保存しておくのではなく、EFSやS3などの外部に保存することをご検討ください。
この記事がどなたかの参考になれば幸いです。
以上、チバユキ (@batchicchi)がお送りしました。







