angular - 在 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)
解决方案
由于您似乎使用 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
- 创建一个名为的文件
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 的代理开发服务器一样。
- 调整您的 Dockerfile 如下:
...
# Add this line right before `EXPOSE 80`
COPY nginx-default.conf.template /etc/nginx/templates/default.conf.template
...
- 下次你将环境变量传递
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:latest
或node:latest
.latest
顾名思义,总是指向最新版本。- 对于每条
docker build
指令,都将从 Docker Hub 中提取具有最新版本的相应映像,但是,这可能不是您真正想要/需要的。想象一下,今天 node 的当前版本是 12,几天/几周后,版本 13 出来了,带有标签node:latest
,你可以拉它并在引擎盖下使用它。那将是有风险的,因为它可能会破坏某些东西 - 所以最好坚持一个特定的版本,并在你通过测试新版本之后随着时间的推移自己增加版本(例如,你可以使用
node:14-alpine
和nginx: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
...
推荐阅读
- r - 尽管在 r 中使用 as.POSIXct 时间跨过午夜,但日期并没有改变
- c# - C# File System Watcher windows 服务发生内存泄漏,无法追踪导致内存泄漏的原因
- python - 内置身份验证视图的 Django Admin 不会消失
- javascript - 在javascript嵌套循环中获取未知整数
- laravel - 我可以在刀片组件(模板)中嵌入样式和 JavaScript 吗?
- xamarin.forms - TabbedPage 中的 CollectionView 不显示数据 Xamarin.Forms
- c - 通过基本脚本程序检查 C 语言中是否存在函数
- android - java.lang.NoSuchMethodError:Lkotlin/time/TimeMark 类中没有虚方法 elapsedNow()D
- blazor - Blazor:可选地提供一个方法作为参数
- java - 扩展一个类并重新定义一个最终变量