In Angular the BASE/API URLs are be stored environment files which are present under src/environments directory. Usually we can create new file for each environment.
- environment.ts
- environment.dev.ts
- environment.test.ts
- environment.stage.ts
- environment.prod.ts
environment.ts
import packageInfo from '../../package.json';
export const environment = {
production: false,
BASE_URL: '//localhost:4200',
VERSION: packageInfo.version,
};
During the build, a configuration flag is provided to swap the default environment.ts
file with environment.<CONFIGURATION>.ts
based on the flag
npm run build -- --configuration=stage
The problem with this approach is you can’t reuse same build for multiple environments and promote DEV to TEST then to STAGE eventually to PROD since BASE_URL is hard coded during build. To prevent this we need to replace the BASE_URL in main.*.js
file generated by Angular during the Docker container start up.
First lets look at standard Dockerfile that follows multi stage Dockerfile. To better understand this, refer my other post.
Dockerfile
// See my other post for Build stage, so skipping it here
############ User Nginx alpine image ############
FROM nginx:stable-alpine
# Remove default nginx website
RUN rm -rf /usr/share/nginx/html/*
# Copy nginx config file
COPY ./nginx/nginx.conf /etc/nginx/nginx.conf
# Copy dist folder fro build stage to nginx public folder
COPY --from=builder /app/dist /usr/share/nginx/html
# Start NgInx services
CMD ["nginx", "-g", "daemon off;"]
In this we can add single that will update the BASE_URL during Docker container/service. Let’s say out BASE_URL/API_URL is employee-dev.example.com
, then it can be replaced with UNIX sed
command as shown below
CMD sed -i "s/employee-dev.example.com/employee-$CONFIGURATION.example.com/g" /usr/share/nginx/html/main.*.js && nginx -g 'daemon off;'
So the updated Dockerfile looks as below
Dockerfile (Updated)
// See my other post for Build stage, so skipping it here
############ User Nginx alpine image ############
FROM nginx:stable-alpine
# Remove default nginx website
RUN rm -rf /usr/share/nginx/html/*
# Copy nginx config file
COPY ./nginx/nginx.conf /etc/nginx/nginx.conf
# Copy dist folder fro build stage to nginx public folder
COPY --from=builder /app/dist /usr/share/nginx/html
# Start NgInx services
CMD sed -i "s/employee-dev.example.com/employee-$CONFIGURATION.example.com/g" /usr/share/nginx/html/main.*.js && nginx -g 'daemon off;'
and you can start the container with Docker run command
docker run -p 4000:80 -e CONFIGURATION=test <IMAGE_ID>
Entrypoint
When multiple variables need to be replaced, then using multiple sed commands Dockerfile can be cumbersome. For this we can use Docker ENTRYPOINT to achieve the same result. To do this using ENTRYPOINT, create new start.sh script file and copy the command.
start.sh
#!/bin/sh
sed -i "s/employee-dev.example.com/employee-$CONFIGURATION.example.com/g" /usr/share/nginx/html/main.*.js
sed -i "s|client_id|$APP_CLIENT_ID|g" /usr/share/nginx/html/main.*.js
# Start Nginx
nginx -g "daemon off;"
and make sure to copy this file, make it executable and refer in ENTRYPOINT
Dockerfile (Updated with ENTRYPOINT)
###### User Nginx alpine image ######
FROM nginx:stable-alpine
ENV CONFIGURATION='dev'
# Remove default nginx website
RUN rm -rf /usr/share/nginx/html/*
# Copy nginx config file
COPY ./nginx/nginx.conf /etc/nginx/nginx.conf
# Copy dist folder fro build stage to nginx public folder
COPY /dist /usr/share/nginx/html
COPY start.sh /usr/share/nginx/html
RUN chmod +x /usr/share/nginx/html/start.sh
# Start NgInx service
ENTRYPOINT ["/usr/share/nginx/html/start.sh"]
and start the container with Docker run command
docker run -p 4000:80 -e CONFIGURATION=test <IMAGE_ID>
If you are not using Docker you can also same approach, since sed
is simple UNIX command