Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resource deployment #5

Open
wants to merge 13 commits into
base: deployingclusterbranch
Choose a base branch
from
92 changes: 79 additions & 13 deletions cdk_framework/EKS/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,34 @@ Since the code base in written in TypeScript, the CDK library has to be download
2. Download from EKS directory the AWS CDK Library by typing `npm install aws-cdk-lib`.
3. In order to use the linter, the eslint dependency needs to be downloaded. This could be done by calling `npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin`.

### Environemnt Variables
### Environment Variables

There are a number of environment variables that should be defined before deploying the clusters:

* `CDK_CONFIG_PATH` - This is the path for which the cluster configuration file is located - default is `clusters.yml` in `lib/config/cluster-config` folder.
* `CDK_CONFIG_PATH` - The path for the cluster configuration file - default is `clusters.yml` in `lib/config/cluster-config` folder.
* `REGION` - This is the region for which the clusters should be deployed - default is `us-west-2`.

### Setting Config File
In order to deploy resources onto the clusters the following environment variables must be set:

Sample template of what config file looks like could be seen in the YAML files found in `lib/config` folder. Should create a category called `clusters`, where each desired cluster should be configured. The name of the cluster given should be the key name for each cluster. Then, there are a couple of fields that need to be addressed:
* `CDK_EKS_RESOURCE_DEPLOY` - Must be set to value "true" in order for resource deployment to take place. Any other value or leaving it unset results in resources not being deployed.
* `TESTCASE_CONFIG_PATH` - The path for the test case configuration file - no default.

### Defining Config Files

The framework involves two configuration files, one pertaining to cluster deployment and the other pertaining to resource deployment.

#### Cluster Config

The YAML must have a root key called `clusters` under which all of the desired cluster should be configured and have the following structure:

* `clusters`:
* `launch_type` - choose either `ec2` or `fargate` subcategory - can't be both. Determines the launch type for the cluster to be deployed. This will act as the key to another list.
* `ec2_instance` - This is the the CPU Architecture for `ec2` launch types. It is only useful information for `ec2` key. If the `launch_type` is `fargate`, then nothing will happen by providing an `ec2_instance`. The options are `m6g`, `t4g`, amd `m5`, otherwise, an error will be thrown. There can’t be any other characters. It is case insensitive.
* `node_size` - This determines the size of the cpu architecture (memory, vCPUs, etc). It is only useful information for `ec2` key. If the key is `fargate` nothing will happen by providing the `node_size`. The list of compatible sizes could be found here: [Compatible Node Sizes](https://www.amazonaws.cn/en/ec2/instance-types/). It is case insensitive.
* `version` - Kubernetes Version. Supported Kubernetes versions are any versions between 1.18-1.21. This can be seen at [KubernetesVersion API](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_eks.KubernetesVersion.html). Additionally, specifying patch releases isn't an option as the CDK doesn't support it. Therefore, every input value must be the minor version.
* `clusterName`: - This key should be set to the desired name for the cluster.
* `launch_type` - choose either `ec2` or `fargate` subcategory - can't be both. Determines the launch type for the cluster to be deployed. This will act as the key to another list.
* `ec2_instance` - This is the the CPU Architecture for `ec2` launch types. It is only useful information for `ec2` key. If the `launch_type` is `fargate`, then nothing will happen by providing an `ec2_instance`. The options are `m6g`, `t4g`, amd `m5`, otherwise, an error will be thrown. There can’t be any other characters. It is case insensitive.
* `node_size` - This determines the size of the cpu architecture (memory, vCPUs, etc). It is only useful information for `ec2` key. If the key is `fargate` nothing will happen by providing the `node_size`. The list of compatible sizes could be found here: [Compatible Node Sizes](https://www.amazonaws.cn/en/ec2/instance-types/). It is case insensitive.
* `version` - Kubernetes Version. Supported Kubernetes versions are any versions between 1.18-1.21. This can be seen at [KubernetesVersion API](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_eks.KubernetesVersion.html). Additionally, specifying patch releases isn't an option as the CDK doesn't support it. Therefore, every input value must be the minor version.

Here is a sample configuration file example:
Here is a an example of a cluster configuration file:
```
---
clusters:
Expand All @@ -68,12 +78,68 @@ clusters:
```

There are three different clusters being deployed in this example - amdCluster, fargateCluster, and t4gCluster. There are only 2 fields for each cluster - `launch_type` and `version`. Then, in `launch_type`, either `ec2` or `fargate` is specified. If `fargate` is specified, then it should be left empty as shown above. If `ec2` is specified, then both `ec2_instance` and `node_size` should be defined.


### Deploying clusters
A sample template of a cluster config file can be found in the `lib/config/cluster_config` folder.

#### Test Case Config

The YAML must have a root key called `test_case` under which the test case should be configured and have the following structure:

* `test_case`:
* `cluster_name` - The name of the cluster onto which the resources should be deployed. Must match the name of a cluster in the configuration file that has either been deployed or will be deployed upon running the test case.
* `sample_app_image_uri` - The URI of the sample app image that should be used for this test case.
* `sample_app_mode` - The mode of the sample app: must be either `push` or `pull`.
* `collector_config` - The configuration that should be used for the collector deployment for this test case. The configuration should correspond with the type of sample app that is being used.

Here is an example of a test case configuration file:
```
---
test_case:
cluster_name: amdCluster
sample_app_image_uri: "public.ecr.aws/aws-otel-test/aws-otel-java-spark:latest"
sample_app_mode: push
collector_config:
extensions:
health_check:

receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318

processors:
batch/traces:
timeout: 1s
send_batch_size: 50
batch/metrics:
timeout: 60s

exporters:
logging:

service:
pipelines:
traces:
receivers: [otlp]
processors: [batch/traces]
exporters: [logging]
metrics:
receivers: [otlp]
processors: [batch/metrics]
exporters: [logging]

extensions: [health_check]
```

Sample templates of test case config files can be found in the `lib/config/test_case_config` folder.

### Deployment

1. Call `cdk synth` to synthesize the clusters to be deployed. This also makes sure everything was configured properly.
2. Call `cdk deploy --all` to dpeloy all the clusters. You could specify the cluster to deploy by the name calling `cdk deploy CLUSTERNAME`. CLUSTERNAME is the name of the cluster you passed in.
1. Set the environment variables (listed [here](#environment-variables)) to their desired values.
2. Call `cdk deploy --all` to deploy all the clusters specified in the configuration file. You could specify a specific cluster to deploy by calling `cdk deploy CLUSTERNAME` where CLUSTERNAME is the name of the cluster as set in the configuration file.

#### Makefile

Expand Down
11 changes: 6 additions & 5 deletions cdk_framework/EKS/lib/app.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { ClusterStack } from './stacks/cluster-stack';
import { deployClusters } from './cluster-deployment';
import { deployResources } from './resource-deployment';

const app = new cdk.App();

let clusterMap = new Map<string, ClusterStack>()

clusterMap = deployClusters(app);

const clusterStackMap = deployClusters(app);

// resource deployment
if (process.env.CDK_EKS_RESOURCE_DEPLOY == 'true') {
deployResources(clusterStackMap)
}
2 changes: 1 addition & 1 deletion cdk_framework/EKS/lib/cluster-deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const yaml = require('js-yaml')
export function deployClusters(app: cdk.App) : Map<string, ClusterStack> {
const REGION = process.env.REGION || 'us-west-2'

const route = process.env.CDK_CONFIG_PATH || __dirname + '/config/cluster-config/clusters.yml';
const route = process.env.CDK_CONFIG_PATH || __dirname + '/config/cluster_config/clusters.yml';

if (!/(.yml|.yaml)$/.test(route)){
throw new Error ('Path for cluster configuration must be to a yaml file')
Expand Down
18 changes: 0 additions & 18 deletions cdk_framework/EKS/lib/config/cluster-config/clusters.yml

This file was deleted.

18 changes: 18 additions & 0 deletions cdk_framework/EKS/lib/config/cluster_config/clusters.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
clusters:
amdCluster:
launch_type:
ec2:
ec2_instance: m5
node_size: large
version: 1.21
# fargateCluster:
# launch_type:
# fargate:
# version: 1.21
# t4gCluster:
# launch_type:
# ec2:
# ec2_instance: t4g
# node_size: large
# version: 1.21
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
test_case:
cluster_name: amdCluster
sample_app_image_uri: "public.ecr.aws/aws-otel-test/prometheus-sample-app:latest"
sample_app_mode: pull
collector_config:
receivers:
prometheus:
config:
global:
scrape_interval: 15s
scrape_configs:
- job_name: "test-prometheus-sample-app"
static_configs:
- targets: [ sample-app-service:8080 ]

exporters:
logging:
logLevel: debug
awsemf:
log_group_name: 'PrometheusSampleLogGroup'
log_stream_name: 'PrometheusSampleLogStream'
namespace: 'PrometheusSampleAppMetricNS'
dimension_rollup_option: 1

service:
pipelines:
metrics:
receivers: [prometheus]
exporters: [logging, awsemf]
telemetry:
logs:
level: debug
14 changes: 12 additions & 2 deletions cdk_framework/EKS/lib/config/test_case_config/spark-test-case.yml
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
---
testcase:
test_case:
cluster_name: amdCluster
sample_app_image_uri: "public.ecr.aws/aws-otel-test/aws-otel-java-spark:latest"
sample_app_mode: push
collector_config:
extensions:
health_check:

receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318

processors:
batch/traces:
timeout: 1s
send_batch_size: 50
batch/metrics:
timeout: 60s

exporters:
logging:
logLevel: debug
awsemf:
log_group_name: 'SparkSampleLogGroup'
log_stream_name: 'SparkSampleLogStream'
namespace: 'SparkSampleAppMetricNS'
dimension_rollup_option: 1

service:
pipelines:
traces:
Expand All @@ -31,5 +40,6 @@ testcase:
metrics:
receivers: [otlp]
processors: [batch/metrics]
exporters: [logging]
exporters: [logging, awsemf]

extensions: [health_check]
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface TestCaseConfigInterface {
cluster_name: string
sample_app_image_uri: string
sample_app_mode: string
collector_config: string
}
49 changes: 49 additions & 0 deletions cdk_framework/EKS/lib/resource-deployment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import 'source-map-support/register';
import { ClusterStack } from './stacks/cluster-stack';
import { TestCaseConfigInterface } from './interfaces/test-case-config-interface';
import { validateTestCaseConfig } from './utils/validate-test-case-config';
import { readFileSync } from 'fs';
const yaml = require('js-yaml')
import { TestCaseResourceDeploymentConstruct } from './resource_constructs/general_constructs/test-case-resource-deployment-construct';


export function deployResources(clusterStackMap: Map <string, ClusterStack>) {
const region = process.env.REGION || 'us-west-2'

// load the file
const testcaseConfigRoute = process.env.TESTCASE_CONFIG_PATH
// if no testcase config path is provided, throw error
if (testcaseConfigRoute == undefined){
throw new Error ('No path provided for testcase configuration')
}
// if testcase config path doesn't route to a yaml file, throw error
if (!/(.yml|.yaml)$/.test(testcaseConfigRoute)){
throw new Error ('Path for testcase configuration must be to a yaml file')
}

// load the data from the file
const raw = readFileSync(testcaseConfigRoute, {encoding: 'utf-8'})
const data = yaml.load(raw)
if (!data['test_case']) {
throw new Error('No root test_case field in the yaml file')
}
const testCaseConfig = data['test_case'] as TestCaseConfigInterface

// validate the configuration
validateTestCaseConfig(testCaseConfig, clusterStackMap)

const clusterStack = clusterStackMap.get(testCaseConfig['cluster_name'])
// This was already checked in the validation function but needs to be checked again
// to avoid compilation errors
if (clusterStack == undefined) {
throw Error('Cluster name "' + testCaseConfig['cluster_name'] + '" does not reference an existing cluster')
}

new TestCaseResourceDeploymentConstruct(clusterStack, 'test-case-resource-deployment-construct', {
cluster: clusterStack.cluster,
sampleAppImageURI: testCaseConfig['sample_app_image_uri'],
sampleAppMode: testCaseConfig['sample_app_mode'],
region: region,
collectorConfig: testCaseConfig['collector_config']
})
}
Loading