zaki work log

作業ログやら生活ログやらなんやら

[Ansible] S3互換オブジェクトストレージのデータをget/putする

本エントリは、Ansible Advent Calendar 2023の8日目の記事です。

昨日のAnsibleアドカレ7日目で id:usagi_automate さんがAWXで作成したテキストファイルをZipに固めて手元に持ってきたい - うさラボという記事で「バイナリデータもBase64でテキスト化して転送やログ記録する」という内容を紹介していたので、本記事ではアプローチを変えて、クラウドサービスでよく使用するS3互換オブジェクトストレージに対してAnsibleを使ってデータをやり取りする方法について紹介します。

確認した環境は以下の通り。

  • Ubuntu 22.04
  • Ansible core 2.15.3
  • amazon.aws collection 6.3.0
  • boto3 1.33.9
  • botocore 1.33.9

ちなみに本記事ではS3とのデータのやり取りについて説明しており、S3自体の管理(バケットを作成したり等)は扱いません。予めS3バケットは存在し、適切な権限設定が行われているものとしています。

(12/13追記) Amazon S3以外の例としてOCIのオブジェクトストレージについて追記


amazon.aws.s3_objectモジュール

docs.ansible.com

Amazon S3とデータのやり取りを行うにはこのモジュールを使用します。
実行にはPythonパッケージのboto3botocoreが必要なのでpip installでインストールしておきます。

書き込み

ローカルにあるlocal.txtというファイルを、S3のsample-bucketバケット/path/to/sample.txtにアップロードします。

---
- hosts: localhost

  tasks:
  - name: put file
    amazon.aws.s3_object:
      bucket: sample-bucket
      object: path/to/sample.txt
      src: local.txt
      region: ap-northeast-1
      mode: put
      access_key: <AWS_ACCESS_KEY_ID>
      secret_key: <AWS_SECRET_ACCESS_KEY>

例えばジョブの実行で生成した結果のファイルをS3に保存したりする場合に使用できます。

読み込み

S3のsample-bucketバケット/path/to/sample.txtにあるファイルを、ローカルにdownload.txtとしてダウンロードします。

- hosts: localhost

  - name: get file
    amazon.aws.s3_object:
      bucket: sample-bucket
      object: path/to/sample.txt
      dest: download.txt
      region: ap-northeast-1
      mode: get
      access_key: <AWS_ACCESS_KEY_ID>
      secret_key: <AWS_SECRET_ACCESS_KEY>

例えば何かのアプリケーションをセットアップするジョブで、S3にインストーラを保存しておいてそれを利用する、みたいなことに使用できます。

Appendix

ディレクトリのアップロード/ダウンロード

ディレクトリを再帰的に…みたいな処理は対応していないので、複数ファイルのアップロード/ダウンロードが必要な場合は個別にタスクを実装します。
ダウンロードファイルしたい場合のS3上のファイル一覧はmode: listを指定すれば取得できるので、これとloop併用するなどして処理します。
prefixでパス指定もできます。(未指定の場合はルートから全てリストアップされるます)

  - name: list files
    amazon.aws.s3_object:
      bucket: sample-bucket
      prefix: path/
      region: ap-northeast-1
      mode: list
      access_key: <AWS_ACCESS_KEY_ID>
      secret_key: <AWS_SECRET_ACCESS_KEY>
    register: s3_files_list

このタスクの実行結果は以下の通り。

ok: [localhost] => changed=false 
  msg: LIST operation complete
  s3_keys:
  - path/to/files/files/file1.txt
  - path/to/files/files/file2.txt
  - path/to/sample.txt

Ansibleバージョンが古い場合

Ansibleバージョンというよりamazon.awsコレクションのバージョンが、という感じだけど、古い環境だとamazon.aws.s3_objectモジュールは存在せず、amazon.aws.aws_s3という名前でタスクを実装します。
また、アクセスキーとシークレットの指定は以下のようにaws_が付与されたキーを使います。

aws_access_key: <AWS_ACCESS_KEY_ID>
aws_secret_key: <AWS_SECRET_ACCESS_KEY>

警告

objectにフルパスの要領で/path/to/filenameと先頭に/を付与すると下記警告が出るので現バージョンでは不要です。

[DEPRECATION WARNING]: Support for passing object key names with a leading '/' has been deprecated.
This feature will be removed from amazon.aws in a release after 2025-12-01. 
Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.

Amazon S3以外 (12/13追記)

例えばOracle Cloud Infrastructure(OCI)のオブジェクトストレージはS3互換なので、このモジュールでやり取りが可能です。
アクセスキーとシークレットは「顧客秘密キー」で取得できます。
また、endpoint_urlは上記の通り書式は$namespace.compat.objectstorage.$region.oraclecloud.comとなります。

  - name: put file
    amazon.aws.s3_object:
      bucket: <バケット名>
      object: path/to/sample.txt
      src: local.txt
      mode: put
      access_key: <アクセスキー>
      secret_key:  <シークレット>
      endpoint_url: https://<namespace>.compat.objectstorage.<region>.oraclecloud.com

docs.oracle.com

docs.public.oneportal.content.oci.oraclecloud.com

使いどころ

サーバー上でCLIansible-playbookコマンドを実行する際はその環境のファイルシステム上にあるファイルにアクセスできるので、大容量ファイルをあらかじめ配置してそれを参照、とか、自動化の実行後に生成するファイルを後から確認、みたいなことは従来通り容易ですが、AAPやAWXからジョブを実行する際はコンテナ環境の実行になることで「あらかじめファイルを配置しておく」「実行後にファイルを確認する」が基本的に出来ません(ジョブ完了後は実行環境は消えるため)。
そこでリモートからファイルをgetしたりputするという手順が必要になるため、S3のようなオブジェクトストレージを使うことで比較的簡単にファイルのやり取りが可能になります。

レガシーな環境であればHTTPやFTPの方が良かったりするかもしれないので、環境に合わせて実装してみましょう。