Serving an NX monorepo of angular apps in Docker-compose
Asked Answered
M

2

8

I have an NX monorepo with 2 apps:

  • Shop
  • Landing

I wish to use docker-compose to run my entire environment with eventually some APIs and a database etc etc.

I created a docker-file that takes arguments and could be re-used to to run multiple angular apps in Nx:

# base image
FROM node

ARG APP


# # install chrome for protractor tests
# RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
# RUN sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
# RUN apt-get update && apt-get install -yq google-chrome-stable
# set working directory
WORKDIR /app

# add `/app/node_modules/.bin` to $PATH
ENV PATH /app/node_modules/.bin:$PATH

# install and cache app dependencies
COPY package.json /app/package.json
COPY decorate-angular-cli.js /app/decorate-angular-cli.js
RUN npm install
RUN npm install -g @angular/cli@latest
RUN npm install reflect-metadata tslib rxjs @nestjs/platform-express

# add app
COPY . /app
# start app
CMD npm start $APP -- --host 0.0.0.0 --port 4200 --disableHostCheck=true --poll 100

and I created a docker-compose file that sets up an .net 5 API and the 2 web applications:

version: '3.4'

services:
  sletsgo.user.api:
    image: ${DOCKER_REGISTRY-}sletsgo.user.api
    build:
      context: .
      dockerfile: SletsGo.User.Api/Dockerfile
    ports:
      - "5000:2000"
      - "444:443"

  sletsgo.shop:
    container_name: 'SletsGo.Shop'
    image: ${DOCKER_REGISTRY}sletsgo.shop:dev
    build:
        context: SletsGo
        dockerfile: .docker/Dockerfile
        args:
            - APP=shop
    ports:
        - '4000:4200'
    #volumes:
    #    - sletsgo-web:/app
    #    - '/app/node_modules'

  sletsgo.landing:
    container_name: 'SletsGo.Landing'
    image: ${DOCKER_REGISTRY}sletsgo.landing:dev
    build:
        context: SletsGo
        dockerfile: .docker/Dockerfile
        args:
            - APP=landing
    ports:
        - '4100:4200'
  #  volumes:
  #      - sletsgo-web:/app
  #      - '/app/node_modules'

 


#volumes:
# sletsgo-web:
#    driver: local
#    driver_opts:
#      type: local
#      device: ./SletsGo
#      o: bind

Please note that a lot of lines are commented out. The issue is that if I run this docker-compose i get 2 instances of the shop application ran.

screenshot showing 2 instaces of shop

How can i fix this?

P.S. I also imagine that using volumes i might be able to simplify things a lot. But the mounting i tried failed because im using linux containers on a windows machine. If someone is willing to help me to that next level i would like that very much, but for now i just want to run both the web applications.

Maitland answered 3/4, 2021 at 21:1 Comment(10)
Try adding the following property to your landing service: command: npm start landing -- --host 0.0.0.0 --port 4200 --disableHostCheck=true --poll 100Bituminous
Add it where exactlyt?Maitland
services -> sletsgo.landing -> command: npm start landing -- --host 0.0.0.0 --port 4200 --disableHostCheck=true --poll 100. The thing is, APP argument may be empty when you start the container. command in service definition overrides CMD from Dockerfile.Bituminous
Do i then not use the dockerfile anymore?Maitland
No, you still need the Dockerfile but if it worked it proved that the problem is in argument missing. Did it help?Bituminous
Persisting the APP values in the environment during the build should solve the issue. Otherwise you can overwrite the command for both services in the docker-compose.yaml.Ascogonium
why you need --host 0.0.0.0 in the docker file if you are mapping the port in the Docker compose?Poor
@Bituminous your solution works! strange since when i had an echo in my dockerfile it would show it. Couldnt i just remove the dockerfile all together if i had a volume mounted?Maitland
@NikhilWalvekar Idk this is how i got it working before. maybe its redundant now.Maitland
@NikhilWalvekar Doesnt work without d--host 0.0.0.0Maitland
A
7

TL;DR

ARG's are build time variables. You can persist the ARG's value in the images environment during the build or override the services[*].command in the docker-compose.yaml.


Persist in the environment

You can persist an environment variable set from a --build-arg in the images environment during the build:

FROM alpine:3
ARG APP
ENV APP=${APP}
CMD echo $APP

Build the docker image: docker build --rm --build-arg APP=123 -t so:66935830 .

Run the docker container: docker run --rm -it so:66935830

docker run with environment variable set from --build-arg

Override the command

You can override the command for each service in the docker-compose.yaml:

version: '3.7'
services:
  a:
    image: 'a'
    build:
      context: '.'
    command: ['echo', '123']
  b:
    image: 'b'
    build:
      context: '.'
    command: ['echo', '456']

docker-compose run command override

Ascogonium answered 12/4, 2021 at 18:32 Comment(1)
Thanks for this lesson! very helpfulMaitland
P
0

Project Structure

apps

  • ProjectA
  • -ProjectB
  • package.json
  • packageLock.json
  • decorate-angular-cli.js
  • tsconfig.base.json
  • nx.json

Create a Dockefile in root level

     # Use a specific version of the official Node.js image based on the slim variant
    FROM node:18.15.0-bullseye-slim AS build
    
    # Set the working directory
    WORKDIR /usr/src/root
    
    # Copy required files for installing dependencies
    COPY package.json package-lock.json nx.json tsconfig.base.json decorate-angular-cli.js ./
    COPY libs/ ./libs/
    COPY apps/ ./apps/
    
    
    
    # Install npm dependencies
    RUN npm ci
    
    # Install nx globally
    RUN npm install -g nx
    
    # Set NX_DAEMON environment variable to false to prevent nx from running in daemon mode
    ENV NX_DAEMON=false
    
    # Build the application
    RUN nx run projectA:build
    RUN nx run projectB:build
    
    
    # Create a new stage for the runtime image
    FROM node:18.15.0-bullseye-slim AS runtime
    
    # Set the working directory
    WORKDIR /usr/src/root
    
    # Copy build artifacts from the build stage
    COPY --from=build /usr/src/root/dist/apps/projectA /usr/src/root/dist/apps/projectA
    
    # Copy build artifacts from the build stage
    COPY --from=build /usr/src/root/dist/apps/projectB /usr/src/root/dist/apps/projectB
    
    # Expose ports
    EXPOSE 4200
    EXPOSE 4300
    # Install serve globally
    RUN npm install -g serve

Create a docker-compose.yaml in root level

   version: '3.4'
services:
  projectA:
    container_name: 'projectA'
    image: projectA
    build:
      context: '.'
      dockerfile: Dockerfile
    command:
      ['serve', '-s', 'dist/apps/projectA', '--listen', 'tcp://0.0.0.0:4200']
    ports:
      - 4200:4200
  projectB:
    container_name: 'projectB'
    image: projectB
    build:
      context: '.'
      dockerfile: Dockerfile
    command:
      ['serve', '-s', 'dist/apps/projectB', '--listen', 'tcp://0.0.0.0:4300']
    ports:
      - '4300:4300'

run docker-compose up in root level.

Potash answered 28/2 at 20:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.