Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/renovate.json5
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
// Renovate disabled in this training fork to avoid auto-PR noise during
// training days. Re-enable by removing `enabled: false` if upstreaming.
enabled: false,
extends: [
'github>GoogleCloudPlatform/kubernetes-engine-samples//.github/renovate-configs/dee-platform-ops.json5',
'schedule:earlyMondays',
Expand Down
138 changes: 138 additions & 0 deletions .github/workflows/deploy-attendee.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Auto-deploy attendee branches.
#
# Triggers on push to attendee/<name> (i.e. after a PR is auto-merged into
# the attendee's base branch). Detects which service was changed,
# builds + pushes only that service's image to GAR, then helm-upgrades
# the attendee's namespace to point that one service at the new tag.
#
# Repository variables this expects (Settings -> Secrets and variables -> Actions -> Variables):
# WIF_PROVIDER full WIF provider resource name (terraform output workload_identity_provider)
# GAR_PUSHER_SA email of the SA the workflow impersonates (terraform output github_pusher_sa_email)
# GCP_PROJECT_ID re5-n8n-platform
# GAR_REGION europe-west1
# GAR_REPO microservices-demo-training
# GKE_CLUSTER n8n-cluster
# GKE_REGION europe-west1

name: deploy-attendee

on:
push:
branches:
- 'attendee/*'

permissions:
contents: read
id-token: write

concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: true

jobs:
detect:
runs-on: ubuntu-latest
outputs:
attendee: ${{ steps.parse.outputs.attendee }}
services: ${{ steps.changed.outputs.services }}
any_changed: ${{ steps.changed.outputs.any_changed }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2

- name: Parse attendee name from branch
id: parse
run: |
name="${GITHUB_REF_NAME#attendee/}"
if [[ ! "$name" =~ ^[a-z][a-z0-9-]{1,30}$ ]]; then
echo "branch name doesn't match attendee/<name> pattern: $GITHUB_REF_NAME"
exit 1
fi
echo "attendee=$name" >> "$GITHUB_OUTPUT"

- name: Detect changed services
id: changed
run: |
services=()
for svc in adservice cartservice checkoutservice currencyservice emailservice frontend loadgenerator paymentservice productcatalogservice recommendationservice shippingservice; do
if git diff --name-only HEAD^ HEAD | grep -q "^src/$svc/"; then
services+=("$svc")
fi
done
if [[ ${#services[@]} -eq 0 ]]; then
echo "no service changed - nothing to deploy"
echo "any_changed=false" >> "$GITHUB_OUTPUT"
echo "services=[]" >> "$GITHUB_OUTPUT"
else
echo "any_changed=true" >> "$GITHUB_OUTPUT"
json=$(printf '%s\n' "${services[@]}" | jq -R . | jq -sc .)
echo "services=$json" >> "$GITHUB_OUTPUT"
echo "changed: ${services[*]}"
fi

build-and-deploy:
needs: detect
if: needs.detect.outputs.any_changed == 'true'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
service: ${{ fromJSON(needs.detect.outputs.services) }}
steps:
- uses: actions/checkout@v4

- name: Authenticate to GCP via WIF
id: auth
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ vars.WIF_PROVIDER }}
service_account: ${{ vars.GAR_PUSHER_SA }}

- name: Configure Docker for Artifact Registry
run: gcloud auth configure-docker ${{ vars.GAR_REGION }}-docker.pkg.dev --quiet

- name: Build and push image
env:
IMAGE: ${{ vars.GAR_REGION }}-docker.pkg.dev/${{ vars.GCP_PROJECT_ID }}/${{ vars.GAR_REPO }}/${{ matrix.service }}:attendee-${{ needs.detect.outputs.attendee }}-${{ github.sha }}
run: |
docker build -t "$IMAGE" "src/${{ matrix.service }}"
docker push "$IMAGE"
echo "image=$IMAGE" >> "$GITHUB_ENV"

- uses: google-github-actions/get-gke-credentials@v2
with:
cluster_name: ${{ vars.GKE_CLUSTER }}
location: ${{ vars.GKE_REGION }}

- name: Map service dir to Helm values key
id: valuekey
run: |
case "${{ matrix.service }}" in
adservice) echo "key=adService" >> "$GITHUB_OUTPUT" ;;
cartservice) echo "key=cartService" >> "$GITHUB_OUTPUT" ;;
checkoutservice) echo "key=checkoutService" >> "$GITHUB_OUTPUT" ;;
currencyservice) echo "key=currencyService" >> "$GITHUB_OUTPUT" ;;
emailservice) echo "key=emailService" >> "$GITHUB_OUTPUT" ;;
frontend) echo "key=frontend" >> "$GITHUB_OUTPUT" ;;
loadgenerator) echo "key=loadGenerator" >> "$GITHUB_OUTPUT" ;;
paymentservice) echo "key=paymentService" >> "$GITHUB_OUTPUT" ;;
productcatalogservice) echo "key=productCatalogService" >> "$GITHUB_OUTPUT" ;;
recommendationservice) echo "key=recommendationService" >> "$GITHUB_OUTPUT" ;;
shippingservice) echo "key=shippingService" >> "$GITHUB_OUTPUT" ;;
esac

- name: Helm upgrade attendee namespace
env:
NS: attendee-${{ needs.detect.outputs.attendee }}
KEY: ${{ steps.valuekey.outputs.key }}
REPO: ${{ vars.GAR_REGION }}-docker.pkg.dev/${{ vars.GCP_PROJECT_ID }}/${{ vars.GAR_REPO }}
TAG: attendee-${{ needs.detect.outputs.attendee }}-${{ github.sha }}
run: |
helm upgrade boutique ./helm-chart \
--namespace "$NS" \
-f training/values-training.yaml \
--reuse-values \
--set "${KEY}.image.repository=${REPO}" \
--set "${KEY}.image.tag=${TAG}" \
--wait --timeout 5m
22 changes: 22 additions & 0 deletions helm-chart/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{{/*
Renders the container image reference for a service.

Resolution order (most specific wins):
1. .<service>.image.repository / .<service>.image.tag (per-service override)
2. .Values.images.repository / .Values.images.tag
3. .Chart.AppVersion (tag fallback only)

Usage:
image: {{ include "onlineboutique.image" (list . .Values.checkoutService) }}
*/}}
{{- define "onlineboutique.image" -}}
{{- $root := index . 0 -}}
{{- $svc := index . 1 -}}
{{- $repo := $root.Values.images.repository -}}
{{- $tag := default $root.Chart.AppVersion $root.Values.images.tag -}}
{{- if $svc.image -}}
{{- $repo = default $repo $svc.image.repository -}}
{{- $tag = default $tag $svc.image.tag -}}
{{- end -}}
{{- printf "%s/%s:%s" $repo $svc.name $tag -}}
{{- end -}}
2 changes: 1 addition & 1 deletion helm-chart/templates/adservice.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ spec:
- ALL
privileged: false
readOnlyRootFilesystem: true
image: {{ .Values.images.repository }}/{{ .Values.adService.name }}:{{ .Values.images.tag | default .Chart.AppVersion }}
image: {{ include "onlineboutique.image" (list . .Values.adService) }}
ports:
- containerPort: 9555
env:
Expand Down
2 changes: 1 addition & 1 deletion helm-chart/templates/cartservice.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ spec:
- ALL
privileged: false
readOnlyRootFilesystem: true
image: {{ .Values.images.repository }}/{{ .Values.cartService.name }}:{{ .Values.images.tag | default .Chart.AppVersion }}
image: {{ include "onlineboutique.image" (list . .Values.cartService) }}
ports:
- containerPort: 7070
env:
Expand Down
2 changes: 1 addition & 1 deletion helm-chart/templates/checkoutservice.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ spec:
- ALL
privileged: false
readOnlyRootFilesystem: true
image: {{ .Values.images.repository }}/{{ .Values.checkoutService.name }}:{{ .Values.images.tag | default .Chart.AppVersion }}
image: {{ include "onlineboutique.image" (list . .Values.checkoutService) }}
ports:
- containerPort: 5050
readinessProbe:
Expand Down
2 changes: 1 addition & 1 deletion helm-chart/templates/currencyservice.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ spec:
- ALL
privileged: false
readOnlyRootFilesystem: true
image: {{ .Values.images.repository }}/{{ .Values.currencyService.name }}:{{ .Values.images.tag | default .Chart.AppVersion }}
image: {{ include "onlineboutique.image" (list . .Values.currencyService) }}
ports:
- name: grpc
containerPort: 7000
Expand Down
6 changes: 4 additions & 2 deletions helm-chart/templates/emailservice.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ spec:
- ALL
privileged: false
readOnlyRootFilesystem: true
image: {{ .Values.images.repository }}/{{ .Values.emailService.name }}:{{ .Values.images.tag | default .Chart.AppVersion }}
image: {{ include "onlineboutique.image" (list . .Values.emailService) }}
ports:
- containerPort: 8080
env:
Expand All @@ -91,10 +91,12 @@ spec:
{{- end }}
readinessProbe:
periodSeconds: 5
timeoutSeconds: 5
grpc:
port: 8080
livenessProbe:
periodSeconds: 5
periodSeconds: 10
timeoutSeconds: 5
grpc:
port: 8080
resources:
Expand Down
2 changes: 1 addition & 1 deletion helm-chart/templates/frontend.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ spec:
- ALL
privileged: false
readOnlyRootFilesystem: true
image: {{ .Values.images.repository }}/{{ .Values.frontend.name }}:{{ .Values.images.tag | default .Chart.AppVersion }}
image: {{ include "onlineboutique.image" (list . .Values.frontend) }}
ports:
- containerPort: 8080
readinessProbe:
Expand Down
2 changes: 1 addition & 1 deletion helm-chart/templates/loadgenerator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ spec:
- ALL
privileged: false
readOnlyRootFilesystem: true
image: {{ .Values.images.repository }}/{{ .Values.loadGenerator.name }}:{{ .Values.images.tag | default .Chart.AppVersion }}
image: {{ include "onlineboutique.image" (list . .Values.loadGenerator) }}
env:
- name: FRONTEND_ADDR
value: "{{ .Values.frontend.name }}:80"
Expand Down
2 changes: 1 addition & 1 deletion helm-chart/templates/paymentservice.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ spec:
- ALL
privileged: false
readOnlyRootFilesystem: true
image: {{ .Values.images.repository }}/{{ .Values.paymentService.name }}:{{ .Values.images.tag | default .Chart.AppVersion }}
image: {{ include "onlineboutique.image" (list . .Values.paymentService) }}
ports:
- containerPort: 50051
env:
Expand Down
2 changes: 1 addition & 1 deletion helm-chart/templates/productcatalogservice.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ spec:
- ALL
privileged: false
readOnlyRootFilesystem: true
image: {{ .Values.images.repository }}/{{ .Values.productCatalogService.name }}:{{ .Values.images.tag | default .Chart.AppVersion }}
image: {{ include "onlineboutique.image" (list . .Values.productCatalogService) }}
ports:
- containerPort: 3550
env:
Expand Down
6 changes: 4 additions & 2 deletions helm-chart/templates/recommendationservice.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,17 @@ spec:
- ALL
privileged: false
readOnlyRootFilesystem: true
image: {{ .Values.images.repository }}/{{ .Values.recommendationService.name }}:{{ .Values.images.tag | default .Chart.AppVersion }}
image: {{ include "onlineboutique.image" (list . .Values.recommendationService) }}
ports:
- containerPort: 8080
readinessProbe:
periodSeconds: 5
timeoutSeconds: 5
grpc:
port: 8080
livenessProbe:
periodSeconds: 5
periodSeconds: 10
timeoutSeconds: 5
grpc:
port: 8080
env:
Expand Down
2 changes: 1 addition & 1 deletion helm-chart/templates/shippingservice.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ spec:
- ALL
privileged: false
readOnlyRootFilesystem: true
image: {{ .Values.images.repository }}/{{ .Values.shippingService.name }}:{{ .Values.images.tag | default .Chart.AppVersion }}
image: {{ include "onlineboutique.image" (list . .Values.shippingService) }}
ports:
- containerPort: 50051
env:
Expand Down
7 changes: 7 additions & 0 deletions helm-chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ images:
repository: us-central1-docker.pkg.dev/google-samples/microservices-demo
# Overrides the image tag whose default is the chart appVersion.
tag: ""
# Per-service image overrides are also supported. Any service block below
# can set:
# image:
# repository: <registry>/<path> # overrides .Values.images.repository
# tag: <tag> # overrides .Values.images.tag
# Used by the training pipeline to flip the tag on a single fixed service
# while leaving the other ten on the shared :base tag.

serviceAccounts:
# Specifies whether service accounts should be created.
Expand Down
15 changes: 15 additions & 0 deletions speckit-setup/.claude/commands/speckit.constitution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
description: Create or update the project constitution.
---

## User Input

```text
$ARGUMENTS
```

## Outline

1. Create or update the project constitution and store it in `.specify/memory/constitution.md`.
- Project name, guiding principles, non-negotiable rules
- Derive from user input and existing repo context (README, docs)
22 changes: 22 additions & 0 deletions speckit-setup/.claude/commands/speckit.implement.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
description: Execute the implementation plan by processing all tasks in tasks.md.
---

## User Input

```text
$ARGUMENTS
```

## Outline

1. Read `.specify/feature.json` to get the feature directory path.

2. **Load context**: `.specify/memory/constitution.md` and `<feature_directory>/spec.md` and `<feature_directory>/plan.md` and `<feature_directory>/tasks.md`.

3. **Execute tasks** in order:
- Complete each task before moving to the next
- Mark completed tasks by changing `- [ ]` to `- [x]` in `<feature_directory>/tasks.md`
- Halt on failure and report the issue

4. **Validate**: Verify all tasks are completed and the implementation matches the spec.
19 changes: 19 additions & 0 deletions speckit-setup/.claude/commands/speckit.plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
description: Create a plan and store it in plan.md.
---

## User Input

```text
$ARGUMENTS
```

## Outline

1. Read `.specify/feature.json` to get the feature directory path.

2. **Load context**: `.specify/memory/constitution.md` and `<feature_directory>/spec.md`.

3. Create an implementation plan and store it in `<feature_directory>/plan.md`.
- Technical context: tech stack, dependencies, project structure
- Design decisions, architecture, file structure
23 changes: 23 additions & 0 deletions speckit-setup/.claude/commands/speckit.specify.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
description: Create a specification and store it in spec.md.
---

## User Input

```text
$ARGUMENTS
```

## Outline

1. **Ask the user** for the feature directory path (e.g., `specs/my-feature`). Do not proceed until provided.

2. Create the directory and write `.specify/feature.json`:
```json
{ "feature_directory": "<feature_directory>" }
```

3. Create a specification from the user input and store it in `<feature_directory>/spec.md`.
- Overview, functional requirements, user scenarios, success criteria
- Every requirement must be testable
- Make informed defaults for unspecified details
Loading