N_OR’s diary

無職が何か言ってる

感想文:絵で見てわかるマイクロサービスの仕組み

レガシーおっさんなので、最近の開発におけるアーキテクチャ的なものを知りたくて、本を買ってみました。 一通り読むのに6時間くらいかかりました(理解したとは言ってない)
マイクロサービスとは「細かく作れ」ではなくて「独立して作れ」だと解釈しました。

概要

アプリやシステムをマイクロサービスとして構成しようとしたときのアーキテクチャのパターン例と用いられる技術、および運用方法の解説です。

あと、dockerとkubernetesの説明がすごく丁寧で助かりました。こいつらの役割や利点がどの解説よりもわかりやすかったです。

感想

レガシーおっさんとしては、最近の人はこんなこと考えてアーキテクチャ考えているのかと、とてもためになりました。

マイクロサービスについての感想

ここで紹介されているアーキテクチャを採用するにはどういった判断材料が必要でしょうかね。 損益分岐点と言うか。

適用するなら、今後の拡張が決まっている大規模なアプリで、予算が潤沢にあって、専任アーキテクト抱えられるくらいな感じじゃないといけないような気がしないでもないです。
特に、最近流行りの「いかに早く価値を届けるか」を優先するリリースサイクルだと、環境作るのがボトルネックになるかもしれないくらいにマイクロサービスは扱いが難しいと思います。

リリースするサービスが需要を探るような最初期の段階だと、中の仕組みを頑張るより表の動く物が優先でしょうし。
(本書でも安易に適用するなとは言っている(はず))

なんかマイクロサービスに対して否定的な意見っぽくなってしまいましたが、マイクロサービスのコンセプトの一つである、サービス同士が開発のボトルネックにならないようにしようというのには賛成です。

クラウドサービスについての感想

あと、クラウドサービスについての説明もありまして。 それに対して感じたのが、クラウドサービスって、サービスを抽象的に使いたいもののはずなのに、クラウドだからこそのサービスやツールが必要になるって、なんか面倒くさいことになってないですか?

複数のサービスを保守や稼働率のために細かくコントロールする必要があるが、それぞれのサービスは独立しているのでいっぺんにコントロールできるわけでもないく、うまいこと外側からいっぺんにコントロールするためにあらたなツールを使う、みたいな印象を受けています。

とは言いつつ、よく考えたら物理サーバでもクラウドサービスに匹敵するくらいの仕掛けを実現しようとしたら同じかそれ以上に面倒なことになる気がしないでもないです。
物理サーバよりマシというというくらいの認識です。 作ろうとしているシステムの規模にもよるかもですが、私のレベルではクラウドにすると圧倒的に安く楽になります(構築・運用に工数かかりません)とはなかなか言えない難易度であります。

運用についての感想

DevOpsはマイクロサービス関係なく頑張ったほうが良いと思います。 自分たちの開発業務のシステム化なので。

以上

ブラウザでビデオ通話

ビデを通話を実現するのにSkyWayというサービスが使える。

apiがライブラリとして提供されているのでそれを利用して組み込むことができる。 使い方は公式をコピペして動かせば何となくわかるかと。

最初にユーザ登録など必要だが基本無料。
無料枠は通信回数などに利用制限あるが、個人で遊ぶ分には無料枠で充分だと思う 。

videoタグの動画をキャプチャする

ブラウザでvideoタグを利用して再生されている動画のキャプチャをとる。

事前にvideoタグを使って動画が出力される仕掛けを作っているイメージ。

例)

※laravelのbladeを利用しているためtemplateタグから開始。

<template>
<!-- ボタン -->
<input type="button" class="btn-check" id="camera-image-save" autocomplete="off">
<label class="btn btn-outline-primary" for="camera-image-save">撮影</label>

<!-- 映像 -->
<div>
    <video id="my-video" width="400px" height="300px" autoplay muted playsinline></video>
</div>
</template>

<script>

document.getElementById('camera-image-save').onclick = () => {

    // 映像を停止
    const videoElm = document.getElementById('my-video');
    videoElm.pause();

    // canvasを作って画像を貼り付ける
    const canvas = document.createElement('canvas');
    canvas.width = videoElm.width;
    canvas.height = videoElm.height;
    canvas.getContext("2d").drawImage(videoElm, 0, 0, videoElm.width, videoElm.height);

    // 保存
    {
        const a = document.createElement('a');
        //canvasをJPEG変換し、そのBase64文字列をhrefへセット
        //品質は適当
        a.href = canvas.toDataURL('image/jpeg', 0.85);
        //ダウンロード時のファイル名を指定
        a.download = 'download.jpg';
        //クリックイベントを発生させる
        a.click();
    }

    // 再開
    videoElm.play();
};

</script>

余談。 とりあえず画像データの取り回しはBase64にしておけば良い気もしている。 そうするとjson形式で扱えるので扱いが楽。今回はあんまり意味ないけど。

ブラウザからPCに接続したカメラ・マイクを接続する

scriptで以下。

<template>
<div>
    <video id="my-video" width="400px" height="300px" autoplay muted playsinline></video>
</div>
</template>

<script>
// カメラ映像取得
navigator.mediaDevices.getUserMedia({
        video: true,
        audio: true
    })
    .then(stream => {
        // 成功時にvideo要素にカメラ映像をセットし、再生
        const videoElm = document.getElementById('my-video');
        videoElm.srcObject = stream;
        videoElm.muted = true;
        videoElm.play();
    }).catch(error => {
        // 失敗時にはエラーログを出力
        console.error('mediaDevice.getUserMedia() error:', error);
        return;
    });
</script>

おそらくセキュリティの関係でhttpsのサイトじゃないとカメラにアクセスできない。(navigator.mediaDevicesが利用できない)

ブラウザはchromeを利用しており、カメラ利用できないかいろいろ試してみたが、chromeではhttpのサイトにおけるカメラ・音声の利用設定が不可の状態から変更できない。 ただし、ホスト名がlocalhostの場合はhttpでもカメラ利用可能。

MDN Web Docsに書いてありましたわ。

httpsを利用しない理由は特に無いのでhttps化するのが良いかと。
今回はwebサーバにはlaradockのnginxを利用しているのでhttps化の設定はそちらで行う。

ちなみに以下は古い書き方らしい。

navigator.getUserMedia(constraints, successCallback, errorCallback)

Vueでコントロールとデータのバインド

画面の入力用コントロールにvueが提供するv-model属性で、dataの中身を指定する。

例ではuserinfo.idがコントロールとバインドされる。

バインドすると、画面が変わればuserinfo.idの中身が変わるし、userinfo.idを書き換えれば画面の値が変わる。

<!-- blade.phpに記載しているのでtemplateタグ -->
<template>
  <input
    type="text"
    id="id"
    class="form-control"
    v-model="userinfo.id"
  />
</template>

<script>
export default {
  data: function () {
    return {
      userinfo: { id:'1'},
    };
  },
}
</script>

Vueで非同期通信

Ajax的な動作をさせる場合、Axiosというライブラリでできるっぽい。 (プレーンなjsの場合async/awaitを使う?)

例)

axiosをlarabelのbladeやvueで利用する場合

<script>
export default {
  // 略・・・

  // データ
  data: function () {
    return {
      req: {}, // htmlのinputとかと連携させておいたりする
      res: {}, // post結果取得用
    };
  },
  // 関数
  methods: {
    /**
     * なにかのボタンクリック時
     */
    click: function () {

      // サーバ処理
      axios
        .post("htpps://localhost/hoge", this.req)
        .then(
          function (response) {
            console.log(response);
            // リクエスト受け取り
            this.res = response.data;
          }.bind(this)
        )
        .catch(function (error) {
          console.log(error);
        });
    }
};
</script>

axios.postの引数はurlと渡す値。戻り値はPromiseオブジェクト。

Promiseオブジェクトではthenには成功時のコールバック関数、catchはエラー時のコールバック関数を引数として与える。
関数オブジェクトにbindで、関数内にて使用されるthisの値を指定することができる。 例ではコールバック関数内のthisがvueオブジェクトになっている。

ajaxの代替なので、レスポンスのdataはjsonオブジェクト。

LaravelでVueファイルを使う

Bladeに直接Vueを使用した記述をするのはよろしくなさそうなので、.vueファイルをつくって,vueを利用する部分を外に分離しました。
(bladeファイルのhtml部に@clickやv-on:click等のイベントを記載しても効かなかった...ただしv-ifや、script部にvueを使った記述は有効な様子)

うまくいかない動作があることはともかく、vueファイルに分離する事自体は、多分、コンポーネントとして真っ当な記述の方法だと思います。

構成は以下のようなイメージ。

メインページ(blade.php)  
┗vueファイル(.vue)

vueファイルを作る

以下にファイルを作成する。
resource/js/components/hoge.vue

vueファイルの登録

resource/js/app.jsにvueの利用を宣言。
これでhtml部分にhogeタグが使える。

Vue.component('hoge', require('./components/hoge.vue').default); 

blade側

html部分にタグを設定

<hoge></hoge>

ビルド

npm run dev 

このコマンドはnode.jsのパッケージ管理ツール。 npmをつかってdevというスクリプトをrunする。(あってる?)

npmはnode.jsとセットで提供されるため、npmを使いたいがためにnode.jsをインストールすることがある(ほんと?) ちなみにnode.jsとはサーバ側で動くjsの実行エンジン・実行環境のこと。

runのコマンドで使えるスクリプトはpackage.jsonに記述されている。

"scripts": {
    "dev": "npm run development",
    "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --config=node_modules/laravel-mix/setup/webpack.config.js",
    略・・・
},

webpackで何かしている様子。
webpackは配信用にリソースをまとめるためのツールらしい。
webpackもnode.jsについてくるものらしい。
スクリプトの引数になっているconfigファイルとか追っていけば、どこかのファイルをまとめてどこかに出力する、見たいなことが書いてあるんじゃないでしょうか。(間違えてたらごめんなさい)

もうちょっと具体的な想像をすると、webpackでまとめられたjsファイルがpublicとかの参照可能なファイルに置かれるんだと思います。

想像するくらいならソース読めというツッコミは無しで。

余談

スクリプト言語の良いところはデバッグのしやすさだと思っていましたが、ビルドするようになるとクライアント側で動いているソースが分かりにくくなってしまうのが残念なところ。

いちおう、Chromeのvueデバッグ用ツールがあるみたいなのでメモしておきます。 https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd