将Spring Boot后端和TypeScript前端放入容器中

你好。每到星期五,我就会想要观看动画电影。我是Docker大叔。
在上一篇文章中,我使用Nginx将前端和后端连接到同一个端口上进行访问。
这次,我打算将前端和后端分别放在Docker容器中并启动。

环境信息

    • Docker version 20.10.17, build 100c70180f

 

    • docker-compose version 1.21.2, build a133471

 

    • nginx version: nginx/1.22.1

 

    • Node.js v18.14.2 (npm 9.5.0)

 

    Java OpenJDK Runtime Environment Microsoft-7209853 (build 17.0.6+10-LTS)

同时,前端/后端的源代码将使用与上篇文章相同的版本。

    • フロント: TypeScript + React + MUI

 

    バック: Java + Spring boot + gradle

容器的组成

这次我将尝试两种方法,第一种方法是。

    • ①Nginx, フロント, バック 全てが別コンテナに乗っかっているパターン

 

    ②Nginxとフロントを1コンテナにまとめており、バックは別コンテナのパターン

目录结构

.
├── docker-compose.yml
├── front
│   ├── node_modules
│   ├── package.json
│   ├── package-lock.json
│   ├── public
│   ├── README.md
│   ├── src
│   │   ├── App.tsx
│   │   ├── index.tsx
│   │   ├── logo.svg
│   │   ├── react-app-env.d.ts
│   │   ├── reportWebVitals.ts
│   │   └── setupTests.ts
│   └── tsconfig.json
│
├── README.md
│
└── spring
    ├── build.gradle
    ├── gradle
    ├── gradlew
    ├── gradlew.bat
    ├── README.md
    ├── settings.gradle
    └── src
        ├── main
        │   ├── java
        │   │   └── ...
        │   └── resources
        │       └── application.yml
        └── test
            ├── java
            │   └── ...
            └── resources
                └── application.yml

我把docker-compose.yml文件放在根目录下,并在其中加入了以下内容:
– “front”:前端源代码,
– “spring”:后端源代码。

让我们试一试 shì yī shì)

①Nginx、前端和后端均以独立的容器部署的模式

容器的配置图像

pattern1.png

准备Nginx容器。

nginx配置文件的描述

在根目录下创建一个 nginx/conf/ 目录,并放置以下类似的 nginx.conf 文件。

server {
    # Nginxがlocalhost:80でアクセスを受け付けます。
    listen       80;
    server_name  localhost;
    proxy_set_header    Host    $host;
    proxy_set_header    X-Real-IP    $remote_addr;
    proxy_set_header    X-Forwarded-Host       $host;
    proxy_set_header    X-Forwarded-Server    $host;
    proxy_set_header    X-Forwarded-For    $proxy_add_x_forwarded_for;

    # "http://<nginxコンテナ>:80/"配下のアクセスはfrontコンテナの3000番ポートに転送します。
    location / {
        proxy_pass    http://front:3000/;
    }

    # "http://<nginxコンテナ>:80/api/"配下のアクセスはspringコンテナの8080番ポートに転送します。
    location /api/ {
        proxy_pass    http://spring:8080/api/;
    }
}
准备Dockerfile。

准备以下类似的Dockerfile。

FROM nginx:1.22.1

# ベースイメージの設定ファイルを自前に置換
RUN rm /etc/nginx/conf.d/default.conf
COPY ./conf/nginx.conf /etc/nginx/conf.d

CMD ["nginx", "-g", "daemon off;"]

准备前台容器

在前端文件夹的根目录下创建一个如下所示的Dockerfile。

# ローカルで使っているNode.jsのバージョンと最も近いものを使用
FROM node:18.15.0

# コンテナの作業ディレクトリを/app配下に設定
WORKDIR /app

# /front配下すべてを/app配下に持っていく
COPY ./* /app/
COPY public/ /app/public/
COPY src/ /app/src/

# 必要なモジュールを全てインストール
RUN npm install

# コンテナ起動と同時に"npm start"が走る
ENTRYPOINT [ "npm", "start" ]

我将使用docker-compose来运行它。

前方容器的操作确认

我们先试着确认一下动作,执行下面的指令。

cd <プロジェクトのルートディレクトリ>/front
# コンテナイメージのビルド
docker build -t front .
# "front"というコンテナイメージを"front"という名前で起動
docker run -itd -p 3000:3000 --name front front
loading.png

准备后端容器

准备Spring Boot的后端容器。

    • ソースからビルドしたい

 

    • ビルドされたjarファイル名はプロジェクトごとに可変となるため、ビルド時に指定したい

 

    最終的に実行するコンテナにはjarファイルだけがあればいい

在这个条件下,使用多阶段构建。

我将写下一个与下面的Dockerfile类似的文件。

# ソースのビルド用コンテナ
FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS builder

# ソースを全て/app配下に持っていく
WORKDIR /app

COPY ./* ./
COPY ./gradle/ ./gradle/
COPY ./src/ ./src/

# sdkman!からgradleを入手→パスを通す
RUN apt-get update
RUN apt-get -y install curl
RUN apt-get -y install zip
RUN curl -s "https://get.sdkman.io" | bash
RUN echo ". $HOME/.sdkman/bin/sdkman-init.sh; sdk install gradle" | bash

# gradle build
RUN $HOME/.sdkman/candidates/gradle/current/bin/gradle build

# 実際に動かすコンテナの記述
FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu

# gradle buildで生成される実行可能jarファイルのパス ファイル名をbuild-argで受け取る
ARG JAR_FILE_PATH="/app/build/libs/demo-0.0.1-SNAPSHOT.jar"

WORKDIR /app

# builderコンテナから実行可能jarファイルをコピー jarファイル名はbuild-argから受け取る
COPY --from=builder ${JAR_FILE_PATH} ./app.jar

ENTRYPOINT ["java", "-jar", "app.jar"]
确认后端容器的操作

我们也先试试看这个功能是否正常运作。
①执行以下命令。

cd <プロジェクトのルートディレクトリ>/spring
# コンテナイメージのビルド
# 例: docker build --build-arg JAR_FILE_PATH=<JARファイルのフルパス> -t spring .
# 生成されるjarファイル名が"demo-0.0.1-SNAPSHOT.jar"だと、以下のようになります。
docker build --build-arg JAR_FILE_PATH=/app/build/libs/demo-0.0.1-SNAPSHOT.jar -t spring .
# "spring"というコンテナイメージを"spring"という名前で起動
docker run -itd --name spring spring

请使用浏览器访问 http://(docker运行环境的主机):8080/api/hello

curl http://localhost:8080/api/hello
{"jpn":"こんにちは","eng":"hello"}

如果问候内容以JSON格式返回,那就算成功了。

创建docker-compose.yml

最后,我们将编写一个docker-compose.yml文件来整合上述三个容器。

在项目的根目录下,创建一个类似下面的docker-compose.yml文件。

version: "3"
services:
  nginx:
    build: nginx #nginxディレクトリでコンテナをビルドする
    container_name: nginx
    ports:
      - 80:80 # 80番ポートを内外に公開

  front:
    build: front
    container_name: front
    restart: always
    expose:
      - "3000" # 3000番ポートを内部ネットワークに公開
    depends_on:
      - spring # springコンテナよりも後に起動させる

  spring:
    build:
      context: spring
      args:
        ${JAR_FILE_PATH}: /app/build/libs/demo-0.0.1-SNAPSHOT.jar
    container_name: spring
    restart: always
    expose:
      - "8080" # 8080番ポートを内部ネットワークに公開

创建.env文件

将docker-compose.yml中的可变值集中到.env文件中。
在与docker-compose.yml相同的层级中创建一个名为”.env”的文件。

JAR_FILE_PATH=/app/build/libs/demo-0.0.1-SNAPSHOT.jar

容器构建

使用docker-compose命令启动容器。

cd <プロジェクトのルートディレクトリ>
docker-compose up -d
確定行動
success.png

将Nginx和前端整合到一个容器中,而后端则是另一个容器的模式。

容器的构成图像

pattern2.png

准备前台容器

准备nginx.conf文件

在front/nginx/conf目录下创建一个名为nginx.conf的文件,文件内容如下。

server {

  listen 80;

  location / {
    root   /usr/share/nginx/html;
    index  index.html index.htm;
    try_files $uri $uri/ /index.html;
  }

  location /api/ {
      proxy_pass http://spring:8080;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection 'upgrade';
      proxy_set_header Host $host;
      proxy_cache_bypass $http_upgrade;
   }

  error_page   500 502 503 504  /50x.html;

  location = /50x.html {
    root   /usr/share/nginx/html;
  }
}
准备Dockerfile。

我们将使用多阶段构建来准备前端容器。3

# ローカルで使っているNode.jsのバージョンと最も近いものを使用
FROM node:18.15.0 AS builder

# コンテナの作業ディレクトリを/app配下に設定
WORKDIR /app

# /front配下すべてを/app配下に持っていく
COPY ./* /app/
COPY public/ /app/public/
COPY src/ /app/src/

# 必要なモジュールを全てインストール
RUN npm install

# フロントのソースをビルド
RUN npm run build

# 実際に動かすコンテナ
FROM nginx:1.22.1

# ベースイメージの設定ファイルを自前に置換
RUN rm /etc/nginx/conf.d/default.conf
COPY ./nginx/conf/nginx.conf /etc/nginx/conf.d

# ビルドされたフロントのソースを持っていく
COPY --from=builder /app/build/ /usr/share/nginx/html

CMD ["nginx", "-g", "daemon off;"]

准备后端容器

后端容器与模式1相同。

创建docker-compose.yml文件

最后,我们将描述一个docker-compose.yml文件来整合上面提到的三个容器。

在项目的根目录下,创建一个名为docker-compose.yml的文件,内容如下。

version: "3"
services:
  front:
    build: front # frontディレクトリでコンテナをビルドする
    container_name: front
    restart: always
    ports:
      - 80:80 # 80番ポートを内外に公開
    depends_on:
      - spring # springコンテナよりも後に起動させる

  spring:
    build:
      context: spring
      args:
        - ${JAR_FILE_PATH}: /app/build/libs/demo-0.0.1-SNAPSHOT.jar
    container_name: spring
    restart: always
    expose:
      - "8080" # 8080番ポートを内部ネットワークに公開

创建.env文件

将docker-compose.yml中的可变值集中到.env文件中。
在与docker-compose.yml相同的层级下创建一个名为”.env”的文件,内容如下。

JAR_FILE_PATH=/app/build/libs/demo-0.0.1-SNAPSHOT.jar

构建容器

使用docker-compose命令,启动容器。

cd <プロジェクトのルートディレクトリ>
docker-compose up -d
确认动作
success.png
尽管可以将所有内容放入一个容器中,但是一个容器中包含3个应用程序,并且由于其容错性差,所以从实用性的观点来看,我们决定不这样做。我认为在这方面存在各种不同的派系,希望不会对此感到反感。在实际业务的CI/CD环境中,
1. 源代码被合并到主分支中,
2. 构建工具检测并生成jar文件。
3. 在docker build阶段,只需将其复制并启动即可,我认为这种方法是现实可行的。

对于前端,在实际业务的CI/CD环境中,
1. 源代码被合并到主分支中,
2. 构建工具检测并运行npm run build命令。
3. 在docker build阶段,复制②生成的build目录并启动即可,我认为这种方法是现实可行的。

广告
将在 10 秒后关闭
bannerAds