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

feat: add front rendering app #8728

Merged
merged 30 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
72d5d65
feat: add front CODE stack
jamesgorrie Sep 1, 2023
c1c3e17
fix: change ELB dns name ssm parameter to something more useful and d…
jamesgorrie Sep 1, 2023
3412638
Merge branch 'main' into front-code-stack
JamieB-gu Sep 5, 2023
5b7b247
AMI parameter name is generated from app name
JamieB-gu Sep 5, 2023
de8d923
chore: update AWS stack platform
jamesgorrie Sep 20, 2023
187cc8f
Merge branch 'main' of github.com:guardian/dotcom-rendering into fron…
jamesgorrie Sep 25, 2023
930d040
Merge branch 'main' of github.com:guardian/dotcom-rendering into fron…
jamesgorrie Sep 28, 2023
70db435
update riffraff bundle shape to desired shape
jamesgorrie Sep 29, 2023
7e9434e
feat: add copyApp method to build-riff-raff-bundle
jamesgorrie Sep 29, 2023
64f2adc
feat: add autoscaling task for render-front to riff-raff.yml
jamesgorrie Sep 29, 2023
52fe648
add PROD cfn template
jamesgorrie Oct 3, 2023
0bf8185
fix: rename render-front CFN name front => render-front
jamesgorrie Oct 3, 2023
a9231dd
fix: call an app and app not stack
jamesgorrie Oct 3, 2023
1010082
chore: use const over jobs.push
jamesgorrie Oct 3, 2023
148bc66
fix: change render-front id in cdk
jamesgorrie Oct 3, 2023
42580b9
feat: add PROD render-front stack
jamesgorrie Oct 3, 2023
5ccdfc4
fix: spaces not tabs
jamesgorrie Oct 3, 2023
dcfaae3
fix: fix parameter store ID for load balancer DNS name
jamesgorrie Oct 3, 2023
ae13d20
Merge branch 'main' into front-code-stack
jamesgorrie Oct 3, 2023
109dddc
fix: make app more explicit for rendering app
jamesgorrie Oct 3, 2023
bfc8d7c
fix: rename render-front => front-web
jamesgorrie Oct 3, 2023
6ff96a5
fix: change order of when to append `ELB` to load balancer
jamesgorrie Oct 3, 2023
3ed3c0d
chore: rerun snapshot for cdk
jamesgorrie Oct 3, 2023
13d3930
fix: add `-` to cfnFolder
jamesgorrie Oct 6, 2023
776bfaa
Merge branch 'main' into front-code-stack
jamesgorrie Oct 6, 2023
08f0365
add front-web to publish action
jamesgorrie Oct 6, 2023
6e94365
Merge branch 'front-code-stack' of github.com:guardian/dotcom-renderi…
jamesgorrie Oct 6, 2023
e29b77e
remove - from cfn folder name
jamesgorrie Oct 10, 2023
0751562
AMIRenderfront => AMIFrontweb
jamesgorrie Oct 10, 2023
d9490ef
Merge branch 'main' into front-code-stack
jamesgorrie Oct 11, 2023
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
4 changes: 4 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ jobs:
- frontend-cfn
rendering:
- rendering
front-web-cfn:
- front-web-cfn
front-web:
- front-web
frontend-static:
- frontend-static

22 changes: 21 additions & 1 deletion dotcom-rendering/cdk/bin/cdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import { DotcomRendering } from '../lib/dotcom-rendering';
const app = new App();

const sharedProps = {
app: 'rendering',
stack: 'frontend',
region: 'eu-west-1',
};

new DotcomRendering(app, 'DotcomRendering-PROD', {
...sharedProps,
app: 'rendering',
stage: 'PROD',
minCapacity: 30,
maxCapacity: 120,
Expand All @@ -20,8 +20,28 @@ new DotcomRendering(app, 'DotcomRendering-PROD', {

new DotcomRendering(app, 'DotcomRendering-CODE', {
...sharedProps,
app: 'rendering',
stage: 'CODE',
minCapacity: 1,
maxCapacity: 4,
instanceType: 't4g.micro',
});

new DotcomRendering(app, 'DotcomRendering-front-web-CODE', {
...sharedProps,
app: 'front-web',
stage: 'CODE',
minCapacity: 1,
maxCapacity: 4,
instanceType: 't4g.micro',
});

new DotcomRendering(app, 'DotcomRendering-front-web-PROD', {
...sharedProps,
app: 'front-web',
stage: 'PROD',
// TODO: up this once we have code working
minCapacity: 1,
maxCapacity: 4,
instanceType: 't4g.micro',
});
Original file line number Diff line number Diff line change
Expand Up @@ -1081,6 +1081,25 @@ sudo NODE_ENV=$NODE_ENV GU_STAGE=$GU_STAGE -u dotcom-rendering -g frontend make
},
"Type": "AWS::IAM::InstanceProfile",
},
"loadBalancerDnsName0B1DEBAD": {
"Properties": {
"Name": "/frontend/TEST/rendering.loadBalancerDnsName",
"Tags": {
"Stack": "frontend",
"Stage": "TEST",
"gu:cdk:version": "TEST",
"gu:repo": "guardian/dotcom-rendering",
},
"Type": "String",
"Value": {
"Fn::GetAtt": [
"InternalLoadBalancer",
"DNSName",
],
},
},
"Type": "AWS::SSM::Parameter",
},
},
}
`;
14 changes: 13 additions & 1 deletion dotcom-rendering/cdk/lib/dotcom-rendering.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
import { CfnAlarm } from 'aws-cdk-lib/aws-cloudwatch';
import { InstanceType, Peer } from 'aws-cdk-lib/aws-ec2';
import { LoadBalancingProtocol } from 'aws-cdk-lib/aws-elasticloadbalancing';
import { StringParameter } from 'aws-cdk-lib/aws-ssm';
import type { DCRAlarmConfig, DCRProps } from './types';
import { getUserData } from './userData';

Expand Down Expand Up @@ -88,7 +89,11 @@ export class DotcomRendering extends GuStack {
/**
* TODO - migrate this ELB (classic load balancer) to an ALB (application load balancer)
* @see https://github.com/guardian/cdk/blob/512536bd590b26d9fcac5d39329e8217103d7859/src/constructs/loadbalancing/elb.ts#L24-L46
*
* GOTCHA: The load balancer name appends `-ELB` when the `app = "rendering"` for backwards compatibility
* We removed this to avoid the `LoadBalancerName.length > 32`. This will be fixable once we migrate to ALBs.
*/
const loadBalancerName = app === 'rendering' ? `${stack}-${stage}-${app}-ELB` : `${stack}-${stage}-${app}`;
const loadBalancer = new GuClassicLoadBalancer(
this,
'InternalLoadBalancer',
Expand Down Expand Up @@ -129,7 +134,7 @@ export class DotcomRendering extends GuStack {
],
subnetSelection: { subnets: publicSubnets },
propertiesToOverride: {
LoadBalancerName: `${stack}-${stage}-${app}-ELB`,
LoadBalancerName: loadBalancerName,
// Note: this does not prevent the GuClassicLoadBalancer
// from creating a default security group, though it does
// override which one is used/associated with the load balancer
Expand All @@ -145,6 +150,13 @@ export class DotcomRendering extends GuStack {
new CfnOutput(this, 'LoadBalancerUrl', {
value: loadBalancer.loadBalancerDnsName,
});

new StringParameter(this, 'loadBalancerDnsName', {
// Annoyingly this doesn't follow the same pattern as the other SSM parameters
parameterName: `/${stack}/${stage}/${app}.loadBalancerDnsName`,
stringValue: loadBalancer.loadBalancerDnsName,
});

// ------------------------------------

// ------------------------------------
Expand Down
163 changes: 95 additions & 68 deletions dotcom-rendering/scripts/deploy/build-riffraff-bundle.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,89 +8,120 @@ import { log, warn } from '../env/log.js';
const dirname = url.fileURLToPath(new URL('.', import.meta.url));
const target = path.resolve(dirname, '../..', 'target');

// This task generates the riff-raff bundle. It creates the following
// directory layout under target/
//
// target
// ├── build.json
// ├── riff-raff.yaml
// ├── frontend-cfn
// │ ├── DotcomRendering-CODE.template.json
// │ ├── DotcomRendering-PROD.template.json
// ├── frontend-static
// │ ├── assets
// │ │ └── **
// │ │ └── *
// │ └── static
// │ ├── frontend
// │ │ └── **
// │ │ └── *
// │ └── etc
// └── rendering
// └── dist
// └── rendering.zip

const copyCfn = () => {
log(' - copying cloudformation config');
return cpy(
/** This task generates the riff-raff bundle. It creates the following
* directory layout under target/
* target
* ├── build.json
* ├── riff-raff.yaml
* ├── ${copyFrontendStatic()}
* ├── ${copyApp('rendering')}
* └── ${copyApp('renderi-front')}
*/

/**
* This method creates a bundle needed to run an app including:
* - CloudFormation files
* - .zip artefact comprised of the JS app
*
* It generates a folder like this:
* ├── ${appName}-cfn
* │ ├── DotcomRendering-${appName}-CODE.template.json
* │ └── DotcomRendering-${appName}-PROD.template.json
* └── ${appName}
* └── dist
* └── ${appName}.zip
*
* Except for the instance where appName === 'rendering' due to backwards compatibility
*
* @param appName {string}
**/
const copyApp = (appName) => {
// GOTCHA: This is a little hack to be backwards compatible with the naming for when this was a single stack app
const cfnTemplateName = appName === 'rendering' ? '' : `-${appName}`;
const cfnFolder =
appName === 'rendering' ? 'frontend-cfn' : `${appName}-cfn`;

log(` - copying app: ${appName}`);

log(` - ${appName}: copying cloudformation config`);
const cfnJob = cpy(
[
'cdk.out/DotcomRendering-CODE.template.json',
'cdk.out/DotcomRendering-PROD.template.json',
`cdk.out/DotcomRendering${cfnTemplateName}-CODE.template.json`,
`cdk.out/DotcomRendering${cfnTemplateName}-PROD.template.json`,
],
path.resolve(target, 'frontend-cfn'),
path.resolve(target, cfnFolder),
);

log(` - ${appName}: copying makefile`);
const makefileJob = cpy(['makefile'], path.resolve(target, appName));

log(` - ${appName}: copying server dist`);
const serverDistJob = cpy(
path.resolve(dirname, '../../dist/**'),
path.resolve(target, appName, 'dist'),
{
nodir: true,
},
);

log(`' - ${appName}: copying scripts`);
const scriptsJob = cpy(
path.resolve(dirname, '../../scripts/**'),
path.resolve(target, appName, 'scripts'),
{
nodir: true,
},
);

return [cfnJob, makefileJob, serverDistJob, scriptsJob];
};

const copyStatic = () => {
/**
* This method copies the static files over the frontend-static folder, which is then deployed to S3.
*
* It generates a folder like this:
* ├── frontend-static
* ├── assets
* │ └── **
* │ └── *
* └── static
* ├── frontend
* │ └── **
* │ └── *
* └── etc
*/
const copyFrontendStatic = () => {
log(' - copying static');
return cpy(
const staticJob = cpy(
path.resolve(dirname, '../../src/static/**'),
path.resolve(target, 'frontend-static', 'static', 'frontend'),
{
nodir: true,
},
);
};

const copyDist = () => {
log(' - copying dist');
const source = path.resolve(dirname, '../../dist');
const dest = path.resolve(target, 'frontend-static', 'assets');
return Promise.all([
cpy(path.resolve(source, '**/*.!(html|json)'), dest, {
nodir: true,
}),
cpy(path.resolve(source, 'stats'), path.resolve(dest, 'stats'), {
nodir: true,
}),
]);
};

const copyScripts = () => {
log(' - copying scripts');
return cpy(
path.resolve(dirname, '../../scripts/**'),
path.resolve(target, 'rendering', 'scripts'),
log(' - copying dist => assets');
const distToAssetsJob = cpy(
path.resolve(source, '**/*.!(html|json)'),
dest,
{
nodir: true,
},
);
};

const copyDistServer = () => {
log(' - copying server dist');
return cpy(
path.resolve(dirname, '../../dist/**'),
path.resolve(target, 'rendering', 'dist'),
log(' - copying stats => assets');
const statsToAssetsJob = cpy(
path.resolve(source, 'stats'),
path.resolve(dest, 'stats'),
{
nodir: true,
},
);
};

const copyMakefile = () => {
log(' - copying makefile');
return cpy(['makefile'], path.resolve(target, 'rendering'));
return [staticJob, distToAssetsJob, statsToAssetsJob];
};

const copyRiffRaff = () => {
Expand All @@ -99,15 +130,11 @@ const copyRiffRaff = () => {
};

Promise.all([
copyCfn(),
copyMakefile(),
copyStatic(),
copyDist(),
copyDistServer(),
copyScripts(),
...copyApp('rendering'),
...copyApp('front-web'),
...copyFrontendStatic(),
copyRiffRaff(),
])
.catch((err) => {
warn(err.stack);
process.exit(1);
});
]).catch((err) => {
warn(err.stack);
process.exit(1);
});
32 changes: 26 additions & 6 deletions dotcom-rendering/scripts/deploy/riff-raff.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,48 @@ regions: [eu-west-1]
allowedStages:
- CODE
- PROD
templates:
cloudformation:
type: cloud-formation
parameters:
amiEncrypted: true
amiTags:
# Keep the Node version in sync with `.nvmrc`
Recipe: dotcom-rendering-ARM-jammy-node-18.17.0
AmigoStage: PROD
deployments:
frontend-cfn:
type: cloud-formation
template: cloudformation
parameters:
templateStagePaths:
CODE: DotcomRendering-CODE.template.json
PROD: DotcomRendering-PROD.template.json
cloudFormationStackByTags: false
cloudFormationStackName: rendering
amiParameter: AMIRendering
amiEncrypted: true
amiTags:
# Keep the Node version in sync with `.nvmrc`
Recipe: dotcom-rendering-ARM-jammy-node-18.17.0
AmigoStage: PROD
rendering:
type: autoscaling
parameters:
bucketSsmKey: /account/services/dotcom-artifact.bucket
dependencies:
- frontend-static
- frontend-cfn
front-web-cfn:
template: cloudformation
parameters:
templateStagePaths:
CODE: DotcomRendering-front-web-CODE.template.json
PROD: DotcomRendering-front-web-PROD.template.json
cloudFormationStackByTags: false
cloudFormationStackName: front-web
amiParameter: AMIFrontweb
front-web:
type: autoscaling
jamesgorrie marked this conversation as resolved.
Show resolved Hide resolved
parameters:
bucketSsmKey: /account/services/dotcom-artifact.bucket
dependencies:
- frontend-static
- frontend-cfn
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we want to depend on the render-front-cfn deployment here:

Suggested change
- frontend-cfn
- render-front-cfn

frontend-static:
type: aws-s3
parameters:
Expand Down
Loading