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

时间:2018-04-04 11:42:41

标签: docker angular-cli

我正在使用角度cli项目和节点项目运行两个单独的docker容器。

这是我的Dockerfile

### 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(angular)中。

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 在角项目的构建时间内进行。但我想在docker run命令期间修改环境变量。 (即)我想在docker container runtime

期间动态地将环境变量值添加到environment.ts文件中

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

我怎样才能做到这一点?

1 个答案:

答案 0 :(得分:9)

我将尝试总结我与开发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 /资产/ JSON / runtime.json

{
  "PARAM_API_URL": "${API_URL}"

  ...other parameters...
}

在运行时,角度代码将从此文件中读取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),在容器启动时,在上面的文件中执行一个evnsubst在启动nginx Web服务器之前:

<强> ./搬运工/ startup.sh

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;'

如下所示,Dockerfile执行以下操作:在./dist)中复制已编译的角度文件后,将startup.sh脚本定义为CMD起点( host /dist文件夹在/usr/share/nginx/html中被复制,这就是为什么这是用于查找上面envsubst调用中提到的runtime.json文件的路径。请注意,与Dockerfile不同,这里我们不包括角度cli源的构建阶段,相反,ng build应该由开发人员在容器映像创建之前执行 - 并且预计会在./dist文件夹中找到此类构建的结果。不过,对于解决问题的方法来说,这是一个微小的差异。

<强> ./ Dockerfile

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 

现在,当您构建容器时,可以使用以下命令运行它:

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

并且在启动nginx之前将在runtime.json中替换给定值。

为了完整性,虽然与特定问题无关,但我还包括docker/nginx/default.conf文件来配置nginx实例

<强> ./搬运工/ nginx的/ default.conf

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;
  }

}