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.
Prerequisites
Section titled “Prerequisites”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 three objects
Section titled “The three objects”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.
apiVersion: apps/v1kind: Deploymentmetadata: name: demospec: 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: v1kind: Servicemetadata: name: demospec: # 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/v1kind: Ingressmetadata: name: demo annotations: cert-manager.io/cluster-issuer: letsencrypt-prodspec: 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: 80Apply and check
Section titled “Apply and check”-
Apply the file in your namespace.
Terminal window kubectl apply -n qro-demo -f demo.yaml -
Watch the pods start.
RunningwithREADY 1/1, and the rest can follow.Terminal window kubectl get pods -n qro-demo -w -
Wait for the certificate. cert-manager requests it as soon as the Ingress is created; allow a minute before
READYswitches toTrue.Terminal window kubectl get ingress,certificate -n qro-demo -
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. |
When I’m done
Section titled “When I’m done”Nothing stops and nothing deletes itself. The namespace takes everything it contains with it.
kubectl delete namespace qro-demoSave what matters first, manifests and container images, since no backup is guaranteed. Your manifests belong in a Git repository, not just in the cluster.
What isn’t self-service
Section titled “What isn’t self-service”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.