TSUBOCK★LABO-ツボックラボ-

とあるセキュリティエンジニアの技術メモブログ

MENU

MinIOをPythonで操作してみよう

以前紹介したMinIOをPythonで操作してみたいと思います。

過去の記事はこちら

www.tsubock-lab.xyz

MinIOはAmazon S3互換であるためAmazon S3を操作する際のPythonモジュールを使用することで使用することができます。今回はBoto3というPythonモジュールを使用してみたいと思います。

Boto3とは

Boto3はAWSが公式で提供している、Amazon S3をPythonから操作するためのライブラリです。Amazon S3がAPIとして公開している機能をBoto3を使うことで利用することができます。

インストール

Boto3のインストールはpipコマンドから行うことができます。

pip install boto3

実際に使ってみる

Boto3を使ってMinIOを操作してみたいと思います。まずは前回作成したバケットにアップロードされているファイルの一覧を取得してみましょう。

import boto3

s3 = boto3.client("s3", endpoint_url="http://127.0.0.1:9000",
                  aws_access_key_id='minioadmin',
                  aws_secret_access_key='minioadmin')

object_list = s3.list_objects(Bucket='test').get("Contents")

print(object_list)

実行した結果は下記の通り

[
 {
  'Key': 'minio_01.png', 
  'LastModified': datetime.datetime(2020, 7, 23, 16, 39, 18, 470000, tzinfo=tzutc()), 
   'ETag': '"c1acffd60da35db4c180b0a5858dd735"', 
   'Size': 18253, 
   'StorageClass': 'STANDARD', 
   'Owner': 
    {
      'DisplayName': '', 
      'ID': '02d6176db174dc93cb1b899f7c6078f08654445fe8cf1b6ce98d8855f66bdbf4'
    }
  }
]

Keyにはアップロードされているファイル名が入ってきます。 今回はアップロードされている`minio_01.png'を取得したいと思います。 ファイルのダウンロードにはdownload_fileを使用します。

使い方は

download_file('Bucket名', 'バケット上のobject名', '保存先のfilepath')

でファイルをダウンロードすることができます。

import boto3

s3 = boto3.client("s3", 
                  endpoint_url="http://127.0.0.1:9000",
                  aws_access_key_id='minioadmin',
                  aws_secret_access_key='minioadmin')

file = s3.download_file('test',"minio_01.png", "./minio_01.png")

上記の実行結果としてカレントディレクトリに'minio_01.png'が保存できていることが確認できます。

MinIO用のPythonパッケージ

実はMinIO用のPythonパッケージもあります。私の場合は開発するPythonプログラムの実動作環境がAmazon S3で、ローカルの開発環境でAmazon S3の代わりとしてMinIOを使用するため、Amazon S3互換のboto3を使用することが多いのですが、最初からMinIOしか使用しないのであれば、MinIO用のPythonモジュールを使うといいかもしれません。

minioのインストール

minioはpipコマンドでインストールすることができます。

pip install minio

また、gitリポジトリからダウンロードして使用することもできます。

git clone https://github.com/minio/minio-py
cd minio-py
python setup.py install

実際に使ってみる

先ほどのようにファイルリストを取得して、その後ファイルを取得したいと思います。

from minio import Minio

minioClient = Minio('127.0.0.1:9000',
                    access_key='minioadmin',
                    secret_key='minioadmin',
                    secure=True)

objects = minioClient.list_objects('test',
                                   prefix='',
                                   recursive=True)
                                                                      
for obj in objects:
    print(obj.object_name.encode('utf-8'))

しかし、上記の結果がエラーになってしまいます。。。なぜでしょうか・・・

$ python3 list_objects.py
Traceback (most recent call last):
  File "/home/testuser/.local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 672, in urlopen
    chunked=chunked,
  File "/home/testuser/.local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 376, in _make_request
    self._validate_conn(conn)
  File "/home/testuser/.local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 994, in _validate_conn
    conn.connect()
  File "/home/testuser/.local/lib/python3.6/site-packages/urllib3/connection.py", line 394, in connect
    ssl_context=context,
  File "/home/testuser/.local/lib/python3.6/site-packages/urllib3/util/ssl_.py", line 370, in ssl_wrap_socket
    return context.wrap_socket(sock, server_hostname=server_hostname)
  File "/usr/lib/python3.6/ssl.py", line 407, in wrap_socket
    _context=self, _session=session)
  File "/usr/lib/python3.6/ssl.py", line 817, in __init__
    self.do_handshake()
  File "/usr/lib/python3.6/ssl.py", line 1077, in do_handshake
    self._sslobj.do_handshake()
  File "/usr/lib/python3.6/ssl.py", line 689, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:852)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "list_objects.py", line 29, in <module>
    for obj in objects:
  File "/home/testuser/.local/lib/python3.6/site-packages/minio/api.py", line 1036, in list_objects
    headers=headers)
  File "/home/testuser/.local/lib/python3.6/site-packages/minio/api.py", line 1984, in _url_open
    region = self._get_bucket_region(bucket_name)
  File "/home/testuser/.local/lib/python3.6/site-packages/minio/api.py", line 1919, in _get_bucket_region
    region = self._get_bucket_location(bucket_name)
  File "/home/testuser/.local/lib/python3.6/site-packages/minio/api.py", line 1950, in _get_bucket_location
    headers=headers)
  File "/home/testuser/.local/lib/python3.6/site-packages/urllib3/poolmanager.py", line 330, in urlopen
    response = conn.urlopen(method, u.request_uri, **kw)
  File "/home/testuser/.local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 760, in urlopen
    **response_kw
  File "/home/testuser/.local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 760, in urlopen
    **response_kw
  File "/home/testuser/.local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 760, in urlopen
    **response_kw
  [Previous line repeated 2 more times]
  File "/home/testuser/.local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 720, in urlopen
    method, url, error=e, _pool=self, _stacktrace=sys.exc_info()[2]
  File "/home/testuser/.local/lib/python3.6/site-packages/urllib3/util/retry.py", line 436, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /test?location= (Caused by SSLError(SSLError(1, '[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:852)'),))

公式が出しているSampleを使ってもうまくいかないですね・・・ list_objects.py - minio/minio.py

とりあえず取得したいファイル名はわかっているので、ファイルが取得できるか試してみたいと思います。

from minio import Minio

minioClient = Minio('127.0.0.1:9000',
                    access_key='minioadmin',
                    secret_key='minioadmin',
                    secure=True)

file = s3.fget_object('test',"minio_01.png", "./minio_01.png")

うーん・・・上記もうまく動かないですね・・・

例によって公式が出してるSampleでも動かないです・・・ぐぬぬ・・・

fget_object.py - minio/minio-py

まとめ

本来であれば、どっちのモジュールの方が使いやすいかというのをお伝えしたかったのですが、うまく動かずでした。引き続き調べてみたいと思います。 MinioをPythonで使うときはBoto3を使った方がうまく動きそうなのと、Boto3の方が広く使われているモジュールなのでトラブルシューティングがしやすいと感じました。MinioはAmazon S3と互換性がありますし、そのままBoto3を使用するのが良いのかもしれないと思います。

参照:

AWS SDK for Python (Boto3)

MinIO Python Library for Amazon S3 Compatible Cloud Storage