I am having angular cli project and node project running two seperate docker containers.
Here is my 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;"]
The node container URL is stored inside environment.ts (angular).
Environment.ts file
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'
};
Node API_URL is taken during the build time of angular project. But I want to modify the environment variable during the docker run command. ( i.e ) I want to dynamically add environment variable value to the environment.ts file during docker container runtime
Such as, docker run -e API_URL=192.168.10.147:3000 -p 4200:80 --name=angular angular_image
How can I achieve this?
I'll try to summarize the solution I've worked out with a colleague developing an Angular app, to solve exactly this problem. To better illustrate the solution, I start by including a depiction of the dev folder tree for our angular application (folder names are in square brackets), each relevant element of which is described below:
+---[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 ...
In your angular cli project configuration data that need to be replaced at runtime with the values of environment variables are kept in a static json file in the application assets. We choose to locate this for instance at assets/json/runtime.json
. In this file, values to be replaced are handled like the ${API_URL}
variable in the following example:
./src/assets/json/runtime.json:
{
"PARAM_API_URL": "${API_URL}"
...other parameters...
}
At runtime, the angular code will read the value of PARAM_API_URL
from this file, whose contents will have been modified at runtime with environment values as explained below. Technically, the json is read by one Angular service by means of http that is, the web application performs a HTTP GET operation to itself to the URLs of the static asset json file above.
@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 ...
}
);
}
}
To create a docker container that performs the environment replacement at runtime startup, a script startup.sh
will be put inside it (see Dockerfile
below) that, at container startup peforms an evnsubst on the above file before launching the nginx web server:
./docker/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;'
As shown below, the Dockerfile performs the following operations: after copying the compiled angular files in ./dist
), then defines the startup.sh
script as a CMD starting point (the host /dist
folder is COPYed in /usr/share/nginx/html
, that's why this is the path used to locate the runtime.json file mentioned in the envsubst invocation above). Note that, differently from your Dockerfile, here we don't include the build stage of the angular cli sources, instead, the ng build
is supposed to have been performed by the developers before the container image creation - and the result of such build is expected to be found in the ./dist
folder. This is a minor difference for what concerns the solution to the problem at hand, though.
./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
Now, when you build your container you can run it with:
docker run -e "API_URL=<your api url>" <your image name>
and the given value will be replaced inside runtime.json before launching nginx.
For completeness, though not relevant for the specific problem, I include also the docker/nginx/default.conf
file to configure the nginx instance
./docker/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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With