I've been building nodejs applications and wanted to investigate projects inside a Docker container.
But when I check the running container via bin/bash I cannot find /app directory in a container
While building image no errors are being displayed
This is my docker image file
FROM node:15.7.0 as build-stage
WORKDIR /app
COPY package*.json /app/
RUN npm install
COPY ./ /app/
ARG configuration=production
RUN npm run build -- --output-path=./dist/out --configuration $configuration
FROM nginx:1.18
COPY --from=build-stage /app/dist/out/ /usr/share/nginx/html
COPY ./nginx-custom.conf /etc/nginx/conf.d/default.conf
Sèdjro has the correct answer, but I wanted to expand on it briefly.
You're using what is called a multi-stage build. If you haven't seen them already, the linked docs are a good read.
Each FROM ... line in your Dockerfile starts a new build stage, and only the contents of the final stage are relevant to the generated Docker image.
Other stages in the file are available as sources of the COPY --from=... directive.
In other words, as soon as you add a second FROM ... line, as in...
FROM node:15.7.0 as build-stage
.
.
.
FROM nginx:1.18
...then the contents of the first stage are effectively discarded,
unless you explicitly copy them into the final image using COPY --from=.... Your /app directory only exists in the first stage, since you're copying it into a different location in the final stage.
The /app directory is not inside of your docker image.
It's in your build stage image.
Check the /usr/share/nginx/html directory or don't use build stage.
Related
I saw a dockerfile for building a Node.js app with npm:
FROM diamol/node AS builder,
WORKDIR /src
COPY src/package.json .
RUN npm install <-------------Q2
# app
FROM diamol/node <-------------Q1
EXPOSE 80
CMD ["node", "server.js"]
WORKDIR /app
COPY --from=builder /src/node_modules/ /app/node_modules/
COPY src/ .
I have some questions:
Q1-Why we need FROM diamol/node twice, we already have it in the beginning, isn't it, what will happen if I remove the second FROM diamol/node
Q2- when the instruction runs npm install, a lot of packages are downloaded to src folder and we know each instruction represents an image layer, so does those packages stored in "RUN npm install" layer, or they are saved in "WORKDIR /src" layer since src folder is created here?
You can think as if they were 2 different Dockerfiles. So each one requires it's base image (FROM). And each one has its own layers.
The additional benefit from multi-stage is that it allow you to copy from one image to the other (the --from=builder in COPY instruction).
The npm install in first image creates a new layer with node_modules directory.
The COPY --from=builder in the second one, just copies that directory from the resulting first image.
This particular example doesn't seem to have any advantage over a single stage build.
Hi everyone I'm facing a strange issue in the creating of a docker image for a remix.run app, and using it inside a github job.
I have this Dockerfile
FROM node:16-alpine as deps
WORKDIR /app
ADD package.json yarn.lock ./
RUN yarn install
# Build the app
FROM node:16-alpine as build
ENV NODE_ENV=production
WORKDIR /app
COPY --from=deps /app/node_modules /app/node_modules
COPY . .
RUN yarn run build
# Build production image
FROM node:16-alpine as runner
ENV NODE_ENV=production
ENV PORT=80
WORKDIR /app
COPY --from=deps /app/node_modules /app/node_modules
COPY --from=build /app/build /app/build
COPY --from=build /app/public /app/public
COPY --from=build /app/api /app/api
COPY . .
EXPOSE 80
CMD ["npm", "run", "start"]
If build the image on my local machine, everything works fine, and I'm able to run the container and point at it.
I made a github workflow build the same image and push it on my docker hub.
But when the github job runs it always fail with this error
Step 16/21 : COPY --from=build /app/build /app/build
COPY failed: stat app/build: file does not exist
My remix.run config is:
/**
* #type {import('#remix-run/dev/config').AppConfig}
*/
module.exports = {
appDirectory: "app",
assetsBuildDirectory: "public/build",
publicPath: "/build/",
serverBuildDirectory: "api/_build",
devServerPort: 8002,
ignoredRouteFiles: [".*"],
};
Thanks in advance for any help
You are using the config option serverBuildDirectory: "api/_build", so when you run the remix build, your server built files are in api/_build/ and not in build/ directory.
In your docker image, at the last stage you try to copy the content of the build/ directory from the previous stage named build. But that directory does not exist there. The server content is built in api/_build/ instead.
So you just don't need that line:
COPY --from=build /app/build /app/build
One possible reason I see for the fact it works for you locally:
You have a local directory named build/, and which contains your local build for server files. Maybe because you built it before changing the serverBuildDirectory option. And it's probably ignored from your git repository.
When you build your docker image, the stage named build copies
everything from your local directory to its own environment with
COPY . ., and so it gets your local build/ directory.
then during the last stage that directory is copied to the final environment with COPY --from=build /app/build /app/build.
When you do the same thing in a fresh environment like github actions, the build/ directory does not exist in the environment that runs the docker command so it's not copied from stage to stage. And you finally get an error trying to copy something that does not exist.
This artifact copying is probably not what you want. If you do the build in your docker image, you don't want also to copy it from your local environment.
To avoid these unwanted copies, you can add a .dockerignore file with at least the following things:
node_modules
build
api/_build
public/build
I am new to Docker and got confused in couple of things. I have few queries as well. Please find them below. I would be happy if these queries got resolved.
Question 1:
In multi-stage builds, how does docker identify the artifacts of a stage? Because I saw in many articles, people say COPY --from=0 src dest will copy the artifacts from the last build stage. I mean where have we explicitly defined that you need to copy the artifacts from this folder? What defines the build output/build artifact of a stage?
# Stage 1
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /build
COPY . .
RUN dotnet restore
RUN dotnet publish -c Release -o /app
# Stage 2
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS final
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "Core3Api.dll"]
Q2 - Does COPY --from=build src dest copy files from a previous build or the image?
Q3 - Normally copy has two parameters, one is the source and the
other is a destination. Above we have three parameters,
--from=build src dest. How does this copy works?
Q4 - Do we need to set WORKDIR in every build stage? Because I
think every build stage executes in a new isolated context? OR it
uses the same context?
Q5 - Where does Docker stores previous build's image when it moves to
next stage?
All my questions are interrelated, that's why I clubbed all into one.
Docker builds images; each image consists of a filesystem plus some additional metadata. Within the context of a multi-stage build (Q5) each FROM line starts a new image build, and the result of these image builds are totally normal images; you can see them (probably with a <none> name) in docker images output. Similarly, because each build stage stars FROM the context of some previous image, (Q4) you do need to repeat WORKDIR in every stage where it matters (but since each stage is in an isolated build context, different stages don't necessarily need the same working directory).
The Dockerfile COPY command (Q3) can take options, in much the same way as you can cp -r from to in a normal shell. The --from option (Q2) names an image; it can be an earlier build stage FROM ... AS name in the same Dockerfile, or it can be an arbitrary other image. (Q1) It copies from whatever the filesystem result of the image build is.
FROM ... AS build
WORKDIR /build
RUN ...
COPY ...
# An image is created that's effectively a snapshot here
FROM ...
WORKDIR /app
COPY src dest # from the build context
COPY --from=build /build/dir dest2 # from the "snapshot" point
COPY --from=0 /build/dir dest3 # from the first image in this Dockerfile
COPY --from=busybox:latest /bin/busybox dest4 # from another image
I'm using Docker to build an ASP site, and I'm confused about where my files are going. Here's my dockerfile (the application is called AspCore)
FROM microsoft/dotnet:2.2-sdk as build
ARG BUILDCONFIG=RELEASE
ARG VERSION=1.0.0
COPY AspCore.csproj /build/
RUN dotnet restore ./build/AspCore.csproj
COPY . ./build/
WORKDIR /build/
RUN dotnet publish ./AspCore.csproj -c $BUILDCONFIG -o out /p:Version=$VERSION
FROM microsoft/dotnet:2.2-aspnetcore-runtime
WORKDIR /app
COPY --from=build /build/out .
ENTRYPOINT ["dotnet", "AspCore.dll"]
This works correctly and I can access the site when I run the image, but I don't quite understand how this is working. When I open a shell to my container, I don't see a build directory either in the app directory or in the base directory. I also can't find the AspCore.csproj file.
Isn't the dockerfile copying AspCore.csproj into the build directory, so shouldn't there be a build directory with a bunch of files in it on my container? What am I misunderstanding?
That's just because you're using 2 stage on your Dockerfile to build your image.
Stage 1: (BUILD) Based on microsoft/dotnet:2.2-sdk as build image to build your source code into dll files
Stage 2: (SERVE) Based on microsoft/dotnet:2.2-aspnetcore-runtime to create a runtime for your dlls, in this stage you've already copy files from previous stage into a folder called app by this line COPY --from=build /build/out ..
After stage 2 copied files from stage1, nothing else you can see from stage1 but copied files, that's why when you start your container you didn't see /build folder
This pattern is good for production build when you want to minimize your image, because actually we don't need sdk in production environment, we just need runtime for the compiled code.
Hope that clear enough, for more information, you can take a look at this article
I have the docker file as follows:
FROM node:8 as builder
WORKDIR /usr/src/app
COPY ./src/register_form/package*.json .
RUN npm install
COPY ./src/register_form .
RUN yarn build
FROM tensorflow/tensorflow:1.10.0-gpu-py3
COPY --from=builder /usr/src/app/register_form/build/index.html /app/src/
WORKDIR /app
ENTRYPOINT ["python3"]
CMD ["/app/src/main.pyc"]
However, it cannot copy the index.html from the builder stage. Although when I list the folder in the first stage, the files are there.
The error is:
Step 8/22 : COPY --from=builder ./register_form/build/ /app/src/
COPY failed: stat /var/lib/docker/overlay2/5470e05501898502b3aa437639f975ca3e4bfb5a1e897281e62e07ab89866304/merged/register_form/build: no such file or directory
How can I fix this problem - the COPY --from=builder docker command?
I think you are misusing COPY command. As it is told in docs:
If src is a directory, the entire contents of the directory are
copied, including filesystem metadata.
Note: The directory itself is not copied, just its contents.
So your command COPY ./src/register_form . does NOT create register_form folder in container, but instead copies all contents. You can try adding:
RUN ls .
to your Dockerfile to make sure.
As noticed by #BMitch in comments, you can explicitly set destination folder name to achieve expected results:
COPY ./src/register_form/ register_form/