如何使用Docker将环境变量动态分配给angular cli项目?

如何使用Docker将环境变量动态分配给angular cli项目?,docker,angular-cli,Docker,Angular Cli,我有angular cli项目和node项目运行两个独立的docker容器 这是我的文件 ### STAGE 1: Build ### # We label our stage as 'builder' FROM node:carbon as builder COPY package.json package-lock.json ./ RUN npm set progress=false && npm config set depth 0 && npm ca

我有angular cli项目和node项目运行两个独立的docker容器

这是我的文件

### STAGE 1: Build ###

# We label our stage as 'builder'
FROM node:carbon as builder

COPY package.json package-lock.json ./

RUN npm set progress=false && npm config set depth 0 && npm cache clean --force

## Storing node modules on a separate layer will prevent unnecessary npm installs at each build
RUN npm i && mkdir /ng-app && cp -R ./node_modules ./ng-app

WORKDIR /ng-app

COPY . .

## Build the angular app in production mode and store the artifacts in dist folder
RUN $(npm bin)/ng build --aot --build-optimizer --environment=test

### STAGE 2: Setup ###

FROM nginx:1.13.3-alpine

## Copy our default nginx config
COPY nginx/default.conf /etc/nginx/conf.d/

## Remove default nginx website
RUN rm -rf /usr/share/nginx/html/*

## From 'builder' stage copy over the artifacts in dist folder to default nginx public folder
COPY --from=builder /ng-app/dist /usr/share/nginx/html

CMD ["nginx", "-g", "daemon off;"]
节点容器URL存储在environment.ts(角度)中

Environment.ts文件

declare var require: any;
const pack = require('../../package.json');

export const environment = {
  production: false,
  API_URL: 'http://localhost:3000/',
  socket: 'http://localhost:3200',
  appName: pack.name,
  version: pack.version,
  envi: 'test'
};
节点API_URL在angular项目的构建期间获取。但是我想在docker run命令期间修改环境变量。(即)我希望在docker容器运行时将环境变量值动态添加到environment.ts文件中

比如,, docker run-e API_URL=192.168.10.147:3000-p 4200:80--name=angular_image


我如何才能做到这一点?

我将尝试总结一下我与一位同事开发Angular应用程序时提出的解决方案,以准确地解决这个问题。为了更好地说明该解决方案,我首先介绍了angular应用程序的dev文件夹树(文件夹名称在方括号中),其每个相关元素如下所述:

+---[my angular cli project]
¦   ¦
¦   +---[src]
¦   ¦   +---[assets]
¦   ¦   ¦   +---[json]
¦   ¦   ¦   ¦   +---runtime.json
¦   ¦   ¦   ¦  
¦   ¦   ¦   ..other angular application assets files ...
    ¦   ¦   
¦   ¦   ...other angular application source files...
¦   ¦
¦   +---[dist]
¦   ¦   ...built angular files
¦   ¦
¦   +---[docker]
¦   ¦   +---[nginx]
¦   ¦   ¦   +---default.conf
¦   ¦   +---startup.sh
¦   ¦
¦   +---Dockerfile
¦
... other angluar cli project files in my project ...
在angular cli项目中,需要在运行时用环境变量值替换的配置数据保存在应用程序资产中的静态json文件中。例如,我们选择将其定位在
assets/json/runtime.json
。在此文件中,要替换的值的处理方式与以下示例中的
${API_URL}
变量类似:

/src/assets/json/runtime.json

{
  "PARAM_API_URL": "${API_URL}"

  ...other parameters...
}
echo "Starting application..."
echo "API_URL = ${API_URL}"
envsubst < "/usr/share/nginx/html/assets/json/runtime.json" > "/usr/share/nginx/html/assets/json/runtime.json"
nginx -g 'daemon off;'
FROM nginx:1.13.3-alpine

## Copy our default nginx config
COPY docker/nginx/default.conf /etc/nginx/conf.d/

## Remove default nginx website
RUN rm -rf /usr/share/nginx/html/*

## copy over the artifacts in dist folder to default nginx public folder
COPY dist /usr/share/nginx/html

## startup.sh script is launched at container run
ADD docker/startup.sh /startup.sh
CMD /startup.sh 
server {

  listen 80;

  sendfile on;

  default_type application/octet-stream;

  gzip on;
  gzip_http_version 1.1;
  gzip_disable      "MSIE [1-6]\.";
  gzip_min_length   256;
  gzip_vary         on;
  gzip_proxied      expired no-cache no-store private auth;
  gzip_types        text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
  gzip_comp_level   9;

  root /usr/share/nginx/html;

  location / {
    try_files $uri $uri/ /index.html =404;
  }

}
在运行时,角度代码将从此文件中读取
PARAM_API_URL
的值,其内容将在运行时使用环境值进行修改,如下所述。从技术上讲,json是由一个Angular服务通过http读取的,也就是说,web应用程序对上面静态资产json文件的URL执行http GET操作

@Injectable()
export class MyComponent {

    constructor( private http: Http ) {
    }

    ...

    someMethod() {

        this.http.get( 'assets/json/runtime.json' ).map( result => result.PARAM_API_URL ).subscribe( 
            api_url => {
                ... do something with the api_url 
                eg. invoke another http get on it ...
            }
        );
      }

}
要创建在运行时启动时执行环境替换的docker容器,将在其中放入一个脚本
startup.sh
(请参见下面的
Dockerfile
),该脚本在容器启动时在启动nginx web服务器之前在上述文件上形成一个evnsubst:

/docker/startup.sh

{
  "PARAM_API_URL": "${API_URL}"

  ...other parameters...
}
echo "Starting application..."
echo "API_URL = ${API_URL}"
envsubst < "/usr/share/nginx/html/assets/json/runtime.json" > "/usr/share/nginx/html/assets/json/runtime.json"
nginx -g 'daemon off;'
FROM nginx:1.13.3-alpine

## Copy our default nginx config
COPY docker/nginx/default.conf /etc/nginx/conf.d/

## Remove default nginx website
RUN rm -rf /usr/share/nginx/html/*

## copy over the artifacts in dist folder to default nginx public folder
COPY dist /usr/share/nginx/html

## startup.sh script is launched at container run
ADD docker/startup.sh /startup.sh
CMD /startup.sh 
server {

  listen 80;

  sendfile on;

  default_type application/octet-stream;

  gzip on;
  gzip_http_version 1.1;
  gzip_disable      "MSIE [1-6]\.";
  gzip_min_length   256;
  gzip_vary         on;
  gzip_proxied      expired no-cache no-store private auth;
  gzip_types        text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
  gzip_comp_level   9;

  root /usr/share/nginx/html;

  location / {
    try_files $uri $uri/ /index.html =404;
  }

}
现在,当您构建容器时,可以使用以下工具运行它:

docker run -e "API_URL=<your api url>" <your image name> 

使用
process.env.env_NAME
?process.env是解决方案之一。但是不可能在环境中直接修改。这里可以找到一个更通用的方法:哇,谢谢!这应该是公认的答案。我摆弄了几下后,终于开始工作了!我想补充一点。正在对应用程序初始化的“assets/json/runtime.json”文件执行http请求。使用APP_初始值设定项提供程序(足够的文档可以在别处找到)应该是轻而易举的事。