Fuse for the Idle Fellow – Re-assigning Fabric container ports

Once is happenstance, twice is coincidence.
The third time it’s a dependable product feature.

If you were to spin up a fresh instance of JBoss Fuse and add a container for your CXF web services, you’ll find port 8182 is where you need to go to call them. Do it over again and you’ll still find 8182 is the place to go. Over again and thrice it’s 8182. For Idle Fellows that’s usually enough to comfortably announce that 8182 is our web service port and have our client applications, tests, utility scripts and so on freely use it. After all, to paraphrase Auric Goldfinger , “Once is happenstance, twice is coincidence, the third time it’s a feature.”

Idle Fellows who want to avoid a similar fate to Mr Goldfinger though might be wise to know what to do when it turns out not to be.

Container port

Every container deployed in a Fabric exposes a welter of goodies on its HTTP port, such as Jolokia (for JMX over HTTP operations), CXF web-services and its Hawtio console:-

JBossFuse:admin@root> container-info an-example-container
Name:                   an-example-container
Version:                1.0
Connected:              true
Type:                   karaf
...            
SSH Url:                extra:8103
JMX Url:                service:jmx:rmi://extra:44446/jndi/rmi:...
Http Url:               http://extra:8183
Jolokia Url:            http://extra:8183/jolokia
Blueprint Status:       started
Provision Status:       success

These ports are allocated by the Fabric’s OSGi Port Service and by default each new container is allocated the first available port starting with 8181.

So if we deploy our containers in a consistent pattern and in a consistent order, our web-based services should always be allocated a consistent set of ports.

Right?

Well, yes, ‘til it’s wrong.

Any port in a storm

By way of an example, here are two Fabric containers with CXF services deployed to a clean host:-

JBossFuse:admin@root> container-list
[id]               [version] [type] [connected] [profiles]   [status]
extra-services-1   1.0       karaf  yes         default      success
                                                feature-cxf
extra-services-2   1.0       karaf  yes         default      success
                                                feature-cxf

Since they were deployed to a clean host extra-services-1 got port 8181 and extra-services-2 got port 8182:-

JBossFuse:admin@root> cluster-list servlets
[cluster]             [masters]         [slaves]  [services]
io.fabric8.fabric-jolokia/1.2.0.redhat-133/jolokia
  extra-services-1   extra-services-1  -         http://extra:8181/jolokia
  extra-services-2   extra-services-2  -         http://extra:8182/jolokia
org.apache.cxf.cxf-rt-transports-http/3.0.4.redhat-620133/cxf
  extra-services-1   extra-services-1  -         http://extra:8181/cxf
  extra-services-2   extra-services-2  -         http://extra:8182/cxf

If we were deploying the same containers to fresh environments in the same order, and if the deployment was successful every time, then they’d always get these ports. But what if our deployment wasn’t consistent for some reason? Maybe one of the containers failed to deploy and we had to manually re-create it, or another container already existed on the host and was already hogging port 8181. We might end up with something like this:-

JBossFuse:admin@root> cluster-list servlets
[cluster]             [masters]           [slaves]  [services]
io.fabric8.fabric-jolokia/1.2.0.redhat-133/jolokia
  extra-already-here extra-already-here  -         http://extra:8181/jolokia
  extra-services-1   extra-services-1    -         http://extra:8182/jolokia
  extra-services-2   extra-services-2    -         http://extra:8183/jolokia
org.apache.cxf.cxf-rt-transports-http/3.0.4.redhat-620133/cxf
  extra-already-here extra-already-here  -         http://extra:8181/cxf
  extra-services-1   extra-services-1    -         http://extra:8182/cxf
  extra-services-2   extra-services-2    -         http://extra:8183/cxf

The presence of extra-already-here on the host has shifted the service containers up a port.  Idle Fellows would be forgiven for resorting to wiping out these containers and deploying again, but fortunately there is a slightly niftier solution.

New ports of call

It’s not only possible, but also pretty easy, to re-assign the port a container uses for its web-based services if you know where to find them and if you’ve got the ZooKeeper Karaf commands installed:-

JBossFuse:admin@root> zk:list
Command not found: zk:list

They’re not there by default, and they’re not here in my environment either, so we need to add them:-

JBossFuse:admin@root> profile-create zookeeper-commands
JBossFuse:admin@root> profile-edit --features fabric-zookeeper-commands 
    zookeeper-commands
Adding feature:fabric-zookeeper-commands to profile:zookeeper-commands 
    version:1.0
JBossFuse:admin@root> container-add-profile root zookeeper-commands
JBossFuse:admin@root> zk:list
zookeeper
fabric

The port used for web-based services by each Fabric container is buried in the ZooKeeper registry under /fabric/registry/ports/containers/<container-name>/org.ops4j.pax.web/org.osgi.service.http.port:-

JBossFuse:admin@root> zk:get /fabric/registry/ports/containers/
    extra-already-here/org.ops4j.pax.web/org.osgi.service.http.port
8181

What we can zk:get, we can also zk:set:-

JBossFuse:admin@root> zk:set /fabric/registry/ports/containers/
    extra-already-here/org.ops4j.pax.web/org.osgi.service.http.port 8183
JBossFuse:admin@root> zk:set /fabric/registry/ports/containers/
    extra-services-1/org.ops4j.pax.web/org.osgi.service.http.port 8181
JBossFuse:admin@root> zk:set /fabric/registry/ports/containers/
    extra-services-2/org.ops4j.pax.web/org.osgi.service.http.port 8182

These changes won’t take effect on-the-fly so we need to bounce all three containers, after which we find our service containers back on their expected ports and extra-already-here bumped out of the way to port 8183:-

JBossFuse:admin@root> cluster-list servlets
[cluster]             [masters]           [slaves]  [services]
io.fabric8.fabric-jolokia/1.2.0.redhat-133/jolokia
  extra-already-here extra-already-here  -         http://extra:8183/jolokia
  extra-services-1   extra-services-1    -         http://extra:8181/jolokia
  extra-services-2   extra-services-2    -         http://extra:8182/jolokia
org.apache.cxf.cxf-rt-transports-http/3.0.4.redhat-620133/cxf
  extra-already-here extra-already-here  -         http://extra:8183/cxf
  extra-services-1   extra-services-1    -         http://extra:8181/cxf
  extra-services-2   extra-services-2    -         http://extra:8182/cxf

A girl in every port

When deploying containers and services in a consistent pattern those containers will expose their web based services on a consistent set of ports, so it’s not unreasonable to rely on those port assignments for clients. There are more meritorious ways of meeting the need for fixed port connectivity to services within a Fabric but, as all Idle Fellows know, sometimes simple needs are best met in the simplest possible way.

Leave a Reply

Your email address will not be published. Required fields are marked *