Skip to content

Commit

Permalink
Add EBS data volume support (#36)
Browse files Browse the repository at this point in the history
Fixes: #7
  • Loading branch information
pcholakov authored Aug 29, 2024
1 parent e474d88 commit 1ed6be8
Showing 1 changed file with 61 additions and 13 deletions.
74 changes: 61 additions & 13 deletions lib/restate-constructs/single-node-restate-deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,6 @@ import { TracingMode } from "./deployments-common";
import * as cdk from "aws-cdk-lib";
import { RemovalPolicy } from "aws-cdk-lib";

const PUBLIC_INGRESS_PORT = 443;
const PUBLIC_ADMIN_PORT = 9073;
const RESTATE_INGRESS_PORT = 8080;
const RESTATE_ADMIN_PORT = 9070;
const RESTATE_IMAGE_DEFAULT = "docker.io/restatedev/restate";
const RESTATE_DOCKER_DEFAULT_TAG = "latest";
const ADOT_DOCKER_DEFAULT_TAG = "latest";

export interface SingleNodeRestateProps {
/** The VPC in which to launch the Restate host. */
vpc?: ec2.IVpc;
Expand All @@ -46,6 +38,11 @@ export interface SingleNodeRestateProps {
/** Restate Docker image tag. Defaults to `latest`. */
restateTag?: string;

/**
* EBS data volume settings for Restate data storage. If not specified, a default 8GB volume will be created.
*/
dataVolumeOptions?: ec2.EbsDeviceProps | undefined;

/** Restate high-level configuration options. Alternatively, you can set {@link restateConfigOverride}. */
restateConfig?: {
/** Defaults to the construct id if left unspecified. */
Expand Down Expand Up @@ -84,6 +81,15 @@ export interface SingleNodeRestateProps {
ingressNginxConfigOverride?: string;
}

const PUBLIC_INGRESS_PORT = 443;
const PUBLIC_ADMIN_PORT = 9073;
const RESTATE_INGRESS_PORT = 8080;
const RESTATE_ADMIN_PORT = 9070;
const RESTATE_IMAGE_DEFAULT = "docker.io/restatedev/restate";
const RESTATE_DOCKER_DEFAULT_TAG = "latest";
const ADOT_DOCKER_DEFAULT_TAG = "latest";
const DATA_DEVICE_NAME = "/dev/sdd";

/**
* Creates a Restate service deployment backed by a single EC2 instance, and is suitable for
* development and testing purposes.
Expand Down Expand Up @@ -140,19 +146,20 @@ export class SingleNodeRestateDeployment extends Construct implements IRestateEn

const initScript = ec2.UserData.forLinux();
initScript.addCommands(
"set -euf -o pipefail",
"yum install -y docker nginx",

this.mountDataVolumeScript(),
"mkdir /etc/restate",
["cat << EOF > /etc/restate/config.toml", this.restateConfig(id, props), "EOF"].join("\n"),
["cat << EOF > /etc/restate/config.toml", this.restateConfig(props), "EOF"].join("\n"),

"systemctl start docker.service",
[
"docker run --name adot --restart unless-stopped --detach",
"docker run --name adot --restart on-failure --detach",
" -p 4317:4317 -p 55680:55680 -p 8889:8888",
` public.ecr.aws/aws-observability/aws-otel-collector:${adotTag}`,
].join(""),
[
"docker run --name restate --restart unless-stopped --detach",
"docker run --name restate --restart on-failure --detach",
" --volume /etc/restate:/etc/restate",
" --volume /var/restate:/restate-data",
" --network=host",
Expand Down Expand Up @@ -188,8 +195,22 @@ export class SingleNodeRestateDeployment extends Construct implements IRestateEn
cpuType: ec2.AmazonLinuxCpuType.ARM_64,
}),
role: this.instanceRole,
blockDevices: [
{
deviceName: DATA_DEVICE_NAME,
volume: {
ebsDevice: {
volumeSize: 8,
deleteOnTermination: props.removalPolicy === RemovalPolicy.DESTROY,
...(props.dataVolumeOptions ?? {}),
},
virtualName: "restate-data",
},
},
],
userData,
});

this.instance = restateInstance;

// We start the ADOT collector regardless, and only control whether they will be published to X-Ray via instance
Expand Down Expand Up @@ -222,7 +243,7 @@ export class SingleNodeRestateDeployment extends Construct implements IRestateEn
this.adminUrl = `https://${restateInstance.instancePublicDnsName}:${PUBLIC_ADMIN_PORT}`;
}

protected restateConfig(id: string, props: SingleNodeRestateProps) {
protected restateConfig(props: SingleNodeRestateProps) {
return (
props.restateConfigOverride ??
[
Expand Down Expand Up @@ -267,6 +288,33 @@ export class SingleNodeRestateDeployment extends Construct implements IRestateEn
);
}

protected mountDataVolumeScript() {
return `
if mount | grep -qs '/var/restate'; then
echo "/var/restate is mounted"
else
if [ -d /var/restate ]; then
if [ "$(ls -A /var/restate)" ]; then
echo "Data exists in /var/restate that is not on data volume; refusing to overwrite!"
exit 1
fi
else
mkdir /var/restate
fi
if file -sL ${DATA_DEVICE_NAME} | grep -q ': data$'; then
mkfs -t xfs ${DATA_DEVICE_NAME}
fi
mount ${DATA_DEVICE_NAME} /var/restate
if ! grep -qs '/var/restate' /etc/fstab; then
echo "${DATA_DEVICE_NAME} /var/restate xfs defaults 0 0" >> /etc/fstab
echo "Added entry for ${DATA_DEVICE_NAME} to /etc/fstab"
else
echo "Entry for ${DATA_DEVICE_NAME} already exists in /etc/fstab"
fi
fi
`;
}

/**
* @param props construct properties
* @returns nginx configuration to use for ingress reverse proxy, formatted as a multi-line string
Expand Down

0 comments on commit 1ed6be8

Please sign in to comment.