stephen.pearl
01/29/2021, 2:15 PMstephen.pearl
01/29/2021, 2:16 PMJonathan
01/29/2021, 4:17 PMJonathan
01/29/2021, 4:17 PMJonathan
01/29/2021, 4:18 PMstephen.pearl
01/29/2021, 5:19 PMstephen.pearl
01/29/2021, 5:21 PMJonathan
01/29/2021, 6:41 PMJonathan
01/29/2021, 6:41 PMstephen.pearl
01/29/2021, 6:42 PMJonathan
01/29/2021, 6:44 PMJonathan Romano
01/29/2021, 6:46 PMJonathan Romano
01/29/2021, 6:47 PMJonathan
01/29/2021, 6:51 PMJonathan
01/29/2021, 6:51 PMJonathan Romano
01/29/2021, 6:52 PMJonathan
01/29/2021, 6:54 PMJonathan Romano
01/29/2021, 6:55 PMJonathan
01/29/2021, 6:55 PMJonathan
01/29/2021, 6:55 PMJames
06/16/2021, 5:07 AMJonathan
06/16/2021, 7:07 AMJames
06/16/2021, 9:35 PMJames
06/21/2021, 3:31 AMJonathan
06/21/2021, 1:39 PMconst buildStage = pipeline.addStage('build');
buildStage.addActions(new codepipeline_actions.CodeBuildAction({
actionName: `${props?.prefix}DockerBuild`,
input: sourceArtifact,
outputs: [buildArtifact],
// The build will create an envrionment and
// - Create a production-ready build (new tag and latest with an imagedefinitions.json for the deployment).
// - Create a migration-container containing the latest changes and prisma.
// This is necssary as the codebuild is mostly private and has no access to npm.
project: new codebuild.PipelineProject(this, `${props?.prefix}DockerBuild`, {
environmentVariables: {
SERVICE_NAME: { value: props?.apiService.service.taskDefinition.defaultContainer?.containerName },
IMAGE_REPO_NAME: { value: repoName },
MIRATE_REPO_NAME: { value: migrationRepoName },
IMAGE_TAG: { value: 'latest' },
AWS_ACCOUNT_ID: { value: 'YOUR_ACCOUNT_ID' },
AWS_DEFAULT_REGION: { value: 'eu-central-1' },
},
environment: {
privileged: true,
buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_3
},
buildSpec: codebuild.BuildSpec.fromObject({
version: '0.2',
phases: {
pre_build: {
commands: [
'echo Logging in to AWS',
'$(aws ecr get-login --region $AWS_DEFAULT_REGION --no-include-email)',
'aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$<http://AWS_DEFAULT_REGION.amazonaws.com|AWS_DEFAULT_REGION.amazonaws.com>'
]
},
build: {
commands: [
'echo Build started',
'echo Building the Docker image...',
'docker build -t $IMAGE_REPO_NAME:$CODEBUILD_RESOLVED_SOURCE_VERSION ./api',
'docker build -t $MIRATE_REPO_NAME:latest --target migrateBuilder ./api',
'docker tag $IMAGE_REPO_NAME:$CODEBUILD_RESOLVED_SOURCE_VERSION $AWS_ACCOUNT_ID.dkr.ecr.$<http://AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$CODEBUILD_RESOLVED_SOURCE_VERSION|AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$CODEBUILD_RESOLVED_SOURCE_VERSION>',
'docker tag $IMAGE_REPO_NAME:$CODEBUILD_RESOLVED_SOURCE_VERSION $AWS_ACCOUNT_ID.dkr.ecr.$<http://AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:latest|AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:latest>',
'docker tag $MIRATE_REPO_NAME:latest $AWS_ACCOUNT_ID.dkr.ecr.$<http://AWS_DEFAULT_REGION.amazonaws.com/$MIRATE_REPO_NAME:latest|AWS_DEFAULT_REGION.amazonaws.com/$MIRATE_REPO_NAME:latest>'
]
},
post_build: {
commands: [
'echo finishing up',
'docker push $AWS_ACCOUNT_ID.dkr.ecr.$<http://AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$CODEBUILD_RESOLVED_SOURCE_VERSION|AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$CODEBUILD_RESOLVED_SOURCE_VERSION>',
'docker push $AWS_ACCOUNT_ID.dkr.ecr.$<http://AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:latest|AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:latest>',
'docker push $AWS_ACCOUNT_ID.dkr.ecr.$<http://AWS_DEFAULT_REGION.amazonaws.com/$MIRATE_REPO_NAME:latest|AWS_DEFAULT_REGION.amazonaws.com/$MIRATE_REPO_NAME:latest>',
'echo finished pushing docker image',
`printf '[{"name":"%s","imageUri":"%s"}]' $SERVICE_NAME $AWS_ACCOUNT_ID.dkr.ecr.$<http://AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$CODEBUILD_RESOLVED_SOURCE_VERSION|AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$CODEBUILD_RESOLVED_SOURCE_VERSION> > imagedefinitions.json`,
]
}
},
artifacts: {
files: [
'imagedefinitions.json'
]
}
}),
role: buildRole,
}),
}));
Jonathan
06/21/2021, 1:39 PMconst migrationRepoName = 'migrations';
const migrationRepo = ecr.Repository.fromRepositoryName(this, 'MigrationRepo', migrationRepoName);
Then, I do a codebuild
step, where we build basically two images: one which is the general API container image, and one which will contain prisma + migrations
. The latter is what we refer to as the MIGRATE_REPO
, and is passed using CDK. By pushing to this repository, we allow a separate repo whJonathan
06/21/2021, 1:41 PMconst migrateRole = new iam.Role(this, `${props?.prefix}MigrateRole`, {
assumedBy: new iam.ServicePrincipal('<http://codebuild.amazonaws.com|codebuild.amazonaws.com>'),
});
const migrateBuildProject = new codebuild.PipelineProject(this, `${props?.prefix}MigrateBuild`, {
// This build will call prisma's migration function, and output it to `output.txt` in the artifact.
buildSpec: codebuild.BuildSpec.fromObject({
version: '0.2',
phases: {
pre_build: {
commands: [
'cd /app'
]
},
build: {
commands: [
'echo $CODEBUILD_SRC_DIR > codebuildsrcdir.txt',
'pwd > whereami.txt',
'ls > whatsaroundme.txt',
'./node_modules/.bin/prisma migrate up --experimental > output.txt 2>&1',
]
}
},
artifacts: {
files: [
'/app/codebuildsrcdir.txt',
'/app/whereami.txt',
'/app/whatsaroundme.txt',
'/app/output.txt'
]
}
}),
environment: {
buildImage: codebuild.LinuxBuildImage.fromEcrRepository(migrationRepo),
privileged: true,
environmentVariables: {
DB_STRING: {
value: `${secret.secretName}:url`,
type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER
},
}
},
vpc: props?.vpc,
subnetSelection: {
subnetType: ec2.SubnetType.ISOLATED
},
role: migrateRole,
securityGroups: props?.rdsSecurityGroup ? [props?.rdsSecurityGroup] : undefined
});
props?.db.grantConnect(migrateRole);
migrateStage.addActions(new codepipeline_actions.CodeBuildAction({
actionName: `${props?.prefix}MigrateBuild`,
input: sourceArtifact,
outputs: [migrateArtifact],
project: migrateBuildProject
}));
Jonathan
06/21/2021, 1:41 PMJonathan Romano
06/21/2021, 2:03 PMJames
06/21/2021, 9:17 PMJonathan
06/22/2021, 6:24 PMJonathan Romano
06/22/2021, 7:12 PM