Docker: Handling Circular Dependency between Containers

PROBLEM

Let’s assume we are going to run 3 containers:-

Nginx is used to serve cleaner URLs through reverse proxies so that users will access http://server/jenkins and http://server/nexus instead of remembering specific ports.

So, the simplified docker-compose.yml looks like this:-

version: '2'

services:
  jenkins:
    image: "jenkinsci/jenkins"
    ports:
     - "8080:8080"
    volumes:
     - jenkins:/var/jenkins_home
    environment:
      JENKINS_OPTS: "--prefix=/jenkins"

  nexus:
    image: "sonatype/nexus3"
    ports:
     - "8081:8081"
    volumes:
     - nexus:/nexus-data
    environment:
      NEXUS_CONTEXT: "nexus"
    
  nginx:
    build: ./nginx
    ports:
     - "80:80"
    links:
     - jenkins
     - nexus

volumes:
  jenkins:
  nexus:

While http://server/jenkins and http://server/nexus work flawlessly, the Jenkins container is unable to communicate with Nexus through http://server/nexus/some/path, which is handled by Nginx.

Hence, when a Jenkins job tries to pull artifacts from Nexus, the following error is thrown:

[ERROR]     Unresolveable build extension: Plugin ... or one of its 
dependencies could not be resolved: Failed to collect dependencies 
at ... -> ...: Failed to read artifact descriptor for ...: Could 
not transfer artifact ... from/to server 
(http://server/nexus/repository/public/): Connect to server:80 
[server/172.19.0.2] failed: Connection refused (Connection refused) 
-> [Help 2]

SOLUTION: ATTEMPT #1

The first attempt is to set up a link between Jenkins and Nginx with the Nginx alias pointing to the hostname, which is server.

The goal is when Jenkins communicate with Nexus through http://server/nexus/some/path, Nginx will handle the reverse proxy accordingly.

version: '2'

services:
  jenkins:
    image: "jenkinsci/jenkins"
    ports:
     - "8080:8080"
    volumes:
     - jenkins:/var/jenkins_home
    environment:
      JENKINS_OPTS: "--prefix=/jenkins"
    links:
     - nginx:${HOSTNAME}

  nexus:
    image: "sonatype/nexus3"
    ports:
     - "8081:8081"
    volumes:
     - nexus:/nexus-data
    environment:
      NEXUS_CONTEXT: "nexus"

  nginx:
    build: ./nginx
    ports:
     - "80:80"
    links:
     - jenkins
     - nexus

volumes:
  jenkins:
  nexus:

However, when running the containers, it halts with an error:-

ERROR: Circular dependency between nginx and jenkins

SOLUTION: ATTEMPT #2

In effort to prevent the circular dependency problem, we can set up a link between Jenkins and Nexus with the Nexus alias pointing to the hostname, which is server.

This way, Jenkins communicate directly with Nexus through http://server:8081/nexus/some/path and Nginx will stay out of it.

version: '2'

services:
  jenkins:
    image: "jenkinsci/jenkins"
    ports:
     - "8080:8080"
    volumes:
     - jenkins:/var/jenkins_home
    environment:
      JENKINS_OPTS: "--prefix=/jenkins"
    links:
     - nexus:${HOSTNAME}

  nexus:
    image: "sonatype/nexus3"
    ports:
     - "8081:8081"
    volumes:
     - nexus:/nexus-data
    environment:
      NEXUS_CONTEXT: "nexus"

  nginx:
    build: ./nginx
    ports:
     - "80:80"
    links:
     - jenkins
     - nexus

volumes:
  jenkins:
  nexus:

This works without problem.

However, this configuration somewhat defeats the purpose of using Nginx because while the users may access Jenkins and Nexus without specifying custom ports, Jenkins has to communicate with Nexus using port 8081.

Furthermore, this Nexus port is fully exposed in the build logs in all Jenkins jobs.

SOLUTION: ATTEMPT #3

The last attempt is to configure Nginx with the hostname as a network alias.

version: '2'

services:
  jenkins:
    image: "jenkinsci/jenkins"
    ports:
     - "8080:8080"
    volumes:
     - jenkins:/var/jenkins_home
    environment:
      JENKINS_OPTS: "--prefix=/jenkins"

  nexus:
    image: "sonatype/nexus3"
    ports:
     - "8081:8081"
    volumes:
     - nexus:/nexus-data
    environment:
      NEXUS_CONTEXT: "nexus"

  nginx:
    build: ./nginx
    ports:
     - "80:80"
    links:
     - jenkins
     - nexus
    networks:
      default:
        aliases:
         - ${HOSTNAME}

volumes:
  jenkins:
  nexus:

networks:
  default:

This time, Jenkins is able to communicate successfully with Nexus through http://server/nexus/some/path and Nginx will handle the reverse proxy accordingly.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s