Skip to content

Notes05-Application Lifecycle

Application Lifecycle

Rollouts and rollbacks, process arguments, configuration, multi-container Pods, probes, and the HorizontalPodAutoscaler.

Updated Oct 1, 2026

Application Lifecycle Quick Notes





Rolling updates and rollbacks


A Deployment stores the Pod template. Editing the template (image, env, labels in the template) creates a new ReplicaSet. The old ReplicaSet is scaled down as the new one becomes Ready.

Strategy field

Default idea

Effect

type: RollingUpdate

Default

Old and new Pods overlap

maxUnavailable

Often 25%

How many old Pods may be down during the rollout

maxSurge

Often 25%

How many extra Pods may exist above replicas

type: Recreate

No overlap

All old Pods terminate, then new ones start


bash
kubectl set image deployment/web nginx=nginx:1.28
kubectl rollout status deployment/web
kubectl rollout history deployment/web
kubectl rollout undo deployment/web
kubectl rollout undo deployment/web --to-revision=2
kubectl rollout pause deployment/web
kubectl rollout resume deployment/web


  • History needs revisionHistoryLimit above 0 (default is 10). kubectl rollout undo scales the previous ReplicaSet back up.
  • A paused Deployment ignores further template changes until rollout resume.
  • kubectl rollout restart deployment/web bumps a template annotation so Pods are replaced even when the image tag did not change. Useful for picking up a ConfigMap that was edited in place.
  • Record the cause: kubectl annotate deployment/web kubernetes.io/change-cause="bump nginx" so rollout history shows a comment.
  • Stuck rollout: New Pods are not Ready (bad probe, image pull, pending PVC). The old ReplicaSet stays. kubectl describe pod on a new Pod, then fix the template. Progress deadline is progressDeadlineSeconds (default 600). Past that, the Deployment condition is Progressing=False.


Command and args

Containers start from the image’s entrypoint and cmd. Kubernetes overrides those with two fields:

Kubernetes field

Overrides

Role

command

Image entrypoint

The executable

args

Image cmd

Arguments to that executable

  • Only args: The image entrypoint runs, with your arguments.
  • Only command: Your executable runs, with the image’s cmd as arguments (if the image set one).
  • Both: Your executable and your arguments. The image cmd is ignored.



yaml
containers:
- name: worker
  image: busybox:1.36
  command: ["sh", "-c"]
  args: ["echo hello && sleep 3600"]


Docker’s ENTRYPOINT / CMD names are easy to mix up with these fields. In a Pod manifest the names are command and args. kubectl explain pod.spec.containers.command confirms the current wording.


Environment variables


yaml
env:
- name: COLOR
  value: blue
- name: POD_NAME
  valueFrom:
    fieldRef:
      fieldPath: metadata.name
- name: CPU_REQUEST
  valueFrom:
    resourceFieldRef:
      resource: requests.cpu
- name: PASSWORD
  valueFrom:
    secretKeyRef:
      name: db
      key: password
- name: CACHE
  valueFrom:
    configMapKeyRef:
      name: web-config
      key: cache_size
envFrom:
- configMapRef:
    name: web-config
- secretRef:
    name: db


  • env: You pick keys. A missing ConfigMap or Secret key prevents the container from starting (CreateContainerConfigError).
  • envFrom: Every key in the object becomes an environment variable. A key that is not a valid env name is skipped.
  • fieldRef: Pod metadata (metadata.name, metadata.namespace, spec.nodeName, status.podIP).
  • Order: Env vars are fixed when the container starts. Editing a ConfigMap does not change env vars in an already running container. Restart the Pod.


ConfigMaps

A ConfigMap holds non-secret configuration: property files, flags, small text.


bash
kubectl create configmap web-config \
  --from-literal=cache_size=10 \
  --from-file=nginx.conf=./nginx.conf
kubectl create configmap web-env --from-env-file=app.env


Two ways to consume it:

  • Environment (env / envFrom) — copied at start.
  • Volume — files mounted into the container. Updates to the ConfigMap eventually appear in the mounted files (kubelet sync). The process must re-read the file, or you restart the Pod.



yaml


  • subPath mounts do not receive ConfigMap updates. Mount the directory if the app should see changes.
  • immutable: true locks the object. Replace it by creating a new ConfigMap and pointing the Pod at the new name.
  • Size: ConfigMaps are API objects, meant for small config (the etcd object limit is about 1 MiB). Large binaries belong on a volume.


Secrets

Same consumption model as ConfigMaps (env or volume), for credentials.

Type

Contents

Opaque

Arbitrary keys. Default.

kubernetes.io/tls

tls.crt and tls.key

kubernetes.io/dockerconfigjson

Registry auth, usually named via imagePullSecrets

kubernetes.io/service-account-token

Legacy token Secret. Prefer projected ServiceAccount tokens.


bash
kubectl create secret generic db \
  --from-literal=password='s3cr3t' \
  --from-file=username=./user.txt
kubectl create secret tls web-tls --cert=tls.crt --key=tls.key
kubectl create secret docker-registry regcred \
  --docker-server=ghcr.io --docker-username=me --docker-password='token'


  • Encoding: Values in YAML data: are base64, which hides them from a casual glance and is trivial to reverse (echo <value> | base64 -d). stringData: accepts plain text and is encoded on write.
  • Encryption at rest is a separate apiserver feature (encryption configuration against etcd). Creating a Secret does not turn that on.
  • tmpfs: Secret volumes are stored in memory on the node, not in a world-readable disk file under the container’s writable layer.
  • RBAC: Reading Secrets is a different verb from reading ConfigMaps. view and many app roles should not have get on Secrets unless you mean it.


Multi-container Pods

Containers in one Pod share localhost and any volumes you mount into more than one of them.

Pattern

What the extra container does

Sidecar

Helps the main container: ships logs from a shared volume, refreshes certificates, runs a mesh proxy

Adapter

Rewrites the main container’s output into the format the cluster expects

Ambassador

Proxies outbound calls (localhost:port in the app, the ambassador opens the remote connection)


yaml
volumes:
- name: logs
  emptyDir: {}
containers:
- name: app
  image: myapp:1.2
  volumeMounts:
  - name: logs
    mountPath: /var/log/app
- name: shipper
  image: fluent-bit:3.0
  volumeMounts:
  - name: logs
    mountPath: /var/log/app
    readOnly: true


  • Scheduling unit: Requests and limits of all containers are summed. The Pod is placed only if the node can hold the total.
  • Probes and logs are per container. A sidecar in CrashLoop does not automatically restart the main container, and it does mark the Pod not-Ready if its own readiness probe fails.


Init containers

  • Run to completion, in order, before app containers. The next init starts only after the previous one exits 0.
  • Uses: Wait for a dependency, run a migration, chown a volume, render config into an emptyDir.
  • Failure: A failing init container restarts according to the Pod restartPolicy (default Always restarts it). App containers stay stopped until every init has succeeded.
  • Resources: The scheduler uses the maximum of (the highest init container request, the sum of app container requests), because inits and apps do not run at the same time. Still declare requests on inits so a huge init cannot surprise the node.
  • Network and volumes: Same Pod IP and the same volume names.



yaml
initContainers:
- name: wait-db
  image: busybox:1.36
  command: ["sh", "-c", "until nc -z db 5432; do sleep 2; done"]


restartPolicy: Never on a bare Pod leaves a failed init in Init:Error / Init:CrashLoopBackOff without an infinite retry storm. Deployments still replace Pods according to their own rules.


Probes

Probe

Failure means

startupProbe

The process is still starting. Liveness and readiness wait. Failure restarts the container. Give slow JVMs a high failureThreshold.

livenessProbe

The process is wedged. Kubelet restarts the container.

readinessProbe

The process should not receive Service traffic. Kubelet removes the Pod from EndpointSlices. The container is left running.

Handlers: httpGet, tcpSocket, grpc, exec.


yaml
readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 2
  periodSeconds: 5
  failureThreshold: 3
livenessProbe:
  httpGet:
    path: /live
    port: 8080
  periodSeconds: 10
startupProbe:
  httpGet:
    path: /live
    port: 8080
  periodSeconds: 5
  failureThreshold: 30


  • A liveness probe that shares a dependency with the app (it fails whenever the database blips) causes a restart loop. Readiness is the right probe for “I cannot serve yet.”
  • No readiness probe: The Pod is added to the Service as soon as the container is started, including during a crash loop’s brief uptime.
  • startupProbe + slow start: Set liveness failureThreshold low, and let startup cover the boot window (periodSeconds × failureThreshold).


Self-healing, stacked

  1. Process dies → kubelet restarts the container (restartPolicy: Always on Deployment Pods).
  2. Liveness fails → kubelet restarts the container.
  3. Readiness fails → Service stops sending traffic; the process keeps running.
  4. Pod is deleted or the node dies → ReplicaSet / Deployment creates a replacement.
  5. Too much CPU demand → HPA adds Pods (below).


HorizontalPodAutoscaler

HPA changes the replicas of a Deployment, ReplicaSet, or StatefulSet from a metric. It needs the Metrics API (metrics-server).


bash
kubectl autoscale deployment web --cpu-percent=70 --min=2 --max=10
kubectl get hpa



yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70


  • Utilization is usage divided by the CPU request. Pods with no CPU request cannot scale on CPU utilization.
  • Stabilization: HPA waits between scale events so a spike does not flap the replica count. kubectl describe hpa shows the current metric and the last scale time.
  • Cluster size: HPA adds Pods. It does not add nodes. Pending Pods after a scale-up mean nothing schedulable has enough free CPU and memory for the requests. Adding nodes is a separate controller (Cluster Autoscaler or Karpenter) watching for those Pending Pods.


Official docs