Kekeの日記

エンジニア、読書@1915keke

宣言的Spinnaker設計 継続的デリバリーのさらに上にいく

tl;dr

学部4年になり忙しくなるので、よりすべてを「自動化」しようと思いました。

最近自分が考案した 宣言的継続的デリバリー(Declartive Continuous Delivery) を紹介させていただきます。

まず、宣言的継続的デリバリーを定義させていただきます。

宣言的継続的デリバリーとは、カナリアデプロイなどの知的なデプロイを、宣言的に継続的デリバリーする手法

記事のざっくりとして内容は

  • マイクロサービスを継続的デリバリーことができるspinnakerを宣言的に構築する
  • まるでCircleCIの設定ファイルのようなconfig.ymlを配置するだけでspinnakerのパイプラインを走らせることができる。
    • 既存の環境への親和性が高い
    • 「それぞれの設定がそれぞれのアプリケーションへ帰属」というわかりやすさ
  • templateは一括でrepoでモジュール化して管理しよう
    • 組織の財産となる
    • templateとアプリケーションを分離することで管理しやすい
    • 再利用性

です。設計したDCDフローは以下の通りです。 解説は記事を読んでください。

image.png


対象とする読者

  • デプロイが大きな負担となっているひと
  • 自動化が大好きな人
  • Kubernetesなどでマイクロサービスを運用していて、さらにDeployサイクルをあげたい人
  • カナリアデプロイ、ブルー・グリーンデプロイを自動的にやりたい人

解決する問題

1.kubernetesのDeploy問題 kubernetesは非常に機能が多く、マイクロサービスを導入しやすくして、よりアジャイルな開発へのパラダイムシフトを促したソフトです。

manifestファイルと呼ばれる、どのロードバランサーに何を繋げて、どのくらいのVMで、、、といったようなことがすべて宣言的に書けて、Deployするにはapplyコマンドを叩くだけです。

image.png

しかしながら、Deployが毎日数回など行われるときにapplyコマンドを叩くのは面倒です。 現状として、Botを使ってSlack越しでDeployしたり、CIに任せて要るケースがほとんどです。

2.Deploy戦略の難しさ Deployとは単純な作業ではなくて、実際にはデプロイ後に変な挙動をしていないか、他のマイクロサービスとうまく連携が取れて要るかなど、確認することが膨大にあります。

  • Blue/Green Deployment
  • Canary Deployment
  • Rollbackが安全にできるか
  • ビジネスモデルとの連携
  • ...

image.png https://sweetcode.io/13115-2/

これらをメンテしていくのは難しく、よくチームに「インフラエンジニア」や「SRE」などと肩書きがつくエンジニアが面倒見たりしています。

3.インフラエンジニアを導入する盲点 インフラに関するタスクがヘビーならインフラ専門のエンジニアをおけばいいじゃん! って考えるかもしれません。 確かにインフラには専門的な知識や経験が必要で、膨大なドキュメントを読まないといけません。

image.png https://www.youtube.com/watch?v=LVgP63BkhKQ

確かにインフラにマジつよエンジニアがいればその人に任せることができます。 実際、どの会社もそのような形態を取っていることが多く、採用でもコースが分かれているほどです。

今年、夏休み1週間くらいインターン行こうかなって思って募集を見ていたらサイボウズSummerInternshipがこのようになっていて、やはりサーバーサイドとインフラの乖離はどこでもあるのだなと痛感しました。

image.png

しかしながら、一人に任せるのにはデメリットがあり、

  • インフラで起きることのフィードバックをその他のエンジニアに還元できない
  • 責任がインフラエンジニアだけに生じる
  • 本来の企業としての価値は生んでいない
  • ...

のようなことが挙げられます。

Spinnakerとは

image.png

Spinnakerとは継続的デリバリーを容易に導入しやくするソフトウェアで

  • 高度なUIで設定、フィードバック
  • 自動デプロイ機能を搭載している
  • ヘキサゴナルアーキテクチャ(GCP,AWSなどに関わらす使える)
  • Immutable Infrastructureを強制できる

のような特徴があり、現在のDeploy問題を解決します。 以下のようなメリットをもたらします。

  • UIや通知でエンジニアにフィードバック
    • ソースを更新したエンジニアに直接還元
  • PodやServiceなども監視することができる
  • プロジェクト単位で管理できる

しかしGUIでぽちぽちするのでMutableなのです。 新米エンジニアが設定するときにうたた寝をしてしまい、レプリカ数を1000にしてしまうかもしれません。

つまり宣言的にしないといけないのです。

なぜ宣言的がいいのか

そもそも宣言的とは

設定ファイルを書いて、あとは何もいじれない状態です。 そのような面でCircleCIはテストを宣言的に書いているといえます。

まずconfig.ymlなどに設定を描き、それを反映させます。

image.png

すると、それ以降は誰もいじれません。

image.png

このようにすることで

  • 誰でもconfig.ymlなどがあれば同じ環境を作れる。
  • 複製が容易になり、マイクロサービスに使えやすい
  • Deploy戦略を構築しやすい
  • スノーフレークサーバーを生み出さない

などなどメリットがたくさんあります。 これをSpinnakerに適用すると、すぐあとで説明する「知的デプロイ」という、デプロイ戦略やフィードバックを含むデプロイまでを宣言的に書くことが宣言的Spinnakerの目的です。

image.png

宣言的の現状

現状では、Deployは継続デリバリーで実現しているところはありますが、Deploy戦略までは宣言的に実現している組織は見当たりませんでした。

僕がドキュメントにContributeさせてもらった商用SpinnakerであるArmoryでは以下のようにソフトウェアデリバリー(CD)のレベルを定義しています。 最も高いのは知的デプロイ(ID)です。

image.png

Stages of Software Delivery Evolution Infographic

大まかに説明すると従来(低いCD)は

  • Mutableのものは「デプロイはイベントごと」くらいひやひやする
  • 開発遅い
  • 危ない

宣言的のメリット

最もレベルの高い知的デプロイは

  • 自動カナリアデプロイ
  • 自動ロールバック
  • カオスエンジニアリング

などの特徴がありデプロイもものすごい数が行われます。 マイクロサービスに分けてサービスごとのチーム・組織を組み、開発サイクルを高速に回すことが可能となります。

このようなことから、エンジニアやデザイナーが創出した価値がユーザーにすぐに届けられるわけです。 宣言的のよさがわかったところで、Spinnakerの詳細に入りましょう。

Spinnakerでの概念

Spinnakerにはいくつか重要な概念があるので説明します。

application

これは特定のリポジトリで使われることが多いです。 レポジトリごとにアプリケーションを作るのが良いのではないかと思います。

applicationを作成する image.png

pipeline

テストして、デプロイして、監視して、通知してなどの流れを定義する水道管のようなものです。

実際に簡単なものを作るとこんな感じです。

image.png

pipeline-template

これは可視化をするのが難しいのですが

pipelineの虫食い版のようなもの でtemplateに「レプリカ数はその時に決めるよ」のように書くと、pipelineを使うときに変数定義ができます。

またpipeline-templateを用いるとImmutable Pipelineとなり、あとから設定を消すことはできません。

Pipelineを作るときにTemplateを指定します。 image.png

すると変数を定義する画面に遷移するので変数を定義します。 image.png

するとImmutable Pipelineが完成します。 スクリーンショット 2018-05-19 2.42.51.png

ここで注目していただきたいのが「 Manual edits are not allowed on templated pipelines 」と後から変更ができないようになっていることです。 これによって誰が作っても同じ構成で、変更すべて変数だけ作成時に指定することになります。


宣言的Spinnakerの導入

コンセプト

重要なコンテプトとして以下のようなことを設計思想にいれました。

  • 一つのアプリにはひとつの設定を
  • 初期設定以外は何も意識しなくていい世界
  • 一般的なCI、CDをいじらなくて済むように
  • 直感的にわかりやすいもの

設計したフロー

image.png

簡単に説明すると

  • アプリ固有のパイプライン設定ファイルを配置
  • mergeされるとパイプライン設定ファイルと、使用するテンプレートを参照しspinnakerにデプロイ
  • GCRにアプリのコンテナpush
  • パイプラインがトリガーされて、パイプラインが走る
  • カナリアデプロイができて、デプロイ環境は設定ファイルから読み取る

メリット - アプリに書いた設定(例:.spinnaker/config.yml)が宣言的であり、それ以外はいじれない - 宣言的継続的デリバリーの中では直感的にわかりやすい - 従来のプロジェクトとの親和性 - CIはそのまま、パイプラインデプロイ(curl経由で可能)、GCRプッシュくらい - もう取り入れて要る可能性が高い - それ以外はいじらなくていい

今回作るもの

ngnixサーバーを更新すると、CircleCIがテストをして、カナリアデプロイして、SlackにWebhookを送るパイプライン

実際のプロジェクト

githubリポジトリをアプリケーションとテンプレートの二つに分けています。

  1. テンプレート側 テンプレートを保存してあるリポジトリのファイル構成です。
$ tree keke-template/
.
└── templates
    └── AtomicCanaryWithoutWebhook
         └── template.yml

template.ymlにSpinnakerのUIに1対1対応するように記述します。

  1. アプリケーション側 実際のRailsやGolang Serverなどのアプリケーションのファイル構成です。 余計なもの(READMEgitignoreなど)は省略させていただいてます。
$ tree keke-app/
. 
├── .circleci
│   └── config.yml
├── .spinnaker
│   └── value.yml
├── app
    ├── Dockerfile
    └── default.conf

今回、Spinnakerの設定ファイルは.spinnaker/value.ymlに定義し、以下のようになっています。

schema: "1"
pipeline:
  application: Demo
  name: Atomic Canary Deployment
  template:
    source: [YOUR_TEMPLATE_PATH]
  variables:
    replicas: 2
    loadbalancer: nginx-keke
    slackWebhookURL: [YOUR_SLACK_URL]

Demo

1. アプリケーションを更新したとき

image.png

nginxを更新するとCircleCIが走ります。 Jobはこのようになっています。

  • test
  • pipelineをデプロイ
  • nginx/Dockerfileでイメージを作ってGCRにpushする

image.png

二番目の手順であるpipelineのデプロイはSpinnakerで確認できます。 三番目のジョブはGCRにプッシュすることです。

pipelineはできていました。 GCRにpushされるとパイプラインが実行されてカナリアデプロイの完了です。

これを実際にやってみます。 まず、アプリケーションは作ったものの、何もpipelineが定義されていない状態からスタートです。 image.png

コードを更新して、githubにpushします

image.png

そしてPull requestを作成してmergeをするとします。 するとCircleCIでworkflowが走ります。

testジョブが走りましたが、何も変化がありません。 image.png image.png

testが無事に終わって、Spinnakerにpipelineを走らせるジョブが走っています。 image.png

完了しました。

image.png

成功しました。するとSpinnaker上では

image.png

とpipelineができており、もちろん宣言的に書いたので一切いじれないパイプラインができています。

image.png

あとはGCRにイメージがpushされて、パイプラインが実行されるといういつも通りです。

image.png

1.1 まとめ

アプリケーション(Rails、Golang,Node.jsなど)を更新すると、.spinnaker/config.ymlを定義するだけで宣言的パイプラインで実行することができる。

(注)宣言的Spinnakerの設定ファイルである.spinnaker/config.ymlなどのパスは任意です。

Notificationを設定しているので、以下のような通知が来るようになります。 image.png

2. tempateが更新されたとき

リポジトリを分けているからtemplateが更新されたときに、どうなるの? って思う方が要ると思いますが、こちらも対応しています。

image.png

具体的にはtemplateがmergeされるとpipelineそのものを新テンプレートで更新しなおす、ということをします。

試しに変数を追加してmergeします。 今回は以下のようなnewVariablesForDemoという変数を追加しました。

image.png

CircleCI以下のようなWorkflowになっています。 image.png

最初にtestジョブが走って、これ自体はpipeline-template自体をバリデーションしています。 テストが完了すると、publishジョブが実行されテンプレートが更新されます。

image.png

次に古いバージョンのテンプレートを使用しているものを新しく更新しないといけません。これを担うのはsyncです。

image.png

このジョブが終わるとCircleCI APIを通してアプリケーション側のWorkflowのSpinnakerのPipelineをビルドしなおし、新しいテンプレートを用いてパイプラインをデプロイしなおします。

image.png

完了しました。するとアプリケーション側でまたビルドが走っているのです。

スクリーンショット 2018-05-19 3.11.13.png

これによって最新テンプレートがすぐ反映されることになります。

確認用にGUIからtemplateを利用してみると

image.png

と新しいtemplateができていることがわかります。

もちろん、これをしなくてもアプリケーション自体の更新があれば新しいテンプレートは反映されますが、template merge時とアプリで使っているテンプレートが異なるということは、カオスな環境をうむので即座に反映させようと思いました。

2.1 まとめ

別repositoryで管理しているtemplate自体もうまくすればアプリケーション側と連携を取ることができ、すぐ反映することができます。 これによってテンプレート自体も、エンジニアにフィードバックをもたらすことができます。

3. フィードバック

サーバーサイドエンジニアなどでも容易に「どのようなパイプラインでデプロイされたのか」や「カナリアデプロイがなんで失敗したか」などを知ることができます。

スクリーンショット 2018-05-19 12.10.06.png

参考になるリンク

多くある問い合わせ

1. proddevクラスタなど複数のクラスタがあるときに使用できるの?

もちろん使用可能です。 想定としてはymlにて宣言的にデプロイ先のクラスタを定義することになります。

 variables:
    devcluster: keke-dev
    prodcluster: keke-prod

これだけでは使うことができなく、あらかじめhalyardにて設定を読み込む必要があります。 この部分が参考になるかもしれません。

www.spinnaker.io

2. Spinnaker内のapplicationのユースケースは?

Spinnakerにはapplicationだけではなくて、projectなどの一見どのように使うのかわからない概念があります。

僕自身のチーム運用でのベストプラクティス以下の通りです。

  • project: プロダクトを束ねる組織で分ける(例として、部署、小さい規模の会社など)。
  • application: プロダクトに紐づくように分ける。

しかしながら、これに対してはベストプラクティスがなく、チームのコンセンサスを取りながら進めていくのがいいのかもしれません。

最後に

これまでは宣言的継続的デリバリー(DCD)を実現すると理論的にはハッピーと周知されているものの、どのようすればよいのかが明白ではなかったです。

しかし、Spinnakerやkubernetesなどが登場し、継続的デリバリーが容易にできるようになった今、それを宣言的にするというパラダイムが到来することは自明でした。

今回挑戦してみて、CircleCIやTravis、JenkinsなどのCI手法を参考にしつつ、かなりよいDCDを考えつくことができたのではないかと思っています。

コメントやコメントなど質問・雑談・感想お待ちしています。 各種フォローよろしくお願いします!

Github: https://github.com/KeisukeYamashita

Start your Bitcoin app with just 4 lines of code. go-btcrpc

Hey Guys. A great announcement to everyone who wants to use blockchain.

I made a simple bitcoin library to interact with your bitcoin node called go-btcrpc.

What's JSONRPC?

JSONRPC is like JSON but the object is a bit different. Unlike JSON, JSONRPC has a mandatory key like jsonrpc or method.

And all methods of the Http requests are POST. It is used for remote method executing.

In the blockchain application, the infrastructure looks like this. The app server interacts to the blockchain though the bitcoin node server. You can get the docker file of the bitcoin node amacneil/bitcoin.

https://qiita-image-store.s3.amazonaws.com/0/153320/744a8c95-5e4e-73f4-9d4a-5e6d5e0cfcc5.png

How can I create a app?

For my example, I use a golang webframework for my application server. And I use this go-btcrpc package for the interaction between these two.

image.png

How to use this package?

This is extremely easy.

package main

import (
  "fmt"
  btcrpc "github.com/KeisukeYamashita/go-btcrpc"
  )

func main() {
    basicAuth := &BasicAuth{
        Username: os.Getenv("USERNAME"),
        Password: os.Getenv("PASSWORD"),
    }
    c := NewRPCClient(os.Getenv("BTCD_ENDPOINT"), basicAuth)
    address := "my88QLpf2RYYDdNMmDwYvfx6TFc6NXaELa"
    balance := c.GetBalance(address)
    fmt.Print(balance) // 0.13514 BTC
}

That's all. It alreadly got the balance(the mount of bitcoin) of the address. There is more useful methods, see the README.md for more specific infomations about the methods. Not all methods of bitcoin api is implemented!

How to get the bitcoin node?

See the official repo for installation. bitcoin/bitcoin

Remember to set the basic auth option when you start your bitcoind.

How to contribute?

Just send a pull request to this repo. I believe that this project is very cool lets people develop blockchain application much easlier.

Make world a better place. That's why this project is OSS.

Questions

Please feel free to ask questions about this package via email, github, facebook and such like. I've created app on Ethereum,Bitcoin, Ripple, Lisk...etc.

Any questions are welcomed.

Email: 19yamashita15@gmail.com

Github: @KeisukeYamashita

Ripple開発者コミュニティを作りました

f:id:bobchan1915:20180214213318p:plain

TL;DR

  • Rippleの開発者コミュニティを作りました
  • XRP testnetで10000XRP持っていないと入れません
  • Rippleについて熱く議論できればなと思います

->リップル開発者コミュニティ

はじめに

本来ならばslackinのように自動招待をしたかったのですが、忙しくできませんでした。

本質的なRippleを持っているかどうかでチェックしています。 ブロックチェーン関連のSlackコミュニティは以上にサイバーテロ攻撃をされます。(僕もフィッシングやアドレス詐欺など)

なので一回目を通そうと思いました。 自分も何回か攻撃されているし、特定通貨ではコミュニティが荒らされているケースもあります。

背景

RippleはRipple.incによって開発が行われている分散型台帳技術を利用した即時グロス決済システム、 外国為替・送金ネットワークのことで、Bitcoin系やEthereumとは少し違った運用方法をしています。

Rippleはそもそも分散的な社会ということを目標としているわけではなくて「非中央集権」的な社会を目指しています。 ブリッジ通貨、ゲートウェイ、ペイメントなど難しい単語が並んでいて、開発をしていてもハマって、開発が遅くなってしまいます。

日本でも投資対象として、単なる送金通貨対象としてではなくて、エンジニアリング精神を主軸に開発を促進していけるコミュニティがほしいと思って作りました。

テストネットでXRP所有者限定に

なぜテストネットXRP所有者だけがSlackコミュニティに入れるのかというと、それはブロックチェーンハッキングのジレンマが重要な鍵となっています。

暗号通貨を始めとするブロックチェーンおよびそれら自体はセキュアなシステムです。 つまり、ハッカーがブロックチェーン自体をハッキング(51%アタッキングなど)をしても、それ自体の通貨の信用を下げることになり、結果的に誰も使わないので価値が下がってしまいハッキングをした意味が低下します。 また、コインチェックのNEM流出事件では、ほぼ100%の通貨が大幅に下落して(今はまた上がってますが)暗号通貨そのものの価値は下がっていました。

なるべくエンジニアが集まるには、やはりXRP所有者であることがエンジニアとしての責務を果たす動機になるのだと思い、それを参加条件にしました。

テストネットでXRPは容易に手にいれることができます。 なので、XRPを勉強するついでに入手するといいと思います。

仕組み

Metamaskを代表とするブラウザの拡張機能がすでにあればいいのですが、なかったので直接RippleのLedger Testnetに問い合わせています。 その結果を元に招待を送るか否かを判定しています。

かなり簡単なので、放課後ハッカソンみたいなモチベでやりました。

余談にもありますが、あくまでもPHPを使って何かがしたかっただけです。笑

最後に

Rippleは個人的にはEthereumにも、Bitcoinにも似てもいない暗号通貨だと思います。 (技術起因による)命名法から、組織体制、コンセンサスアルゴリズムなど、、、

個人的なことですが、ちょうど最近Bitcoin, Litecoinのサービス開発の受託開発やEthereum上でトークン発行、スマートコントラクトによるアプリ(iOS, Rails)などをし終わって、Ripple開発に着手しました。

もっと日本で文献や知見が増えるためにも、このコミュニティがその背中を押せるようなものになれればいいと願っています。

余談

本サイトはセキュリティ運用やハッキング手法の勉強のためにPHPで作りました。 PHPは人気はないものの、20年間の歴史があって、いたるところに使われています。

Web サイトのサーバー・サイド 82.3%* で PHP が使用。 また PHP ベースの WordPress は、全サイトの 27.2% で利用中。(引用:今学ぶべきプログラミング言語ランキング【2018最新版】)

今まではC/C++, Golang, Ruby, Python, HTML, CSSがメインでしたが、PHPも活用していきたいです。

->リップル開発者コミュニティ

綿矢りさ「蹴りたい背中」が読みたくなる痺れるフレーズ集

自分が2017年読んだ小説の中でトップ3に入るくらい面白かったので紹介します。 「いまさら?」って思うかもしれませんが、大人になってから読むと何倍も楽しめたので、ぜひ皆さんにも読んでみてほしいです。

蹴りたい背中 (河出文庫)

蹴りたい背中 (河出文庫)


綿矢りさとは

Wikepediaによると、綿矢りささんは京都府京都市生まれです。 現在(2017年12月時点)で33歳です。早稲田大学教育学部国語国文科卒業です。

彼女が一躍有名になったのは「インストール」でで第38回文藝賞受賞してからです(当時17歳)。その二年後にこの記事で取り上げる「蹴りたい背中」で芥川賞を受賞して、ミニオンセラーになるなど反響を及びました。

「蹴りたい背中」とは

周りの人間とどうも自分は違う生き物のように感じる主人公が、同級生のオタクであるにな川との交流を沸き立つ、淡い青春を描いています。 この本は、2003年、当時著者が在学中には単行本が刊行されて、第130回芥川龍之介賞を受賞しました。

あらすじ

理科の授業で仲間外れにされたハツは、同じ班のにな川が読んでいる女性ファッション誌のモデル(オリチャン)に目がとまる。ハツは中学生のとき、隣町の無印良品でオリチャンに会ったことがあり、そのことを言うとにな川は興味を持つ。放課後彼の家に呼ばれ、そこでにな川がオリチャンの大ファンであると知る。後日ハツはにな川に頼まれ、オリチャンと会った無印良品へ向かう。そしてにな川の家で休憩する二人だったが、ハツはオリチャンのアイコラ(にな川作)を見つける。ハツは異様な気分になり、にな川を後ろから思い切り蹴り倒す。

その後、にな川が学校を4日間休む。不登校ではないかと言われるも、ハツはにな川の家にお見舞いに行く。実はにな川は徹夜でオリチャンのライブのチケットを取ったため、風邪を引いたのだった。にな川はチケットを4枚買っており、ハツは誰か呼んで一緒に行こうと誘われる。友人は絹代しかいないので、仕方なく絹代を誘って3人でライブに行く。絹代がハツに「にな川はいい彼氏なんじゃないか」「ハツはにな川のことが本当に好きなんだね」と言うが、ハツは「自分の気持ちはそうじゃない」と思っていた。

ライブから帰ると、バスはもう出ていなかった。仕方なくハツと絹代はにな川の家に泊まる。ハツはよく眠れず、ベランダでにな川と話をする。にな川が「オリチャンを一番遠くに感じた」と言ってハツの方を背にして寝転がると、ハツはにな川の背中を蹴ろうとする。指が当たったところでにな川が気づくが、ハツは知らないふりをする。(wikipedia)


読みなるフレーズ

私が勝手ながら、印象だった描写を列挙します。

  • 書き出し

      さびしさは鳴る。耳が痛くなるほど高く澄んだ鈴の音で鳴り響いて、胸を締めつけるから、せめて周りには聞こえないように、 私はプリントを指で千切る。 細長く、細長く。紙を裂く耳障りな音は、孤独の音を消してくれる。気怠げに見せてくれたりもするしね。葉緑体?オオカナダモ?ハッ。っていうこのスタンス。

  • 理科の実験で、自分の椅子が余り物の華奢ないすだった時

    余り者には余り物がしっくりくるのだ。いじめじゃない、ごく自然なことなんだ。

  • はじめてにな川に抱く違和感

    味噌汁の、砂が抜けきっていないアサリを噛みしめて、じゃりっときた時と同じ、ものすごい違和感が一瞬に通り過ぎていく。

  • 友人の友達グループのトランプに誘われて

    どうしてそんなに薄まりたがるんだろう。同じ溶液に使ってぐったり安心して、他人と飽和することは、そんなに心地いいもんなんだろうか。私は余り者も嫌だけど、グループはもっと嫌だ。

  • 陸上の部活動をしているときに思った顧問に対して

    人間に囲まれて先生が舞い上がる度に、生き生きとする度に、私は自分の生き方に対して自信を失っていく。

  • モデルであるオリチャンの雑誌を貪るように読むにな川に対して

    あんなに健康的なものを、よくこれだけ卑猥な目で見られますね。

  • ふと学校で誰にも気にすらされていないことを想って

    学校にいる間は、頭の中ですっと一人でしゃべっているから、外の世界が遠いんだ。

  • 最後ににな川の背中を蹴るハツ

    川の浅瀬に重い石を落とすと、川底の砂が立ち上がって水を濁すように、"あの気持ち"がそこから立ち上がってきて心を濁す。

まとめ

この本の描写は本当に面白くて、読みやすいです。

高校生のときに抱いてた無力感や淡い青春をストレートに描いています。 この冬休みに読んでみてはいかがでしょうか。

最後に好きなフレーズを。

話のネタのために毎日を生きているみたいだった。とにかく"しーん"が怖くて、ボートに浸水してくる冷たい沈黙の水を、つまらない日常の報告で埋めるのに死に物狂いだった。


おすすめの綿矢りさの他の作品

インストール(2001年)

インストール (河出文庫)

インストール (河出文庫)

夢を与える(2006年)

夢を与える (河出文庫)

夢を与える (河出文庫)

かわいそうだね(2012年)

かわいそうだね? (文春文庫)

かわいそうだね? (文春文庫)

JSON-RPC1.0と2.0

この記事はBlockChain Advent Calendar 2017 15日目の記事となっています。

非情報系の3年生なので、技術的に説明不足なことがあったらすみません。

招待制のウォレットを作ったので紹介させていただきます。 これは実験的に招待制にしたので、意味があるかないかはわかりません。

こちらがバランス確認ページです。

f:id:bobchan1915:20171215122514p:plain

そしてこちらが招待された場合のメールです。

f:id:bobchan1915:20171215122724p:plain

JSON-RPCはブロックチェーン開発では非常に重要な反面、JSONで普段開発しなれているので、新たに開発しなくてはいけないのではないかと怖がっている人を多く見かけます。

今回は記事が冗長にならない範囲で、JSON-RPCパッケージを作ったときの「JSON-RPC」に思ったことをお話しします。

開発内容

今回、私が開発したのは以下の通りです。

  • JSON-RPC1.0に対応したライブラリ
  • Bitcoin nodeと通信するためのライブラリ

これらを開発するにあたってJSON-RPCを学ぶことができたのでまとめます。

 JSONRPC2.0とは

JSONRPCの公式リファレンスはプロトコルの一種でRPC(Remote procedure call)の略です。 簡単にいうと遠隔からメソッドをサーバーで実行するものです。

例として以下のようなJSONRPCリクエストがあります。

{"jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42}, "id": 3}

具体的な仕様としては

  • jsonrpc: バージョンを指定(最新は1.0)
  • method: 実行したいメソッド
  • params:パラメータ
  • id:識別子

があるだけです。識別子があるのはどのリクエストに対してのレスポンス化を明確にするためです。

これを叩くと

{"jsonrpc": "2.0", "result": 19, "id": 3}

のようなresponseが返ってきます。

これは以下のような仕様になっています。

  • jsonrpc: バージョンを指定(bitcoindの最新は1.0)
  • result: レスポンスのjson
  • id:識別子

なぜJSONRPC2.0を使うのか

JSONRPCを使うのには以下の理由があります。 - RESTfulなサーバーを立てる必要がない - エンドポイントが非常に透明性が保たれる - メソッドを実行できるため「したいことをできるようになる」 などと行ったようなメリットがあります。

RESTfulなサーバーを立てる必要がない

私自身、Railsや他のRESTfulを意識したフレームワークを使ったことはありますが、

GET /new
POST /create
GET /show
...

などと少し面倒です。どれがGET、POSTで、どんなエンドポイントに何をroutingしなくてはいけないのか、、、 考えるだけで面倒です。ならば、JSON-RPCを使うと非常に便利になるのです。 以下のようなメソッドを実装するだけで以下のように簡単に実装ができます。

Endpoint              /user
methods              getName
                             createUser
                             updatePassword
...
{"jsonrpc": "2.0", "method": "getName", "params": {"user_id": 23}, "id": 3}

また、3回のリクエストが同時に来たとしましょう。

# Ayumiが
{"jsonrpc": "2.0", "method": "getName", "params": {"user_id": 23}, "id": 1}
# Kekeが
{"jsonrpc": "2.0", "method": "getName", "params": {"user_id": 23}, "id": 2}
# Tunakichiが
{"jsonrpc": "2.0", "method": "getName", "params": {"user_id": 23}, "id": 3}

レスポンスが以下の順で返ってきました。しかしながら、識別子があるので、どのリクエストに対応するレスポンスかすぐ知ることができます。

{"jsonrpc": "2.0", "result": "Tunakichi",  "id": 3}
{"jsonrpc": "2.0", "result": "Ayumi", "id": 1}
{"jsonrpc": "2.0", "result": "Keke",  "id": 2}

非常に便利なんです。 JSON-RPCの歴史までも知りたい人はwikipediaをご参照ください。

JSON-RPC1.0とは

JSON-RPC1.0はJSON-RPC2.0と比較して

  • jsonrpc:2.0といったようなバージョン指定がない
  • paramsは必須。2.0では無視可能.

などの特徴があります。 この規格にBitcoinは対応しているのです。

まとめ

JSON-RPCとは - POSTメソッドでmethodをJSONの中に組み込んで実行するもの - リモートでメソッドを実行できるので、RESTに従う必要がなくなる - JSONをHTTPリクエストで飛ばすところが非常に軽い実装になる

以上の理由より推奨されます。

誰もがつまづくDjangoをHerokuにデプロイするときあるある

はじめに

今回は「ツナキチ」というニューラルネットワークによる画像認識を用いて人間の顔が一体何% ネコっぽいのかを調べられるWebサイトを作りました。 時間がなくてsafariではデザインが崩れてしまってます。いずれ直します!) 明示的にHerokuでデプロイしていることを示したいので、リンクを貼らさせてもらいます。 https://tunakichi.herokuapp.com/

使ったバージョンは

  • python : v3.6.1
  • django : v1.11.7

です。

コメント、いいね大歓迎です。誤字や間違いは指摘していただけると助かります。

前提

ここではすでにアプリは完成していて、いまからデプロイするぞ!という方を前提にしています。 そしてデプロイをする上で、困ったことを紹介していきます。

デプロイ

pushする

まず、herokuのアプリケーションをherokuに登録しなければなりません。

heroku create <アプリ名>

で登録をすることができます。 一応、うまく繋がっているか確認してください。(これはgitとも接続されているか確認できるので初心者の人は使ってください。)

git remote -v

そして以下のように出ればおっけいです。

hogehoge:~/tunakichi[master]>> git remote -v
heroku  https://git.heroku.com/<リポジトリ名>.git (fetch)
heroku  https://git.heroku.com/<リポジトリ名>.git (push)
origin  git@github.com:KeisukeYamashita/<リポジトリ名>.git (fetch)
origin  git@github.com:KeisukeYamashita/<リポジトリ名>.git (push)

そしたら次にClearDBを作っていきます。簡単にいうとheroku上のDBです。

heroku addons:add cleardb:ignite

そしてherokuの環境変数を変更してください。

heroku config:set DISABLE_COLLECTSTATIC=1

ここでアプリ側の設定を変えなければなりません。wgsi.pyに以下に変更してください。

import os

from dj_static import Cling
from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "<アプリ名>.settings")

application = Cling(get_wsgi_application())

これで設定ができたので、pushすればデプロイできます。

git add .
git commit -m "hogehoge"
git push origin master
git push heroku master

確認

git push heroku masterのときにURLがすでに表示されるのですが、開くには以下のコマンドが便利です。

heroku open

またマイグレーションが必要な方は以下のコマンドでしてください。

heroku run python manege.py migrate

さらにシードデータがあるときはloaddataで入れることができます。 DjangoではJSONによるシードデータを入れる方法と、.YAMLによるシードデータの入れ方があります。

heroku run python manegy.py loaddata <シードデータファイル(JSONorYAML)>

これで再起動すると正しく動くはずです。

heroku restart

トラブルシューティング

[ケース1] herokuへのpushがrejectされるNo default Language

これはDjangoをデプロイしようとしている人の多くが直面する問題です。

原因

ディフォルトでなんの言語を使うのかを指定していないことが問題です。 herokuでは次のような言語がサポートされていて、簡単にいうとどの言語を使いますかという設定をしないといけない。

image.png

今回はPythonを使います。

解決策

まず、pythonのバージョンをruntime.txtに書き込みます。

echo $(python -V) > runtime.txt

次にローカルで使っているパッケージをherokuでも使いたいのでrequirement.txtに記載します。

pip freeze > requirement.txt

そしてpushすればリジェクトされないはずです。

[ケース2]無料枠の落とし穴。「たまに見ると落ちているんですけど、、、」

原因

herokuの無料枠では、30分間アクセスがなれけばスリープモードに入ってしまい、再起動が必要となります。

解決策

毎20分ごとぐらいにherokuに自分でアクセスしてもいいのですが、これを自動化しましょう。 デプロイしたWebサーバー自体が自分にアクセスするように組めばいいのです。

'<アプリ名>/wgsi.pyに以下を追加してください。

import os
import threading
import requests
import time


def awake():
    while True:
        try:
            print("Start Awaking")
            requests.get("http://hogefuga.herokuapp.com/")
            print("End")
        except:
            print("error")
        time.sleep(300)

t = threading.Thread(target=awake)
t.start()

これによって自分にアクセスするようになるので、サーバーがスリープになるようなことはなくなります。

[ケース3]変な名前のモジュールがない。No module name _tkinker

原因

これはグラフを書くのによく使われるmatplotlibライブラリに含まれるmoduleであり、これがherokuでインストールされていないことが原因です。

解決策

まずサーバーにmatplotlibを使うことはおかしいです。笑 (僕はローカルで使っていた数値計算アルゴリズムをそのまま.pyファイルとしてサーバーの計算部分に使おうとしたら勝手に混入していました)

なのでアプリ内の全import <Matploblib>を削除すれば解決できます。

[ケース4]ケース3の一般系。No module name hogehoge

原因

とあるhogehogeモジュールがないといっています。 これは抽象度が高いので、原因がいくつか考えられると思います。

原因1. そんなモジュールなんてない説

本当にそのモジュールがあるかを確認してください。 タイピングミスでmodule名が変わっていないですが?

原因2. herokuにインストールされていない説 ← 定説

ローカルで追加で開発をして、再度pushしたとします。 ローカル環境で新しくpipで導入したことをherokuは知りません。

なのでrequirement.pyを更新することが必要です。

pip freeze > requirement.txt

ScalaでMVCを構築する手順

はじめに

Scalaの超軽量フレームワーク「Scalatra」上でMVC構造を構築するまでを解説します。 Scalatraだけでなく、Scalaは記事が少なすぎる

タグを見るとわかるが、Scalatraに限って8です。

image.png

圧倒的少なさから入門もしにくいし、、、 そのせいで、普段はSwift,Go, Python, Rubyを書きますが、Scalaをやると非常に面白いが文献が少なかった。 なので今回はWebアプリケーション開発できるようにMVCを構築することから始めます。

ニーズ

自分は普段からRailsや、Django、Ginなどの「フルスタックフレームワーク」で開発をしたりしますが、MVC構造といってもあまりにも自由がないです。 Railsなんてブラックボックス化がひどいし、体験的なプログラミングをしてない気がします。

前提

本記事は以下のことを対象にしています。

  • すでにbstなどでビルトが済んでいる方

を対象にしています。

ディレクトリ構造

若干の違いはあるかもしれませんが、以下のようなディレクトリ構造をしているはずです。

src
├── main
│   ├── java
│   ├── resources
│   │   └── logback.xml
│   ├── scala
│   │   ├── ScalatraBootstrap.scala
│   │   └── com
│   │       └── example
│   │           └── app
│   │               └── ScalaServlet.scala
│   └── webapp
│       └── WEB-INF
│           └── web.xml
└── test
    ├── java
    ├── scala
    │   └── com
    │       └── example
    │           └── app
    │               └── MyScalatraServletTests.scala
    └── scala-2.12

初心者な私には、どこに何を配置したらいいのかわからなかったのですが、Goのpackageを思いました。 Packageとは、名前空間と覚えればオッケイ。

つまり、MVCにするならばpackageで区切ればよくて、次の問題はどのように明示的にMVCであることを透明性を保ったまま構築できるかです。

もちろんapp以下に構築するのがいいかもしれません。 先程のディレクトリツリーを抜粋して以下のように変更します。

src
├── main
│   ├── java
│   ├── resources
│   │   └── logback.xml
│   ├── scala
│   │   ├── ScalatraBootstrap.scala
│   │   └── com
│   │       └── example
│   │           └── app
│   │               └── ScalaServlet.scala
│   │               └── view
│   │               └── controller
│   │               └── model
│   └── webapp
│       └── WEB-INF
│           └── web.xml
└── test

ScalaServlet.scalaを中心に、MVCを構築すると透明性の高く、開発しやすいのでおすすめです。

golang+gormで画像をバイナリ化してDBに保存する

はじめに

過去に長期インターンでRubyonRailsをやっていたのでその経験も活かして記事にしました。 はてなブログ記事

やりたいこと

今回は自分のプロフィール(冬仕様)であるこの画像をバイナリ化してDBに保存しようと思います。(184MB)

この記事はRuby on Rails(RoR)を例にしてあげますが、全く理解できなくてもスルーしても読めるようにしたいとは思っています。

今回使用したVersionは以下の通りです。

  • Golang 1.9.1
  • gorm 0.6.3
  • Ruby on Rails 5.0.3(参考用)

より良い記事にしたいので 誤字や間違いがありましたらコメントなどをいただけると幸いです。

方針

Ruby on Railsが、やすやすとここらへんを実装していて、自分も実装経験があるので、参考にしながら進めていきますが Railsはあくまでも比較のためにあるだけなので、さらっと読みたい人はGolang部分だけを見てください。

文法的なことはあまり解説しませんがコンタクトしてくださればわかる範囲で答えます!

実装

DB

この記事では明示的にファイルを示したいのでオブジェクトをFileと名前をつけます。 命名法に違和感を抱く人がいたらすみません。

Railsでは以下のように書いて、ActiveRecord(Ruby製のORM)に働いてもらいます。

class File < ActiveRecord::Migration
  def change
    create_table :files do |t|
      t.binary :upload_file
      t.timestamps
    end
  end
end

なんですがupload_fileがRubyでいうbinaryでDBに書き込まれます。 正直、ORMは仲介人くらいなんでどうでもいいです。要はDBにどんなデータ型で保存されるかが重要なんです。

実際に見てみると(create_atなど省略しています)

Field Type Null Key Default Extra
id int(11) NO PRI NULL auto_increment
upload_file mediumblob YES NULL

となってました。 つまりupload_fileの方はmediumblob(8bit整数)。 これ[]byteと同じ???!!! だってgoでは[]byteと指定するとVARBINARYというデータ型になり、MySQLでは等価だからです。(※厳密には違う) []byteとは[]uint8のaliasです。詳しくは以下リンクで。 https://stackoverflow.com/questions/22950392/difference-between-uint8-byte-golang-slices

では、どのようにしたらbinary fileにできるのでしょうか? ちょっとその前に、これを実装するために、データベースを作るためのdb.goを用意しておきます。

package main

import (
  "os"
  "log"
  "fmt"
  "encoding/binary"
  "image/jpeg"
  "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
  "bytes"
)

var db *gorm.DB

type File struct {
    gorm.Model
    Source             []byte  
}

func init(){
  db, err = gorm.Open("mysql", "host:hogehoge@mysql/database")
    if err != nil {
        panic(err)
    }
  f = &File{}
  db.CreateTable(f)
  defer db.Close()

これを以下のコマンドで実行し、データベースを作成します。

$ go run db.go

データベース内容

Field Type Null Key Default Extra
id int(11) NO PRI NULL auto_increment
upload_file VARBINARY YES NULL

ImageのBinary化

 最初に

JPEGを画像を扱うためimage/jpegがありますが、この他に標準ではGIF,PNGに対応しています。 この他の拡張子を使う場合は、他にパッケージを使うしかないようです。

Railsでは<form>によってアップロードされたファイルはActionDispatch::Http::UploadedFile クラスなのでReadメソッドで読んでDBに保存すればよかったのですがGolangではどのような感じでしょう。

ディレクトリ構造は以下のようになっています。

.
├── db.go           ← DB作成用
├── image.JPG  ←プロフ画
└── main.go    ← 実行フィアル

以下にコードを示します。 また、最終的なコードはこの記事の最後に書いています。

    file, err := os.Open("image.JPG")
  if err != nil {
        log.Fatal(err)
    }

  img, err := jpeg.Decode(file)
  if err != nil {
      log.Fatal(err)
  }
  file.Close()

  buffer := new(bytes.Buffer)
    if err := jpeg.Encode(buffer, img, nil); err != nil {
        log.Println("unable to encode image.")
    }
  imageBytes := buffer.Bytes()

  f := &File{Source:imageBytes}
  db.Create(u)

解説

それではすこし解説をします。

まず開きたい画像ファイルのパスをPATH部分にいれてos.Open(<PATH>)で開きます。 問題なくいくと*os.File型の戻り値が返ってきます。

    file, err := os.Open("image.JPG")
  if err != nil {
        log.Fatal(err)
  }

次にimage/jpegDecodeメソッドを使ってimage.image型の変数を作ります。 なぜこのimage.image型を作るかというと、あとにエンコーディングをするときに必要だからです。

また、ここで注意したいのはかならずfile.Close()をやってください。

  img, err := jpeg.Decode(file)
  if err != nil {
      log.Fatal(err)
  }
  file.Close()

そしてファイルを生成してください。 同じくout.Close()をすることを忘れないでください。

そしてbytesでバッファを扱うための便利なパッケージがあります。bytes.Bufferは書き込み用のインターフェイスを持っています。 newbyte.Bufferを初期化して、imgがもつimage.image型の変数をともにjpeg.Encodeに渡しています。

  buffer := new(bytes.Buffer)
    if err := jpeg.Encode(buffer, img, nil); err != nil {
        log.Println("unable to encode image.")
    }
  imageBytes := buffer.Bytes()

json.Encodeをなぜこのようにするかというとリファレンスを読んでみたらすぐわかります。

func Encode(w io.Writer, m image.Image, o *Options) error

byte.Bufferは書き込み用のインターフェイスio.Writerを持っているのでわたすことができます。 そして、もとの[]byte型はBytes()で取得できるのでimageBytesに変換することができます。

imageBytes := buffer.Bytes()

そしてこれを構造体に渡してDBに保存して終了です!

f.Source = imageBytes
db.Create(f)
db.Close()

これでこの記事終了です! お疲れ様でした!!

終わりじゃない、、、

というもの、まだ問題が残っています。 それはこのままでは動かないのです。

ERROR 1406 (22001): Data too long for column 'source' at row 1

実は今回のbinaryは長すぎるのです。 というもの、冒頭で、「VARBINARYMIDDLEBLOBは等価だ!Rails通りだぜ!」みたいなことを書きました。

しかし、ここにきて痛い目に合うのです。 データの大きさが鍵となっています。

余談(Blob型の歴史)

もともとMySQLではバイナリ型はblob型で一括してまとめてました。(たしか5.0.7ぐらいまで) しかしバージョンが上がると、VARBINARYVARCHARが出てきました。 MySQL公式ドキュメントから参照しています。

image.png

簡単な乗数の計算ですがだいたいblob型の大きさは

  • TINYBLOB:255B
  • BLOB:65,535B
  • MIDDLEBLOB:16MB
  • LONGBLOB:4GB

であり、VARCHARVARBINARYはというと255Bです。 到底足りません。

解決する

話をもとに戻します。

データのSizeに原因があることがわかりました。 冒頭のこの部分に注目してください。

スクリーンショット 2017-11-19 5.23.45.png

到底足りません!LONGBLOB型が必要です

Railsのときは指摘してなかったじゃないか!と思われるかもしれませんが、その通りで、勝手にデフォルトでなっていました。 Railsに親しい人は当然だと思いますが、実は:limit => 3.gigabyteとして指定してすることで、今回の場合でいうとLongBlobに変更することができるのです。

class File < ActiveRecord::Migration
  def change
    create_table :files do |t|
      t.binary :upload_file, :limit => 3.gigabyte
      t.timestamps
    end
  end
end

同様にgormにだってできます。 gormは構造体をマッピングするという特徴があるので、構造体をいじればどうにかなりそうですよね。 実際もそうで指定したいメンバにgorm:"size:70000などとしてあげるとLONGBlOBに変わります。

type File struct {
    gorm.Model
    Source             []byte    `gorm:"size:70000"`
}

このようにしてSizeを変更できたので最後に実行して終わりです。

$ go run main.go

DBを確認すると人間には優しくない文字列がありますが、それがバイナリです。 最後までお読みしてくださりありがとうございました。 お疲れ様でした。

ソースコード

package main

import (
  "os"
  "log"
  "fmt"
  "image/jpeg"
  "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
  "bytes"
)

type File struct {
    gorm.Model
    Source []byte `gorm:"size:70000"`
}

func main(){
   db, err := gorm.Open("mysql", "host:hogehoge@mysql/database)
    if err != nil {
        panic(err)
    }
    defer db.Close()

  file, err := os.Open("image.JPG")
  if err != nil {
        log.Fatal(err)
    }

  img, err := jpeg.Decode(file)
  if err != nil {
      log.Fatal(err)
  }
  file.Close()

  buffer := new(bytes.Buffer)
    if err := jpeg.Encode(buffer, img, nil); err != nil {
        log.Println("unable to encode image.")
    }
  imageBytes := buffer.Bytes()

  f := &File{Source:imageBytes}
  db.Create(f)
  db.Close()
}

そしてrunすると実行できます。

go run main.go

余談

最近後輩がこの本を読んでいました。 実際、python以外はプログラミングの本を読んだことがないので、そろそろ読まないとなって思います。

スターティングGo言語

スターティングGo言語