事件背景#
部門内には複数の業務が存在しており、アクセスと管理のために全体のシステムは乾坤アーキテクチャを採用しています。各業務は独自のサブアプリケーションを開発し、基盤アプリケーションに統一的にマウントして使用します。大まかな構造は以下のようになります:
➜ Project tree
.
├── ASCM
│ └── index.html
├── OSCM
│ └── index.html
├── PSCM
│ └── index.html
├── TMS
│ └── index.html
├── VSCM
│ └── index.html
├── assets
│ ├── dist.css
│ └── dist.js
└── index.html
7 directories, 8 files
長い間、すべてのアプリケーションはビルドマシンでビルドされ、パッケージ化された後にアップロードされ、Nginx で静的ファイルディレクトリが直接指定されてアクセスされていました。設定は以下のようになります:
server {
listen 80;
server_name xxx.test.demo.local;
client_max_body_size 15M;
access_log logs/halley.access.log log_access; # ログ出力ディレクトリ
gzip on;
gzip_min_length 1k;
location ^~ / {
root /mnt/work/h5/project-dist/;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
これは非常に一般的でよく使われる方法です。しかし、内部の運用プラットフォーム自体の問題により、本番環境に新しいメインアプリケーションをデプロイする際(テストとステージングでは問題ありません)、プロジェクトフォルダ全体の内容を直接クリアして新しいリソースをリリースするため、単に上書きするだけではありません。これはつまり、毎回の更新で内部のサブアプリケーションがクリアされ、"基盤アプリケーションのリリース === すべてのアプリケーションの再公開" ということを意味します。
リリース頻度は高くありません(月に 2 回程度)、しかし、サブアプリケーションの数が増えるにつれて、これはまだ非常に重い負担となっています。特に工場に関連するアプリケーションの中には、昼間に中断することができず、深夜にまとめて更新する必要があるものもあります。そのため、問題を完全に解決するための考えが生まれました。
しかし、運用とのコミュニケーションの後、現在使用している運用プラットフォームはほとんどメンテナンスされておらず、要件に応じて別のシステムに移行する必要があることがわかりました。
移行プロセス#
リリース原則#
ミドルウェアを使用してビルド環境を構築し、リポジトリ内のユーザーが作成した build.sh を読み取り、ビルド後の成果物を OSS/S3 にプッシュし、その後、内部のルーティングを使用して URL を index.html の OSS/S3 アドレスに解析します。
プロジェクトの更新#
スクリプトの作成#
プロジェクトの下に build.sh を追加し、内容は以下の通りです。
#! /bin/sh
. ~/.profile
yarn install --registry http://npm.xxxx.local:7001 --ignore-engines
export CICD_STATIC_PATH=$(echo $CICD_STATIC_PATH) && yarn build
ビルドシステムは、今回のビルドの OSS アドレスをCICD_STATIC_PATH
変数に保存し、スクリプト内で取得して webpack に渡すために使用します。
Webpack の更新#
webpack.config.js の関連するリソースパスを修正します。
const publicPath = {
dev: `http://${process.env.HOST}:${process.env.PORT}/`,
production: process.env.CICD_STATIC_PATH
};
{
path: __dirname + '/dist/', // パッケージ化されたファイルを配置するパス。devモードではメモリ上にのみ存在し、実際にはこのパスにパッケージ化されません
publicPath: publicPath[process.env.NODE_ENV], // ファイルの解析パス。index.htmlで参照されるパスは、このパスを基準として設定されます
filename: process.env.NODE_ENV === 'dev' ? 'bundle.js' : 'bundle-[contenthash].js' // コンパイル後のファイル名
}
Nginx の設定の更新#
server {
listen 80;
server_name xxx.test.demo.local;
client_max_body_size 15M;
access_log /var/log/nginx/halley.access.log ; # ログ出力ディレクトリ
gzip on;
gzip_min_length 1k;
location ^~ / {
proxy_set_header X-Scheme $scheme; # プロトコルの伝達
proxy_set_header Host apisix-area.test.demo.com; # ドメインの伝達
proxy_set_header X-Real-IP $remote_addr; # IPの伝達
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
add_header X-Rewrite-Result $uri;
proxy_intercept_errors on;
error_page 400 403 404 500 = 200 /index.html;
proxy_pass http://apisix-area.test.demo.com/xxx/xxx-project/;
}
}
http://apisix-area.test.demo.com
は、運用によって統一的に提供され、ビルド時にシェルスクリプトからCICD_STATIC_PATH
変数を読み取ります。
更新後、静的リソースではなく、完全にリモートの OSS 上のリソースにプロキシされるようになります。プロジェクトは React で構築されており、独自のフロントエンドルーターを持ち、js/css などの静的リソースは自動的にCICD_STATIC_PATH
ドメインにアップロードされます。そのため、ここではすべてのアクセスに失敗したリクエストを OSS 上の index.html にプロキシするだけです。
余談#
Nginx の設定を行う際に、ローカルで Docker を使用してテストサーバーを起動すると便利です。サーバーの設定を更新するたびに、サーバー側の設定を更新する手間が省けます。人を探したり手続きを進める時間が多く費やされるように感じますが、非常に不愉快です。