よしたく blog

ITエンジニアとして自分が知らなかったことをまとめています

MinIOをboto3を使ってPythonから操作する

Python で S3 を操作するときに使う、AWS SDK for Python(boto3) を使って MinIO も操作できる。 以前作った環境を利用し、Python から操作できるか確認する。

yoshitaku-jp.hatenablog.com

準備

インストール

pip で boto3 をインストールしておく。

pip install boto3

コピー元ファイルの配置

ファイルアップロード機能を確認する際、minio から minio へファイルをコピーするような形で実現する。 今回はsystem-drummondバケットを作成し、test.mdファイルを作成して配置しておいた。

接続情報の確認

接続は client を使い、接続のための情報を設定する。

  • endpoint_url
    • 起動している Docker を指定
  • aws_access_key_id
    • ユーザ ID
    • 前回記事の Docker よりminioを設定
  • aws_secret_access_key
    • パスワード
    • 前回記事の Docker よりminiominiominioを設定
s3 = boto3.client(
    "s3",
    endpoint_url="http://127.0.0.1:9000",
    aws_access_key_id="minio",
    aws_secret_access_key="miniominiominio",
)

バケットの作成

import boto3

s3 = boto3.client(
    "s3",
    endpoint_url="http://127.0.0.1:9000",
    aws_access_key_id="minio",
    aws_secret_access_key="miniominiominio",
)
response = s3.list_buckets()
print(response["Buckets"])

s3.create_bucket(Bucket="from-boto")

response = s3.list_buckets()
print(response["Buckets"])
[{'Name': 'system-drummond', 'CreationDate': datetime.datetime(2022, 4, 29, 2, 4, 53, 547000, tzinfo=tzutc())}]
[{'Name': 'from-boto', 'CreationDate': datetime.datetime(2022, 4, 29, 2, 49, 46, 32000, tzinfo=tzutc())}, {'Name': 'system-drummond', 'CreationDate': datetime.datetime(2022, 4, 29, 2, 4, 53, 547000, tzinfo=tzutc())}]

まず初期状態をs3.list_buckets()で確認すると、準備で作成したsystem-drummondが存在していることがわかる。 s3.create_bucket(Bucket="from-boto")from-botoバケットを作成し、再度s3.list_buckets()で確認するとfrom-botoバケットが作成されていることが確認できる。

ファイルアップロード

import boto3

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

object_list = s3.list_objects(Bucket="from-boto").get("Contents")
print(object_list)

s3.upload_file("./minio/data/system-drummond/test.md", "from-boto", "test.md")

object_list = s3.list_objects(Bucket="from-boto").get("Contents")
print(object_list)
None
[{'Key': 'test.md', 'LastModified': datetime.datetime(2022, 4, 29, 3, 4, 45, 30000, tzinfo=tzutc()), 'ETag': '"2debfdcf79f03e4a65a667d21ef9de14"', 'Size': 5, 'StorageClass': 'STANDARD', 'Owner': {'DisplayName': 'minio', 'ID': '02d6176db174dc93cb1b899f7c6078f08654445fe8cf1b6ce98d8855f66bdbf4'}}]

こちらも、まずは初期状態を確認する。 from-botos3.list_objects(Bucket="from-boto").get("Contents")で確認すると、Noneであることがわかる。 「コピー元ファイルの配置」で配置したtest.mdを、s3.upload_file("./minio/data/system-drummond/test.md", "from-boto", "test.md")でアップロード処理する。 再びs3.list_objects(Bucket="from-boto").get("Contents")で見ると、test.mdが追加されていることがわかる。

バケットの削除

import boto3

s3 = boto3.client(
    "s3",
    endpoint_url="http://127.0.0.1:9000",
    aws_access_key_id="minio",
    aws_secret_access_key="miniominiominio",
)
response = s3.list_buckets()
print(response["Buckets"])

s3.delete_object(Bucket="from-boto", Key="test.md")
s3.delete_bucket(Bucket="from-boto")

response = s3.list_buckets()
print(response["Buckets"])
[{'Name': 'from-boto', 'CreationDate': datetime.datetime(2022, 4, 29, 2, 49, 46, 32000, tzinfo=tzutc())}, {'Name': 'system-drummond', 'CreationDate': datetime.datetime(2022, 4, 29, 2, 4, 53, 547000, tzinfo=tzutc())}]
[{'Name': 'system-drummond', 'CreationDate': datetime.datetime(2022, 4, 29, 2, 4, 53, 547000, tzinfo=tzutc())}]

from-botosystem-drummondが取得できる。 s3.delete_object(Bucket="from-boto", Key="test.md")でオブジェクトの中身のtest.mdを削除、その直後にs3.delete_bucket(Bucket="from-boto")from-botoバケットを削除している。 無事に削除できているので、最終的に表示されるのはsystem-drummondバケットだけになっている。

まとめ

Python から MinIO を触り、オブジェクト操作をおこなってみた。 S3 同様にcreate_bucketupload_filedelete_objectといった標準的な部分を使えることが確認できた。

【Rails】HerokuでPumaを使用する

Heroku の dyno リソースを理解できておらず、rails serverでアプリケーションを起動していた。 Heroku は Web サーバとして Puma を推奨しているので、Puma で明示的に起動できるように設定を変更してみる。

puma.io

Procfile

設定をせずシンプルに起動させるならば、Procfile に下記を記述する。

web: bundle exec puma

通常、rails new をするとconfig/puma.rbにファイルが生成されている。 そして-Cconfig/puma.rbを指定すると、設定ファイルに書き込まれた設定を読み込んでくれる。

web: bundle exec puma -C config/puma.rb

config/puma.rb

config/puma.rbの中身も確認してみる。 Rails 7.0.2.3では次のようになっている。

max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
threads min_threads_count, max_threads_count

worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development"

port ENV.fetch("PORT") { 3000 }

environment ENV.fetch("RAILS_ENV") { "development" }

pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }

plugin :tmp_restart

max_threads_countで使用する最大のスレッド数を決める。環境変数RAILS_MAX_THREADSがなければ 5 が設定される。 min_threads_countは使用する最低のスレッド数を決める。環境変数RAILS_MIN_THREADSがなければ max_threads_count を設定することになり、今回の場合は 5 となる。 threadsで、max_threads_countmin_threads_countの値を利用し設定する。

worker_timeoutは、指定された時間内にすべてのワーカーがマスタープロセスにチェックインしたことを確認する。確認できない場合ワーカープロセスが再開される。 "RAILS_ENV"が設定されていれば利用し、なければdevelopmentとなり、3600 が設定される。

portは利用するポートになる。 environmentは実行環境を指定する。

pidfileは、環境変数PIDFILEを利用し、なければtmp/pids/server.pidから値を取得する。

pluginは Puma へ機能追加するときに使用する。今回の場合はサーバの再起動を可能にするプラグインが設定されている。

Rails7でTailwind CSSを試す

Rails7 になって TailwindCSS が使えるようになったので、導入方法をメモしておく。

rails new

rails new をするタイミングで tailwind を導入するには--css tailwindオプションを指定する。

rails new myapp --css tailwind
cd myapp

このあたりは定型文になるが載せておく。

rails g scaffold todo name:string
rails db:create db:migrate

rails sをしてhttp://127.0.0.1:3000/todosにアクセスする。

f:id:yoshitaku_jp:20220417112311p:plain

変わっていない…

Rails7 では起動方法に注意

Rails 7 ではrails sコマンドを実行しても JavaScriptCSS がビルドされず、./bin/devコマンドで起動すると JavaScriptCSS がビルドされる。 ブラウザをリフレッシュすると TailwindCSS が適用されていることがわかる。

f:id:yoshitaku_jp:20220417112446p:plain

また、./bin/devで起動すると JavaScriptCSS を変更したときに自動的に再ビルドもしてくれるので、今後はこちらで起動することを忘れないようにしたい。

Docker Compose環境のRailsをHerokuへデプロイする

Docker Compose 環境で作成した Rails アプリケーションを Heroku へアップロードするには Git を使用したデプロイとは別のコマンド実行が必要になる。 例えば Git を使用するときはgit push heroku mainなどでデプロイができたが、Docker Compose 環境は Heroku CLI ツールを使うことになる。 今回は Docker Compose 環境をデプロイするための手順をまとめる。

Dockerfile と docker-compose.yml

Dockerfile と docker-compose.yml も参考として載せておく。

Dockerfile

FROM ruby:3.1.0

ENV APP_ROOT /myapp
RUN mkdir $APP_ROOT
WORKDIR $APP_ROOT
ADD . $APP_ROOT
RUN bundle install

CMD ["rails", "server", "-b", "0.0.0.0"]

docker-compose.yml

version: '3'
services:
  db:
    image: postgres
    ports:
      - '5432:5432'
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: 'admin'
      POSTGRES_PASSWORD: 'admin-pass'
  web:
    build: .
    volumes:
      - .:/myapp
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    ports:
      - 3000:3000
    depends_on:
      - db

Docker Compose 環境をデプロイするまで

Heroku の Container Registry にログインする。

heroku container:login

Heroku アプリを作成する。

heroku create

Container Registry に docker image を push する。

heroku container:push web

push した docker image を Heroku アプリにリリースする。

heroku container:release web

まとめ

Docker Compose 環境で作成した Rails アプリケーションを Heroku へアップロードする手順を確認した。 無事にアップロードできたが、毎回コマンドを打ち込まなければいけないのが大変とも感じる。 heroku.ymlを使ってデプロイする方法もあるので、こちらも確認していく。

Action CableをHerokuで動かす時のサブスクリプションアダプタ設定

Heroku で Action Cable を使うにはデフォルトの設定から変更する必要がある。 具体的に、初期設定ではconfig/cable.ymlファイルは下記のようになっており、redis を使う設定になっている。Heroku 環境を用意したときにデフォルトで Redis は使用できないので production 部分を変更する必要がある。

development:
  adapter: async

test:
  adapter: test

production:
  adapter: redis
  url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
  channel_prefix: heroku_cable_production

Action Cable で使えるサブスクリプションアダプタ

Action Cable で使えるサブスクリプションアダプタを整理する。 前提として Action Cable を動かすためにはサブスクリプションアダプタを設定する必要があり、現在利用できるアダプタは 3 種類ある。

  • Async アダプタ
    • 開発やテスト環境で利用するためのもの
  • Redis アダプタ
  • PostgreSQL アダプタ

Async アダプタは開発やテスト環境用で、 Heroku を本番環境として用意し Action Cable を動かすためには適していない。 Redis アダプタは、Heroku で Redis を使おうとすると別料金が掛かるため、一旦選択肢から外す。 その結果、Heroku 環境で無料利用できる PostgreSQL アダプタを使うのが選択肢に上がってくる。 ここからは PostgreSQL アダプタを使うための設定変更をおこなう。

設定変更

config/cable.yml の設定を変更する。 作成直後、 production 部分は redis が指定されていたが adapter を postgresql に変更する。 また、URL 部分も DATABASE_URL を見るように変更する。

development:
  adapter: async

test:
  adapter: test

-production:
-  adapter: redis
-  url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
-  channel_prefix: heroku_cable_production
+production:
+  adapter: postgresql
+  url: <%= ENV['DATABASE_URL'] %>

まとめ

Heroku で Action Cable を使うための設定変更を確認した。 ちなみに、Heroku 環境で async 使うことは推奨されていないだけで、使うことはできる。 その場合は development に書いてあるのと同じように adapter に async を設定すれば利用可能になる。

development:
  adapter: async

test:
  adapter: test

-production:
-  adapter: redis
-  url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
-  channel_prefix: heroku_cable_production
+production:
+  adapter: async

macOS Montereyから登場したショートカットを使う

iOSでは以前から使うことができたショートカットアプリが、Macでも使うことができるようになった。 現在自分が設定しているものをアイデアとして載せておく。

www.apple.com

コミュニケーション系アプリを全部終わらせるショートカット

起動したコミュニケーション系アプリをすべて閉じるためのショートカットを作成した。

f:id:yoshitaku_jp:20220327213119p:plain

コミュニケーション系アプリを開始するショートカット

逆にこちらはコミュニケーション系アプリを起動するためのショートカットになる。 ダラダラ見て時間が経っていることを避けるため、起動した後は5分後に前述の「コミュニケーション系アプリを全部終わらせるショートカット」を呼び出すようにしている。

f:id:yoshitaku_jp:20220327222136p:plain

ブログ執筆環境をVisual Studio Codeで開く

iOS版より様々なことができるようでシェルスクリプトの実行も可能になっている。

cd /Users/yoshitaku/workspace/blog
code .

を実行して執筆環境を開けるものになっている。

f:id:yoshitaku_jp:20220327222540p:plain

Terminal is dumb but no VISUAL nor EDITOR defined.エラーを解決する

macOS Monterey にして VS Code から git commitとしたらTerminal is dumb but no VISUAL nor EDITOR defined.が発生した。

デフォルト設定が外れてしまった理由がよくわからないけど、再度設定しておく。 設定する際に検索したことと、検索しても欲しい情報になかなかヒットしなかったのでメモとして残しておく。

git config --global core.editor vim

S3互換のMinIOを触ってみた

MinIO とは

MinIO は、高性能で S3 互換のオブジェクトストレージを提供します。 Kubernetes にネイティブな MinIO は、以下のような環境で利用できる唯一のオブジェクトストレージスイートです。 すべてのパブリッククラウド、すべての Kubernetes ディストリビューションプライベートクラウド、そして エッジになります。MinIO はソフトウェア定義型であり、GNU AGPL v3 のもと 100%オープンソースで提供されます。

MinIO は AWS の S3 と互換性のあるストレージになる。 Minio と表記されている記事をよく見たけど、公式サイトには MinIO と書いてあった。

min.io

Docker で動かす

MinIO を docker-compose で動かす。 ports90009001で分けているが、1 つにまとめようとするとうまくうごかなかったので、このまま分けておいたほうが良さそう。 docker-compose.yml は次のような形。

minio:
  image: "minio/minio"
  container_name: minio
  environment:
    MINIO_ROOT_USER: minio
    MINIO_ROOT_PASSWORD: miniominiominio
  command: server /export --address :9000 --console-address :9001
  volumes:
    - ./minio/data:/export
  ports:
    - "9000:9000"
    - "9001:9001"

docker-compose upで起動すると、http://127.0.0.1:9001/loginでアクセスができる。

ユーザ名とパスワードは docker-compose.yml で設定したので、ログインする。

  • ユーザ名
    • minio
  • パスワード
    • miniominiominio

Bucket 作成

画面上から Bucket を作成してみる。

Bucket Name に system-a と入力し、Create Bucket をクリックする。

無事に作成できたことが確認できる。

ファイル配置

Upload ボタンをクリックするとファイルをアップロードできる。 これはアップロード後の画面になる。

左のタブの Buckets をクリックすると Bucket の一覧と先ほど作成したsystem-aBuclet が見える。 ファイルを置いたことにより、Usage と Objects にも現在の数値が反映されている。

ディレクトリにもファイルが配置されていることがわかる。

まとめ

ローカルで S3 と同等のことができる MinIO を触ってみた。 ローカル環境で開発するときに S3 を用意する必要もないし、Docker で実行することも確かめられたので CI 環境でも利用できそう!

Streamlitに用意されている「line_chart」「area_chart」「bar_chart」を触ってみた

Streamlit について引き続き確認していく。

yoshitaku-jp.hatenablog.com

今回は Streamlit で標準に用意されている simple chart を試す。

紹介されているのは以下の 3 種類になる。

line_chart

線グラフはst.line_chart関数で表現できる。 ここでは温度の上下を想定したデータを作って表現してみた。

df_temp = pd.DataFrame(
    np.random.uniform(15.0, 25.0, 6), columns=["温度"], index=np.array(range(9, 15))
)
st.line_chart(df_temp)

表示されるとこんな感じ。

f:id:yoshitaku_jp:20220305092503p:plain

docs.streamlit.io

area_chart

面グラフはst.area_chart関数で表現できる。 ここでは月の収支を想定したデータを作って表現してみた。

df_pl = pd.DataFrame(
    np.random.uniform(500, 1000, (12, 2)),
    columns=["収入", "支出"],
)
st.area_chart(df_pl)

表示されるとこんな感じ。

f:id:yoshitaku_jp:20220305092510p:plain

docs.streamlit.io

bar_chart

棒グラフはst.bar_chart関数で表現できる。 ここではページごとのクリック数を想定したデータを作って表現してみた。

df_clicks = pd.DataFrame(
    np.random.uniform(500, 1000, 3),
    columns=["clicks"],
    index=["Page A", "Page B", "Page C"],
)
st.bar_chart(df_clicks)

表示されるとこんな感じ。

f:id:yoshitaku_jp:20220305092518p:plain

docs.streamlit.io

まとめ

今回は simple chart として紹介されていた line_chartarea_chartbar_chartを触ってみた。

簡単に表現できてとても便利だと感じたが、DataFrame でのデータの持ち方や DataFrame の Index に依存するようなので、そこのメンテナンスが鍵になりそう。現段階で pyplot に慣れていない自分でも、関数に DataFrame を流すだけで図表を書いてくれるのは大変ありがたかった! また、今は種類が少ないので別の図表も表現できるようになれば嬉しいと感じた。 streamlit/roadmap#q2-2022に 「Develop apps in the browser.」「We want to make it much, much easier to create beautiful charts with a single line of code!」といったことが書いてあるので、期待している!

凝った表現をしたければシンタックスシュガーとして紹介されているst.altair_chart st.pyplotを使うことになる。Streamlit を導入する前までに pyplot で作成してきた資産があれば、こちらがいいと思う

SQLAlchemyを使ってMysql 8.0にアクセスしたらAuthentication plugin 'caching_sha2_password' is not supported エラーが発生した

SQLAlchemyを使ったPython環境でDcoker上に立てたMysql 8.0にアクセスしたらAuthentication plugin 'caching_sha2_password' is not supported エラーが発生した。 これはMySQLのバージョン8.0以降、デフォルトの認証方式がcaching_sha2_passwordに変更されているが、SQLAlchemyが対応していないため発生している。

MySQL5.7までの認証プラグインには mysql_native_password がデフォルトで使用されていましたが、MySQL8.0より新たに追加された caching_sha2_password に変更されました。 SHA-256を使用した、より安全なパスワードの暗号化を提供するとともに、キャッシュを使用して同一ユーザの認証処理を高速化しようという、MySQL推奨の認証プラグインです。

(中略)

しかし、認証プラグインに caching_sha2_password を設定しているユーザは、接続に使用するクライアント又はコネクタ側でも caching_sha2_password をサポートしている必要があり、サポートされていない場合は、認証エラーが返されます。

MySQL8.0新機能 (caching_sha2_password 認証プラグイン) | スマートスタイル TECH BLOG

このエラーを回避するためにcaching_sha2_passwordがサポートされているコネクタを使用することはもちろん挙げられるが、Dockerを使って一時的にアクセスしたかったことと、Pandasのread_sql_query関数では引数sqlalchemyを使わなければいけないので、MySQL側の設定を変更することで回避した。

mysqld --default-authentication-plugin=mysql_native_password