Pixela をSlackにつないで遊んでみた

小ネタ。
昨日が〜〜〜っとコーディングして、寝て、起きたのでブログです。

土曜日くらいから、たまたまSlackを題材にJSのお勉強!をしていて(それについては別途書く)、おもしれ〜少しわかってきたぞ〜〜となり、「他になにか作ろう〜〜」って気分でいたのですが、Twitterを眺めていたらあまりにもpixelaが盛り上がっていたので勢いで作ってみました。

blog.a-know.me

やったこと

Slack上で

  1. ユーザー登録ができて
  2. グラフの新規作成ができて
  3. グラフのインクリメントができる
  4. グラフ一覧も取得できる

必要最低限、って感じ。機能を絞ってインターフェイスをシンプルにした感じのv0.1。

ユーザー登録

  1. @bot pixela me とダイレクトメンションしたら起動
  2. tokenを自動生成する
  3. POST /v1/users を叩く
  4. SlackのユーザーID、Pixelaのusername,tokenを紐づけてDBに保存しておく
  5. 処理完了後、発話者のみ見える形でusername,tokenをSlack上に通知

この「SlackのユーザーIDと紐づけて格納して、実際のサービス(Pixela)のアカウント情報を隠蔽する」ってやり方が、何ともチャットbotぽいな〜とか思ったり。

イメージ

f:id:o0h:20181016124952p:plain

シーケンス

f:id:o0h:20181016125234p:plain

グラフ登録

  1. @bot pixela new とダイレクトメンションしたら起動
  2. 発話者のSlackユーザーIDをもとに、DBからPixela登録情報を引っ張ってくる
  3. conversationのセッションを開始
    • 対話的に「グラフID」「グラフ名」を入力する
    • グラフの詳細なオプション(色、単位、値の型)は現状だと省略。shibafu/cnt/intに固定
  4. POST /v1/users/<username>/graphsを叩く
  5. 処理完了後、登録された情報をリプライ

イメージ

f:id:o0h:20181016133859p:plain

シーケンス

f:id:o0h:20181016131700p:plain

インクリメント

  1. @bot pixela ${グラフID}++ とダイレクトメンションしたら起動
  2. 発話者のSlackユーザーIDをもとに、DBからPixela登録情報を引っ張ってくる
  3. PUT /v1/users/<username>/graphs/<graphID>/increment を叩く
  4. 処理完了後、操作対象となったグラフのURLをリプライ

イメージ

f:id:o0h:20181016132001p:plain

シーケンス

f:id:o0h:20181016131933p:plain

グラフ一覧

  1. @bot pixela list とダイレクトメンションしたら起動
  2. 発話者のSlackユーザーIDをもとに、DBからPixela登録情報を引っ張ってくる
  3. GET /v1/users/<username>/graphs を叩く
  4. 処理完了後、登録されているグラフの一覧をリプライ

イメージ

f:id:o0h:20181016132231p:plain

シーケンス

f:id:o0h:20181016132338p:plain

やっていないこと

概ね「対応してないエンドポイント」「対応していないパラメータ」も面白く使えるようにしたい・・というのがほとんど。 あとは、SVG to PNGを行うためのサーバーを自前で持つか何かをしたら、インクリメント後とか、サムネイル出せるようになるよな〜絶対にそのほうが楽しいよな〜という気持ち。。

あとは、グラフの登録のところ、ひっさびさにBotkitのconversationを使ってみたけどイマイチ・・・Interactive componentにしてフォームで入れたほうが便利っぽいな。

感想など

何個かSlackのbotを作っていて、「いまいち使う楽しさに欠ける」というのはインターフェイスの問題な事が非常に多いなと思っています。要するに「呼び出し方がわからない」「フォーマットが複雑」など。そこに関して、今回は 「私にPixelaを使わせろ!」という意味の me でアカウント登録、ほとんど"graph"がすべてのサービスにおいて「新しく始めるよ!」という意味の new で新規作成、 ++ でインクリメント・・・と、だいぶシュッとしたコマンドをデザインできたかな?という気持ち。

サービスを触っていて思ったのは、単機能&RESTFulなAPIデザイン素敵すぎる。ほとんどドキュメントは流し読みで、実際に動くところまで行けた!!というのが最高の体験でした・・・

正直、最初に見た時に「草が生えるよ!」というサービスって嬉しいか・・?とピンと来てなかったのだけど。数時間後に開いたTwitterで、たまたま別のツイートが目に入ってきて、「Slackに結びつけたら面白いかも?」と思ってから一気に書きました。
「とりあえず動かしてみたら面白いんじゃねwww」くらいのノリでさくさく〜っとマッシュアップできるサービスとかアイディアっていうのはストレス解消に良いですね・・・👼

今のとこ会社のSlackに置こうとしているだけだけど、もーちょい汎用化できたらOSS化するのはアリだよな〜とか。Storage周りどうしよーっていうとこだけ悩まし。
とりあえず、今やりたいのは「運動習慣をつけたい人たちが、運動をしたら報告するチャンネル」があるので「運動したら草を早そう」を盛り上げたいw

Botkit middleware を作ってみる作業メモ②

続き。

やること

  • [x] modern JavaScript なプロジェクトをセットアップしてみる
  • [x] Botkitアプリケーションに対して外から入れるような形のモジュールを作ってみる
    • Botkit middleware
  • [x] ローカルでのyarnを介したモジュール開発をしてみる
  • [ ] npmに登録してみる
  • [ ] サンプルアプリケーションを作成してみる
  • [ ] Deploy to Heroku で簡単に触って見られる、という感じにしてみる

第3章: npmへの登録

やっていきましょう。前回のステップでも大変お世話になった記事、続きを読んでいきます。

liginc.co.jp

「ソースはgit管理させつつ自動生成された最終成果物はgit管理させない、最終成果物はnpmに登録させつつソースは登録させない」か。そのためにbuildとprepublishが必要〜と。。

コマンドはrollup.jsの公式に載っている例をそのまま、で良い・・かな? f:id:o0h:20181014181825p:plain

ということで、

diff --git a/package.json b/package.json
index 02a630d..e7121b7 100644
--- a/package.json
+++ b/package.json
@@ -5,6 +5,8 @@
   "main": "dist/index.js",
   "scripts": {
     "watch": "rollup -cw",
+    "prepublish": "rollup -c --environment INCLUDE_DEPS,BUILD:production",
+    "build": "rollup -c --environment INCLUDE_DEPS,BUILD:production",
     "test": "echo \"Error: no test specified\" && exit 1"
   },
   "repository": {

こんなんでいいのかな。

qiita.com docs.npmjs.com

Additionally, everything in node_modules is ignored, except for bundled dependencies. npm automatically handles this for you, so don't bother adding node_modules to .npmignore.

なのね。なるほど。

あとは、「タグを打ってgithubにpushしてnpmにpublishする」っぽい。

docs.npmjs.com

npm version patch
git tag
git push -f
git push origin v0.0.2
npm publish

やった〜〜〜!🎉🎉 f:id:o0h:20181014183529p:plain

READMEとか、あとでちゃんと整えよ・・・

publish打ったときに、

npm WARN prepublish-on-install As of npm@5, prepublish scripts are deprecated

と言われたのだけど。気になって調べてみたら、なんだか面倒くさいんですね・・・

qiita.com これもどっかしらで。

ひとまず、これで公開された!ということで、ローカルのパッケージを正常な状態にしてみる。

  • yarn unlink botkit-hashtag
  • yarn add botkit-hashta

ls打ってみたらちゃんと入ってるな〜〜!嬉しい。yarn.lockとかrollup.config.jsもnpmignoreしちゃっていいのかな?

$ ls -l node_modules/botkit-hashtag
total 192
-rw-r--r--  1 hkinjyo  staff   1070 10 14 18:49 LICENSE
-rw-r--r--  1 hkinjyo  staff     53 10 14 18:49 README.md
drwxr-xr-x  4 hkinjyo  staff    128 10 14 18:49 dist
-rw-r--r--  1 hkinjyo  staff   1323 10 14 18:49 package.json
-rw-r--r--  1 hkinjyo  staff    288 10 14 18:49 rollup.config.js
-rw-r--r--  1 hkinjyo  staff  81303 10 14 18:49 yarn.lock

第4章: サンプルアプリの作成 & deploy to heroku

ローカルでbotkitアプリを作りながら作業を進めてきていたので、それを少し整える。

  • yarn add botkit botkit-hashtag

あとは、dev系のツールは基本的にbotkit-hashtagと同じでいいかな〜という感じで。ただ、(楽をするために)勤め先のeslint-configに乗っかりたいので、依存するモジュールを足しておく

  • yarn add eslint-plugin-flowtype eslint-plugin-react

アプリケーションの内容は、 src/index.js に数行書いて終わりになりそ〜

そしてもう最後の山場?となる、Deploy to Heroku buttonである。

devcenter.heroku.com

今回でいうと、やりたいことは

  • 初回インストール時にENVの指定を案内できて
  • yarnで依存を解決できて
  • nodeアプリケーションを起動できて

くらいかなぁ。大したことがない! 👼
そういう観点で、 app.json の設置と一部 package.json の修正を加えて。

・・・で、ここで結構ハマったのだけど 基本的な事しかしないのであれば、package.jsonにだけ書いておけば十分に動くので、app.jsonのscriptsは必要なかった みたい。
基本的なこと => 要するに、

{
  "scripts": {
    "build": "rollup -c --environment INCLUDE_DEPS,BUILD:production",
    "start": "node dist/index.js",
    "postinstall": "yarn run build",
  }
}

あたり。これらを用いて、良しなにビルド&スタートしてくれた。app.json側にも同様に start などの動きを指定できるのだが、中途半端に使おうとしたためか、デプロイに失敗して暫くハマってしまった・・

formationの変更

ここまでで、ひとまずデプロイまではうまく行った・・・のだが、少し時間が経つと反応しなくなる。
ログを見る。

  • heroku logs -t --app $HEROKU_APP_NAME

Web process failed to bind to $PORT within 60 seconds of launch

と書いてある。
たどり着いたのがこの文書で、「あーたしかにworkerにしたほうが良いよね〜webで起動しているのにweb用のポートの待受ができていないよ!!」っていう理屈で落ちるのか、と。

[Slack]Botkitをherokuの無料プランで動かす方法

app.jsonの formation 、Procfile辺りが関係しそう。うまきゃって「workerだけ動かす」ができれば最高。

Platform API Reference | Heroku Dev Center

・・・なのだが、暫くハマってみて解決できなかった。。。*1

で、気持ち悪いのだけど「無理やりwebサーバー起動してしまえばいいのか」っていう発想の転換。会社で使っているbotkitベースのアプリケーションにはworkerの利用などの様子が見られず、なんで大丈夫なんだ?というところから得た解法。

index.jsを修正する。

diff --git a/src/index.js b/src/index.js
index c1f3d28..53014f3 100644
--- a/src/index.js
+++ b/src/index.js
@@ -3,6 +3,7 @@ const controller = botkit.slackbot({ debug: process.env.DEBUG })

 require('botkit-hashtag')(controller)

+controller.setupWebserver(process.env.PORT || 3000, (err, webserver) => {})
 controller
   .spawn({
     token: process.env.SLACK_TOKEN

いやー・・・👼

とりあえず動くようになりましたよ!

作業メモとしてはここらへんまで。

残タスクとしては

  • npmモジュールちゃんとする。いい感じにREADME入れる
    • botkitのmiddlewareでテスト書いてあるやつないかな〜参考になるのがあればちゃんとしたい
  • app側も使いやすくする。機能紹介+step-by-steoの導入を作る。qiita辺りかなー

*1:「webじゃないからか」という点に至るまでに、そもそも時間を要していて、そこからの「formationが組めないなぁ」の絶望たるや・・・何が悪いんだろうか。やり方は確実にあると思うのだけども。

Botkit middleware を作ってみる作業メモ

やること

  1. modern JavaScript なプロジェクトをセットアップしてみる
  2. Botkitアプリケーションに対して外から入れるような形のモジュールを作ってみる
    • Botkit middleware
  3. ローカルでのyarnを介したモジュール開発をしてみる
  4. npmに登録してみる
  5. サンプルアプリケーションを作成してみる
  6. Deploy to Heroku で簡単に触って見られる、という感じにしてみる

きっかけ

そこそこお久しぶりな方から、Slackにハッシュタグ的な「ゆるく情報をまとめる方法」が欲しかった話 - コネヒト開発者ブログをみて、「今まさにこういうの欲しいのですがーーーーー」的なご連絡をいただきまして、自分が作ったり発信したりした何かに興味を持ってもらって & ましてや、ソレをきっかけにリアルグラフ内からのご連絡を頂戴するなど技術者冥利に尽きるなガッハッハ!という事で、テンションが上がってしまいましたとさ。

ただ、実装詳細についてはポイントポイントでスニペットをつけてはいるものの、 普段からslack apiやbotに触れている〜〜みたいな人でもない限り、これを「ゼロから自分でコードに落とす」みたいなのは確かに面倒臭そう。
自分のアイディアなので使ってもらえたら嬉しいな〜とは素直に思いつつ、どうやって手にとってもらうかな〜が悩まし、いっそコード晒すか!!ってなりました*1

序章: やり方を考える

〜botkitに組み込むポータビリティの高いパッケージ管理とかあるの?〜

せっかくなら、メンタビリティを損なわないような形をとりたい。疎結合、外から注入できる必要がある。プラグイン的な機構が必要。 f:id:o0h:20181013185417p:plain

で・・ botkit.ai

あるじゃん!

botkitのサイトにもリンクされていたGitHub - shishirsharma/botkit-mixpanel: Botkit plugin for Mixpanel analytics https://botkit.aiとかは、題材的にも自分の身近感あるし参考になりそう。

ああ、なんかここまで調べてるうちにコレは自分にとってすごい楽しいオモチャなのでは・・って気持ちが湧いてきた。compsor plugin, redashのquery runnerに並ぶような。。

第1章: まずはlocalでbotkitを立てましょう

ミドルウェアの概念を理解して実装をしたいのだけど、とにかくまずは開発環境の構築だ。

  • yarn add botkit
  • eslint周り + prettier をyarn add
    • 関連設定ファイルは、会社のJS強い人が書いているやつをそのまま参考にする
    • ぷりてぃあ〜使える安心感たるやすっごい・・・

ビルドツール

うげ〜〜JSわからんのだよ〜〜〜っていう苦手意識が強いので、「パッと入れてガッと動く」と噂に聞くparcelを使えばいいのかな?と思って試してみた。

・・・のだけど、会社のJSに強い人に聞いてみたら、「今回の目的からすればrollupでないかい!」と。マジか。設定ファイル書きたくないんだけど。調べてみる。

f:id:o0h:20181013202636p:plain

なるほどなるほど。ググって出てきて参考にした記事。

最小構成で始めるRollup.js - コンパイラかく語りき

神がいる、ありがとうございます。

rollup.js ふむふむ。

あと、ついでに「本当に必要最低限な.babelrcについて教えてください」と前出の人に問うた結果、 @babel/preset-env はあったほうが良さそうだったので入れる。
それに加え、「モジュールの読み込みがうまくいかない・・・」ってハマった。

  • npmでインストールしたもの = node_modules以下を使えるように node-resolve が必要
  • 自分で書いたものなどを使えるように commonjs が必要

ココらへんの知識の無さを痛感するなぁ。。。参考にした記事。

最終的にこんな感じ

  • yarn add --dev rollup rollup-plugin-node-resolve rollup-plugin-commonjs rollup-plugin-babel @babel/core @babel/preset-env

.babelrc

{
  "presets": [
    ["@babel/preset-env", {
      "targets": { "node": "current" },
      "useBuiltIns": "usage"
    }]
  ]
}

rollup.config.js

import commonjs from 'rollup-plugin-commonjs'
import resolve from 'rollup-plugin-node-resolve'
import babel from 'rollup-plugin-babel'

export default {
  input: 'src/index.js',
  output: {
    file: 'dist/index.js',
    format: 'cjs',
  },
  plugins: [resolve(), commonjs(), babel()],
}

これでいいのかな? ついでに、package.jsonにscriptsを追記しておく

  "scripts": {
    "watch": "rollup -cw"
  },
  • yarn run watch
  • node bot.js

f:id:o0h:20181013222223p:plain

無事に動いた。

ちなみに、動かしたスクリプトの内容は以下。

第2章: npmモジュールを作成してみる

「ミドルウェアの概念を掴んだり実際に機能実装をやろうかな?」と思ったのだけど、強い人の声。

f:id:o0h:20181013222717p:plain

なるほど・・?そういうのがあるなら、手戻りなく「最初からbotkitのappからスタンドアロンにして作ってしまおう」ができるかもしれない。
概念がよくわかっていないので調べる。

yarnpkg.com

お、なるほど〜。
このあたり、PHP(composer)だとtypeをsrcにしてレポジトリは直接ローカルを指定〜とかやるけど、それよりもシュッとしたやり方?それとも、無用な抽象化でまどろっこしい?どっちなんだろ〜、という感想。いずれにせよ思想の違いを感じて面白いな!!

ということで、
現状のディレクトリ構成がこう。

- hoghoge-ws
    - botkit-hogehoge
    - app

いつもそうなんだけど、プラグインとかモジュールとか作るときは「ws: workspace」ディレクトリを掘って、その配下に実際に公開されるgitレポと合わせた名前でモジュール本体のディレクトリ & 被検する「app」ディレクトリをおく、というやり方をしてる。

ということで、とても簡単にできそうなので、まずは「パッケージ化するためのもろもろ」からですな〜

npmモジュールとして登録するための諸々を行う

qiitaの記事で流れを掴みつつ、 qiita.com

「実際に公開されているミドルウェア」で構成だったり記述内容を学ぶ感じで行けるでしょうか。

www.npmjs.com

最低限の構成と思われるものを整えた。

$ git diff --name-only HEAD~~

.babelrc
.eslintrc
package.json
rollup.config.js
yarn.lock

で、 yarn link ・・・

$ yarn link
yarn link v1.9.4
success Registered "botkit-hashtag".
info You can now run `yarn link "botkit-hashtag"` in the projects where you want to use this package and it will be used instead.
✨  Done in 0.20s.

お〜!なるほどね。 これを食うようにしてみる。

$ cd ../app
 $ yarn link botkit-hashtag
yarn link v1.9.4
success Using linked package for "botkit-hashtag".
✨  Done in 0.15s.

$ ls -l node_modules | grep hashtag
lrwxr-xr-x    1 hkinjyo  staff     20 10 14 00:29 botkit-hashtag -> ../../botkit-hashtag

ほうほう。とりあえず、「簡単なオウム返しなミドルウェア」を作ってみよう。
botkit-mixpanelを見ると、

  1. module.exports = function(controller, options) {} のクロージャを作って、その中でcontrollerをゴニョゴニョしている
  2. readmeをみると require('botkit-mixpanel')(controller, {mixpanel_api_key: process.env.MIXPANEL_API_KEY, debug: true, always_update: true}); 的な感じで食わせている

なるほど〜。
これでやっと、「ESどうやって書くの・・・」な世界から抜け出してbotkitな世界に進める。

Middleware Endpoints。

botkit.ai

公式のスニペット

// this example does a simple string match instead of using regular expressions
function custom_hear_middleware(patterns, message) {

    for (var p = 0; p < patterns.length; p++) {
        if (patterns[p] == message.text) {
            return true;
        }
    }
    return false;
}


controller.hears(['hello'],'direct_message',custom_hear_middleware,function(bot, message) {

    bot.reply(message, 'I heard the EXACT string match for "hello"');

});

あ、ちょっとAPIの形が違うのね。って思ったけど、 controller には変わりないよね。一旦試してみよう、さっき雑にapp/src/index.jsに書いていたreplyをこっちに移してみる

// botkit-hashtag/src/index.js
module.exports = (controller, options) => {
  controller.hears('hello', ['direct_mention'], (bot, message) => {
    bot.reply(message, 'Hello my friend!');
  });
};

// app/src/index.js
const botkit = require('botkit')
const controller = botkit.slackbot({ debug: true })

require('botkit-hashtag')(controller, {})

controller
  .spawn({
    token: process.env.SLACK_TOKEN
  })
  .startRTM(function(err) {
    if (err) {
      throw new Error(err)
    }
  })

f:id:o0h:20181014005003p:plain

おお〜〜、ちゃんと動いた〜〜〜!

  • When hearing a message
  • When matching patterns with hears(), after the pattern has been matched but before the handler function is called

ってあるから、ミドルウェアに関しては特別なのかもしれない?


あとは、実装は愚直に。しかしprettier最高すぎるな・・
このエントリーは一旦ここまで!折角だし、もっとミドルウェアっぽい機能を作ってみたいな。楽しそう

*1:いっそコーヒーでも奢ってもらいながらコーディング&インストールでもペアプロでもするか・・?とかよぎったけど、口実つけてお喋りしたがるムーブに自分の中のおっさんを感じた

フレームワークとどこまで骨を埋めるか問題 ( #phpgenba を聞いて)

問題〜とか言いつつ何も答えが出てない、どころかissueを見定められてないけど。ただの散文です。

#phpgenba を聞きまして。

php-genba.shin1x1.com

「フレームワークとの付き合い方」というトピックがありました。
これについて。正解もないし、良い視点で主張や議論ができるほどの経験値もないと思っているのだけど、まぁ「今の時点で感じていること」を言語化して残して置くことには面白い点もあると思うので。

「どこまでフレームワークの機能を使うか」「(自身で層を敷いて)線引き、責務分離をした上で付き合った方が辛くなりにくい」という話がありました。
DDD、クリーンアーキテクチャの立場から「実装と詳細の分離」という思想と捉えて良いのかな。

その感想を、今の自分なりに。
なお、ここでは「チームで開発する」とした時の「価値」を「自分だけでなく他人も書きやすい・読みやすい・分かりやすい」こと、と定義して思考します。
それを支える要素としては、

  1. PJ全体を通じてブレがない
  2. 具体的なプラクティスやディスカッションを多く仕入れやすい

というのがあると良いな、と思います。

さて、個人的には フレームワークを使うと決めたら、骨の髄までその流儀に乗っかって、旨みを享受する方が美味しい のでは、という立場。*1

支払った学習コストに対して横展開がきくので、少なくとも短期的にはスピードが出る。新規者において、公のソース*2から得られる情報の大きさゆえの学びやすさからだし、同じ理由で、既存メンバーからの指導のしやすがあるから。
この辺りは分かりやすいから良いにしても、自分なりに疑問なのが「フレームワークにロックインされる」ことがどれくらいリスク足り得るか?について。

podcast中で「新しくバンバンwebサービスが立ち上がって行くフェーズから、数年経ったプロジェクトやコードベースをお世話する場面が増えてきた。その背景があって、DDDやクリーンアーキテクチャといった概念が注目されるようになっめきたのではないか」という観点。これは、なるほどなーと思い、賛成で。

他方で、「ドメインに関しては依存したくない」「こっちはフレームワークの機能を使わないレイヤー、というのを決めて置くとうまくいきやすい」のかな?という部分。*3

さて、自分の場合において、「今書いているコードが5年生き残った場合に、(フレームワークべったりか否かで)どっちが親切で説得力があるか」をどう考えれば良いか。

まず、自分が充分に経験を積んだアーキテクト足りえるか?は大きい気がする。要するに、「辛い体験」の経験不足。これは否定しようがないし、今はその「身の丈」で物事を考えなければいけない。
その上で、「世界中で使われているOSSの設計者やコミュニティのほうが、質の高い"良さ"を持っているはずだ」という公算が高かろうな〜と思うところで。
私が考えたデザインと、フレームワークそのものが、「5年後に生き延びていて、かつ良くメンテナンスされている」ことの期待値はどっちが高い・・?

プログラマーは、概して、その本質として「自分の力より高い次元のことを要求される」ものだよな〜とは時々思う。もちろん出来る範囲のことでしかできないのだけど、もし「もっと出来たら」もっと良いデザインや良いやり方で「正解」を出すだろうなーっていう。
そう考えると、「自分の持つ実力を出せる方法があれば、そうしたい」という欲求が生まれる。巨人の方に乗る方法があれば、そうするのが賢いと思う。

自分の中で「フレームワークにのっかり、しゃぶりつくす」というのはそのための方法論の1つ・・・そして、「他のフレームワークに移るときのコストが」という話についても、(今の自分の考えでは)「そのタイミングというのは、これまでの常識で太刀打ちできない要求の変化が起きた」というトリガーがあると想像する。
奇しくも、短いような短くないような職業プログラマ歴の中で、自分は前職と現職で1度ずつ「フルスクラッチの改修」に関わっている。その時に、既存コードの部品を流用しようとはならなかった*4。なので、「この機能を使っちゃうと後々困るかもね」という懸念で、「フレームワークのフルパワーを引き出しながら日々の業務に取り組む」メリットを殺しに行くかなぁ〜というのが、あまりイメージできないなーと。。。正確に言えば、「ここからは独自に」という線引きをするための知識・経験・センスが足りていない・・・のかな。

と、書きながら、程度問題は絶対にあるなとも思った。
それでもソフトウェア/フレームワーク以上のレイヤーで「よくある」かはまだわからないのだけど、例えばデータベースの移行はつらそうだなぁ。。
「mongoすごい!使おう!!」「スキーマレス最高!!多次元構造最高!!」「スケールしていったらつらみが・・」「乗り換えるか・・・?」とかは、一筋縄ではいかないだろうなぁ。


今の自分の武器に盲目的になることはせず、守備範囲内外へのアンテナを貼りつつ、良いもの・悪いもののどちらも正しく批判しつつ、使う道具にはリスペクトを持つ!!

というスタンスでいたい。

*1:数年後には揺り戻しが来るだろうな〜という予感はする・・あくまで、今においてはというもの。

*2:githubも、slackなどのチャットも、stackoverflowもqiitaも。「ググれば出てくる」こと。

*3:この流れで出てきた、「節度」「治安」というのは良い概念だな〜と思いました

*4:cake2 -> cake3の移行は、「同じフレームワークの移行」とは数えないのが正解な気がする・・概念等は共有されているので、キャッチアップについては下駄を履けるのだけど、コードをそのまま使えるか?は・・

herokuでphp動かすためのDockerイメージを組んだ

「herokuでDocker使えるよ」って言うから試そうとしたらハマった - 大好き!にちようび というものを書いたじゃないですか。 あれ以来、「一旦Container registryでやるの諦めてアプリケーションだけ書いちゃおう・・・」となり放置、さらに他のことに浮気をしたりが重なりアプリケーション自体も書いていなかったのですが。

他のことが消化されたり、というのもあったので「久々に作るかー」となり起動したのでした。

で、結論、できた。

ということで、かなり参考にさせていただきつつphp72のものを組めた。今の所、php:7.2-fpm-alpineをベースとしてnginxを足した感じ。

o0ho0h/heroku-php72-fpm - Docker Hub

これを使って、例えば「PostgreSQLとxDebugを足したものを作りたいな」となったら、次のようなDockerfileを用意すれば立ち上がるしHerokuに載せられる。

FROM o0ho0h/heroku-php72-fpm
RUN apk add --no-cache \
    $PHPIZE_DEPS \
    postgresql-dev \
    && docker-php-ext-install pdo pdo_pgsql \
    && pecl install xdebug \
    && docker-php-ext-enable xdebug

ENV COMPOSER_ALLOW_SUPERUSER=1
COPY ./webapp /var/www/html
WORKDIR /var/www/html
RUN php composer install -o

構成イメージはこんな感じだ。

$ tree -L 2
.
├── Dockerfile
├── docker-compose.yml
└── webapp
    ├── composer
    ├── composer.json
    ├── composer.lock
    ├── index.php
    ├── public
    ├── src
    └── vendor

composerは本体をgitに入れて管理させちゃっても良いか、と思ったので入れてある。デプロイ周りの整え方によっては、composer/composer - Docker Hubを使っても良いかもしれない。

実際のアプリケーションを作ってみながらコチラも整えていこう、という気持ちでいるのでまずは「動くところまで」という着地。最終的には、気になっているところをちゃんと取り除きたい。
いま気持ち悪いのは以下

  • rootのままになっている。 docker-nginx-php-fpm-heroku を見ると ADDUSER はしているのだが、USER nonroot とはしておらず、さて・・?という疑問が。
  • 近い問題で、herokuでの起動時にfpmでの user group` ディレクティブが注意される。「superユーザーで実行しない限り効かないよ」と。無指定にすればlocalでの起動に失敗するので、今の所「書いておく、herokuに怒られているけど仕方ない」みたいな割り切り
  • run.sh に乗せている内容を、どうにかDockerfileに持ってこれないものか。理由としては、ベースイメージのCMDの中で実行される内容が肥大化すると、自分のDockerfileに細やかな処理が書きにくくなりそうじゃない?と思うから。

はぁ、それにしても「同じイメージをそのまま使える」のマジで便利。すごいと思う、革命や・・・ 前回apacheでうまく行かなかった理由は相変わらず謎のまま〜〜