The review flagged `:latest` as a critical issue, and it is right: a mutable
tag makes `kubectl rollout undo` meaningless and lets different pods in the
same deployment run different code if they restart at different times.
- The build job now pushes the image with BOTH `:latest` and
`:${{ github.sha }}`.
- The deployment manifest carries a sentinel tag rather than `:latest`, and
the deploy job sets the real SHA with `kubectl set image`. That makes the
deploy a genuine manifest change, so the Deployment rolls because its pod
template changed — not because it was told to. `kubectl rollout undo` now
means something: it goes back to the previous SHA.
- The digest check now compares against the SHA tag rather than `:latest`,
and it checks EVERY running pod instead of `items[0]`. During a rolling
update `items[0]` may still be an old pod that has not been terminated,
which would compare against the wrong digest. The job also fails if the
deployment is not fully rolled out.
- The smoke test now checks the app through the Service as well as directly
in the pod. The pod check alone would pass even if the Service selector
or the port mapping were wrong.
- `readOnlyRootFilesystem: true` — the app writes no files, so the root
filesystem can be read-only. /tmp is still writable via the emptyDir.
- The kubectl install is skipped when the runner already has one.
101 lines
3.1 KiB
YAML
101 lines
3.1 KiB
YAML
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: beer-deployment
|
|
namespace: beer
|
|
labels:
|
|
app: beer-data
|
|
spec:
|
|
replicas: 3
|
|
selector:
|
|
matchLabels:
|
|
app: beer-data
|
|
strategy:
|
|
rollingUpdate:
|
|
maxSurge: 25%
|
|
maxUnavailable: 25%
|
|
type: RollingUpdate
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: beer-data
|
|
spec:
|
|
containers:
|
|
- name: beer-data
|
|
# The image tag is pinned to the commit SHA by CI (`kubectl set
|
|
# image`). The value here is a sentinel: applying the manifest
|
|
# as-is would leave the deployment on that sentinel, so CI always
|
|
# replaces it before rolling. It is deliberately NOT `:latest` —
|
|
# a mutable tag makes the rollout a no-op (the pod template does not
|
|
# change) and makes `rollout undo` meaningless.
|
|
image: git.aridgwayweb.com/armistace/beer-data:SET_BY_CI
|
|
imagePullPolicy: Always
|
|
ports:
|
|
- containerPort: 5000
|
|
protocol: TCP
|
|
env:
|
|
- name: MONGO_HOST
|
|
value: "192.168.178.229"
|
|
- name: MONGO_USER
|
|
value: "root"
|
|
# MONGO_PASS and SECRET_KEY come from the live Secret - they are
|
|
# deliberately NOT in this file. See RUNBOOK.md.
|
|
- name: MONGO_PASS
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: beer-db
|
|
key: mongo_pass
|
|
- name: SECRET_KEY
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: beer-app
|
|
key: secret_key
|
|
resources:
|
|
limits:
|
|
cpu: 200m
|
|
memory: 256Mi
|
|
requests:
|
|
cpu: 50m
|
|
memory: 64Mi
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
capabilities:
|
|
drop:
|
|
- ALL
|
|
# The app reads its own source and talks to Mongo over the
|
|
# network. It writes no files, so the root filesystem can be
|
|
# read-only. /tmp is still writable via the emptyDir below.
|
|
readOnlyRootFilesystem: true
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /healthz
|
|
port: 5000
|
|
initialDelaySeconds: 10
|
|
periodSeconds: 20
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /readyz
|
|
port: 5000
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 10
|
|
volumeMounts:
|
|
- name: tmp
|
|
mountPath: /tmp
|
|
volumes:
|
|
- name: tmp
|
|
emptyDir: {}
|
|
securityContext:
|
|
runAsNonRoot: true
|
|
# The image creates a named user "beer". kubelet cannot verify that a
|
|
# *named* user is non-root (it can only check a numeric UID), so the
|
|
# UID is set explicitly here. It must match the UID in the image.
|
|
runAsUser: 999
|
|
runAsGroup: 999
|
|
fsGroup: 999
|
|
nodeSelector:
|
|
kubernetes.io/hostname: archlinux-k3s-3
|
|
imagePullSecrets:
|
|
- name: beercred
|
|
terminationGracePeriodSeconds: 30
|
|
restartPolicy: Always
|