I want to deploy an application to AWS. In the first time, I was overwhelmed with the architecture of AWS and couldn't find tutorials for people without knowledge AWS. So I wrote this post for people who don't want to spend too much time on cloud.
Basic concepts
AWS ECR
AWS ECR is where consists of all encrypted docker images. AWS ECS will consume these docker images.
AWS ECS
AWS ECS controls the way your images is run. It has 3 main concepts: cluster, service, task definitions.
- Cluster: the center of ECS that consist of services, tasks.
- Service: help you control tasks how task run, how many tasks will run, etc.
- Task definitions: where you can add docker image.
AWS EC2
You can think it helps us secure and computes the size of our applications. We can restrict IPs that have permission to access our application.
I'm going to use this flow to deploy my next app.
Setup project
Next app
- Let's run this command to initiate a next app with
create-next-app
:
npx create-next-app --typescript
Give it a name:
demo-deploy
hit enter and wait for it runs.We need to create a docker file for our app. Let's do it:
FROM node:16-alpine3.11
WORKDIR /demo-deploy
ENV PORT 80
COPY . /demo-deploy
RUN npm install
CMD ["npm", "run", "dev"]
Setup AWS
Create IAM user
We have to have an account in order to interact with AWS console. You need to create a IAM user.
Setup AWS ECS
- You have to setup an IAM user Administrator, a key pair for EC2 in order to unlock ECS. Click here and do as instructed.
And hit Administrator
to create a couple of access key - access secret we need to use later.
- We're going to create cluster, service and task definition for AWS ECS. Click here in order to move on the console screen.
Select Create Cluster
then choose EC2 Linux Networking
,
click Next step
. There are three important things you need to set up as the image below.
Note:
key pair
which you have just created in previous steps.
Click Create new Task Definition
select EC2
Hit Add container
and config like the image below. The first time image we set null
temporary.
It will be updated by the image from ECR that was uploaded through Github action
.
Finally, we will create service
:
Setup Github action
- In the nextjs app we're going to create config file
.github/workflows/pipeline.yml
.
name: Deploy to Amazon ECS
on:
release:
types: [created]
env:
AWS_REGION: ap-northeast-1 # set this to your preferred AWS region, e.g. us-west-1
ECR_REPOSITORY: demo-deploy # set this to your Amazon ECR repository name
ECS_SERVICE: demo-service # set this to your Amazon ECS service name
ECS_CLUSTER: demo-cluster # set this to your Amazon ECS cluster name
ECS_TASK_DEFINITION:
.aws/task-definition.json # set this to the path to your Amazon ECS task definition
# file, e.g. .aws/task-definition.json
CONTAINER_NAME:
demo-container # set this to the name of the container in the
# containerDefinitions section of your task definition
defaults:
run:
shell: bash
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@13d241b293754004c80624b5567555c4a39ffbe3
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@aaf69d68aa3fb14c1d5a6be9ac61fe15b48453a2
- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
IMAGE_TAG: ${{ github.sha }}
run: |
# Build a docker container and
# push it to ECR so that it can
# be deployed to ECS.
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
- name: Fill in the new image ID in the Amazon ECS task definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@97587c9d45a4930bf0e3da8dd2feb2a463cf4a3a
with:
task-definition: ${{ env.ECS_TASK_DEFINITION }}
container-name: ${{ env.CONTAINER_NAME }}
image: ${{ steps.build-image.outputs.image }}
- name: Deploy Amazon ECS task definition
uses: aws-actions/amazon-ecs-deploy-task-definition@de0132cf8cdedb79975c6d42b77eb7ea193cf28e
with:
task-definition: ${{ steps.task-def.outputs.task-definition }}
service: ${{ env.ECS_SERVICE }}
cluster: ${{ env.ECS_CLUSTER }}
wait-for-service-stability: true
You only have to change some values in env:
that you just created in ECS
steps and a value for AWS_REGION
.
Create a file json
.aws/task-definition.json
. You need to go to theECS console
hitTask Definitions
and copy content fromJSON
tab then paste it totask-definition.json
.Create new repo on
Github
with namedemo-deploy
.
Then hitSettings
->Secrets
, create new secret for this repo with nameAWS_ACCESS_KEY_ID
andAWS_SECRET_ACCESS_KEY
that you created inSetup AWS ECS
step.
Release repo, confirm result
- We need to commit code to the remote repo. And trigger an action
release
thenGithub action
will deploy toAWS ECS
.
We need to come back
AWS ECS
, access theservice
we just created before.
Click id in
EC2 instance id
we will redirect toEC2 console
.
- Click
Open address
inPublic IPv4 DNS
we are able to view our app.
If it doesn't work, you will have to change https
-> http
or see the VPC ID in EC2 instance
and go to Security group
in order to add Inbound rules
.
I hope this guide was helpful for those of you looking to deploy a next app to AWS ECS. Feel free to refer source code .
Top comments (12)
I like the guide with the screenshots but for a Next.js app Amplify is so much more practical and cost effective. You literally just have to connect your repo and you are good to go.
Totally agree with you. It's so easy to deploy a next app with Amplify.😅
I have had that question, what's the difference to deploy on EC2 and Amplify?, in my job they have it on EC2, but I found many docs with Amplify. Thanks. Greate Article!
I think You can secure, compute your app with EC2. But using Amplify you can't do that. Amplify can be useful in case You want to deploy apps quickly.
What do you mean by secure?
I think You can restrict what IP can access to the resources that you have deployed to EC2!
I mean EC2 is not serverless for sure. You can also create EC2 snapshots.
I am really not sure the point you are trying to make here. If you want whitelist access to your serverless service you can do that as well. It will definitely not look like whitelisting access to an EC2, and they should not look alike because they are two different things.
I have an error on build step,
name unknown: The repository with name 'demo-deploy' does not exist in the registry with id '***'
, I don't know what I missing.Hmm, Did this error come from
github-action
's log or ECS's log ?From
github-action
's log, my repo is here github.com/alejomartinez8/deploy-demo maybe I don't understand the ECR configurationThis code is from my aws?
uses: aws-actions/configure-aws-credentials@13d241b293754004c80624b5567555c4a39ffbe3
I saw in this repo github.com/aws-actions/amazon-ecr-... they just useuses: aws-actions/amazon-ecr-login@v1
there are any difference?Did you create a repo in ECR envinronment?
I think the matter isn't
uses
's config, it's only the version of amazon-ecr-login that you would like to set up.Great article!