Skip to content

Commit

Permalink
Persistent Redis (#177)
Browse files Browse the repository at this point in the history
* Add ConfigMap for Persistent Redis Configuration

* Add initial changes needed

* Update snapshots

* i am but a servant to the great ol' Code Coverage

* Cleanup

* Snapshott

* Failing chart test :D

* Woooo

* the anti-power of eunsoo shin

* bet

* lol

* Better testing

* Abstract away configmap interface

* Update snapshot and naming conventions

* Update host path

* Update host path
  • Loading branch information
joyliu-q authored Oct 26, 2023
1 parent 05ba9d2 commit d014744
Show file tree
Hide file tree
Showing 24 changed files with 11,169 additions and 6,150 deletions.
2 changes: 1 addition & 1 deletion cdk/kittyhawk/.projenrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const project = new TypeScriptProject({
},
});

project.addFields({ ["version"]: "1.1.8" });
project.addFields({ ["version"]: "1.1.9" });
project.prettier?.ignoreFile?.addPatterns("src/imports");
project.testTask.steps.forEach((step) => {
if (step.exec) {
Expand Down
2 changes: 1 addition & 1 deletion cdk/kittyhawk/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cdk/kittyhawk/package.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

110 changes: 110 additions & 0 deletions cdk/kittyhawk/src/application/redis.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { Construct } from "constructs";
import { DeploymentProps } from "../deployment";
import {
KubeConfigMap,
KubePersistentVolume,
KubePersistentVolumeClaim,
Quantity,
} from "../imports/k8s";
import { Application } from "./base";

export interface RedisApplicationProps {
Expand All @@ -20,6 +26,19 @@ export interface RedisApplicationProps {
* serviceAccountName: release name
*/
readonly createServiceAccount?: boolean;

/**
* Persists data to a volume, using a ConfigMap to decide where to mount it.
*/
readonly persistData?: boolean;

/**
* Override the default redis ConfigMap configuration and creates a custom ConfigMap object.
*/
readonly redisConfigMap?: {
readonly name: string;
readonly config: string;
};
}

export class RedisApplication extends Application {
Expand All @@ -28,10 +47,101 @@ export class RedisApplication extends Application {
appname: string,
redisProps: RedisApplicationProps
) {
const CONFIG_MAP_NAME = "redis-config";
const releaseName = process.env.RELEASE_NAME || "undefined_release";

// Persistence constants
const storageClassName = `${releaseName}-${appname}-storage`;
const pvName = `${releaseName}-${appname}-pv`;
const pvcName = `${releaseName}-${appname}-pvc`;

if (redisProps.redisConfigMap) {
new KubeConfigMap(scope, redisProps.redisConfigMap.name, {
metadata: {
name: redisProps.redisConfigMap.name,
},
data: {
"redis-config": redisProps.redisConfigMap.config,
},
});
}

if (redisProps.persistData) {
new KubePersistentVolume(scope, pvName, {
metadata: {
name: pvName,
},
spec: {
storageClassName,
accessModes: ["ReadWriteMany"], // TODO: ask Redis folks
capacity: {
storage: Quantity.fromString("1Gi"),
},
hostPath: {
path: `/${releaseName}/redis`,
},
},
});
new KubePersistentVolumeClaim(scope, pvcName, {
metadata: {
name: pvcName,
},
spec: {
storageClassName,
accessModes: ["ReadWriteMany"], // TODO: ask Redis folks
resources: {
requests: {
storage: Quantity.fromString("1Gi"),
},
},
},
});
}

super(scope, appname, {
deployment: {
image: redisProps.deployment?.image ?? "redis",
tag: redisProps.deployment?.tag ?? "6.0",
volumeMounts: [
...(redisProps.persistData
? [
{
name: "data",
mountPath: "/redis-master-data",
},
{
name: "config",
mountPath: "/redis-master",
},
]
: []),
...(redisProps.deployment?.volumeMounts ?? []),
],
volumes: [
...(redisProps.persistData
? [
{
name: "data",
persistentVolumeClaim: {
claimName: pvcName,
},
},
{
name: "config",
configMap: {
name: redisProps.redisConfigMap?.name ?? CONFIG_MAP_NAME,
items: [
{
key: "redis-config",
path: "redis.conf",
},
],
},
},
]
: []),
...(redisProps.deployment?.volumes ?? []),
],
...redisProps.deployment,
},
port: redisProps.port ?? 6379,
Expand Down
23 changes: 18 additions & 5 deletions cdk/kittyhawk/src/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ export interface ContainerProps {
*/
readonly secretMounts?: VolumeMount[];

/**
* Volume mounts for deployment container.
*
* @default []
*/
readonly volumeMounts?: VolumeMount[];

/**
* Internal port.
*
Expand Down Expand Up @@ -165,10 +172,16 @@ export class Container implements ContainerInterface {
: [{ containerPort: props.port ?? 80 }];
this.imagePullPolicy = props.pullPolicy || "IfNotPresent";
this.command = props.cmd;
this.volumeMounts = props.secretMounts?.map((vm) => ({
...vm,
name: secretVolumeName(vm),
}));
this.volumeMounts = [
...(props.secretMounts?.map((vm) => ({
...vm,
name: secretVolumeName(vm),
})) ?? []),
...(props.volumeMounts || []),
];
if (this.volumeMounts.length === 0) {
this.volumeMounts = undefined;
}
this.envFrom = props.secret
? [{ secretRef: { name: props.secret } }]
: undefined;
Expand All @@ -180,7 +193,7 @@ export class Container implements ContainerInterface {
const secretVolumeName = (vm: VolumeMount) => {
const mountString = (a: string) => a.toLowerCase().split("_").join("-");
return `${mountString(vm.name)}${
vm.subPath && `-${mountString(vm.subPath)}`
vm.subPath ? `-${mountString(vm.subPath)}` : ""
}`;
};
export class SecretVolume implements VolumeInterface {
Expand Down
17 changes: 16 additions & 1 deletion cdk/kittyhawk/src/deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
KubeDeployment as DeploymentApiObject,
KubeServiceAccount,
VolumeMount,
Volume,
} from "./imports/k8s";
import { defaultChildName } from "./utils";

Expand All @@ -23,6 +24,20 @@ export interface DeploymentProps extends ContainerProps {
*/
readonly secretMounts?: VolumeMount[];

/**
* Volume mounts for deployment container.
*
* This appends to the existing list of volumes, if created by the `secretMounts` property.
*
* @default []
*/
readonly volumeMounts?: VolumeMount[];

/**
* Volume mounts for deployment container.
*/
readonly volumes?: Volume[];

/**
* The service account to be used to attach to any deployment pods.
* Default serviceAccountName: release name
Expand Down Expand Up @@ -64,7 +79,7 @@ export class Deployment extends Construct {
? { serviceAccountName: props.serviceAccount.name }
: {}),
containers: containers,
volumes: secretVolumes,
volumes: [...secretVolumes, ...(props.volumes || [])],
},
},
},
Expand Down
Loading

0 comments on commit d014744

Please sign in to comment.