「北海道新型コロナウイルスまとめサイト」で、データの自動更新の仕組みを構築しましたので、ご紹介します。
とりあえずは手動更新で運用を始めるのは全然OKだと思いますが、段々めんどくさくなるし、タイムラグも発生するし、なのでどこかのタイミングで自動化するとけっこう幸せになれます。
関連記事。
- 東京都新型コロナウイルス感染症対策サイトをforkしてnetlifyでdev環境を立ち上げる手順」
- 北海道新型コロナウイルスまとめサイトのインフラ構成(リリース時)
- (東京都 新型コロナウイルス感染症対策サイトで)Netlifyでデプロイプレビューを設定するとレビューが捗るよ
私がメインで協力している北海道版はこちらです。

前提
- 北海道まとめサイト -> 北海道新型コロナウイルスまとめサイトの事
- 東京都対策サイト -> 東京都 新型コロナウイルス感染症対策サイトの事
- 北海道新型コロナウイルスまとめサイトのインフラ構成(リリース時) の続きからです
- data.json -> グラフ系のコンポーネントから読み込むデータファイルの事。北海道まとめサイトでは分割しているので実際は複数ファイル。
説明すること
- インフラ/リポジトリの構成
- Nuxtの実装
- nginxの設定
- 運用開始後の所感
インフラ構成
こうです!

まず、下半分と右側の説明をします。
メインリポジトリとサーバ
- 基本的に初期リリース時と同じ
- GitHubActionsで、ビルドしてproductionブランチへコミット
- ↑で生成したファイルを、さくらのクラウドサーバ側から5分に1回 git pull
- 少しパワーアップして、dev環境と本番環境で、サーバとアクセラレータを別セット用意しました(合計2セット
- nginxの設定をdev環境でテストしやすいように(これが後で効いてくる
という感じです。
データリポジトリ
まず、メイン(nuxtのやつ)のリポジトリとは別で、データ取得用のスクリプトのリポジトリを用意しました。
データリポジトリでは、最初はHTMLをスクレイピングしたりしていましたが、現在は北海道と札幌市との協力の元公開してくれている、CSVのオープンデータを取得して、jsonファイルに加工する処理をしています。
詳細は、@Kanehiroさんご本人が記事にしてくれています。



- 作成されたdata.jsonはgh-pagesブランチにコミットされる
- さくらのクラウドサーバから↑を定期的にgit pull
- nginxのlocationで、メインリポジトリから取得したHTML、jsと、data.jsonファイルをそれぞれ取得できるように
- 設定は後述
なぜこの構成にしたか
リポジトリを分けた
これは、あまり最初から考えたわけではなく、@Kanehiroさんが別ブランチでスクレイピングの処理をサクッと作ってくれて(神)、本体にマージする/しないという議論もありましたが、なんかマージするのは難しかったので、結局別リポジトリで開発・運用をしていました。
自動化されるまでdata.jsonファイル自体はメインリポジトリに必要なので、data.jsonファイルだけ手動でコミットしていました。めんどくさいですね。
結果論ですが、データの更新タイミングと、本体の更新タイミングは違うので、最終的にはこの構成で良かったと思います。
当時の議論。
さくらのサーバに集約した
これもあまり深く考えたわけでは無くて、結果としてこうなりました。
そもそも、data.jsonはgh-pagesブランチにコミットしているので、GitHubPagesとして公開できます。なので、そこから取ってくれば良いじゃん!
とやってみたのですが、Chrome以外ではCORSの制限にひっかかって動きませんでした。
Nuxtからは、axios経由で非同期でdata.jsonを取得するのですが、GitHubPagesはPreflightRequestがNGのようでした。
(ちなみに、ChromeはPreflightRequestを送信しない仕様なので動いた)
多分Netlifyも同じだろうという事で、既にさくらクラウドのサーバは動いていて、そこに入れちゃえば同一ドメインになるから、CORS気にしなくて良いよね!
ということで、さくらクラウドのサーバにあいのりすることにしました。
Nuxtの実装
- 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についてはこちらがわかりやすかったです。

運用開始後の所感
- データ更新の度にPRしたりしなくて良いのでめちゃめちゃ楽、、、
- 人手がかからない分、反映されるまでの時間も早いので、ユーザー的にもうれしい
特に2つめが大事で、1日に何回か最新情報が出てくるので、ユーザーさんにとって価値がある情報を提示し続けられる仕組みになったのは大変良いと思います。
自動化するにあたって気をつけた方が良いこと
- データ形式が変わらないか
- データ形式についてネゴれていなじ状態(勝手にスクレイピングで取ってきているとか)だと、データ取得に失敗して、壊れたデータになってしまうリスクがあります
- なので、最初から自動化はしない方が良さそう
- 北海道まとめサイトでは、北海道と札幌市に協力いただける事になったので、このリスクが大きく減った。大変助かった。
- サーバ負荷
- data.jsonファイルはアクセラレータでキャッシュできるのですが、preflight requestはキャッシュできないです
- アクセラレータがGETリクエストのみキャッシュする仕様なので(preflight requestはOPTIONリクエスト)
- なので、めちゃめちゃアクセスがあるサイトだと負荷には気をつけた方が良いです
- 北海道まとめサイトでは、Mackerelをインストールして監視しているので(なんかまずければSlackに通知来る)ので、気持ち的には安心
- data.jsonファイルはアクセラレータでキャッシュできるのですが、preflight requestはキャッシュできないです
まとめ
データ自動更新の仕組みについてご紹介でした。
私は、こんな感じで作りたいっすね〜という話と、プロトタイプと、nginxの設定をやったくらいです。
JUST道ITメンバーや北海道・札幌市、サーバを提供いただいているさくらインターネットさんなどなど、色々な方々にご協力いただいて、スムーズに自動化までできたのはけっこう奇跡的だな〜と思っています。感謝感謝です。
データの自動更新ができるようになると、もっと色々な改修にリソースをさけるようになります。
他自治体でも、よければ参考にしてみてください〜。
おまけ
長野県版でも違うアプローチで自動化していました!(Netlify環境で動いているので、環境によってはこちらの方が簡単かも?)

コメント