【北海道新型コロナウイルスまとめサイト】データ自動更新が実装されたので仕組みを解説

プログラム全般

「北海道新型コロナウイルスまとめサイト」で、データの自動更新の仕組みを構築しましたので、ご紹介します。

とりあえずは手動更新で運用を始めるのは全然OKだと思いますが、段々めんどくさくなるし、タイムラグも発生するし、なのでどこかのタイミングで自動化するとけっこう幸せになれます。

関連記事。

私がメインで協力している北海道版はこちらです。

北海道 新型コロナウイルスまとめサイト
当サイトは、道内の新型コロナウイルス感染症(COVID-19)に関する最新情報を提供するために作成されました。開発は、ICTエンジニアやデザイナーなどによって結成された「JUST道IT」が行っています。 複製・改変が許されたオープンソースライセンスで公開されている、の仕組みを利用しています。

前提

説明すること

  • インフラ/リポジトリの構成
  • Nuxtの実装
  • nginxの設定
  • 運用開始後の所感

インフラ構成

こうです!

まず、下半分と右側の説明をします。

メインリポジトリとサーバ

  • 基本的に初期リリース時と同じ
  • GitHubActionsで、ビルドしてproductionブランチへコミット
  • ↑で生成したファイルを、さくらのクラウドサーバ側から5分に1回 git pull
  • 少しパワーアップして、dev環境と本番環境で、サーバとアクセラレータを別セット用意しました(合計2セット
    • nginxの設定をdev環境でテストしやすいように(これが後で効いてくる

という感じです。

データリポジトリ

まず、メイン(nuxtのやつ)のリポジトリとは別で、データ取得用のスクリプトのリポジトリを用意しました。

データリポジトリでは、最初はHTMLをスクレイピングしたりしていましたが、現在は北海道と札幌市との協力の元公開してくれている、CSVのオープンデータを取得して、jsonファイルに加工する処理をしています。

詳細は、@Kanehiroさんご本人が記事にしてくれています。

COVID-19Hokkaidoデータ編①スクレイピングなどによる初期データ作成 - Qiita
もくじ COVID-19Hokkaidoデータ編①スクレイピングなどによる初期データ作成←この記事だよ! COVID-19Hokkaidoデータ編②オープンデータ化+自動更新 COVID-19Hokkaidoデータ編③完全自動化...
COVID-19Hokkaidoデータ編②オープンデータ化+自動更新へ向けて - Qiita
もくじ COVID-19Hokkaidoデータ編①スクレイピングなどによる初期データ作成 COVID-19Hokkaidoデータ編②オープンデータ化+自動更新へ向けて←この記事だよ! COVID-19Hokkaidoデータ編③完...
COVID-19Hokkaidoデータ編③完全自動化(バリデーション・エラー検知) - Qiita
もくじ COVID-19Hokkaidoデータ編①スクレイピングなどによる初期データ作成 COVID-19Hokkaidoデータ編②オープンデータ化+自動更新へ向けて COVID-19Hokkaidoデータ編③完全自動化←この記...

  • 作成されたdata.jsonはgh-pagesブランチにコミットされる
  • さくらのクラウドサーバから↑を定期的にgit pull
  • nginxのlocationで、メインリポジトリから取得したHTML、jsと、data.jsonファイルをそれぞれ取得できるように
    • 設定は後述

なぜこの構成にしたか

リポジトリを分けた

これは、あまり最初から考えたわけではなく、@Kanehiroさんが別ブランチでスクレイピングの処理をサクッと作ってくれて(神)、本体にマージする/しないという議論もありましたが、なんかマージするのは難しかったので、結局別リポジトリで開発・運用をしていました。

自動化されるまでdata.jsonファイル自体はメインリポジトリに必要なので、data.jsonファイルだけ手動でコミットしていました。めんどくさいですね。

結果論ですが、データの更新タイミングと、本体の更新タイミングは違うので、最終的にはこの構成で良かったと思います。

当時の議論。

北海道のCOVID19にまつわる機械可読性の高いデータがない · Issue #2 · codeforsapporo/covid19
バグ / Bug 改善提案 / Suggestions for improvement 起こっている問題 / Occurred problem HTML +PDFの状況なので、パース不可 そもそも東京都JSONと同様のデータがあるのか(私が)未検証 期待する見せ方・挙動 / Expected behavior データを

さくらのサーバに集約した

これもあまり深く考えたわけでは無くて、結果としてこうなりました。

そもそも、data.jsonはgh-pagesブランチにコミットしているので、GitHubPagesとして公開できます。なので、そこから取ってくれば良いじゃん!

とやってみたのですが、Chrome以外ではCORSの制限にひっかかって動きませんでした。

Nuxtからは、axios経由で非同期でdata.jsonを取得するのですが、GitHubPagesはPreflightRequestがNGのようでした。

(ちなみに、ChromeはPreflightRequestを送信しない仕様なので動いた)

多分Netlifyも同じだろうという事で、既にさくらクラウドのサーバは動いていて、そこに入れちゃえば同一ドメインになるから、CORS気にしなくて良いよね!

ということで、さくらクラウドのサーバにあいのりすることにしました。

Nuxtの実装

codeforsapporo/covid19
北海道 新型コロナウイルス対策サイト. Contribute to codeforsapporo/covid19 development by creating an account on GitHub.
  • data.jsonを$axios経由で非同期で取得
  • 元々data() で実行されていた初期化処理を、↑の非同期処理で設定するように修正
  • グラフ系のcomponentにnull対策(data.jsonを読み込まれるまではデータが空で、初期実装だとぬるぽが起きる)

vuexを使うか?という議論もありましたが、現状は使っていません。

  • 1画面でしか使われない
  • ユーザーはそんなに画面遷移しない

ので、割と好みの問題かな?とも思います。

個人的にはこの程度であれば使わない方がすっきりして良いと思います。

あと、NuxtのfetchやasyncDataだと、ビルド時のデータが表示されて、データ取得処理が走らない(要はビルド時にSSRされてる的な動きをする)ので注意です。

多分universalモードでnuxt genrateするとこういう動きになるんだと思います。

nginxの設定

同一ドメインだし、CORS対策いらないよね!

と思って構築したのですが、実際にはデプロイプレビューやローカル環境から、devサーバにつなぎにいくため、CORS対策は必要でした、、、(Nuxtの@nuxtjs/proxyを軽く試したけどうまくいかなかったのでnginxで解決した)

というわけで、こんな風になっています。

server {
	listen 80 default_server;

	root /home/covid19/production;

	# Add index.php to the list if you are using PHP
	index index.html index.htm index.nginx-debian.html;

	server_name _;

        # メインの設定
	location / {
		# First attempt to serve request as file, then
		# as directory, then fall back to displaying a 404.
		try_files $uri $uri/ =404;

		# cache settings for CDN
		add_header Cache-Control "s-maxage=300, public";
	}

        # data.jsonの設定 
        location ^~ /api/ {
		try_files $uri $uri/ =404;
	        root /home/covid19/data;

                if ($request_method = OPTIONS) {
                  add_header 'Access-Control-Allow-Headers' 'Access-Control-Allow-Origin';
                  add_header 'Content-Length' 0;
                  add_header 'Access-Control-Allow-Origin' '*';
                  add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
                  add_header 'Content-Type' 'text/plain; charset=utf-8';
                  add_header 'Access-Control-Max-Age' 1728000;
                  return 204;
                 }

	        add_header Cache-Control "s-maxage=300, public";
                add_header 'Access-Control-Allow-Origin' '*';
                add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        }


	location /.well-known/ {
		try_files $uri $uri/ =404;

		# no cache settings for CDN
		# add_header Cache-Control s-maxage=300;
	}

	gzip on;
	gzip_types text/html text/css text/javascript text/plain application/x-javascript application/javascript application/json;
	gzip_vary on;
        # gzip_proxiedつけないとアクセラレータ経由でgzipが効かないので注意
        gzip_proxied any;
}

data.jsonへは、

https://stopcovid19.hokkaido.dev/api/XXXXXX.json

というURLでアクセスできるようにしました。

location ^~ /api/

の中でごにょごにょやっているのは、CORS対策です。めんどくさいですねw

CORSについてはこちらがわかりやすかったです。

なんとなく CORS がわかる...はもう終わりにする。 - Qiita
概要 Access to XMLHttpRequest at ' from origin ' has been blocked by COR...

運用開始後の所感

  • データ更新の度にPRしたりしなくて良いのでめちゃめちゃ楽、、、
  • 人手がかからない分、反映されるまでの時間も早いので、ユーザー的にもうれしい

特に2つめが大事で、1日に何回か最新情報が出てくるので、ユーザーさんにとって価値がある情報を提示し続けられる仕組みになったのは大変良いと思います。

自動化するにあたって気をつけた方が良いこと

  • データ形式が変わらないか
    • データ形式についてネゴれていなじ状態(勝手にスクレイピングで取ってきているとか)だと、データ取得に失敗して、壊れたデータになってしまうリスクがあります
    • なので、最初から自動化はしない方が良さそう
    • 北海道まとめサイトでは、北海道と札幌市に協力いただける事になったので、このリスクが大きく減った。大変助かった。
  • サーバ負荷
    • data.jsonファイルはアクセラレータでキャッシュできるのですが、preflight requestはキャッシュできないです
      • アクセラレータがGETリクエストのみキャッシュする仕様なので(preflight requestはOPTIONリクエスト)
    • なので、めちゃめちゃアクセスがあるサイトだと負荷には気をつけた方が良いです
    • 北海道まとめサイトでは、Mackerelをインストールして監視しているので(なんかまずければSlackに通知来る)ので、気持ち的には安心

まとめ

データ自動更新の仕組みについてご紹介でした。

私は、こんな感じで作りたいっすね〜という話と、プロトタイプと、nginxの設定をやったくらいです。

JUST道ITメンバーや北海道・札幌市、サーバを提供いただいているさくらインターネットさんなどなど、色々な方々にご協力いただいて、スムーズに自動化までできたのはけっこう奇跡的だな〜と思っています。感謝感謝です。

データの自動更新ができるようになると、もっと色々な改修にリソースをさけるようになります。

他自治体でも、よければ参考にしてみてください〜。

おまけ

長野県版でも違うアプローチで自動化していました!(Netlify環境で動いているので、環境によってはこちらの方が簡単かも?)

新型コロナウイルス対策サイトの data.json を外部から読み込めるよう疎結合化してみた - Qiita
開発した動機 新型コロナウイルス対策サイトを1からブラウザだけで更新データを編集してプレビューまでできるようにしてみた この作者さんの思いを感じ、 「たしかに、データとプログラム部分は分離されているほうが便利なことも多いよな...

コメント

タイトルとURLをコピーしました