Deploying an application to Kubernetes involves creating a set of resource objects that describe the desired state of the application — Kubernetes continuously works to make the actual state match this desired state. The core resources for most applications are: a Deployment (manages the desired number of running pod replicas and handles rolling updates), a Service (provides stable DNS and load-balanced access to pods), a ConfigMap (stores non-sensitive configuration data), and a Secret (stores sensitive credentials). This guide covers deploying a full-stack web application to Kubernetes on RHEL 9 using these resources, configuring health checks, performing rolling updates, and scaling workloads.
Prerequisites
- Kubernetes cluster (kubeadm or k3s) running on RHEL 9
kubectlconfigured with cluster access
Step 1 — Create a Namespace and Secret
# Create an isolated namespace for the application
kubectl create namespace myapp
# Create a Secret for database credentials (base64-encoded automatically)
kubectl create secret generic db-credentials
--from-literal=DB_PASSWORD='SecurePass123!'
--from-literal=DB_USER='appuser'
-n myapp
Step 2 — Deployment Manifest
# /tmp/myapp-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # Extra pods during update
maxUnavailable: 0 # Zero downtime
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:1.0.0
ports:
- containerPort: 3000
envFrom:
- secretRef:
name: db-credentials
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
Step 3 — Service Manifest
# /tmp/myapp-service.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: myapp
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 3000
type: ClusterIP # Use LoadBalancer for cloud, NodePort for bare-metal
Step 4 — Apply and Monitor the Deployment
kubectl apply -f /tmp/myapp-deployment.yaml
kubectl apply -f /tmp/myapp-service.yaml
# Monitor rollout
kubectl rollout status deployment/myapp -n myapp
# View running pods
kubectl get pods -n myapp -o wide
# View logs
kubectl logs -l app=myapp -n myapp --tail=50
Step 5 — Scale and Update
# Scale horizontally
kubectl scale deployment myapp --replicas=5 -n myapp
# Rolling update — change image version
kubectl set image deployment/myapp myapp=myapp:1.1.0 -n myapp
kubectl rollout status deployment/myapp -n myapp
# Roll back if the new version has issues
kubectl rollout undo deployment/myapp -n myapp
kubectl rollout history deployment/myapp -n myapp
Conclusion
Deploying to Kubernetes on RHEL 9 requires understanding three key concepts: Deployments manage pod lifecycles and rolling updates; Services provide stable network access to pods regardless of which physical pods are running; and resource requests/limits prevent a single misbehaving application from starving other workloads on the same cluster. The readinessProbe is critical — without it, Kubernetes sends traffic to pods that have started but are not yet ready to serve requests (during app initialisation), causing request failures during rolling updates.
Next steps: How to Install Helm on RHEL 9, How to Configure Kubernetes Persistent Volumes on RHEL 9, and How to Set Up Kubernetes Ingress on RHEL 9.