Amazon RDS for OracleのRMANでバックアップを取得してS3に転送してみた

Amazon RDS for OracleのRMANでバックアップを取得してS3に転送してみた

Amazon RDS for OracleでRMAN(Recovery Manager)を実際に動かしてみました。オンプレミスと異なる操作方法やバックアップ先の選択肢、S3連携までの一連の流れを確認します。
2026.05.30

コンバンハ、千葉(幸)です。

Amazon RDS for Oracleの利用を検討する機会がありました。わたしは他のDBエンジンでAmazon RDSを使ったことはありますが、for Oracleは初めてです。

Oracleデータベースには RMAN(Recovery Manager) というバックアップ・リカバリのための仕組みがあります。

Amazon RDSではスナップショットという仕組みがある中で、どのような機会にRMANを使うのか?使うとしたらどのような設定や操作が必要になるのか?が気になりました。

実際に動かしてイメージを掴みたいと思い、簡単な構成を作ってバックアップ取得までの一連の流れを試してみました。

この記事は、RDSは使い慣れているけれどOracleやRMANはあまり触ったことがない方、あるいは逆に OracleやRMANは分かるけれどRDSでどう扱うのかが気になる方を想定して書いています。わたしが前者の立場なのでRDSやAWSまわりの説明がサラッとになってしまうかもしれませんが、なるべく補足しながら書いていきます。

先にまとめ

RDS Oracle RMAN

  • 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を使う機会があります。セルフマネージドインスタンスへのリストアを伴うユースケースは下記ブログで紹介されています。

https://aws.amazon.com/jp/blogs/database/restore-an-amazon-rds-for-oracle-instance-to-a-self-managed-instance/

Amazon RDSでのRMANを試してみる

今回は下記の構成で試してみます。

RDS Oracle RMAN Lab

  • EC2にOracle接続のクライアントであるSQL*Plusをインストールし、そこからRDS DBインスタンスに接続、操作する
  • PL/SQLプロシージャでRMAN操作を実施し、バックアップを取得する
  • 取得したRMANバックアップをS3にアップロードする

CloudFormationで環境一式を構築します。一連の操作はAWS CloudShell経由で行います。

確認シナリオ

EC2からDBインスタンスに接続したあと、以下の流れで進めます。

  1. 事前準備:アーカイブログをバックアップに含めるための保持期間を設定し、テストデータを投入する
  2. 健全性の検証validate_databaseでソースデータベースに破損がないか確認する
  3. フルバックアップ:アーカイブログを含むフルバックアップをDBインスタンスのローカルに取得する
  4. S3へ転送:取得したバックアップをS3へアップロードする
  5. ローカルバックアップ削除:ローカルのバックアップファイルを削除する

あわせて、各ステップで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テンプレート

今回作成する環境を、あまりお行儀良くないですがひとつのテンプレートに詰め込みました。

折りたたみ
template.yaml
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-roleACTIVEで紐づいています。これが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"
        }
    ]
}

OptionsS3_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を(コピー&ペーストで)入力すると、継続行の番号(23)が末尾にまとまって出て、次のような表示になります。(少なくとも今回のわたしの環境ではなりました。)

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_configurationarchivelog retention hoursを設定します。

この値はRDSがアーカイブREDOログをローカルに保持する時間数で、バックアップに含めるには0より大きい値を設定する必要があります。今回は24時間に設定します。set_configurationrdsadminスキーマが管理する設定テーブルへの書き込みです。トランザクション操作のため、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 OKMarked Corrupt0になっており、破損ブロックがないことが確認できました。コントロールファイル・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分程度かかりました。

改めてまとめ

RDS Oracle RMAN

  • 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)がお送りしました。

参考

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事