Can we have a docker container without a shell? - docker

Can we build a docker container that doesn't have any shell in that container ? Is it possible to create a container without a shell ?

Yes, you can create a container from scratch, which does not contain anything even bash, it will only contain binaries that you copy during build time, otherwise, it will be empty.
FROM scratch
COPY hello /
CMD ["/hello"]
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.
While scratch appears in Docker’s repository on the hub, you can’t
pull it, run it, or tag any image with the name scratch. Instead, you
can refer to it in your Dockerfile. For example, to create a minimal
container using scratch:
scratch-docker-image
Using this as a base image, you can create your custom image, for example you only node runtime not thing more, then you try form scratch-node.
FROM node as builder
WORKDIR /app
COPY package.json package-lock.json index.js ./
RUN npm install --prod
FROM astefanutti/scratch-node
COPY --from=builder /app /
ENTRYPOINT ["node", "index.js"]

Related

Dockerfile with entrypoint only from base image

I have a very simple Dockerfile like the below :-
FROM my-base-image
COPY abc.properties /opt/conf/
Now my base-image has a docker entrypoint (at the end of its Dockerfile) but this resulting image as you can see has none. Does this work or do we need to have a docker entrypoint/CMD in any given Dockerfile. Also what would be the order of execution for the COPY instruction in the resulting image. With this i mean since this Dockerfile has no entrypoint it would execute one from the base image but will that be executed after the COPY instruction or will the base image entrypoint be executed first and then execute this COPY instruction when the container starts
Just looking for concepts in docker.
Several of the Dockerfile directives (notably ENTRYPOINT and CMD, but also EXPOSE, LABEL, and MAINTAINER) just set metadata in the image; they don't really do anything themselves. Within a single Dockerfile this will work just fine:
FROM ubuntu:18.04
WORKDIR /app
# Just remembers this in the image metadata; doesn't actually run it
CMD ["/app/main.sh"]
# ...we should actually copy the file in too
COPY main.sh /app
When you have one Dockerfile built FROM another image it acts almost entirely like you ran all of the commands in the first Dockerfile, then all of the commands in the second Dockerfile. Since CMD and ENTRYPOINT just set metadata, the second image inherits this metadata.
Building and running an image are two separate steps. In the example you show, the COPY directive happens during the docker build step, and the base image's command doesn't take effect until the later docker run step. (This is also true in Docker Compose; a common question is about why Dockerfile steps can't connect to other containers declared in the Compose YAML file.)
There is one exception, and it's around ENTRYPOINT. If you have a base image that declares an ENTRYPOINT and a CMD both, and you redeclare the ENTRYPOINT in a derived image, it resets the CMD as well (very last paragraph in this section). This usually isn't a practical problem.
When you build an image, the Dockerfiles are merged as per their instructions. Building an image doesnt mean it runs. So ideally your instructions from your Base Dockerfile and your current Dockerfile will be packed. Since you have mentioned CMD entrypoint in the Base Dockerfile, that will be used for execution of your image inside the container, when you use docker run.
So when you build your image, the COPY statement from your child Dockerfile will also get set. and your image must be built fine.
Execute your docker build and docker run and let us know

How to copy a file from the host into a container while starting?

I am trying to build a docker image using the dockerfile, my purpose is to copy a file into a specific folder when i run the "docker run" command!
this my dockerfile code:
FROM openjdk:7
MAINTAINER MyPerson
WORKDIR /usr/src/myapp
ENTRYPOINT ["cp"]
CMD ["/usr/src/myapp"]
CMD ls /usr/src/myapp
After building my image without any error (using the docker build command), i tried to run my new image:
docker run myjavaimage MainClass.java
i got this error: ** cp: missing destination file operand after ‘MainClass.java’ **
How can i resolve this? thx
I think you want this Dockerfile:
FROM openjdk:7
WORKDIR /usr/src/myapp
COPY MainClass.java .
RUN javac MainClass.java
ENV CLASSPATH=/usr/src/myapp
CMD java MainClass
When you docker build this image, it COPYs your Java source file from your local directory into the image, compiles it, and sets some metadata telling the JVM where to find the resulting .class files. Then when you launch the container, it will run the single application you've packaged there.
It's common enough to use a higher-level build tool like Maven or Gradle to compile multiple files into a single .jar file. Make sure to COPY all of the source files you need in before running the build. In Java it seems to be common to build the .jar file outside of Docker and just COPY that in without needing a JDK, and that's a reasonable path too.
In the Dockerfile you show, Docker combines ENTRYPOINT and CMD into a single command and runs that command as the single main process of the container. If you provide a command of some sort at the docker run command, that overrides CMD but does not override ENTRYPOINT. You only get one ENTRYPOINT and one CMD, and the last one in the Dockerfile wins. So you're trying to run container processes like
# What's in the Dockerfile
cp /bin/sh -c "ls /usr/src/myapp"
# Via your docker run command
cp MainClass.java
As #QuintenScheppermans suggests in their answer you can use a docker run -v option to inject the file at run time, but this will happen after commands like RUN javac have already happened. You don't really want a workflow where the entire application gets rebuilt every time you docker run the container. Build the image during docker build time, or before.
Two things.
You have used CMD twice.
CMD can only be used once, think of it as the purpose of your docker image. Every time a container is run, it will always execute CMD if you want multiple commands, you should use RUN and then lastly, used CMD
FROM openjdk:
MAINTAINER MyPerson
WORKDIR /usr/src/
ENTRYPOINT ["cp"]
RUN /usr/src/myapp
RUN ls /usr/src/myapp
Copying stuff into image
There is a simple command COPY the syntax being COPY <from-here> <to-here>
Seems like you want to run myjavaimage so what you will do is
COPY /path/to/myjavaimage /myjavaimage
CMD myjavaimage MainClass.java
Where you see the arrows, I've just written dummy code. Replace that with the correct code.
Also, your Dockerfile is badly created.
ENTRYPOINT -> not sure why you'd do "cp", but it's an actual entrypoint. Could point to the root dir of your project or to an app that will be run.
Don't understand why you want to do ls /usr/src/myapp but if you do want to do it, use RUN and not CMD
Lastly,
Best way to debug docker containers are in interactive mode. That means ssh'ing in to your container, have a look around, run code, and see what is the problem.
Run this: docker run -it <image-name> /bin/bash and then have a look inside and it's usually the best way to see what causes issues.
This stackoverflow page perfectly answers your question.
COPY foo.txt /data/foo.txt
# where foo.txt is the relative path on host
# and /data/foo.txt is the absolute path in the image
If you need to mount a file when running the command:
docker run --name=foo -d -v ~/foo.txt:/data/foo.txt -p 80:80 image_name

Docker WORKDIR - on my machine or the container?

What context does the WORKDIR keyword in a Dockerfile refer to? Is it in the context I run docker build from or inside the container I am producing?
I find myself often putting RUN cd && ... in my docker files and am hoping there's another way, I feel like I'm missing something.
It is inside the container.
Taken for the Dockerfile reference site https://docs.docker.com/engine/reference/builder/#workdir
The WORKDIR instruction sets the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD instructions that follow it in the Dockerfile. If the WORKDIR doesn’t exist, it will be created even if it’s not used in any subsequent Dockerfile instruction.
So rather than adding RUN cd && ... you could do:
WORKDIR /path/to/dir
RUN command
All paths in a Dockerfile, except the first half of COPY and ADD instructions, refer to image filesystem paths. The source paths for COPY and ADD are relative paths (even if they start with /) relative to the build context (the directory at the end of the docker build command, frequently the directory containing the Dockerfile). Nothing in a Dockerfile can ever reference an absolute path on the host or content outside the build context tree.
The only difference between these two Dockerfiles is the directory the second command gets launched in.
RUN cd /dir && command1
RUN command2
WORKDIR /dir
RUN command1
RUN command2
WORKDIR sets the directory inside the image and hence allows you to avoid RUN cd calls.

Install Bash on scratch Docker image

I am presently working with a third party Docker image whose Dockerfile is based on the empty image, starting with the FROM scratch directive.
How can Bash be installed on such image? I tried adding some extra commands to the Dockerfile, but apparently the RUN directive itself requires Bash.
When you start a Docker image FROM scratch you get absolutely nothing. Usually the way you work with one of these is by building a static binary on your host (or these days in an earlier Dockerfile build stage) and then COPY it into the image.
FROM scratch
COPY mybinary /
ENTRYPOINT ["/mybinary"]
Nothing would stop you from creating a derived image and COPYing additional binaries into it. Either you'd have to specifically build a static binary or install a full dynamic library environment.
If you're doing this to try to debug the container, there is probably nothing else in the image. One thing this means is that the set of things you can do with a shell is pretty boring. The other is that you're not going to have the standard tool set you're used to (there is not an ls or a cp). If you can live without bash's various extensions, BusyBox is a small tool designed to be statically built and installed in limited environments that provides minimal versions of most of these standard tools.
The question is old but I see a similar question and came here, SO posting to deal with such case below.
I am presently working with a third party Docker image whose
Dockerfile is based on the empty image, starting with the FROM scratch
directive.
As mentioned by #David there is nothing in such image that is based on scratch, If the image is based on the scratch image they just copy the binaries to image and that's it.
So the hack around with such image is to copy the binaries into your extend image and use them in your desired docker image.
For example postgres_exporter
FROM scratch
ARG binary
COPY $binary /postgres_exporter
EXPOSE 9187
ENTRYPOINT [ "/postgres_exporter" ]
So this is based on scratch and I can not install bash or anything else I can just copy binaries to run.
So here is the work, use them as the multi-stage base image, copy the binaries and installed packages in your docker images.
Below we need to add wait-for-it
FROM wrouesnel/postgres_exporter
# use the above base image
FROM debian:7.11-slim
RUN useradd -u 20001 postgres_exporter
USER postgres_exporter
#copy binires
COPY --from=0 /postgres_exporter /postgres_exporter
EXPOSE 9187
COPY wait-for-it.sh wait-for-it.sh
USER root
RUN chmod +x wait-for-it.sh
USER postgres_exporter
RUN pwd
ENTRYPOINT ["./wait-for-it.sh", "db:5432", "--", "./postgres_exporter"]

Dockerfile ONBUILD instruction

I read on the docker documentation how ONBUILD instruction can be used, but it is not clear at all.
Can someone please explain it to me?
The ONBUILD instruction is very useful for automating the build of your chosen software stack.
Example
The Maven container is designed to compile java programs. Magically all your project's Dockerfile needs to do is reference the base container containing the ONBUILD intructions:
FROM maven:3.3-jdk-8-onbuild
CMD ["java","-jar","/usr/src/app/target/demo-1.0-SNAPSHOT-jar-with-dependencies.jar"]
The base image's Dockerfile tells all
FROM maven:3-jdk-8
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
ONBUILD ADD . /usr/src/app
ONBUILD RUN mvn install
There's a base image that has both Java and Maven installed and a series of instructions to copy files and run Maven.
The following answer gives a Java example
How to build a docker container for a java app
As stated by the docker docs:
The ONBUILD instruction adds to the image a trigger instruction to be executed at a later time, when the image is used as the base for another build. The trigger will be executed in the context of the downstream build, as if it had been inserted immediately after the FROM instruction in the downstream Dockerfile.
So what does that mean? Let's take this Nodejs Dockerfile:
FROM node:0.12.6
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
ONBUILD COPY package.json /usr/src/app/
ONBUILD RUN npm install
ONBUILD COPY . /usr/src/app
CMD [ "npm", "start" ]
In your own Dockerfile, when you do FROM node:0.12.6-onbuild you're getting an image, which means the build command has already been run, so the instructions have ALREADY been executed as well, however all but those starting with ONBUILD. These have been deferred to another time, when the downstream build (when your image is getting built from your own Dockerfile) uses this image as the base (FROM node:0.12.6-onbuild).
You can’t just call ADD and RUN now, because you don’t yet have access to the application source code, and it will be different for each application build.
That's right! The image containing onbuild instructions wasn't built on your machine, so it doesn't yet have access to package.json.
Then when you build your own Dockerfile, before executing any instruction in your file, the builder will look for ONBUILD triggers, which were added to the metadata of the parent image when it was built.
That spares you the hassle of executing these commands yourself, it really is as though these commands were written in your own Dockerfile.
Finally, they add:
You could simply provide application developers with a boilerplate Dockerfile to copy-paste into their application, but that is inefficient, error-prone and difficult to update because it mixes with application-specific code.
The thing is that if these instructions are modified in the boilerplate Dockerfile, you will have to modify them as well in your Dockerfile. But thanks to the ONBUILD instruction, we don't have to worry about it.

Resources