6

I have dockerized my existing angular cli application with following setup:

Root level dockerfile:

#  Create a new image from the base nodejs 7 image.
FROM node:7
# Create the target directory in the imahge
RUN mkdir -p /usr/src/app
# Set the created directory as the working directory
WORKDIR /usr/src/app
# Copy the package.json inside the working directory
COPY package.json /usr/src/app
# Install required dependencies
RUN npm install
# Copy the client application source files. You can use .dockerignore to exlcude files. Works just as .gitignore does.
COPY . /usr/src/app
# Open port 4200. This is the port that our development server uses
EXPOSE 4200
# Start the application. This is the same as running ng serve.
CMD ["npm", "start"]

docker-compose.yml:

version: '2'

services:

  # Build the container using the client Dockerfile
  client:
      build: .
      ports: 
        - "4200:4200"

  # Build the container using the nginx Dockerfile
  nginx:
    build: ./nginx
    # Map Nginx port 80 to the local machine's port 80
    ports:
      - "85:85"
    # Link the client container so that Nginx will have access to it
    links:
      - client

I have another folder called nginx which has dockerfile:

#  Create a new image from the base nginx image.
FROM nginx
# Overwrite nginx's default configuration file with our own.
COPY default.conf /etc/nginx/conf.d/

and default.conf:

server {
    location / {
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass http://client:4200/;
    }
}

docker-compose build and docker-compose up are successful and I can access my application at localhost:4200. However, live reload dos not work e.g. whenever I change something in my .ts file or in HTML or CSS file it does not reflect immediately.

How can I fix this?

UPDATE: modified docker-compose

  # Build the container using the client Dockerfile
  client:
      build: .
  # This line maps the contents of the client folder into the container.
      volumes:
        - ./:/usr/src/app    
      ports: 
        - "4200:4200"

gives me:

enter image description here

UPDATE 2 For following docker-compose

version: '2'

services:

  # Build the container using the client Dockerfile
  client:
        image: node:6
        command: bash -c "cd /app && npm start"
        volumes:
            - D:/Development/personal_projects/library-owner-frontend :/app
        ports: 
            - "4200:4200"

  # Build the container using the nginx Dockerfile
  nginx:
    build: ./nginx
    # Map Nginx port 80 to the local machine's port 80
    ports:
      - "85:85"
    # Link the client container so that Nginx will have access to it
    links:
      - client

I am getting:

enter image description here

Thinker
  • 5,326
  • 13
  • 61
  • 137
  • Where do you change your files? Within the running container? Does live-reload work running locally, without Docker? – jannis Feb 08 '18 at 14:03
  • BTW And I think you don't need the `link: client` part in the nginx service declaration. If you are using this nginx service at all that is (you are not in the usecase you described - but you probably know that). – jannis Feb 08 '18 at 14:07
  • @jannis Yes live reload work locally without docker. I never really worked with nginx before. I was simply following (https://dpopescu.me/2017/03/13/running-angular-applications-inside-a-docker-container-part-1/) this tutorial – Thinker Feb 08 '18 at 14:12
  • What about the other question: where do you change your files? Do you log into the container and make changes there? Because only in this scenario it has a chance of working (given this Dockerfile). – jannis Feb 08 '18 at 14:16
  • I am not sure If I understand that correctly. Just to explain the workflow how I came about it: I had an existing project, I added above dockerfiles, ran: docker-compose build (it was successful), then ran docker-compose up and acced the application in my browser. Changes I was making in my workspace – Thinker Feb 08 '18 at 14:18
  • I have updated my question with a screenshot of my console, if at all it is helpful – Thinker Feb 08 '18 at 14:23
  • The changes you are doing in your local filesystem are not propagated to the running container's filesystem. Container has its own filesystem where it copied your files when you built the image (Dockerfile `COPY` command). Container doesn't have the access to your local filesystem unless you grant it (volumes, mounts) which you don't in your example. – jannis Feb 08 '18 at 14:41
  • @jannis I tried adding volumes (see updated question), but it is now giving me errors as you can see in the screenshot – Thinker Feb 08 '18 at 14:51

2 Answers2

4

OK I got this running with this command:

docker run -it --rm -p 4200:4200 -v /your/app/path:/app --name myappcontainer node:7 bash -c "cd /app && npm install && npm start"

where /your/app/path is the ABSOLUTE path to your application in your local file system (Docker host).

I tested my solution with a simple app generated with Angular's CLI ng new testApp.

What happens here is that a container is started (from image node:7) and it gets your app directory mounted under /app directory in container's file system (the -v /your/app/path:/app part). Upon starting bash -c "cd /app && npm install && npm start" command is run. It goes to the mounted directory and fires npm install and npm start comands therefore running your application. The -p 4200:4200 part maps container's 4200 tcp port to your docker host 4200 tcp port. You should see your app by navigating to http://localhost:4200 in your browser.

Translating to docker-compose it would look like this:

version: '2'

services:

    client:
        image: node:7
        command: bash -c "cd /app && npm install && npm start"
        volumes:
            - /your/app/path:/app
        ports: 
            - "4200:4200"

As a side note I'll just mention that I ran this using Docker for Windows and stumbled upon two gotchas in the process:

  • Volume file changes are not detected in container on Windows 10 host: it seems that on Windows FS events don't work properly with host mounts, so you should rather use polling to enable live-reload:

    For those who are getting into the same troubles: To achieve this with angular-cli, "poll": 1000 has to be inserted into the defaults-object in angular-cli.json. Unfortunately, this is not well documented. see angular/angular-cli#1814

  • Issues with angular-cli and node docker official image.: Angular CLI needs help binding to the network interface correctly (I can see you've got this solution hardcoded in the npm's start script):

    Under defaults in your angular-cli.json you can do the following:

    "serve": {
        "port": 4200,
        "host": "0.0.0.0"
    }
    

EDIT

Added a ready-to-run POC on Github for this: https://github.com/jannis-baratheon/stackoverflow--angular-live-reload-in-docker-container

jannis
  • 4,843
  • 1
  • 23
  • 53
  • Hi! First of all thank you so much for your detailed reply. `D:\Development\Personal projects\library-owner-frontend` this is what absolute path to my project look like. I tried replacing my docker-compose with above snippet. build was successful. However up command gave me `ERROR: for client Cannot create container for service client: invalid bind mount spec "/D:/Development/Personal projects/library-owner-frontend :/app": invalid mode: /app` – Thinker Feb 09 '18 at 12:55
  • For `volumes: - D:/Development/Personal projects/library-owner-frontend :/app` I am getting `npm ERR! enoent ENOENT: no such file or directory` and `nginx: [emerg] host not found in upstream "client" in /etc/nginx/conf.d/default.conf:7` – Thinker Feb 09 '18 at 12:58
  • Try slashes instead of backslashes. Also I'm not sure how to Docker handles spaces in mounter directory name. For starters try removing the space by renaming `Personal projects` to e.g. `personal_projects`. The path will then look like this `d:/Development/personal_projects/library-owner-frontend` – jannis Feb 09 '18 at 13:41
  • I tried with changing folder name and with different slashes but it's same. I guess I am using Docker for windows and am on linux container as I see Switch to Windows containers on right clicking on docker Icon. I have shared my D drive – Thinker Feb 10 '18 at 09:47
  • Same error. It can not find files like package.json. I will post screenshot – Thinker Feb 10 '18 at 10:01
  • why do you put a space before `:/app` in the volume declaration? – jannis Feb 10 '18 at 12:10
  • I tested you docker-compose file and managed to reproduce your error. I'm positive it's about the mentioned space. I'd think that it should throw a docker-compose syntax error but it doesn't - it just doesn't mount the volume.So in `volumes` section change: `- D:/Development/personal_projects/library-owner-frontend :/app` to `- D:/Development/personal_projects/library-owner-frontend:/app` and you're all good. – jannis Feb 10 '18 at 13:17
  • Also with the newest Docker for Windows it seems that relative path work after all so you can change it to `- .:/app` altogether and it will work as well (assuming you are in `- D:/Development/personal_projects/library-owner-frontend` when running `docker-compose up`). – jannis Feb 10 '18 at 13:22
  • Hi! First of all thanks a lot for all your replies, you were too kind. I tried this latest answer without spaces and there are no errors anymore. I have commented out nginx part. My docker was running and I gave docker-compose build and then up. I could access my app at localhost:4200. But hot reload still did not work. I tried modifying HTML and CSS but even after browser refresh changes did not reflect. – Thinker Feb 11 '18 at 10:54
  • Could something be conflicting in dockerfile and docker-compose? In dockerfile I have `/usr/src/app` whereas in dockercompose `:/app`? – Thinker Feb 11 '18 at 11:16
  • the point is you should forget about your custom docker file because it's plain wrong. use the `node` image instead. I tried with both `node:6` and `node:7` and it worked. do exactly what I wrote in my answer. additionally if you're on Windows read the 'gotchas' part (you will have to configure polling as stated there). – jannis Feb 11 '18 at 20:25
  • Okay I haven't done anything about polling, I will look into that. – Thinker Feb 12 '18 at 08:09
  • Hey Jannis! Got it running! Thanks a lot! So basically I can totally get read of my dockerfile right? I just need docker-compose? – Thinker Feb 12 '18 at 09:29
  • Yes. `node` imaghe is hosted in the Docker central repository. Glad to hear you got it working. – jannis Feb 12 '18 at 10:15
0

I came across the same issue in Docker Desktop for Windows. I know it has been a while but, anybody came here looking for a answer like me, you should do these steps.

Modify start command to "start": "ng serve --host 0.0.0.0 --poll 500" on scripts section in package.json. (Here the number 500 means that client will check every 500 milliseconds whether a change has been made, you can reduce this number. Refer this)

Make sure port 49153 is exposed in Dockerfile (use correct node version)

FROM node:10.16.3-alpine
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
EXPOSE 4200 49153
CMD npm run start

Map ports and volumes in docker-compose.yml

version: "3.7"
services:
  webapp:
    build: .
    ports:
      - "4200:4200"
      - "49153:49153"
    volumes:
      - "/app/node_modules"
      - ".:/app"

After that running docker-compose up will build an image and spin up a new container which will automatically reload with new changes.

Nishan
  • 3,644
  • 1
  • 32
  • 41