Skip to content

Commit

Permalink
Add docker deployment configuration and fix up standby configuration.
Browse files Browse the repository at this point in the history
  • Loading branch information
mikeb01 committed Aug 29, 2023
1 parent 4ab6b12 commit 5788ee4
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 23 deletions.
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
* limitations under the License.
*/

val useStandby: String by project

plugins {
java
}
Expand Down
14 changes: 14 additions & 0 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,20 @@ services:
- CLUSTER_ADDRESSES=172.16.202.2,172.16.202.3,172.16.202.4
- CLUSTER_PORT_BASE=9000
- BACKUP_HOST=172.16.202.20
standby:
profiles: ["standby"]
build:
context: ../standby
hostname: backup
shm_size: '1gb'
networks:
internal_bus:
ipv4_address: 172.16.202.30
environment:
- CLUSTER_ADDRESSES=172.16.202.2,172.16.202.3,172.16.202.4
- CLUSTER_PORT_BASE=9000
- STANDBY_HOST=172.16.202.30
- CLUSTER_NODE=4

networks:
internal_bus:
Expand Down
6 changes: 3 additions & 3 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.7.0"
}

val useStandby = true

rootProject.name = "aeron-io-samples"
include("cluster", "cluster-protocol", "admin", "backup")
if (useStandby) {

val standby: String? by settings
if (true == standby?.toBoolean()) {
include("standby")
}
15 changes: 15 additions & 0 deletions standby/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
ARG REPO_NAME=docker.io/
ARG IMAGE_NAME=azul/zulu-openjdk-debian
ARG IMAGE_TAG=17
FROM ${REPO_NAME}${IMAGE_NAME}:${IMAGE_TAG}

SHELL [ "/bin/bash", "-o", "pipefail", "-c" ]

COPY --chmod=755 setup-docker.sh /root/dockerbuild/setup-docker.sh
COPY --chmod=755 setup-docker.sh /root/aeron/
RUN /root/dockerbuild/setup-docker.sh && rm --recursive --force "/root/dockerbuild"

WORKDIR /root/jar/
COPY --chmod=755 /build/libs/standby-uber.jar /root/jar/standby-uber.jar
COPY --chmod=755 entrypoint.sh /root/jar/entrypoint.sh
ENTRYPOINT ["/root/jar/entrypoint.sh"]
19 changes: 19 additions & 0 deletions standby/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Standby

Aeron Cluster Standby is a premium feature.
In order to the Standby quickstart you must have access to the binaries Aeron Cluster Standby provided by Adaptive.
If you don't have access to these this feature interests you please contact adaptive via http://aeron.io.

The Standby features of the quickstart a disabled by default.
They need to be enabled in both the build and with any docker compose steps.
E.g. for builds within the project root.

```shell
> ./gradlew -Pstandby=true
```

When running the docker steps within the `<project root>/docker` directory
```shell
> docker compose --profile standby build --no-cache
> docker compose --profile standby up
```
23 changes: 23 additions & 0 deletions standby/setup-docker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash

echo "debconf debconf/frontend select noninteractive" | debconf-set-selections

apt-get update \
--quiet \
--assume-yes

apt-get install \
--quiet \
--assume-yes \
--no-install-recommends \
bash \
procps \
less \
sysstat \
wget

mkdir /root/aeron
mkdir /root/jar

wget https://repo1.maven.org/maven2/io/aeron/aeron-all/1.42.0/aeron-all-1.42.0.jar -P /root/aeron/
# TODO: Copy cluster standby jars in place as well...
64 changes: 44 additions & 20 deletions standby/src/main/java/io/aeron/samples/ClusterStandbyApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,17 @@

package io.aeron.samples;

import io.aeron.archive.Archive;
import io.aeron.archive.ArchiveThreadingMode;
import io.aeron.archive.ArchivingMediaDriver;
import io.aeron.archive.client.AeronArchive;
import io.aeron.cluster.ClusterBackup;
import io.aeron.cluster.ClusterStandby;
import io.aeron.cluster.service.ClusteredServiceContainer;
import io.aeron.driver.MediaDriver;
import io.aeron.samples.cluster.ClusterConfig;
import io.aeron.samples.infra.AppClusteredService;
import org.agrona.concurrent.NoOpLock;
import org.agrona.concurrent.ShutdownSignalBarrier;
import org.agrona.concurrent.SystemEpochClock;
import org.slf4j.Logger;
Expand All @@ -31,15 +36,14 @@
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;
import java.util.StringJoiner;

import static io.aeron.samples.cluster.ClusterConfig.ARCHIVE_CONTROL_PORT_OFFSET;
import static io.aeron.samples.cluster.ClusterConfig.MEMBER_FACING_PORT_OFFSET;
import static java.lang.Integer.parseInt;

/**
* Sample cluster backup application
* Sample cluster standby application
*/
public class ClusterStandbyApp
{
Expand All @@ -58,22 +62,38 @@ public static void main(final String[] args)
final String standbyHost = getStandbyHost();
final int standbyMemberId = getMemberId();
final int basePort = getBasePort();
final String hosts = getClusterAddresses();
final List<String> hostAddresses = List.of(hosts.split(","));
final File baseDir = getBaseDir(standbyMemberId);

final ClusterConfig clusterConfig = ClusterConfig.create(
standbyMemberId, hostAddresses, hostAddresses, basePort, new AppClusteredService());
clusterConfig.baseDir(baseDir);
final MediaDriver.Context mediaDriverContext = new MediaDriver.Context().dirDeleteOnStart(true);
final String aeronDirectoryName = mediaDriverContext.aeronDirectoryName();

final String standbyConsensusEndpoint = standbyHost + ":" + ClusterConfig.calculatePort(
standbyMemberId, basePort, MEMBER_FACING_PORT_OFFSET);
final String standbyArchiveEndpoint = standbyHost + ":" + ClusterConfig.calculatePort(
standbyMemberId, basePort, ARCHIVE_CONTROL_PORT_OFFSET);
final String standbyResponseEndpoint = standbyHost + ":0";
final String standbyDynamicEndpoint = standbyHost + ":0";
final String standbyResponseEndpoint = standbyDynamicEndpoint;
final String clusterConsensusEndpoints = getClusterConsensusEndpoints();

clusterConfig.archiveContext().archiveDir(new File("standby/archive"));
final AeronArchive.Context replicationArchiveContext = new AeronArchive.Context()
.controlResponseChannel("aeron:udp?endpoint=" + standbyDynamicEndpoint);

final Archive.Context archiveContext = new Archive.Context()
.aeronDirectoryName(aeronDirectoryName)
.archiveDir(new File(baseDir, ClusterConfig.ARCHIVE_SUB_DIR))
.controlChannel("aeron:udp?endpoint=" + standbyArchiveEndpoint)
.archiveClientContext(replicationArchiveContext)
.localControlChannel("aeron:ipc?term-length=64k")
.replicationChannel("aeron:udp?endpoint=" + standbyDynamicEndpoint)
.recordingEventsEnabled(false)
.threadingMode(ArchiveThreadingMode.SHARED);

final AeronArchive.Context aeronArchiveContext = new AeronArchive.Context()
.lock(NoOpLock.INSTANCE)
.controlRequestChannel(archiveContext.localControlChannel())
.controlRequestStreamId(archiveContext.localControlStreamId())
.controlResponseChannel(archiveContext.localControlChannel())
.aeronDirectoryName(aeronDirectoryName);

// Context for Cluster Standby.
final ClusterStandby.Context clusterStandbyContext = new ClusterStandby.Context()
Expand All @@ -87,26 +107,30 @@ public static void main(final String[] args)
.responseEndpoint(standbyResponseEndpoint) // The endpoint that receives responses to requests
// (e.g backup queries).
.standbyDir(new File(baseDir, "standby"))
.archiveContext(clusterConfig.aeronArchiveContext().clone())
.aeronDirectoryName(clusterConfig.mediaDriverContext().aeronDirectoryName())
.archiveContext(aeronArchiveContext.clone())
.aeronDirectoryName(aeronDirectoryName)
.sourceType(ClusterBackup.SourceType.FOLLOWER) // What kind of node(s) to connect to.
.standbySnapshotEnabled(true)
.standbySnapshotNotificationsEnabled(true)
.deleteDirOnStart(true);

final ClusteredServiceContainer.Context clusteredServiceContext = clusterConfig.clusteredServiceContext();
final ClusteredServiceContainer.Context clusteredServiceContext = new ClusteredServiceContainer.Context()
.aeronDirectoryName(aeronDirectoryName)
.archiveContext(aeronArchiveContext.clone())
.clusterDir(new File(baseDir, ClusterConfig.CLUSTER_SUB_DIR))
.clusteredService(new AppClusteredService())
.serviceId(0);

LOGGER.info("Standby Directory: {} ", clusterStandbyContext.standbyDirectoryName());
LOGGER.info("Archive Directory: {} ", clusterConfig.archiveContext().archiveDir());
LOGGER.info("Archive Directory: {} ", archiveContext.archiveDir());
LOGGER.info("Connecting to cluster: {}", clusterConsensusEndpoints);

try (
ArchivingMediaDriver ignored = ArchivingMediaDriver.launch(
clusterConfig.mediaDriverContext(), clusterConfig.archiveContext());
ArchivingMediaDriver ignored = ArchivingMediaDriver.launch(mediaDriverContext, archiveContext);
ClusterStandby ignored1 = ClusterStandby.launch(clusterStandbyContext);
ClusteredServiceContainer ignored2 = ClusteredServiceContainer.launch(clusteredServiceContext))
{
LOGGER.info("Started Cluster Backup...");
LOGGER.info("Started Cluster Standby...");
barrier.await();
LOGGER.info("Exiting");
}
Expand Down Expand Up @@ -180,13 +204,13 @@ private static String getClusterAddresses()

private static String getStandbyHost()
{
final String backupHost = System.getenv("STANDBY_HOST");
if (backupHost == null || backupHost.isEmpty())
final String standbyHost = System.getenv("STANDBY_HOST");
if (standbyHost == null || standbyHost.isEmpty())
{
return "localhost";
}
awaitDnsResolution(backupHost);
return backupHost;
awaitDnsResolution(standbyHost);
return standbyHost;
}

private static void awaitDnsResolution(final String[] hosts)
Expand Down

0 comments on commit 5788ee4

Please sign in to comment.