Skip to content

Deploy and expose an application

Three objects are all it takes to put an application online here: what runs it, what addresses it inside the cluster, and what exposes it to the outside. The TLS certificate takes care of itself.

kubectl connected to the cluster and a namespace of your own. If not, ten minutes: connect to the cluster. The examples use the qro-demo namespace and the qro-demo.k8s.qiminfo-lab.ch hostname; replace them with your own.

You can pick any hostname under *.k8s.qiminfo-lab.ch: the wildcard DNS already resolves it, there’s no record to request. Just one constraint: a name a colleague has taken can’t be taken twice. Use your trigram followed by the topic.

The Deployment runs the containers, the Service gives them a stable address inside the cluster, and the Ingress publishes the whole thing on the wildcard domain. The cert-manager.io/cluster-issuer annotation triggers the certificate request.

demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo
spec:
replicas: 1
selector:
matchLabels:
app: demo
template:
metadata:
labels:
app: demo
spec:
containers:
- name: demo
image: nginxinc/nginx-unprivileged:stable
ports:
- containerPort: 8080
# A shared cluster: what you don't reserve stays available
# to others, and what you don't cap can get in their way.
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 500m
memory: 256Mi
---
apiVersion: v1
kind: Service
metadata:
name: demo
spec:
# Neither LoadBalancer nor NodePort: the cluster's Ingress is the way in.
type: ClusterIP
selector:
app: demo
ports:
- port: 80
targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- qro-demo.k8s.qiminfo-lab.ch
secretName: qro-demo-tls
rules:
- host: qro-demo.k8s.qiminfo-lab.ch
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: demo
port:
number: 80
  1. Apply the file in your namespace.

    Terminal window
    kubectl apply -n qro-demo -f demo.yaml
  2. Watch the pods start. Running with READY 1/1, and the rest can follow.

    Terminal window
    kubectl get pods -n qro-demo -w
  3. Wait for the certificate. cert-manager requests it as soon as the Ingress is created; allow a minute before READY switches to True.

    Terminal window
    kubectl get ingress,certificate -n qro-demo
  4. Open the URL. The redirect from HTTP is handled by the Ingress.

    Terminal window
    curl -I https://qro-demo.k8s.qiminfo-lab.ch

What catches you out on the first deployment

Section titled “What catches you out on the first deployment”
The symptom What’s going on
The certificate stays pending kubectl describe certificate -n qro-demo tells you why it failed. Most often a hostname outside *.k8s.qiminfo-lab.ch, spelled differently in tls and in rules, or a secretName already taken in the namespace.
404 returned by the Ingress The request reached the cluster but no rule matches: a hostname different from the one in the manifest, or a forgotten ingressClassName: nginx.
502 or 503 The Ingress found its rule, but not the application behind it. The Service’s selector doesn’t match the Deployment’s labels, or the container isn’t listening on targetPort.
The pod keeps restarting kubectl logs, then kubectl describe pod. Typically an image that wants to write to a file system it doesn’t have access to, or bind to a privileged port.
ImagePullBackOff The cluster doesn’t have your registry credentials. Publish the image to a public registry, or create a docker-registry secret in your namespace and reference it in imagePullSecrets.
The service stays Pending as a LoadBalancer That Service type isn’t the way in here. Switch back to ClusterIP and expose through the Ingress.
The data disappeared on redeployment A pod is ephemeral, and so is its disk. Check what kubectl get storageclass offers before relying on a persistent volume, and don’t count on any backup.

Nothing stops and nothing deletes itself. The namespace takes everything it contains with it.

Terminal window
kubectl delete namespace qro-demo

Save what matters first, manifests and container images, since no backup is guaranteed. Your manifests belong in a Git repository, not just in the cluster.

Anything beyond your namespace: installing an operator or CRDs, adding a certificate issuer, a hostname outside the wildcard domain, or reserving more resources than the few pods of a test. Write to lab@qiminfo.ch describing what you want to test and for how long.