Skip to content

Commit

Permalink
Merge pull request #1051 from bugathagit/ipv6
Browse files Browse the repository at this point in the history
IPv6
  • Loading branch information
shapirov103 authored Aug 26, 2024
2 parents 0d46b45 + 69e7c00 commit 1058f59
Show file tree
Hide file tree
Showing 17 changed files with 617 additions and 80 deletions.
63 changes: 58 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ cdk init app --language typescript
cdk bootstrap aws://<AWS_ACCOUNT_ID>/<AWS_REGION>
```

### Usage
### Usage for IPv4 cluster

Run the following command to install the `eks-blueprints` dependency in your project.
Run the following command to install the `eks-blueprints` dependency in your project. By default, blueprints creates IPv4 cluster.

```sh
npm i @aws-quickstart/eks-blueprints
Expand Down Expand Up @@ -109,18 +109,71 @@ const stack = blueprints.EksBlueprint.builder()
.account(account)
.region(region)
.addOns(...addOns)
.build(app, 'eks-blueprint');
.build(app, 'eks-blueprint-ipv4');
// do something with stack or drop this variable
```


### Usage for IPv6 cluster

Run the following command to install the `eks-blueprints` dependency in your project. This example creates Ipv6 cluster.

#### Note: ipFamily has been introduced to support ipv6 cluster.

At time of creation, if VPC is not provided to EKS blueprints. It will automatically divide the provided VPC CIDR range, and create public and private subnets per Availability Zone.
Network routing for the public subnets will be configured to allow outbound access directly via an Internet Gateway.
Network routing for the private subnets will be configured to allow outbound access via a one NAT Gateway to reduce the cost.
IPv6 does not require NAT for pod to pod communication. By default, we are creating one NAT for cluster communications outside endpoints if any.

```typescript
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import * as blueprints from '@aws-quickstart/eks-blueprints';

const app = new cdk.App();

// AddOns for the cluster. For ipv6 cluster, we haven't tested with all the addons except for the below addons.
const addOns: Array<blueprints.ClusterAddOn> = [
new blueprints.addons.VpcCniAddOn(),
new blueprints.addons.KarpenterAddOn(),
new blueprints.addons.SecretsStoreAddOn()
];

const account = 'XXXXXXXXXXXXX';
const region = 'us-east-2';
const ipFamily = IpFamily.IP_V6; //IpFamily.IP_V6 isquavelent to "ipv6"

const stack = blueprints.EksBlueprint.builder()
.account(account)
.region(region)
.ipFamily(ipFamily)
.addOns(...addOns)
.build(app, 'eks-blueprint-ipv6');

```

Note: if the account/region combination used in the code example above is different from the initial combination used with `cdk bootstrap`, you will need to perform `cdk bootstrap` again to avoid error.

Please reference [CDK](https://docs.aws.amazon.com/cdk/latest/guide/home.html) usage doc for detail.

Deploy the stack using the following command
List the stacks using the following command

```sh
cdk deploy
cdk list
```
Example output for `cdk list`:
```sh
eks-blueprint-ipv4
eks-blueprint-ipv6
```

Deploy the stack using the following command
```sh
cdk deploy <stack-name>
```
Example to deploy IPv6 cluster:
```sh
cdk deploy eks-blueprint-ipv6
```

This will provision the following:
Expand Down
11 changes: 8 additions & 3 deletions bin/main.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import BlueprintConstruct from '../examples/blueprint-construct';
import BlueprintIPV6Construct from '../examples/blueprint-ipv6-construct';
import BlueprintIPv4Construct from "../examples/blueprint-ipv4-construct";

const app = new cdk.App();

const account = process.env.CDK_DEFAULT_ACCOUNT;
const region = process.env.CDK_DEFAULT_REGION;
const props = { env: { account, region } };
let props = { env: { account, region } };
new BlueprintIPv4Construct(app, props);

new BlueprintConstruct(app, props);
// Deploying IPV6 cluster in us-east-2 region. Assuming IPV4 cluster will be deployed to another region.
props = { env: { account, region: "us-east-2" } };
// Create ipv6 cluster
new BlueprintIPV6Construct(app, props);
120 changes: 63 additions & 57 deletions examples/blueprint-construct/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import * as blueprints from '../../lib';
import { logger, userLog } from '../../lib/utils';
import * as team from '../teams';
import { CfnWorkspace } from 'aws-cdk-lib/aws-aps';
import {
CreateEfsFileSystemProvider,
CreateRoleProvider,
CreateS3BucketProvider,
GenericClusterProvider, ManagedNodeGroup
} from "../../lib";

const burnhamManifestDir = './examples/teams/team-burnham/';
const rikerManifestDir = './examples/teams/team-riker/';
Expand All @@ -22,45 +28,58 @@ export interface BlueprintConstructProps {
}

export default class BlueprintConstruct {
teams: Array<blueprints.Team>;
nodeRole: CreateRoleProvider;
ampWorkspaceName: string;
ampWorkspace: CfnWorkspace;
apacheAirflowS3Bucket: CreateS3BucketProvider;
apacheAirflowEfs: CreateEfsFileSystemProvider;
addOns: Array<blueprints.ClusterAddOn>;
clusterProvider: GenericClusterProvider;
dataTeam: blueprints.EmrEksTeamProps;
batchTeam: blueprints.BatchEksTeamProps;
nodeClassSpec: blueprints.Ec2NodeClassSpec;
nodePoolSpec: blueprints.NodePoolSpec;


constructor(scope: Construct, props: cdk.StackProps) {

blueprints.HelmAddOn.validateHelmVersions = true;
blueprints.HelmAddOn.failOnVersionValidation = false;
logger.settings.minLevel = 3; // info
userLog.settings.minLevel = 2; // debug

const teams: Array<blueprints.Team> = [
this.teams = [
new team.TeamTroi,
new team.TeamRiker(scope, teamManifestDirList[1]),
new team.TeamBurnham(scope, teamManifestDirList[0]),
new team.TeamPlatform(process.env.CDK_DEFAULT_ACCOUNT!)
];

const nodeRole = new blueprints.CreateRoleProvider("blueprint-node-role", new iam.ServicePrincipal("ec2.amazonaws.com"),
[
iam.ManagedPolicy.fromAwsManagedPolicyName("AmazonEKSWorkerNodePolicy"),
iam.ManagedPolicy.fromAwsManagedPolicyName("AmazonEC2ContainerRegistryReadOnly"),
iam.ManagedPolicy.fromAwsManagedPolicyName("AmazonSSMManagedInstanceCore")
]);
this.nodeRole = new blueprints.CreateRoleProvider("blueprint-node-role", new iam.ServicePrincipal("ec2.amazonaws.com"),
[
iam.ManagedPolicy.fromAwsManagedPolicyName("AmazonEKSWorkerNodePolicy"),
iam.ManagedPolicy.fromAwsManagedPolicyName("AmazonEC2ContainerRegistryReadOnly"),
iam.ManagedPolicy.fromAwsManagedPolicyName("AmazonSSMManagedInstanceCore")
]);

const ampWorkspaceName = "blueprints-amp-workspace";
const ampWorkspace: CfnWorkspace = blueprints.getNamedResource(ampWorkspaceName);
this.ampWorkspaceName = "blueprints-amp-workspace";
this.ampWorkspace = blueprints.getNamedResource(this.ampWorkspaceName);

const apacheAirflowS3Bucket = new blueprints.CreateS3BucketProvider({
this.apacheAirflowS3Bucket = new blueprints.CreateS3BucketProvider({
id: 'apache-airflow-s3-bucket-id',
s3BucketProps: { removalPolicy: cdk.RemovalPolicy.DESTROY }
});
const apacheAirflowEfs = new blueprints.CreateEfsFileSystemProvider({
this.apacheAirflowEfs = new blueprints.CreateEfsFileSystemProvider({
name: 'blueprints-apache-airflow-efs',
});

const nodeClassSpec: blueprints.Ec2NodeClassSpec = {
this.nodeClassSpec = {
amiFamily: "AL2",
subnetSelectorTerms: [{ tags: { "Name": `${blueprintID}/${blueprintID}-vpc/PrivateSubnet*` }}],
securityGroupSelectorTerms: [{ tags: { "aws:eks:cluster-name": `${blueprintID}` }}],
};

const nodePoolSpec: blueprints.NodePoolSpec = {
this.nodePoolSpec = {
labels: {
type: "karpenter-test"
},
Expand All @@ -85,7 +104,7 @@ export default class BlueprintConstruct {
}
};

const addOns: Array<blueprints.ClusterAddOn> = [
this.addOns = [
new blueprints.KubeRayAddOn(),
new blueprints.addons.AwsLoadBalancerControllerAddOn(),
new blueprints.addons.AppMeshAddOn(),
Expand All @@ -98,7 +117,7 @@ export default class BlueprintConstruct {
version: 'auto'
}),
new blueprints.addons.AmpAddOn({
ampPrometheusEndpoint: ampWorkspace.attrPrometheusEndpoint,
ampPrometheusEndpoint: this.ampWorkspace.attrPrometheusEndpoint,
namespace: 'adot'
}),
new blueprints.addons.XrayAdotAddOn({
Expand Down Expand Up @@ -148,8 +167,8 @@ export default class BlueprintConstruct {
}),
new blueprints.addons.KarpenterAddOn({
version: "v0.33.2",
nodePoolSpec: nodePoolSpec,
ec2NodeClassSpec: nodeClassSpec,
nodePoolSpec: this.nodePoolSpec,
ec2NodeClassSpec: this.nodeClassSpec,
interruptionHandling: true,
}),
new blueprints.addons.AwsNodeTerminationHandlerAddOn(),
Expand Down Expand Up @@ -247,22 +266,12 @@ export default class BlueprintConstruct {
hostedZoneResources: [ blueprints.GlobalResources.HostedZone ]
});

const clusterProvider = new blueprints.GenericClusterProvider({
version: KubernetesVersion.V1_29,
tags: {
"Name": "blueprints-example-cluster",
"Type": "generic-cluster"
},
mastersRole: blueprints.getResource(context => {
return new iam.Role(context.scope, 'AdminRole', { assumedBy: new iam.AccountRootPrincipal() });
}),
managedNodeGroups: [
addGenericNodeGroup(),
addCustomNodeGroup(),
addWindowsNodeGroup(), // commented out to check the impact on e2e
addGpuNodeGroup()
]
});
this.clusterProvider = getClusterProvider([
addGenericNodeGroup(),
addCustomNodeGroup(),
addWindowsNodeGroup(), // commented out to check the impact on e2e
addGpuNodeGroup()
]);

const executionRolePolicyStatement:iam. PolicyStatement [] = [
new iam.PolicyStatement({
Expand All @@ -281,7 +290,7 @@ export default class BlueprintConstruct {
}),
];

const dataTeam: blueprints.EmrEksTeamProps = {
this.dataTeam = {
name:'dataTeam',
virtualClusterName: 'batchJob',
virtualClusterNamespace: 'batchjob',
Expand All @@ -294,7 +303,7 @@ export default class BlueprintConstruct {
]
};

const batchTeam: blueprints.BatchEksTeamProps = {
this.batchTeam = {
name: 'batch-a',
namespace: 'aws-batch',
envName: 'batch-a-comp-env',
Expand All @@ -308,27 +317,24 @@ export default class BlueprintConstruct {
},
jobQueueName: 'team-a-job-queue',
};

blueprints.EksBlueprint.builder()
.addOns(...addOns)
.resourceProvider(blueprints.GlobalResources.Vpc, new blueprints.VpcProvider(undefined, {
primaryCidr: "10.2.0.0/16",
secondaryCidr: "100.64.0.0/16",
secondarySubnetCidrs: ["100.64.0.0/24","100.64.1.0/24","100.64.2.0/24"]
}))
.resourceProvider("node-role", nodeRole)
.resourceProvider('apache-airflow-s3-bucket-provider', apacheAirflowS3Bucket)
.resourceProvider('apache-airflow-efs-provider', apacheAirflowEfs)
.clusterProvider(clusterProvider)
.resourceProvider(ampWorkspaceName, new blueprints.CreateAmpProvider(ampWorkspaceName, ampWorkspaceName))
.teams(...teams, new blueprints.EmrEksTeam(dataTeam), new blueprints.BatchEksTeam(batchTeam))
.enableControlPlaneLogTypes(blueprints.ControlPlaneLogType.API)
.build(scope, blueprintID, props);

}
}

function addGenericNodeGroup(): blueprints.ManagedNodeGroup {
export function getClusterProvider(managedNodeGroups: ManagedNodeGroup[]){
return new blueprints.GenericClusterProvider({
version: KubernetesVersion.V1_29,
tags: {
"Name": "blueprints-example-cluster",
"Type": "generic-cluster"
},
mastersRole: blueprints.getResource(context => {
return new iam.Role(context.scope, 'AdminRole', { assumedBy: new iam.AccountRootPrincipal() });
}),
managedNodeGroups: managedNodeGroups
});
}

export function addGenericNodeGroup(): blueprints.ManagedNodeGroup {

return {
id: "mng1",
Expand All @@ -351,7 +357,7 @@ function addGenericNodeGroup(): blueprints.ManagedNodeGroup {
};
}

function addCustomNodeGroup(): blueprints.ManagedNodeGroup {
export function addCustomNodeGroup(): blueprints.ManagedNodeGroup {

const userData = ec2.UserData.forLinux();
userData.addCommands(`/etc/eks/bootstrap.sh ${blueprintID}`);
Expand Down Expand Up @@ -385,7 +391,7 @@ function addCustomNodeGroup(): blueprints.ManagedNodeGroup {
};
}

function addWindowsNodeGroup(): blueprints.ManagedNodeGroup {
export function addWindowsNodeGroup(): blueprints.ManagedNodeGroup {

return {
id: "mng3-windowsami",
Expand All @@ -404,7 +410,7 @@ function addWindowsNodeGroup(): blueprints.ManagedNodeGroup {
};
}

function addGpuNodeGroup(): blueprints.ManagedNodeGroup {
export function addGpuNodeGroup(): blueprints.ManagedNodeGroup {

return {
id: "mng-linux-gpu",
Expand Down
37 changes: 37 additions & 0 deletions examples/blueprint-ipv4-construct/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as cdk from 'aws-cdk-lib';
import { Construct } from "constructs";
import * as blueprints from '../../lib';
import BlueprintConstruct from "../blueprint-construct";

const blueprintID = 'blueprint-construct-dev';

export interface BlueprintConstructProps {
/**
* Id
*/
id: string
}

export default class BlueprintIPv4Construct extends BlueprintConstruct {
constructor(scope: Construct, props: cdk.StackProps) {
super(scope, props);

blueprints.EksBlueprint.builder()
.addOns(...this.addOns)
.resourceProvider(blueprints.GlobalResources.Vpc, new blueprints.VpcProvider(undefined, {
primaryCidr: "10.2.0.0/16",
secondaryCidr: "100.64.0.0/16",
secondarySubnetCidrs: ["100.64.0.0/24","100.64.1.0/24","100.64.2.0/24"]
}))
.resourceProvider("node-role", this.nodeRole)
.resourceProvider('apache-airflow-s3-bucket-provider', this.apacheAirflowS3Bucket)
.resourceProvider('apache-airflow-efs-provider', this.apacheAirflowEfs)
.clusterProvider(this.clusterProvider)
.resourceProvider(this.ampWorkspaceName, new blueprints.CreateAmpProvider(this.ampWorkspaceName, this.ampWorkspaceName))
.teams(...this.teams, new blueprints.EmrEksTeam(this.dataTeam), new blueprints.BatchEksTeam(this.batchTeam))
.enableControlPlaneLogTypes(blueprints.ControlPlaneLogType.API)
.build(scope, blueprintID, props);

}
}

Loading

0 comments on commit 1058f59

Please sign in to comment.