首页 > 解决方案 > 在 Docker 中构建 Angular 项目 - 特定于环境

问题描述

这是我第一次编写 Dockerfile。我在 Angular 中有一个连接到不同后端(Spring Boot Rest 服务)的应用程序。我的意思是说 Spring Boot 应用程序已部署在许多不同的站点/位置。它们都有不同的 URL。这些休息服务已经存在(我没有写这些休息服务)。当我尝试调用这些 Rest 服务时,我遇到了 CORS 错误。所以我不得不给我们下面的 xyx.proxy.conf.json

以下是我的配置:

包.json

  "scripts": {
    "ng": "ng",
    "start:localhost": "ng serve --proxy-config localhost.proxy.conf.json",
    "start:site1qa": "ng serve --proxy-config site1qa.proxy.conf.json",
    "start:site2qa": "ng serve --proxy-config site2qa.proxy.conf.json",
    "start:site1prod": "ng serve --proxy-config site1qa.proxy.conf.json",
    "start:site2prod": "ng serve --proxy-config site2prod.proxy.conf.json",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e --proxy-config site1qa.proxy.conf.json"
  },

site1qa.proxy.conf.json注意:我必须使用代理,因为我收到 CORS 错误

{
  "/RestWeb/*": {
    "target": "http://site1qa:8005",
    "secure": false,
    "changeOrigin": true,
    "logLevel": "debug"
  }
}

角服务.ts

  findAllByModelYear(): Observable<string[]> {
    return this.httpClient.get<string[]>('/RestWeb/model/findAllModelYearCodes');
  }

我在本地使用以下命令测试了应用程序,指向不同的后端,如下所示:

npm run start:localhost
OR
npm run start:site1qa
OR
npm run start:site2prod

我当前的Dockerfile是这样的:

# Stage 1: Compile and Build angular codebase

# Use official node image as the base image
FROM node:latest as build

# Set the working directory
WORKDIR /usr/local/app

# Add the source code to app
COPY ./ /usr/local/app/

# Install all the dependencies
RUN npm install

# Generate the build of the application
RUN npm run build

# Stage 2: Serve app with nginx server

# Use official nginx image as the base image
FROM nginx:latest

# Copy the build output to replace the default nginx contents.
COPY --from=build /usr/local/app/dist/my-projectt /usr/share/nginx/html

# Expose port 80
EXPOSE 80

目前我是这样构建的:

docker build -t dockerangular .

并像这样运行:

docker run -it -p 8000:80 --name angulardocker1 my-first-app

问题:

如何传递参数(在构建和/或运行应用程序时),以便我可以连接到不同的站点(如 package.json 中所述,即使用 xyx.proxy.conf.json)

标签: angulardocker

解决方案


由于您似乎使用 NGINX 作为 HTTP 服务器,因此您可以将proxy_pass指令用于代理目的。

此外,您可以创建自己的 NGINX 模板配置文件,即在引导期间 NGINX 会在/etc/nginx/templates/文件夹中查找,如果存在任何.template文件,NGINX 会将执行envsubst的结果输出到/etc/nginx/conf.d,例如:

如果您将文件放在 中/etc/templates/default.conf.template,其中包含如下变量引用:

listen  ${MY_NGINX_PORT};

输出会变成/etc/nginx/conf.d/default.conf这样(假设MY_NGINX_PORT是 8080):

listen 8080;

参考:https ://hub.docker.com/_/nginx

解决方案:

/etc/nginx/conf.d/default.conf由于NGINX的默认配置文件位于

/etc/templates/default.conf.template--(会变成之后envsubst)-->/etc/nginx/conf.d/default.conf

  1. 创建一个名为的文件nginx-default.conf.template并用此内容填充它,然后将其放入项目根文件夹中:
server {
    listen       80;
    server_name  _;

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

    location /RestWeb/ {
        proxy_pass ${REMOTE_API_URL};
    }
}

注意/RestWeb/路径和${REMOTE_API_URL}自定义环境变量,即任何以路径开头的请求/RestWeb/都将无缝代理到${REMOTE_API_URL},就像 ng cli/webpack 的代理开发服务器一样

  1. 调整您的 Dockerfile 如下:
...
# Add this line right before `EXPOSE 80`
COPY nginx-default.conf.template /etc/nginx/templates/default.conf.template
...
  1. 下次你将环境变量传递REMOTE_API_URL给 时docker run,它的值将在 NGINX 服务器启动时自动使用,例如
docker run -p 8000:80 -e REMOTE_API_URL="http://site1qa:8005" my-first-app

或用于安全 API:

docker run -p 8000:80 -e REMOTE_API_URL="https://site1prod:8005" my-first-app

一些提示

  • 你不需要EXPOSE 80。它仅用于文档目的,实际上什么也不做。

  • 避免使用最新版本的 Docker 镜像,例如nginx:latestnode:latest. latest顾名思义,总是指向最新版本。

    • 对于每条docker build指令,都将从 Docker Hub 中提取具有最新版本的相应映像,但是,这可能不是您真正想要/需要的。想象一下,今天 node 的当前版本是 12,几天/几周后,版本 13 出来了,带有标签node:latest,你可以拉它并在引擎盖下使用它。那将是有风险的,因为它可能会破坏某些东西
    • 所以最好坚持一个特定的版本,并在你通过测试新版本之后随着时间的推移自己增加版本(例如,你可以使用node:14-alpinenginx:1.19.9-alpine。有关更多标签,请参阅 Docker Hub )
  • 这些是等价的:

    WORKDIR /usr/local/app
    COPY ./ /usr/local/app/
    
    WORKDIR /usr/local/app
    COPY ./ .
    

请参阅:https ://docs.docker.com/engine/reference/builder/#workdir

  • 如下修改你的 Dockerfile 以利用 Docker 层缓存机制使后续 Docker 构建运行得更快
...
WORKDIR /usr/local/app
COPY package.json .
RUN npm install
COPY . .
RUN npm run build
...

请参阅:为什么 COPY package*.json ./ 在 COPY 之前。.?


推荐阅读