Communication Between Linked Docker Containers With Java EE

Docker container to container communication requires either the use of legacy docker links or links in user defined frameworks.

The IP address is dynamically assigned by the docker daemon to the containers and is not known at build time. In a legacy-link scenario the IP address and port-number has to be extracted from static OS environment variables, and in the user-defined networks case the container name, or its alias, can be directly used as hostname. Also in the user-defined scenario there is no additional port-lookup needed. The exposed port can be used without any translation.

For the extraction of legacy links the IP address and the port have to be resolved using System#getenv:


public interface URIProvider {

    public static String computeURIWithEnvironmentEntries(String linkName, int portNumber) {
        String stringifiedPort = String.valueOf(portNumber);
        String portKey = computePortKey(linkName, stringifiedPort);
        String addressKey = computeAddressKey(linkName, stringifiedPort);
        return "http://" + getEnvironmentVariable(addressKey) + ":" + getEnvironmentVariable(portKey);
    }
    static String getEnvironmentVariable(String key) {
        String variable = System.getenv(key);
        if (variable == null) {
            throw new IllegalStateException("No environment variable found for: " + key);
        }
        return variable;
    }

    static String computeKeyPrefix(String linkName, String portNumber) {
        String upperLink = linkName.toUpperCase();
        return upperLink + "_PORT_" + portNumber + "_TCP_";
    }

    static String computePortKey(String linkName, String portNumber) {
        return computeKeyPrefix(linkName, portNumber) + "PORT";
    }

    static String computeAddressKey(String linkName, String portNumber) {
        return computeKeyPrefix(linkName, portNumber) + "ADDR";
    }    
}

In the user-defined network scenario the link and port can be directly used:


  public static String computeUri(String linkName, int portNumber, String resource) {
        return "http://" + linkName + ":" + portNumber + resource;
    }

    public static String computeUri(String linkName, int portNumber) {
        return computeUri(linkName, portNumber, "");
    }


In Java EE context we can introduce more convenience with a qualifier:


@Qualifier
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LegacyLink {

    @Nonbinding
    String name() default "";

    @Nonbinding
    int portNumber() default 8080;

    @Nonbinding
    String path() default "";
}

...and combine it with some conventions:


    @Produces
    @LegacyLink
    public String exposeLegacyLink(InjectionPoint ip) {
        Annotated field = ip.getAnnotated();
        LegacyLink link = field.getAnnotation(LegacyLink.class);
        String linkName = link.name();
        if (linkName.isEmpty()) {
            linkName = ip.getMember().getName().toUpperCase();
        }
        int portNumber = link.portNumber();
        String resource = link.path();
        if (resource.isEmpty()) {
            return URIProvider.computeURIWithEnvironmentEntries(linkName, portNumber);
        } else {
            return URIProvider.computeURIWithEnvironmentEntries(linkName, portNumber, resource);
        }
    }

    @Produces
    @LegacyLink
    public WebTarget exposeLegacyLinkWebTarget(InjectionPoint ip) {
        Client client = ClientBuilder.newClient();
        return client.target(exposeLegacyLink(ip));
    }


...what makes the WebTarget conveniently injectable:


    @Inject
    @LegacyLink(portNumber = 8080, path = "/hugo")
    String ping;


The servicelink utility is already available in maven-central:


<dependency>
    <groupId>com.airhacks</groupId>
    <artifactId>servicelink</artifactId>
    <version>[RECENT]</version>
</dependency>

See also: github.com/AdamBien/servicelink for documentation.

I got the idea for this utility in an undisclosed location -- the origin name was: urimator :-).

See you at Java EE Workshops at Munich Airport, Terminal 2 or Virtual Dedicated Workshops / consulting. Is Munich's airport too far? Learn from home: airhacks.io.

Comments:

Hi Adam!

Maybe I didn't understand this correctly, but /etc/hosts is updated (at least in my docker version) everytime a container is started, so that the alias given by --link <container>:<alias> can successfully be resolved. And the documentation says that the environment variables are only updated on first start (as far as I understood).

Bye
Stefan

Posted by Stefan on February 22, 2016 at 02:29 PM CET #

Post a Comment:
  • HTML Syntax: NOT allowed
...the last 150 posts
...the last 10 comments
License