In AWS ECR I have 2 images, and I wish to create an image that is the result of combining the contents of these two images. I have the following Dockerfile to do this:
FROM *insert image uri of image #1* as a
COPY --from=a . /a
FROM *insert image uri of image #2* as b
COPY --from=b . /b
When I try to run docker build . -t final-image:latest --file ., I get Error response from daemon: unexpected error reading Dockerfile: read /var/lib/docker/tmp/docker-builder590433020: is a directory. Would anyone know what the correct way to build this image would be?
You are passing a directory in place of the file argument.
Since you are used the dot, which is the current dir, you can omit the file argument, given the assumption your Dockerfile is called Dockerfile and exists in the context dir. Otherwise, point to it to the actual file.
In any case, use the dot as (last) positional argument to provide the context dir.
Run one of:
docker build --tag myimge .
docker build --tag myimage --file /path/to/Dockerfile .
Afterwards, your Dockerfile doesn't make a lot of sense. If you want to copy from 2 existing images, you can reference them directly.
As example:
FROM busybox
COPY --from=docker.io/ubuntu /foo /a
COPY --from=docker.io/debian /bar /b
Another problem is that you COPY from the same stage you are currently in, twice:
FROM foo as a
# here you say copy from a but you are currently in a
# so that doesnt make sense
COPY --from=a . /a
If you want to copy from a previous stage, you need to name the previous stage, not the current one:
FROM foo as a
RUN /touch /myfile
FROM bar as b
COPY --from a /myfile /mycopy
You can chain this, of course, with more stages.
Related
I have two custom images. One is for developing websites using next.js and the other is to develop APIs.
My company/site image is like:
FROM node:lts-bullseye-slim
# the rest of it
And my company/api image is like:
ARG VARIANT="6.0-bullseye-slim"
FROM mcr.microsoft.com/vscode/devcontainers/dotnet:${VARIANT}
# the rest of it
The problem is that, the COPY commands works when I use company/api as my FROM image, but fails when I use company/site.
In other words, this works:
FROM company/api
COPY . .
RUN /buildScript.sh
But for the same directory, the same context, the same everything, this fails:
FROM compnay/site
COPY . .
RUN /buildScript.sh
In other words, COPY copies no file to the image. Everything is the same. There is no .dockerignore file. The same directory, the same context, the same syntax docker build -t company/api-or-site .
The only thing that causes this fail, is changing the base image.
What can cause this error? How can I debug this?
After spending days on this, I finally realized what the problem was.
When you create a custom image using a Dockerfile, if you use the WORKDIR command, then that would be the . in your future COPY commands.
Consider the following image:
FROM node:lts-bullseye-slim
# Your specific commands
WORKDIR /project
Let's say you build this image and tag it company/node.
Now if you want to use it as the base image for another image, and COPY . . files, then those files would be copied to the /project directory.
FROM company/node
COPY . . # here, the second dot means the relative path inside the company/node image
I have to create a Dockerfile to copy certain zip files. Assume the files are
/opt/source
A.zip
B.zip
C.zip
D.zip
Dockerfile
When building Dockerfile, I will be passing the file names as an argument in arraylist format, as below:
docker build -t mch --build-arg arg1="A.zip B.zip C.zip D.zip" --no-cache .
The crux is file names can vary each time when building the Dockerfile; for example, only A, B and C file will only be available or sometime more file will be available or at times there could be zip files that shouldn't be copied at all. Only the ones mentioned in the argument should be picked.
How could I complete file to iterate through arg1 arraylist to copy the files from local to container while building? Different approach on this are welcome.
My Dockerfile contains:
# The official Red Hat registry and the base image
FROM registry.access.redhat.com/ubi8/ubi:8.2
ARG arg1
RUN yum install -y unzip && \
yum install -y procps && \
mkdir -p /opt/dict
WORKDIR /opt/dict
COPY $arg1 .
I can think of three reasonable approaches to do this, depending on what exactly you're trying to copy in.
Separate Dockerfile per file set. Say these images are substantially different in some predictable way; one image has application-a.jar and static-files.zip, and another has application-b.jar, static-files.zip, and public-keys.zip. You can create two separate Dockerfiles
# a.dockerfile
COPY application-a.jar static-files.zip .
# b.dockerfile
COPY application-b.jar static-files.zip public-keys.zip .
and then build the separate images
docker build -t me/application-a -f a.dockerfile .
docker build -t me/application-b -f b.dockerfile .
Manually construct the build context. On the host system, you can create a directory tree that contains only the specific files you need:
rm -rf build-context
mkdir build-context
cp Dockerfile application-a.jar static-files.zip build-context
docker build -t me/application-a build-context
Nothing that's not in this build-context directory will be accessible to the Dockerfile, so you can directly put
COPY . . # copies everything in the build context
(I used this approach with a host build system to simulate what multi-stage builds would eventually do, before there were multi-stage builds. If the files you're omitting are large, this can result in a faster build as well.)
Edit the Dockerfile. You can create a template Dockerfile that looks like
# Dockerfile.tmpl
COPY %FILES% .
and then use a tool like sed(1) to fill in the template variables
sed 's/%FILES%/application-a.jar static-files.zip/' Dockerfile.tmpl > Dockerfile
You might be able to use envsubst(1), with a little easier syntax, but it could conflict with the native Dockerfile variable substitution or variable references in RUN statements. You need to be careful with quoting and syntax if there are punctuation conflicts.
I'm new to Docker so please be kind.
I have a Dockerfile I'm working on that uses the COPY instruction to copy some files into an image I'm building. The COPY is working fine, the files end up in my Docker image at the end. The problem I have is when using the RUN command to execute a sed find and replace statement on some of the files I just copied to the image does not appear to make the changes in the final docker image.
This is the build command I'm using.
docker build --build-arg web_domain=mydomain.com -t me/myproject:latest .
Here is a sample of the Dockerfile.
FROM mattrayner/lamp:latest-1804
# Custom Arguments
ARG web_domain
# Copy Files Into Image
COPY /app/src/ /app/src/
# Add Domain to config
RUN sed -i "s|\$domain = '';|\$domain = '${web_domain}';|g" /app/src/config.ini
# Entrypoint
CMD ["/run.sh"]
I'm expecting that this file /app/src/config.ini will contain a line in it that looks like:
$domain = 'mydomain.com';
What I'm finding is the file in the resulting docker container when it is run looks like this.
$domain = '';
I'm suspecting that because the copied file is not part of the base image that my changes with the sed command are only applied to the container produced with the RUN instruction. If that's the case how do I get the edited file into the docker image I'm trying to build?
Thanks for your effort in checking this out. The sample Docker file was a subset of a larger Dockerfile but it did hold the essential commands that I needed to work. I've since resolved this issue by simply running the SED command much earlier in the build process, directly after I do the COPY command.
I also added the following setting to my Docker config but I don't think it's related.
"features": {"buildkit": true}
I am confused about whether . means that it's a shortened abbreviation of the current directory of the image or if it's the current working directory on the local machine. Or is it the same meaning of . in most console commands like essentially selecting all in the current directory.
COPY somecode.java .
#copy the rest of the code
COPY . .
The . also seems to mean find the docker file in the current directory.
docker build -t image-tag .
The . simply means "current working directory"
docker build
In the context of the docker build command, you are using it to signal that the build context for docker build is the current working directory. Like so:
docker build -t mytag:0.1 .
Let's say that you have this structure:
/home/me/myapp/
├── Dockerfile
├── theapp.py
And you invoke the docker build command from /home/me/myapp - you will pass the current working directory as the build context. This means that docker will see the following filestructure when building:
/
├── Dockerfile
├── theapp.py
Dockerfile
In the context of a Dockerfile, it means that same. Both inside and outside the image.
Take this COPY instruction for example:
COPY . /app
Here the . means the current working directory, where the docker build command is executed. This will be relative the to build context that is passed to the docker build command.
For this COPY instruction:
COPY theapp.py .
It means, take the file theapp.py and copy it to the working directory of the docker image that is being built. This directory can be set at build time with the WORKDIR instruction, so that:
WORKDIR /app
COPY theapp.py .
Would leave you with the file /app/theapp.py inside the resulting docker image.
Finally, this COPY instruction:
COPY . .
Means take everything from the working directory where the docker build command is issued, relative to the build context that is passed to it. And copy it to the current working directory of the docker image.
I saw 3 . characters on your question, so let me expand one by one.
The first, as you imagine, the . character means the current directory.
In your Dockerfile
COPY . .
The second dot represented the current location on your virtual machine. Whenever you run cd command in the Dockerfile. That may be easy to understand.
The first dot more unintelligible a little. The first dot character represented the current location on your host machine. The location you input after docker build command like that:"docker build [options] <location>".
Docker build command
The dot character means the current directory whenever you call your docker build command. For example:
[~]$ docker build .
The dot character represented for default home directory of this user on your real machine.
It depends on the context. In your COPY somecode.java . it's the image. In COPY . . it's both. The first dot is in the local machine and the second dot is the image.
In the docker build command, it tells Docker to take files for the newly built image from the working directory on your local machine.
As others said, it's basically just means "current working directory". But when building a Docker image, there are two of those. One in your local machine where you're building the image. The second one is the file system that's built in the image.
.(dot) means current working directory.
I have a Dockerfile that creates the build image I want to use here: ~/build/Dockerfile then I use a standard image to deploy
The image built from ~/build/Dockerfile is not Published anywhere, I know I can simply copy paste the one Dockerfile into the other, however it would be better if I could simply reference it so..
Is it possible to somehow reference the Dockerfile itself when deploying?
like so:
FROM [insert something that creates an image using ~/build/Dockerfile] as build-env
... build operations ....
FROM some-image
COPY --from=build-env /built .
ENTRYPOINT [blah]
This won't work but is there some other way to accomplish this?
No you can't do it because you have to provide an image to FROM.
Change the COPY line to
COPY --from=step1 /built .
And write a script to build your image:
cd path1
docker build -t step1 .
cd path2
docker build -t final_image .
(if you don't want to hard code step1 in the Dockerfile, replace it with a var and call with ARG)
Generally things in Docker space like the docker run command and the FROM directive will use a local image if it exists; it doesn't need to be pushed to a repository. That means you can build your first image and refer to it in the later Dockerfile by name. (There's no way to refer to the other Dockerfile per se.)
Newer versions of Docker have an extended form of the Dockerfile COPY command which
accepts a flag --from=<name|index>.... In case a build stage with a specified name can’t be found an image with the same name is attempted to be used instead.
So if you ahead of time run
docker build -t build-env ~/build
then the exact syntax you show in your proposed Dockerfile will work
FROM some-image
COPY --from=build-env /built .
and it doesn't matter that the intermediate build image isn't actually pushed anywhere.