事件背景#
部門内には複数の業務が存在しており、アクセスと管理を容易にするために、全体のシステムは乾坤アーキテクチャを採用しています。各業務は独自のサブアプリケーションを開発し、基座アプリケーションに統一的にマウントして使用します。大まかな構造は以下のようになります:
➜ 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 を読み取り、ビルド後に dist ディレクトリの成果物を oss/s3 にプッシュし、その後、内部のルーティングを使用して url を oss/s3 上の index.html のアドレスに解析します。
プロジェクトの更新#
スクリプトの作成#
プロジェクトの下に 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 を使用してテストサービスを起動すると便利です。サーバーの設定を更新するたびに議論が絶えず、かなり不愉快です。