Docker-compose, Windows 10/Linux/Bamboo and containers’ IP address

Last time I was playing a little bit with setting up a Docker-compose environment with couple of applications running in separate containers and communicating with them from the host machine. A program running on a host machine needed to know IP address and port number mapped to a given containerized application. The aim was to prepare an infrastructure in an OS-independent way. Unfortunately it looks that Docker-compose for Linux works a little bit different that Docker-compose for Windows (at least in Docker Toolbox variant).

Containers were configured to use network mode “bridge”, so containerized applications could communicate between each other. Each container exposed one port that should be mapped by Docker-compose to a dynamically allocated port accessible from the host machine. Those ports can be easily established based on the output of docker-compose ps command.

How to establish IP address?

Please note that we’re not interested in internal IP addresses of containers used in inter-container communication. We would like to know the IP address used from the host machine to communicate with containers.


It turned out that under Windows (Windows 10, Docker Toolbox for Windows) to establish IP address that is used on the host machine to communicate with containerized applications one needs to use the docker-machine command:

docker-machine ip

The IP address returned by this command is the one assigned to a virtual machine created internally by Docker-compose on Windows to implement containers. And this is a kind of a surprise for beginners.


On the other hand, under Linux, the IP address used on the host machine to communicate with containerized applications is just… a local host address (or localhost).

But wait! This doesn’t work when Docker containers are started by a job on Atlassian Bamboo server which itself is running under Linux. I was facing “connection refused” error in this case. So according to point 2 of step 4 in “Get started with Docker Compose” document (official Docker documentation!) there is a second option: use IP address of

This worked on my computer with Linux but again it didn’t work in Atlassian Bamboo environment which seemed to be Linux environment! But it looks like Bamboo agents are running in Docker. Or at least they can run in Docker (Bamboo server was out of my control so I wasn’t sure). So it’s possible this was a case of running Docker containers inside a Docker container!

Solution for Linux and for Atlassian Bamboo

The universal solution for establishing correct IP that works under Linux and in Atlassian Bamboo (if it runs under Linux) is to determine the IP of a network interface created by Docker to provide its network mode “bridge”. There are couple of ways how to determine:

  1. Use command docker network inspect bridge and look for line with “Gateway” (in the example below the IP is
    $ docker network inspect bridge
            "Name": "bridge",
            "Id": "7f08d9b766b7ac71c6a87f049f2e9908137d03fd4e5ea682f3d7b9009359f756",
            "Created": "2018-02-21T17:02:29.521034216+01:00",
            "Scope": "local",
            "Driver": "bridge",
            "EnableIPv6": false,
            "IPAM": {
                "Driver": "default",
                "Options": null,
                "Config": [
                        "Subnet": "",
                        "Gateway": ""
            "Internal": false,
            "Attachable": false,
            "Containers": {},
            "Options": {
                "": "true",
                "": "true",
                "": "true",
                "": "",
                "": "docker0",
                "": "1500"
            "Labels": {}
  2. Use command ifconfig and look for something like docker0 interface:
    $ ifconfig
    docker0   Link encap:Ethernet  HWaddr 01:41:16:d1:e1:01  
              inet addr:  Bcast:  Mask:
              UP BROADCAST MULTICAST  MTU:1500  Metric:1
              RX packets:0 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0 
              RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
  3. Use “docker inspect” command with ID of any of your running Docker containers and look for NetworkSettings.Gateway property. Sample output.
  4. If any of above methods is not available (still possible under Bamboo) then use Docker-client library made by Spotify. For me this Java code worked to get the IP:
    DockerClient dockerClient = DefaultDockerClient.fromEnv().build();
    ContainerInfo info = dockerClient.inspectContainer(dockerContainerId);
    String ipAddress = info.networkSettings().gateway();

This single approach of establishing IP to communicate with Docker containers worked for me if my environment setup script just detected Linux, no matter if it was running on my Linux box or under Bamboo (running under Linux as well).


Docker-compose is mostly great in unifying runtime environment however establishing IP address to communicate with containers from outside of Docker is still not unified. The problems are not only introduced by Windows OS. The case I’ve experienced with Atlassian Bamboo shows network related problem with Docker can appear in other circumstances as well. :-\

Posted in Docker, Linux | Tagged , , , , | Leave a comment

No Windows in boot menu after installing Linux Mint 18.3

Last days I needed to install Linux on a computer having pre-installed Windows. I wasn’t installing Linux next to Windows for many years and the previous time it was a plain PC with BIOS and Windows XP and all went well.

But this time… this time it was a laptop (Lenovo ThinkPad L470) with UEFI (What it’s all about UEFI vs BIOS?) and Windows 10. And this time after installing Linux Mint 18.3 I was surprised to notice that Grub menu is missing Windows entry! And BIOS (UEFI?) option to boot Windows Boot Loader didn’t work. Apparently I was left with no way to boot Windows 10 again.


In my case it was enough to boot the installed Linux, open a terminal and execute this command:

sudo update-grub

After this, on the next start/reboot of the computer, the Grub menu contained the entry “Windows 10” and Windows was booting correctly when selected. Voila!

Posted in Linux | Tagged , , , | Leave a comment

Spring Framework and uber-jar made by maven-shade-plugin

If you’re trying to build a Java application in a form of an uber-jar with use of Spring Framework, maven and maven-shade-plugin and you see an error similar to the below one (BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace) after running the application then this article is for you.

org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace []
Offending resource: class path resource [app-context.xml]

	at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(
	at org.springframework.beans.factory.parsing.ReaderContext.error(
	at org.springframework.beans.factory.parsing.ReaderContext.error(
	at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.error(
	at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(
	at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(


The solution is to extend maven-shade-plugin configuration in your pom.xml as given in documentation for maven-shade-plugin Resource Transformers. The important part to add is:

<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">

The complete configuration of maven-shade-plugin is therefore something like this:

		        <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
		        <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
		        <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">

The above worked for me. Parameters <filters> and <createDependencyReducedPom/> were accompanying some sample plugin configuration I found and they’re not breaking things in my case.

Posted in Java, Spring | Tagged , , | Leave a comment

How to install Skype 8 on Linux (Ubuntu & Mint)

An installation of Skype in version 8.xx is a little bit different than it was with Skype 4.xx from what I found. As of writing this the current version of Skype is 8.11 and the procedure that I’ve checked on 2 computers was:

  1. Download DEB package with Skype from
  2. Check if GDebi is installed in your system. If not, install it from a repository. I used Synaptic package manager for this.
  3. Open downloaded DEB file (skypeforlinux-64.deb) with GDebi. To to this right-click on the file. On Linux Mint with Mate the context menu already contained “Open with GDebi” as the first menu-item. On Linux Ubuntu with Cinnamon one has to select “Open with…” menu-item and then select GDebi from the sub-menu.
  4. Click on “Install” button and provide your password


This worked for me under Linux Mint 17.3 and Linux Ubuntu 16.04 both being 64-bit.


Please note that Skype is not an open-source software and I don’t recommend it. This article is just providing an instruction how to get latest Skype version working on Linux in case you need it.

If you know the open-source alternative to Skype that is available on Linux and allows video-calls and it quite stable and somehow popular then please let me know.

Posted in Linux | 2 Comments

Gradle vs Maven

Short story

Don’t use gradle. Use maven.

A little longer story

Don’t use gradle until you really have to. Otherwise use maven.

Long story

Last time I was dropped into a project that was using gradle. And it was the first time during my professional career in Java (11 years!) I’ve encountered gradle in the wild. Moreover in the team there were 3 younger developers having different degree of experience. None of them knew gradle as well and preferred to use maven. Some 3 years before this in another company at the start of a new project we were discussing what build tool to use. Around 20 people and only one of them proposed to use gradle. I think I don’t have to say we’ve decided to use maven.

Conclusion 1: Maven is much more popular and gradle is just exotic. Maven is familiar to most Java developers so choosing gradle will make it harder to maintain the project.

Maven build files (pom.xml) are expressed in XML. XML is a kind of a document so maven build files are documents. It’s good. On the other hand gradle build files (build.gradle) are expressed in something similar to Groovy programming language. That’s make them programs! And as usual in a computer program you can do things in many different ways. And Groovy is even making things worse! There are many optional syntax elements – so they can appear or not (like semicolons – please refer to DZone: Groovy, Sometimes You Still Need a Semicolon.).

Conclusion 2: Gradle build files can be much more messy than Maven build files. Moreover Maven build files are documents you just read while Gradle build files are programs you’re wondering what they do.

Moreover my personal impression was that building a project with gradle is slower than building with maven. It seems others experienced this as well: How to speed up your slow Gradle builds. It’s crazy to use this tool until you really have to!

Posted in Java | Tagged , | 2 Comments

Network problem inside a Docker container

Last weeks me and couple of folks from my team have started using Docker. So every one of us was a Docker-newbie. And I have noticed all of us had the same common problem:

Network connections were not working inside a Docker while they were fine on a host running the Docker container.

Example: I wanted to build a Docker image based on the following Dockerfile:

FROM debian:9.2
RUN apt-get update
RUN apt-get install -y openjdk-8-jdk
RUN apt-get install -y maven
RUN apt-get install -y gradle

My command to build an image:
docker build -t java8_maven_gradle .

It failed as soon as it started executing the apt-get update command. None of other commands making network requests was running as well.

After some surprisingly long search in the Internet I found out that a Docker container by default has networking turned off. That explained our problems. The solution was to add
parameter to commands invoking Docker. So my command became:
docker build --network=host -t java8_maven_gradle .

I used version 17.xx of Docker. Some older versions of Docker do not recognize --network parameter. Instead they need -net.


I suppose this is something obvious for people knowing Docker well. However it looks like people that need to just quickly start using Docker without devoting a longer time for studying are facing this problem often. I guess this is something Docker tutorial/beginners guides don’t cover good enough.

Posted in Docker | Tagged | 1 Comment

Spring Boot configuration for Tomcat’s pooling data source

In one of projects I was just working on in my professional career I’ve faced the problem of a Spring Boot configuration for a Tomcat’s database connection pool. The main issue was that after some time the pool was giving database connections that were not valid so we were trying different pool configuration parameters – but this is not relevant here. What is relevant is that all re-configuring approaches had no effect.

Is Spring Boot properly configuring the data source?

At some point I stopped believing that the Spring Boot is applying data source parameters from configuration file which was application.yml having following part related to the data source:

    url: jdbc:mysql://localhost:3306/some_db
    username: root
    password: root
    driver-class-name: "com.mysql.jdbc.Driver"
      removeAbandoned: true
      removeAbandonedTimeout: 120
      logAbandoned: true
      maxActive: 50
      maxIdle: 5
      maxWait: 1000
      validationQuery: "select 1"
      testOnBorrow: true
      testOnConnect: true
      testWhileIdle: true

I’ve realized that I cannot easily verify what are actual data source parameters being applied by the Spring Boot. At last I’ve added a diagnostic REST endpoint showing what are actual parameters of the data source configured by Spring Boot. It was looking like this:

import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.sql.DataSource;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

public class InfoController {
    private static final Logger LOGGER = LoggerFactory.getLogger(InfoController.class);
    private static final List<String> TOMCAT_DB_CONN_POOL_PROPERTIES = Arrays.asList(
            "driverClassName", "maxActive", "maxAge", "maxIdle", "maxWait", "minEvictableIdleTimeMillis",
            "minIdle", "name", "removeAbandonedTimeout", "timeBetweenEvictionRunsMillis", "validationInterval",
            "validationQuery", "validationQueryTimeout", "removeAbandoned", "testOnBorrow", "testWhileIdle",
            "testOnConnect", "poolSweeperEnabled", "logAbandoned", "jmxEnabled", "url", "dataSourceJNDI",
            "initialSize", "suspectTimeout", "username", "useDisposableConnectionFacade");

    private DataSource dataSource;

    @RequestMapping(path = "/data-source-info", method = RequestMethod.GET, produces = "application/json")
    public Object getInfo() {
        Map<String, Object> dataSourceDetails = new TreeMap<>();
        dataSourceDetails.put("data-source-class", dataSource.getClass().getName());
        addObjPropertiesUnderKey(dataSource, "data-source-config", dataSourceDetails);
        return dataSourceDetails;

    static void addObjPropertiesUnderKey(Object obj, String key, Map<String, Object> map) {
        try {
            Map<String, Object> properties = new TreeMap<>();
   -> addPropertyIfNotNull(obj, property, properties));
            if (!properties.isEmpty()) {
                map.put(key, properties);
        } catch (Exception e) {
            LOGGER.warn("Cannot fetch properties of object: {}.", obj, e);

    static void addPropertyIfNotNull(Object obj, String property, Map<String, Object> map) {
        try {
            String value = BeanUtils.getProperty(obj, property);
            if (value != null) {
                map.put(property, value);
        } catch (Exception e) {
            LOGGER.warn("Cannot get property '{}' from  object of class {}. {}", property, obj.getClass(), e.getMessage());

The above solution uses dynamic property access with BeanUtils to not bind the application code to the actual data source implementation class (org.apache.tomcat.jdbc.pool.DataSource in case of Tomcat db-connection pool). And of course the set of property names is specific for this data source class.

The first look at the output produced by this REST controller confirmed my suspicion. Only first 4 parameters were properly applied (url, user, password and driver class). The remaining parameters (all with prefix spring.datasource.tomcat.) were ignored by the Spring Boot!

Spring Boot versions and the parameters naming

It turned out the data source parameters definition given in project’s application.yml file was conforming to the current version of the Spring Boot – which was 1.5.8 at the time of writing this article. But the Spring Boot version used in the project was much older: 1.3.8.

Please note the difference between the section “Connection to a production database” for Spring Boot 1.5.8 and the same section for Spring Boot 1.3.8!

For Spring Boot 1.3.8 we have:

And for Spring Boot 1.5.8 we have:

Now it got clear that parameters naming with “tomcat” was not valid for the Spring Boot version used in the project. The naming scheme was changed in Spring Boot somewhere between versions 1.3.x and 1.5.x! The correct form of this part of application.yml for Spring Boot 1.3.8 is:

    url: jdbc:mysql://localhost:3306/some_db
    username: root
    password: root
    driver-class-name: "com.mysql.jdbc.Driver"
    removeAbandoned: true
    removeAbandonedTimeout: 120
    logAbandoned: true
    maxActive: 50
    maxIdle: 5
    maxWait: 1000
    validationQuery: "select 1"
    testOnBorrow: true
    testOnConnect: true
    testWhileIdle: true

After this change the actual data source parameters dump provided by my diagnostic endpoint confirmed that now values from the configuration file are used.

Very tricky!


  1. One should always refer to the documentation in version corresponding to the version of a framework being used.
  2. It’s really hard to solve a problem without a diagnostic tool (like the InfoController class presented above) so don’t hesitate to invest time into preparing one. In a result it will save your time.
Posted in database, Java, Spring, Tomcat | Tagged , | 3 Comments