Tutorial
Deploy Your First Application¶
In this tutorial, you’ll deploy a simple web application to your KUP6S cluster using ArgoCD. You’ll learn the GitOps workflow and how to expose your app via Traefik ingress.
What you’ll deploy¶
A simple “Hello KUP6S” web application that demonstrates:
ArgoCD Application manifest
Kubernetes Deployment and Service
Traefik Ingress with Let’s Encrypt SSL
Health checks and readiness probes
Step 1: Verify cluster access¶
Ensure you can access your cluster:
export KUBECONFIG=~/kup6s/kube-hetzner/kup6s_kubeconfig.yaml
kubectl get nodes
All nodes should show Ready status.
Step 2: Access ArgoCD UI¶
Get ArgoCD admin password¶
kubectl get secret -n argocd argocd-initial-admin-secret \
-o jsonpath='{.data.password}' | base64 -d
echo
Access ArgoCD¶
Open your browser to https://argocd.ops.kup6s.net
Note
If you haven’t configured DNS yet, add to your /etc/hosts:
YOUR_LOAD_BALANCER_IP argocd.ops.kup6s.net
Get your LB IP: kubectl get svc -n kube-system traefik -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
Login with:
Username:
adminPassword: (from command above)
Step 3: Create application namespace¶
kubectl create namespace hello-kup6s
Verify:
kubectl get namespace hello-kup6s
Step 4: Create application manifests¶
Create deployment manifest¶
Save as hello-deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-kup6s
namespace: hello-kup6s
labels:
app: hello-kup6s
spec:
replicas: 2
selector:
matchLabels:
app: hello-kup6s
template:
metadata:
labels:
app: hello-kup6s
spec:
containers:
- name: hello
image: nginx:1.27-alpine
ports:
- containerPort: 80
name: http
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 100m
memory: 128Mi
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
configMap:
name: hello-html
---
apiVersion: v1
kind: ConfigMap
metadata:
name: hello-html
namespace: hello-kup6s
data:
index.html: |
<!DOCTYPE html>
<html>
<head>
<title>Hello KUP6S</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.container {
text-align: center;
}
h1 {
font-size: 4em;
margin: 0;
}
p {
font-size: 1.5em;
}
</style>
</head>
<body>
<div class="container">
<h1>🚀 Hello KUP6S!</h1>
<p>Your first app is running on Kubernetes</p>
<p>Pod: <strong id="hostname"></strong></p>
</div>
<script>
fetch('/hostname')
.then(r => r.text())
.then(h => document.getElementById('hostname').textContent = h)
.catch(() => document.getElementById('hostname').textContent = window.location.hostname);
</script>
</body>
</html>
Create service manifest¶
Save as hello-service.yaml:
apiVersion: v1
kind: Service
metadata:
name: hello-kup6s
namespace: hello-kup6s
labels:
app: hello-kup6s
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app: hello-kup6s
Create ingress manifest¶
Save as hello-ingress.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-kup6s
namespace: hello-kup6s
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
spec:
ingressClassName: traefik
tls:
- hosts:
- hello.sites.kup6s.com
secretName: hello-kup6s-tls
rules:
- host: hello.sites.kup6s.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: hello-kup6s
port:
number: 80
Step 5: Deploy the application¶
Apply manifests¶
kubectl apply -f hello-deployment.yaml
kubectl apply -f hello-service.yaml
kubectl apply -f hello-ingress.yaml
Watch the deployment¶
kubectl get pods -n hello-kup6s -w
Wait until both pods show Running and 2/2 ready.
Press Ctrl+C to stop watching.
Step 6: Verify the deployment¶
Check pods¶
kubectl get pods -n hello-kup6s
Expected output:
NAME READY STATUS RESTARTS AGE
hello-kup6s-xxxxxxxxxx-xxxxx 1/1 Running 0 1m
hello-kup6s-xxxxxxxxxx-xxxxx 1/1 Running 0 1m
Check service¶
kubectl get svc -n hello-kup6s
Check ingress¶
kubectl get ingress -n hello-kup6s
You should see an IP address assigned.
Check certificate¶
kubectl get certificate -n hello-kup6s
Wait until READY shows True (may take 1-2 minutes for Let’s Encrypt).
Step 7: Access your application¶
Configure DNS¶
Point hello.sites.kup6s.com to your load balancer IP.
Or for testing, add to /etc/hosts:
YOUR_LOAD_BALANCER_IP hello.sites.kup6s.com
Open in browser¶
Visit: https://hello.sites.kup6s.com
You should see your “Hello KUP6S!” page with a valid SSL certificate! 🎉
Step 8: Create ArgoCD Application (GitOps way)¶
Now let’s manage this app the GitOps way with ArgoCD.
Create Git repository¶
mkdir hello-kup6s-gitops
cd hello-kup6s-gitops
git init
Commit manifests¶
cp ../hello-*.yaml .
git add .
git commit -m "Initial hello-kup6s application"
Push to Git server¶
# Push to your Git server (GitHub, GitLab, etc.)
git remote add origin git@your-git-server:your-org/hello-kup6s.git
git push -u origin main
Create ArgoCD Application¶
Save as argocd-app.yaml:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: hello-kup6s
namespace: argocd
spec:
project: default
source:
repoURL: https://your-git-server/your-org/hello-kup6s.git
targetRevision: main
path: .
destination:
server: https://kubernetes.default.svc
namespace: hello-kup6s
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Apply it:
kubectl apply -f argocd-app.yaml
Watch ArgoCD sync¶
Go to ArgoCD UI and you’ll see your application syncing automatically!
Step 9: Test GitOps workflow¶
Make a change¶
Edit hello-deployment.yaml and change replicas:
spec:
replicas: 3 # Changed from 2
Commit and push¶
git add hello-deployment.yaml
git commit -m "Scale to 3 replicas"
git push
Watch ArgoCD¶
Within 3 minutes, ArgoCD will detect the change and automatically sync!
Check pods:
kubectl get pods -n hello-kup6s
You should now see 3 pods running! 🚀
Congratulations! 🎉¶
You’ve successfully deployed your first application using GitOps!
What you’ve learned¶
How to create Kubernetes Deployments, Services, and Ingress
How to configure Traefik ingress with Let’s Encrypt SSL
How to use ArgoCD for GitOps deployments
How the automated sync and self-heal features work
What’s next?¶
Monitoring basics - Learn to monitor your app with Grafana and Loki
Create S3 bucket - Add object storage to your app
Query logs - Find and analyze application logs
Troubleshooting¶
Pods stuck in Pending¶
kubectl describe pod -n hello-kup6s <pod-name>
Check for resource constraints or storage issues.
Certificate not ready¶
kubectl describe certificate -n hello-kup6s hello-kup6s-tls
kubectl logs -n cert-manager -l app=cert-manager
Ingress not accessible¶
# Check Traefik logs
kubectl logs -n kube-system -l app.kubernetes.io/name=traefik
# Verify ingress
kubectl get ingress -n hello-kup6s -o yaml
ArgoCD not syncing¶
Check the repository URL is correct
Verify ArgoCD has access to your Git repository
Check ArgoCD application status:
kubectl get application -n argocd hello-kup6s -o yaml