Skip to content

Commit 62c2edd

Browse files
authored
Merge pull request #1 from test-zeus-ai/values-update-helm
Migrate traceviewer service to GKE
2 parents 1060841 + 19b920a commit 62c2edd

6 files changed

Lines changed: 500 additions & 0 deletions

File tree

.github/workflows/deploy.yaml

Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
name: Build and Deploy
2+
3+
on:
4+
push:
5+
branches:
6+
- main-prod
7+
paths:
8+
- .github/workflows/deploy.yaml
9+
- helm/**
10+
- package.json
11+
- package-lock.json
12+
- packages/injected/**
13+
- packages/playwright-core/**
14+
- packages/protocol/**
15+
- packages/trace/**
16+
- packages/trace-viewer/**
17+
- packages/web/**
18+
- utils/build/**
19+
workflow_dispatch:
20+
inputs:
21+
deploy_prod:
22+
description: "Deploy to production"
23+
required: true
24+
type: boolean
25+
default: false
26+
27+
permissions:
28+
contents: read
29+
id-token: write
30+
31+
env:
32+
SERVICE_NAME: traceviewer
33+
APP_DIR: .
34+
DOCKERFILE: packages/trace-viewer/Dockerfile
35+
CHART_DIR: helm
36+
GAR_LOCATION: ${{ vars.GAR_LOCATION }}
37+
38+
jobs:
39+
build:
40+
runs-on: ubuntu-latest
41+
permissions:
42+
contents: read
43+
id-token: write
44+
outputs:
45+
image_tag: ${{ steps.meta.outputs.image_tag }}
46+
image_repo: ${{ steps.meta.outputs.image_repo }}
47+
steps:
48+
- uses: actions/checkout@v4
49+
50+
- name: Authenticate to Google Cloud
51+
id: auth
52+
uses: google-github-actions/auth@v2
53+
with:
54+
workload_identity_provider: ${{ github.ref == 'refs/heads/main-prod' && secrets.GCP_WIF_PROVIDER_PROD || secrets.GCP_WIF_PROVIDER_DEV }}
55+
service_account: ${{ github.ref == 'refs/heads/main-prod' && secrets.GCP_SA_PROD || secrets.GCP_SA_DEV }}
56+
token_format: access_token
57+
58+
- name: Setup gcloud
59+
uses: google-github-actions/setup-gcloud@v2
60+
61+
- name: Set up Docker Buildx
62+
uses: docker/setup-buildx-action@v3
63+
with:
64+
driver: docker-container
65+
66+
- name: Login to GAR
67+
uses: docker/login-action@v3
68+
with:
69+
registry: ${{ env.GAR_LOCATION }}-docker.pkg.dev
70+
username: oauth2accesstoken
71+
password: ${{ steps.auth.outputs.access_token }}
72+
73+
- name: Build image metadata
74+
id: meta
75+
run: |
76+
IMAGE_TAG="${GITHUB_SHA}-${GITHUB_RUN_ATTEMPT}"
77+
PROJECT_ID="${{ github.ref == 'refs/heads/main-prod' && vars.GCP_PROJECT_ID_PROD || vars.GCP_PROJECT_ID_DEV }}"
78+
GAR_REPO="${{ github.ref == 'refs/heads/main-prod' && vars.GAR_DOCKER_REPOSITORY_PROD || vars.GAR_DOCKER_REPOSITORY_DEV }}"
79+
IMAGE_REPO="${GAR_LOCATION}-docker.pkg.dev/${PROJECT_ID}/${GAR_REPO}/${SERVICE_NAME}"
80+
echo "image_tag=${IMAGE_TAG}" >>"${GITHUB_OUTPUT}"
81+
echo "image_repo=${IMAGE_REPO}" >>"${GITHUB_OUTPUT}"
82+
83+
- name: Build and push image
84+
uses: docker/build-push-action@v6
85+
with:
86+
context: ${{ env.APP_DIR }}
87+
file: ${{ env.DOCKERFILE }}
88+
push: true
89+
tags: ${{ steps.meta.outputs.image_repo }}:${{ steps.meta.outputs.image_tag }}
90+
cache-from: type=gha
91+
cache-to: type=gha,mode=max
92+
93+
helm4-compat:
94+
if: github.ref == 'refs/heads/main-prod'
95+
needs: build
96+
runs-on: ubuntu-latest
97+
env:
98+
TARGET_ENV: ${{ github.ref == 'refs/heads/main-prod' && 'prod' || 'dev' }}
99+
VALUES_FILE: ${{ github.ref == 'refs/heads/main-prod' && 'values-prod.yaml' || 'values-dev.yaml' }}
100+
DEPLOY_NAMESPACE: ${{ github.ref == 'refs/heads/main-prod' && 'testzeus-prod' || 'testzeus-dev' }}
101+
GKE_CLUSTER: ${{ github.ref == 'refs/heads/main-prod' && vars.GKE_PROD_CLUSTER || vars.GKE_DEV_CLUSTER }}
102+
GKE_LOCATION: ${{ github.ref == 'refs/heads/main-prod' && vars.GKE_PROD_LOCATION || vars.GKE_DEV_LOCATION }}
103+
GCP_PROJECT_ID: ${{ github.ref == 'refs/heads/main-prod' && vars.GCP_PROJECT_ID_PROD || vars.GCP_PROJECT_ID_DEV }}
104+
GAR_HELM_REPOSITORY: ${{ github.ref == 'refs/heads/main-prod' && vars.GAR_HELM_REPOSITORY_PROD || vars.GAR_HELM_REPOSITORY_DEV }}
105+
GCP_SA: ${{ github.ref == 'refs/heads/main-prod' && secrets.GCP_SA_PROD || secrets.GCP_SA_DEV }}
106+
GCP_WIF_PROVIDER: ${{ github.ref == 'refs/heads/main-prod' && secrets.GCP_WIF_PROVIDER_PROD || secrets.GCP_WIF_PROVIDER_DEV }}
107+
steps:
108+
- uses: actions/checkout@v4
109+
110+
- name: Set up Helm 4 (compat check)
111+
uses: azure/setup-helm@v4
112+
with:
113+
version: v4.0.0
114+
115+
- name: Authenticate to Google Cloud
116+
uses: google-github-actions/auth@v2
117+
with:
118+
workload_identity_provider: ${{ env.GCP_WIF_PROVIDER }}
119+
service_account: ${{ env.GCP_SA }}
120+
121+
- name: Get GKE credentials
122+
uses: google-github-actions/get-gke-credentials@v2
123+
with:
124+
cluster_name: ${{ env.GKE_CLUSTER }}
125+
location: ${{ env.GKE_LOCATION }}
126+
project_id: ${{ env.GCP_PROJECT_ID }}
127+
128+
- name: Login Helm to GAR OCI registry
129+
run: |
130+
gcloud auth print-access-token | \
131+
helm registry login -u oauth2accesstoken --password-stdin \
132+
"${GAR_LOCATION}-docker.pkg.dev"
133+
134+
- name: Set Helm dependency repository (target env)
135+
run: |
136+
CHART_REPO="oci://${GAR_LOCATION}-docker.pkg.dev/${GCP_PROJECT_ID}/${GAR_HELM_REPOSITORY}"
137+
sed -i "/- name: service-template/,/repository:/ s#repository: \".*\"#repository: \"${CHART_REPO}\"#" "${CHART_DIR}/Chart.yaml"
138+
139+
- name: Helm dependency update (Helm 4)
140+
run: helm dependency update "${CHART_DIR}"
141+
142+
- name: Helm lint (Helm 4)
143+
run: helm lint "${CHART_DIR}" -f "${CHART_DIR}/${VALUES_FILE}"
144+
145+
- name: Helm template render (Helm 4)
146+
run: |
147+
helm template "${SERVICE_NAME}-helm4-compat" "${CHART_DIR}" \
148+
-f "${CHART_DIR}/${VALUES_FILE}" \
149+
--set-string service-template.containers[0].image.repository=${{ needs.build.outputs.image_repo }} \
150+
--set-string service-template.containers[0].image.tag=${{ needs.build.outputs.image_tag }} \
151+
--set-string service-template.serviceAccount.annotations.iam\\.gke\\.io/gcp-service-account=${{ env.GCP_SA }} \
152+
> rendered-helm4.yaml
153+
154+
- name: Guard rendered manifest fields
155+
run: |
156+
if grep -nE '^[[:space:]]*(managedFields:|resourceVersion:|uid:|creationTimestamp:)$' rendered-helm4.yaml; then
157+
echo "Forbidden metadata fields found in rendered output."
158+
exit 1
159+
fi
160+
if grep -nE '^[[:space:]]*status:[[:space:]]*$' rendered-helm4.yaml; then
161+
echo "Forbidden status field found in rendered output."
162+
exit 1
163+
fi
164+
165+
- name: Helm upgrade dry-run (Helm 4)
166+
run: |
167+
helm upgrade "${SERVICE_NAME}-helm4-compat" "${CHART_DIR}" \
168+
-f "${CHART_DIR}/${VALUES_FILE}" \
169+
--set-string service-template.containers[0].image.repository=${{ needs.build.outputs.image_repo }} \
170+
--set-string service-template.containers[0].image.tag=${{ needs.build.outputs.image_tag }} \
171+
--set-string service-template.serviceAccount.annotations.iam\\.gke\\.io/gcp-service-account=${{ env.GCP_SA }} \
172+
--namespace "${DEPLOY_NAMESPACE}" \
173+
--create-namespace \
174+
--install \
175+
--dry-run \
176+
--server-side=false \
177+
--debug
178+
179+
deploy-dev:
180+
if: github.event_name == 'push' && github.ref == 'refs/heads/main-prod'
181+
needs: [build, helm4-compat]
182+
runs-on: ubuntu-latest
183+
environment: dev
184+
env:
185+
GKE_CLUSTER: ${{ vars.GKE_DEV_CLUSTER }}
186+
GKE_LOCATION: ${{ vars.GKE_DEV_LOCATION }}
187+
GCP_PROJECT_ID: ${{ vars.GCP_PROJECT_ID_DEV }}
188+
steps:
189+
- uses: actions/checkout@v4
190+
191+
- name: Set up Helm
192+
uses: azure/setup-helm@v4
193+
with:
194+
version: v4.0.0
195+
196+
- name: Authenticate to Google Cloud
197+
uses: google-github-actions/auth@v2
198+
with:
199+
workload_identity_provider: ${{ secrets.GCP_WIF_PROVIDER_DEV }}
200+
service_account: ${{ secrets.GCP_SA_DEV }}
201+
202+
- name: Get GKE credentials
203+
uses: google-github-actions/get-gke-credentials@v2
204+
with:
205+
cluster_name: ${{ env.GKE_CLUSTER }}
206+
location: ${{ env.GKE_LOCATION }}
207+
project_id: ${{ env.GCP_PROJECT_ID }}
208+
209+
- name: Login Helm to GAR OCI registry
210+
run: |
211+
gcloud auth print-access-token | \
212+
helm registry login -u oauth2accesstoken --password-stdin \
213+
"${GAR_LOCATION}-docker.pkg.dev"
214+
215+
- name: Set Helm dependency repository (dev)
216+
run: |
217+
CHART_REPO="oci://${GAR_LOCATION}-docker.pkg.dev/${{ vars.GCP_PROJECT_ID_DEV }}/${{ vars.GAR_HELM_REPOSITORY_DEV }}"
218+
sed -i "/- name: service-template/,/repository:/ s#repository: \".*\"#repository: \"${CHART_REPO}\"#" "${CHART_DIR}/Chart.yaml"
219+
220+
- name: Helm dependency update
221+
run: helm dependency update "${CHART_DIR}"
222+
223+
- name: Helm deploy to dev
224+
run: |
225+
helm upgrade "${SERVICE_NAME}" "${CHART_DIR}" \
226+
-f "${CHART_DIR}/values-dev.yaml" \
227+
--set-string service-template.containers[0].image.repository=${{ needs.build.outputs.image_repo }} \
228+
--set-string service-template.containers[0].image.tag=${{ needs.build.outputs.image_tag }} \
229+
--set-string service-template.serviceAccount.annotations.iam\\.gke\\.io/gcp-service-account=${{ secrets.GCP_SA_DEV }} \
230+
--namespace "testzeus-dev" \
231+
--create-namespace \
232+
--install \
233+
--wait \
234+
--rollback-on-failure \
235+
--server-side=false \
236+
--timeout 5m
237+
238+
deploy-prod:
239+
if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main-prod' && github.event.inputs.deploy_prod == 'true'
240+
needs: [build, helm4-compat]
241+
runs-on: ubuntu-latest
242+
environment: production
243+
env:
244+
GKE_CLUSTER: ${{ vars.GKE_PROD_CLUSTER }}
245+
GKE_LOCATION: ${{ vars.GKE_PROD_LOCATION }}
246+
GCP_PROJECT_ID: ${{ vars.GCP_PROJECT_ID_PROD }}
247+
steps:
248+
- uses: actions/checkout@v4
249+
250+
- name: Set up Helm
251+
uses: azure/setup-helm@v4
252+
with:
253+
version: v4.0.0
254+
255+
- name: Authenticate to Google Cloud
256+
uses: google-github-actions/auth@v2
257+
with:
258+
workload_identity_provider: ${{ secrets.GCP_WIF_PROVIDER_PROD }}
259+
service_account: ${{ secrets.GCP_SA_PROD }}
260+
261+
- name: Get GKE credentials
262+
uses: google-github-actions/get-gke-credentials@v2
263+
with:
264+
cluster_name: ${{ env.GKE_CLUSTER }}
265+
location: ${{ env.GKE_LOCATION }}
266+
project_id: ${{ env.GCP_PROJECT_ID }}
267+
268+
- name: Login Helm to GAR OCI registry
269+
run: |
270+
gcloud auth print-access-token | \
271+
helm registry login -u oauth2accesstoken --password-stdin \
272+
"${GAR_LOCATION}-docker.pkg.dev"
273+
274+
- name: Set Helm dependency repository (prod)
275+
run: |
276+
CHART_REPO="oci://${GAR_LOCATION}-docker.pkg.dev/${{ vars.GCP_PROJECT_ID_PROD }}/${{ vars.GAR_HELM_REPOSITORY_PROD }}"
277+
sed -i "/- name: service-template/,/repository:/ s#repository: \".*\"#repository: \"${CHART_REPO}\"#" "${CHART_DIR}/Chart.yaml"
278+
279+
- name: Helm dependency update
280+
run: helm dependency update "${CHART_DIR}"
281+
282+
- name: Helm deploy to prod
283+
run: |
284+
helm upgrade "${SERVICE_NAME}" "${CHART_DIR}" \
285+
-f "${CHART_DIR}/values-prod.yaml" \
286+
--set-string service-template.containers[0].image.repository=${{ needs.build.outputs.image_repo }} \
287+
--set-string service-template.containers[0].image.tag=${{ needs.build.outputs.image_tag }} \
288+
--set-string service-template.serviceAccount.annotations.iam\\.gke\\.io/gcp-service-account=${{ secrets.GCP_SA_PROD }} \
289+
--namespace "testzeus-prod" \
290+
--create-namespace \
291+
--install \
292+
--wait \
293+
--rollback-on-failure \
294+
--server-side=false \
295+
--timeout 5m

helm/Chart.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
apiVersion: v2
2+
name: trace-viewer
3+
version: 1.0.0
4+
description: Playwright trace viewer
5+
type: application
6+
7+
dependencies:
8+
- name: service-template
9+
version: "~0.5.0"
10+
repository: "oci://us-central1-docker.pkg.dev/prod-testarmy/helm-repository-prod"

helm/templates/NOTES.txt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{{- $values := index .Values "service-template" -}}
2+
{{- $serviceName := $values.fullnameOverride | default (printf "%s-service-template" .Release.Name) -}}
3+
1. Get the application URL by running these commands:
4+
{{- if $values.service }}
5+
{{- if contains "LoadBalancer" ($values.service.type | default "ClusterIP") }}
6+
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
7+
You can watch the status by running 'kubectl get svc -w {{ $serviceName }}'
8+
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ $serviceName }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
9+
echo http://$SERVICE_IP:{{ $values.service.port | default 80 }}
10+
{{- else if contains "ClusterIP" ($values.service.type | default "ClusterIP") }}
11+
{{- $appName := $values.fullnameOverride | default "service-template" -}}
12+
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ $appName }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
13+
echo "Visit http://127.0.0.1:8080 to use your application"
14+
{{- $containerPort := 8080 -}}
15+
{{- if $values.containers -}}
16+
{{- if (index $values.containers 0).ports -}}
17+
{{- $containerPort = (index (index $values.containers 0).ports 0).containerPort | default 8080 -}}
18+
{{- end -}}
19+
{{- end -}}
20+
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:{{ $containerPort }}
21+
{{- else if contains "NodePort" ($values.service.type | default "ClusterIP") }}
22+
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ $serviceName }})
23+
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
24+
echo http://$NODE_IP:$NODE_PORT
25+
{{- end }}
26+
{{- end }}
27+
28+
{{- if and $values.autoscaling (and $values.autoscaling.enabled (and $values.vpa $values.vpa.enabled)) }}
29+
WARNING: Both HPA and VPA are enabled. This is a conflicting configuration as both will try to manage resources for the same workload.
30+
{{- end }}
31+
{{- if and $values.persistentStorage (and $values.persistentStorage.enabled (eq $values.persistentStorage.accessMode "ReadWriteOnce") (gt (int ($values.replicaCount | default 1)) 1)) }}
32+
WARNING: persistentStorage is enabled with ReadWriteOnce access mode but replicaCount is greater than 1. Only one pod will be able to mount the volume.
33+
{{- end }}

0 commit comments

Comments
 (0)