You are currently viewing Mastering Nuxt.js Deployment: From Setup to Load Balancing and Orchestration on AWS ECS with GitHub Actions

Mastering Nuxt.js Deployment: From Setup to Load Balancing and Orchestration on AWS ECS with GitHub Actions

INTRODUCTION:

Deploying a Nuxt.js app using AWS ECS, ECR, and GitHub Actions brings a ton of benefits that make your life easier, especially when it comes to scaling, automating tasks, and managing everything smoothly. Here’s why you’d want to go this route:

1. Containers and Scaling Made Simple

Containers: By running your app in a Docker container on AWS ECS, you’re ensuring the environment is consistent—no more “it worked on my machine” problems. Whatever runs locally will run just as smoothly in production.

Scaling: As traffic to your app increases, ECS makes it super easy to scale. You can add more containers without needing to mess around with complex configurations.

2. Automation with GitHub Actions

CI/CD Pipeline: GitHub Actions helps automate the entire deployment process. Whenever you push changes to GitHub, it can automatically build, test, and deploy your app. This cuts down on manual work and makes your deployments faster and more reliable.

3. High Availability with Load Balancing

AWS Load Balancer: Adding a load balancer ensures your app stays up even if traffic spikes or a container crashes. It automatically distributes traffic between your ECS containers, so if one goes down, users won’t even notice—they’ll be routed to a healthy instance instead.

4. Version Control and Easy Rollbacks

Docker Image Management: By using AWS ECR, you can store all versions of your app’s Docker images. This gives you peace of mind—if a deployment goes south, you can easily roll back to an earlier version.

5. Cost-Effective and Flexible

Pay for What You Use: ECS is pay-as-you-go, so you don’t need to maintain a big, expensive infrastructure for peak traffic that may only come occasionally. You scale up or down as needed, keeping costs down.

Flexible Deployment Strategies: You can also use things like blue/green deployments, which means you can roll out updates with less risk of downtime or failure.

6. Tight Security

IAM Permissions: AWS makes security easier with fine-grained control over who and what can access your services through IAM roles. This ensures your pipeline and services operate securely, with the least amount of access needed to get the job done.

In short, deploying a Nuxt.js app this way sets you up for success with an approach that’s scalable, cost-effective, and secure. Plus, by automating key parts of the process, you get faster and more reliable deployments—ideal for handling growth and keeping downtime to a minimum.

INSTRUCTIONS:

Part I: Create and Set Up a Nuxt.js Application and GitHub Repository

Step 1: Install Prerequisites

Ensure you have the following installed on your machine:

  1. Node.js: Download and install.
  2. npm (Node Package Manager): Comes with Node.js.
  3. Git: Download and install.

Step 2: Create a New Nuxt.js Application

  1. Open a terminal, navigate to the folder where you want your project, and run the following command:
npx create-nuxt-app <NameOfApplication>
  1. When prompted, choose the following options (Or desired options):
  • Project name: <NameOfApplication>
  • Programming language: JavaScript
  • Package manager: npm
  • UI framework: None
  • Nuxt.js modules: Select none or the ones you need.
  • Linting tools: Select none or the ones you need.
  • Testing framework: None (for a simple hello world app).
  • Rendering mode: Single Page App.
  • Deployment target: Server (Node.js hosting).
  • Development tools: Select your preferred tools (Prettier is recommended).

After selecting the options, Nuxt.js will automatically set up the app and create the project structure.


Step 3: Understand the Directory Structure

Nuxt.js creates an optimized directory structure for both small and large projects. Here’s a breakdown:

<NameOfApplication>/
├── assets/            # Uncompiled assets like CSS, images, etc.
├── components/        # Vue.js components
├── layouts/           # Layouts for different pages
├── middleware/        # Middleware for handling logic before rendering pages
├── pages/             # Nuxt.js pages (automatically routed)
├── plugins/           # JavaScript plugins
├── static/            # Static files served at the root of the app
├── store/             # Vuex store (state management) files
├── nuxt.config.js     # Nuxt.js configuration file
└── package.json       # Project metadata and dependencies

Key Folders:

  • pages/: Contains page components. Each .vue file is automatically routed.
  • components/: Reusable Vue components used in the pages.
  • assets/: CSS, Sass, images, and fonts.
  • layouts/: Application layouts to wrap your pages.
  • nuxt.config.js: The main configuration file for your Nuxt.js app.

Step 4: Create a “Hello World” Page

  1. Inside the pages/ folder, create an index.vue file and add the following:
<template>
  <div>
    <h1>Hello World from Nuxt.js!</h1>
  </div>
</template>

<script>
export default {
  head() {
    return {
      title: 'Hello World'
    }
  }
}
</script>
  1. Run the app locally:
npm run dev

Visit http://localhost:3000 in your browser to see the “Hello World” message.


Step 5: Set Up a GitHub Repository

  1. Create a repository on GitHub (e.g., NameOfApplication).
  • Do not initialize it with a README, .gitignore, or license (Nuxt will generate these files).
  1. In your project folder, connect the local repository to GitHub:
# Initialize Git (Careful when copy and paste. Formatting might be off)
git init --initial-branch=main

# If I want all new repos to have "main" as the default branch: Advised if you're using Github.
git config --global init.defaultBranch main

# Add all files
git add .

# Commit the changes
git commit -m "Initial commit - Nuxt.js Hello World app"

# Add the GitHub repository as a remote
git remote add origin https://github.com/<your-username>/<NameOfApplication>.git

# Push the code to GitHub
git push -u origin main

Replace <your-username> with your GitHub username and <NameOfApplication> with your app’s name.


Step 6: Run the application.

It’s a good practice to add a README.md file. Create it in the root of your project and add basic information:

# Nuxt.js Hello World App

This is a simple Nuxt.js Hello World app built with Vue.js.

## Running the app locally

1. Install dependencies:

npm install

2. Run the app in development mode:

npm run dev

Visit the app at `http://localhost:3000`.

Summary of Part I:

  1. Create a Nuxt.js app using npx create-nuxt-app.
  2. Understand the directory structure:
  • pages/: for routes and main pages.
  • components/: for reusable Vue components.
  • nuxt.config.js: the main configuration file.
  1. Create a “Hello World” page in pages/index.vue.
  2. Initialize a GitHub repository:
  • Create a repo on GitHub.
  • Push your code to GitHub.
  1. Add a README.md for project documentation.

Part II: Deploy a Nuxt.js Application Using GitHub Actions, AWS ECS, ECR, EC2 (Load Balancer) and Route 53

Step 1: Create Security Groups

You’ll need two security groups: one for the load balancer and one for the ECS service.

1.1 Load Balancer Security Group

  1. Go to EC2 > Security Groups in the AWS Console.
  2. Create a security group and name it loadbalancersecuritygroup-<app-name>.
  3. Inbound rules: Allow HTTP (port 80) and HTTPS (port 443) from the internet.
  4. Outbound rules: Allow all outbound traffic to the ECS tasks.

1.2 ECS Task Security Group

  1. Go to EC2 > Security Groups and create a security group named ecstasksecuritygroup-<app-name>.
  2. Inbound rules: Allow traffic from the load balancer security group on port 3000.
  3. Outbound rules: Allow all outbound traffic.

Step 2: Set Up AWS ECR

  1. Go to ECR in the AWS Console and create a repository.
  2. Name it repository-<app-name>, and keep the default settings.
  3. Copy the ECR repository URI.

Step 3: Write Dockerfile for Nuxt.js

In your Nuxt.js project, create a Dockerfile:

# Use a lightweight Node.js base image
FROM node:16-alpine

# Create app directory
WORKDIR /app/krickstacks

# Copy dependency definitions
COPY package*.json ./

# Install dependencies
RUN apk add --no-cache --virtual .gyp python3 make g++ \
  && npm install \
  && apk del .gyp

# Copy all application files
COPY . .

# Build the application
RUN npm run build

# Expose the port Nuxt.js runs on
EXPOSE 3000

# Ensure Nuxt.js listens on all IPs
ENV HOST 0.0.0.0

# Avoid reaching system limit for file watchers
ENV CHOKIDAR_USEPOLLING=true

# Start the app
CMD ["npm", "run", "start"]

Step 4: Create an ECS Cluster

  1. Go to ECS > Clusters in the AWS Console.
  2. Click Create Cluster, choose Networking only (Fargate), and name the cluster (e.g., cluster-<app-name>).

Step 5: Create an ECS Task Definition

  1. Go to ECS > Task Definitions and click Create New Task Definition.
  2. Choose Fargate as the launch type and name it taskdefinition-<app-name>.
  3. Set CPU and Memory:
  • CPU: 2 vCPU
  • Memory: 4 GB
  1. Add a container:
  • Container Name: container-<app-name>
  • Image URI: The ECR repository URI with :latest appended.
  • Port Mappings: Set container port to 3000.
  1. Attach the ECS Task Execution Role and click Create.

Step 6: Create Target Group

  1. Go to EC2 > Target Groups and click Create Target Group.
  2. Choose IP Addresses and name it targetgroup-<app-name>.
  3. Set Protocol to HTTP and Port to 3000.
  4. Configure Health Check:
  • Path: / or /health.
  • Increase timeout and interval values.

Step 7: Create Load Balancer

  1. Go to EC2 > Load Balancers and click Create Load Balancer.
  2. Choose Application Load Balancer.
  3. Name the load balancer (e.g., loadbalancer-<app-name>).
  4. Set Scheme to Internet-facing.
  5. Choose two availability zones (e.g., us-east-1a and us-east-1b).
  6. Attach the load balancer security group.
  7. Add a listener for HTTP on port 80, forwarding traffic to the target group.
  8. Click Create.

Step 8: Create Deploy.yml and Update nuxt.config.js files

  1. Go to nuxt application and create directory .github/workflows
  2. Create deploy.yml file
name: Deploy to AWS ECS

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v2

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: <YOUR-AWS-ACCESS-ID>
        aws-secret-access-key: <YOUR-AWS-ACCESS-KEY>
        aws-region: us-east-1

    - name: Log in to Amazon ECR
      id: login-ecr
      run: |
        aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin <your_aws_account_id>.dkr.ecr.us-east-1.amazonaws.com

    - name: Build, tag, and push Docker image to Amazon ECR
      run: |
        docker build -t repository-krickstacks .
        docker tag repository-krickstacks:latest <your_aws_account_id>.dkr.ecr.us-east-1.amazonaws.com/repository-krickstacks:latest
        docker push <your_aws_account_id>.dkr.ecr.us-east-1.amazonaws.com/repository-krickstacks:latest

    - name: Deploy to Amazon ECS
      run: |
        aws ecs update-service --cluster cluster-krickstacks --service service-krickstacks --force-new-deployment
  • Update nuxt.config.js file
export default {
  serverMiddleware: [
    {
      path: '/health',
      handler: (req, res) => {
        res.writeHead(200, { 'Content-Type': 'text/plain' });
        res.end('OK');
      }
    }
  ],
  ...
  existing code...
}
  • Deploy addition and changes to Github
  • Got to Github and click Actions tab in repository and watch the deploy happen.
  • Check AWS ECR for container deployment.

Step 9: Create ECS Service

  1. Go to ECS > Services and click Create Service.
  2. Choose Fargate as the launch type.
  3. Select the task definition and cluster created earlier.
  4. Make sure to delete subnets not chosen in load balancer
  5. Add created load balancer
  6. Set the number of tasks to 1.

Step 10: Create Route53 Subdomain Record

  1. Go to Route53 > Hosted Zones > Your Domain and click Create Record.
  2. Choose A record
  3. Choose Alias
  4. Choose us-east-1
  5. Choose create load balancer
  6. Click Create Record

SUMMARY:

Deploying a Nuxt.js app using AWS ECS, ECR, and GitHub Actions has a lot of benefits, especially in terms of scalability, automation, and reliability. Here’s a quick summary of why this method is so effective:

1. Consistent Environment: Running the app in Docker containers on AWS ECS ensures everything works the same across all environments—no more “works on my machine” issues.

2. Easy Scaling: As your app traffic increases, ECS allows you to easily scale up by adding more containers without dealing with complicated configurations.

3. Automation with GitHub Actions: GitHub Actions handles the build, test, and deployment process automatically. Push your code, and it’s deployed. This saves time and reduces manual errors.

4. High Availability: Using an AWS load balancer, you ensure your app stays up even if traffic spikes or containers fail. The load balancer directs traffic to healthy containers without downtime.

5. Version Control & Rollbacks: Docker images are stored in AWS ECR, allowing you to track versions and easily roll back if something goes wrong with the latest deployment.

6. Cost-Effective & Flexible: ECS operates on a pay-as-you-go model, so you’re only charged for the resources you use, which is great for managing costs during different traffic peaks.

7. Enhanced Security: AWS IAM lets you control who has access to what, ensuring the security of your app and deployment pipeline.

In short, deploying this way ensures your Nuxt.js app is scalable, highly available, cost-effective, and secure, while automating a lot of the tedious tasks.

Leave a Reply