在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,屏幕上显示了“你好!”这个词。

image.png
    Reactアプリの動作確認

当用浏览器访问 http://localhost:8080 并点击”调用API”按钮时,会显示”你好!”。

image.png

使用本地的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时,会显示“你好!”

image.png
    Reactアプリの動作確認

在浏览器中访问 http://localhost:8080 ,点击“调用API”按钮后,会显示“你好!”。

image.png

在 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时会显示“你好!”。

image.png
    Reactアプリの動作確認

在浏览器中访问 https://your_service_domain,并点击”调用API”按钮,会显示出”你好!”。

image.png
广告
将在 10 秒后关闭
bannerAds