wireproxyでDockerから--cap-addせずにWireGuardに繋ぐ
はじめに
試用期間を無事に乗り越えた
お久しぶりです。今年の7月からさくらインターネットで働き始めておりました。
先月で試用期間が終わり、今月から正式採用となりました。
無事に試用期間を乗り切れて一安心です。
担当業務は?
所属部署はこれまで通りSRE室です。
ボスであるkazeburoさんをはじめ頼もしい同僚たちに囲まれて毎日楽しく仕事しております。
そんな中での私の業務はというと、引き続きUsacloudやTerraformプロバイダーといったOSSの開発をしつつSREとしての業務も担当しています。
Embedded SRE/Enabling SREとして、開発/運用の両者が共通のゴールをもって、運用性に優れたソフトウェアを開発すべくさまざまな取り組みをしています。
今日は最近のSREとしての取り組みの中から、デプロイの自動化にまつわる話を紹介させていただきます。
本題: wireproxyでDockerコンテナ内からWireGuard VPNに繋ぐ
SREとしての取り組みの一環として、これまで手動で行われていたとあるアプリケーションのデプロイ作業を自動化しました。
CI/CDという取り組みは既に一般的に広まっており、私自身これまで何度もデプロイの自動化を行なってきました。
今回対象にしたアプリケーションは比較的小規模で単純なGo製のアプリケーションでしたので、割とすんなりと自動化できるだろうと思っていたのですが少々引っかかる点もありました。
というのも、今回のデプロイ対象サーバへはWireGuard VPNを経由して接続する必要があり、さらにデプロイに用いているDrone上で起動されるDockerコンテナからそれを行う必要があるというのが難点でした。
wireproxyというツールを併用することでこの問題を解決しましたので以下で今回のシステム構成〜使い方まで含めて紹介します。
今回のシステム構成
今回の構成は以下の通りです。
- ソースコード管理: GitHub Enterprise(GHE)
- CI/CD: Drone
- VPN: WireGuard

アプリケーションのソースコードは社内ネットワーク上のGHEに置かれており、CI/CDには同じく社内ネットワーク上においたDroneを利用しています。
DroneではDockerパイプラインを利用しています。
今回デプロイ対象のシステムはさくらのクラウドに置いており、VPCルータを用いてVPCを構築、その中にサーバを複数台置くという構成です。
VPCルータのWireGuardサーバ機能でVPNを構築している
今回の構成ではVPNのためにVPCルータのWireGuardサーバ機能を利用しています。 VPCの中のサーバには外部から直接SSH接続出来ないようにしており、VPCルータとWireGuardでVPN接続してからサーバに接続する形となっています。
サーバ上で動かすアプリケーションはWeb APIを提供するもので、クライアントからのアクセス経路は別途確保する必要がありますが、今回のデプロイの話には関係ないので記載を省略しました。
問題: DockerからどうやってWireGuard VPNに繋ぐ?
普通にdocker runするとエラーになる
上記の通り、VPCの中のサーバにSSH接続するにはまずWireGuardでVPN接続する必要があります。
これをDroneのDockerパイプラインからやろうとするとエラーになってしまいます。
以下は手元でエラーを再現してみたものです。
# docker run -it --rm ubuntu:22.04 # 必要なものをインストール $ apt-get update; apt-get install -y iproute2 wireguard # インターフェース作成 $ ip link add dev wg0 type wireguard RTNETLINK answers: Operation not permitted
RTNETLINK answers: Operation not permittedって怒られてしまいますね。
権限が足りない -> --cap-add NET_ADMIN or --privilegedで実行できる
これは権限が足りないからで、docker runする時に--cap-add NET_ADMINを指定することで実行できるようになります。
参考: Docker run リファレンス - Linuxケイパビリティ
--privilegedでも良いですが、不要な権限は与えない方が良いでしょう。
Dockerのドキュメントにも以下のように書かれてます。
ネットワーク・スタックとやりとりするには、 --privileged を使う替わりに、ネットワーク・インターフェースの変更には --cap-add=NET_ADMIN を使うべきでしょう。
DockerはOK、次にDroneではどうすればいい?
Droneも--cap-add相当のことができる設定があればよさそうです。
しかしドキュメントを見る限りどうも--cap-addは出来ないようです。
代わりに--privilegedであれば指定できますが、Drone上で該当リポジトリをTrustedとしてマークする必要があります。
(各リポジトリのSettingsから設定可能です)
これで一応対応出来るとはいえデプロイのためにコンテナへ特権を与えたくないです。
ということで別の方法を探します。
別の方法: wireproxyを使う
この件についてSRE室の朝会(業務内容の共有だったり雑談したりする会)で話題に出したところ、kazeburoさんから「wireproxyというのがあるよ」と教えていただきました。
wireproxyとは
READMEにはwireproxy is a completely userspace application that connects to a wireguard peer, and exposes a socks5 proxyと書かれています。
どう実装されているのでしょうか?
ざっと見たところ以下のものを使ってユーザースペースでの実装を実現しているようです。
- tunデバイス: wireguard-go/tun/netstack -> gVisorのTCP/IPスタックを用いたtunの実装
- WireGuardプロトコルの実装: wireguard-go
wireguard-go/tun/netstackについてはこちらの記事でも触れられていますね。
0x6b.github.io
これなら--cap-add NET_ADMINしなくても大丈夫そうです。
ちなみにSOCKS5プロキシの実装にはこちらが使われています。
- SOCKS5プロキシ: github.com/armon/go-socks5
ということで早速試してみます。
wireproxyを手元から試してみる
WireGuardのクライアント設定ファイルを用意する
wireproxyはWireGuardクライアント設定ファイルを読み込めますので、まずは動くクライアント設定ファイルを用意した上でwireproxyの設定という手順で進めます。 まずWireGuardクライアント設定ファイルを用意し、その設定でWireGuardに繋がることを確認します。
今回は以下のような感じで用意しました。
$ vi wg0.conf [Interface] PrivateKey = xxx Address = 192.168.0.11/32 [Peer] PublicKey = xxx AllowedIPs = 192.168.0.0/24 Endpoint = 192.0.2.1:51820 PersistentKeepalive = 25
これで繋がるかDockerで試してみます。--cap-add NET_ADMINをつけるのを忘れないようにします。
# wg0.confを置いたディレクトリで実行 $ docker run -it --rm --cap-add NET_ADMIN -v $PWD:/etc/wireguard -v ~/.ssh:/root/.ssh ubuntu:latest # 必要なものをインストール $ apt-get update; apt-get install -y iproute2 wireguard openssh-client # WireGuardでVPN接続してみる $ wg-quick up wg0 # 確認: VPC内のサーバへSSHしてみる $ ssh user@192.168.0.x
設定が正しければ繋がるはずです。
WireGuardクライアント設定ファイルを参照するようにwireproxyの設定ファイルを作成
次に先ほど動作確認したWireGuardクライアント設定ファイルを参照するような形でwireproxyの設定ファイルを作成します。
今回のwireproxyの設定ファイルは以下のような構成となります。
# WireGuardのクライアント設定ファイルへのパス WGConfig = /path/to/wg0.conf # 以下でwireproxyの設定 [Socks5] BindAddress = 127.0.0.1:1080
wireproxyにはTCPClientTunnelとTCPServerTunnel、Socks5という設定項目がありますが、今回はSocks5を利用します。
Socks5を利用すると、指定したアドレスでリッスンするSOCKS5プロキシを起動してくれます。
sshコマンドからはProxyCommand='nc -X 5 -x 127.0.0.1:1080 %h %p'のように指定することでSOCKS5プロキシを利用できます。
ということで動作確認してみましょう。今度は--cap-add不要です。
# wg0.confを置いたディレクトリで実行 $ docker run -it --rm -v $PWD:/etc/wireguard -v ~/.ssh:/root/.ssh ubuntu:latest # 必要なものをインストール $ apt-get update; apt-get install -y iproute2 wireguard openssh-client curl netcat # wireproxyをダウンロード&インストール $ curl -LO https://github.com/octeep/wireproxy/releases/download/v1.0.5/wireproxy_linux_amd64.tar.gz $ tar zxvf wireproxy_linux_amd64.tar.gz && rm wireproxy_linux_amd64.tar.gz $ install wireproxy /usr/local/bin # wireproxy用の設定ファイルを作成 $ vi proxy.conf WGConfig = /path/to/wg0.conf [Socks5] BindAddress = 127.0.0.1:1080 # wireproxyをデーモンモードで起動 $ wireproxy -d -c proxy.conf # SSH接続してみる $ ssh -o ProxyCommand='nc -X 5 -x 127.0.0.1:1080 %h %p' user@192.168.0.x
これでうまく動きました。これならDrone上でTrustedにしたりprivileged: trueにしたりしなくても動きそうです。
Droneから使えるようにDockerfile作成
Droneから使いたいのでDockerfileを作っておきます。これをビルドしてレジストリにプッシュしておきます。
$ vi Dockerfile
FROM ubuntu:latest
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update \
&& apt-get -y install \
iproute2 \
wireguard \
openssh-client \
curl \
netcat \
&& apt-get clean \
&& rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/* \
&& curl -LO https://github.com/octeep/wireproxy/releases/download/v1.0.5/wireproxy_linux_amd64.tar.gz \
&& tar zxvf wireproxy_linux_amd64.tar.gz \
&& rm wireproxy_linux_amd64.tar.gz \
&& install wireproxy /usr/local/bin
ADD deploy.sh /deploy.sh
deploy.shは以下の値を環境変数で受け取る形にしました。
- WG_CONF: WireGuardクライアント設定ファイルの内容
- SSH_USER_NAME: SSH接続時のユーザー名
- SSH_PRIVATE_KEY: SSHための秘密鍵
- TARGET_HOSTS: 対象ホスト(スペース区切り)
今回はscp/sshコマンドをベタ書きしてますが、その辺を書き直せばもう少し汎用的に使えるはずです。
#!/bin/sh set -e if [ -z "$WG_CONF" ]; then echo "\$WG_CONF is required" exit 1 fi if [ -z "$SSH_USER_NAME" ]; then echo "\$SSH_USER_NAME is required" exit 1 fi if [ -z "$SSH_PRIVATE_KEY" ]; then echo "\$SSH_PRIVATE_KEY is required" exit 1 fi if [ -z "$TARGET_HOSTS" ]; then echo "\$TARGET_HOSTS is required" exit 1 fi # 各種ファイルを生成 echo "$WG_CONF" > wg0.conf echo "$SSH_PRIVATE_KEY" > /deploy_key; chmod 0600 /deploy_key cat << EOL > proxy.conf WGConfig = wg0.conf [Socks5] BindAddress = 127.0.0.1:1080 EOL # wireproxy起動 wireproxy -d -c proxy.conf # 接続完了するまで数秒待つ sleep 5 for host in $TARGET_HOSTS; do # scpでファイルを送り込んだり scp -i /deploy_key -o StrictHostKeyChecking=no -o ProxyCommand='nc -X 5 -x 127.0.0.1:1080 %h %p' ./your-application-file ${SSH_USER_NAME}@${host}:/path/to/your/application # sshで何かしたり ssh -i /deploy_key -o StrictHostKeyChecking=no -o ProxyCommand='nc -X 5 -x 127.0.0.1:1080 %h %p' ${SSH_USER_NAME}@${host} : do something done
Droneの設定
最後にDroneでこのDockerイメージを使ってデプロイするように設定します。
$ vi .drone.yml --- kind: pipeline type: docker name: deploy # タグをトリガーとする trigger: ref: - refs/tags/** steps: # ...中略... - name: deploy image: your-image:tags environment: WG_CONF: from_secret: WG_CONF SSH_USER_NAME: from_secret: SSH_USER_NAME SSH_PRIVATE_KEY: from_secret: SSH_PRIVATE_KEY TARGET_HOSTS: from_secret: TARGET_HOSTS
これでGHEにタグをpushするとWireGuard経由でデプロイが行えるようになりました。
終わりに
ということでwireproxyを使ってDockerから--cap-addなしでWireGuard VPNに繋いでデプロイするようにした話を紹介しました。
Drone特有の処理はないのでGitHub Actionsなどからも同様の方法が取れるはずです。
まだまだ改善の余地は多々ありますので今後も継続して改善していきます。
また、今回は紹介しませんでしたがデプロイの自動化の前段階としてE2Eテストの導入といったより安心して作業できる環境づくりなども行いました。
これらの取り組みは機会があれば改めてご紹介させていただきます。
以上です。
参考文献
WireGuardについて
- インターネットVPNの選択肢に WireGuardはいかがですか?: WireGuardの入門記事
- 作って理解するWireGuard: WireGuardの詳細解説
ユーザースペースでのWireGuard実装関連
- Userspace networking mode (for containers): tailscale/tailscaledのUserspace networking mode(SOCKS5プロキシ)
- cloudflare/boringtun: ユーザースペースでのWireGuardプロトコルの実装(Rust)
- Fadis/userspace_wireguard: WireGuardプロトコルのユーザースペース実装(C++)
- soratun を改造して AWS Lambda から簡単に SORACOM Arc を使ってみました: wireproxyと同じくwireguard-goを用いたユーザースペース実装(Go)
その他
続: さくらのクラウドにTerraformでISUCON過去問の環境を作る
前回: ISUCON12予選環境を作るやつ
前回はISUCON12予選の環境を作りました。
matsuu/cloud-init-isuconには他の過去問もある
環境を作るのに使わせていただいているmatsuu/cloud-init-isuconではISUCON12予選以外の過去問の環境向けのファイルも提供されています。
せっかくなので他の過去問にも対応しました。
対応した環境
matsuu/cloud-init-isuconが対応している環境は一通り対応してみました。
公式
非公式
ISUCON本に載ってるprivate-isuもあります
ISUCON本に載ってるprivate-isuも構築できちゃいます。
今回作成した過去問環境は基本的にサーバ1台で動かすようになっているのですが、 private-isuについてだけはさくらのナレッジに従いapp/benchの2台構成となっています。
ということで
非常に手軽に作成できるようになってますので是非お試しください〜。
以上です。
さくらのクラウドにTerraformでISUCON12予選の環境を作る
朝起きたらこちらのツイートが流れてきました。
ISUCON12予選のcloud-init-isuconを取り急ぎ作りました。まだ試してないけどさくらのクラウドにも適用できるはず。
— matsuu(シン・ウー馬場ーイー2) (@matsuu) 2022年7月29日
Apple Silicon上では一部動かない可能性あり。問題があればお知らせください #isucon https://t.co/vV1m6L1Hns
cloud-initで一発で環境構築できるすごいやつですね。ありがとうございます!!
そして
さくらのクラウドにも適用できるはず
とのことなので試しがてらTerraformで一発構築できるようにしてみました。
さくらのクラウドにTerraformでISUCON12環境を作る
こちらにコード類一式を置いておきました。
手順としてはこんな感じです。
詳しくはREADME.mdを参照してください。
私も環境を作ったばかりでまだ動作確認中なのでおかしいところがあったらご指摘いただけると嬉しいです。
502エラーが出たら
UPDATED: 2022-07-30: この問題は修正されていました
cosmetic by matsuu · Pull Request #10 · matsuu/cloud-init-isucon · GitHub
私の手元では管理画面にログインしようとするとFailed to Login: AxiosError: Request failed with status code 502というエラーが出ていました。
調べたところ認証サービスblackauthが起動していないようでしたので手動で起動しました。
sudo -i -u isucon sudo systemctl start blackauth
後でこの辺の原因をもうちょい調べてみます。
ということで取り急ぎ公開してみました。 私もこれからじっくり触ってみます。
以上です。
さくらインターネット株式会社に入社しSRE室で働き始めました
本日2022/7/1よりさくらインターネット株式会社に入社いたしました。
これまで主にさくらのクラウド関連OSSの開発という形で関わってまいりましたが、
これからは中の人として色々と活動していくことになりました。
みなさまどうぞよろしくお願いいたします。
どんなお仕事をするの?
所属は本日(7/1)始動のクラウド事業本部 SRE室です。
📣 本日よりさくらインターネット クラウド事業本部 SRE室が始動です!
— 達人が教えるつぶあん🇺🇦 (@kazeburo) 2022年7月1日
ワクワクするメンバーと一緒に、お客様によりよいサービスを提供し、お客様がやりたいことを実現できるようやっていきます。
素敵な仲間と共に、お客様によりよいサービスを提供し、お客様がやりたいことを実現できるように幅広く色々やっていきます。
これまでのOSSのツール類はどうなるの?
引き続き開発/メンテナンスを行います。 従来よりさくらのクラウドのCLIであるUsacloudやTerraform/PackerプラグインといったツールをOSSで提供していましたが、より安心/安定して使えるように引き続き取り組みます。
直近だとsacloud/autoscalerを用いたオートスケール機能がベータ版として提供開始されましたので正式リリース目指して頑張ります。
フリーランスとして受けてたお仕事はどうするの?
フリーランスとしてのお仕事は減らしましたが、継続中の案件についてはもちろん対応していきます。
当面は新規でのお仕事を受ける余裕はないと思いますが、そのうち落ち着いたら副業という形で再開するつもりです。
ということで
まずは試用期間を無事に乗り切れるように頑張ります。 今後ともよろしくお願いいたします。
さくらのクラウド: シンプル監視のWebhookでIFTTTと連携してみる
シンプル監視のアラート通知先にIFTTTとZapierが追加されました。
昨年末にZapierからさくらのクラウドAPIをポーリングする方法について記事を書きましたが、Webhookが使えるようになると出来ることの幅が広がりますね!
ということで連携を試してみました。
IFTTTと連携してみる
今回はシンプル監視からのWebhookを受けたら何かしてみます。
IFTTT側でアプレットを作成
まず新しくアプレットを作成します。If Thisの方をWebhookにします。


Webhookには2つのトリガーが用意されています。 送られてくるJSONはSlackのIncoming webhookに準拠したフォーマットとなっているので左の方を選びます。
なおシンプル監視から送られてくるJSONの例は以下のようなものでした。 参考: さくらのクラウド マニュアル: Zapier、IFTTTのWebhook URLに送信されるJSONの例
{
"icon_url": "https://secure.sakura.ad.jp/cloud/iaas/sacloud/img/logo/cloud_logo_slack.png",
"attachments": [
{
"color": "danger",
"fields": [
{
"short": "false",
"value": "113100******",
"title": "リソースID"
},
{
"short": "false",
"value": "203.0.113.5",
"title": "監視対象"
},
{
"short": "false",
"value": "(監視対象の説明)",
"title": "説明"
},
{
"short": "true",
"value": "ping",
"title": "プロトコル"
},
{
"short": "false",
"value": "CRITICAL - 203.0.113.5: rta nan, lost 100%",
"title": "ログ"
}
],
"text": "2022-03-18 11:35:13 にアラートを検知しました。",
"title": "ダウン検知 203.0.113.5",
"fallback": "ダウン検知 203.0.113.5"
}
],
"username": "sacloud-simplemonitor"
}
次にこのWebhookに名前(Event Name)を付ける必要があります。 ここで入力した値は後ほどシンプル監視を設定する時にWebhookのURLの一部となります。
後のThen Thatの部分はお好みで設定してください。
IFTTT側のWebhookのURLを確認する
アプレットを作成したらWebhookの送信先となるURLを確認します。 以下のページの「Documentation」ボタンから確認ページにいけます。
この記事の執筆時点ではURLは以下のような形式になっています。
https://maker.ifttt.com/trigger/{イベント名}/json/with/key/{アカウントごとのキー}
カッコ内は適切に置き換えます。
- {イベント名}: アプレット作成時に指定した名前
- {アカウントごとのキー}: 確認ページに記載されているキー
さくらのクラウドでシンプル監視を作成
次にシンプル監視を作成します。Webhookの通知先として先ほど確認したURLを設定します。
シンプル監視の作成時に通知先としてWebhookを選択するとWebhook URLという入力欄が出てきますのでそこに入力します。
動かしてみる
あとは動かしてみましょう。
応用: Webhookのペイロードを使いたい場合は?
IFとTHENの間にフィルターを追加してコードを書く必要があります。
参考: Parsing JSON body with filter code
// シンプル監視から渡されるJSONのパース let payload = JSON.parse(MakerWebhooks.jsonEvent.JsonPayload); // パースした内容を利用する例(Slackへの投稿) Slack.postToChannel.setMessage(payload.attachments[0].text); Slack.postToChannel.setTitle(payload.attachments[0].title);
終わりに
まだZapierは試せてませんが、近いうちにそちらも試してみようかと思います。
以上です。
備忘録: TeamCityでGolangのテスト結果をリアルタイム表示する
忘れがちなTeamCityの設定についての備忘録です。
今回の設定内容: Golangのテスト結果をリアルタイム表示
Golangで書いたアプリをTeamCity上でCIする際にテスト結果をきれいに表示するようにします。

設定手順
- プロジェクト - ビルド機能(Build Features)で
Golangを有効化 go testに-jsonパラメータを追加
ビルド構成でGolangを有効化
まずは各プロジェクト/各ビルド構成でビルド機能(Build Features)の画面を開き、Golangを追加します。

Add Build Featuresボタンから追加できます。

go testに-jsonパラメータを追加
次にテスト結果をJSONで出力するようにパラメータを追加します。
直接go testに追加しても良いですし、環境変数GOFLAGSに-jsonを指定してもOKです。
(ただし両方指定するとエラーになるので注意)
実行
あとは該当ビルド構成をRunするだけです。

Testsというタブが追加され、各テストの詳細が表示されていることが確認できるはずです。
普通にコンソール出力された文字列を追うよりわかりやすいですね。
ということで今回は以上です。
出典
AWSの料金をSlackに通知するLambdaをRustに移植してみた
はじめに
お仕事でAWS Lambdaを使って実装する処理が出てきました。
この処理はクリティカルな部分ではない、補助的な処理だったため日頃から使う機会を窺っていたRustで実装してみることにしました。
まずはRust+Lambdaの肩慣らしのために、プライベートなアカウントで利用している毎日のAWSの料金をSlackに通知する処理をRustに移植してみることにしました。
元ネタ: LambdaでAWSの料金を毎日Slackに通知する(Python3) qiita.com
今回移植したコード一式はこちらにおきました。 github.com
Rustへの移植
基本的には元のPythonの処理をそのまま移植していく方針としました。
関数の作成やIAMロールへのポリシーのアタッチなども元ネタとほぼ同じやり方にしています。
関数の作成はこんな感じでカスタムランタイムを選択しておきます。アーキテクチャはx86_64にしました。

コードはローカルでzipファイルを作ってアップロードする形にします。

プロジェクト構成
全体的な構成はこんな感じにしました。
$ tree . . ├── Cargo.lock ├── Cargo.toml ├── Makefile ├── bootstrap // エントリーポイント用のバイナリクレート │ ├── Cargo.toml │ └── src │ └── main.rs └── event.json // テスト用のダミーインプット
Lambdaのカスタムランタイムの仕様としてエントリーポイントはbootstrapという実行可能ファイルにする必要があるとのことでした。
docs.aws.amazon.com
今回はCargoのワークスペースを作成しその中にバイナリクレートとしてbootstrapというクレートを配置する形にしました。
ビルド〜zip作成
こちらに従ってビルドしていくようなMakefileを用意しました。
あらかじめrustup target add x86_64-unknown-linux-gnuしておいた上でmake zipするとDocker上でクロスコンパイル〜zip作成が行われるようになっています。
Makefileはこんな感じです。
DOCKER_PLATFORM ?= linux/amd64 RUST_VERSION ?= 1.57 RUST_ARCH ?= x86_64-unknown-linux-gnu DEPS ?= bootstrap/src/*.rs bootstrap/Cargo.toml Cargo.toml Cargo.lock RELEASE_DIR := ${PWD}/target/${RUST_ARCH}/release TARGET_BIN := ${RELEASE_DIR}/bootstrap TARGET_ZIP := lambda.zip build: cargo build --release --target ${RUST_ARCH} .PHONY: buildx buildx: $(TARGET_BIN) $(TARGET_BIN): $(DEPS) docker run -it --rm --platform ${DOCKER_PLATFORM} \ -v "$${PWD}":/usr/src/myapp -w /usr/src/myapp rust:${RUST_VERSION} \ make build .PHONY: zip zip: $(TARGET_ZIP) $(TARGET_ZIP): $(TARGET_BIN) zip -j "$(TARGET_ZIP)" "$(TARGET_BIN)"
PythonからRustへの移植
移植したコード全体はこちらです。 github.com
ロギング
pythonではloggerをこんな感じで用意していました。
logger = logging.getLogger() logger.setLevel(logging.INFO)
print!やprintln!でも良かったのですが、ログレベルをサポートするためにこちらを使うことにしました。
こんな感じで使います。
// 初期化 simplelog::SimpleLogger::init(LevelFilter::Info, Config::default()).unwrap(); // ログ出力 log::info!("hello {}", "world");
AWS SDK
boto3の代わりにrusotoを使います。
⚠️ Rusoto is in maintenance mode. ⚠️と書かれてますが今回は気にせず使うことにしました。
こんな感じになります。
let client = CloudWatchClient::new(Region::UsEast1); client.get_metric_statistics(GetMetricStatisticsInput { namespace: String::from("AWS/Billing"), metric_name: String::from("EstimatedCharges"), dimensions: Some(vec![Dimension { name: String::from("Currency"), value: String::from("USD"), }]), start_time: (Utc::today().and_hms(0, 0, 0) - Duration::days(1)) .format("%+") .to_string(), end_time: Utc::today().and_hms(0, 0, 0).format("%+").to_string(), period: 86400, statistics: Some(vec![String::from("Maximum")]), ..GetMetricStatisticsInput::default() }).await
SlackへのPost(WebHook)
requestsの代わりにreqwestを使います。
こんな感じにになりました。
let client = reqwest::Client::new(); client.post(slack_post_url.to_string()).body(body.to_string()).send().await?;
実行!
ということでmake zipし、作成されるzipファイルをマネジメントコンソールからアップロードしテスト実行してみます。

いい感じですね!
残課題
Dockerでのビルド周りが遅いのは要改善です。
また、LocalStackやlambci/lambdaを用いてローカル実行できるようにしてあげる必要もあると思います。
この辺は追々対応していきます。
ということで今回は以上です。
![LeanとDevOpsの科学[Accelerate] テクノロジーの戦略的活用が組織変革を加速する impress top gearシリーズ LeanとDevOpsの科学[Accelerate] テクノロジーの戦略的活用が組織変革を加速する impress top gearシリーズ](https://m.media-amazon.com/images/I/51TuqLnPBCL._SL500_.jpg)









![実践Rust入門 [言語仕様から開発手法まで] 実践Rust入門 [言語仕様から開発手法まで]](https://m.media-amazon.com/images/I/51t+hDKJOvL._SL500_.jpg)
