From 457b105479f4428db820a24e2f35a7138a211a54 Mon Sep 17 00:00:00 2001 From: Emilio Lahr-Vivaz Date: Thu, 18 Apr 2024 10:46:31 -0400 Subject: [PATCH] Update to work with rootless docker networking --- README.md | 26 +++---------- docker/start.sh | 7 +++- .../testcontainers/AccumuloContainer.java | 39 ++++++++++++++++++- 3 files changed, 49 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 78c8da6..9004ef2 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,6 @@ This project is a wrapper for [fluo-uno](https://github.com/apache/fluo-uno). -Accumulo, Hadoop and Zookeeper are all configured by IP address when the container is started. As such, they should -generally be accessible from the host machine (usually using `localhost` through exposed ports) or through a docker -network (using the docker `host`.) - Note that the container is meant for quick tests, and data may be corrupted or lost on shutdown. If data needs to be preserved, `exec` into the running container and run `$UNO_HOME/bin/uno stop accumulo` to perform a graceful shutdown. @@ -14,28 +10,15 @@ preserved, `exec` into the running container and run `$UNO_HOME/bin/uno stop acc docker pull ghcr.io/geomesa/accumulo-uno:2.1.2 docker run --rm \ -p 2181:2181 -p 9997:9997 -p 9999:9999 \ + --hostname $(hostname -s) \ ghcr.io/geomesa/accumulo-uno:2.1.2 +Note that the `hostname` must be set to the hostname of the host in order for Accumulo's networking to work. + The Accumulo connection properties are available in the container: docker cp $(docker ps | grep accumulo-uno | awk '{ print $1 }'):/opt/fluo-uno/install/accumulo/conf/accumulo-client.properties . -### Rootless Docker - -When running in rootless Docker, some additional steps are required to enable networking. - -First, add an entry to `/etc/hosts` to alias `accumulo.local` to `127.0.0.1`: - - sed -i 's/127\.0\.0\.1.*/\0 accumulo.local/' /etc/hosts - -The add the following flags to the `docker run` command: - - docker run --rm \ - -p 2181:2181 -p 9997:9997 -p 9999:9999 \ - --hostname accumulo.local \ - -e UNO_HOST=accumulo.local \ - ghcr.io/geomesa/accumulo-uno:2.1.2 - ### Using the Docker with GeoMesa In order to use GeoMesa, the distributed runtime JAR must be mounted in to the container. The distributed runtime @@ -45,6 +28,7 @@ JAR is available from [GeoMesa](https://github.com/locationtech/geomesa/releases tar -xf accumulo_2.12-4.0.5-bin.tar.gz docker run --rm \ -p 2181:2181 -p 9997:9997 -p 9999:9999 \ + --hostname $(hostname -s) \ -v "$(pwd)"/geomesa-accumulo_2.12-4.0.5/dist/accumulo/geomesa-accumulo-distributed-runtime_2.12-4.0.5.jar:/opt/fluo-uno/install/accumulo/lib/geomesa-accumulo-distributed-runtime.jar \ ghcr.io/geomesa/accumulo-uno:2.1.2 @@ -103,6 +87,7 @@ Most functionality should work with the following ports exposed: * `2181` - Zookeeper * `9997` - Accumulo Tablet Server +* `9999` - Accumulo Manager Server See the Accumulo [docs](https://accumulo.apache.org/docs/2.x/administration/in-depth-install#network) for a full list of ports. @@ -118,6 +103,7 @@ The following environment variables are supported at runtime: * `ZOOKEEPER_PORT` - override the default Zookeeper port * `TSERVER_PORT` - override the default tablet server port +* `MANAGER_PORT` - override the default manager client port * `UNO_HOST` - bind the Accumulo processes to the specified host * `UNO_COMMAND` - the command used to run fluo-uno, default `run` * `UNO_GRACEFUL_STOP` - enable a graceful shutdown to prevent data loss diff --git a/docker/start.sh b/docker/start.sh index 6b4782b..3326d75 100755 --- a/docker/start.sh +++ b/docker/start.sh @@ -4,7 +4,7 @@ set -e UNO_HOME="${UNO_HOME:-/opt/fluo-uno}" -UNO_HOST="${UNO_HOST:-$(hostname -I | awk '{ print $1 }')}" # use IP address if not specified +UNO_HOST="${UNO_HOST:-$(hostname -s)}" # use hostname if not specified UNO_SERVICE="${UNO_SERVICE:-accumulo}" UNO_COMMAND="${UNO_COMMAND:-run}" UNO_GRACEFUL_STOP="${UNO_GRACEFUL_STOP:-}" @@ -48,6 +48,11 @@ if [[ -n "$TSERVER_PORT" ]] && [[ $TSERVER_PORT != "9997" ]]; then echo -e "\ntserver.port.client=${TSERVER_PORT}" >> "$UNO_HOME"/install/accumulo/conf/accumulo.properties fi +if [[ -n "$MANAGER_PORT" ]] && [[ $MANAGER_PORT != "9999" ]]; then + echo "Setting manager.port.client to $MANAGER_PORT" + echo -e "\nmanager.port.client=${MANAGER_PORT}" >> "$UNO_HOME"/install/accumulo/conf/accumulo.properties +fi + # sets a hadoop config value - assumes that the value does not already exist # params: function setHadoopConf() { diff --git a/testcontainers/src/main/java/org/geomesa/testcontainers/AccumuloContainer.java b/testcontainers/src/main/java/org/geomesa/testcontainers/AccumuloContainer.java index e06fc05..8e2743d 100644 --- a/testcontainers/src/main/java/org/geomesa/testcontainers/AccumuloContainer.java +++ b/testcontainers/src/main/java/org/geomesa/testcontainers/AccumuloContainer.java @@ -11,10 +11,12 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.output.Slf4jLogConsumer; +import org.testcontainers.shaded.org.apache.commons.io.IOUtils; import org.testcontainers.utility.DockerImageName; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.net.ServerSocket; import java.net.URI; import java.net.URISyntaxException; @@ -22,6 +24,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Paths; import java.util.Properties; +import java.util.concurrent.ExecutionException; public class AccumuloContainer extends GenericContainer { @@ -40,12 +43,44 @@ public AccumuloContainer() { public AccumuloContainer(DockerImageName imageName) { super(imageName); int tserverPort = getFreePort(); + int managerPort = getFreePort(); addFixedExposedPort(zookeeperPort, zookeeperPort); addFixedExposedPort(tserverPort, tserverPort); + addFixedExposedPort(managerPort, managerPort); addExposedPorts(9995); // accumulo monitor, for debugging addEnv("ZOOKEEPER_PORT", Integer.toString(zookeeperPort)); addEnv("TSERVER_PORT", Integer.toString(tserverPort)); + addEnv("MANAGER_PORT", Integer.toString(managerPort)); + // noinspection resource withLogConsumer(new AccumuloLogConsumer()); + + // to get networking right, we need to make the container use the same hostname as the host - + // that way when it returns tserver locations, they will map to localhost and go through the correct port bindings + String hostname = null; + try { + hostname = + Runtime.getRuntime() + .exec("hostname -s") + .onExit() + .thenApply((p) -> { + try (InputStream is = p.getInputStream()) { + return IOUtils.toString(is, StandardCharsets.UTF_8).trim(); + } catch (IOException e) { + logger.error("Error reading hostname:", e); + return null; + } + }) + .get(); + } catch (IOException | InterruptedException | ExecutionException e) { + logger.error("Error reading hostname:", e); + } + if (hostname != null) { + String finalHostname = hostname; + // noinspection resource + withCreateContainerCmdModifier((cmd) -> cmd.withHostName(finalHostname)); + // noinspection resource + withNetworkAliases(hostname); + } } public AccumuloContainer withGeoMesaDistributedRuntime() { @@ -53,7 +88,7 @@ public AccumuloContainer withGeoMesaDistributedRuntime() { } public AccumuloContainer withGeoMesaDistributedRuntime(String jarHostPath) { - logger.info("Binding to host path " + jarHostPath); + logger.info("Binding to host path {}", jarHostPath); return withFileSystemBind(jarHostPath, "/opt/fluo-uno/install/accumulo/lib/geomesa-accumulo-distributed-runtime.jar", BindMode.READ_ONLY); @@ -105,7 +140,7 @@ private static String findDistributedRuntime() { try { URL url = AccumuloContainer.class.getClassLoader().getResource(DISTRIBUTED_RUNTIME_PROPS); URI uri = url == null ? null : url.toURI(); - logger.debug("Distributed runtime lookup: " + uri); + logger.debug("Distributed runtime lookup: {}", uri); if (uri != null && uri.toString().endsWith("/target/classes/" + DISTRIBUTED_RUNTIME_PROPS)) { // running through an IDE File targetDir = Paths.get(uri).toFile().getParentFile().getParentFile();