在Cloud Run上,将Web API服务器和React应用程序部署在同一个容器和同一个域下运行
在本文中所要进行的内容
将Web API服务器和React应用程序构建到相同的Docker镜像中,在同一个Cloud Run中以相同的域名运行。
以下是进行此项活动的动机。
-
- CORSのプリフライトリクエスト(Preflight request)を回避したい
- 小さなアプリなら1つのCloud Runで十分かも
请参考以下网址(感谢您)
- Deploy React and Nginx to Cloud Run
构成
在用于React应用程序发布的Nginx中添加反向代理配置,将请求分发到Web API服务器。
同时,在Web API服务器的API名称前面添加”/api/”前缀,并要求从React应用程序以”/api/{API名称}”的形式进行请求。
-
- Web APIサーバー
PORT 8081
Reactアプリ
PORT 8080
源代码
网络API服务器(Go语言)
我准备了一个API,它是通过「GET /hello」进行访问,返回的响应是「Hello!」这个文本。
package main
import (
"fmt"
"net/http"
)
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello!")
}
func main() {
http.HandleFunc("/hello", hello)
err := http.ListenAndServe("localhost:8081", nil)
if err != nil {
panic(err)
}
}
module server
go 1.20
React应用程序
点击按钮会调用“GET /api/hello” API,并将响应显示在屏幕上。
import {useState} from 'react';
import axios from "axios";
function App() {
const [message, setMessage] = useState("");
const handler = () => {
(async() => {
const url = window.location.origin.toString() + "/api/hello";
const response = await axios.get(url);
setMessage(response.data);
})();
};
return (
<div>
<button onClick={handler}>
APIを呼ぶ
</button>
<p>
{message}
</p>
</div>
);
}
export default App
Vite的设置。
-
- PORTを8080に設定します。
- ローカルでもAPIサーバーへのリバースプロキシが効くように設定します。
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
server: {
port: 8080,
proxy: {
'/api': {
target: 'http://127.0.0.1:8081',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
}
})
{
"name": "client",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"axios": "^1.4.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10",
"@vitejs/plugin-react": "^3.1.0",
"typescript": "^4.9.3",
"vite": "^4.1.0"
}
}
在本地进行操作验证
- Web APIサーバーの動作確認
当我在浏览器中访问 http://localhost:8080/api/hello,屏幕上显示了“你好!”这个词。

- Reactアプリの動作確認
当用浏览器访问 http://localhost:8080 并点击”调用API”按钮时,会显示”你好!”。

使用本地的Docker进行操作验证
准备用于Docker的文件。
我将准备三个新文件。
-
- nginx.conf
-
- cmd.sh
- Dockerfile
下面是执行 docker build 的目录结构。
current directory
├── server/ → Web APIサーバー
│ ├── main.go
│ └── go.mod
├── client/ → Reactアプリ
│ ├── src/
│ │ ├── App.tsx
│ │ (以下省略)
│ ├── public/
│ │ └── (省略)
│ ├── node_modules/
│ │ └── (省略)
│ ├── index.html
│ ├── package.json
│ ├── package-lock.json
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── nginx.conf
├── cmd.sh
└── Dockerfile
nginx配置文件
Deploy React and Nginx to Cloud Run のnginx.confに、Web APIサーバーへのリバースプロキシの設定を追加した内容です。
server {
listen $PORT;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri /index.html;
}
location /api/ {
proxy_pass http://localhost:8081/;
}
gzip on;
gzip_vary on;
gzip_min_length 10240;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml;
gzip_disable "MSIE [1-6]\.";
}
cmd.sh的中文释义是什么?
-
- Reactアプリ配信の部分は、Deploy React and Nginx to Cloud Run のDockerfileを参考にしました。
- Web APIサーバー、Reactアプリ配信の2つをバックグラウンドで動かします。そのうち1つでも終了したら、シェルスクリプト自体を終了させます。
#!/bin/sh
set -eo pipefail
echo "exec server."
exec /app/server &
echo "exec client."
export PORT=8080
envsubst '\$PORT' < /etc/nginx/conf.d/configfile.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;' &
# Exit immediately when one of the background processes terminate.
echo "wait."
wait -n
Dockerfile 文件
-
- Reactアプリの部分は、Deploy React and Nginx to Cloud Run のDockerfileをアレンジしました。
-
- 「go build environment」で、Web APIサーバーをビルドします。
-
- 「react build environment」で、Reactアプリをビルドします。
- ビルド結果を「run environment」にコピーして実行環境とします。
# go build environment
FROM golang:1.20-alpine as go-build
WORKDIR /app
COPY ./server ./_server
RUN go build -o server ./_server/main.go
# react build environment
FROM node:18-alpine as react-build
WORKDIR /app
COPY ./client ./
RUN npm ci
RUN npm run build
# run environment
FROM nginx:alpine
COPY nginx.conf /etc/nginx/conf.d/configfile.template
COPY --from=go-build /app/server /app/
COPY --from=react-build /app/dist /usr/share/nginx/html
EXPOSE 8080
COPY ./cmd.sh /app/
RUN chmod +x /app/cmd.sh
CMD ["/app/cmd.sh"]
使用Docker构建例子。
docker build ./ -t example
运行一个 Docker 容器的示例。
docker run --rm --name example1 -p 8080:8080 example
确认操作
- Web APIサーバーの動作確認
当在浏览器中访问http://localhost:8080/api/hello时,会显示“你好!”

- Reactアプリの動作確認
在浏览器中访问 http://localhost:8080 ,点击“调用API”按钮后,会显示“你好!”。

在 Cloud Run 上进行功能确认。
範例建立
gcloud builds submit --tag gcr.io/your_project/exercise:your_tag
部署示例
gcloud run deploy exercise \
--image gcr.io/your_project/exercise:your_tag \
--platform managed \
--cpu 1 \
--max-instances 1 \
--concurrency 1 \
--memory 1024Mi \
--timeout 3600 \
--allow-unauthenticated \
--region us-central1 \
--service-account your_identity
确认操作
- Web APIサーバーの動作確認
当使用浏览器访问https://your_service_domain/api/hello时会显示“你好!”。

- Reactアプリの動作確認
在浏览器中访问 https://your_service_domain,并点击”调用API”按钮,会显示出”你好!”。
