Skip to content

Commit cf6931e

Browse files
authored
feat: add Helm chart for Kubernetes deployment (#3)
feat: add Helm chart for Kubernetes deployment Adds a Helm chart under helm/ for deploying gRPC Studio to Kubernetes. - Connections: plaintext, TLS, and mTLS - Auth: bearer token and OAuth2 (entra-id) - Ingress: standard, nginx-ingress, and Istio patterns - Config: pod checksum annotation rolls pods on config-only upgrades - CI: lint + template render + kind install (.github/workflows/helm-ci.yaml) - Release: release-please + GHCR OCI push, with workflow_dispatch and HELM_RELEASE_TOKEN fallback (.github/workflows/helm-release.yaml) - PetStore example Dockerfile + minikube testing guide - README: add Helm Chart section
1 parent 8a6de3d commit cf6931e

39 files changed

Lines changed: 2131 additions & 0 deletions

.dockerignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ example/
8383
# Scripts
8484
scripts/
8585

86+
# Helm chart (not needed in Docker images)
87+
helm/
88+
8689
# Production readiness docs
8790
PRODUCTION_READINESS_ASSESSMENT.md
8891
OBSERVABILITY_IMPLEMENTATION_SUMMARY.md

.github/ct.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright (c) 2026 Electronic Arts Inc. All rights reserved.
2+
3+
# chart-testing configuration
4+
# https://github.com/helm/chart-testing
5+
6+
# ct scans repo root and finds helm/ as the chart directory
7+
chart-dirs:
8+
- .
9+
10+
target-branch: main
11+
12+
helm-extra-args: "--timeout 120s"
13+
14+
# Validate maintainers field against GitHub
15+
validate-maintainers: false

.github/workflows/helm-ci.yaml

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Copyright (c) 2026 Electronic Arts Inc. All rights reserved.
2+
3+
name: Helm CI
4+
5+
on:
6+
pull_request:
7+
branches: [main]
8+
paths:
9+
- 'helm/**'
10+
- '.github/ct.yaml'
11+
- '.github/workflows/helm-ci.yaml'
12+
push:
13+
branches: [main]
14+
paths:
15+
- 'helm/**'
16+
- '.github/ct.yaml'
17+
- '.github/workflows/helm-ci.yaml'
18+
19+
permissions:
20+
contents: read
21+
22+
jobs:
23+
lint:
24+
name: Lint
25+
runs-on: ubuntu-latest
26+
steps:
27+
- uses: actions/checkout@v4
28+
with:
29+
fetch-depth: 0
30+
31+
- name: Set up Helm
32+
uses: azure/setup-helm@v4
33+
with:
34+
version: "3.17.0"
35+
36+
- name: Set up chart-testing
37+
uses: helm/chart-testing-action@v2
38+
39+
- name: helm lint
40+
run: helm lint ./helm
41+
42+
- name: Render examples
43+
run: |
44+
helm template grpc-studio ./helm -f helm/examples/basic/values.yaml > /dev/null
45+
helm template grpc-studio ./helm -f helm/examples/nginx-ingress/values.yaml > /dev/null
46+
helm template grpc-studio ./helm -f helm/examples/istio/values.yaml > /dev/null
47+
48+
- name: ct lint
49+
run: ct lint --config .github/ct.yaml
50+
51+
install:
52+
name: Install test
53+
runs-on: ubuntu-latest
54+
needs: lint
55+
steps:
56+
- uses: actions/checkout@v4
57+
with:
58+
fetch-depth: 0
59+
60+
- name: Set up Helm
61+
uses: azure/setup-helm@v4
62+
with:
63+
version: "3.17.0"
64+
65+
- name: Set up chart-testing
66+
uses: helm/chart-testing-action@v2
67+
68+
- name: Set up Docker Buildx
69+
uses: docker/setup-buildx-action@v3
70+
71+
- name: Build backend image
72+
uses: docker/build-push-action@v6
73+
with:
74+
context: .
75+
file: docker/backend/Dockerfile
76+
load: true
77+
tags: grpc-studio-backend:ci
78+
cache-from: type=gha,scope=backend
79+
cache-to: type=gha,scope=backend,mode=max
80+
81+
- name: Build frontend image
82+
uses: docker/build-push-action@v6
83+
with:
84+
context: .
85+
file: docker/frontend/Dockerfile
86+
load: true
87+
tags: grpc-studio-frontend:ci
88+
cache-from: type=gha,scope=frontend
89+
cache-to: type=gha,scope=frontend,mode=max
90+
91+
- name: Create kind cluster
92+
uses: helm/kind-action@v1
93+
with:
94+
cluster_name: kind
95+
96+
- name: Load images into kind
97+
run: |
98+
kind load docker-image grpc-studio-backend:ci
99+
kind load docker-image grpc-studio-frontend:ci
100+
101+
- name: ct install
102+
run: >
103+
ct install
104+
--config .github/ct.yaml
105+
--all
106+
--helm-extra-set-args "
107+
--set backend.image.repository=grpc-studio-backend
108+
--set backend.image.tag=ci
109+
--set backend.image.pullPolicy=Never
110+
--set frontend.image.repository=grpc-studio-frontend
111+
--set frontend.image.tag=ci
112+
--set frontend.image.pullPolicy=Never
113+
--set connection.target.host=my-grpc-server
114+
--set connection.target.port=50051
115+
--set connection.mode=plaintext
116+
"
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Copyright (c) 2026 Electronic Arts Inc. All rights reserved.
2+
3+
name: Helm Release
4+
5+
on:
6+
push:
7+
branches: [main]
8+
paths:
9+
- 'helm/**'
10+
- '.github/workflows/helm-release.yaml'
11+
workflow_dispatch:
12+
inputs:
13+
version:
14+
description: 'Chart version to publish (e.g. 0.2.0). Must match helm/Chart.yaml.'
15+
required: true
16+
17+
permissions:
18+
contents: write
19+
packages: write
20+
pull-requests: write
21+
22+
jobs:
23+
release-please:
24+
name: Release Please
25+
runs-on: ubuntu-latest
26+
# Skip when triggered manually — release-please is not involved in manual publishes
27+
if: github.event_name == 'push'
28+
outputs:
29+
release_created: ${{ steps.release.outputs.release_created }}
30+
tag_name: ${{ steps.release.outputs.tag_name }}
31+
version: ${{ steps.release.outputs.version }}
32+
steps:
33+
- uses: googleapis/release-please-action@v4
34+
id: release
35+
with:
36+
config-file: helm/release-please-config.json
37+
manifest-file: helm/.release-please-manifest.json
38+
# Use a PAT if available so release-please PRs can trigger CI.
39+
# Fall back to GITHUB_TOKEN for repos that don't have the secret set.
40+
token: ${{ secrets.HELM_RELEASE_TOKEN || secrets.GITHUB_TOKEN }}
41+
42+
chart:
43+
name: Publish Helm chart
44+
runs-on: ubuntu-latest
45+
needs: [release-please]
46+
# Runs on automated release or manual dispatch
47+
if: |
48+
always() && (
49+
needs.release-please.outputs.release_created ||
50+
github.event_name == 'workflow_dispatch'
51+
)
52+
steps:
53+
- uses: actions/checkout@v4
54+
55+
- name: Resolve chart version
56+
id: version
57+
run: |
58+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
59+
echo "version=${{ inputs.version }}" >> "$GITHUB_OUTPUT"
60+
else
61+
echo "version=${{ needs.release-please.outputs.version }}" >> "$GITHUB_OUTPUT"
62+
fi
63+
64+
- name: Set up Helm
65+
uses: azure/setup-helm@v4
66+
with:
67+
version: "3.17.0"
68+
69+
- name: Log in to GHCR
70+
run: |
71+
TOKEN="${{ secrets.HELM_RELEASE_TOKEN || secrets.GITHUB_TOKEN }}"
72+
echo "$TOKEN" | helm registry login ghcr.io \
73+
--username "${{ github.actor }}" --password-stdin
74+
75+
- name: Package chart
76+
run: helm package ./helm --version "${{ steps.version.outputs.version }}"
77+
78+
- name: Push chart to GHCR
79+
run: |
80+
helm push grpc-studio-${{ steps.version.outputs.version }}.tgz \
81+
oci://ghcr.io/electronicarts/helm-charts

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,20 @@ docker-compose up -d
187187

188188
See [docker/README.md](docker/README.md) for complete deployment documentation including Kubernetes manifests.
189189

190+
## Helm Chart
191+
192+
A Helm chart is published to GitHub Container Registry for Kubernetes deployments:
193+
194+
```bash
195+
helm upgrade --install my-grpc-studio oci://ghcr.io/electronicarts/helm-charts/grpc-studio \
196+
--set connection.target.host=my-grpc-server.default.svc.cluster.local \
197+
--set connection.target.port=50051 \
198+
--set connection.mode=insecure \
199+
--namespace grpc-studio --create-namespace
200+
```
201+
202+
See [helm/README.md](helm/README.md) for configuration options and [helm/examples/](helm/examples/) for ingress-nginx and Istio setups.
203+
190204
## CI/CD
191205

192206
This project uses GitHub Actions for continuous integration and Docker image publishing:

example/.dockerignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
node_modules
2+
npm-debug.log
3+
.git
4+
.gitignore
5+
README.md
6+
Dockerfile
7+
.dockerignore

example/Dockerfile

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# PetStore example gRPC server — for testing gRPC Studio against a
2+
# reflection-enabled service that exercises the full proto3 feature set.
3+
4+
FROM node:22-alpine
5+
6+
WORKDIR /app
7+
8+
COPY package.json package-lock.json ./
9+
RUN npm ci --omit=dev --ignore-scripts --no-audit --no-fund && npm cache clean --force
10+
11+
COPY proto ./proto
12+
COPY src ./src
13+
14+
RUN addgroup -g 1001 -S nodejs && \
15+
adduser -S petstore -u 1001 && \
16+
chown -R petstore:nodejs /app
17+
USER petstore
18+
19+
EXPOSE 50051
20+
21+
CMD ["node", "src/server.js"]

example/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ npm start
3535

3636
The server starts on `localhost:50051` (override with `PORT=6565 npm start`).
3737

38+
### Docker
39+
40+
```bash
41+
docker build -t petstore-example ./example
42+
docker run --rm -p 50051:50051 petstore-example
43+
```
44+
45+
The image is also used by the Helm chart's [local testing guide](../helm/TESTING.md) as the sample backend.
46+
3847
If you edit `proto/petstore.proto`, regenerate the descriptor:
3948

4049
```bash

helm/.helmignore

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Patterns to ignore when building packages.
2+
# Follows the same conventions as .gitignore.
3+
4+
.DS_Store
5+
.git/
6+
.gitignore
7+
.helmignore
8+
9+
# IDE / editor artifacts
10+
.idea/
11+
.vscode/
12+
*.swp
13+
*.bak
14+
15+
# Examples are documentation, not chart resources
16+
examples/
17+
18+
# CI/CD artifacts
19+
*.tgz

helm/.release-please-manifest.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"helm": "1.0.0"
3+
}

0 commit comments

Comments
 (0)