ci: deploy :latest with rollout restart, single replica
Drop the sha-pinned overlay and automatic rollback. The deployment now runs 1 replica with imagePullPolicy Always, and CI restarts it after apply so the new :latest image is pulled. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
bab237834b
commit
5365bcdf82
@@ -74,7 +74,6 @@ jobs:
|
|||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=latest
|
type=raw,value=latest
|
||||||
type=sha,format=long
|
|
||||||
|
|
||||||
- name: Build and push image
|
- name: Build and push image
|
||||||
uses: docker/build-push-action@v7
|
uses: docker/build-push-action@v7
|
||||||
@@ -119,34 +118,22 @@ jobs:
|
|||||||
|
|
||||||
KUBECONFIG="${KUBECONFIG_PATH}" kubectl cluster-info --request-timeout=15s
|
KUBECONFIG="${KUBECONFIG_PATH}" kubectl cluster-info --request-timeout=15s
|
||||||
|
|
||||||
# Overlay that pins the image to this commit, using kubectl's built-in kustomize.
|
|
||||||
- name: Pin image to this commit
|
|
||||||
run: |
|
|
||||||
mkdir -p k8s-deploy
|
|
||||||
cat > k8s-deploy/kustomization.yaml <<EOF
|
|
||||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
|
||||||
kind: Kustomization
|
|
||||||
resources:
|
|
||||||
- ../k8s
|
|
||||||
images:
|
|
||||||
- name: ${REGISTRY}/${IMAGE_NAME}
|
|
||||||
newTag: sha-${GITHUB_SHA}
|
|
||||||
EOF
|
|
||||||
kubectl kustomize k8s-deploy/ | grep 'image:'
|
|
||||||
|
|
||||||
- name: Apply manifests
|
- name: Apply manifests
|
||||||
run: kubectl apply -k k8s-deploy/
|
run: kubectl apply -k k8s/
|
||||||
|
|
||||||
|
# The spec still says :latest, so force new pods to pull the image just pushed.
|
||||||
|
- name: Restart deployment
|
||||||
|
run: kubectl rollout restart "deployment/${DEPLOYMENT}" -n "${NAMESPACE}"
|
||||||
|
|
||||||
- name: Wait for rollout
|
- name: Wait for rollout
|
||||||
run: |
|
run: |
|
||||||
if ! kubectl rollout status "deployment/${DEPLOYMENT}" -n "${NAMESPACE}" --timeout=5m; then
|
if ! kubectl rollout status "deployment/${DEPLOYMENT}" -n "${NAMESPACE}" --timeout=5m; then
|
||||||
kubectl get pods -n "${NAMESPACE}" -o wide
|
kubectl get pods -n "${NAMESPACE}" -o wide
|
||||||
kubectl describe pods -n "${NAMESPACE}" | tail -40
|
kubectl describe pods -n "${NAMESPACE}" | tail -40
|
||||||
kubectl rollout undo "deployment/${DEPLOYMENT}" -n "${NAMESPACE}" || true
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Verify deployment
|
- name: Verify deployment
|
||||||
run: |
|
run: |
|
||||||
kubectl get deployments,pods,services,ingress -n "${NAMESPACE}"
|
kubectl get deployments,pods,services,ingress -n "${NAMESPACE}"
|
||||||
echo "### Deployed sha-${GITHUB_SHA} to ${NAMESPACE}" >> "${GITHUB_STEP_SUMMARY}"
|
echo "### Deployed ${GITHUB_SHA} to ${NAMESPACE}" >> "${GITHUB_STEP_SUMMARY}"
|
||||||
|
|||||||
+5
-6
@@ -8,9 +8,9 @@ https://jesseinit.dev (`www.` redirects to the apex). TLS comes from cert-manage
|
|||||||
`.github/workflows/deploy.yml` (run by Gitea Actions) on every push to `master`:
|
`.github/workflows/deploy.yml` (run by Gitea Actions) on every push to `master`:
|
||||||
|
|
||||||
1. **Build site**: `npm ci && npm run build`, and renders the kustomization to catch manifest errors.
|
1. **Build site**: `npm ci && npm run build`, and renders the kustomization to catch manifest errors.
|
||||||
2. **Build and push image**: `tea.jesseinit.dev/jesseinit/personal-site:sha-<commit>` and `:latest`.
|
2. **Build and push image**: `tea.jesseinit.dev/jesseinit/personal-site:latest`.
|
||||||
3. **Deploy**: pins `newTag` in `kustomization.yaml` to `sha-<commit>`, runs `kubectl apply -k k8s/`,
|
3. **Deploy**: runs `kubectl apply -k k8s/`, then `kubectl rollout restart` so the pod pulls the new
|
||||||
waits for the rollout, and rolls back automatically if it fails.
|
`:latest` (`imagePullPolicy: Always`), and waits for the rollout. There is no automatic rollback.
|
||||||
|
|
||||||
Pull requests run step 1 only. Old images are cleaned up by the nightly `gitea-package-prune` cronjob.
|
Pull requests run step 1 only. Old images are cleaned up by the nightly `gitea-package-prune` cronjob.
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ Pull requests run step 1 only. Old images are cleaned up by the nightly `gitea-p
|
|||||||
## Files
|
## Files
|
||||||
|
|
||||||
- `namespace.yaml`: `personal-site` namespace
|
- `namespace.yaml`: `personal-site` namespace
|
||||||
- `deployment.yaml`: 2 replicas, zero-downtime rolling updates, non-root, health checks
|
- `deployment.yaml`: 1 replica, zero-downtime rolling updates, non-root, health checks
|
||||||
- `service.yaml`: ClusterIP on port 80 → container port 3000
|
- `service.yaml`: ClusterIP on port 80 → container port 3000
|
||||||
- `ingress.yaml`: nginx ingress + TLS for `jesseinit.dev` / `www.jesseinit.dev`
|
- `ingress.yaml`: nginx ingress + TLS for `jesseinit.dev` / `www.jesseinit.dev`
|
||||||
- `configmap.yaml`: optional environment variables
|
- `configmap.yaml`: optional environment variables
|
||||||
@@ -35,8 +35,7 @@ Pull requests run step 1 only. Old images are cleaned up by the nightly `gitea-p
|
|||||||
```bash
|
```bash
|
||||||
kubectl --context personal-cluster -n personal-site get pods,ingress,certificate
|
kubectl --context personal-cluster -n personal-site get pods,ingress,certificate
|
||||||
kubectl --context personal-cluster -n personal-site logs -l app=jesseinit-portfolio -f
|
kubectl --context personal-cluster -n personal-site logs -l app=jesseinit-portfolio -f
|
||||||
kubectl --context personal-cluster -n personal-site rollout undo deployment/jesseinit-portfolio
|
|
||||||
|
|
||||||
# Deploy by hand (uses :latest)
|
# Deploy by hand (uses :latest)
|
||||||
kubectl --context personal-cluster apply -k k8s/
|
kubectl --context personal-cluster apply -k k8s/
|
||||||
|
kubectl --context personal-cluster -n personal-site rollout restart deployment/jesseinit-portfolio
|
||||||
```
|
```
|
||||||
|
|||||||
+2
-2
@@ -5,7 +5,7 @@ metadata:
|
|||||||
labels:
|
labels:
|
||||||
app: jesseinit-portfolio
|
app: jesseinit-portfolio
|
||||||
spec:
|
spec:
|
||||||
replicas: 2
|
replicas: 1
|
||||||
revisionHistoryLimit: 5
|
revisionHistoryLimit: 5
|
||||||
strategy:
|
strategy:
|
||||||
type: RollingUpdate
|
type: RollingUpdate
|
||||||
@@ -23,7 +23,7 @@ spec:
|
|||||||
containers:
|
containers:
|
||||||
- name: portfolio
|
- name: portfolio
|
||||||
image: jesseinit-portfolio:latest
|
image: jesseinit-portfolio:latest
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: Always
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 3000
|
- containerPort: 3000
|
||||||
name: http
|
name: http
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ labels:
|
|||||||
app.kubernetes.io/name: personal-site
|
app.kubernetes.io/name: personal-site
|
||||||
app.kubernetes.io/managed-by: kustomize
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
|
||||||
# CI pins the tag to sha-<commit> via a generated overlay (see deploy.yml).
|
# CI deploys :latest and runs `kubectl rollout restart` to pick up the new image.
|
||||||
images:
|
images:
|
||||||
- name: jesseinit-portfolio
|
- name: jesseinit-portfolio
|
||||||
newName: tea.jesseinit.dev/jesseinit/personal-site
|
newName: tea.jesseinit.dev/jesseinit/personal-site
|
||||||
|
|||||||
Reference in New Issue
Block a user