Skip to content

Commit e856155

Browse files
committed
added kube
1 parent 4be9734 commit e856155

6 files changed

Lines changed: 419 additions & 45 deletions

File tree

.github/workflows/test.yml

Lines changed: 161 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
1-
name: Deploy Vite React App
1+
# .github/workflows/cicd-pipeline.yml
2+
name: Complete CI/CD Pipeline
23

34
on:
45
push:
5-
branches:
6-
- main
6+
branches: [ main, develop ]
7+
pull_request:
8+
branches: [ main, develop ]
9+
workflow_dispatch:
10+
11+
env:
12+
IMAGE_NAME: vite-react-app
13+
NAMESPACE: production
714

815
jobs:
9-
deploy:
16+
test:
17+
name: Run Tests
1018
runs-on: self-hosted
1119

1220
steps:
@@ -16,57 +24,165 @@ jobs:
1624
- name: Setup Node.js
1725
uses: actions/setup-node@v4
1826
with:
19-
node-version: '18'
27+
node-version: '20'
2028
cache: 'npm'
2129

2230
- name: Install dependencies
2331
run: npm ci
2432

25-
- name: Build project
26-
run: npm run build
27-
env:
28-
NODE_ENV: production
33+
- name: Run linter
34+
run: npm run lint || echo "Linting step skipped"
35+
continue-on-error: true
36+
37+
- name: Run tests
38+
run: npm test
39+
40+
- name: Generate coverage report
41+
run: npm test -- --coverage
42+
continue-on-error: true
43+
44+
- name: Upload coverage
45+
uses: actions/upload-artifact@v4
46+
if: always()
47+
with:
48+
name: coverage-report
49+
path: coverage/
50+
retention-days: 30
51+
52+
build-and-deploy:
53+
name: Build & Deploy to MicroK8s
54+
runs-on: self-hosted
55+
needs: test
56+
if: github.event_name == 'push'
57+
58+
steps:
59+
- name: Checkout code
60+
uses: actions/checkout@v4
61+
62+
- name: Set image tag
63+
id: image-tag
64+
run: |
65+
TAG="${{ env.IMAGE_NAME }}:${{ github.sha }}"
66+
echo "tag=$TAG" >> $GITHUB_OUTPUT
67+
echo "Image tag: $TAG"
68+
69+
- name: Build Docker image in MicroK8s
70+
run: |
71+
# Build image with Docker and import to MicroK8s
72+
docker build -t ${{ steps.image-tag.outputs.tag }} .
73+
docker save ${{ steps.image-tag.outputs.tag }} > /tmp/app-image.tar
74+
microk8s ctr image import /tmp/app-image.tar
75+
rm /tmp/app-image.tar
76+
77+
# Tag as latest
78+
docker tag ${{ steps.image-tag.outputs.tag }} ${{ env.IMAGE_NAME }}:latest
79+
docker save ${{ env.IMAGE_NAME }}:latest > /tmp/app-image-latest.tar
80+
microk8s ctr image import /tmp/app-image-latest.tar
81+
rm /tmp/app-image-latest.tar
82+
83+
- name: Verify image in MicroK8s
84+
run: |
85+
echo "Images available in MicroK8s:"
86+
microk8s ctr images ls | grep ${{ env.IMAGE_NAME }}
87+
88+
- name: Setup kubectl
89+
run: |
90+
mkdir -p ~/.kube
91+
microk8s config > ~/.kube/config
92+
93+
- name: Create namespace if not exists
94+
run: |
95+
microk8s kubectl create namespace ${{ env.NAMESPACE }} --dry-run=client -o yaml | microk8s kubectl apply -f -
96+
97+
- name: Update deployment manifest with new image
98+
run: |
99+
sed -i "s|image:.*${{ env.IMAGE_NAME }}.*|image: ${{ steps.image-tag.outputs.tag }}|g" k8s/deployment.yaml
29100
30-
- name: Backup existing deployment
101+
- name: Apply Kubernetes manifests
31102
run: |
32-
DEPLOY_DIR="/var/www/your-app"
33-
if [ -d "$DEPLOY_DIR" ]; then
34-
BACKUP_DIR="${DEPLOY_DIR}.backup.$(date +%Y%m%d_%H%M%S)"
35-
echo "Creating backup at $BACKUP_DIR"
36-
sudo cp -r "$DEPLOY_DIR" "$BACKUP_DIR"
37-
ls -dt ${DEPLOY_DIR}.backup.* | tail -n +6 | xargs -r sudo rm -rf
38-
fi
103+
microk8s kubectl apply -f k8s/ --namespace=${{ env.NAMESPACE }}
39104
40-
- name: Deploy to server
105+
- name: Wait for rollout
41106
run: |
42-
DEPLOY_DIR="/var/www/your-app"
43-
echo "Deploying to $DEPLOY_DIR"
44-
sudo mkdir -p "$DEPLOY_DIR"
45-
sudo rm -rf "$DEPLOY_DIR"/*
46-
sudo cp -r ./dist/* "$DEPLOY_DIR"/
47-
sudo chown -R www-data:www-data "$DEPLOY_DIR"
48-
sudo chmod -R 755 "$DEPLOY_DIR"
107+
microk8s kubectl rollout status deployment/vite-react-app \
108+
--namespace=${{ env.NAMESPACE }} \
109+
--timeout=5m
49110
50111
- name: Verify deployment
51112
run: |
52-
DEPLOY_DIR="/var/www/your-app"
53-
if [ -f "$DEPLOY_DIR/index.html" ]; then
54-
echo "✅ Deployment successful!"
55-
echo "Files deployed:"
56-
ls -lah "$DEPLOY_DIR"
57-
else
58-
echo "❌ Deployment failed - index.html not found"
59-
exit 1
60-
fi
61-
62-
- name: Deployment summary
63-
if: always()
113+
echo "Pods:"
114+
microk8s kubectl get pods --namespace=${{ env.NAMESPACE }}
115+
echo ""
116+
echo "Services:"
117+
microk8s kubectl get services --namespace=${{ env.NAMESPACE }}
118+
echo ""
119+
echo "Deployment:"
120+
microk8s kubectl get deployment --namespace=${{ env.NAMESPACE }}
121+
122+
- name: Get service URL
123+
id: service-url
124+
run: |
125+
NODE_PORT=$(microk8s kubectl get service vite-react-app-service -n ${{ env.NAMESPACE }} -o jsonpath='{.spec.ports[0].nodePort}')
126+
NODE_IP=$(microk8s kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}')
127+
echo "url=http://$NODE_IP:$NODE_PORT" >> $GITHUB_OUTPUT
128+
echo "Application URL: http://$NODE_IP:$NODE_PORT"
129+
130+
- name: Deployment Summary
131+
run: |
132+
NODE_PORT=$(microk8s kubectl get service vite-react-app-service -n ${{ env.NAMESPACE }} -o jsonpath='{.spec.ports[0].nodePort}')
133+
NODE_IP=$(microk8s kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}')
134+
135+
echo "## Deployment Status :rocket:" >> $GITHUB_STEP_SUMMARY
136+
echo "" >> $GITHUB_STEP_SUMMARY
137+
echo "**Namespace:** ${{ env.NAMESPACE }}" >> $GITHUB_STEP_SUMMARY
138+
echo "**Image:** ${{ steps.image-tag.outputs.tag }}" >> $GITHUB_STEP_SUMMARY
139+
echo "**Commit:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
140+
echo "**URL:** http://$NODE_IP:$NODE_PORT" >> $GITHUB_STEP_SUMMARY
141+
echo "" >> $GITHUB_STEP_SUMMARY
142+
echo "### Pods Status" >> $GITHUB_STEP_SUMMARY
143+
echo '```' >> $GITHUB_STEP_SUMMARY
144+
microk8s kubectl get pods --namespace=${{ env.NAMESPACE }} >> $GITHUB_STEP_SUMMARY
145+
echo '```' >> $GITHUB_STEP_SUMMARY
146+
147+
- name: Cleanup old images
148+
run: |
149+
# Keep only the last 5 images
150+
microk8s ctr images ls | grep ${{ env.IMAGE_NAME }} | grep -v latest | awk '{print $1}' | sort -r | tail -n +6 | xargs -r microk8s ctr images rm || true
151+
152+
rollback:
153+
name: Rollback on Failure
154+
runs-on: self-hosted
155+
needs: build-and-deploy
156+
if: failure()
157+
158+
steps:
159+
- name: Setup kubectl
160+
run: |
161+
mkdir -p ~/.kube
162+
microk8s config > ~/.kube/config
163+
164+
- name: Rollback deployment
165+
run: |
166+
microk8s kubectl rollout undo deployment/vite-react-app \
167+
--namespace=${{ env.NAMESPACE }}
168+
169+
- name: Wait for rollback
170+
run: |
171+
microk8s kubectl rollout status deployment/vite-react-app \
172+
--namespace=${{ env.NAMESPACE }} \
173+
--timeout=3m
174+
175+
- name: Verify rollback
176+
run: |
177+
microk8s kubectl get pods --namespace=${{ env.NAMESPACE }}
178+
179+
- name: Rollback Summary
64180
run: |
65-
echo "=========================================="
66-
echo "Deployment Summary"
67-
echo "=========================================="
68-
echo "Branch: ${{ github.ref_name }}"
69-
echo "Commit: ${{ github.sha }}"
70-
echo "Triggered by: ${{ github.actor }}"
71-
echo "Status: ${{ job.status }}"
72-
echo "=========================================="
181+
echo "## Rollback Completed :warning:" >> $GITHUB_STEP_SUMMARY
182+
echo "" >> $GITHUB_STEP_SUMMARY
183+
echo "Deployment has been rolled back to previous version" >> $GITHUB_STEP_SUMMARY
184+
echo "" >> $GITHUB_STEP_SUMMARY
185+
echo "### Current Pods" >> $GITHUB_STEP_SUMMARY
186+
echo '```' >> $GITHUB_STEP_SUMMARY
187+
microk8s kubectl get pods --namespace=${{ env.NAMESPACE }} >> $GITHUB_STEP_SUMMARY
188+
echo '```' >> $GITHUB_STEP_SUMMARY

k8s/deployment.yaml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# k8s/deployment.yaml
2+
apiVersion: apps/v1
3+
kind: Deployment
4+
metadata:
5+
name: vite-react-app
6+
labels:
7+
app: vite-react-app
8+
spec:
9+
replicas: 2
10+
strategy:
11+
type: RollingUpdate
12+
rollingUpdate:
13+
maxSurge: 1
14+
maxUnavailable: 0
15+
selector:
16+
matchLabels:
17+
app: vite-react-app
18+
template:
19+
metadata:
20+
labels:
21+
app: vite-react-app
22+
spec:
23+
containers:
24+
- name: vite-react-app
25+
image: vite-react-app:latest
26+
imagePullPolicy: Never # Use local image, don't pull from registry
27+
ports:
28+
- containerPort: 80
29+
name: http
30+
resources:
31+
requests:
32+
memory: "128Mi"
33+
cpu: "100m"
34+
limits:
35+
memory: "256Mi"
36+
cpu: "200m"
37+
livenessProbe:
38+
httpGet:
39+
path: /health
40+
port: 80
41+
initialDelaySeconds: 10
42+
periodSeconds: 10
43+
timeoutSeconds: 3
44+
failureThreshold: 3
45+
readinessProbe:
46+
httpGet:
47+
path: /health
48+
port: 80
49+
initialDelaySeconds: 5
50+
periodSeconds: 5
51+
timeoutSeconds: 3
52+
failureThreshold: 3

k8s/hpa.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# k8s/hpa.yaml (optional - Horizontal Pod Autoscaler)
2+
apiVersion: autoscaling/v2
3+
kind: HorizontalPodAutoscaler
4+
metadata:
5+
name: vite-react-app-hpa
6+
spec:
7+
scaleTargetRef:
8+
apiVersion: apps/v1
9+
kind: Deployment
10+
name: vite-react-app
11+
minReplicas: 2
12+
maxReplicas: 5
13+
metrics:
14+
- type: Resource
15+
resource:
16+
name: cpu
17+
target:
18+
type: Utilization
19+
averageUtilization: 70
20+
- type: Resource
21+
resource:
22+
name: memory
23+
target:
24+
type: Utilization
25+
averageUtilization: 80

k8s/service.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
apiVersion: v1
2+
kind: Service
3+
metadata:
4+
name: vite-react-app-service
5+
labels:
6+
app: vite-react-app
7+
spec:
8+
type: NodePort
9+
selector:
10+
app: vite-react-app
11+
ports:
12+
- port: 80
13+
targetPort: 80
14+
nodePort: 30080
15+
protocol: TCP
16+
name: http

0 commit comments

Comments
 (0)