# Deploy a Kubernetes application

The most common way to deploy an application on a plain Kubernetes is to use a deployment. This does not yet make use of Knative, but only standard Kubernetes resources.

Here you can see an example of such a deployment, with all the additional parts included you need to make it work out of the box:

# cf-env-demo-app.yaml

---
# define our namespace "cf-env" where we place this standard Kubernetes deployment / app
apiVersion: v1
kind: Namespace
metadata:
  labels:
    app: cf-env
    namespace.kubernetes.io/name: cf-env
  name: cf-env
  namespace: cf-env

---
# service account is optional, but we create one because it's good practice for Kubernetes "deployment"'s
apiVersion: v1
kind: ServiceAccount
metadata:
  name: cf-env
  namespace: cf-env

---
# the Kubernetes service that points to our app / deployment. It exposes container port 8080 to port 80 cluster-local wide.
apiVersion: v1
kind: Service
metadata:
  name: cf-env
  namespace: cf-env
spec:
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: cf-env
    app.kubernetes.io/component: app
    app.kubernetes.io/instance: cf-env
    app.kubernetes.io/name: cf-env

---
# this Ingress defines external access / routing to our app / deployment.
# it registers the route "cf-env.demo.kube-plus.cloud" and directs all HTTP(S) to the service specified above.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    # these annotations will give us automatic Lets-Encrypt integration with valid public certificates
    cert-manager.io/cluster-issuer: letsencrypt-contour
    ingress.kubernetes.io/force-ssl-redirect: "true"
    kubernetes.io/ingress.class: contour # "contour" is the default ingress class you should use
    kubernetes.io/tls-acme: "true"
  name: cf-env
  namespace: cf-env
spec:
  tls:
  - hosts:
    - cf-env.demo.kube-plus.cloud # hostname / route we want our app to be
    secretName: cf-env-tls
  rules:
  - host: cf-env.demo.kube-plus.cloud # hostname / route we want our app to be
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: cf-env
            port:
              number: 80

---
# finally our actual app deployment.
# it's just a simple HTTP app listening on port 8080.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cf-env
  namespace: cf-env
spec:
  replicas: 2
  revisionHistoryLimit: 5
  selector:
    matchLabels:
      app: cf-env
      app.kubernetes.io/component: app
      app.kubernetes.io/instance: cf-env
      app.kubernetes.io/name: cf-env
  template:
    metadata:
      labels:
        app: cf-env
        app.kubernetes.io/component: app
        app.kubernetes.io/instance: cf-env
        app.kubernetes.io/name: cf-env
    spec:
      serviceAccountName: cf-env
      securityContext:
        fsGroup: 1007
        runAsGroup: 1007
        runAsUser: 1007
      containers:
      - name: cf-env
        # here we specifiy which image we want to run. for this example its the simple "cf-env" app
        image: index.docker.io/jamesclonk/cf-env@sha256:19ec75c211a2b05b5d9b78b5204dcf9b6d3240b275ffa35c42065d945d7f6508
        securityContext:
          allowPrivilegeEscalation: false
          privileged: false
        env:
        - name: PORT
          value: "8080"
        ports:
        - containerPort: 8080
        readinessProbe:
          httpGet:
            path: /
            port: 8080
        resources:
          limits:
            cpu: 100m
            memory: 64Mi
          requests:
            cpu: 50m
            memory: 32Mi

You can deploy this full-fledged example application via the kubectl like this:

$ kubectl apply -f cf-env-demo-app.yaml

Here's how it should now look on the Kubernetes cluster:

$ kubectl -n cf-env get all,ing

NAME                          READY   STATUS    RESTARTS   AGE
pod/cf-env-85c8ff55f5-4m97t   2/2     Running   0          29m
pod/cf-env-85c8ff55f5-rpnxc   2/2     Running   0          29m

NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/cf-env   ClusterIP   10.100.156.35   <none>        80/TCP    29m

NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/cf-env   2/2     2            2           29m

NAME                                DESIRED   CURRENT   READY   AGE
replicaset.apps/cf-env-85c8ff55f5   2         2         2       29m

NAME                               CLASS    HOSTS                              ADDRESS                                                                      PORTS     AGE
ingress.networking.k8s.io/cf-env   <none>   cf-env.demo.kube-plus.cloud   a33e7d797ce6249d9b7b51891b9286da-1068130475.eu-central-1.elb.amazonaws.com   80, 443   29m

Afterwards you can access the application on the URL that was specified by the Ingress definition. Simply point your browser here: cf-env.demo.kube-plus.cloud (opens new window)

Last Updated: 9/12/2022, 7:31:38 PM