IT」カテゴリーアーカイブ

Node.jsでumzug+SequelizeによるDBマイグレーション

今回は、Node.jsでデータベースマイグレーションツールであるumzugについて整理したいと思います。umzugを使うと、アプリケーション内やコマンドラインからDBマイグレーションを実行するプログラムを作成することができます。

Sequelizeのmigration

Node.jsのORMとして有名なOSSの1つとしてSequelizeがあります。そして、sequelizeにはsequelize-cliというコマンドラインインターフェースがあり、初期データを投入するためのseedや、データベースのスキーマ移行をするためのmigrationがあります。ただ、sequelize-cliが生成してくれるテンプレートはJavaScriptであり、私がGitHubを眺めていた時点では(本記事作成時点)TypeScriptへの対応はまだされていないようでした。

例えば、以下のようになコマンドでUser modelを生成してみます。

生成されたUser modelの中身は以下のようになっています。

sequelize-cliをtypescript対応にしているnpmパッケージもありましたが、あまり更新が活発ではないようでした。

umzug

umzugは、sequelize-cliの内部で使われているマイグレーションツールフレームワークです。sequelize-cliのソースを見ると、マイグレーション実行部分はumzugが担っていることが分かります。sequelize-cliは、umzugを使いやすくしたツールと言えます。umzugはTypeScriptに対応しています。

テスト環境の準備

手元の環境は以下の通りです。

OS macOS Catalina 10.15.7
Node.js v16.13.2
sequelize 6.17.0
sequelize-cli 6.4.1
umzug 3.0.0
TypeScript 4.5.5
ts-node 10.5.0
sqlite3 5.0.2

テスト環境の初期化

テスト環境の初期化を行ないます。今回は、ts-nodeを使ってTypeScriptコードをNode.jsから実行できるようにします。

こんなコードを書いて、実行できることを確認しておきます。

ついでにpackage.jsonに書いて、npm runできるようにしておきます。

npm  runコマンドを実行してみます。

よさそうです。

最小サンプル

雰囲気を掴むため、小さなサンプルを見てみたいと思います。以下は、GitHubに掲載されているサンプルと同じです。

  • Sequelizeインスタンスを作成
  • UmzugのsequelizeインスタンスをDBドライバとして渡す
  • upで上位レベルに向かってマイグレーションを実行

migrationsディレクトリが空でも実行可能です。実行すると以下のような結果になります。

SequelizeMetaはマイグレーションのメタデータを管理するテーブルです。

TypeScriptファイルの雛形からマイグレーションファイルを生成する

続いて、TypeScriptでマイグレーションファイルを生成するようにしてみます。

migrate.tsファイルを以下のように書き換えます。

違いは、以下の2点です。

  • Umzugの引数にcreateプロパティを追加
  • umzug.up()をrunAsCLI()に変更

runAsCLI()は、umzug ver3で使用可能なcli実行インターフェースです。こうしておくことで、npm run migrate create -- --name setup.tsのように引数を渡してumzugに渡して実行することができます。

テンプレートファイルは以下のようにしてみます。

では、migrateターゲットでcreateコマンドを実行してみます。

migrationsディレクトリにsetup.tsファイルが作成されることを確認できます。

ついでに、usersテーブルを作成するマイグレーションを実行してみましょう。

生成したsetupマイグレーションファイルを上記のように修正します。そして、再びマイグレーションを実行します。

無事にusersテーブルが作成されました。

マイグレーションファイルのOrder

辞書でソートされた順にファイルが読み込まれる。タイムスタンプをプリフィックスに元ファイル名にすると良いと思います。

m1.js、m2、…、m10.jsの場合、m1.js、m10.js、…となります。m2.jsよりm10.jsが先にくるということになります。

その他の使用方法

GitHubの公式のドキュメントを見ながら試してみましょう。マイグレーションフォルダには2つの定義を入れています。

ペンディング中のマイグレーションの取得

pendingコマンドを実行します。

未適用の2件が表示されます。

適用済みのマイグレーションの取得

executedコマンドの実行前にDBを空にして、upコマンド実行後に再度executedコマンドを実行してみます。

マイグレーション実行後に2件の適用済みリストが表示されます。

マイグレーションの巻き戻し

最後に適用したマイグレーションを巻き戻してみます。

最後に適用したaddColumnsToUserTableが打ち消されます。

まとめ

  • umzugを使うと、Sequelizeを使ったDBマイグレーションのプログラムを独自に実装できます。
  • umzug#runAsCLI()を使うと、コマンドラインのマイグレーションプログラムを容易に実行することができます。

参考リンク

crop faceless developer working on software code on laptop

Nuxt3をさわってみる

Nuxt3はbeta版になっている、Nuxt3の雰囲気をつかむためインストールから起動するところまでやってみる。

インストール

nuxiという新しいCLIを使う。

nuxiについて、プロジェクトのトップでinfoコマンドを実行してみる。

ディレクトリ構造

initした直後は以下の感じ。Nuxt2までのようなlayoutsやpagesのようなディレクトリがなく、プロジェクト作成直後はとてもすっきりしている。

ドキュメントを見ると、今までのようなlayoutsやpagesといったディレクトリは、Nuxt3でも有効であることが分かる。これらは、アプリの特性に合わせて作成すればよいのだと思う。なお、ディレクトリについては、pluginsディレクトリ下のプラグインファイルが自動で読み込まれるなど新しい点もあるので注意したい。

参考リンク

アプリ起動

この状態でrun devするとWelcomeビューが表示される。 

httpsオプションで自己署名証明書を使ってhttpsモードで起動ができる。Nuxt2では、nuxt.configのserverオプションで指定していたと思うけれど、この辺りとても簡単になっている。

Welcomeビューを変更するには、app.vueを編集するか、pages/index.vueのような新たなビューを作る。

srcDirの変更

公式ドキュメントにあるようなclientの下にアプリリソースを配置する構成にしてみる。ディレクトリを作成し、nuxt.configのsrcDirにclientリソースを格納するディレクトリを指定、そして今ままでのようなlayoutsやpagesにビューを作成する。

上記の変更を加え、改めてrun devしてみると以下のように作成したビューが表示されることを確認できる。

 

参考リンク

Mattermost Dockerのconfig.jsonの指定

Mattermostのdockerコンテナで、mattermostコマンドを使って設定更新操作を行なうと、あらかじめ作成しておいたconfig.jsonが何故が初期化されてしまう事象に遭遇してしまった、??。(再現性を確認できていないが、pluginをenableやdeleteして何らかのschedulerが動くタイミングで発生している?)

そこで、本記事ではMattermostの設定方法について整理する。

本動作検証バージョンはv5.37.4である。

MattermostのConfiguration

Mattermostは、設定情報をconfig.jsonファイルで管理する。通常、mattermost/configディレクトリにあるconfig.jsonファイルが対象となる。環境変数MM_CONFIGでconfig.jsonファイルのパスを指定することもできる。設定情報は、System Consoleや直接ファイルを編集することで更新できる。設定を更新するとconfigの変更を検知してリロードしてくれる。

v.5.10からはデータベースで構成管理をすることができる。

ファイルで管理する場合

環境変数MM_CONFIGにconfig.jsonファイルのパスを指定する。指定がない場合は、config/config.jsonが対象となる。

ローカルテスト環境で起動する場合は、以下のようにする。Dockerコンテナ環境が必要である。macであれば、Docker Desktop For Mac(個人利用は無料:ライセンスは公式を確認のこと)を使うとよいだろう。

参考:Setting up Your Development Environment – Mattermost

データベースで管理する場合

MM_CONFIGにDatabase DSNを指定する。mysqlの場合は以下のようになる。

参考:Configuration in the Mattermost Database

起動時にカスタムのデフォルト設定を適用したい場合は、以下の環境変数を指定する。

現在有効な設定はデーターベースに接続して確認できる。

mattermostコマンドでconfigを更新してみる。

データベースのConfigurationsのレコード件数を見ると新たにレコードが増えていることが分かる。

値も反映されている。

configファイルの変更検知を停止する

Mattermostでは、構成の変更を検知するconfig watcherが動いており、構成情報の変更を検知して反映する。本機能を止めるには、以下のオプションを起動時に指定する。

config watcherを停止して何度かmattermostコマンドでpluginのenable/deleteを繰り返した限りでは、config.jsonの予期せぬ上書きに遭遇はしなかった。

なお、v5.38からはconfig.jsonの自動リロードはDeprecatedとなっているようである。設定のリロードは、mmctlコマンドで明示的に行なう、となっている。(以下リンクより)

参考:Configuration Settings

今後は、configの変更後、mmctlコマンド(mmctl config reload)で反映という手順になるのであろう。

なお、config watcherを停止した場合、configの変更はmmctlコマンドでリロードしないと反映されなかった。これは、データベース管理でも同様であった。config watcherを停止した場合は、反映漏れがないように気をつけたい。

参考

nginx http/3を動かす

NginxでHTTP/3を動かしてみます。HTTP/3はQUICというプロトコルに基づいているようです。詳しくは理解していないので追々学んでいきたいと思います。まずは、ローカルで動かしてどのようなデータやり取りが行われているのかwiresharkで覗くところから。

Dockerコンテナでビルドします。gistでレシピが公開されているのでそれに倣います。

 

ビルドすると以下のエラーとなってしまいました。

どうも上記のオプションは--with-http_v3_moduleに統合された?ようなので削除します。

参考: https://hg.nginx.org/nginx-quic/rev/33226ac61076

最終的に以下のようにしました。

nginx.conf

ビルドしてコンテナ起動します。

curlでアクセスしてみます。

RFC9000 https://www.rfc-editor.org/rfc/rfc9000.html

参考

WiresharkのTLS Record Layerのhttp-over-tls

WiresharkでTLS Layerのパケットを調べていた時に、表示されていたプロトコルが何を指しているのか疑問になったので調べてみた。

具体的には以下に表示されている部分である。HTTPでないプロトコルだと思っていたけれどhttp-over-tlsと表示されていたので、HTTP??と思ってしまった。Record部分は、暗号化されていて読めないはずなのに何故HTTPと分かったのか?、という疑問である。

ポート番号で判断している?

もし、パケットの中身を見てHTTPと判断しているのならば、ポート番号を変えてアクセスしてもhttp-over-tlsと表示されるはずである。

ということで試してみた。

Dst Portを8443としてみた。ApacheでListen 8443 httpsと設定し自己署名証明書をセットしてある。

結果、http-over-tlsと表示されてはいなかった。実際には、Webブラウザで、Webページhttps://<address>:8443/にアクセスしているので、HTTPプロトコルでデータを送受信しているはずである。このことから、Wiresharkはポートのみで判断して表示しているのではと推測できる。

Wiresharkのプロトコル解釈に関する記事

検索するとPortで判断しているような記述があり、その線が濃厚そうだ。

Wiresharkのソースはどうなってる?

念のためソースも少し確認しておく。大まかな予想をつけてソースを眺めてみる。以下の箇所がTLSデータの情報表示部分だと思われる。

プロトコルのTreeの部分に表示されている%s Record Layer: %s Protocol: %sの部分が該当箇所であろう。http-over-tlsの表示箇所であるdissector_handle_get_dissector_nameを追ってみると、以下のようになっており、app_handleの変数nameのポインタを返している。

app_handleは、以下の部分で設定されているようである。

pinfo->srcportpinfo->destportの値をもとにapp_handleを決定しているように見える。portの値をもとに決定しているとすると、ここに443の数値を入れると、http-over-tlsとなるはず。

以下のようにソース修正しビルドしてみる。

上記ではDestPortを443にしている。結果は以下のとおりとなった。DestPortは60881であるがhttp-over-tlsと表示されている。SrcPortのケースも同様に443とすると、http-over-tlsと表示されることが分かった。

TLSのレコードプロトコル

念のためTLSのレコードプロトコル構造を確認しておく。上位レイヤであるHTTPのヘッダとボディのデータはペイロードに含まれる。

  • TCPヘッダ
    • Content-Type(1 Byte)
    • Version(2 Bytes)
    • Length(2 Bytes)
    • ペイロード
  • MAC

まとめ

WiresharkのTLSレコードのhttp-over-tlsの表示は、SrcまたはDestのPortを見て決定している。

ただし、session->app_handleが決定済みのケースは、今回追っていない。

参考