Deploying a Next.js Application on Azure Container Apps: A Comprehensive Guide
In today’s rapidly evolving tech landscape, deploying applications in a scalable, reliable, and efficient manner is crucial. There are numerous options available for deploying web applications, each with its own set of benefits and trade-offs. Popular choices include traditional hosting providers, Platform-as-a-Service (PaaS) offerings like Vercel or Heroku, and container orchestration platforms like Kubernetes.
Azure Container Apps stands out as a robust option for deploying containerized applications, particularly for those looking to leverage the power of serverless architecture combined with containerization. Here are a few reasons why you might consider deploying your application as a container app on Azure:
In this guide, you will walk through the process of deploying a Dockerized Next.js application to Azure Container Apps. This approach combines the modern capabilities of Next.js with the powerful containerization and serverless deployment features of Azure Container Apps. By the end of this guide, you will have a fully deployed Next.js application running in Azure cloud.
In this section, you’ll create a new Next.js project to serve as the foundation for your deployment. You’ll use the npx create-next-app@latest
command to quickly set up a Next.js application and ensure it’s running correctly on our local machine. Ensure that you have NodeJS installed on your system before proceeding with the instructions.
npx create-next-app@latest
cd nextjs-container-app
code .
'use client'
import { useState } from 'react';
export default function Home() {
const [task, setTask] = useState('');
const [tasks, setTasks] = useState([]);
const addTask = () => {
if (task.trim() !== '') {
setTasks([...tasks, task]);
setTask('');
}
};
const removeTask = (index) => {
const newTasks = tasks.filter((_, i) => i !== index);
setTasks(newTasks);
};
return (
<div className="min-h-screen bg-gray-100 flex items-center justify-center">
<div className="bg-white p-8 rounded shadow-md w-full max-w-md">
<h1 className="text-2xl font-bold mb-4">To-Do List</h1>
<div className="flex mb-4">
<input
type="text"
value={task}
onChange={(e) => setTask(e.target.value)}
className="border p-2 rounded w-full"
placeholder="Add a new task"
/>
<button
onClick={addTask}
className="bg-blue-500 text-white p-2 rounded ml-2"
>
Add
</button>
</div>
<ul className="list-disc list-inside">
{tasks.map((task, index) => (
<li key={index} className="flex justify-between items-center mb-2">
<span>{task}</span>
<button
onClick={() => removeTask(index)}
className="bg-red-500 text-white p-1 rounded"
>
Remove
</button>
</li>
))}
</ul>
</div>
</div>
);
}
npm run dev
in the terminal.You’ve successfully created and run a basic Next.js application locally. This step ensures that your development environment is set up correctly and your application is ready for further development and deployment.
In this section, you’ll package your Next.js application into a Docker container. Docker enables you to create isolated environments for your applications, ensuring they run consistently across different environments, whether it’s your local machine, a staging server, or in production.
By containerizing your application, you encapsulate all dependencies, libraries, and configuration files, which simplifies deployment and scaling. This step is crucial for deploying your Next.js application on Azure Container Apps, providing a reliable and efficient way to manage and distribute your application.
By the end of this section, you’ll have a Docker image of your Next.js application ready for deployment. If it’s your first time working with Docker, consider reviewing this article to get yourself familiar with Docker CLI and Docker Desktop.
Before you begin, ensure you have the following prerequisites:
docker -v
Dockerfile
:Dockerfile
and add the following content: # Use the official Node.js image as the base image
FROM node:18-alpine
# Set the working directory inside the container
WORKDIR /app
# Copy package.json and package-lock.json to the working directory
COPY package*.json ./
# Install dependencies
RUN npm install
# Copy the rest of the application code to the working directory
COPY . .
# Build the Next.js application
RUN npm run build
# Expose port 3000 to the outside world
EXPOSE 3000
# Command to run the application
CMD ["npm", "start"]
.dockerignore
:.dockerignore
and add the following content: node_modules
npm-debug.log
Dockerfile
.dockerignore
Dockerignore file is used to ignore the common files and folder that must not be included while building the docker project. This ensures clean build process with little unnecessary files/folders.
docker build -t nextjs-container-app .
If you get the following error when building your Docker image: ERROR: error during connect: this error may indicate that the docker daemon is not running: Head “http://%2F%2F.%2Fpipe%2Fdocker_engine/_ping”: open //./pipe/docker_engine: The system cannot find the file specified. Make sure you have the Docker Desktop app running.
This command will build the Docker image and tag it as nextjs-container-app
docker run -p 3000:3000 nextjs-container-app
This command maps port 3000 on your host to port 3000 in the container.http://localhost:3000
. You should see your Next.js application running inside the Docker container.This container can now be deployed on Azure Container Apps or any other container orchestration platform. Next, you’ll move on to pushing this Docker image to Azure Container Registry (ACR) for deployment.
Now that you have Dockerized your Next.js application, the next step is to push the Docker image to Azure Container Registry (ACR). ACR is a managed Docker container registry service used for storing and managing private Docker container images. By pushing your Docker image to ACR, you ensure that it is securely stored and easily accessible for deployment on Azure services, including Azure Container Apps.
In this section, you’ll learn how to create an Azure Container Registry, push your Docker image to it, and prepare for the final deployment step. This will streamline your deployment process and enhance the security and management of your application images.
Before you begin, ensure you have the following prerequisites:
az login
This command will open a web browser window where you can sign in with your Azure account credentials. Once logged in, you can close the browser window.
az group create --name nextjsContainerApp --location eastus
A resource group is a container that holds related resources for an Azure solution. The location specifies where your resources will be physically stored.
az acr create --resource-group nextjsContainerApp --name containerapp832 --sku Basic
Replace containerapp832
with your desired registry name (it must be globally unique). The SKU Basic
is suitable for development and testing environments.
az acr login --name containerapp832
Wait for the command to run. You should see a Login Succeeded message in the terminal, indicating that you are authenticated with your ACR.
docker tag nextjs-container-app containerapp832.azurecr.io/nextjs-container-app:latest
This tags your local Docker image with the ACR login server name, preparing it for upload.
docker push containerapp832.azurecr.io/nextjs-container-app:latest
This command uploads your Docker image to ACR.
az acr repository list --name containerapp832 --output table
This command lists the repositories in your ACR, verifying that your Docker image has been successfully pushed. You should see your repository in the output.
Example output:
Result
--------------------
nextjs-container-app
By completing these steps using the Azure CLI, you have securely stored your Docker image in Azure Container Registry. This image is now ready for deployment on Azure Container Apps or any other Azure services, ensuring a smooth and efficient deployment process. In the next section, you’ll learn how to deploy this Docker image to Azure Container Apps.
Now that your Docker image is securely stored in Azure Container Registry (ACR), the next step is to deploy it to Azure Container Apps. Azure Container Apps is a managed serverless container service that enables you to deploy modern applications and microservices using containers. It provides built-in scaling, supports various programming languages and frameworks, and integrates seamlessly with other Azure services.
In this section, you’ll learn how to create and configure an Azure Container App, deploy your Docker image from ACR, and verify that your Next.js application is running in the cloud. This deployment process will ensure your application is scalable, reliable, and easy to manage.
az containerapp env create --name nextjsContainerAppEnv --resource-group nextjsContainerApp --location eastus
This command creates an environment for your Container App. Replace myContainerAppEnv
with your desired environment name.
az containerapp create --name my-container-app --resource-group nextjsContainerApp --environment nextjsContainerAppEnv --image containerapp832.azurecr.io/nextjs-container-app:latest --target-port 3000 --ingress 'external' --cpu 0.5 --memory 1.0Gi --registry-server <Login server> --registry-username <Username> --registry-password <password>
Replace <Login server>, <Username> and <password> with the details from Access keys page above.
This command creates a new Container App using the image from your ACR. Replace my-container-app
with your desired app name. The --target-port 3000
option specifies the port your application listens on.
az containerapp show --name my-container-app --resource-group nextjsContainerApp --query properties.configuration.ingress.fqdn
This command retrieves the fully qualified domain name (FQDN) of your Container App. You will use this URL to access your Next.js application.
In this guide, you walked through the entire process of deploying a Dockerized Next.js application to Azure Container Apps. Here’s a quick recap of what you covered:
By following these steps, you have successfully leveraged Azure’s robust cloud infrastructure to deploy a Next.js application using modern containerization practices. This setup not only simplifies the deployment process but also enhances the scalability and maintainability of your application.