Skip to content

Commit

Permalink
Update to work with rootless docker networking
Browse files Browse the repository at this point in the history
  • Loading branch information
elahrvivaz committed Apr 18, 2024
1 parent 2445d37 commit 457b105
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 23 deletions.
26 changes: 6 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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.

Expand All @@ -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
7 changes: 6 additions & 1 deletion docker/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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:-}"
Expand Down Expand Up @@ -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: <config file name> <config property> <config value>
function setHadoopConf() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,20 @@
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;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.Properties;
import java.util.concurrent.ExecutionException;

public class AccumuloContainer
extends GenericContainer<AccumuloContainer> {
Expand All @@ -40,20 +43,52 @@ 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() {
return withGeoMesaDistributedRuntime(findDistributedRuntime());
}

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);
Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit 457b105

Please sign in to comment.