Docker: Parent context

Sometimes when building Docker images, if we have custom files or resources we want to use and multiple images are going to use them, it is interesting to have then just once in a shared folder and to have all Dockerfile commands pointing to that shared folder.

The problem with this is that, when we are running a build, docker use as a context the current directory where the docker build command runs and, this, initially, can cause some fails.

Let’s see an example of this. Let’s imagine we have a few projects with a structure like this:

projectA -> DockerfileA
         -> fileA
         -> resources -> script.sh
         -> resources -> certs -> cert
projectB -> DockerfileA
         -> fileB
         -> resources -> script.sh
         -> resources -> certs -> cert
projectC -> DockerfileA
         -> fileC
         -> resources -> script.sh
         -> resources -> certs -> cert

In the above folder structure, we have three different projects and we can see we have some duplicated resources making more difficult to maintain and been error-prone. For this reason, we decide to restructure the folders and shared resources in something like:

projects -> projectA -> DockerfileA
         -> projectA -> fileA
         -> projectB -> DockerfileB
         -> projectB -> fileB
         -> projectC -> DockerfileC
         -> projectC -> fileC
         -> resources -> script.sh
         -> resources -> certs -> cert

As we can see, the above structure seems easier to maintain and less error-prone. The only consideration we need to have now is the docker build context.

Let’s say our Dockerfile files, among others, has the ADD or COPY commands inside. In this case, something like:

...
COPY ./resources/script.sh /opt/
COPY ./resources/certs/cert /opt/cert
...

Building docker images under the first folder structure is something like:

(pwd -> ~/projectA)
$ docker build -t projectA .

(pwd -> ~/projectB)
$ docker build -t projectB .

(pwd -> ~/projectC)
$ docker build -t projectC .

But, if we try to do it in the same way using the second folder structure we are going to be prompted with an error:

COPY failed: Forbidden path outside the build context.

This is because the context when executing the docker command does not have access to the folders allocated in the parent folder.

To avoid this problem, the only thing we need to do is to execute the build command from the parent folder and to add an extra flag (-f) to our command to point to the Dockerfile file we want to use when building the image. Something like:

(pwd -> projects)
$ docker build -t projectA -f projectA/DockerfileA .
$ docker build -t projectB -f projectB/DockerfileB .
$ docker build -t projectC -f projectC/DockerfileC .

This should solve the problem as now, the context of the docker build command is the parent folder.

Docker: Parent context

Docker Java Client

No questions about containers been one of the latest big things. They are everywhere, everyone use them or want to use them and the truth is they are very useful and they have change the way we develop.

We have docker for example that provides us with docker and docker-compose command line tools to be able to run one or multiple containers with just a few lines or a configuration file. But, we, developers, tend to be lazy and we like to automize things. For example, what about when we are running our application in our favorite IDE the application starts the necessary containers for us? It will be nice.

The point of this article was to play a little bit the a docker java client library, the case exposed above is just an example, probably you readers can think about better cases but, for now, this is enough for my learning purposes.

Searching I have found two different docker java client libraries:

I have not analyze them or compare them, I have just found the one by GitHub before and it looks mature and usable enough. For this reason, it is the one I am going to use for the article.

Let’s start.

First, we need to add the dependency to our pom.xml file:

<dependency>
    <groupId>com.github.docker-java</groupId>
    <artifactId>docker-java</artifactId>
    <version>3.1.1</version>
</dependency>

The main class we are going to use to execute the different instructions is the DockerClient class. This is the class that establishes the communication between our application and the docker engine/daemon in our machine. The library offers us a very intuitive builder to generate the object:

DockerClient dockerClient = DockerClientBuilder.getInstance().build();

There are some options that we can configure but for a simple example is not necessary. I am just going to say there is a class called DefaultDockerClientConfig where a lot of different properties can be set. After that, we just need to call the getInstance method with our configuration object.

Image management

Listing images

List<Image> images = dockerClient.listImagesCmd().exec();

Pulling images

dockerClient.pullImageCmd("postgres")
                .withTag("11.2")
                .exec(new PullImageResultCallback())
                .awaitCompletion(30, TimeUnit.SECONDS);

Container management

Listing containers

// List running containers
dockerClient.listContainersCmd().exec();

// List existing containers
dockerClient.listContainersCmd().withShowAll(true).exec();

Creating containers

CreateContainerResponse container = dockerClient.createContainerCmd("postgres:11.2")
                .withName("postgres-11.2-db")
                .withExposedPorts(new ExposedPort(5432, InternetProtocol.TCP))
                .exec();

Starting containers

dockerClient.startContainerCmd(container.getId()).exec();

Other

There are multiple operations we can do with containers, the above is just a short list of examples but, we can extended with:

  • Image management
    • Listing images: listImagesCmd()
    • Building images: buildImageCmd()
    • Inspecting images: inspectImageCmd("id")
    • Tagging images: tagImageCmd("id", "repository", "tag")
    • Pushing images: pushImageCmd("repository")
    • Pulling images: pullImageCmd("repository")
    • Removing images: removeImageCmd("id")
    • Search in registry: searchImagesCmd("text")
  • Container management
    • Listing containers: listContainersCmd()
    • Creating containers: createContainerCmd("repository:tag")
    • Starting containers: startContainerCmd("id")
    • Stopping containers: stopContainerCmd("id")
    • Killing containers: killContainerCmd("id")
    • Inspecting containers: inspectContainerCmd("id")
    • Creating a snapshot: commitCmd("id")
  • Volume management
    • Listing volumes: listVolumesCmd()
    • Inspecting volumes: inspectVolumeCmd("id")
    • Creating volumes: createVolumeCmd()
    • Removing volumes: removeVolumeCmd("id")
  • Network management
    • Listing networks: listNetworksCmd()
    • Creating networks: createNetworkCmd()
    • Inspecting networks: inspectNetworkCmd().withNetworkId("id")
    • Removing networks: removeNetworkCmd("id")

And, that is all. There is a project suing some of the operations listed here. It is call country, it is one of my learning projects, and you can find it here.

Concretely, you can find the code using the docker java client library here, and the code using this library here, specifically in the class PopulationDevelopmentConfig.

I hope you find it useful.

Docker Java Client

Docker for Java developers

Today, it has been one of this days to learn something new. If you have seen any of my blogs, you should know that I like to write about what I am learning and I like to write it myself, I am not a fan of just paste resources or other people’s materials or tutorials but, sometimes, I need to make exceptions.

Today, I was learning Docker, you know, the container platform that allows us to deploy applications in containers in a easy way. Unless you have been living for a long time under a rock probably you what I am talking about.

Looking for resources I have found a video of one of the presentation in the Devnexus conferences in 2015 that it has help me a lot. Considering it is a great resource, I am gonna link the video here, instead of writing myself an article, because I consider that it is very well explained and the tricks and solutions he shows are very interesting.

The speaker is Burr Sutter, a former employee (at the time the article is written) of Red Hat. He has a blog, a github account and a twitter account you can check. The video is quite interesting and not boring at all, it is more than one hour but it feels much shorter than that.

In addition, I strongly recommend you to go to his github account (listed before) and take a look to the tutorials he is using during the video:

  • Docker tutorial: Simple deploy of a Java EE application.
  • Docker MySQL tutorial: Same application than the previous one but with two different containers, one with the application server and the application and another one with the MySQL database.

Just a tiny addition to the excellent job he has done. Right now, we can download from the Docker page the native version of Docker for MAC and for Windows. They are still in beta version but I have not had any problem with that and everything looks a bit simpler.

Good luck with your learning and enjoy it.

See you.

Docker for Java developers