How make docker layer to single layer - docker

Docker images create with multiple layers, I want to convert this to single layer is there any docker build command to achive this ? i googled for but cant find anything

No command to achieve that, and a single layer image is against docker's design concept. This Understand images, containers, and storage drivers doc described why docker image has multiple layers. In short, image layers are one of the reasons Docker is so lightweight. When you change a Docker image, such as when you update an application to a new version, a new layer is built and replaces only the layer it updates. Besides, even your image has only one layer, when you create a container with that image, docker still will add a thin Read/Writable container layer on the top of your image layer.
If you just want to move your image around and think one single layer could make it easier, you probably should try to use docker save command to create a tar file of it.
Or you have more complicated requirements, you may need to use VM image rather than docker image.

I have just workaround by using multistage build (the last build will be just a COPY from the previous build)
FROM alpine as build1
RUN echo "The 1st Build"
FROM scratch
COPY --from=build1 / /

First option:
# docker image build .
# docker run <your-image>
# docker container export <container-id created from previous command> -o myimage.tar.gz
# docker image import myimage.tar.gz
The imported image will be a single layer file system image.
Second option: (not a complete solution) - use multi stage builds to reduce number of image layers.

During build we can also pass --squash option to make it a single layer image.
Experimental (daemon)API 1.25+
Squash newly built layers into a single new layer
https://docs.docker.com/engine/reference/commandline/image_build/

Flattening a Docker Image to a Single Layer:
docker run -d --name flat_container nginx
docker export flat_container > flat.tar
cat flat.tar | docker import - flat:latest
docker image history flat

Related

DockerFile: Is it use to create an image or To the docker host how to create the container

I am confused with some terms.
Is Dockerile designed to create an image or a set of instruction of how to create a container from an image?
Because there are command e.g. FROM (to get the base image), RUN (To run executable in the container) etc. These command looks like an instruction to how to create the container.
Docker images are static, and are built from the instructions specified in the Dockerfile. They use Union File-System (UnionFS), so that the changes made when building an image are stacked on top of each other, generating a DAG (Directed Acyclic Graph) of build history. The FROM directive at the top of the Dockerfile simply points to an existing image, and starts building on top of that.
A container is simply an instantiated version of an image, basically just this UnionFS with a read/write layer dropped on top of it.
Interestingly, if you watch the output when you run docker build (in a directory with a Dockerfile) you'll see that what is happening is each instruction starts up a container based on the current state of the image, runs the command (apt-get install ... or whatever) and then commits that change to the image. That's why it's good to batch up commands in a Dockerfile - because each one will start a new container.
Dockerfile is used to create an image which you can later use to create a container using docker build.
From the docs
Docker can build images automatically by reading the instructions from a Dockerfile. A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. Using docker build users can create an automated build that executes several command-line instructions in succession.
Also RUN will instruction will execute any commands in a new layer on top of the current image and commit the results. The resulting committed image will be used for the next step in the Dockerfile and not "Run (To run executable in the container)". For details see this.
Image:
Docker engine use Dockerfile reference to build up Image from Dockerfile instruction like (FROM, RUN etc.)
Container:
Docker engine start container from Image and we can say Container is RUN time instance of Image

Docker create independent image

Hy i build a little image for docker on top of the debian:jessie image form the Docer Hub.
First i got debian:jessie from Docker Hub:
docker pull debian:jessie
Then I startet this image with a bash:
docker run -it debian:jessie
Then I installed my stuff e.g. ssh server and configured it.
Next from a second shell, i commitet the changes:
docker commit <running container id> debian-sshd
Now i have two images:
debian:jessie and debian-sshd
If i now want to delete debian:jessie, docker tells me i can't delete this because it has child-images(debian-sshd)
Is There a way I can make debian-sshd an independent image?
Most Dockerfiles start from a parent image. If you need to completely
control the contents of your image, you might need to create a base
image instead. Here’s the difference:
A parent image is the image that your image is based on. It refers to the contents of the FROM directive in the Dockerfile. Each
subsequent declaration in the Dockerfile modifies this parent image.
Most Dockerfiles start from a parent image, rather than a base image.
However, the terms are sometimes used interchangeably.
A base image either has no FROM line in its Dockerfile, or has FROM scratch.
Having quoted from docs, I would say that images are made up of layers, and since you have based your image on debian:jessie, one of the layers of debian-sshd is the debian:jessie image. If you want your independent image, build from scratch.
Other then that, all docker images are open source, so you can browse the dockerfile and modify it to suit your needs. Also, you could build from scratch if you want your own base image.

Docker save only non public layers

I can export images with
docker save -o <save image to path> <image name>
but this will pack all layers, and the file is big
is there a possibility to pack only layers which are not public available, so only the difference to the last public layer is exported?
You can try undocker. The tool can extract all or part of the layers of a Docker image onto the local filesystem. You can extract one or more specific layers:
$ docker save busybox |
undocker -vi -o busybox -l ea13149945cb6b1e746bf28032f02e9b5a793523481a0a18645fc77ad53c4ea2
INFO:undocker:extracting image busybox (4986bf8c15363d1c5d15512d5266f8777bfba4974ac56e3270e7760f6f0a8125)
INFO:undocker:extracting layer ea13149945cb6b1e746bf28032f02e9b5a793523481a0a18645fc77ad53c4ea2
Of course, it doesn't automatically sort out publicly available layers, but this is something you can start with, here is the tool intro article by original author.
The docker-save-last-layer command line utility combined with docker build --squash is made to accomplish exactly this.
It exports only the last layer of the specified docker image.
It works by using a patched version of the docker daemon inside a docker image that can access the images on your host machine. So it doesn't require doing a full docker save before using it like the undocker answer. This makes it much more performant for large base images.
Typical usage is simple and looks like:
pip install d-save-last
docker build --t myimage --squash .
d-save-last myimage -o ./myimage.tar

Get dockerfile / docker commands from docker image

Is it possible to get back the docker commands which were run to produce a given docker image? Since each line of a docker file should map to a single layer, it seems this would be possible, but I don't see anything in the docs.
docker history <image>
Does pretty much that.
Is it possible to get back the docker commands which were run to produce a given docker image?
No, considering you have commands like docker export / docker import which allows to flatten an image:
docker export <containerID> | docker import - <imagename>
The resulting image would be build from a container, and include only one layer. Not even a docker history would be able to give clues as to the original images and their Dockerfile which where part of the original container.
You can use combinations of two docker commands to achieve what you want:
docker inspect <image>
and
docker history <image>
Or you can use this cool service to see how that image being generated, each layer is a command in your docker file:
https://imagelayers.io/?images=java:latest,golang:latest,node:latest,python:latest,php:latest,ruby:latest
I guess it depends on where you got the image from.
In the case of these docker containers of mine from the Docker Hub you can use
this link from the right hand side of the webpage to follow it to this github repo containing the Dockerfile(s).
I do not think there is a command to "unassemble" a container / image and get back the instructions which made it.
For the images you create image metadata (labels) can be used to store Dockerfile
https://docs.docker.com/engine/userguide/labels-custom-metadata/
Initial solution was proposed here https://speakerdeck.com/garethr/managing-container-configuration-with-metadata
This approach of storing Dockerfile is not very efficient - it requires container to be started in order to extract the Dockerfile.
I personally use different approach - encode Dockerfile with Base64 and pass such encoded string using external arguments to set image label. This way you can read content of Dockerfile directly from image using inspect.
You can find detailed example here: https://gist.github.com/lruslan/3dea3b3d52a66531b2a1

Why do you need a base image with Docker?

I have went through every single page of the documentation of Docker.
I do not understand, yet still, why a "base image" (for example, the Ubuntu Base Image) is necessary to furnish the containers before installing/creating an application environment.
My questions:
What is a base image and why is it required?
Why is it not possible to just to create a container and put the application in it similar to virtualenv of Python?
In fact, Docker works through application of layers that are added to the base image. As you have to maintain coherence between all these layers, you cannot base your first image on a moving target (i.e. your writable file-system). So, you need a read-only image that will stay forever the same.
Here is an excerpt of the documentation of Docker about the images:
Since Docker uses a Union File System, the processes think the whole file system is mounted read-write. But all the changes go to the top-most writable layer, and underneath, the original file in the read-only image is unchanged. Since images don’t change, images do not have state.
An image is just a snapshot of file system and dependencies or a specific set of directories of a particular application/software. By snapshot I mean, a copy of just those files which are required to run that piece of software (for example mysql, redis etc.) with basic configurations in a container environment. When you create a container using an image, a small section of resources from your system are isolated with the help of namespacing and cgroups, and then the files inside the image are copied in this isolated environment of resources.
Let us understand what is a base image:
A base image is a starting point or an initial step for the image that we finally want to create.
Suppose you want an image that runs redis (this is a silly example and you can achieve it another way, but just for the sake of explanation think you will not find that image on docker hub) You would need a starting point to create the image for that. So let us take Alpine image as a base image.
Alpine is the lightest image that contains files just to run basic commands(for example: ls, cd, apk add inside the container).
Create a Dockerfile with following commands:
FROM alpine
RUN apk add --update redis
CMD ["redis-server"]
Now when you run docker build . command, it gives the following output:
Sending build context to Docker daemon 2.048kB
Step 1/3 : FROM alpine
---> a24bb4013296
Step 2/3 : RUN apk add --update redis
---> Running in 535bfd2d1ff1
fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/main/x86_64/APKINDEX.tar.gz
fetch http://dl-
cdn.alpinelinux.org/alpine/v3.12/community/x86_64/APKINDEX.tar.gz
(1/1) Installing redis (5.0.9-r0)
Executing redis-5.0.9-r0.pre-install
Executing redis-5.0.9-r0.post-install
Executing busybox-1.31.1-r16.trigger
OK: 7 MiB in 15 packages
Removing intermediate container 535bfd2d1ff1
---> 4c288890433b
Step 3/3 : CMD ["redis-server"]
---> Running in 7f01a4da3209
Removing intermediate container 7f01a4da3209
---> fc26d7967402
Successfully built fc26d7967402
This output shows that in Step 1/3 it takes the base alpine image, in Step 2/3, adds a layer of redis to it and then executes the redis-server command in Step 3/3 whenever the container is started. The RUN command is only executed when the image is is build process.
Further explanation of output is out of the scope of this question.
So when you pull an image from docker hub, it just has the configurations to run the basic requirements. When you need to add your own requirements and configurations to an image, you create a Dockerfile and add dependencies layer by layer on a base image to run it according to your needs.
In simple words I can explain that..as we use certain libraries and node packages for our application in similar way we can use Base Images which are already made and use them with simple search.You can also define your own base image and make use of it.
From Docker docs,
"A container is nothing but a running process, with some added encapsulation features applied to it in order to keep it isolated from the host and from other containers.
One of the most important aspects of container isolation is that *each container interacts with its own private filesystem; this filesystem is provided by a Docker image (like image of any Linux OS - which is also the Base image)." The final image may include multiple layers which are just some other filesystem changes. Like for running a Java application, you put on a JDK layer on top of the Base Linux image.
*Credits: Image taken from Educative.io

Resources