say.farewell.cloud admin

K8s Learning: Step 06 — Deploy the Application

06 — Deploy the Application

Script: 06_deploy.sh · Creates Deployment + Service + Ingress

Takes the deploy template, substitutes env vars, copies to VM, applies it. Creates (or updates) three Kubernetes resources. Your app goes live with HTTPS.


Resource 1: The Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: blog-farewell-cloud
spec:
  replicas: 1
  selector:
    matchLabels:
      app: blog-farewell-cloud
  template:
    metadata:
      labels:
        app: blog-farewell-cloud
    spec:
      containers:
        - name: blog-farewell-cloud
          image: docker.io/library/blog-farewell-cloud:latest
          imagePullPolicy: Never
          ports:
            - containerPort: 8000
          volumeMounts:
            - name: externaldata
              mountPath: /externaldata
      volumes:
        - name: externaldata
          hostPath:
            path: /externaldata/say.farewell.cloud
            type: DirectoryOrCreate
  • Labels & selectors — Deployment creates pods with label app: blog-farewell-cloud; Service finds them by this label
  • imagePullPolicy: Never — use locally loaded image
  • volumeMounts + hostPath — persistent data on VM filesystem, survives pod restarts
  • DirectoryOrCreate — creates the host directory if it doesn't exist

Resource 2: The Service

apiVersion: v1
kind: Service
metadata:
  name: blog-farewell-cloud
spec:
  selector:
    app: blog-farewell-cloud
  ports:
    - port: 80
      targetPort: 8000

Stable internal address. Cluster consumers talk to it on port 80; it forwards to the pod's port 8000. Inside cluster: http://blog-farewell-cloud:80.


Resource 3: The Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: blog-farewell-cloud
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: traefik
  tls:
    - hosts:
        - say.farewell.cloud
      secretName: blog-farewell-cloud-tls
  rules:
    - host: say.farewell.cloud
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: blog-farewell-cloud
                port:
                  number: 80
  • cert-manager.io/cluster-issuer — triggers automatic TLS
  • tls.secretName — cert-manager stores cert here; Traefik reads it
  • rules — hostname → Service routing

Certificate: First Deploy vs. Subsequent

ScenarioWhat Happens
First deployNo Secret exists → ACME challenge → cert obtained (30–90 sec)
Subsequent deploysSecret valid → cert-manager does nothing → instant HTTPS
After ~60 dayscert-manager auto-renews, no deploy needed

The Script Actions

1. Template substitution

DEPLOY_YAML_CONTENT=$(cat deploy_template.yaml)
DEPLOY_YAML_CONTENT=${DEPLOY_YAML_CONTENT//{K3S_UNIQUE_DOCKER_IMAGE_NAME}/$K3S_UNIQUE_DOCKER_IMAGE_NAME}
# ... same for other variables

2. Copy and apply

scp $DEPLOY_YAML_PATH $K3S_SSH_USER@$K3S_SSH_HOSTNAME:~
ssh ... "sudo k3s kubectl apply -f ~/deploy.yaml"

kubectl apply is declarative — "make reality match this YAML."

3. Restart the deployment

ssh ... "sudo k3s kubectl rollout restart deployment/$K3S_UNIQUE_DOCKER_IMAGE_NAME"

Forces a new pod since the tag is always :latest. Old pod terminates only after new one is running (rolling update).


The Complete Flow

Deploy pipeline
← Back to homepage