将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、前端和后端均以独立的容器部署的模式
容器的配置图像
准备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
准备后端容器
准备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
確定行動
将Nginx和前端整合到一个容器中,而后端则是另一个容器的模式。
容器的构成图像
准备前台容器
准备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
确认动作
1. 源代码被合并到主分支中,
2. 构建工具检测并生成jar文件。
3. 在docker build阶段,只需将其复制并启动即可,我认为这种方法是现实可行的。
对于前端,在实际业务的CI/CD环境中,
1. 源代码被合并到主分支中,
2. 构建工具检测并运行npm run build命令。
3. 在docker build阶段,复制②生成的build目录并启动即可,我认为这种方法是现实可行的。