はじめに
前回の記事でIBM Cloud Code EngineにPlay Framework/Scalaアプリケーションをデプロイする方法を紹介しましたが、今回は同様のプロセスをNode.jsベースのアプリケーションでも行なってみます。このNode.jsアプリケーションはフロントエンドにReactを用い、バックエンドにはExpressを使ってサーバーを構築します。プロダクションへのデプロイ時にはバックエンドのExpressサーバーが両方ともホストすることになります。(ネット上にこの構成でクラウド環境へのデプロイまでカバーしている記事があまり多くはなかったので記述しておくという意味合いもあります。)
Expressサーバーの構築
Expressサーバーを構築するのにexpress-generator
を使用します。
$ npm i -g express-generator
早速Expressサーバーの雛形を作成します。
$ express react-express
最終的にフロントエンドはReactで書くことになるので、ここではテンプレートエンジンの設定等を除いていきます。まずpublic
とviews
ディレクトリは削除します。次にpackage.json
から以下の行を削除します。
"jade": "~1.11.0",
次にapp.js
からも以下の行を削除します。
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
indexRouter
関連の行も削除して構いません。また、後述のReactアプリケーション側とポートが衝突しないように、bin/www
も変更しておきます。
var port = normalizePort(process.env.PORT || '8080');
app.set('port', port);
これだけで既にweb application serverとして起動できます。
$ npm i
$ npm start
> react-express@0.0.0 start
> node ./bin/www
ブラウザからlocalhost:8080/users
にアクセスして確認すると以下のようになります。
Reactアプリケーションの作成
ReactアプリケーションをCreate React Appを使って作っていきます。最終的にclient
以下にReactのコードを配置したいので、ディレクトリ名をclient
とするため以下のコマンドで作成します。
$ npx create-react-app client
出来上がったらclient
ディレクトリに移動してnpm start
すると見慣れたトップページが表示されます。
これでExpressサーバーとReactアプリケーションが起動していますが、ばらばらに動いている状態です。これを接続するため、まずはproxyの設定をします。client/package.json
にproxy
を定義します。
"proxy": "http://localhost:8080",
client/src/App.js
を改変して/users/
を呼び出して結果を表示するように変更します。
import logo from './logo.svg';
import './App.css';
import {useState, useEffect} from 'react';
function App() {
const [users, setUsers] = useState('');
useEffect(() => {
fetch('/users/')
.then((res) => res.text())
.then((text) => setUsers(text));
}, []);
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Hello {users}!
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
ブラウザ上で表示を確認します。
プロダクション用の構成
この構成で開発を進めることはできますが、client
ディレクトリでのnpm start
はdevelopment modeでの動作な上、このままでは2つのサーバーを起動しなければいけないのでプロダクションでの使用には適しません。
プロダクション用のビルドを行うため、以下のようにpackage.json
を変更します。
"scripts": {
"build": "cd client && npm run build && rm -rf ../public && mv build ../public",
"start": "node ./bin/www"
},
この変更を行なってnpm run build
を行うと、まずclientディレクトリ内でnpm run build
を行うことでプロダクション用のReactアプリケーションがbuild
ディレクトリ以下に生成され、それを親ディレクトリのpublic
ディレクトリとして配置することになります。こうすることで、app.js
内の以下の行によってExpressサーバーがReactで書かれたフロントエンドアプリケーションを提供するようになります。
app.use(express.static(path.join(__dirname, 'public')));
Expressサーバーを再起動すると、ブラウザの8080番でアプリケーションが動作していることが確認できます。
IBM Cloud Code Engineへのデプロイ
アプリケーションは完成したので、あとはこれをCode EngineへデプロイできるようにDockerfile
にまとめていきます。
FROM node:16 as builder
RUN mkdir /home/node/app
WORKDIR /home/node/app
COPY . .
# Run install for React app
RUN cd client && npm install
# Run install for the application (w/ Express server)
RUN npm install
# Produce production React app
RUN npm run build
# Once application is generated, client code is not needed any more
RUN rm -rf client
FROM node:16
COPY --from=builder /home/node/app /home/node/app
RUN chown -R node:node /home/node/app
USER node
WORKDIR /home/node/app
EXPOSE 8080
CMD ["node", "bin/www"]
ローカルで実験する時のために .dockerignore
も適宜指定しておくと良いと思います。
Dockerfile
.dockerignore
node_modules
public
client/build
client/node_modules
ローカルでビルドして立ち上げてみます。
$ docker build . -t react-express
$ docker run -p 8080:8080 --rm react-express:latest
ブラウザからアクセスして先ほどと同じページが表示されるのを確認できたら、ソースコードをGitHubにpushしておきます。
GitHub経由でコードが取得できるようになったら、IBM CloudコンソールからCode Engineのページを開き、前回と同様にGitHubリポジトリを指定してデプロイします。手順は前回とほぼ変わりません。今回は既に8080ポートでアプリケーションが起動するのでlistenポートも空欄で大丈夫です。ビルド詳細でイメージ名等を設定したら作成をクリックして完了です。
アプリケーションが作成されたら、ビルドが終わってデプロイされるのを待ちます。デプロイが完了したらブラウザからアプリケーションが動作していることが確認できます。
上のdeveloper toolsを見るとわかるように、フロントエンドからバックエンドの/users
を呼び出していて、フロントエンドのアプリケーションもバックエンドのAPIも正しくExpressサーバーで提供されていることがわかります。
まとめ
Expressサーバーの構成にexpress-generator
、Reactアプリケーションの作成にcreate-react-app
を使い、開発環境の作成及びCode Engineへのデプロイまでの手順をまとめました。
参考
上記で使ったソースコードはこちらにあります(後の記事での変更も含んでいます): https://github.com/fterui/react-express