7rikazhexde’s tech log

技術的な興味関心、備忘録、アウトプットなどを書いています。

Manta Networkでのステーキング方法について

久々に暗号資産の記事を投稿します。
暗号資産について、2024年はModular Blockchain,DePin,AI関連のトークンに注目しています。

日本の取引所では2024/02/23現在で匿名性のトークンは取り扱われていませんが、プライバシーに配慮したトークンにも注目しています。
特にゼロ知識証明(Zero-Knowledge Proof)によるユースケースが増えることに期待しています。

medium.com

また、元々私はPolkadotに関心があり、プライバシーを考慮した仕組みを持つManta Networkにも注目していました。Manta Networkのパラチェーンオークションには参加していませんが、2023年にはL2向けのManta Pacificが開発され、2024年にはバイナンスでもトークンが扱われるようになりました。

本記事では調査したManta Networkについての概要と、ステーキング方法について紹介します。

概要

  • Manta Networkについて
  • Manta Pacific(L2:イーサリアムLayer2ネットワーク/Manta Pacific L2 Rollup)からManta Atlantic(L1:PolkadotパラチェーンのMoonbeam)へのブリッジ
  • Manta Atlanticでのステーキング方法

Manta Networkについて

Manta Networkは、web3のためのモジュラー型エコシステムを提供しており、二つの主要な部分、Manta PacificとManta Atlanticに分かれています。

参考記事: プライバシーを提供するブロックチェーン「Manta Network(MANTA)」の解説

Manta Network

Manta Pacific

Manta PacificはModular Blockchainに分類されるレイヤー2です。詳細は下記リンクを参照ください。

MantaトークンはERC-20, Native1を持つトークンで、
Manta Pacific L2 Rollupネットワークをメタマスクに追加することでManta Pacificチェーンとしてブリッジや後述するステーキング(L1/XCMへのブリッジが必要)をできるようになります。

Manta Atlantic

Manta Atlanticはプライバシーを重視しかつコンプライアンスに対応することが可能な、高速なZKレイヤー1です。詳細は下記リンクを参照ください。

Manta PacificからManta Atlanticへのブリッジ

公式ドキュメントのBridging $MANTA between Pacific and Atlanticに記載されていますが、ブリッジにはいくつかの工程があります。まとめると下記です。

  • トークンはL2(Ethereumネットワーク:Manta Pacific) からL1(Polkadotネットワーク:Manta Atlantic / XCM Bridge / Moonbeam)に移動させるために、ブリッジを使用する。
  • L2ではネイティブトークンとして$MANTAが存在する状態。
  • ブリッジを使用すると、Moonbeamネットワーク2を介してxcMantaトークンが生成される。(L2->L1)
  • xcMantaは、Manta Atlantic上で使用できる形式のトークンとなる。

Manta Atlanticでのステーキング

詳細は公式ドキュメントのルールにまとめられていますが、ポイントは以下です。(2024/02/23現在)

  • StakeにはMinimum Stake以上が必要
  • CollatorへのDelegateは1カウント25件まで
  • 報酬対象はCollatorが上位63位内
  • 報酬対象のDelegatorsは1Collatorにつき上位100位内
  • 報酬はラウンドと呼ばれる6時間間隔で計算/付与される
  • 手動のClaimは不要
  • Delegatorsの解除または縮小には7日間の待機期間が必要

Collator数はSubscan Explorer / Manta / Acountから確認できます。(2024/02/23現在)

Manta Atlantic Subscan Manta AccountRole

Delegatorsのランキングは下記Stakingページのリンクから確認できます。 https://app.manta.network/manta/stake

Manta Atlantic Staking Status

ステーキングの流れ

Manta Atlanticアプリからステーキングする場合

Manta Pacific(L2)からManta Atlantic(L1)にブリッジしてxcMantaトークンを取得する

xcMantaトークンはMoonbeamネットワーク経由で取得するため、GLMRトークンが必要になりますが、自動で付与されるので事前に準備しておく必要はありません。

また、MantaトークンをManta PacificからMoonbeamに送金する際には最大10分の時間が必要になります。転送途中で止めることはできないため、途中ブラウザを閉じるとGOXしますので注意してください。

Bridge from Manta Pacific to Manta Atlantic

補足として、上記画像ではガス代が不足していますが、ETHがManta Pacific L2 Rollupネットワークに必要になります。イーサリアムメインネットからブリッジでは個人的には比較的ガス代が安いLayerswapをおすすめします。

xcManta

コレーターを選択しステーキングする

ステーキングはNova Walletでも指定できますが、2024/02/23現在ではコレーターの追加には対応していないようです。

Manta Atlantic Staking

BIfrostアプリによるステーキング方法

MantaのステーキングはBIfrostアプリからもできます。

私はBifrostアプリからのステーキングは確認していないので詳細は紹介できませんが、Manta Networkの日本コミュニティが公開しているNotionページ(Bifrostにおける$MANTA リキッドステーキング チュートリアル)にて紹介されていますので、こちらを参照してください。BIfrostアプリではswapやfarmingもできるようです。

まとめ

以下内容について紹介しました。

  • Manta Networkについて
  • Manta Pacific(L2:イーサリアムLayer2ネットワーク/Manta Pacific L2 Rollup)からManta Atlantic(L1:PolkadotパラチェーンのMoonbeam)へのブリッジ
  • Manta Atlanticでのステーキング方法

Manta Networkの今後については、ロードマップトークンで記事が公開されていますが、zkEVMに移行して開発環境の整備を進めてMainnetの完了となるようです。

ここは同様にパラチェーンオークションに参加したASTRと共通していますが、Manta PacificはUniversal Circuits(可能汎用ZK回路)をさらにアップグレードして、ガスコストの削減、より多くのユースケースのサポート、さらに優れたユーザーエクスペリエンスの提供を可能にすることを目指しているようです。

より多くのユースケースに見合ったZKアプリケーションが作成されることを期待します。

以上です。


  1. MantaのNativeトークンはBifrost appでswapする方法で取得可能かも知れませんが、動作確認はしていないため結果は保証しません。
  2. Moonbeamは、Ethereumと完全に互換性を持つスマートコントラクトを展開するPolkadot系プロジェクトです。

ObsidianとShortcutsアプリを使用して簡単に日記作成する環境を整えた話

はじめに


2024年が始まりました。
年始早々、令和6年能登半島地震があり、心落ち着かない年の始まりとなりましたが、被害を受けた方には1日でも早く普段の生活に戻れるよう願っています。


昨年、以下の記事で2023年の振り返り記事を投稿し、
その中で、「月次の投稿もしていきたい」ということを記載しました。

ただ、記事を書く際、私の場合は、

  • 何をやったか思い出せない。
  • 明日から日記を書くぞと意気込んでも、3日坊主で気づいたら書かなくなる。

そんな状況が続き、気づくと2023年が終わってしまいました…。

そこで、どうしたら続けられるかなと考えたところ、
ObsidianとShortcutsアプリを使えば続けられそうだ、という環境を作れたので本記事で紹介することにしました。

モチベーション

日記をアナログで考えるとノートとペンがあれば書けますが、それをデジタルに置き換えた場合、それはアプリとキー入力に相当すると考えます。

次に日記を書くまでの工程をアナログとデジタルで考えてみます。

アナログの場合:
1️⃣ノートを出す > 2️⃣日記ページを開く > 3️⃣日記を書く

デジタルの場合:
1️⃣アプリを開く > 2️⃣日記ページを開く > 3️⃣日記を書く(キーを入力する)

工程数は同じですが、アナログでは栞を挟むなどすれば1️⃣と2️⃣を省くこともできます。しかし、デジタルの場合はどうでしょうか?

3️⃣で入力をショートカットキーなどで作成すれば、効率的に日記を書くことはできますが、1️⃣と2️⃣では思っているよりも、手間がかかると感じています。(少なくとも私の性格ではここをクリアしないと書かないです。)

そこで、1️⃣、2️⃣、3️⃣の操作をなるべく短く、簡単に実行できるような方法を考えることにしました。

作成したもの

iPhone/iPad/Mac限定ですが、ShortcutsMarkdownメモアプリであるObsidianを使用するショートカットを作成しました。

ショートカットは以下のiCloudリンクから取得できます。

ObsidianとShortcutsアプリのインストールと後述するvaultの設定、日記保存先のフォルダを設定することでショートカットを1度実行するだけで日記の記入から保存まで実行できます。

www.icloud.com

処理の流れ

3️⃣, 1️⃣, 2️⃣をショートカットで順に実行します。
結果、ショートカットを1度実行するだけで日記の記入から保存まで実行します。

  • その日に初めて日記を書く場合

    • 指定入力(日記内容)をYYYY-MM-dd.txtで保存
    • YYYY-MM-dd.txtをObsidianがメモを保存するローカルファイルシステムのフォルダーであるvaultの日記保存用のフォルダに保存
    • YYYY-MM-dd.txtYYYY-MM-dd.mdに変換1
  • すでに日記(YYYY-MM-dd.md)が存在する場合(例:日記保存用のフォルダに2023-12-17.mdがすでに保存されている)

    • 指定入力(日記内容)とYYYY-MM-dd.mdの中身を取得し、結合
    • YYYY-MM-dd.mdで上書き保存

日記記入(Obsidian)ショートカット

日記記入(Obsidian)

取得結果

以前投稿したものと同じですが、処理の流れで記載した内容で日記を保存できていること確認できると思います。

Community plugins / Daily-Notes-Editorについて

Obsidianで日記(YYYY-MM-dd.md)を作成する場合、以下のDaily-Notes-Editorを追加するとブログ形式で表示できます。
便利な機能ですのでショートカットと合わせて使うことをお勧めします。

github.com

まとめ

ObsidianとShortcutsアプリ使用して簡単に日記を作成する方法について紹介しました。

ショートカットで記入した内容はObsidianに読み込まれるため、タグやボックスの入力も反映されます。

気になればショートカットを追加して使ってみてください。

また、記事が参考になれば、是非「はてなスター」もお願いします!

以上です。


  1. .txtから.mdの変換はYYYY-MM-dd.mdを指定しても.txtで保存されるので変換します。

【Obsidian】テンプレート設定とショートカットキーの使い方

概要

私はメモアプリとしてObsidianを使用しています。

ノート作成時は右クリック > insertで、Tableなどを挿入できますが、調べると設定から作成済みのテンプレートを指定して挿入できることがわかりました。

本記事ではObsidianのテンプレート機能について以下内容について記載します。

  • テンプレートの設定(Core plugins / Templates)
  • ショートカットキーの設定とテンプレートの挿入(Options / Hotkeys)
  • 新規ノート作成時にテンプレート呼び出し可能なプラグインである Auto Template Trigger の設定

テンプレートの設定(Core plugins / Templates)

以下でテンプレート保存先を指定します。

Settings > Core plugins > template folder location

下記例ではTemplatesとしています。

Obsidian_Core-plugins_Templates設定

ショートカットキーの設定とテンプレートの挿入(Options / Hotkeys)

以下で挿入します。

command + p > Templates: insert template > 挿入したい作成したテンプレートを選択する

これで作成したテンプレートを選択することでノートに挿入することができます。

追加情報として、私は検索が操作が手間だと感じたため、Templates: insert templateを呼び出せるように、hotkeyを設定して、すぐに選択できるようにしました。

Settings > Options > Hotkeys

Templates: insert templateで検索し右側の+ボタンで、割り当てたいキーを入力して設定します。

割り当ては自由ですが、下記例では、option + iとしています。

Obsidian_Options_Hotkeys_Template設定

新規ノート作成時にテンプレート呼び出し可能なプラグインである Auto Template Trigger の設定

他にもファイル作成時にテンプレートを選択することも可能です。

Community pluginである、Auto Template Triggerを使用します。

Community plagins > Brows > Auto Template Trigger

注意点として、事前に上記記載のtemplate folder locationを設定する必要があるので未設定の場合は設定が必要です。

これで新規ノート作成時にTemplates: insert templateを起動してくれます。

まとめ

本記事ではObsidianのテンプレート機能について以下内容について記載しました。

  • テンプレートの設定(Core plagins / Templates)
  • ショートカットキーの設定とテンプレートの挿入(Options / Hotkeys)
  • 新規ノート作成時にテンプレート呼び出し可能なプラグインである Auto Template Trigger の設定

また便利な機能があれば記事で紹介したいと思います。

最後に、記事が参考になれば、是非「はてなスター」もお願いします!

以上です。

2023年振り返り

2023年を振り返ると

今年は何をしただろうと振り返ると、ChatGPTを活用することでよりコードを書くことが増えた一年だったかなという印象でした。

関連してブログ記事も作成したコード関連の記事投稿が多かったかなと思います。

他にもSSGであるMaterial for MkDocsを使用して技術系のまとめサイト作成しました。こちらは全然アクセスはないですが、備忘録として自分がわかれば良いと思っているので、悲観的ではありません。また、サイトは将来的には他のSSGに移行する可能性はありますが、今はMkDocsで満足しています。

7rikazhexde.github.io

ブログに関しては月1本以上の記事を書こうと決めてから継続しています。今年はGA4を設定したのですが、環境構築系の記事へのアクセスが多い印象でした。一方で作成したプロジェクトに関する記事へのアクセスは少ないので残念な気持ちがあります。(それ程記事があるわけではなく、アクセスもゼロではないですが。)

作成したコード(GitHub)では主にPythonですが、pre-commit、GitHub Actionなど、CI/CD環境を作成して運用することも試しました。また、issueの登録、プルリクエスト、リリースなど基本的な操作も実際に使って確認しました。他にもdockerやクラウド(AWS)もアカウント作成して試しました。

まだまだやりたいことだったり、身につけたいスキルはあります。とりあえず触って作って使ってみることを意識していましたが、今後もこの意識は変えずに取り組んでいこうと思います。

仕事の話について

仕事は組み込み系がメインで要求分析からシステム評価が主業務ですが、本業とは別にAI,クラウド関連の業務をやったり、忙しい中でもやりたいことはやったかなという1年でした。

その他、外部の技術系コンサル関連の研修に参加して、要求から設計までのスキル強化ができたと感じでいます。

研修ではアーキテクトの育成強化、つまり設計力強化が目的で、ベテラン社員に成果物をレビューして、フィードバックを受けて、成果物を提出するというプロセスがありました。成果物では担当プロジェクトに関して、要求分析、目的、設計方針、モデル化(静的/動的構造)、目的に対する考察、という流れでした。対象プロジェクトに依存しますが、基本的にはアーキテクチャ変更とリファクタリングになります。12月末時点では成果物は提出済みであり、認定結果待ちですが、無事に認定されれば良いなと思ってます。

また、本業は組み込みと言いましたが、弊社にも当てはまる話として、23年末時点でダイハツの不正が大きな問題になってますが、弊社もリストラ、開発期間短縮、同時開発など、一部共通する部分もあり、トラブルが多発した状況がありました。ダイハツのアンケート調査結果を見ると、既視感を感じることがありました。(ダイハツより風通しは良い気はしますが、そんなに商品作る意味あるのか?と疑問に思うことはありました。)

弊社ではトラブルに関して、上層部が問題を分析して、企画書や販売後のフィードバック、営業とのコミュニケーション、売上比率は低い商品の開発停止、開発期間を遅らせる、外部評価機関に評価依頼、UTの強化など、対策が取られることになりました。

弊社は車ほど人命に関わる物ではないとは言え、強引に進めること(そうせざる得ない状況ではあった)は、個人的には良い方向に行くことはないと思います。真意はわかりませんが、トヨタも言わせない雰囲気があり、ダイハツも言えない雰囲気を作ってしまったのかなと。プロセスは成功するとそれが標準になりますが、標準にすることに対する議論が足りなかったのでは?体制に大いに問題があったのかなと思います。時代に合わないプロセスとかたくさんあったのかなとも。

第三者委員会による調査結果および今後の対応について|ニュースリリース|ダイハツ工業株式会社 企業情報サイト

第三者委員会 調査報告書

個人的な話

少し話が変わりますが、仕事でそんな状況が続く中で、私は4月以降、耳の調子が悪くなり、夜寝れない状況にありました。体調の波はありますが、現在も錠剤を飲んで過ごしています。一時調子が良くなったときもありましたが、仕事のストレスも一因と考えており、通院、薬を飲みながら様子を見ています。(早く回復したいところです。)

一方、来年で今の業界で10年目という節目もあり、転職も意識しています。個人的に興味関心がある企業についてはイベントに参加して調べていますが、転職サイト(エンジニアHub、Findy)を登録して調べてもいます。(エンジニアHubはサービス終了するようなので他のサービスを検討しようと思ってます。)

どうも体の調子がパッとしない部分があるので、どこか踏み込めない部分はありますが、一歩踏み出さなければ何も進まないので、来年は具体的にアクションを起こしたいと考えています。

25年に向けて

まずは健康でありたい。次にスキル獲得。スキルについては、特にワークフロー、クラウド、データ分析を計画的に学習したいなという思いがあります。あとはRustにすごく興味を持っているので、学習して何か作ってみたいなと考えています。(まずはRust本を読む。)

また、情報として、Findyのサービスである2023年末時点のGitHubのコントリビューションの集計結果と偏差値を載せておきます。コントリビューションは多からず、少なからずという感じでした。基本土日メインなのでこの程度かなという感じです。偏差値は60が壁と聞くので、Pythonはあと少しですが、60を目指したいと思います。(何をしたら数値が上がるのかはわかっていないのですが)

Findy_GitHub_2023年_年間コントリビューション

Findy_GitHub_2023年_スキル偏差値

会社ではAzure OpenAI ServiceでGPTを使えるようになり、udemy bussinessも契約されたので、積極的に活用していきスキル強化に繋げたいと思いますし、資格も取りたいと考えています。(直近ではG検定止まりです。)

あと、個人でやったことを振り返ることとして、月次の投稿もしていきないなと考えています。 下記のX(Twitter)で投稿を見ていただくと分かると思いますが、その月で「何をやったかをまとめてなくて結局書けなかった。」ということがあったの、気軽に日記を書くことを目的にしたShortcutsを使って月次の投稿もしていきます。Shortcutsは公開する予定ですので、気になれば使ってもらえると嬉しいです。(別途ブログで公開予定です。)

色々やりたいことがあります。どれも中途半端にならないように注意して、24年は仕事とプライベートのバランスを取りながら、健康にも注意して過ごせるようにしていきたいと思います。

まとまりのない文章になってしまった気もしますが、内容は以上となります。
最後まで読んでいただきありがとうございました。

既存のPoetry環境をベースにしたDocker環境の構築方法について

はじめに

Docker上でPoetryの依存ファイルを使用した環境を構築したいと思い調査しました。
本記事はその手順の備忘録となります。

使用するプロジェクト

以下のプロジェクトを例に説明します。 詳細は割愛しますが、pythonでdashフレームワークを使用したwebアプリのプロジェクトになります。現状はpoetryコマンドで実行環境を構築できるようにしていますが、これをdocker環境でも構築できるようにします。

github.com

方針

作業ディレクトリにプロジェクトと同じフォルダ(dlSubscanStakingRewardsHistoryDash)を構築します。
そして、Docker環境ではアプリケーションの実行で必要となる、後述するスースコード類(パッケージ管理ファイルも含む)が格納されたフォルダ、および、ファイルをコピーして同期することにします。

フォルダ構成

ソースコードapp,ci,testフォルダに格納されています。
メインのプログラムはappフォルダ内のコードで、プロジェクト以下でpoetry run python appを実行することでDashフレームワークのWebアプリが起動します。

# 以下は一部記載を省略しています。
% tree -a -L 2
.
├── .DS_Store
├── .demofile
├── .git
├── .gitignore
├── .markdownlint.jsonc
├── .mypy_cache
├── .pre-commit-config.yaml
├── .ruff_cache
├── .venv
├── .vscode
├── Dockerfile
├── LICENSE
├── README.md
├── app
│   ├── __init__.py
│   ├── __main__.py
│   ├── __pycache__
│   ├── assets
│   ├── config.toml
│   ├── config_manage.py
│   ├── cryptact.py
│   ├── dcc_manage.py
│   ├── df_manage.py
│   └── subscan.py
├── ci
│   ├── run_git_tag_base_pyproject.py
│   └── update_pyproject_version.py
├── docker-compose.yaml
├── poetry.lock
├── pyproject.toml
├── requirements-dev.txt
├── requirements.txt
├── scripts
│   └── create_post-commit.sh
└── tests
    ├── __init__.py
    └── test_cryptact.py

続けて方針に従いDockerfiledocker-compose.yamlを作成します。

Dockerfile

# ベースとなるDockerイメージを指定
FROM python:3.10

# 作業ディレクトリを設定
WORKDIR /

# APTパッケージインストール / パッケージアーカイブのキャッシュ削除 / パッケージリストのキャッシュ削除
# 日本語のロケールを指定
RUN apt-get update && \
    apt-get -y --no-install-recommends install locales && \
    localedef -f UTF-8 -i ja_JP ja_JP.UTF-8 && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
ENV TZ JST-9

# ターミナルエミュレーターにxtermを指定する
ENV TERM xterm

# Poetryのインストール
## https://python-poetry.org/docs/#installing-with-the-official-installer
### Linux, macOS, Windows (WSL)
RUN curl -sSL https://install.python-poetry.org | python3 -

# Poetryのパスをunix指定で設定
## https://python-poetry.org/docs/#installing-with-the-official-installer
### Add Poetry to your PATH
ENV PATH /root/.local/bin:$PATH

# Poetryが仮想環境を生成しないようにする
RUN poetry config virtualenvs.create false

# 作業ディレクトリを/dlSubscanStakingRewardsHistoryDashに設定
WORKDIR /dlSubscanStakingRewardsHistoryDash

# 依存関係のコピー
COPY pyproject.toml poetry.lock ./

# 依存関係のインストール
RUN poetry install

# アプリケーションのコピー
COPY ./app ./app
COPY ./tests ./tests
COPY ./ci ./ci
COPY README.md .

補足: Dockerfile用のlinterについて

pre-commitではpre-commit hookとして以下のDockerfile linterが公開されています。
Dockerfileの構文や指定について指摘されるため、pre-commitを利用している場合は下記指定で使用できます。 実際に、Dockerfileはフックの結果を元に作成しています。個人的には有用だと感じました。

.pre-commit-config.yaml

  # https://github.com/pryorda/dockerfilelint-precommit-hooks#usage
  - repo: https://github.com/pryorda/dockerfilelint-precommit-hooks
    rev: v0.1.0
    hooks:
      - id: dockerfilelint
        stages: [commit]

docker-compose.yaml

# Docker Composeのバージョン指定
version: '3'
services:
  # アプリケーションサービスの設定
  app:
    # カレントディレクトリをベースにビルド
    build: .
    # コンテナの名前を指定
    container_name: 'dlssrhd'
    # ターミナルの割り当てを有効にする
    tty: true
    # ボリュームのマウント設定
    volumes:
      - ./app:/dlSubscanStakingRewardsHistoryDash/app
      - ./tests:/dlSubscanStakingRewardsHistoryDash/tests
      - ./ci:/dlSubscanStakingRewardsHistoryDash/ci
      - ./pyproject.toml:/dlSubscanStakingRewardsHistoryDash/pyproject.toml
      - ./poetry.lock:/dlSubscanStakingRewardsHistoryDash/poetry.lock
      - ./README.md:/dlSubscanStakingRewardsHistoryDash/README.md
    # ポートのマッピング
    ports:
      - 8050:8050
    # アプリケーションの起動コマンド実行
    command: ["poetry", "run", "python", "app"]

補足: docker compose ファイルが有効かどうかをチェックするpre-commit

pre-commitではpre-commit hookとして以下のdocker-pre-commitが公開されています。
docker-compose configコマンドを使用して、作成したdocker-compose.yamlについて環境変数の評価や、ファイルのインクルードなど、Composeファイルが正しく構成されているかどうかを確認するとができます。pre-commitを利用している場合は下記指定で使用できます。 実際に、docker-compose.yamlに適用し、指摘はありませんでしたが、docker-compose configをpre-commitで実行できるので有用だと思います。

.pre-commit-config.yaml

  # https://github.com/IamTheFij/docker-pre-commit#installation
  - repo: https://github.com/iamthefij/docker-pre-commit
    rev: v3.0.1
    hooks:
      - id: docker-compose-check

Docker環境の構築

docker-compose upappサービスのdlssrhdコンテナを起動する

処理の流れ

  1. docker-compose upコマンド実行:

    • docker-compose upコマンドを実行すると、Docker Composeは指定されたdocker-compose.yamlを読み込みます。
  2. ベースとなるDockerイメージのダウンロード:

    • python:3.10というベースイメージがなければ、このイメージをDocker Hubからダウンロードします。
  3. Dockerfileのビルド:

    • ダウンロードしたベースイメージを元に、指定されたDockerfileがビルドされます。
    • ビルドの際には、各命令が順番に実行されます。
  4. 作業ディレクトリとロケールの設定:

  5. Poetryのインストール:

  6. Poetryのパスの設定:

    • インストールしたPoetryのパスを環境変数に追加します。
  7. Poetryの仮想環境生成設定:

    • Poetryが仮想環境を生成しないように設定します。
  8. 作業ディレクトリの変更:

    • 以降の作業は、/dlSubscanStakingRewardsHistoryDashディレクトリで行います。
  9. 依存関係のコピーとインストール:

    • pyproject.tomlpoetry.lockがコピーされ、Poetryを使用して依存関係がインストールされます。
  10. アプリケーションのコピー:

    • ./app./tests./ciREADME.mdがコピーされます。
  11. ポートのバインドとコンテナの起動:

    • docker-compose.yamlで指定されたポート8050がホストマシンのポート8050にバインドされ、dlssrhdという名前のコンテナが起動されます。
  12. Pseudo-TTYの割り当て:

    • tty: trueが指定されているため、コンテナ内で対話的なシェルを使用できるようになります。
  13. docker-compose.yamlのcommandの指定:

    • docker-compose.yamlcommand: ["poetry", "run", "python", "app"]の指定からデフォルトのコンテナ起動時のコマンドとして使用されます。

これにより、docker-compose upコマンドによって、指定されたサービス(appサービス)に基づいたコンテナが構築、起動され、アプリケーションが実行されます。

補足:CMDcommandの使い分け

プロジェクトの運用方針にもよりますが、CMDcommandの両方を使用する場合はdocker-compose.yamlcommandが優先されるようなので、個人的にはcommandでコマンド実行するのが良いと思います。

参考記事

qiita.com

  1. CMDのみを使用する場合:

    • CMD ["poetry", "run", "python", "app"]
      • コンテナが実行されるときに、何もコマンドが指定されなかった場合はCMDで指定されたコマンドが実行されます。
  2. commandのみを使用する場合:

    • command: ["poetry", "run", "python", "app"]
      • docker-compose.yamlcommandでコンテナの起動時のコマンドを上書きします。
      • CMDにコマンドの指定がある場合でも、docker-compose.yamlcommandで指定したコマンドが優先されます。
  3. CMDとcommandの両方を使用する場合:

    • CMD ["poetry", "run", "python", "app"]
    • command: ["poetry", "run", "python", "app"]
      • この場合、docker-compose.yamlcommandが優先されます。

補足:コンテナの起動方法

参考記事

qiita.com

コンテナ一覧を表示

% docker ps -a                
CONTAINER ID   IMAGE                                    COMMAND                   CREATED       STATUS                      PORTS                    NAMES
5c41a6c6a8ca   dlsubscanstakingrewardshistorydash-app   "poetry run python a…"   5 hours ago   Up 22 seconds               0.0.0.0:8050->8050/tcp   dlssrhd

単一コンテナ起動: docker start "CONTAINER ID"

 % docker start 5c41a6c6a8ca           

5c41a6c6a8ca

複数コンテナ(アプリケーション)の起動: docker compose up

appサービスのdlssrhdコンテナを起動する

% docker compose up
[+] Building 0.0s (0/0)                                                                                        docker:desktop-linux
[+] Running 1/0
 ✔ Container dlssrhd  Created                                                                                                  0.0s 
Attaching to dlssrhd
dlssrhd  | Skipping virtualenv creation, as specified in config file.
dlssrhd  | Dash is running on http://0.0.0.0:8050/
dlssrhd  | 
dlssrhd  |  * Serving Flask app '__main__'
dlssrhd  |  * Debug mode: on

# Ctrl+Cで停止
^CGracefully stopping... (press Ctrl+C again to force)
Aborting on container exit...
[+] Stopping 1/1
 ✔ Container dlssrhd  Stopped                                                                                                  0.3s 
canceled

# -d(デタッチドモード) でバックグラウンドでサービスを実行
% docker compose up -d     
[+] Building 0.0s (0/0)                                                                                        docker:desktop-linux
[+] Running 1/1
 ✔ Container dlssrhd  Started 

まとめ

実際のプロジェクトを例にPoetryを使用したDocker環境の構築方法について紹介しました。

環境構築について、プロジェクトではフォルダ構成を維持して、全てのファイルをコピーせず、必要なファイルをコピーしたかったので、実際に作成することで処理の流れを理解することができました。

Docker環境のインストールは必要ですが、実際にMacWindows(WSL)でgitクローンしてdocker-compose upコマンドを実行してwebアプリを起動できることを確認できました。実際に動かしてみることもできますので参考になるかと思います。

今後や他のプログラミング言語やDBと組み合わせたサービスについても、調査して作成してみたいと思います。

以上です。

「Warning: poetry-plugin-export will not be installed by default in a future version of Poetry.」の対応について

要約

  • pre-commitのpoetry-export hookで警告が表示された
  • poetry-plugin-exportをインストールする
  • poetry self show pluginsでインストール内容を確認し、 poetry config warnings.export falseで警告表示を無効にする

現象

pre-commitでpoetry-export hookを使用しているのですが、v1.7.1に変更し、poetry run pre-commit run --all-filesを実行したところ、以下の警告が表示されました。

Warning: poetry-plugin-export will not be installed by default in a future version of Poetry. In order to avoid a breaking change and make your automation forward-compatible, please install poetry-plugin-export explicitly. See https://python-poetry.org/docs/plugins/#using-plugins for details on how to install a plugin. To disable this warning run 'poetry config warnings.export false'.

公式ドキュメントにも同様の警告内容が記載されていました。

python-poetry.org

実行環境

.pre-commit-config.yaml(poetry部分抜粋)

  # https://python-poetry.org/docs/pre-commit-hooks/#usage
  - repo: https://github.com/python-poetry/poetry
    # Cannot be executed with local designation (as of 23.11.25)
    rev: 1.7.1
    hooks:
      - id: poetry-check
        verbose: true
      - id: poetry-lock
        verbose: true
      - id: poetry-export
        args: ["-f", "requirements.txt", "-o", "requirements.txt"]
        verbose: true
        files: ^pyproject\.toml$
      - id: poetry-export
        args: ["--dev", "-f", "requirements.txt", "-o", "requirements-dev.txt"]
        verbose: true
        files: ^pyproject\.toml$

解決方法

警告メッセージの記載通りですが、将来のPoetryのバージョンでは、poetry-plugin-exportはデフォルトではインストールされないようです。したがって、自動化が前方互換性を持つように、poetry-plugin-exportを明示的にインストールすることが推奨されます。そこで、公式のインストール手順を確認し、poetry-plugin-exportをインストールします。

github.com

poetry self add poetry-plugin-export

Using version ^1.6.0 for poetry-plugin-export

Updating dependencies
Resolving dependencies... (0.2s)

No dependencies to install or update

Writing lock file

念の為以下のコマンドでインストールされたプラグインを確認します。

poetry self show plugins                   

  • poetry-plugin-export (1.6.0) Poetry plugin to export the dependencies to various formats
      1 application plugin

      Dependencies
        - poetry (>=1.6.0,<2.0.0)
        - poetry-core (>=1.7.0,<2.0.0)

動作確認

poetry run pre-commit run --all-filesによる確認

poetry run pre-commit run --all-files
# 省略

poetry-export............................................................Passed
- hook id: poetry-export
- duration: 0.69s

Warning: poetry-plugin-export will not be installed by default in a future version of Poetry.
In order to avoid a breaking change and make your automation forward-compatible, please install poetry-plugin-export explicitly. See https://python-poetry.org/docs/plugins/#using-plugins for details on how to install a plugin.
To disable this warning run 'poetry config warnings.export false'.

poetry-export............................................................Passed
- hook id: poetry-export
- duration: 0.7s

Warning: poetry-plugin-export will not be installed by default in a future version of Poetry.
In order to avoid a breaking change and make your automation forward-compatible, please install poetry-plugin-export explicitly. See https://python-poetry.org/docs/plugins/#using-plugins for details on how to install a plugin.
To disable this warning run 'poetry config warnings.export false'.
The `--dev` option is deprecated, use the `--with dev` notation instead.

poetry exportによる確認

poetry export -f requirements.txt --output requirements.txt
Warning: poetry-plugin-export will not be installed by default in a future version of Poetry.
In order to avoid a breaking change and make your automation forward-compatible, please install poetry-plugin-export explicitly. See https://python-poetry.org/docs/plugins/#using-plugins for details on how to install a plugin.
To disable this warning run 'poetry config warnings.export false'.

コマンドの実行結果から、poetry exportコマンドを実行しても警告メッセージは表示され続けます。プラグインはインストールされたことは確認しているので、poetry config warnings.export falseで警告表示を無効にします。

poetry config warnings.export false

警告メッセージ表示を無効にしているので、正しく設定できているが不安になりますが、これで警告表示は消えて引き続きpoetry exportフックが使用できるはずです。

以上です。

【AWS】API Gateway + Lambda + DynamoDB構成でGETリクエストで DBのデータ(json)を取得して、 DataFrameを作成する

前書き

これまでは私はクラウド(AWS)と通信するデバイス側の開発(組込みデバイス、デスクトップアプリ)が中心でした。I/Fの仕様が決まれば通信はできますが、サービスを作る上でクラウド側の知識がないとエンジニアとして面白みがないなと感じることが増えてきました。これは現業が類似した業務の繰り返しでエンジニアとしてこのままで良いのかという危機感的な部分もありますが、スキルを増やしたいというモチベーションが強いです。

個人的な経験からクラウドの運用にはコストはかかりますが、アイデアを具現化することに関して、短期的に拡張性を考慮して実現することに利点があると考えています。何だかんだ見栄えも良いです。また、その中心はクラウドという印象です。いくらデバイスが良くても、データを取得、分析、解析までできなければ、使えるサービスにはなりません。各工程のスキルを身に付けることは簡単なことではありませんが、作りたいものの選択肢は拡がると思います。

一方で、ちょうど業務でAWSのサービスを使うことになり、良い機会なので、プライベートでもアカウントも作成して触りながら知識を深めていこうと思い、コードを書いてAWSのサービスを使ってみることにしました。

前置きが長くなりましたが、本記事はクラウドを触ってみた記事であり、AWSのサービスとして、API Gateway, Lambda, DynamoDBを使用した記事になります。

前提条件

  • AWSアカウント(ルートユーザー)を作成済みであること

ソースコード

ソースコードGitHubにコミットしています。

github.com

IAMユーザー作成

ルートユーザーでログインし、「IAMユーザーを作成する 」を指定して作成します。

ステップ 1 ユーザーの詳細を指定

  • ユーザー名:[割愛]
  • AWS マネジメントコンソールへのユーザーアクセスを提供する - オプション:チェック
    • IAMユーザーを作成します:選択
    • コンソールパスワード
      • 自動生成されたパスワード
    • ユーザーは次回のサインイン時に新しいパスワードを作成する必要があります - 推奨:チェック

ユーザーは次回のサインイン時に新しいパスワードを作成する必要があります」という項目については、チェックをつけます。 自動作成だと文字数が少ないため、ログイン時に変更した方が良いと思いました。
また、作成後は参照できませんが、作成直後はコピー、csv保存が可能です。

補足: IAMユーザー作成時の選択肢

chatgptより引用(2023/11/05時点)

AWSのIAMユーザー作成時には、以下の2つの選択肢があります。

  1. Identity Centerでユーザーを指定する - Identity Centerでは、AWSアカウントおよびクラウドアプリケーションへのユーザーアクセスを一元管理できます。これは推奨される方法です。
  2. IAMユーザーを作成する - アクセスキー、AWS CodeCommit または Amazon Keyspaces のサービス固有の認証情報、または緊急アカウントアクセス用のバックアップ認証情報を使用してプログラムによるアクセスを有効にする必要がある場合のみ、IAMユーザーの作成が推奨されます。

一般的には、Identity Centerでユーザーを指定することが推奨されています。これにより、AWSアカウントおよびクラウドアプリケーションへのユーザーアクセスを一元管理できます。ただし、プログラムによるアクセスを有効にする必要がある場合は、IAMユーザーの作成を選択することもあります。どちらの選択肢を選ぶかは要件によります。

また、「Identity Centerでユーザーを指定する」場合は、AWS Organizationsを有効化する必要があります。AWS Organizationsは、複数のAWSアカウントを一元管理するためのサービスです。これにより、単一の支払い者と一元化されたコスト追跡が可能になり、他のAWSアカウントを作成して招待したり、ポリシーベースのコントロールを適用したりすることができます。

今回は個人利用で複数のAWSアカウントを管理する必要がないため、「IAMユーザーを作成します」で作成しました。

ステップ 2 許可を設定

  • 許可のオプション:ポリシーを直接アタッチする(AdministratorAccessを指定)

ステップ 3 確認して作成

ユーザーの詳細、許可の概要、タグ(オプション)を確認し、問題がなければ、ユーザーの作成を押下する。
タグ(オプション)は必要に応じて設定する。

ステップ 4 パスワードを取得

パスワード情報をコピー、csv保存し、完了

参考記事

IAMユーザーのアクセスキー作成

AWSの各サービスを利用するためにはアクセスキーが必要になります。アカウント作成時はアクセスキーを自動で作成する選択肢もあったかと思いますが、基本的にはIAMユーザー作成後にアクセスキーを作成します。以下の指定で作成します。

IAMユーザー > セキュリティ認証情報 > アクセスキーを作成 > ユーザーケース選択(※) > 次へ

AWS CLI V2で認証情報を設定、コードで参照する方式のため、コマンドラインインターフェース(CLI)を選択しました。

DynamoDB

テーブルの作成

以下で作成します。その他はデフォルトです。

  • テーブル名:TestJsonTable1
  • パーテーションキー:id
  • ソートキー:date

補足:予約語について

ソートキーで指定するdate予約語です。

DynamoDB の予約語 - Amazon DynamoDB

もし、AWSCLIで取得する場合は#をつけて実行する必要があるようです。
今回作成するLambda関数(Python)ではqueryメソッドを使用しますが、書式は変更しなくても取得出来ました。

DynamoDB の式の属性名 - Amazon DynamoDB

データの追加

pythonコードでjsonファイルを読み込み、テーブルに追加します。 エラーにならなければ"Data written to table successfully."が表示されます。

追加したデータはテーブル > 名前 > 項目の検索から確認できます。
例えば、クエリ、id:camera2date:次の値/2023-04-01および2023-04-2で実行すれば条件に応じたデータを表示できます。

テストデータ(test_data.json)を作成するコード

注意点
  • テストデータは正確ではありません。あくまでサンプルです。
  • データとしては特定のカメラで検出したPoseNetの骨格点情報を持つ日時データ(json)を想定しています。本来は検出時間間隔は短いのですが、サンプルのため30分間隔にしています。
  • skeletal_pointsは都合により検出時間で共通としています。
create_json_file.py
import json
import random
from datetime import datetime, timedelta

# 初期データ
skeletal_points = '[{"key_point": "2", "key_points": [{"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}]}, {"key_point": "3", "key_points": [{"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}]}]'
start_time = datetime(2023, 4, 1)
end_time = datetime(2023, 4, 5)
time_step = timedelta(minutes=30)

# 結果を格納するリスト
results = []

# 指定された時間範囲でループ
while start_time <= end_time:
    result = {
        "detected_date_time": start_time.strftime("%Y-%m-%dT%H:%M:%S.000"),
        "date": start_time.strftime("%Y-%m-%dT%H:%M:%S.000"),
        "detected_status": random.choice(["fallen", "normal"]),
        "id": random.choice(["camera1", "camera2"]),
        "skeletal_points": skeletal_points,
        "num_of_people": str(random.randint(0, 5)),
    }
    results.append(result)
    start_time += time_step

# JSONファイルに保存

with open("./incert_files/test_data.json", "w") as f:
    json.dump({"result": results}, f, indent=2)

test_data.jsonを書き込むコード

incert_data_json.py
import json
import boto3

# DynamoDBオブジェクトを取得
dynamodb = boto3.resource(
    "dynamodb",
    endpoint_url="https://dynamodb.ap-northeast-1.amazonaws.com",  # DynamoDBのエンドポイントURL
)

# テーブル名を定義
table_name = "TestJsonTable1"

# テーブルオブジェクトを取得
table = dynamodb.Table(table_name)

file_name = "./incert_files/test_data.json"

# JSONファイルからデータを読み込む
with open(file_name, "r") as f:
    data = json.load(f)

# データをテーブルに書き込む
for item in data["result"]:
    table.put_item(Item=item)

print("Data written to table successfully.")

API Gateway

GETメソッド 経由でLambda関数を実行するため、API GatewayAPIを作成します。

API作成

REST API

  • 新しいAPI
  • API名:TestJsonTable1_API1
  • APIエンドポイント:リージョン

メソッドを作成

  • メソッドタイプ: GET
  • 統合タイプ:Lambda 関数
  • Lambdaプロキシ:オフ
  • Lambda関数:後述するLambda関数のARNを指定

メソッドリクエストの設定

URL クエリ文字列パラメータ

メソッドリクエストを編集 > URL クエリ文字列パラメータ

  • id:必須(True)
  • start_date:必須(False)
  • end_date:必須(False)

統合リクエストの設定

マッピングテンプレート

{
  "id": "$input.params('id')",
  "start_date": "$input.params('start_date')",
  "end_date": "$input.params('end_date')"
}
マッピングテンプレートを設定する理由

URLクエリのみ設定すると以下のエラーになりました。

{'errorMessage': "'id'", 'errorType': 'KeyError', 'requestId': '[割愛]', 'stackTrace': ['  File "/var/task/lambda_function.py", line 17, in lambda_handler\n    id = event[\'id\']\n']}

chatgptで確認(2023/11/05時点)するとGETリクエストで指定したパラメータはLambda関数ではイベントオブジェクトでは参照できないようです。

これはエラーメッセージ'errorMessage': "'id'", 'errorType': 'KeyError'は、Pythonの辞書(この場合はevent)から存在しないキー(この場合は'id')を取得したことによるエラーです。

API Gateway経由でLambda関数を呼び出すとき、API GatewayはHTTPリクエストを特定の形式のイベントオブジェクトに変換します。このイベントオブジェクトは、Lambda関数のeventパラメータとして渡されます。

しかし、このイベントオブジェクトは、直接Lambda関数をテストするときに使用するイベントオブジェクトとは形式が異なる場合があります。そのため、Lambda関数がevent['id']を期待している場合でも、API Gatewayから渡されるイベントオブジェクトには'id'キーが含まれていない可能性があります。

この問題を解決するためには、API Gatewayの統合リクエストのマッピングテンプレートを設定して、HTTPリクエストから適切な形式のイベントオブジェクトを作成する必要があります。具体的には、マッピングテンプレートでHTTPリクエストのクエリパラメータ(この場合はid、start_date、end_date)をイベントオブジェクトの対応するキーにマッピングします。

これにより、Lambda関数はAPI Gatewayから期待する形式のイベントオブジェクトを受け取り、'id'キーを正しく取得できるようになります。

Lambda

GETリクエストのパラメータを元にDynamoDBから取得するクエリを設定、実行するLambda関数を作成します。

関数の作成

アーキテクチャではx86_64arm64を指定できますが、デフォルトで選択されていたx86_64を指定しました。
下記記事を見る限りは、処理速度、コスト面でarm64を選択するのが良さそうです。

参考記事

Lambdaのポリシー変更(追加)

IAM > アクセス管理 > ロール > Lambdaのロール名
dynamodbにアクセスするため、AmazonDynamoDBFullAccessを追加する
デフォルトではCloudWatchのログ出力するAWSLambdaBasicExecutionRoleが設定されている。

レイヤーの追加

pandasを使用するためPython 3.11版のarnを指定して追加します。

参考記事: [AWS]ARNとは?

pandasのarn情報

arnとして以下を指定します。

arn:aws:lambda:ap-northeast-1:336392948345:layer:AWSSDKPandas-Python311:2

参考情報: AWS Lambda Managed Layers — AWS SDK for pandas 3.4.2 documentation

Lambda関数作成

関数 > 関数名 > コード

import boto3
import pandas as pd
from boto3.dynamodb.conditions import Key

def lambda_handler(event, context):
    dynamodb = boto3.resource(
        "dynamodb",
        region_name="ap-northeast-1",  # 東京リージョン
        endpoint_url="https://dynamodb.ap-northeast-1.amazonaws.com",  # DynamoDBのエンドポイントURL
    )
    table = dynamodb.Table('TestJsonTable1')

    # print文を入れるとCloudWatchにログ出力できる
    # print(event) 

    id = event['id']
    start_date = event.get('start_date')
    end_date = event.get('end_date')

    if start_date and end_date:
        response = table.query(
            KeyConditionExpression=Key('id').eq(id) & Key('date').between(start_date, end_date)
        )
    else:
        response = table.query(
            KeyConditionExpression=Key('id').eq(id)
        )

    # 'result'キーでラップして返す
    return {"result": response['Items']}

タイムアウト時間の設定

実行結果次第でタイムアウト時間を伸ばす場合は以下で変更します。
関数 > 関数名 > 設定 > 一般設定 > 編集 > タイムアウト(変更) > 保存
3秒から30秒に変更しました。

テスト

Lambda関数が期待通り動作するかテストデータを使用して動作確認します。
ログから期待通り出力できていればOKです。

イベントJSON

{
  "id": "camera1",
  "start_date": "2023-04-01T00:00:00.000",
  "end_date": "2023-04-05T00:00:00.000"
}

実行結果

{
  "result": [
    {
      "detected_date_time": "2023-04-01T00:00:00.000",
      "date": "2023-04-01T00:00:00.000",
      "detected_status": "normal",
      "id": "camera1",
      "skeletal_points": "[{\"key_point\": \"2\", \"key_points\": [{\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}]}, {\"key_point\": \"3\", \"key_points\": [{\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}]}]",
      "num_of_people": "0"
    },
    ...
    {
      "detected_date_time": "2023-04-05T00:00:00.000",
      "date": "2023-04-05T00:00:00.000",
      "detected_status": "fallen",
      "id": "camera1",
      "skeletal_points": "[{\"key_point\": \"2\", \"key_points\": [{\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}]}, {\"key_point\": \"3\", \"key_points\": [{\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}]}]",
      "num_of_people": "0"
    }
  ]
}

リクエスト関数

ここまでで、DynamoDB,API Gateway, Lambda関数を作成し、設定することができたのでローカル環境からデータを取得できるか確認します。

動作確認用にrequestモジュールを使用してGETリクエストを送信するコードを作成します。受信したjsonデータはpandas / dataframeに変換して保存します。

事前準備

  • ローカルからAWSにアクセスするため、AWS認証情報を環境変数に設定します。詳細はAWSCLIを参照してください。

  • API GatewayではIAM認証を設定しているため、requests-aws4authをインストールしてください。AWS SigV4 による署名付きリクエストを送信できるようにします。

参考記事

request_api.py
import requests
from requests_aws4auth import AWS4Auth
from typing import Optional
import pandas as pd
import boto3

# AWS認証情報取得
session = boto3.Session()
credentials = session.get_credentials()
aws_access_key_id = credentials.access_key
aws_secret_access_key = credentials.secret_key
region_name = session.region_name
# 「API > ステージ > URLを呼び出す 」より参照
api_endpoint = "ステージ込みのエンドポイントを指定する"

# AWS4Authオブジェクトを作成
auth = AWS4Auth(aws_access_key_id, aws_secret_access_key, region_name, "execute-api")

def get_req(
    id: str,
    columns: list,
    start_date: Optional[str] = None,
    end_date: Optional[str] = None,
):
    # リクエストを作成
    url = f"{api_endpoint}?id={id}"
    if start_date is not None:
        url += f"&start_date={start_date}"
    if end_date is not None:
        url += f"&end_date={end_date}"
    response = requests.get(url, auth=auth)

    # レスポンスを表示
    data = response.json()

    new_data = [[item[column] for column in columns] for item in data["result"]]

    # new_dataは上記で作成したリスト
    df = pd.DataFrame(new_data, columns=columns)
    return df


if __name__ == "__main__":
    columns = ["id", "date", "detected_status", "num_of_people","skeletal_points"]
    df = get_req("camera1", columns, "2023-04-01", "2023-04-02")
    print(df)
    #df = get_req("camera1", columns)

実行結果

指定範囲(日付)とcolumnsのリストに対応したDataframeオブジェクトを作成できています。

         id                 date detected_status num_of_people                                    skeletal_points
0   camera1  2023-04-01T00:00:00.000          normal             0  [{"key_point": "2", "key_points": [{"prob": "8...
1   camera1  2023-04-01T01:30:00.000          fallen             1  [{"key_point": "2", "key_points": [{"prob": "8...
2   camera1  2023-04-01T02:00:00.000          fallen             2  [{"key_point": "2", "key_points": [{"prob": "8...
3   camera1  2023-04-01T04:00:00.000          fallen             0  [{"key_point": "2", "key_points": [{"prob": "8...
4   camera1  2023-04-01T05:00:00.000          normal             4  [{"key_point": "2", "key_points": [{"prob": "8...
5   camera1  2023-04-01T06:30:00.000          fallen             0  [{"key_point": "2", "key_points": [{"prob": "8...
6   camera1  2023-04-01T08:00:00.000          fallen             0  [{"key_point": "2", "key_points": [{"prob": "8...
7   camera1  2023-04-01T09:30:00.000          fallen             5  [{"key_point": "2", "key_points": [{"prob": "8...
8   camera1  2023-04-01T10:00:00.000          normal             2  [{"key_point": "2", "key_points": [{"prob": "8...
9   camera1  2023-04-01T10:30:00.000          fallen             2  [{"key_point": "2", "key_points": [{"prob": "8...
10  camera1  2023-04-01T11:00:00.000          fallen             3  [{"key_point": "2", "key_points": [{"prob": "8...
11  camera1  2023-04-01T13:30:00.000          normal             3  [{"key_point": "2", "key_points": [{"prob": "8...
12  camera1  2023-04-01T15:00:00.000          normal             3  [{"key_point": "2", "key_points": [{"prob": "8...
13  camera1  2023-04-01T16:00:00.000          normal             1  [{"key_point": "2", "key_points": [{"prob": "8...
14  camera1  2023-04-01T17:00:00.000          fallen             5  [{"key_point": "2", "key_points": [{"prob": "8...
15  camera1  2023-04-01T18:00:00.000          fallen             5  [{"key_point": "2", "key_points": [{"prob": "8...
16  camera1  2023-04-01T19:30:00.000          fallen             4  [{"key_point": "2", "key_points": [{"prob": "8...
17  camera1  2023-04-01T21:00:00.000          fallen             2  [{"key_point": "2", "key_points": [{"prob": "8...
18  camera1  2023-04-01T23:30:00.000          normal             4  [{"key_point": "2", "key_points": [{"prob": "8...

まとめ

API Gateway + Lambda + DynamoDB構成でGETリクエストでDBのデータを取得して、DataFrameを作成する方法について紹介しました。
実際にサービスを使うことで触りの部分は理解できました。ただ、認証やネットワーク設定はわからない点が多いので、今後は本やドキュメントを見ながら理解を深めていきたいと思います。

以上です。