DC4

QRコードジェネレータをGKEからFirebase + Herokuに移行した。

GKEからFirebase + Herokuへ

yasun.hatenablog.jp

こちらで作成したQRコードジェネレータを運用しているGCPの無料期間が切れてしまったため、移動先のホスティング先を検討していたところ、FirebaseとHerokuを組み合わせれば無料かつ簡単に移行できそうだったので実施しました。

Docker on Heroku

Goで書かれたAPIをHeroku上のDockerコンテナに移行しました。

jp.heroku.com

公式の手順以外でやったこと

  • Herokuデプロイ用のDockerファイルを新規作成
  • 起動時はコマンドライン引数でポート番号を受け取りListenするように修正

注意点としては Listenするポート番号はHeroku側から指定された値を使う必要があるという点です。

expose も使用することができません。

deploy heroku · yassun/crypto-qrcode-generator@59d7d0b · GitHub

Vue.js on Firebase Hosting

既存ではコンテナ上でbuildしたVue.jsをNginxに配置していたのですが、配置先をFirebase Hostingに向けただけで特に何もしていないです。

$firebase init hostingの際に public directory の場所を聞かれるので build先(デフォルトはdist)に合わせるくらいでしょうか 。

deploy firebase · yassun/crypto-qrcode-generator@c2acb19 · GitHub

まとめ

フロントとバックエンドをそれぞれ別のコンテナにしていたことからホスティング先の選択肢が選べ、想定以上に簡単に移行することができ、コンテナベースで開発する恩恵を感じました。

無料枠では制限があるものの、検証用または簡単なサービスであれば十分すぎる環境かなと思います。

https://crypto-qrcode-generator-web.firebaseapp.com/

Go/Vue/KubernetesでBitcoinのQRコードを生成するWebAppを作った。

Crypto Qrcode Generator

Bitcoinの支払い用QRコードを生成するWebAppを作成しました。

Crypto Qrcode Generator:

https://crypto-qrcode-generator-web.firebaseapp.com/

スクリーンショット 2019-09-01 23 02 42

同様のWebサイトは既に存在するのですが、先日BIP-21をGoで実装したライブラリを作成したことと、Go/Vue.js/Kubernetesの学習目的のために作成しました。

Github Link: github.com

BIP-21

BTCの送金先アドレスを指定する際に用いられるスキームを規定したBIP(Bitcoin Improvement Proposals の略)です。

Go/Vue.js

バックエンドにはGolang/Echoを使用しました。 Go.1.12を使用し、パッケージ管理にはModulesを使用しました。 フロントエンドではVue.js/Vuetifyを使用しました。

開発環境

開発環境用と本番用のDockerファイルを分けており、開発環境はdocker compose upでGo/Vue.jsの両環境がホットリロードできる状態で立ち上がるようになっています。

本番側ではマルチステージビルドを使用してイメージのサイズを小さくし、Vue.jsはビルド後Nginxで配信する構成になっています。

Kubernetes

node構成は preemptibleのf1-micro 3台 + preemptibleではないf1-micro 1台 で運用しています。

外部アクセスの方法はingress + GCLB を選択しました。 L7ロードバランサとして動作しているためhttps化も後ほど対応しようと思います。

CI/CD

概要図

https://user-images.githubusercontent.com/2255617/64079033-5c6e7800-cd1d-11e9-84d8-fbd264d600ac.png

Github上でPull Requestを受けるとTravis上でテストが実施されます。

Masterブランチの場合に限り、Docker Buildの実施後、GCRにイメージがPushされます。

Pushが完了するとPod内のイメージをPushされたイメージでローリングアップデートを実施します。(kubectl set image )

感想

事前に「Kubernetes完全ガイド」を一読していたのでマネージドな環境(GKE)で簡単なアプリを動かすのはそこまで難しくなかったです。むしろ開発環境やCIの方が時間費やしてしまいました。

とはいえ多機能かつ周辺ツールも色々登場してきているので本番のサービスレベルで使いこなすにはまだまだ学習が必要そうな印象です。

今後も監視ツールの導入や機能追加等をしながら学習していこうと思います。

ISUCON8の予選を通過しました。

k02というチームでISUCON8予選に参加し、予選を通過することができました。 528組中16位でした。

isucon.net

準備

kyokomi が事前に kibela を導入してくれていたので毎年よく使うコマンドやNginx/MySQLの設定ファイル等を予め追加していました。

当日の会場とディスプレイ等はwaniji が手配してくれたおかげで横並びで作業することができ、最高の環境でした。

当日

なんとか起床に成功し、恵比寿に集合することに成功。

ひとまず全員でレギュレーションの読込み後、サービスの機能一覧を確認しました。

この時点で h2oMariaDB の存在に気がついたのですが、一旦後回しにし、アプリケーション側のチューニングに集中することに。

今回も諸事情でGo実装を選択していましたが、普段の業務では使っていないためRuby実装とGo実装を交互に読みながらソースを確認していました。

ソースリーディング中はkyokomiが出力してくれたER図がとても役に立ちました。

N+1、インデックス追加、Sheetテーブルのキャシュ等を行いましたが、DBのCPU使用率が高すぎてベンチの結果が上がらなくなったため、早々にDBを別サーバに切り出すことにしました。

このあたりからスコアが徐々に伸び始めて10000点くらいになり、10位代をうろうろしていました。

その後いくつかの変更を加えた後にDBのコネクション数を変更してみたところ、30000点を超えて暫定4位を記録しました

が、/admin/api/reports/events/:id/sales の結果に整合性がない?みたいなエラーが出るようになり、 ベンチーマークの結果がなかなか安定せず、数回に一回だけ成功するガチャ状態に陥ってしまいました。

原因が掴めずここでかなり時間を消費してしまいました...。

この間にシート予約時の場所をランダムではなく、順番に着席させてみたら怒られたりしてゲラゲラ笑ってました。

終盤間際で排他処理が正常にできていないことに気が付き、ベンチマーク結果を安定させることができました。

そのまま終了3分前くらいに、その日の最高得点が出たので終了しました。

感想

2017年ふりかえり。

今年も残り数時間なので恒例のふりかえり。

帰国

約1年半のフィリピン生活を終えて、日本に返ってきました。

食のレベルの高さ、治安の良さを改めて感じました。

帰国直後は毎日セブンイレブンの商品を食べて感動していました。

時々フィリピンの大雑把さや底抜けに明るい雰囲気が恋しくなることも。

フリーランス

昨年から引き続き、リモート中心のフリーランス活動をやっていました。

Rails だけでなくGoやReact関係にも関わることができて勉強になりました。

お仕事を下さった方々/ご紹介して頂いた方々には本当に感謝です。

引越しと断捨離

フィリピン -> 日本(実家) -> 東京(1) -> 東京(2) と今年だけ4回ほど引越しをしました。

引っ越す度に最低限必要なものだけを残してきたため、最終的には全ての持ち物がトランクケース1個になりました。

これを機に定期的に断捨離していこうと思います。

スタートアップにジョイン

入社しました!

来年に向けて

来年は腹筋割りたいです。

それではよいお年を!

未使用アウトプットに基づくトランザクションの生成/署名/送信

Mastering Bitcoinの「未使用アウトプットに基づくトランザクションの生成/署名/送信」を実際にコマンドを実行しながら確認します。

環境は前回作成したDocker環境を使用します。

Bitcoin Coreを試すためのDocker環境を作った。 - DC4

Raw Transaction の受取先アドレスを作成します。

# アドレスの作成
root@56451b900162:/# bitcoin-cli -regtest getnewaddress testuser1
mrmcNKkhippXe8WTm7BbLNSoy5CydCZHhV

Raw Transaction に含めるUTXOを選択

#未使用のアウトプット(UTXO)を確認
bitcoin-cli -regtest listunspent 
...
  {
    "txid": "5f76f24fe419f09e7da5010d8e3d110db4189f3b51f797026d619a7ca95416f8",
    "vout": 0,
    "address": "mzLCAPscRZtYZysh2RjUz8XEgXZuAU7e9v",
    "scriptPubKey": "2103562423e4bd01816ee0e06df4b327970b6f5f04ac817ad9e66ab039d20bd34db7ac",
    "amount": 50.00000000,
    "confirmations": 147,
    "spendable": true,
    "solvable": true,
    "safe": true
  }
...

Raw Transaction の作成

# > bitcoin-cli createrawtransaction "[{\"txid\":\"myid\",\"vout\":0}]" "{\"address\":0.01}"
# `txid` 、`vout` に 上記のUTXO、受取先アドレス、送金額(10BTC) / お釣り(39.9995BTC) (手数料: 0.0005) を指定する。
root@56451b900162:/# bitcoin-cli -regtest createrawtransaction "[{\"txid\":\"5f76f24fe419f09e7da5010d8e3d110db4189f3b51f797026d619a7ca95416f8\",\"vout\":0}]" "{\"mrmcNKkhippXe8WTm7BbLNSoy5CydCZHhV\":10,  \"mzLCAPscRZtYZysh2RjUz8XEgXZuAU7e9v\":39.9995}"
020000000100cc5d9cf910e58d423e4e686d67c9719e6e300eb93be1ecdc92ab53e274b2310000000000ffffffff0200ca9a3b000000001976a9145e4973ba22b718b8336c53cc70504ed16e07caf688acb0646aee000000001976a914ce6164048e09beba6beb0ea63fc9a7edc501393e88ac00000000

vout・・・1つのトランザクションを分割する際の番号

出力された16進数をデコードして内容を確認します。

bitcoin-cli -regtest decoderawtransaction 020000000100cc5d9cf910e58d423e4e686d67c9719e6e300eb93be1ecdc92ab53e274b2310000000000ffffffff0200ca9a3b000000001976a9145e4973ba22b718b8336c53cc70504ed16e07caf688acb0646aee000000001976a914ce6164048e09beba6beb0ea63fc9a7edc501393e88ac00000000
{
  "txid": "086065375607d9afd95a105eda40c362dec067bff7d2ba1cedc7002a5b27ce1e",
  "hash": "086065375607d9afd95a105eda40c362dec067bff7d2ba1cedc7002a5b27ce1e",
  "size": 119,
  "vsize": 119,
  "version": 2,
  "locktime": 0,
  "vin": [
    {
      "txid": "31b274e253ab92dcece13bb90e306e9e71c9676d684e3e428de510f99c5dcc00",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 10.00000000,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 5e4973ba22b718b8336c53cc70504ed16e07caf6 OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a9145e4973ba22b718b8336c53cc70504ed16e07caf688ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "mp7VodBS75f57jFgGWHb6NHNCrDH54CxNr"
        ]
      }
    },
    {
      "value": 39.99950000,
      "n": 1,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 ce6164048e09beba6beb0ea63fc9a7edc501393e OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a914ce6164048e09beba6beb0ea63fc9a7edc501393e88ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "mzLCAPscRZtYZysh2RjUz8XEgXZuAU7e9v"
        ]
      }
    }
  ]
}

scriptSigがnullなので、署名が行われていないことが確認できます。

署名の実施

root@56451b900162:/# bitcoin-cli -regtest signrawtransaction 020000000100cc5d9cf910e58d423e4e686d67c9719e6e300eb93be1ecdc92ab53e274b2310000000000ffffffff0200ca9a3b000000001976a9145e4973ba22b718b8336c53cc70504ed16e07caf688acb0646aee000000001976a914ce6164048e09beba6beb0ea63fc9a7edc501393e88ac00000000
{
  "hex": "020000000100cc5d9cf910e58d423e4e686d67c9719e6e300eb93be1ecdc92ab53e274b23100000000484730440220171a3a74c11ce5e7ffcc2a3ee6cf86957edfa955dd0ca3052ea3d1631eb616f5022054a24b3201cbf3d3b979c4d3074ef490be5cf89b8857056021933201d1f2b7e501ffffffff0200ca9a3b000000001976a9145e4973ba22b718b8336c53cc70504ed16e07caf688acb0646aee000000001976a914ce6164048e09beba6beb0ea63fc9a7edc501393e88ac00000000",
  "complete": true
}

もう一度デコードして内容を確認します。

{
  "txid": "7c7f41ccd1d0df0f3ab1009ab7993ec32ff161b9edaa3c196e6644dda54c8efb",
  "hash": "7c7f41ccd1d0df0f3ab1009ab7993ec32ff161b9edaa3c196e6644dda54c8efb",
  "size": 191,
  "vsize": 191,
  "version": 2,
  "locktime": 0,
  "vin": [
    {
      "txid": "31b274e253ab92dcece13bb90e306e9e71c9676d684e3e428de510f99c5dcc00",
      "vout": 0,
      "scriptSig": {
        "asm": "30440220171a3a74c11ce5e7ffcc2a3ee6cf86957edfa955dd0ca3052ea3d1631eb616f5022054a24b3201cbf3d3b979c4d3074ef490be5cf89b8857056021933201d1f2b7e5[ALL]",
        "hex": "4730440220171a3a74c11ce5e7ffcc2a3ee6cf86957edfa955dd0ca3052ea3d1631eb616f5022054a24b3201cbf3d3b979c4d3074ef490be5cf89b8857056021933201d1f2b7e501"
      },
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 10.00000000,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 5e4973ba22b718b8336c53cc70504ed16e07caf6 OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a9145e4973ba22b718b8336c53cc70504ed16e07caf688ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "mp7VodBS75f57jFgGWHb6NHNCrDH54CxNr"
        ]
      }
    },
    {
      "value": 39.99950000,
      "n": 1,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 ce6164048e09beba6beb0ea63fc9a7edc501393e OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a914ce6164048e09beba6beb0ea63fc9a7edc501393e88ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "mzLCAPscRZtYZysh2RjUz8XEgXZuAU7e9v"
        ]
      }
    }
  ]
}

今回は scriptSigが設定されている事が確認できます。

この状態で 署名されたhexsendrawtransaction 等を使用してブロードキャストすることができます。