<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[devopsbyashish]]></title><description><![CDATA[devopsbyashish]]></description><link>https://devopsbyashish.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1593680282896/kNC7E8IR4.png</url><title>devopsbyashish</title><link>https://devopsbyashish.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sun, 20 Sep 2026 04:40:12 GMT</lastBuildDate><atom:link href="https://devopsbyashish.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How I Set Up an EKS Cluster with Flask, GitHub Actions CI/CD, and ALB Ingress on AWS — A Complete Guide
]]></title><description><![CDATA[Introduction
If you've been trying to deploy a containerized application on AWS using Kubernetes, you've probably hit a wall somewhere — whether it's configuring the ALB Ingress Controller, setting up]]></description><link>https://devopsbyashish.hashnode.dev/how-i-set-up-an-eks-cluster-with-flask-github-actions-ci-cd-and-alb-ingress-on-aws-a-complete-guide</link><guid isPermaLink="true">https://devopsbyashish.hashnode.dev/how-i-set-up-an-eks-cluster-with-flask-github-actions-ci-cd-and-alb-ingress-on-aws-a-complete-guide</guid><category><![CDATA[github-actions]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[EKS]]></category><category><![CDATA[Devops]]></category><category><![CDATA[GitHub]]></category><dc:creator><![CDATA[Ashish Joseph]]></dc:creator><pubDate>Sat, 04 Apr 2026 07:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/69d0b4e3e466e2b7621b594d/3231f1bb-f5d2-4e00-be6a-7af44464983f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<hr />
<h2>Introduction</h2>
<p>If you've been trying to deploy a containerized application on AWS using Kubernetes, you've probably hit a wall somewhere — whether it's configuring the ALB Ingress Controller, setting up ECR, or getting GitHub Actions to push images automatically.</p>
<p>In this guide, I'll walk you through exactly how I built a production-style EKS setup with:</p>
<ul>
<li><p>A Flask application running in EKS</p>
</li>
<li><p>Docker image stored in Amazon ECR</p>
</li>
<li><p>GitHub Actions CI/CD pipeline for automated deployments</p>
</li>
<li><p>ALB Ingress Controller via Helm</p>
</li>
<li><p>Horizontal Pod Autoscaler (HPA)</p>
</li>
</ul>
<p>This isn't theory. I built this on AWS (ap-south-1) and it works.</p>
<hr />
<h2>Architecture Overview</h2>
<pre><code class="language-plaintext">GitHub Push
    ↓
GitHub Actions
    ↓
Docker Build → Push to ECR
    ↓
kubectl apply → EKS Cluster
    ↓
ALB Ingress → Flask App (2 t3.medium nodes)
</code></pre>
<hr />
<h2>Prerequisites</h2>
<ul>
<li><p>AWS CLI configured</p>
</li>
<li><p>kubectl installed</p>
</li>
<li><p>eksctl installed</p>
</li>
<li><p>Helm installed</p>
</li>
<li><p>Docker installed</p>
</li>
<li><p>GitHub account</p>
</li>
</ul>
<hr />
<h2>Step 1: Create the EKS Cluster</h2>
<pre><code class="language-bash">eksctl create cluster \
  --name flask-cluster \
  --region ap-south-1 \
  --nodegroup-name standard-workers \
  --node-type t3.medium \
  --nodes 2 \
  --nodes-min 1 \
  --nodes-max 3 \
  --managed
</code></pre>
<p>This takes about 15–20 minutes. Go grab a chai ☕</p>
<p>Verify:</p>
<pre><code class="language-bash">kubectl get nodes
</code></pre>
<hr />
<h2>Step 2: Create ECR Repository</h2>
<pre><code class="language-bash">aws ecr create-repository \
  --repository-name flask-app \
  --region ap-south-1
</code></pre>
<p>Note down the repository URI — you'll need it in GitHub Actions.</p>
<hr />
<h2>Step 3: Dockerize Your Flask App</h2>
<p><strong>app.py</strong></p>
<pre><code class="language-python">from flask import Flask
app = Flask(__name__)

@app.route('/')
def home():
    return "Hello from EKS! 🚀"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
</code></pre>
<p><strong>Dockerfile</strong></p>
<pre><code class="language-dockerfile">FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["python", "app.py"]
</code></pre>
<hr />
<h2>Step 4: Install ALB Ingress Controller via Helm</h2>
<pre><code class="language-bash"># Add EKS chart repo
helm repo add eks https://aws.github.io/eks-charts
helm repo update

# Install ALB controller
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
  -n kube-system \
  --set clusterName=flask-cluster \
  --set serviceAccount.create=false \
  --set serviceAccount.name=aws-load-balancer-controller
</code></pre>
<hr />
<h2>Step 5: GitHub Actions CI/CD Pipeline</h2>
<p>Create <code>.github/workflows/deploy.yml</code>:</p>
<pre><code class="language-yaml">name: Deploy to EKS

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-south-1

      - name: Login to ECR
        run: |
          aws ecr get-login-password --region ap-south-1 | \
          docker login --username AWS --password-stdin ${{ secrets.ECR_REGISTRY }}

      - name: Build and push Docker image
        run: |
          docker build -t flask-app .
          docker tag flask-app:latest ${{ secrets.ECR_REGISTRY }}/flask-app:latest
          docker push ${{ secrets.ECR_REGISTRY }}/flask-app:latest

      - name: Deploy to EKS
        run: |
          aws eks update-kubeconfig --name flask-cluster --region ap-south-1
          kubectl apply -f k8s/
          kubectl rollout restart deployment/flask-deployment
</code></pre>
<hr />
<h2>Step 6: Set Up HPA (Horizontal Pod Autoscaler)</h2>
<pre><code class="language-bash">kubectl autoscale deployment flask-deployment \
  --cpu-percent=50 \
  --min=2 \
  --max=5
</code></pre>
<p>This automatically scales your pods when CPU goes above 50%.</p>
<hr />
<h2>Common Errors I Hit (and Fixed)</h2>
<p><strong>Error 1:</strong> <code>exec format error</code> <strong>when pod starts</strong> → You built the Docker image on ARM (M1 Mac). Fix:</p>
<pre><code class="language-bash">docker buildx build --platform linux/amd64 -t flask-app .
</code></pre>
<p><strong>Error 2: ALB not provisioning</strong> → Missing IAM permissions for the load balancer controller service account. Attach the correct policy from AWS docs.</p>
<p><strong>Error 3:</strong> <code>ImagePullBackOff</code> → ECR login expired in the node. Re-attach the <code>AmazonEC2ContainerRegistryReadOnly</code> policy to the node IAM role.</p>
<hr />
<h2>Cost Breakdown (ap-south-1)</h2>
<table>
<thead>
<tr>
<th>Resource</th>
<th>Monthly Cost</th>
</tr>
</thead>
<tbody><tr>
<td>2x t3.medium nodes</td>
<td>~$60</td>
</tr>
<tr>
<td>ALB</td>
<td>~$20</td>
</tr>
<tr>
<td>ECR storage</td>
<td>~$1</td>
</tr>
<tr>
<td><strong>Total</strong></td>
<td><strong>~$81/month</strong></td>
</tr>
</tbody></table>
<p>💡 Tip: Delete the cluster when not in use to save costs:</p>
<pre><code class="language-bash">eksctl delete cluster --name flask-cluster --region ap-south-1
</code></pre>
<hr />
<h2>Conclusion</h2>
<p>That's a complete EKS setup with CI/CD from scratch. Once this pipeline is running, every <code>git push</code> to main automatically builds, pushes, and deploys your app — zero manual steps.</p>
<p>If you found this helpful, follow my blog for more real-world AWS and DevOps guides.</p>
<hr />
<p><em>Connect with me:</em> <em>GitHub: github.com/Ashishjo10</em> <em>Blog: devopsbyashish.hashnode.dev</em></p>
]]></content:encoded></item></channel></rss>