Moving a monorepo from AWS Amplify to AWS Beanstalk

Alternative Text
by Dmitry Elisov
Oqtacore CTO
472
alt

AWS Amplify is an amazing tool for publishing next.js websites when you are starting a new project.

However, if you continue growing your web portal, there will be a moment when Amplify will fail building due to final build size being to big.

You can postpone this moment by optimizing your node_modules and win 3-6 months, but the ending is inevitable – you will have to move you project to either EKS or Beanstalk.

We prefer Beanstalk for our own reasons – Docker+k8s seems to be an extra abstraction on top of AWS’s abstraction. Kubernetes makes a cloud from your on-premise data center, but AWS is a cloud by itself already. Beanstalk is basically a managed Kubernetes, so why make life harder? Code Pipeline and Beanstalk provide a great way to control the deployed build versions, as well as other great tools in terms of monitoring, alerts and costs management.

So, here is a step-by-step instruction for deploying a monorepository on next.js@12.0.7 on elastic beanstalk and assembly on AWS Code Pipeline

Project information

  • Next.js version 12.0.7
  • Node.js 16.18.1
  • Yarn 1.22.9
  • NPM 8.19.2
  • Monorepository
  • Environment for running commands:cli.sh
  • The volume of the final assembly is 700mb

Creating elastic beanstalk

  1. Select the region we need in which we will deploy our application
  2. Go to the pageelastic beanstalk in the applications tab
  3. If necessary, create a new application by clicking on the Create application button

word image 1180 1

  1. Enter a name and click the Create button

word image 1180 2

  1. When you click on the application name, go to the tabEnvironments.
  2. Click the Create new environment button

word image 1180 3

  1. We put down the configuration as in the screenshot
  2. Application name will be selected automatically if you clicked on the name in the applications tab

word image 1180 4

  1. Enter yourEnvironment name. Enter your temporary Domain name and check its availability using the Check availability button

word image 1180 5

  1. For version next.js@12.0.7, you must install version Node.js 16 (this must be observed when creating any environments for version next.js@12.0.7)

word image 1180 6

  1. Next, leave the checkboxes as in the screenshot and move on to the next step by clicking on the Next button

word image 1180 7

  1. Next, in the screenshot, select the roles that beanstalk offers us (as in the screenshot below). We do not change them, as the application will launch with an error. If you are creating these roles for the first time, you must refer to the AWS service role instructions.
  2. Next, click the Next button and move on to the next step.

word image 1180 8

  1. Next, select the configured VPC. If your VPC does not already exist, you need to create a new one by clicking on the Create custom VPC button and refer to the AWS VPC documentation

word image 1180 9

  1. Select the Activated option for the Public IP address. We also select all available regions

word image 1180 10

  1. Select all available regions for the database. We leave the remaining options in the Database section unchanged.

word image 1180 11

  1. Next, click the Next button to move to the next stage
  2. Depending on the volume of the finished assembly of your project, select the SSD used. In this example, we use a monorepository, the volume of the final assembly is ~700mb (excluding node_modules)

word image 1180 12

  1. Leave the rest of the options as they are.

word image 1180 13

  1. Next, select the pre-configured EC2 security group. If this is your first time creating a beanstalk, please refer to the AWS documentation on creating an ec2 security group

word image 1180 14

  1. Next, from the Environment type drop-down list, select Load Balanced and the Combine purchase options and instances option
  2. Leave the remaining options unchanged

word image 1180 15

  1. We choose x86_64 architecture. ANDselect the instance type from the requirements of our project. For a testing/development bench we will need 2 CPUs and 4gb of memory. You can also customize your instance to your needs and select it in the AMD ID, but to do this, refer to the AWS AMD ID documentation.

word image 1180 16

  1. We leave the remaining options unchanged.
  2. Next, select all available regions

word image 1180 17

  1. Next, select everything as in the screenshot, and we will return to the listeneres stage at the very end of our instructions

word image 1180 18

  1. If we want to use a different port when listening to an application, we add it by clicking on the Add process button. Within the framework of this instruction, we will not consider this stage, since by default Beanstalk looks for the command in package.jsonnpm start (more details here) and runs it on its default port 8080. This port can be changed by creating a global variable PORT at the last stage of beanstalk configuration. You can check the working port:
    1. Go to the ec2 instance tab
    2. Find the name by our Environment name
    3. Click the Connect button at the top
    4. Login to an instance from the selected 4 connection options (depending on the instance type created, only one login may be available)
    5. Using the command line, we view the application launch ports used

word image 1180 19

  1. Leave the remaining options unchanged and click Next.
  2. We do not consider the following steps for setting up beanstalk within the framework of this instruction because they remain unchanged. At this point you can just add a global PORT variable to configure your application

Creating codePipeline part 1/2

  1. Go to the creation pagepipeline. And click the Create Pipeline button

word image 1180 20

  1. Enter the name of your new pipeline. Service role should be created automatically. Next, click Next

word image 1180 21

  1. Next, select Github (Version 2) from the drop-down list. We select a pre-created Connection Github from the list that has access to the GitHub repository of our project. Next, select the names and branch. If you have not created a Connection, please refer to the AWS Connection GitHub documentation. Next, click Next.

word image 1180 22

  1. Next, select AWS CodeBuild from the Build Provider drop-down list. Select the desired region. And click Create Project. We also set global variables and later we will return to continue building the Code Pipeline

word image 1180 23

Creating a Build Project.

  1. After clicking Create Project, the Build Project configuration interface opens and enter Project Name

word image 1180 24

  1. Next, select Linux 2. And the parameters are as in the screenshot below. Be sure to select the standard:4.0 version since the standard:5.0 build version will not run for our environment and build.

word image 1180 25

  1. Leave the options as default

word image 1180 26

  1. We increase the configuration of the temporary build environment to 7 GB of memory and 4 CPU

word image 1180 27

  1. Next, leave the selected parameters as default and click Next.

word image 1180 28

  1. The codeBuild stage is complete. Let’s return to further configuration of Pipeline

Creating codePipeline part 2/2

  1. After successfully creating a Build Project, the name of the created configuration will be highlighted in the name field and click the Next button

word image 1180 29

  1. Next, select the Elastic Beanstalk option from the Deploy Provider drop-down list. Next, from the list, select Application name, the name of our environment that we created at the Beanstalk configuration stage. Next, select the name of the created application and click Next.

word image 1180 30

  1. At this point, the codePipeline setup is complete
  2. Now we can observe the running assembly of our application

word image 1180 31

  1. But to successfully build the application, you need to add the build configuration configuration (buildspec.yml) for the pipeline and the deploy configuration for beanstalk (installation of yarn and other packages to successfully launch the next.js application)

Configuration files for pipeline (Buildspec.yml & cli.sh)

  1. We create a buildspec.yml file in the root of our project. At the build stage
    1. We create global variables
    2. Call the command from cli.sh – deploy_app
    3. We remove node_modules and .next/cache in order to facilitate the deployment stage on instace beanstalka, since there are memory limits of ~500mb

version: 0.2

phases:

install:

runtime-versions:

nodejs: 16

commands:

– n 16.18.1

pre_build:

commands:

– echo “preBuild APP”

– rm -rf node_modules **/node_modules

– npm cache clean –force

– yarn cache clean

– yarn install –frozen-lockfile

– yarn global add next@12.0.7

build:

commands:

– NAME_VARIABLE_IN_APP=${NAME_VARIABLE_IN_PIPELINE}

– echo “Build APP”

– pwd

– ./cli.sh deploy_app

– rm -rf node_modules

– rm -rf .next/cache

artifacts:

files:

– ‘**/*’

discard-paths: no

cache:

paths:

– node_modules/**/*

  1. Create a cli.sh file in the root of our project
    1. In the deploy_app function we add the ‘set -e’ command, since during the build pipeline stage, errors that occur during our npm run build command are not processed by the pipeline and go to the next pipeline deploy stage
    2. This instruction does not cover setting up the cli.sh file; to do this, contact a search engine or chatGPT

deploy_app() {

set -It is

echo “START npm run build mode”

node -in

npm -in

echo ‘AMPLIFY_ENV: ‘ + $NEXT_PUBLIC_AMPLIFY_ENV

npm run build –workspace=@name_project/app

}

  1. The creation and preparation of files at the pipeline stage is completed

Configuration files for elastic beanstalk (.sh file & package.json)

  1. We create a directory .platform/hooks/prebuild/ in the root of our project with the file yarn.sh
    1. You can learn more about hooks and instance beanstalk configuration inofficial AWS documentation
    2. First, we install node.js of the required version (_16.x is the required syntax for downloading the version) since node.js is not yet available at the prebuild stage.
    3. Next we install yarn and initialize it for global access
    4. Next, using yarn, we install next.js of the required version
    5. And if you are using the env-cmd package to work with global variables
    6. Next, we re-install all package dependencies of our project, since at the build stage in the builddpec.yml file we removed the deploy pipeline stage for proper operation

#!/bin/bash

echo “install node.js”

sudo curl –silent –location https://rpm.nodesource.com/setup_16.x | sudo bash –

sudo yum -y install nodejs

sudo wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo

sudo yum -y install yarn

export PATH=”$PATH:$HOME/.yarn/bin”

source ~/.bashrc

cd /var/app/staging/

sudo yarn global add next@12.0.7

sudo yarn global add env-cmd

sudo chown -R webapp:webapp node_modules/ || true

sudo yarn install –frozen-lockfile

  1. I assume that you already have a package.json file in the root directory because it should be your default when working with next.js. It must contain the npm start command

“scripts”: {

“start”: “npm run start –workspace=@name-project/app”

}

  1. Now we push all the changes to the github repository and the pipeline assembly should start again

Conclusion

  1. We return to codePipeline. We are waiting for the completion of the build stage. If the build was not successful, you can view the logs by clicking on the View logs button at the build stage and scroll to the end.

word image 1180 32

  1. If the build stage was successful, then we have completed 80% of our journey successfully.
  2. If the deploy step fails with an error, you can get the deployed information in Beanstalk by opening your application environment and opening the Logs tab at the bottom (as in the screenshot below) and selecting Full from the drop-down list. And then download by clicking on the Download button. There are a lot of useful command line files and beanstalk hooks there. If this information is not enough, then we can go to the instance itself and try to run the project ourselves and check whether it will work on the temporary beanstalk domain. We discussed the step of how to log into ec2 instance in this instruction

word image 1180 33

  1. If the deploy was successful, then we return to our environment elastic beanstalk
  2. And click the link to our temporary domain
  3. The application will open. If this does not happen, check the logs, the port on which the application is launched and try to go to your ec2 instance and run your assembly on port 8080 yourself.

How can you make the application available via https?

  1. We purchase domain, if you don’t have it yet, for this use the AWS documentation (Route53)
  2. It will help you get a certificateAWS Certificate Manager, a button to automatically add a DNS CNAME record to Route53 is also available there
  3. You need to register DNS records (CNAME) in Route53 and change the type A record with the alias option selected on Beanstalk
  4. And after that we return to Beanstalk. Open the Configuration tab. Find the Instance traffic and scaling section. Click on the Edit button

word image 1180 34

  1. Find the Listeners section

word image 1180 35

  1. Click the Add listener button
  2. Enter port 443, select https, the SSL certificate created in step 2 and select the latest SSL policy. After that, save, scroll down and accept the changes.

word image 1180 36

  1. Congratulations, you have a working next.js project running on aws beanstalk + pipeline on https
Rate this article
Please wait...