Asked  7 Months ago    Answers:  5   Viewed   80 times

I'm experimenting with Dockerfiles, and I think I understand most of the logic. However, I don't see the difference between "exposing" and "publishing" a port in this context.

All the tutorials I have seen first include the EXPOSE command in the Dockerfile:

...
EXPOSE 8080
...

They then build an image from this Dockerfile:

$ docker build -t an_image - < Dockerfile

And then publish the same port as above when running the image:

$ docker run -d -p 8080 an_image

or publish all ports using

$ docker run -d -P an_image

What is the point of exposing a port in the Dockerfile, if it will be published anyway? Would there ever be a need to expose a port first, and not publish it later? Effectively, I would like to specify all the ports that I will use in the Dockerfile when creating the image, and then not bother with them again, running them simply with:

$ docker run -d an_image

Is this possible?

 Answers

30

Basically, you have three options:

  1. Neither specify EXPOSE nor -p
  2. Only specify EXPOSE
  3. Specify EXPOSE and -p

1) If you specify neither EXPOSE nor -p, the service in the container will only be accessible from inside the container itself.

2) If you EXPOSE a port, the service in the container is not accessible from outside Docker, but from inside other Docker containers. So this is good for inter-container communication.

3) If you EXPOSE and -p a port, the service in the container is accessible from anywhere, even outside Docker.

The reason why both are separated is IMHO because:

  • choosing a host port depends on the host and hence does not belong to the Dockerfile (otherwise it would be depending on the host),
  • and often it's enough if a service in a container is accessible from other containers.

The documentation explicitly states:

The EXPOSE instruction exposes ports for use within links.

It also points you to how to link containers, which basically is the inter-container communication I talked about.

PS: If you do -p, but do not EXPOSE, Docker does an implicit EXPOSE. This is because if a port is open to the public, it is automatically also open to other Docker containers. Hence -p includes EXPOSE. That's why I didn't list it above as a fourth case.

Tuesday, June 1, 2021
 
MoarCodePlz
answered 7 Months ago
32

docker save will indeed produce a tarball, but with all parent layers, and all tags + versions.

docker export does also produce a tarball, but without any layer/history.

It is often used when one wants to "flatten" an image, as illustrated in "Flatten a Docker container or image" from Thomas Uhrig:

docker export <CONTAINER ID> | docker import - some-image-name:latest

However, once those tarballs are produced, load/import are there to:

  • docker import creates one image from one tarball which is not even an image (just a filesystem you want to import as an image)

Create an empty filesystem image and import the contents of the tarball

  • docker load creates potentially multiple images from a tarred repository (since docker save can save multiple images in a tarball).

Loads a tarred repository from a file or the standard input stream

Monday, June 28, 2021
 
Gordnfreeman
answered 6 Months ago
34

You need to point to the directory instead. You must not specify the dockerfile.

docker build -t ubuntu-test:latest . does work.

docker build -t ubuntu-test:latest ./Dockerfile does not work.

Sunday, August 1, 2021
 
ALH
answered 4 Months ago
ALH
98

The short answer is:

  • save will fetch an image : for a VM or a physical server, that would be the installation .ISO image or disk. The base operating system.

    It will pack the layers and metadata of all the chain required to build the image. You can then load this "saved" images chain into another docker instance and create containers from these images.

  • export will fetch the whole container : like a snapshot of a regular VM. Saves the OS of course, but also any change you made, any data file written during the container life. This one is more like a traditional backup.

    It will give you a flat .tar archive containing the filesystem of your container.

Edit: as my explanation may still lead to confusion, I think that it is important to understand that one of these commands works with containers, while the other works with images.

  • An image has to be considered as 'dead' or immutable, starting 0 or 1000 containers from it won't alter a single byte. That's why I made a comparison with a system install ISO earlier. It's maybe even closer to a live-CD.

  • A container "boots" the image and adds an additional layer on top of it. This layer stores any change on the container (created/changed/removed files...).

Friday, September 3, 2021
 
Yoshi
answered 3 Months ago
91

That Docker Hub history view doesn't show the actual Dockerfile; instead, it shows content essentially extracted from the docker history of the image. That doesn't preserve the specific details you're looking for: it doesn't remember the names of base images, or the build-context file names of things that get ADDed or COPYed in.

Chasing through GitHub and Docker Hub links, the golang:*-buster Dockerfile is built FROM buildpack-deps:...-scm; buildpack-deps:buster-scm is FROM buildpack-deps:buster-curl; that is FROM debian:buster; and that has a very simple Dockerfile (quoted here in its entirety):

FROM scratch
ADD rootfs.tar.xz /
CMD ["bash"]

FROM scratch starts from a completely totally empty image; that is the base of the Docker image tree (and what tells docker history and similar tools to stop). The ADD line unpacks a tar file of a Debian system image.

If you look at docker history or the Docker Hub history view you cite, you should be able to see these same steps happening. The ADD file:4b0... in / corresponds to the ADD rootfs.tar.gz /, and the second line is the CMD ["bash"]. It is not split up by Dockerfile or image, and the original filenames from ADD aren't saved. (You couldn't reproduce the image anyways without the contents of the rootfs.tar.gz, so it's merely slightly helpful to know its filename but not essential.)

The ADD file:hash in /path syntax is not standard Dockerfile syntax (the word in in particular is not part of it). I'm not sure there's a reliable way to translate from the host file or URL to the hash, but building the image and looking at its docker history would tell you (assuming you've got a perfect match for the file metadata). There's no way to get back to the original filename or syntax, and definitely no way to get back to the file contents.

Monday, October 11, 2021
 
huhushow
answered 2 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share