I was looking for a better way to use the Multi-Stage Build process for my Angular Application. Fortunately, after consulting a couple of resources, I came across something I had thought would suffice for my needs here.
I have also taken advantage of the knowledge I have already gained working with Docker & Docker-Compose. However, my recent Angular service does not seem to want to come to life.
Below is what my stack's directory structure looks like:
.
├── app
├── docker-compose.yaml <--- The docker-compose file used to boot services
├── portal
│ ├── README.md
│ ├── angular.json
│ ├── dist
│ ├── node_modules
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ └── tsconfig.spec.json
└── sys
├── mongodb
├── portal <--- Where the default.conf & Dockerfile reside for portal service
└── rabbitmq
The portal
directory contains the Angular App we are trying to Dockerize. The sys
directory contains both the default.conf
& Dockerfile
files.
I am still in the testing stage of this build and the problem is that when docker-compose tries to build the containers it fails with the portal
service. Below is, first, a typical output that shows:
Building portal
[+] Building 4.5s (11/15)
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 864B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/nginx:stable-alpine 1.1s
=> [internal] load metadata for docker.io/library/node:16-alpine 1.1s
=> [builder 1/6] FROM docker.io/library/node:16-alpine@sha256:a1f9d027912b58a7c75be7716c97cfbc6d3099f3a97ed84aa490be9dee20e787 0.0s
=> [stage-1 1/4] FROM docker.io/library/nginx:stable-alpine@sha256:210650bba35a8e714a56aadb4a5abed9db1e55a90122b4bfa38c3977be831db9 0.0s
=> [internal] load build context 3.3s
=> => transferring context: 4.91MB 3.2s
=> CACHED [builder 2/6] WORKDIR /app 0.0s
=> ERROR [builder 3/6] COPY package.json . 0.0s
=> CACHED [stage-1 2/4] RUN rm -rf /usr/share/nginx/html/* 0.0s
=> CACHED [stage-1 3/4] COPY sys/portal/default.conf /etc/nginx/nginx.conf 0.0s
------
> [builder 3/6] COPY package.json .:
------
failed to compute cache key: "/package.json" not found: not found
ERROR: Service 'portal' failed to build : Build failed
I have thoroughly inspected my Dockerfile and ensured that everything makes sense and is configured based on my directory structure.
The actual Dockerfile looks as shown below:
###### Install dependencies only when needed ######
FROM node:16-alpine AS builder
ARG CONFIGURATION='development'
# Make /app as working directory
WORKDIR /app
# Copy package.json file
COPY package.json .
# Install dependencies
RUN npm install --legacy-peer-deps
# Copy the source code to the /app directory
COPY . .
# Build the application
RUN npm run build -- --output-path=dist --configuration=$CONFIGURATION --output-hashing=all
###### Use NgInx alpine image ######
FROM nginx:stable-alpine
# Remove default nginx website
RUN rm -rf /usr/share/nginx/html/*
# Copy nginx config file
COPY sys/portal/default.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 service
CMD ["nginx", "-g", "daemon off;"]
From the way I see it, things should be working okay with regards to the build
stage since I declare that /app
is my working directory and the fact that I have this directory also mapped under the volumes
entry in docker-compose.yaml
file.
services:
portal:
container_name: coolstuff_portal
image: coolstuffportal:local
build:
context: .
dockerfile: sys/portal/Dockerfile
ports:
- 9300:80
expose:
- 80
volumes:
- ./portal:/app
- /app/node_modules
networks:
- coolstuff-solutions
With all these configurations in place, I am left confused as to what I am getting wrong based on my directory structure.
I'd appreciate pointers in the right direction, thanks.
In the Compose file, you say
build:
context: . # relative to the location of docker-compose.yml
and so in the Dockerfile when you say
COPY package.json .
it looks for the file on the left-hand side in the top-level directory.
The way your file structure is currently set up, you need the build context directory where it is (you can't COPY
from a parent or sibling directory, so it must be a parent or ancestor directory of all of the files that are included. You need to change the two COPY
lines to be relative to the parent directory
COPY portal/package.json ./
...
COPY portal/ ./
The volumes:
block isn't used at all during the image build. I'd recommend removing it entirely: the first line replaces absolutely all of the content you put in the Dockerfile, so you're never running your image proper, and the second line takes the node_modules
tree from a Docker named volume that needs to be separately maintained. This setup runs Node in Docker more than "Dockerizing your application".