-
Notifications
You must be signed in to change notification settings - Fork 2
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
PoC Deployment in Corporate IT Infrastructure #1039
Comments
After some time working with ChatGPT o1-preview, here's something that looks viable potentially. This is for Strapi, not VizHub, but gives a sense of what's possible: ChatGPT output below: Deploying Strapi to AWS ECS with CDK (TypeScript) and Continuous Deployment via CodePipeline Introduction This guide provides a comprehensive walkthrough for deploying a customized Strapi application to Amazon Web Services (AWS) using the AWS Cloud Development Kit (CDK) with TypeScript. We will leverage Amazon Elastic Container Service (ECS) instead of EC2 instances and set up a continuous deployment pipeline using AWS CodePipeline that automatically deploys changes from the Prerequisites
Architecture OverviewWe will set up the following AWS resources:
Step 1: Initialize the CDK ProjectCreate a new directory and initialize a CDK TypeScript project. mkdir strapi-aws-cdk
cd strapi-aws-cdk
cdk init app --language typescript This command sets up a basic CDK project structure with a Step 2: Define AWS Resources in CDKWe'll define all necessary AWS resources in the Import Necessary Modulesimport * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as path from 'path';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ecs_patterns from 'aws-cdk-lib/aws-ecs-patterns';
import * as ecr from 'aws-cdk-lib/aws-ecr';
import * as ecr_assets from 'aws-cdk-lib/aws-ecr-assets';
import * as codebuild from 'aws-cdk-lib/aws-codebuild';
import * as codepipeline from 'aws-cdk-lib/aws-codepipeline';
import * as codepipeline_actions from 'aws-cdk-lib/aws-codepipeline-actions';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as rds from 'aws-cdk-lib/aws-rds';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager'; Create a VPCconst vpc = new ec2.Vpc(this, 'StrapiVPC', {
maxAzs: 2,
natGateways: 1,
}); Step 3: Set Up an RDS PostgreSQL DatabaseCreate a Secrets Manager Secret for Database Credentialsconst dbCredentialsSecret = new secretsmanager.Secret(this, 'DBCredentialsSecret', {
secretName: 'strapi-db-credentials',
generateSecretString: {
secretStringTemplate: JSON.stringify({ username: 'strapiuser' }),
generateStringKey: 'password',
excludePunctuation: true,
},
}); Create the RDS Database Instanceconst database = new rds.DatabaseInstance(this, 'StrapiDB', {
engine: rds.DatabaseInstanceEngine.postgres({
version: rds.PostgresEngineVersion.VER_13_8,
}),
vpc,
credentials: rds.Credentials.fromSecret(dbCredentialsSecret),
vpcSubnets: {
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
},
securityGroups: [], // We'll set up security groups later
multiAz: false,
allocatedStorage: 20,
maxAllocatedStorage: 100,
publiclyAccessible: false,
removalPolicy: cdk.RemovalPolicy.DESTROY, // Change to RETAIN for production
deletionProtection: false,
}); Step 4: Create an S3 Bucket for Asset Storageconst s3Bucket = new s3.Bucket(this, 'StrapiAssetsBucket', {
bucketName: 'your-unique-bucket-name', // Replace with a unique name
removalPolicy: cdk.RemovalPolicy.RETAIN,
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
}); Step 5: Set Up an ECS Cluster and Fargate ServiceCreate an ECS Clusterconst cluster = new ecs.Cluster(this, 'StrapiCluster', {
vpc,
}); Create an ECR Repositoryconst ecrRepository = new ecr.Repository(this, 'StrapiECRRepo', {
repositoryName: 'strapi-repo',
removalPolicy: cdk.RemovalPolicy.RETAIN,
}); Define the Fargate Service with Application Load Balancerconst fargateService = new ecs_patterns.ApplicationLoadBalancedFargateService(this, 'StrapiService', {
cluster,
cpu: 512,
memoryLimitMiB: 1024,
desiredCount: 1,
taskImageOptions: {
image: ecs.ContainerImage.fromEcrRepository(ecrRepository),
containerPort: 1337,
environment: {
DATABASE_CLIENT: 'postgres',
DATABASE_HOST: database.dbInstanceEndpointAddress,
DATABASE_PORT: database.dbInstanceEndpointPort,
DATABASE_NAME: 'strapi',
DATABASE_USERNAME: dbCredentialsSecret.secretValueFromJson('username').unsafeUnwrap(),
DATABASE_PASSWORD: dbCredentialsSecret.secretValueFromJson('password').unsafeUnwrap(),
AWS_ACCESS_KEY_ID: '<<ACCESS_KEY_ID>>',
AWS_ACCESS_SECRET: '<<SECRET_ACCESS_KEY>>',
AWS_REGION: cdk.Stack.of(this).region,
AWS_BUCKET_NAME: s3Bucket.bucketName,
},
secrets: {
DATABASE_PASSWORD: ecs.Secret.fromSecretsManager(dbCredentialsSecret, 'password'),
},
},
publicLoadBalancer: true,
});
Configure Security GroupsAllow the Fargate tasks to connect to the RDS instance. database.connections.allowDefaultPortFrom(fargateService.service, 'Allow ECS to access RDS'); Step 6: Set Up CodePipeline for Continuous DeploymentCreate a Source Artifactconst sourceOutput = new codepipeline.Artifact(); Create a Build Projectconst project = new codebuild.PipelineProject(this, 'StrapiBuildProject', {
environment: {
buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_3,
privileged: true, // Required to run Docker commands
},
environmentVariables: {
REPOSITORY_URI: { value: ecrRepository.repositoryUri },
AWS_ACCOUNT_ID: { value: cdk.Aws.ACCOUNT_ID },
AWS_REGION: { value: cdk.Aws.REGION },
},
buildSpec: codebuild.BuildSpec.fromObject({
version: '0.2',
phases: {
pre_build: {
commands: [
'echo Logging in to Amazon ECR...',
'aws --version',
'$(aws ecr get-login --region $AWS_REGION --no-include-email)',
],
},
build: {
commands: [
'echo Build started on `date`',
'echo Building the Docker image...',
'docker build -t $REPOSITORY_URI:latest .',
'docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION',
],
},
post_build: {
commands: [
'echo Build completed on `date`',
'echo Pushing the Docker image...',
'docker push $REPOSITORY_URI:latest',
'docker push $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION',
],
},
},
artifacts: {
files: ['imagedefinitions.json'],
},
}),
});
ecrRepository.grantPullPush(project.role!); Create the Pipelineconst pipeline = new codepipeline.Pipeline(this, 'StrapiPipeline', {
pipelineName: 'StrapiPipeline',
restartExecutionOnUpdate: true,
}); Add Stages to the PipelineSource Stagepipeline.addStage({
stageName: 'Source',
actions: [
new codepipeline_actions.GitHubSourceAction({
actionName: 'GitHub_Source',
owner: 'your-github-username',
repo: 'your-strapi-repo',
branch: 'production',
oauthToken: cdk.SecretValue.secretsManager('github-token'),
output: sourceOutput,
}),
],
});
Build Stagepipeline.addStage({
stageName: 'Build',
actions: [
new codepipeline_actions.CodeBuildAction({
actionName: 'Docker_Build',
project,
input: sourceOutput,
outputs: [new codepipeline.Artifact()], // Optional
}),
],
}); Deploy Stagepipeline.addStage({
stageName: 'Deploy',
actions: [
new codepipeline_actions.EcsDeployAction({
actionName: 'Deploy_to_ECS',
service: fargateService.service,
input: sourceOutput,
}),
],
}); Step 7: Configure IAM Roles and PoliciesEnsure that all necessary permissions are in place. Grant Permissions to Access SecretsdbCredentialsSecret.grantRead(fargateService.taskDefinition.taskRole); Allow CodeBuild Project to Access ECRecrRepository.grantPullPush(project.role!); Allow CodeBuild Project to Access Secrets ManagerIf your build needs to access Secrets Manager: dbCredentialsSecret.grantRead(project.role!); Step 8: Prepare Strapi ApplicationDockerize Your Strapi ApplicationCreate a # Use an official Node.js runtime as a parent image
FROM node:16-alpine
# Set the working directory
WORKDIR /usr/src/app
# Copy the package.json and package-lock.json
COPY package*.json ./
# Install dependencies
RUN npm install
# Copy the rest of the application code
COPY . .
# Build the Strapi application
RUN npm run build
# Expose port
EXPOSE 1337
# Start the application
CMD ["npm", "start"] Update Strapi ConfigurationEnsure your Strapi application reads configuration from environment variables. config/database.jsmodule.exports = ({ env }) => ({
connection: {
client: 'postgres',
connection: {
host: env('DATABASE_HOST', '127.0.0.1'),
port: env.int('DATABASE_PORT', 5432),
database: env('DATABASE_NAME', 'strapi'),
user: env('DATABASE_USERNAME', 'strapiuser'),
password: env('DATABASE_PASSWORD', ''),
ssl: env.bool('DATABASE_SSL', false),
},
debug: false,
},
}); config/plugins.jsmodule.exports = ({ env }) => ({
upload: {
config: {
provider: 'aws-s3',
providerOptions: {
accessKeyId: env('AWS_ACCESS_KEY_ID'),
secretAccessKey: env('AWS_ACCESS_SECRET'),
region: env('AWS_REGION'),
params: {
Bucket: env('AWS_BUCKET_NAME'),
},
},
},
},
}); Step 9: Commit and Push Changes to GitHubEnsure all your changes, including the git add .
git commit -m "Prepare Strapi for AWS ECS deployment"
git push origin production Step 10: Deploy the CDK StackBootstrap the CDK EnvironmentIf you haven't bootstrapped your AWS environment for CDK: cdk bootstrap aws://ACCOUNT-NUMBER/REGION DeployDeploy the stack: cdk deploy Confirm the deployment when prompted. Step 11: Test the Continuous Deployment PipelineAny changes pushed to the
Step 12: Output the Load Balancer DNSAdd an output to display the Load Balancer DNS name. new cdk.CfnOutput(this, 'LoadBalancerDNS', {
value: fargateService.loadBalancer.loadBalancerDnsName,
}); Important Notes
Complete CDK Stack File (
|
User story:
Acceptance criteria:
The text was updated successfully, but these errors were encountered: