📜 ⬆️ ⬇️

Dive into Docker: Dockerfile and communication between containers

In the last article, we talked about what Docker is and how to use it to bypass Vendor – lock. In this article we’ll talk about Dockerfile as the right way to prepare images for Docker. We will also consider the situation when containers need to interact with each other.


In InfoboxCloud we made a ready image of Ubuntu 14.04 with Docker. Do not forget to tick the “Allow OS kernel management” checkbox when creating the server, this is required for the Docker operation.

Dockerfile


The docker commit approach described in the previous article is not recommended for Docker. Its plus is that we set up the container almost as much as we used to set up a standard server.

Instead of this approach, we recommend using the Dockerfile approach and the docker build command . Dockerfile uses plain DSL with instructions for building Docker images. After that, the docker build command is executed to build a new image with instructions in the Dockerfile.
')
Writing dockerfile

Let's create a simple image with a web server using Dockerfile. First, create a directory and the Dockerfile itself.
mkdir static_web cd static_web touch Dockerfile 

The created directory is a build environment in which the Docker invokes the context or builds the context. Docker will load the context in the folder during the Docker daemon process when the image build is launched. This way, it will be possible for the Docker – daemon to access any code, files, or other data that you want to include in the image.

Add the image construction information to the Dockerfile:
 # Version: 0.0.1 FROM ubuntu:14.04 MAINTAINER Yuri Trukhin <trukhinyuri@infoboxcloud.com> RUN apt-get update RUN apt-get install -y nginx RUN echo 'Hi, I am in your container' \ >/usr/share/nginx/html/index.html EXPOSE 80 

Dockerfile contains a set of instructions with arguments. Each instruction is written in capital letters (for example FROM). Instructions are processed from top to bottom. Each instruction adds a new layer to the image and commits the changes. Docker executes instructions following the process:

This means that if the Dockerfile execution stops for some reason (for example, the instruction cannot complete), you can use the image to this stage. This is very useful when debugging: you can run the container from the image online and find out why the instruction failed to execute using the last created image.

Dockerfile also supports comments. Any line starting with # means a comment.

The first instruction in the Dockerfile should always be FROM , indicating which image to build the image from. In our example, we build an image from the base image of ubuntu version 14:04.

Next, we specify the MAINTAINER instruction, which informs the Docker of the image's author and his email. This is useful for users of the image to contact the author if necessary.

The RUN instruction executes the command in a particular image. In our example, using it, we update the APT repositories and install the package with NGINX, then create the file /usr/share/nginx/html/index.html.

By default, the RUN instruction is executed inside the shell using the command wrapper / bin / sh -c . If you are running the instruction on a platform without a shell or just want to execute the instruction without a shell, you can specify the execution format:
 RUN ["apt-get", "install", "-y", "nginx"] 

We use this format to specify an array containing the command to execute and command parameters.

Next, we specify the EXPOSE statement that tells Docker that the application in the container must use a specific port in the container. This does not mean that you can automatically access the service running on the container port (in our example, port 80). For security reasons, Docker does not open the port automatically, but waits for the user to do this in the docker run command. You can specify multiple EXPOSE instructions to specify which ports should be open. Also, the EXPOSE instruction is useful for port forwarding between containers.

Build an image from our file

 docker build -t trukhinyuri/nginx ~/static_web 

where trukhinyuri is the name of the repository where the image will be stored, nginx is the name of the image. The last parameter is the path to the folder with the Dockerfile. If you do not specify the name of the image, it will automatically be called latest. You can also specify the git repository where the Dockerfile is located.
 docker build -t trukhinyuri/nginx \ git@github.com:trukhinyuri/docker-static_web 

In this example, we are building an image from a Dockerfile located in the Docker root directory.

If there is a .dockerignore file in the root of the build context, it is interpreted as a list of exception patterns.

What happens if the instruction fails?

Let's rename nginx to Dockerfile to ngin and see.



We can create a container from the last but one step with image ID 066b799ea548
docker run -i -t 066b799ea548 / bin / bash
and debug execution.

By default, Docker caches every step and builds the assembly cache. To disable the cache, for example, to use the last apt-get update, use the flag --no-cache.
 docker build --no-cache -t trukhinyuri/nginx 


Using assembly cache for templating

Using assembly caches, you can build images from Dockerfile in the form of simple templates. For example, the template for updating the APT cache in Ubuntu:
 FROM ubuntu:14.04 MAINTAINER Yuri Trukhin <trukhinyuri@infoboxcloud.com> ENV REFRESHED_AT 2014–10–16 RUN apt-get -qq update 

The ENV instruction sets the environment variables in the image. In this case, we indicate when the template was updated. When you need to update a built image, you just need to change the date in ENV. Docker will reset the cache and the version of the packages in the image will be the last.

Dockerfile instructions

Let's take a look at other Dockerfile instructions. Full list can be found here .

Cmd

The CMD instruction indicates which command to run when the container is running. Unlike the RUN command, the specified command is executed not during the creation of the image, but during the launch of the container.
 CMD ["/bin/bash", "-l"] 

In this case, we run bash and pass it the parameter as an array. If we specify a command not in the form of an array, it will be executed in / bin / sh -c. It is important to remember that you can overload the CMD command using the docker run.

ENTRYPOINT

Often the CMD command is confused with ENTRYPOINT. The difference is that you cannot overload the ENTRYPOINT when the container is started.
 ENTRYPOINT ["/usr/sbin/nginx"] 

When the container is started, the parameters are passed to the command specified in ENTRYPOINT.
 docker run -d trukhinyuri/static_web -g "daemon off" 

You can combine ENTRYPOINT and CMD.
 ENTRYPOINT ["/usr/sbin/nginx"] CMD ["-h"] 

In this case, the command in ENTRYPOINT will be executed in any case, and the command in the CMD will be executed if no other command is sent when the container is started. If necessary, you can still overload the ENTRYPOINT command with the --entrypoint flag.

WORKDIR

With the help of WORKDIR, you can set the working directory from which the ENTRYPOINT and CMD commands will run.
 WORKDIR /opt/webapp/db RUN bundle install WORKDIR /opt/webapp ENTRYPOINT ["rackup"] 

You can reload the working directory of the container in runtime with the -w flag.

USER

It specifies the user under which the image should be launched. We can specify username or UID and group or GID.
 USER user USER user:group USER uid USER uid:gid USER user:gid USER uid:group 

You can overload this command using the -u verb when starting the container. If the user is not specified, root is used by default.

VOLUME

The VOLUME instruction adds volumes to the image. A volume is a folder in one or more containers or a host folder, forwarded through the Union File System (UFS).
Volumes can be shared or reused between containers. This allows you to add and modify data without committing to the image.
 VOLUME ["/opt/project"] 

In the example above, a / opt / project mount point is created for any container created from the image. Thus, you can specify multiple volumes in the array.

ADD

The ADD instruction adds files or folders from our build environment to the image, which is useful for example when installing an application.
 ADD software.lic /opt/application/software.lic 

The source can be a URL, a file name or a directory.
 ADD http://wordpress.org/latest.zip /root/wordpress.zip 

 ADD latest.tar.gz /var/www/wordpress/ 

In the last example, the tar.gz archive will be unpacked in / var / www / wordpress. If the destination path is not specified, the full path will be used including directories.

COPY

The COPY instruction differs from ADD in that it is intended to copy local files from the build context and does not support unpacking files:
 COPY conf.d/ /etc/apache2/ 


ONBUILD

The ONBUILD instruction adds triggers to the images. A trigger is executed when an image is used as a base for another image, for example, when the source code required for an image is not yet available, but requires a specific environment to work.
 ONBUILD ADD . /app/src ONBUILD RUN cd /app/src && make 


Communication between containers


The previous article showed how to run isolated Docker containers and how to forward the file system into them. But what if applications need to communicate with each other. There are 2 ways: communication through port forwarding and container linking.

Port forwarding

This method of communication has already been shown earlier. Let's look at the port forwarding options a bit wider.
When we use EXPOSE in the Dockerfile or the -p port_number parameter - the port of the container is bound to an arbitrary port of the host. You can view this port using the docker ps command or docker port container_name container_number_in_container . At the time of creating the image, we may not know which port will be available on the machine at the time the container is launched.

You can specify which particular port of the host you assign to the container port using the docker run -p port_host_port parameter: container_port
By default, the port is used on all interfaces of the machine. You can, for example, bind to localhost explicitly:
 docker run -p 127.0.0.1:80:80 

You can bind UDP ports by specifying / udp:
 docker run -p 80:80/udp 


Container linking

Communication through network ports is just one way to communicate. Docker provides a linking system that allows you to link multiple containers together and send connection information from one container to another.

To establish the connection you need to use the names of the containers. As shown earlier, you can give the container a name when creating it with the --name flag.

Suppose you have 2 containers: web and db. To create a connection, remove the web container and recreate it using the command --link name: alias.
 docker run -d -P --name web --link db:db trukhinyuri/webapp python app.py 

Using docker -ps you can see the associated containers.

What actually happens when linking? A container is created that provides information about itself to the receiving container. This happens in two ways:

You can see the environment variables by running the env command:
 $ sudo docker run --rm --name web2 --link db:db training/webapp env . . . DB_NAME=/web2/db DB_PORT=tcp://172.17.0.5:5432 DB_PORT_5432_TCP=tcp://172.17.0.5:5432 DB_PORT_5432_TCP_PROTO=tcp DB_PORT_5432_TCP_PORT=5432 DB_PORT_5432_TCP_ADDR=172.17.0.5 

The DB_ prefix was taken from the alias container.

You can simply use information from hosts, for example, the ping db command (where db is alias) will work.

Conclusion


In this article, we learned how to use Dockerfile and organize communication between containers. This is only the tip of the iceberg, a lot of things are left behind the scenes and will be considered in the future. For additional reading, we recommend the book The Docker Book .

A ready image with Docker is available in the InfoboxCloud cloud.

In case you can not ask questions on Habré, you can ask in the InfoboxCloud Community .
If you find an error in the article, the author will gladly correct it. Please write in the LAN or in the mail about it.

Successful use of Docker!

Source: https://habr.com/ru/post/240623/


All Articles