angular环境配置
随着向云优先的转变以及托管基础架构和业务流程(例如EWS,Azure AKS或GCP群集)的兴起,应用程序环境需要进行准备和调整以适应新出现的需求。 这不是什么新鲜事,也不是未知数,但是承认这一事实是第一步,而且可能是第一步。
由内而外的深潜
让我们从用户的角度出发,分解技术架构。 从用户向浏览器输入应用程序URL的位置开始,用户访问Kubernetes精心策划的应用程序时,幕后的技术设置如何?
![](https://i-blog.csdnimg.cn/blog_migrate/112ec39f3ce34a3203f067548d60d5eb.png)
图形由 https://www.linkedin.com/in/theresa-ohm-06b7a156
启动的第一个配置是将URL映射到IP地址的DNS配置,在这些情况下,负载平衡器的IP。 负载平衡器几乎没有其他工作可以满足该名称,它会将用户的请求重定向到Web服务器正在侦听的业务流程。 当我们运行kubernetes环境时,通过将此Web服务器指定为kubernetes集群的入口控制器,我们将局限于此。 有多种类型的入口控制器。 我们决定使用Nginx控制器使用默认选项。
作为副节点,此层是可能需要特定于应用程序配置的第一层,例如,当应用程序应传输更大的数据(代理体大小)和/或支持持久操作(代理超时)时),因为nginx入口控制器具有隐式默认配置。
在入口控制器下方,进行编排,因为kubernetes容器通过部署为应用程序容器提供服务。 在这里,可以将部署配置为指定应在其中服务容器的环境。我们再次做出了一个明确的设计决定,即容器。
我们的容器是docker映像,不仅包含内置的angular应用程序(静态javascript),而且还包含nginx Web服务器,因为我们希望能够独立于基础架构及其编排,开发和维护而独立运行docker容器。 /或测试目的。 我们采用这种方法,并优先考虑灵活性和舒适性而不是性能。 docker镜像是完全正常构建的,使用多阶段构建来编译角度源代码并将输出与配置的nginx Web服务器捆绑在一起。
由内而外的深潜
描述了上述“从外而内”的角度之后,现在让我们集中讨论Angular及其默认特征。 Angular的概念确实包括用于这些场景的环境,配置或定义,其中应根据您在本地开发还是在生产中运行对应用程序应用不同的配置。 Angular概念的缺点是,它仅是构建时配置。
这意味着在运行Angular应用程序时,首先将其编译为静态JavaScript,并且在编译时也将环境配置固定。 由于无法绕开此静态代码,因此,除非事先知道并进行操作,否则无法根据其所运行的基础结构来配置应用程序。
如何将配置更改为运行时配置
重新设计Angular应用程序以使其与Docker和Orchestration完美结合的第一步是将环境策略更改为运行时配置。 这可以通过使用Ajax / XHR调用来代替动态获取配置来摆脱默认的环境概念来实现。 @juristr在https://juristr.com/blog/2018/01/ng-app-runtime-config/中对此进行了更详细的描述。
简而言之,我们实现了一个配置服务,该服务在应用程序启动时使用appResolver实例化,该服务通过XHR调用获取配置。 解析程序已作为防护注册到appRoutes。 应用程序的模块可以简单地注入配置。
app.routes.ts
import { AppResolverService } from '@app/resolvers/app-resolver.service' ;
import { IndexComponent } from '@views/index/index.component' ;
export const routes: Routes = [
{
path : '' ,
canActivate : [AppResolverService],
children : [
{
path : '' ,
component : IndexComponent,
pathMatch : 'full'
}
]
}
];
app-resolver.service.ts
import { Injectable } from '@angular/core' ;
import { ConfigService } from '@services/config/config.service' ;
import { EMPTY, Observable } from 'rxjs' ;
import { catchError, map } from 'rxjs/operators' ;
import { CanActivate, UrlTree } from '@angular/router' ;
@Injectable({
providedIn : 'root'
})
export class AppResolverService implements CanActivate {
constructor (private config: ConfigService) {}
canActivate(): Observable<boolean | UrlTree> | Promise <boolean | UrlTree> | boolean | UrlTree {
return this .config.loadAppConfig().pipe(
map( () => true ),
catchError( () => EMPTY)
);
}
}
config.service.ts
import { Injectable } from '@angular/core' ;
import { HttpClient, HttpHeaders } from '@angular/common/http' ;
import { map } from 'rxjs/operators' ;
import { Observable } from 'rxjs' ;
@Injectable({ providedIn : 'root' })
export class ConfigService {
private _config: any = {};
constructor (private http: HttpClient) {}
get data(): any {
return this ._config ? { ...this._config } : {};
}
loadAppConfig(): Observable<any> {
const headers = new HttpHeaders().set( 'Content-Type' , 'application/json; charset=utf-8' );
return this .http.get( `/_ngx-rtconfig.json?cb= ${ new Date ().getTime()} ` , { headers }).pipe(
map( data => {
for ( const key in data) {
if (data.hasOwnProperty(key)) {
this ._config[key.replace( 'NGX_' , '' ).toLowerCase().split( '_' ).map( ( el, i ) => (i > 0 ? el.charAt( 0 ).toUpperCase() + el.slice( 1 ) : el)).join( '' )] = data[key];
}
}
return this .data;
})
);
}
}
如果您仔细观察一下,我们会更进一步,也正式确定了要获取的json键的结构。 这是有充分理由的,并且将成为非常关键的一步。
通过为json键添加一个唯一的前缀,我们以后可以利用此键为来自各个环境的键动态分配值。 对于本地开发,此设置非常简单,因为我们可以简单地将这些值直接放入config.json文件。
更进一步,将有角度的应用程序包装在docker容器中,我们需要根据容器环境调整config.json。 因此,我们将shell脚本添加为docker-entrypoint,在此期间会(重新)生成具有当前环境值的config.json。
docker-entrypoint.sh
#!/usr/bin/env sh
set -eu
jq -n env | grep -E '\{|\}|NGX_' | sed ':begin;$!N;s/,\n}/\n}/g;tbegin;P;D' > /usr/ share/nginx/html/_ngx-rtconfig.json
exec "$@"
Docker文件
FROM node:12.6 .0 -buster-slim AS builder
ARG NODE_ENV
ENV NODE_ENV ${NODE_ENV}
RUN mkdir -p /app
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
COPY . .
RUN yarn build
FROM nginx: 1.15 -alpine
RUN apk update && apk add jq
COPY -- from =builder build/ /usr/ share/nginx/html
COPY ./ops/config/nginx-custom.conf /etc/nginx/conf.d/ default .conf
EXPOSE 80
# generate dynamic json from env
COPY ./ops/config/docker-entrypoint.sh /
ENTRYPOINT [ "/docker-entrypoint.sh" ]
CMD [ "nginx" , "-g" , "daemon off;" ]
我们在这里使用了jq和一些基本的脚本,但是当然有很多方法可以实现相同的目的。 这种方法确实允许我们在docker-compose和部署清单中将角度配置值指定为env变量。
docker-compose.yml
version:"3.5"
services:
ngx-app:
container_name: ngx-app
build:
context: .
dockerfile: Dockerfile
environment:
NGX_API_ENDPOINT: http: //localhost:3000
ports:
- '4200:80'
Deployment.yml
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: {{ CI_PROJECT_NAME }}
spec:
replicas:3
revisionHistoryLimit: 3
template:
spec:
containers:
- name: {{ CI_PROJECT_NAME }}
image: {{ CI_REGISTRY_IMAGE }}:{{ CI_COMMIT_SHA }}
imagePullPolicy: Always
env:
- name: NGX_API_ENDPOINT
value: https: //foo.com/api/
ports:
- name: http
containerPort: 80
最后,我们已经完成了建立一个灵活而一致的机制来动态管理不同情况下的角度配置/环境的工作。 到目前为止,我们还没有意识到这种方法的任何缺点!
参考文献:
- [1]“我怎样才能使用Nginx.conf环境变量” - https://serverfault.com/questions/577370/how-can-i-use-environment-variables-in-nginx-conf
- [2]“如何使用环境变量配置Angular应用程序而无需重建” -https://www.jvandemo.com/how-to-use-environment-variables-to-configure-your-angular-application-without -a重建/
翻译自: https://hackernoon.com/applying-angular-runtime-configurations-in-dockerized-environments-kr3a33pr
angular环境配置