Skip to content

Implementing CDK Pipelines for resource orchestration #293

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

Draft
wants to merge 25 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1a06e98
Removed petfood application
rapgaws Oct 29, 2024
031492d
Added self-mutating pipeline resources
rapgaws Oct 29, 2024
e2c4128
Added needed environment variables for Synth
rapgaws Oct 29, 2024
cca3e97
Added permissions for Synth operation
rapgaws Oct 30, 2024
1481d99
Added Service stage
rapgaws Oct 30, 2024
1b9f06e
Fixed output path for Synth
rapgaws Oct 30, 2024
f3e722b
Move Core network and ECR Repos to the initial stage
rapgaws Oct 30, 2024
30cdb2d
Reorg to create ECR Repos and build projects for each image as part o…
rapgaws Oct 31, 2024
6b6063a
Removed VPC from ImageBuild
rapgaws Oct 31, 2024
fea6c7d
Added ECR permissions to CodeBuild
rapgaws Oct 31, 2024
c37c385
Changed environment variable values source
rapgaws Oct 31, 2024
3a42e96
Removed VPC from Core Stack
rapgaws Oct 31, 2024
22eac8b
CfnOutput renamed for repositories
rapgaws Oct 31, 2024
6e2cf3b
Added base path for container build
rapgaws Oct 31, 2024
1481131
Added missing folder in container path
rapgaws Oct 31, 2024
85e09d1
Update additional Docker base images
rapgaws Oct 31, 2024
1375562
Removed extra folder on C# microservices
rapgaws Oct 31, 2024
af64d47
Added Services stack with local Container images
rapgaws Oct 31, 2024
9a65f76
Added Application Stack
rapgaws Oct 31, 2024
cbdc7cf
Fixed image URI
rapgaws Oct 31, 2024
9e4d255
Fixed error on image name
rapgaws Oct 31, 2024
3a99c96
Renamed pipeline
rapgaws Oct 31, 2024
36a7d2e
Simple test for configuration file
rapgaws Oct 31, 2024
65dbcd9
Set ECR as mutable to allow multiple runs.
rapgaws Oct 31, 2024
43a7e9c
Fixed X-Ray Group definition
rapgaws Oct 31, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions PetAdoptions/cdk/pet_stack/app/pet_stack.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
#!/usr/bin/env node
import 'source-map-support/register';
import { Services } from '../lib/services';
import { Applications } from '../lib/applications';
import { Services } from '../lib/stacks/services';
import { Applications } from '../lib/stacks/applications';
//import { EKSPetsite } from '../lib/ekspetsite'
import { App, Tags, Aspects } from 'aws-cdk-lib';
import { CDKPipeline } from '../lib/stacks/pipeline';
//import { AwsSolutionsChecks } from 'cdk-nag';


const stackName = "Services";
const app = new App();
const stackName = "OneObservabilityWorkshop";
const app = new App({
context: {
stackName: stackName
}
});

const stack = new Services(app, stackName, {
const pipelineStack = new CDKPipeline(app, "Pipeline", {
sourceBucketName: process.env.SOURCE_BUCKET_NAME!,
branchName: process.env.GITHUB_BRANCH || "main",
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION
}});
}
});

const applications = new Applications(app, "Applications", {
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION
}});

Tags.of(app).add("Workshop","true")
//Aspects.of(stack).add(new AwsSolutionsChecks({verbose: true}));
Expand Down
50 changes: 50 additions & 0 deletions PetAdoptions/cdk/pet_stack/lib/constructs/imageBuiltStep.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { PolicyStatement } from "aws-cdk-lib/aws-iam";
import { CodeBuildStep, CodePipelineSource } from "aws-cdk-lib/pipelines";

export interface ImageBuildStepProps {
repositoryName: string;
repositoryUri: string;
source: CodePipelineSource;
account: string;
region: string;
branchName: string;

}

export class ImageBuildStep extends CodeBuildStep {
constructor(name: string, props: ImageBuildStepProps) {
super(name, {
commands: [
'nohup /usr/local/bin/dockerd --host=unix:///var/run/docker.sock --host=tcp://127.0.0.1:2375 --storage-driver=overlay2 &',
'timeout 15 sh -c "until docker info; do echo .; sleep 1; done"',
'cd ${BASE_PATH}',
'aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com',
'docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .',
'docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG',
'docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG'
],
rolePolicyStatements: [
new PolicyStatement({
actions: [
'ecr:*',
],
resources: ['*'],
}),
],
input: props.source,
buildEnvironment: {
privileged: true
},
env: {
'AWS_ACCOUNT_ID': props.account,
'AWS_DEFAULT_REGION': props.region,
'IMAGE_TAG': "latest",
'ECR_REPOSITORY_URL': props.repositoryUri,
'IMAGE_REPO_NAME': props.repositoryName,
'BASE_PATH': `one-observability-demo-${props.branchName}/PetAdoptions/${props.repositoryName}`
}
});

this.consumedStackOutputs.push()
}
}
69 changes: 69 additions & 0 deletions PetAdoptions/cdk/pet_stack/lib/constructs/network.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { Construct } from "constructs";
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as logs from 'aws-cdk-lib/aws-logs';
import * as iam from 'aws-cdk-lib/aws-iam';

export interface WorkshopNetworkProps {
name: string;
cidrRange: string;
}

export class WorkshopNetwork extends Construct {
public readonly vpc : ec2.Vpc;
constructor(scope: Construct, id: string, props: WorkshopNetworkProps) {
super(scope, id);

// Create a VPC with public and private subnets
// The VPC where all the microservices will be deployed into
this.vpc = new ec2.Vpc(this, 'VPC-' + props.name, {
ipAddresses: ec2.IpAddresses.cidr(props.cidrRange),
natGateways: 1,
maxAzs: 2
});

const flowLogGroup = new logs.LogGroup(this, 'FlowLogGroup', {
logGroupName: '/aws/vpcflowlogs/' + this.vpc.vpcId,
retention: logs.RetentionDays.ONE_WEEK
});

const role = new iam.Role(this, 'VPCFlowLogRole', {
assumedBy: new iam.ServicePrincipal('vpc-flow-logs.amazonaws.com')
});

const flowLog = new ec2.FlowLog(this, 'VPCFlowLog', {
destination: ec2.FlowLogDestination.toCloudWatchLogs(flowLogGroup, role),
resourceType: ec2.FlowLogResourceType.fromVpc(this.vpc),
logFormat: [
ec2.LogFormat.ACCOUNT_ID,
ec2.LogFormat.ACTION,
ec2.LogFormat.AZ_ID,
ec2.LogFormat.BYTES,
ec2.LogFormat.DST_ADDR,
ec2.LogFormat.DST_PORT,
ec2.LogFormat.END_TIMESTAMP,
ec2.LogFormat.FLOW_DIRECTION,
ec2.LogFormat.INSTANCE_ID,
ec2.LogFormat.INTERFACE_ID,
ec2.LogFormat.LOG_STATUS,
ec2.LogFormat.PACKETS,
ec2.LogFormat.PKT_DST_AWS_SERVICE,
ec2.LogFormat.PKT_DST_ADDR,
ec2.LogFormat.PKT_SRC_AWS_SERVICE,
ec2.LogFormat.PKT_SRC_ADDR,
ec2.LogFormat.PROTOCOL,
ec2.LogFormat.REGION,
ec2.LogFormat.SRC_ADDR,
ec2.LogFormat.SRC_PORT,
ec2.LogFormat.START_TIMESTAMP,
ec2.LogFormat.SUBLOCATION_ID,
ec2.LogFormat.SUBLOCATION_TYPE,
ec2.LogFormat.SUBNET_ID,
ec2.LogFormat.TCP_FLAGS,
ec2.LogFormat.TRAFFIC_PATH,
ec2.LogFormat.TRAFFIC_TYPE,
ec2.LogFormat.VERSION,
ec2.LogFormat.VPC_ID
]
});
}
}
36 changes: 36 additions & 0 deletions PetAdoptions/cdk/pet_stack/lib/constructs/repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { RemovalPolicy, Stack } from 'aws-cdk-lib';
import { Construct } from "constructs";
import * as ecr from "aws-cdk-lib/aws-ecr";
import * as iam from "aws-cdk-lib/aws-iam";
import { NagSuppressions } from 'cdk-nag';
import { CodeBuildStep } from 'aws-cdk-lib/pipelines';

export interface RepositoryProps {
name: string;
enableScanOnPush: boolean;
initialCodePath: string;
}


export class Repository extends Construct {
public readonly imageRepo: ecr.Repository
public readonly codeBuildStep: CodeBuildStep;

constructor(scope: Construct, id: string, props: RepositoryProps) {
super(scope, id);

this.imageRepo = new ecr.Repository(scope, props.name + "ImageRepo", {
repositoryName: props.name,
imageScanOnPush: props.enableScanOnPush,
imageTagMutability: ecr.TagMutability.IMMUTABLE,
removalPolicy: RemovalPolicy.DESTROY,
encryption: ecr.RepositoryEncryption.AES_256,
autoDeleteImages: true
});

}

public getECRUri() {
return this.imageRepo.repositoryUri;
}
}
20 changes: 20 additions & 0 deletions PetAdoptions/cdk/pet_stack/lib/coreStage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Stage, StageProps } from "aws-cdk-lib";
import { Construct } from "constructs";
import { CoreStack } from "./stacks/core";

export class CoreStage extends Stage {
public readonly repoList = new Map<string, string>();
constructor(scope: Construct, id: string, props: StageProps) {
super(scope, id, props);

const stackName = "WorkshopCore";
const coreStack = new CoreStack(this, stackName, {
env: {
account: props.env?.account,
region: props.env?.region
},
});

this.repoList = coreStack.repoList;
}
}
39 changes: 0 additions & 39 deletions PetAdoptions/cdk/pet_stack/lib/modules/core/cloud9.ts

This file was deleted.

16 changes: 16 additions & 0 deletions PetAdoptions/cdk/pet_stack/lib/servicesStage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Stage, StageProps } from "aws-cdk-lib";
import { Construct } from "constructs";
import { Services } from "./stacks/services";

export class ServiceStage extends Stage {
constructor(scope: Construct, id: string, props: StageProps) {
super(scope, id, props);

const stackName = "Services";
const stack = new Services(this, stackName, {
env: {
account: props.env?.account,
region: props.env?.region
}});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import * as yaml from 'js-yaml';
import { Stack, StackProps, CfnJson, Fn, CfnOutput } from 'aws-cdk-lib';
import { readFileSync } from 'fs';
import { Construct } from 'constructs'
import { ContainerImageBuilderProps, ContainerImageBuilder } from './common/container-image-builder'
import { PetAdoptionsHistory } from './applications/pet-adoptions-history-application'
import { ContainerImageBuilderProps, ContainerImageBuilder } from '../common/container-image-builder'
import { PetAdoptionsHistory } from '../applications/pet-adoptions-history-application'

export class Applications extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
Expand Down
74 changes: 74 additions & 0 deletions PetAdoptions/cdk/pet_stack/lib/stacks/core.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { Aspects, CfnOutput, Stack, StackProps, Tags } from 'aws-cdk-lib';
import { WorkshopNetwork } from '../constructs/network';
import { AwsSolutionsChecks, NagSuppressions } from "cdk-nag";
import { Construct } from 'constructs';
import * as fs from 'fs';
import path = require('path');
import { Repository } from '../constructs/repository';


export class CoreStack extends Stack {
public readonly repoList = new Map<string, string>();
constructor(scope: Construct, id: string, props: StackProps) {
super(scope, id, props);

// Suppressions for the Core Stack
NagSuppressions.addStackSuppressions(this, [
{ id: "AwsSolutions-IAM4", reason: "Stack level suppression, managed policies are aceptable in this workshop."}
])

const repoFolders = __dirname + "/../../resources/microservices";
const repositories = fs.readdirSync(repoFolders);
const basePath = path.resolve(repoFolders);

repositories.forEach(container => {

const repo = new Repository(this, container, {
name: container,
enableScanOnPush: true,
initialCodePath: basePath + "/" + container,
});


this.repoList.set(container, repo.getECRUri());
});

this.repoList.forEach((value, key) => {
new CfnOutput(this, key + "Uri", { value: value })
})

Tags.of(this).add("Workshop","true")
Tags.of(this).add("ModularVersioning","true")
Aspects.of(this).add(new AwsSolutionsChecks({verbose: true}));

function createOuputs(scope: Construct ,params: Map<string, string>) {
params.forEach((value, key) => {
new CfnOutput(scope, key, { value: value })
});
}

// // Stack Level suppressions (TODO: move to the construct if possible)
// NagSuppressions.addResourceSuppressionsByPath(this,
// [
// "/" + id + "/@aws-cdk--aws-eks.ClusterResourceProvider",
// "/" + id + "/@aws-cdk--aws-eks.KubectlProvider"
// ],
// [
// {
// id: "AwsSolutions-IAM5",
// reason: "Creation role is created by the EKS cluster."
// },
// {
// id: "AwsSolutions-IAM4",
// reason: "Managed policy created by the default cdk construct",
// },
// {
// id: "AwsSolutions-L1",
// reason: "Lambda is created inside of the cdk eks module"
// }
// ],
// true
// );

}
}
Loading