Once your Kubernetes cluster is running on RHEL 8, the next essential skill is deploying and managing application workloads using the two most fundamental resource types: Deployments and Services. A Deployment describes the desired state of your application pods and ensures that the specified number of replicas are always running, performing rolling updates and self-healing when pods fail. A Service provides a stable network endpoint that routes traffic to whichever pods are currently healthy. This tutorial covers writing both YAML manifests, applying them with kubectl, and using the rollout commands to manage application updates safely.
Prerequisites
- A running Kubernetes cluster on RHEL 8 (kubeadm or k3s)
kubectlconfigured and pointing at the cluster- Basic familiarity with YAML syntax
- A container image to deploy — this tutorial uses the public
nginx:1.25image
Step 1 — Write a Deployment Manifest
Create a file named deployment.yaml that describes a three-replica nginx Deployment. The selector must match the labels in the pod template.
cat < deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
cpu: "100m"
memory: "64Mi"
limits:
cpu: "250m"
memory: "128Mi"
EOF
Step 2 — Apply the Deployment and Verify Pods
Apply the manifest with kubectl apply and use get and describe to confirm the pods reach the Running state.
kubectl apply -f deployment.yaml
# Watch pods start up
kubectl get pods -l app=nginx -w
# Check deployment status
kubectl get deployments
# Describe a pod for detailed event information
kubectl describe pod -l app=nginx
# Check rollout status
kubectl rollout status deployment/nginx-deployment
Step 3 — Write a Service Manifest
Create a Service to expose the Deployment. The example below creates a NodePort Service so you can reach the application from outside the cluster by hitting any node IP on the assigned port. Replace NodePort with ClusterIP for internal-only access or LoadBalancer if your cluster has a cloud load-balancer provider.
cat < service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
type: NodePort
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
EOF
kubectl apply -f service.yaml
# Confirm the service exists and note the NodePort
kubectl get services nginx-service
Step 4 — Inspect Running Resources
Use kubectl get and kubectl describe to examine the state of all the resources created so far.
# List pods, deployments, and services in one command
kubectl get pods,deployments,services -l app=nginx
# Show detailed information about the deployment
kubectl describe deployment nginx-deployment
# Show endpoints registered behind the service
kubectl describe service nginx-service
# Test the application via NodePort (replace NODE_IP with the node address)
curl http://NODE_IP:30080
Step 5 — Perform a Rolling Update
Update the nginx image to nginx:1.26 by editing the manifest and re-applying it. Kubernetes performs the update pod-by-pod to maintain availability.
# Update the image in the manifest (or use kubectl set image directly)
kubectl set image deployment/nginx-deployment nginx=nginx:1.26
# Monitor the rolling update
kubectl rollout status deployment/nginx-deployment
# View the rollout history
kubectl rollout history deployment/nginx-deployment
Step 6 — Roll Back a Deployment
If a new image introduces a regression, roll back to the previous revision instantly without downtime.
# Undo the last rollout (returns to revision 1)
kubectl rollout undo deployment/nginx-deployment
# Roll back to a specific revision number
kubectl rollout undo deployment/nginx-deployment --to-revision=1
# Confirm the rollback completed
kubectl rollout status deployment/nginx-deployment
kubectl get pods -l app=nginx
Conclusion
You have deployed a multi-replica application to Kubernetes on RHEL 8, exposed it through a NodePort Service, and practiced safe rolling updates with one-command rollback. The Deployment controller continuously reconciles actual state with the desired state defined in your manifest, restarting crashed pods and ensuring the correct number of replicas are always running. Service selectors decouple your network endpoint from the underlying pod instances, so clients always have a stable address regardless of which pods are running or which node they land on. These two primitives form the backbone of nearly every application running on Kubernetes.
Next steps: Configure Kubernetes Persistent Volumes on RHEL 8, Install Helm on RHEL 8, and Install Kubernetes with kubeadm on RHEL 8.