Docker Compose创建React容器但无法启动的问题及解决
更新 - 已解决(2024年7月21日)
我已完成调试,成功配置前端Dockerfile和compose.yaml,只需执行docker compose up --build即可运行Spring-React应用,调试期间搭配使用docker compose down --rmi all命令,未修改后端Spring的Dockerfile。
更新后的compose.yaml
services: backend: build: backend-spring restart: always ports: - 8080:8080 frontend: build: context: frontend-react stdin_open: true tty: true ports: - 3000:3000 depends_on: - backend
更新后的前端Dockerfile
ARG NODE_VERSION=20.13.1 ################################################################################ # 所有阶段均使用Node镜像作为基础镜像 FROM node:${NODE_VERSION}-alpine as base # 为所有构建阶段设置工作目录 WORKDIR /app ################################################################################ # 创建安装生产依赖的阶段 FROM base as deps # 将下载依赖作为单独步骤,利用Docker缓存机制加速构建 # 使用缓存挂载到/root/.npm,加快后续构建速度 # 使用绑定挂载package.json和package-lock.json,避免将它们复制到当前层 RUN --mount=type=bind,source=package.json,target=package.json \ --mount=type=bind,source=package-lock.json,target=package-lock.json \ --mount=type=cache,target=/root/.npm \ npm ci --omit=dev ################################################################################ # 创建构建应用的阶段 FROM deps as build # 构建前下载额外的开发依赖,部分项目需要安装"devDependencies"才能完成构建。如果不需要可移除此步骤 RUN --mount=type=bind,source=package.json,target=package.json \ --mount=type=bind,source=package-lock.json,target=package-lock.json \ --mount=type=cache,target=/root/.npm \ npm ci # 复制package.json,以便执行包管理器命令 COPY package*.json . RUN npm install # 复制剩余的源码文件到镜像中 COPY . . # 执行构建脚本 RUN npm run build --omit=dev ################################################################################ # 创建运行应用的阶段,仅包含最小运行时依赖,从构建阶段复制必要文件 FROM base as final # 默认使用生产环境Node环境 ENV NODE_ENV production # 复制package.json,以便执行包管理器命令 COPY package.json . # 从deps阶段复制生产依赖,从build阶段复制构建完成的应用到镜像中 COPY --from=deps /app/node_modules ./node_modules COPY --from=build /app/build ./build COPY --from=build /app/public ./public COPY --from=build /app/src ./src # 安装`serve`用于运行应用 RUN npm install -g serve # 使用非root用户运行应用 USER node # 暴露应用监听的端口 EXPOSE 3000 # 运行应用 # 在npm start(调试)和serve(生产)之间切换 #CMD [ "npm", "start" ] CMD ["serve", "-s", "build"]
原始问题
我是Docker新手,尝试用单个compose.yaml部署Spring-React应用,通过docker init和相关资料分别为后端(Spring)和前端(React)创建了Dockerfile。
. ├── backend-spring │ ├── ... │ ├── Dockerfile ├── frontend-react │ ├── ... │ └── Dockerfile ├── ... └── compose.yaml
我想先让应用在本地运行,再部署到AWS。
在根目录执行docker compose up -d后,提示后端和前端容器均已创建,但执行docker container ls时仅显示Spring后端容器,导致无法通过localhost访问React应用。
为何frontend-react容器未出现在docker container ls结果中?
我怀疑是前端Dockerfile的问题,已尝试调整RUN/CMD命令但无效。
手动在目录执行serve -s build或npm start时React应用可正常运行,希望仅通过docker compose up -d命令就能同时启动前后端,且已确认Spring后端API可通过localhost访问。
感谢您的帮助。
原始compose.yaml
services: backend: build: backend-spring restart: always ports: - 8080:8080 frontend: build: context: frontend-react # target: development # 指定多阶段Dockerfile中要构建的阶段。由于backend-spring的Dockerfile是单阶段,因此注释掉 stdin_open: true tty: true ports: - 3000:3000 volumes: - /frontend-react/src - /frontend-react/node_modules depends_on: - backend
原始前端Dockerfile
# syntax=docker/dockerfile:1 # Dockerfile参考指南 ARG NODE_VERSION=20.13.1 ################################################################################ # 所有阶段均使用Node镜像作为基础镜像 FROM node:${NODE_VERSION}-alpine as base # 为所有构建阶段设置工作目录 WORKDIR /usr/src/app ################################################################################ # 创建安装生产依赖的阶段 FROM base as deps # 将下载依赖作为单独步骤,利用Docker缓存机制加速构建 # 使用缓存挂载到/root/.npm,加快后续构建速度 # 使用绑定挂载package.json和package-lock.json,避免将它们复制到当前层 RUN --mount=type=bind,source=package.json,target=package.json \ --mount=type=bind,source=package-lock.json,target=package-lock.json \ --mount=type=cache,target=/root/.npm \ npm ci --omit=dev ################################################################################ # 创建构建应用的阶段 FROM deps as build # 构建前下载额外的开发依赖,部分项目需要安装"devDependencies"才能完成构建。如果不需要可移除此步骤 RUN --mount=type=bind,source=package.json,target=package.json \ --mount=type=bind,source=package-lock.json,target=package-lock.json \ --mount=type=cache,target=/root/.npm \ npm ci # 复制剩余的源码文件到镜像中 COPY . . # 安装`serve`用于运行应用 RUN npm install -g serve # 执行构建脚本 RUN npm run build --omit=dev ################################################################################ # 创建运行应用的阶段,仅包含最小运行时依赖,从构建阶段复制必要文件 FROM base as final # 默认使用生产环境Node环境 ENV NODE_ENV production # 使用非root用户运行应用 USER node # 复制package.json,以便执行包管理器命令 COPY package.json . # 从deps阶段复制生产依赖,从build阶段复制构建完成的应用到镜像中 COPY --from=deps /usr/src/app/node_modules ./node_modules COPY --from=build /usr/src/app/build ./build # 暴露应用监听的端口 EXPOSE 3000 # 运行应用 # 在npm start(调试)和serve(生产)之间切换 CMD [ "npm", "start" ] #CMD serve -s build # 无效 #RUN serve -s build # 无效
后端Dockerfile
# syntax=docker/dockerfile:1 # Dockerfile参考指南 ################################################################################ # 创建解析和下载依赖的阶段 FROM eclipse-temurin:17-jdk-jammy as deps WORKDIR /build # 复制具有执行权限的mvnw包装器 COPY --chmod=0755 mvnw mvnw COPY .mvn/ .mvn/ # 将下载依赖作为单独步骤,利用Docker缓存机制加速构建 # 使用缓存挂载到/root/.m2,避免后续构建重复下载依赖包 RUN --mount=type=bind,source=pom.xml,target=pom.xml \ --mount=type=cache,target=/root/.m2 ./mvnw dependency:go-offline -DskipTests ################################################################################ # 基于已下载依赖的阶段创建构建应用的阶段 # 此Dockerfile针对输出uber jar的Java应用优化,uber jar包含JVM运行所需的所有依赖。如果你的应用不输出uber jar,而是依赖Tomcat等应用服务器,则需要更新此阶段的包文件名,并将"final"阶段的基础镜像替换为对应的应用服务器镜像 FROM deps as package WORKDIR /build COPY ./src src/ RUN --mount=type=bind,source=pom.xml,target=pom.xml \ --mount=type=cache,target=/root/.m2 \ ./mvnw package -DskipTests && \ mv target/$(./mvnw help:evaluate -Dexpression=project.artifactId -q -DforceStdout)-$(./mvnw help:evaluate -Dexpression=project.version -q -DforceStdout).jar target/app.jar ################################################################################ # 创建将应用提取到单独层的阶段 # 利用Spring Boot的层工具和Docker缓存,将打包后的应用提取到单独层,以便复制到最终阶段 FROM package as extract WORKDIR /build RUN java -Djarmode=layertools -jar target/app.jar extract --destination target/extracted ################################################################################ # 创建运行应用的阶段,仅包含最小运行时依赖,通常使用与安装或构建阶段不同的基础镜像,并从安装阶段复制必要文件 # # 以下示例使用eclipse-temurin的JRE镜像作为运行应用的基础。 # 指定"17-jre-jammy"标签时,构建Dockerfile会使用该标签的最新版本。 # 如果需要可重复性,建议使用特定的摘要SHA FROM eclipse-temurin:17-jre-jammy AS final # 创建非特权用户用于运行应用 ARG UID=10001 RUN adduser \ --disabled-password \ --gecos "" \ --home "/nonexistent" \ --shell "/sbin/nologin" \ --no-create-home \ --uid "${UID}" \ appuser USER appuser # 从"package"阶段复制可执行文件 COPY --from=extract build/target/extracted/dependencies/ ./ COPY --from=extract build/target/extracted/spring-boot-loader/ ./ COPY --from=extract build/target/extracted/snapshot-dependencies/ ./ COPY --from=extract build/target/extracted/application/ ./ EXPOSE 8080 ENTRYPOINT [ "java", "org.springframework.boot.loader.launch.JarLauncher" ]
内容的提问来源于stack exchange,提问作者ALVIN
相关产品推荐
相关产品推荐

