Blogaomu

WEBアプリケーション開発とその周辺のメモをゆるふわに書いていきます。

Envoy の gRPC-JSON transcoder を利用する場合のアクセスログで元の HTTP method を出力したい

Envoy の gRPC-JSON transcoder を使っているときにアクセスログでハマったのでメモっておきます。

gRPC-JSON transcoder というのは、簡単にいうとRESTful な JSON API としてリクエストすると gRPC の形式に変換した上で upstream のサーバーにプロキシしてくれて、レスポンスについても gRPC の形式から JSON に戻してくれるという機能です。

www.envoyproxy.io

例えばこのような protobuf を定義して Envoy に取り込むと GET /shoes/{item_id} という JSON API のエンドポイントが有効になりリクエストを送れるようになります。

syntax = "proto3";

package shoes;

import "google/api/annotations.proto";

service Shoes {
  rpc GetShoeInfo(GetShoeInfoRequest) returns (ShoeInfo) {
    option (google.api.http) = {
      get : "/shoes/{item_id}"
    };
  }
}

message GetShoeInfoRequest { string item_id = 1; }

message ShoeInfo {
  string item_id = 1;
  string name = 2;
  string type = 3;
  repeated string size_labels = 4;
}

で、実際にリクエストを送ってみると以下のようなアクセスログが出力されました。パスが正しいので見落としていたのですがよく見ると GET でリクエストしたにも関わらず POST と出力されているのに気付き、調べてみることにしました。

$ curl -v http://localhost:8080/shoes/123456
> GET /shoes/123456 HTTP/1.1

---
[2021-02-20T06:56:41.536Z] "POST /shoes/123456 HTTP/1.1" 200 - 0 120 19 15 "-" "curl/7.64.1" "7f86f233-e658-400d-bb8f-999dea810924" "localhost:8080" "172.19.0.2:50051"
続きを読む

ALB で gRPC を利用する on EKS

先日、Application Load Balancer (ALB)が HTTP/2 および gRPC に対応するようになったという発表がありました。これをEKS上で稼働するアプリケーションにも適用できるかを試してみました。

ALB の HTTP/2 および gRPC 対応

EKS で ALB を利用するには?

続きを読む

ExternalDNS の policy を軽く調べたメモ

AWS の EKS 上で ExternalDNS を利用する際に policy という概念が分からなかったので、動かしながら簡単に調べてみたメモです。

policyって?

https://github.com/kubernetes-sigs/external-dns/blob/master/pkg/apis/externaldns/types.go#L410

Modify how DNS records are synchronized between sources and providers

  • マニフェストファイルで定義されるものとDNSプロバイダー間でDNSレコードがどのように同期が取られるかというのを設定する
  • sync, upsert-only, create-only の3種類のうちどれか
    • 鋭い方ならこの時点である程度想像付くかと思う
続きを読む

私が最近知ったGitHubのいくつかの便利機能

こんにちは。Webシステム開発や各種ソフトウェア開発において GitHub を利用する場面は多いかと思いますが、私が最近知った便利な機能をメモがてらいくつか紹介しようと思います。

Issue を Pull Request と関連付けて自動的にクローズさせる

docs.github.com

ある issue に対して Pull Request(以下PR)を作るというのは良くあることですが、PRを作る際に特定のキーワード(close, fix, resolve など詳しくはドキュメント参照)と対象のissue番号を書いておくと issue と PR が関連付けられます(画像1枚目, 2枚目)。右側のメニューに Linked issues という項目がありここに関連付けた issue が表示されます。

https://i.gyazo.com/127c48c1a7bca3d72a4cad2116f584e9.png

https://i.gyazo.com/9ef90b15d73400345557309a7e835826.png

この状態でPRがマージされると関連付けた issue が自動的にクローズされます!(画像3枚目, 4枚目) issue にはどのPRによってクローズされたかが明記され、また Linked pull requests という項目でも記録されます。

https://i.gyazo.com/7a17aecedf9402194ae3ff72c10fe416.png

https://i.gyazo.com/4ab694db3a239d4f47ac3c72b7a38fdc.png

これまではマージして自分で(もしくは他の誰かが) issue をクローズするという一手間がありましたが、自動化されるので楽できますね。あとは明示的に issue と特定のPRが関連しているというのが示されるのも後々振り返るときに便利だと思います。

続きを読む

Kanazawa.rb meetup #92 に参加しました #kzrb

今回もオンライン開催のmeetupでした。

meetup.kzrb.org

kzrb.doorkeeper.jp

もくもく会

今回は、CloudFormation用JSON SchemaをVSCodeで利用しているのですがエラーが出ているので調査していました。現象については以下にまとめました。そこまで致命的なエラーというわけではないです。

github.com

JSON Schemaでは $ref というキーワードを使い特定のスキーマを参照できます。今回の問題ではこの参照先がファイル内に存在しないことでエラーが出ている模様でした。$ref に関しては以下を参照。

json-schema.org

具体的には AWS::ResourceGroups::Group の Tags という定義で、もくもく会のときに見たときは List of JSON というタイプだった記憶があるのですがこの記事書いている時点では List of Tag というより具体的なタイプになっています。もしかするとJSON Schema側を更新すれば解決するかもしれないですね。

docs.aws.amazon.com

作業環境とお題について

話は変わってもくもく会時の手元の作業環境ですが左半分にブラウザを、右半分の上部にSlack、下部にZoomをそれぞれ配置していました。本当はZoomを全画面にしてというのが理想的ですが作業しながら他の人の顔も見たかったのでこんな感じにしていました。別モニターにZoomを常時表示するのもいいかもしれませんね。

この画面をキャプチャしたのはもう一つ意図があります。作業中に「もくもく会でやることを毎回悩むのだけどみなさんどうやって見つけてますか?」という質問があり、私はまさにこのキャプチャ内のやりたいことリストというのを用意しています。調べてみたいことや作りたいことを思いついたときにメモしておいて、もくもく会当日にリストから選ぶという運用をしています。選ぶ基準はその時の気分ですw

f:id:TAKAyuki_atkwsk:20200426110102p:plain

他の人の話を聞いた感想など

  • Rubyの右代入演算子について(http://secret-garden.hatenablog.com/entry/2020/04/10/195207)
    • イデアはとても興味深い
    • プログラム書く側の考え方として、メソッドチェーンして最後に値を変数に入れるというのが新鮮だった
      • もしかすると日本語的な世界観???
    • irbなどのreplではざっと書いたものを逐次実行するので有用なのではと思う
      • 要するにコードスタイルはともかく実行結果がほしいので
      • ファイルに書くときは可読性の問題で左に変数があるスタイルで統一されている方がよいと思った
  • Rust
    • 学習コンテンツ(https://doc.rust-lang.org/book/index.html)
      • 本のようなフォーマットできれいだなと思っていたらmdBookというツールで作られているとのこと
    • 変数は基本的にイミュータブルという話が出てきて、驚いている参加者が多い印象があって逆に驚いた
      • たぶん慣れの問題で、私はScala関数型言語を触る機会が多いので一般的な感覚だった
      • 最近出ているプログラミング言語はイミュータブルな変数を採用しているものが多い気がする
      • こういうのは極論になりがちだけど、適材適所だと思う(私は基本的にはイミュータブルにしておいてループ内とか局所的にミュータブルな変数を使うというのはあり派)
      • 少しだけこの話(ミュータブルの方がいい例)に触れている発表がScalaMatsuri 2019で行われたので興味ある方はどうぞ
  • Cuprite - Headless Chrome driver for Capybara
    • 気になる

懇親会

懇親会は引き続きZoom上で行われました。途中退出したりまた戻ってきたりできて自由度が高くて良いですね。

f:id:TAKAyuki_atkwsk:20200426094132p:plain

作業用EC2インスタンスを cloud-init で準備する

AWS環境で単発の作業用サーバー(例: 負荷テストツールの実行用)を楽に準備したくて cloud-init を利用する方法を調べました。EC2インスタンスの起動時にユーザーが定義した設定を行ってくれる仕組み(= cloud-init)があり、この設定をユーザーデータという形でEC2インスタンスに渡すことができます。

cloudinit.readthedocs.io

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/user-data.html

要件

  • プライベートサブネットに配置
  • デフォルトの ec2-user ではなくて、特定のユーザーでSSHログインしたい(公開鍵認証)
  • OpenJDK8 と sbt がインストール済み
    • Gatling という負荷テストツールを利用する想定
    • amazon-corretto のインストールで良い方法が見つからなかったので OpenJDK にしています

ユーザー作成

まず、SSHログインするためのユーザーアカウントを作成します。ログインするために公開鍵を登録するというのがポイントになります。cloud-init の users 設定で行います。

#cloud-config
cloud_final_modules:
    - [users-groups, always]
users:
    - name: takagi
      groups: [wheel]
      sudo: ["ALL=(ALL) NOPASSWD:ALL"]
      shell: /bin/bash
      ssh-authorized-keys:
          - ssh-rsa publickey # 公開鍵をセットする

この設定は以下資料を参考にしました。

aws.amazon.com

EC2インスタンス作成時に上記の設定内容をユーザーデータに渡しインスタンスが起動するとSSHログインできるようになります。踏み台サーバー経由でログインするために以下のような設定を行います。鍵は簡易的に踏み台サーバーと同じものを利用しています。諸々の設定が上手くいけば ssh working-server でログイン可能です。

# ~/.ssh/config
Host bastion # 踏み台サーバー
    HostName x.x.x.x # public IPアドレス
    User takagi
    IdentityFile /Users/takayuki_atkwsk/.ssh/id_rsa
Host working-server # 作業用サーバー
    HostName 192.168.2.73 # private IPアドレス
    User takagi
    IdentityFile /Users/takayuki_atkwsk/.ssh/id_rsa
    ProxyCommand ssh -W %h:%p bastion

パッケージのインストール

次に必要なパッケージをインストール済みの状態にします。上記でSSHログインできるようになった段階で yum install コマンドを打っても良いのですが、時間が空いて別の作業用インスタンスを起動したときに再度打つのも面倒くさいので cloud-init に任せてしまいます。今回は OpenJDK と sbt をインストールします。注意点としては、パッケージのインストールはインスタンスのライフサイクルで一度しか行われないため、上記の設定でインスタンスを起動した場合は一度終了(stop ではなく terminate)してパッケージの設定を追加した新しいインスタンスを作り直しましょう。

sbt に関しては以下のインストール方法に記されている方法の内、RPMレポジトリをパッケージマネージャに追加する方法で行います。

curl https://bintray.com/sbt/rpm/rpm | sudo tee /etc/yum.repos.d/bintray-sbt-rpm.repo
sudo yum install sbt

www.scala-sbt.org

cloud-init で対応するには yum_repos という設定を利用します。各設定値には上記の sbt RPM URLから得られるデータに含まれる値を使います。こちらがダウンロードしたデータです。

#bintray--sbt-rpm - packages by  from Bintray
[bintray--sbt-rpm]
name=bintray--sbt-rpm
baseurl=https://sbt.bintray.com/rpm
gpgcheck=0
repo_gpgcheck=0
enabled=1

それぞれの値を yum_repos に当てはめると以下の cloud-init 設定になります。これでパッケージマネージャにレポジトリを追加できます。後は yum install でインストールしたいパッケージ名を packages の値に書き込みます。

yum_repos:
    bintray--sbt-rpm:
        baseurl: https://sbt.bintray.com/rpm
        name: bintray--sbt-rpm
        enabled: true
        gpgcheck: false
packages:
    - java-1.8.0-openjdk-devel
    - sbt

yum_repos: https://cloudinit.readthedocs.io/en/latest/topics/modules.html#yum-add-repo

packages: https://cloudinit.readthedocs.io/en/latest/topics/modules.html#package-update-upgrade-install

この設定をユーザーデータに含めてインスタンスを起動すると、OpenJDK および sbt がインストールされた状態になっています。これで Gatling シミュレーションを含んだソースコードをローカルから scp すれば実行できるようになります。

[takagi@ip-192-168-2-73 ~]$ which java
/usr/bin/java
[takagi@ip-192-168-2-73 ~]$ which sbt
/usr/bin/sbt
[takagi@ip-192-168-2-73 ~]$ java -version
openjdk version "1.8.0_242"
OpenJDK Runtime Environment (build 1.8.0_242-b08)
OpenJDK 64-Bit Server VM (build 25.242-b08, mixed mode)

まとめ

用意した cloud-init 設定全体を以下に示します。今回は単発でEC2インスタンスを利用する(=定常的に稼働しないまたは他の人が利用しない)用途だったのでこのくらいの簡潔さが丁度良いなと感じました。組織でEC2インスタンスの構成管理を行いたい場合になると Chef や Ansible などのツールを使う方が上手く運用できるのかもしれません。

#cloud-config
cloud_final_modules:
    - [users-groups, always]
users:
    - name: takagi
      groups: [wheel]
      sudo: ["ALL=(ALL) NOPASSWD:ALL"]
      shell: /bin/bash
      ssh-authorized-keys:
          - ssh-rsa publickey # 公開鍵をセットする
yum_repos:
    bintray--sbt-rpm:
        baseurl: https://sbt.bintray.com/rpm
        name: bintray--sbt-rpm
        enabled: true
        gpgcheck: false
packages:
    - java-1.8.0-openjdk-devel
    - sbt