Deploying a Static Website on Kubernetes (K3s) on AWS EC2 — Part 1
Introduction
Container orchestration has become a fundamental part of modern application deployment, with Kubernetes serving as the de facto standard for managing containerized workloads. For this project, I deployed a static landing page on a K3s cluster running on an AWS EC2 instance to build a lightweight and production-style deployment environment.
This article covers the first stage of the deployment, including creating a Kubernetes Deployment, exposing the application internally using a ClusterIP Service, and verifying that the workload is running successfully.
Project Overview
The objective of this phase was to deploy a static application inside a Kubernetes cluster while keeping it accessible only within the cluster.
At this stage, the architecture looks like this:
AWS EC2 Instance
│
K3s
│
Kubernetes Deployment
│
Landing Page Pod
│
ClusterIP ServiceExternal access, reverse proxy configuration, domain mapping, and HTTPS will be covered in the upcoming parts of this series.
Creating the Deployment
The deployment process begins by creating a Kubernetes Deployment resource.
A Deployment is responsible for managing Pods and maintaining the desired state of an application. If a Pod becomes unavailable or is terminated, Kubernetes automatically creates a replacement to ensure service continuity.
For this project, I configured a Deployment with a single replica of the landing page container.
After applying the deployment manifest, I verified the deployment using the following command:
kubectl get deployments -n devThe output confirmed that the Deployment was successfully created and available.
To verify that the application container was running successfully, I checked the Pods:
kubectl get pods -n devThe Pod entered the Running state, confirming that the application had been deployed successfully.
Exposing the Application with a ClusterIP Service
Deploying the application is only one part of the process. Since Pod IP addresses are temporary and may change whenever a Pod is recreated, accessing the application directly through a Pod IP isn’t a reliable approach.
Get Muhammad Saqib’s stories in your inbox
Join Medium for free to get updates from this writer.
To provide a stable internal endpoint, I created a ClusterIP Service.
The Service routes traffic to the appropriate Pod based on label selectors, allowing workloads inside the Kubernetes cluster to communicate with the application without depending on changing Pod IP addresses.
The Service was verified using:
kubectl get svc -n devThe output confirmed that the ClusterIP Service had been created successfully.
Verifying the Deployment
At this point, the deployment consisted of three primary Kubernetes resources:
- A Deployment responsible for managing the application’s lifecycle.
- A running Pod hosting the landing page.
- A ClusterIP Service providing stable internal networking.
Each component was verified using Kubernetes CLI commands to ensure the application was deployed correctly and operating as expected.
Key Takeaways
This deployment highlights a few important Kubernetes concepts:
- Deployments automate Pod management and maintain the desired application state.
- Pods are ephemeral, making Services essential for stable communication.
- ClusterIP Services provide internal connectivity between workloads inside the cluster.
- Verifying Kubernetes resources after deployment helps ensure the application is healthy before exposing it externally.
Conclusion
The application is now successfully deployed inside the Kubernetes cluster and can be accessed internally through a ClusterIP Service.
In the next part of this series, I’ll deploy NGINX as a reverse proxy to expose the application externally and lay the foundation for custom domain integration and HTTPS.
Thank you for reading!
If you’ve worked with Kubernetes in production or have a different approach to exposing workloads, I’d be interested to hear your thoughts and experiences.






