I have a docker image with the following dockerfile code:
FROM scratch
RUN echo "Hello World - Dockerfile"
And I build my image in a powershell prompt like this:
docker build -t imagename .
Here is what I do when I build my image :
Sending build context to Docker daemon 194.5MB
Step 1/2 : FROM scratch
--->
Step 2/2 : RUN echo "Hello World - Dockerfile"
---> Running in 42d5e5add10e
invalid reference format
I want to run my image with a windows container.
What is missing to make it work?
Thanks
Your image doesn't have a command called echo.
A FROM scratch image contains absolutely nothing at all. No shells, no libraries, no system programs, nothing. The two most common uses for it are to build a base image from a tar file or to build an extremely minimal image from a statically-linked binary; both are somewhat advanced uses.
Usually you'll want to start from an image that contains a more typical set of operating system tools. On a Linux base (where I'm more familiar) ubuntu and debian are common, alpine as well (though it has some occasionally compatibility issues). #gp. suggests FROM microsoft/windowsservercore in a comment and that's probably a good place to start for a Windows container.
Related
I'm confused about when should I use CMD vs RUN. For example, to execute bash/shell commands (i.e. ls -la) I would always use CMD or is there a situation where I would use RUN? Trying to understand the best practices about these two similar Dockerfile directives.
RUN is an image build step, the state of the container after a RUN command will be committed to the container image. A Dockerfile can have many RUN steps that layer on top of one another to build the image.
CMD is the command the container executes by default when you launch the built image. A Dockerfile will only use the final CMD defined. The CMD can be overridden when starting a container with docker run $image $other_command.
ENTRYPOINT is also closely related to CMD and can modify the way a container is started from an image.
RUN - command triggers while we build the docker image.
CMD - command triggers while we launch the created docker image.
I found this article very helpful to understand the difference between them:
RUN -
RUN instruction allows you to install your application and packages
required for it. It executes any commands on top of the current image
and creates a new layer by committing the results. Often you will find
multiple RUN instructions in a Dockerfile.
CMD -
CMD instruction allows you to set a default command, which will be
executed only when you run container without specifying a command.
If Docker container runs with a command, the default command will be
ignored. If Dockerfile has more than one CMD instruction, all but last
CMD instructions are ignored.
The existing answers cover most of what anyone looking at this question would need. So I'll just cover some niche areas for CMD and RUN.
CMD: Duplicates are Allowed but Wasteful
GingerBeer makes an important point: you won't get any errors if you put in more than one CMD - but it's wasteful to do so. I'd like to elaborate with an example:
FROM busybox
CMD echo "Executing CMD"
CMD echo "Executing CMD 2"
If you build this into an image and run a container in this image, then as GingerBeer states, only the last CMD will be heeded. So the output of that container will be:
Executing CMD 2
The way I think of it is that "CMD" is setting a single global variable for the entire image that is being built, so successive "CMD" statements simply overwrite any previous writes to that global variable, and in the final image that's built the last one to write wins. Since a Dockerfile executes in order from top to bottom, we know that the bottom-most CMD is the one gets this final "write" (metaphorically speaking).
RUN: Commands May not Execute if Images are Cached
A subtle point to notice about RUN is that it's treated as a pure function even if there are side-effects, and is thus cached. What this means is that if RUN had some side effects that don't change the resultant image, and that image has already been cached, the RUN won't be executed again and so the side effects won't happen on subsequent builds. For example, take this Dockerfile:
FROM busybox
RUN echo "Just echo while you work"
First time you run it, you'll get output such as this, with different alphanumeric IDs:
docker build -t example/run-echo .
Sending build context to Docker daemon 9.216kB
Step 1/2 : FROM busybox
---> be5888e67be6
Step 2/2 : RUN echo "Just echo while you work"
---> Running in ed37d558c505
Just echo while you work
Removing intermediate container ed37d558c505
---> 6f46f7a393d8
Successfully built 6f46f7a393d8
Successfully tagged example/run-echo:latest
Notice that the echo statement was executed in the above. Second time you run it, it uses the cache, and you won't see any echo in the output of the build:
docker build -t example/run-echo .
Sending build context to Docker daemon 9.216kB
Step 1/2 : FROM busybox
---> be5888e67be6
Step 2/2 : RUN echo "Just echo while you work"
---> Using cache
---> 6f46f7a393d8
Successfully built 6f46f7a393d8
Successfully tagged example/run-echo:latest
RUN - Install Python , your container now has python burnt into its image
CMD - python hello.py , run your favourite script
Note: Don’t confuse RUN with CMD. RUN actually runs a command and
commits the result; CMD does not execute anything at build time, but
specifies the intended command for the image.
from docker file reference
https://docs.docker.com/engine/reference/builder/#cmd
RUN Command:
RUN command will basically, execute the default command, when we are building the image. It also will commit the image changes for next step.
There can be more than 1 RUN command, to aid in process of building a new image.
CMD Command:
CMD commands will just set the default command for the new container. This will not be executed at build time.
If a docker file has more than 1 CMD commands then all of them are ignored except the last one. As this command will not execute anything but just set the default command.
RUN: Can be many, and it is used in build process, e.g. install multiple libraries
CMD: Can only have 1, which is your execute start point (e.g. ["npm", "start"], ["node", "app.js"])
There has been enough answers on RUN and CMD. I just want to add a few words on ENTRYPOINT. CMD arguments can be overwritten by command line arguments, while ENTRYPOINT arguments are always used.
This article is a good source of information.
I'm following the instructions on Docker's website on building a parent image. I'm very new to Docker. I'm on a CentOS 7.5.
I ran the mkimage-yum.sh script suggested on the Docker website for CentOS. I didn't understand why the last line of the script, rm -rf "$target" was there because it seems to delete all the work done by the script. So I commented it out and it leaves a directory /tmp/mkimage-yum.sh.ahE8xx, which looks like a minimal linux image with the typical linux file structure (e.g. /usr/,/etc/)
In my home directory, I compiled the program,
main.c :
#include <stdio.h>
#include <stdlib.h>
int main(void){
printf("Hello Docker World!\n");
return 0;
}
Using gcc -static -static-libgcc -static-libstdc++ -o hello main.c, I compiled the code to a statically linked executable as prescribed in the docker webpage.
I created the Dockerfile,
e.g.
FROM scratch
ADD hello /
CMD ["/hello"]
I start up the dockerd server and in a separate terminal I run docker build --tag hello .
The output is :
Sending build context to Docker daemon 864.8 kB
Step 1/3 : FROM scratch
--->
Step 2/3 : ADD hello /
---> Using cache
---> a38d49d40e50
Step 3/3 : CMD /hello
---> Using cache
---> 3bcbb04c367f
Successfully built 3bcbb04c367f
Gee whiz, it looks like it worked! However, I still only see Dockerfile hello main.c in the directory I did this. Docker clearly thinks it did something, but what? It didn't create any new files.
Now I run docker run --rm hello and it outputs Hello Docker World!.
However, I get disconcerting errors from the dockerd server:
ERRO[502548] containerd: deleting container error=exit status 1: "container f336b3a5505879453b4f7a00c06acf274d0a5f8b3d260762273a2d7c0a846141 does not exist\none or more of the container deletions failed\n"
WARN[502548] f336b3a5505879453b4f7a00c06acf274d0a5f8b3d260762273a2d7c0a846141 cleanup: failed to unmount secrets: invalid argument
QUESTIONS :
What exactly did docker build --tag hello . do? I see no output from this.
What are the dockerd errors all about? Maybe looking for the docker image not created by docker build?
How does the mkimage-yum.sh fit into this? Why does it delete all the work that it does at the end.
When you run --rm with docker run, the container will run then delete itself. If you want to keep the container, remove the --rm from the command.
The command docker build will grab the dockerfile and create a local image, in you case, from scratch with the image name of hello.
You will not see any additional files created in your folder. To see the created image, run command docker images. Here you should be able to see your image built with tag hello.
When you run docker run <imagename> it starts up a container with the provided image. That's why you see your C program's output
New to docker here. I followed the instructions here to make a slim & trim container for my Go Project. I do not fully understand what it's doing though, hopefully someone can enlighten me.
Specifically there are two steps to generating this docker container.
docker run --rm -it -v "$GOPATH":/gopath -v "$(pwd)":/app -e "GOPATH=/gopath" -w /app golang:1.8 sh -c 'CGO_ENABLED=0 go build -a --installsuffix cgo --ldflags="-s" -o hello'
docker build -t myDockerImageName .
The DockerFile itself just contains
FROM iron/base
WORKDIR /app
COPY hello /app/
ENTRYPOINT ["./hello"]
I understand (in a broad sense) that the 1st step is compiling the go program and statically linking the C-dependencies (and doing all this inside an unnamed docker container). The 2nd step just generates the docker image according to the instructions in the DockerFile.
What I don't understand is why the first command starts with docker run (why does it need to be run inside a docker container? Why are we not just generating the Go binary outside of it, and then copying it in?)
And if it's being run inside a docker container, how is binary generated in the docker container being dropped on my local machine's file system?(e.g. why do I need to copy the binary back into the image - as it seems to be doing on line 3 of the DockerFile?)
You're actually using 2 different docker containers, each with a different image. The first container is only around during the compilation... it uses the image golang:1.8. What you're doing is mounting your current working directory into that image and compiling it with the version of GO contained in the image.
The second command builds your custom image that uses the iron/base image as its base. You then copy your built application into that image and run it.
Using a golang container to build the binary is usually done for reproducibility of the build process, i.e.:
it ensures that always the same Go version is used,
compilation takes place in an alway clean environment,
and the build host needs no Go installed at all, or can have a different version,
This way, all parts needed to build the "hello" image can be tracked in a version control system.
However, this example mounts the whole local GOPATH, defeating above purpose. Dependencies must be available to the build container, e.g. by vendoring them. Maybe the author considered vendoring out of scope for his example.
(note: this should be a comment, but my reputation does not allow that)
Nowadays I am trying to learn about the Docker but still have some ideas not clear;
I have tried to run an image that I just created, here is the directory;
hello (directory) :
Dockerfile
start.sh
And the Dockerfile :
FROM scratch
ADD start.sh /var/
CMD ["/var/start.sh"]
start.sh :
#!/bin/bash
echo "hello world"
I have tagged as using :
docker build -t mozer/hello .
Once I run the command;
docker run mozer/hello
no such file or directory
Error response from daemon: Cannot start container f22019aabc81f29fe17e849a2c040902ccadefe6cb8a8fe2612c83fe8eda40ea: [8] System error: no such file or directory
and once I run the command:
docker run mozer/hello /bin/sh -c
exec: "/bin/sh": stat /bin/sh: no such file or directory
Error response from daemon: Cannot start container 3b54584092e70b639671aca66122a0b1f6b1e4327cb2471a8792c3b2337b0bcc: [8] System error: exec: "/bin/sh": stat /bin/sh: no such file or directory
Can you please give me some ideas to find the solution ?
P.S. : I am working on a machine which is not connected to internet !
FROM scratch is a completely empty filesystem. You have no installed libraries, and no shell (like /bin/sh) included in there. To use this as your base, you'd need a statically linked binary, or you'll need to install all of the normal tools that are included with a linux distribution.
The latter is what is prepackaged in the various busybox, debian, ubuntu, centos, etc images on the docker hub. The fast way to make your image work with a minimal base image is to change the from to FROM busybox and change your /bin/bash to /bin/sh.
Scratch image is an empty file system, there is not /bin/sh inside it.
Look at Creating a simple base image using scratch
You can use Docker’s reserved, minimal image, scratch, as a starting
point for building containers. Using the scratch “image” signals to
the build process that you want the next command in the Dockerfile to
be the first filesystem layer in your image.
You can add an executable compiled program and run it.
When I run the command:
docker run dockerinaction/hello_world
The first time the following scenario plays out:
The dockerinaction/hello_world Dockerfile can be seen below:
FROM busybox:latest
CMD ["echo", "hello world"]
So from the wording:
Docker searches Docker Hub for the image
There are several things I'm curious about:
Is the image dockerinaction/hello_world?
Does this image reference another image named busybox:latest?
What about the Dockerfile is that on my machine somewhere?
Answers to each bulleted question, in corresponding order:
Yes, the image is dockerinaction/hello_world.
Yes, the image does reference busybox:latest, and builds upon it.
No, the Dockerfile is not stored on your machine. The docker run command is downloading a compressed version of the built Docker image that it found on Docker Hub. In some ways, you can think of the Dockerfile as the source code and the built image as the binary.
If you wanted to, you could write your own Dockerfile with the following contents:
FROM busybox:latest
CMD ["echo", "hello world"]
Then, in the directory containing that file (named Dockerfile), you could:
$ docker build -t my-hello-world:latest .
$ docker run my-hello-world:latest
The docker build command builds the Dockerfile, which in this case is stored on your machine. The built Docker image is tagged as my-hello-world:latest, and is only available on your machine (where it was built) unless you push it somewhere. You can run the built image from your machine by referring to the tag in the docker run command, as in the second line above.