Rso's Jotter

日々の開発の知見のメモやその他雑記

Netlifyをしばらく使ったので所感を書いておきます。

前回は kintone について 所感を書きましたが、今回はNetlifyについて書きます。

rso.hateblo.jp

Netlifyとは

f:id:rso:20191130144431p:plain

静的ファイルホスティングサービスの部類に属し、いわゆるHTML/Javascript/CSSで完結するサイトをサクッと公開でき、それに関連する様々な機能を提供しています。提供している機能としては、例えば、

  • HTTPS化、SSL証明書の発行(Let's Encrypt)
  • githubなどのリポジトリ連携、ビルド、デプロイなどのCI機能
  • デプロイプレビュー環境の自動作成
  • サーバサイドサポート(Lambda Function)
  • 入力フォーム
  • 認証
  • A/Bテスト, アクセス分析

などがあります。

静的ファイルサイトなので、サーバサイドの動作が必要になるアプリケーション(PHP, Rails)などは対応できません。

自社の業務や個人的なツールやハッカソンなどでNetlifyを使用することがそこそこ多く、そこで得られた良いところ、つらいところを書いておきます。

Netlifyの良いところ

デプロイまでの設定がとにかく早い。手軽。

初めてNetlifyを使用したのはNuxt.jsだったのですが、リポジトリと連携してビルドコマンド(nuxt generate) を設定したら、そのままもうデプロイされるようになりました。これだけでmasterの内容が常にデプロイされる簡易的なCD環境が出来上がります。さらにHTTPS化やカスタムドメインの設定もできます。

以前、実際にNetlifyで設定してみたときのメモを書きましたので、こちらにも書いておきます。 rso.hateblo.jp

デプロイプレビュー(feature環境)が自動でデプロイされる

開発時にfeatureブランチ(masterでないブランチ)をpushするとそのブランチの内容がdeploy-preview環境としてデプロイされます。この機能は、修正内容をユーザや他の人にレビューしてもらう時にとても便利です。この辺りの機能がリポジトリと連携するだけですぐに使えるので、これもとても手軽です。

無料枠の機能が豊富

Netlifyは各機能ごとにプランが設定されていて、ある一定枠までは無料で使用でき、それ以上使いたいときは機能ごとに課金するスタイルになっています。ハッカソンやプロトタイプ開発レベルでは無料枠でほぼ対応できるぐらい使用できます。

ちょっとしたサーバサイド側の機能を実装できる

静的サイトの内容だけで完結できない場合、例えば、CORSの制約によりAjax通信ができない場合、通常ならその部分をAWS Lambda + API Gateway などを用意しないといけないという場合でも、Netlify の Functions を使えば上記のことをNetlifyだけで完結することができます。さらにFunctionのコードも同一のリポジトリに含めて管理できるので、プロジェクトの規模が小さいうちはコードが別々にならずに管理できて良いです。

Netlifyのつらいところ

静的ファイルのダウンロードが遅い

結構大きめのSingle Page ApplicationをNetlifyにデプロイした場合、初回ダウンロードにかなりの待ち時間がかかってしまいます。特にモバイル用のSingle Page Applicationの場合、初回アクセスがネックになります。 検証できている訳ではないですが、ネットの評判によるとダウンロードにかかる時間は同様のサービスであるFirebase に軍配が上がっているようです。

ビルドがたまにこける

masterへpushした内容が反映されるのを待っていると、ビルドが失敗していることがあります。production環境へのビルドが失敗すると、ちょっと心配になる場合があります。

Functionの実行時間に制約がある

とあるプロジェクトでNetlify Functionで簡易的なサーバサイドの処理を実行していたのですが、Function(実態はLambda)の実行時間が最大10秒までしか実行できず、実行したい処理がたまに10秒を超えるようなものだったので、結局このケースではAPI Gateway + Lambdaの構成に変更しました。

devploy preview環境がpublicになる

良いところで挙げたdeploy-preview機能ですが、1つ欠点があり、パブリックでアクセス可能になってしまいます。開発中の内容をpublicに公開したくない場合には向いていないかもしれません。自分の場合、Auth0 による認証を入れるようにして対策しています。

まとめ

今回自分が使った中で良いところつらいところを書きましたが、かなり良いサービスであり、 LPなどはもちろん、簡易的なツールやプロトタイプ作成に向いていると感じています。

VPC内にあるAWS Elastic Search の kibanaをサクッと見たい時のメモ

掲題の対応をするためのメモを残しておきます。

とりあえず手っ取り早く見るためのものなので、ちゃんとした方法が他にもあって、 恒久的な方法としては全然向いていません。

前提

  • Elastic Search Service からインスタンスを立ち上げて、インスタンスはVPC内のPrivateな環境にある。
  • VPC内にSSHできる踏み台サーバがあって、インターネット -> 踏み台, 踏み台 -> ElasticSearchへの通信は空いている

上記のような環境がある時、SSHのポートフォーワーディングすればとりあえず見れるようになります。

手順

ElasticSearchのPrivate IPアドレスを得ます。

ここでは、踏み台サーバからping してみます。

 $ ping vpc-xxxxxxxxxxx.ap-northeast-1.es.amazonaws.com

 vpc-xxxxxxxxxxx.ap-northeast-1.es.amazonaws.com  (192.168.X.X) 56(84) bytes of data.

 -> 192.168.X.X が Private IP

SSH ポートフォワーディング して繋ぎます。

 $ ssh 踏み台サーバIP -L 8443:192.168.X.X:443

これで、 localhost:8443 が 192.168.X.X:443 へ転送されるようになります。

以下にアクセス

https://localhost:8443/_plugin/kibana

もちろん証明書のエラーは出ますが、見れることは見れます。

Kintoneを多少使ったので所感を書いておきます

自社の業務で一部Kintoneを使用していて、社内の事業転換に伴い、その業務が終了し、Kintoneもほぼほぼ役目を終えることになりました。

Kintone上で業務を2年ぐらい運用していましたが、そのなかでよいところ、つらいかゆいところなどをまとめておこうと思います。

Kintoneとは

f:id:rso:20191109222002p:plain

提供元のサイボウズはファストシステムと謳ってたりもしますが、いわゆるノンプログラミングシステムの一つで、ノンプログラミングシステムの中ではかなり学習コストが低い部類に入ると思います。

Kintoneではアプリと呼ばれる単位で管理、運用されますが、このアプリというのは、簡単に説明するのが難しいですが、1つのフォームとそれに関連するCRUDとデータストアがセットになったようなものです。 そしてこのアプリをマウス操作で簡単に作れる、という感じです。 私は自社の簡単な案件管理、見積作成、発注管理で一部Kintoneを使用していました。

Kintoneのよかったところ

GUI操作でさくっとフォームが作れる

これはKintoneの魅力の一つで、1つのフォームと簡単なマスタ参照で完結するものは、ちょっと慣れればプログラミング経験が無い人でもかんたんに作れます。プロトタイプの開発が早くできるだけでなく、一度作って運用に乗せれば、プログラミング経験が無い業務チームに運用を引き継げるということがとても良い利点です。

モバイルのビューも同時に作られる

モバイル対応しているので、作成したアプリを外出先など携帯でちょっと確認したい、という要望に応えられます。モバイルのビューが自動作られるのは良い点です。ただしサブテーブルなど、モバイルの表示適さない要素が多いと見づらくなります。

ユーザ管理、組織管理、アクセス制限, アクセス証跡 など一通り揃っている

システムを運用する上で必要な上記の権限制御などは、一通り揃っているので、特に不便はありませんでした。

Kintoneのつらいところ

アプリ間でのデータ連携が弱い

Kintoneは標準ではルックアップという他のアプリのデータを参照できる仕組みがあります。 これで事足りるような要件であればよいのですが、以下のようなときに辛さが出てきます。

  • データの参照元が更新されたとき、参照先のデータも更新したい(ルックアップでは参照時の値がコピーされるだけ)
  • 複数のアプリをまたがって複数の項目を取得したい(ルックアップを多段にすればできますが設定と運用がめんどくさくなります)

ルックアップでできないデータの更新はJavascriptを書けばできますが、プログラムの量が増えると後述の運用が大変になってきます。

実際、ルックアップ参照元が更新されて、参照元に更新が必要となった場合、データを一度CSVにエクスポートして更新してインポートし直すという作業を行っていました。

またデータの参照であればルックアップでなんとかできますが、アプリの更新結果を他のアプリに連携、というのは標準機能ではできません(Javascriptでカスタマイズすればいけます)

カスタマイズ用のプログラムを継続開発する仕組みが弱い

前述の問題でも挙げた、標準機能でできないことはJavaScriptでカスタマイズすればほぼほぼできるのですが、これに頼りすぎると運用保守が大変になります。

  • CI/CDのサポートが弱い。 コードを更新しても手動打鍵するという確認が通常なのでユニットテストを実行する仕組みがありません。やるとしたらpuppeteerを使って簡単なE2Eテストをデプロイ時に回すなどの仕組みを用意する必要があります。

コードもKintoneにはJavaScriptを登録するインタフェースが用意されているだけなので、そのままではES6のコードは動きません。自前でWebpackなどでトランスパイルしてからアップロードという仕組みを用意する必要があります。 自分はGithubでmasterに取り込まれたらCircle CI でWebpackビルドして、それをS3にデプロイして、それをkintoneが読み込むという方法を使っていました。

いずれにせよ、プログラムを本格的に継続保守していくとなると、自前でCI/CD環境を用意したりする必要があり、このあたりは正直つらくなってきます。

まとめ

よかったところ、つらいところはまだまだ他にもいっぱいあるのですが、だらだらと長くなりそうなので、 主な部分だけ記載しました。良いところ、辛いところを勘案して思ったのは、

  • 簡単なシステムを簡単に作るのはすごく適しているし、運用も楽。
  • 簡単かどうかの基準は、単一のアプリで完結する仕様かどうか。複数アプリでの連携が必要なものは、kintoneで簡単にはできない。
  • JavaScriptカスタマイズを使えばかなり色々できるが、それを前提にしない。最小限に留める。

といったところです。利用者と調整できるのであれば、kintoneに乗るように業務ロジックの方を簡単にしてもらう方が良いかもしれません。 さくっと作れてプログラミング経験がなくても運用できる長所をうまく活用できれば、とても重宝すると思います。

Auth0 で API から Username/Password認証でのトークン発行手順

Auth0でAPIからトークンを発行する方法を調査していて、ちょっとだけ手間だったのでその内容をメモしておきます。

背景

開発中のプロダクトで認証はAuth0を使用しているのですが、今ではフロントエンドのNuxt.jsで動いているAuth module上でWebからの認証オンリーだったのですが、バッチ処理の用途で、プログラム経由でアクセストークン(JWT)を取得する必要が発生しました。

そこでAPI経由でアクセストークン取得の方法を調べました。

調査内容

リファレンスを見ると、この辺りを使えば行けるようです。

POST /oauth/token https://auth0.com/docs/api/authentication?http#resource-owner-password

  • リソースオーナーのID/Passwordでトークン取得可能
  • client_secretは不要(Application Settingがらみ以外)

実施内容

上記のリファレンスを元に、以下のクエリを実行しました。

 curl -XPOST -H "content-type: application/json" https://#{auth-domain}.auth0.com/oauth/token -d '{"grant_type": "password", "client_id": "xxxxxx", "username": "test@example.com", "password": "hogehoge"}'

すると以下のエラーが帰ってきました。

{"error":"server_error","error_description":"Authorization server not configured with default connection."}

ちょっとこの内容だとよくわからなかったのですが、Webで調べると以下の記事が見つかりました。

https://community.auth0.com/t/how-to-authorize-user-with-email-password-from-server-code/7239

どうやら、 Default Directory なるものの設定がいるようです。 あまりよくわかっていないですが、これは認証の際にどのデータソースを使用するか、というような項目ように見えます。

f:id:rso:20191101191339p:plain
Auth0のSetting

で、この値を何に設定するのかすぐにわからなかったのですが、 Connection -> Database 以下の データベース名を入力すれば大丈夫でした。 (デフォルトだと Username-Password-Authentication)

f:id:rso:20191101191357p:plain
Defaut Directoryにこれを指定したらいけた

こちらに設定後再度 /oauth/token APIデトークン発行を叩くと、無事トークンを発行できました。

その後そのトークンでAPIアクセスしましたが、今度はJWTのissuer (iss)が違うと言ってエラーになりました。これはAuth0でカスタムドメインを使用していたのが原因でした。トークン検証する側のカスタムドメインのAUTH0_DOMAINを使用していて、トークン生成はデフォルトドメインに対してアクセスしていたのがよくない原因でした。 両方ともカスタムドメインにアクセスし、無事トークン発行できました。

所感

前の少し思ったんですが、Auth0はすごい便利で、認証の手間を限りなくゼロにするという思想はすごく良いと思うのですが、 Default DirectoryやDefault Audience の設定などを要求されると、結局は認証の仕組みを理解しないとつまづくなと思いました。 何も理解せずに使えるサービスはないと思いますが、Auth0の利用者に要求される知識水準がどのあたりなのか、気になりました。 (そして私は、その要求水準を満たしていない..)

MySQLの外部キー制約の付与でハマったのでメモ

長らく投稿できていませんでしたが、MySQLの外部キー制約の付与で予想以上にハマってしまってので 備忘のためメモを残しておきます。

説明の簡略化のため、簡単なテーブル構造に置き換えて説明します。

状況

以下のような2つのテーブルがあったとします。

mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| organizations  |
| users          |
+----------------+

それぞれ、Stringのuuid をPrimary keyとしてもち、 usersはorganization_id を持てるようにしたいとします。

mysql> desc users;
+-----------------+--------------+------+-----+---------+-------+
| Field           | Type         | Null | Key | Default | Extra |
+-----------------+--------------+------+-----+---------+-------+
| uuid            | varchar(255) | NO   | PRI | NULL    |       |
| name            | varchar(255) | YES  |     | NULL    |       |
| organization_id | varchar(255) | YES  |     | NULL    |       |
+-----------------+--------------+------+-----+---------+-------+

mysql> desc organizations;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| name  | varchar(255) | YES  |     | NULL    |       |
| uuid  | varchar(255) | NO   | PRI | NULL    |       |
+-------+--------------+------+-----+---------+-------+

外部キー制約をつけるため、以下のSQLを実行しました

ALTER TABLE users ADD CONSTRAINT fk_test_1 FOREIGN KEY(organization_id) REFERENCES organization(uuid);

ところが、以下のようにエラーが出てしまい、失敗しました。

 ERROR 1215 (HY000): Cannot add foreign key constraint

organizatons.uuid も users.organization_id も同じ varchar(255) なのに 何で失敗するんだ...!と 数時間悩んでしまいました。

結局、show create table で構造を見たら解決しました。

mysql> show create table users;
| users | CREATE TABLE `users` (
  `uuid` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `organization_id` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci |
mysql> show create table organizations;
| organizations | CREATE TABLE `organizations` (
  `name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `uuid` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |

なんと、charset が異なっていたのです。ですので、 同じカラムとして見なされず、外部キー制約でエラーとなっていたのでした。

背景

実はこれ、Railsのマイグレーション時に発生したエラーで、開発環境は今までオッケーでしたが、構築中の別環境のマイグレーションでのみ発生しておりました。Rails は 5系のどこかからデフォルトで utf8mb4を使用するようになっており、Railsのバージョンアップに起因してDefault charset も変わってしまったのが原因です。しかしその場ですぐ影響が出ず、異なる文字コードのテーブル間で外部キー制約を貼ろうとしたタイミングでエラー発生しました。

詳しい人から見たらすぐにわかる事象かもしれないですが、エラーメッセージからなかなか原因に行き着かず、結構悩んでしまったので、メモとして残しておきます。