Containerizing and Deploying a React App: From Local to EC2
In this post, we'll walk through the process of containerizing a React application, pushing it to Docker Hub, and deploying it on an Amazon EC2 instance. We'll dive deep into each step, exploring best practices and uncovering some pro tips along the way.
Link to our Github Codebase
Docker image can be found on Docker Hub.
1. Containerizing the React App
Let's start by creating a Dockerfile for our React application. Here's the Dockerfile we'll use:
# Use an official Node runtime as the base image
FROM node:14-alpine
# Set the working directory in the container
WORKDIR /app
# Copy package.json and package-lock.json
COPY package*.json ./
# Install dependencies
RUN npm install
# Copy the rest of the application code
COPY . .
# Build the app
RUN npm run build
# Use nginx to serve the static files
FROM nginx:alpine
# Copy the build output to replace the default nginx contents
COPY --from=0 /app/build /usr/share/nginx/html
# Expose port 80
EXPOSE 80
# Start nginx
CMD ["nginx", "-g", "daemon off;"]
This Dockerfile uses a multi-stage build process. The first stage builds our React app, and the second stage sets up Nginx to serve the built files.
Pro Tip: Using Alpine-based images significantly reduces the size of your container, making it faster to push and pull from registries.
To build the Docker image, run:
docker build -t personal-site .
2. Pushing to Docker Hub
Before pushing our image, let's tag it with our Docker Hub username:
docker tag personal-site yourusername/personal-site:latest
Now, let's push it to Docker Hub:
docker push yourusername/personal-site:latest
Pro Tip: Consider using semantic versioning for your tags (e.g., v1.0.0) in addition to the 'latest' tag. This allows for easier rollbacks and version tracking.
3. Deploying on EC2
Now that our image is on Docker Hub, let's deploy it on an EC2 instance.
Launch an EC2 instance (I used an Amazon Linux 2 AMI).
SSH into your instance:
ssh -i "your-key.pem" ec2-user@your-ec2-public-dns
Install Docker on the EC2 instance:
Update your system packages:
sudo yum update -y
Install Docker:
For Amazon Linux 2023:
sudo yum install -y docker
Start the Docker service:
sudo service docker start
Enable Docker to start on boot:
sudo systemctl enable docker
Add your user (e.g., ec2-user) to the docker group to run Docker commands without sudo:
sudo usermod -a -G docker ec2-user
Log out and log back in for the group changes to take effect, or run:
newgrp docker
Verify the installation:
docker --version
To test if Docker is working correctly, you can run:
docker info
If you need docker-compose as well, you can install it using:
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
After installation, you can verify docker-compose is installed correctly by running:
docker-compose version
Remember to reboot your instance if you encounter any permission issues:
sudo reboot
These steps should get Docker up and running on your Amazon Linux EC2 instance
Log out and log back in to apply the group changes.
Pull and run your Docker image:
docker pull yourusername/personal-site:latest
docker run -d -p 80:80 yourusername/personal-site:latest
Pro Tip: Use Docker Compose for more complex deployments involving multiple containers or environment-specific configurations.
4. Security Considerations
Remember to configure your EC2 security group to allow inbound traffic on port 80. Also, consider setting up HTTPS using Let's Encrypt for production deployments.
Curiosity Spark: How would you implement blue-green deployments using this setup? Think about how you could use Docker tags and EC2 load balancers to achieve zero-downtime deployments.
5. Monitoring and Logging
For production deployments, consider integrating with AWS CloudWatch for monitoring and logging. You can use the awslogs log driver when running your container:
docker run -d -p 80:80 --log-driver=awslogs --log-opt awslogs-group=my-app-logs yourusername/personal-site:latest
Pro Tip: Implement health checks in your container to ensure your application is responding correctly. You can add a HEALTHCHECK instruction to your Dockerfile for this.
6. Optimizing for Production
To further optimize your containerized app for production:
Use multi-stage builds to keep your final image small.
Implement caching strategies for your Nginx server.
Consider using a Content Delivery Network (CDN) like AWS CloudFront for global distribution.
Curiosity Spark: How would you implement auto-scaling for your containerized app on EC2? Research EC2 Auto Scaling groups and how they can be used with containerized applications.
Conclusion
Containerizing and deploying a React app involves several steps, each with its own set of best practices and optimization opportunities. By following this guide, you've not only deployed your app but also set up a foundation for scalable, maintainable, and efficient cloud-native applications.
Subscribe to my newsletter
Read articles from Prathamesh directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by