This project creates all the infrastructure needed to build a deployment process for the Next.js serverless app. It uses the Serverless Next.js component https://github.com/serverless-nextjs/serverless-next.js to do the app deployment.
The CodePipeline pipeline created in this project has two stages
- a source stage that sets up a webhook to get events from Github that trigger a pipeline execution
- a build stage that invokes the
serverlesscommand on the app code that build and deploys the app infra
The CodeBuild build is defined in the buildspec.yml file, which is stored in the Next.js app repo and looks something like this:
version: 0.2
env:
secrets-manager:
STATIC_NEXTJS_BUCKET: "DeployEnvVars:STATIC_NEXTJS_BUCKET"
PRECREATED_CLOUDFRONT_ID: "DeployEnvVars:PRECREATED_CLOUDFRONT_ID"
# Set in the CodePipeline build project
# STATE_BUCKET
#
phases:
install:
runtime-versions:
nodejs: 12
commands:
- npm install
- npm install serverless -g
build:
commands:
- sed -e "s/\$STATIC_NEXTJS_BUCKET/$STATIC_NEXTJS_BUCKET/" serverless.yml
- sed -e "s/\$PRECREATED_CLOUDFRONT_ID/$PRECREATED_CLOUDFRONT_ID/" serverless.yml
#to purge the old .serverless contents and recreate them, comment out this line
- aws s3 sync s3://$STATE_BUCKET/.serverless .serverless --delete
- serverless
- aws s3 sync .serverless s3://$STATE_BUCKET/.serverless --delete
- rm .env
The serverless.yml file in the target app repo should look something like this:
awsNextApp:
component: "@sls-next/serverless-component@1.17.0"
inputs:
domain: ["next", "whtsqr.com"] # [ sub-domain, domain ]
# these values need to be imported from secrets manager as they are created in us-east-1 and
# we can't import values from stacks across regions
bucketName: $STATIC_NEXTJS_BUCKET
cloudfront:
# if you want to use an existing cloudfront distribution, provide it here
distributionId: $PRECREATED_CLOUDFRONT_ID
# we add some behaviours in that seem to be needed...
public/*:
minTTL: 10000
maxTTL: 10000
defaultTTL: 10000
name:
defaultLambda: nextjs-default-lambda
apiLambda: nextjs-api-lambda
build:
env:
NEXT_PUBLIC_WORDPRESS_URL: $NEXT_PUBLIC_WORDPRESS_URL
NEXT_CF_ACCESS_CLIENT_ID: $NEXT_CF_ACCESS_CLIENT_ID
NEXT_CF_ACCESS_CLIENT_SECRET: $NEXT_CF_ACCESS_CLIENT_SECRET
The S3 sync of the .serverless directory ensures that the build retains the same infrastructure between invocations.
You will need to create some items before you begin.
- Github Oauth token with admin:webhooks and repo access
- Hostname for CF distribution
- ACM certificate for that hostname created in the
us-east-1region
In addition you will need to gather the outputs from the WAF/Cloudfront/S3 bucket stack, as these are created in us-east-1 and cannot be imported across regions.
These items will be used to populate values in the secrets-stack, described below.
You must run the stacks in this project in the right order to ensure that resources created in each are available to the next stack.
Note that you will probably need to configure some hostnames and ACM certificate info in here first.
Run the stack waf-cloudfront-stack to deploy the static content S3 bucket, WAF and Cloudfront distribution.
cdk deploy waf-cloudfront-stack
This will create two secret objects:
DeployEnvVarscontaining key/value pairs for all the environment variables that are needed in the buildspec.ymlGithub_OAuth_Tokencontaining a keyvaluereferencing a Github OAuth token that has access to the repo andadmin:repo_hookpermissions.
Run the stack secrets-stack to create the needed secrets, then go into the AWS console and configure their values.
cdk deploy secrets-stack
Finally, run serverless-app-pipeline-cdk to create the pipeline and build project.
cdk deploy serverless-app-pipeline-cdk
The serverless build command serverless will use the serverless.yml file in the app repo to configure the build that will run in CodeBuild. As we will have pre-created the S3 bucket and the Cloudfront distribution, the serverless build will configure those resources and in addition will create
- two Lambda functions
- relevant profiles etc
The Lambdas are deployed as Lambda@Edge.
The cdk.json file tells the CDK Toolkit how to execute your app.
This project is set up like a standard Python project. The initialization
process also creates a virtualenv within this project, stored under the .env
directory. To create the virtualenv it assumes that there is a python3
(or python for Windows) executable in your path with access to the venv
package. If for any reason the automatic creation of the virtualenv fails,
you can create the virtualenv manually.
To manually create a virtualenv on MacOS and Linux:
$ python3 -m venv .env
After the init process completes and the virtualenv is created, you can use the following step to activate your virtualenv.
$ source .env/bin/activate
If you are a Windows platform, you would activate the virtualenv like this:
% .env\Scripts\activate.bat
Once the virtualenv is activated, you can install the required dependencies.
$ pip install -r requirements.txt
At this point you can now synthesize the CloudFormation template for this code.
$ cdk synth
To add additional dependencies, for example other CDK libraries, just add
them to your setup.py file and rerun the pip install -r requirements.txt
command.
cdk lslist all stacks in the appcdk synthemits the synthesized CloudFormation templatecdk deploydeploy this stack to your default AWS account/regioncdk diffcompare deployed stack with current statecdk docsopen CDK documentation
Enjoy!
