Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 2, 2026

MySQL Helm Chart Support - COMPLETE ✅

This PR adds comprehensive MySQL support to the llm-proxy Helm chart, enabling users to deploy with MySQL as an alternative database backend alongside the existing SQLite and PostgreSQL options.


Implementation Summary

Phase 1: Values Configuration ✅

  • Add database.mysql section to values.yaml with image, auth, persistence, resources, and config options

Phase 2: MySQL Templates ✅

  • Create mysql-statefulset.yaml with container spec, volumeClaimTemplates, and probes
  • Create mysql-service.yaml with ClusterIP service on port 3306
  • Create mysql-secret.yaml for handling root and application passwords

Phase 3: Helper Functions ✅

  • Add MySQL helper functions to _helpers.tpl (host, port, database, username, password, URL, validation)

Phase 4: Proxy Integration ✅

  • Update deployment.yaml to handle MySQL environment variables and DATABASE_URL generation
  • Add MySQL-specific secret references

Phase 5: Documentation & Examples ✅

  • Create examples/values-mysql.yaml with example configuration
  • Update README.md with MySQL installation examples and configuration details
  • Update Chart.yaml with MySQL annotations

Phase 6: Validation & Testing ✅

  • Test Helm template rendering with MySQL enabled
  • Verify conditional logic works correctly
  • Validate all acceptance criteria
  • Fix probe authentication issues
  • Fix TLS connection string syntax
  • Remove invalid environment variables

Recent Fixes

Probe Authentication

  • Added -u root -p${MYSQL_ROOT_PASSWORD} to mysqladmin ping commands
  • Changed to shell execution to properly handle password variable expansion

TLS Connection String

  • Fixed to omit tls parameter when disabled (was incorrectly using tls=false)
  • Now: disabled = no param, enabled = &tls=true, skip-verify = &tls=skip-verify

Environment Variables

  • Removed unsupported MYSQL_MAX_CONNECTIONS, MYSQL_CHARACTER_SET_SERVER, MYSQL_COLLATION_SERVER env vars
  • These settings are only passed as command-line arguments to mysqld

Files Changed (9 files, +569/-1)

New Files (4)

  • deploy/helm/llm-proxy/templates/mysql-statefulset.yaml - MySQL StatefulSet with persistence
  • deploy/helm/llm-proxy/templates/mysql-service.yaml - Headless ClusterIP service
  • deploy/helm/llm-proxy/templates/mysql-secret.yaml - Password management
  • deploy/helm/llm-proxy/examples/values-mysql.yaml - Example configuration

Modified Files (5)

  • deploy/helm/llm-proxy/values.yaml - Added mysql configuration section
  • deploy/helm/llm-proxy/templates/_helpers.tpl - Added MySQL helper functions
  • deploy/helm/llm-proxy/templates/deployment.yaml - Added MySQL env vars and validation
  • deploy/helm/llm-proxy/README.md - Added MySQL documentation
  • deploy/helm/llm-proxy/Chart.yaml - Added MySQL annotations

Testing Results - All Passed ✅

Template Rendering Tests

  • ✅ MySQL StatefulSet renders correctly with authenticated probes
  • ✅ MySQL Service renders as headless ClusterIP on port 3306
  • ✅ MySQL Secret renders with base64 encoded passwords
  • ✅ DATABASE_URL without TLS: user:$(MYSQL_PASSWORD)@tcp(host:3306)/db?parseTime=true
  • ✅ DATABASE_URL with TLS: user:$(MYSQL_PASSWORD)@tcp(host:3306)/db?parseTime=true&tls=true

Configuration Tests

  • ✅ TLS correctly omitted when disabled (no tls=false)
  • ✅ Invalid MYSQL_* env vars removed
  • ✅ Probe authentication with root password
  • ✅ All settings passed as args to mysqld

Key Features

  1. Full MySQL Support: In-cluster deployment for dev/test or external MySQL for production
  2. Security: Secret management with option for external secrets, TLS support
  3. Persistence: PVC with configurable size (10Gi default) and storage class
  4. Resource Management: Configurable CPU/Memory limits (256Mi-1Gi, 100m-1000m)
  5. Health Monitoring: Authenticated liveness and readiness probes
  6. Configuration: Character set, collation, max connections as mysqld args
  7. TLS Support: Optional TLS with proper connection string syntax
  8. Validation: Comprehensive error checking with helpful messages

Installation Examples

Development (In-Cluster MySQL)

helm install llm-proxy deploy/helm/llm-proxy \
  --set image.repository=ghcr.io/sofatutor/llm-proxy \
  --set image.tag=latest \
  --set env.DB_DRIVER=mysql \
  --set mysql.enabled=true \
  --set-string mysql.auth.rootPassword="$(openssl rand -base64 32)" \
  --set-string mysql.auth.password="$(openssl rand -base64 32)" \
  --set secrets.create=true \
  --set secrets.data.managementToken="your-token"

Production (External MySQL)

kubectl create secret generic llm-proxy-db \
  --from-literal=DATABASE_URL="user:pass@tcp(host:3306)/db?parseTime=true&tls=true"

helm install llm-proxy deploy/helm/llm-proxy \
  --set image.repository=ghcr.io/sofatutor/llm-proxy \
  --set image.tag=latest \
  --set env.DB_DRIVER=mysql \
  --set secrets.managementToken.existingSecret.name=llm-proxy-secrets \
  --set secrets.databaseUrl.existingSecret.name=llm-proxy-db
Original prompt

This section details on the original issue you should resolve

<issue_title>[MySQL] Helm Chart Support</issue_title>
<issue_description>## Summary

Update Helm charts to support MySQL deployment as an alternative to PostgreSQL, including configuration values, templates, and deployment documentation.

Parent Epic

Part of #240 - Add MySQL as Optional Database Backend


Kubernetes Architecture

flowchart TB
    subgraph HelmChart["Helm Chart: llm-proxy"]
        subgraph Proxy["LLM Proxy Deployment"]
            DEP[Deployment]
            SVC[Service]
            CM[ConfigMap]
            SEC[Secret]
        end
        
        subgraph Database["Database Layer"]
            subgraph SQLite["SQLite - default"]
                PVC_LITE[PersistentVolumeClaim]
            end
            
            subgraph PostgreSQL["PostgreSQL - optional"]
                PG_SS[StatefulSet]
                PG_SVC[Service]
                PG_SEC[Secret]
                PG_PVC[PVC Template]
            end
            
            subgraph MySQL["MySQL - NEW optional"]
                MY_SS["StatefulSet NEW"]
                MY_SVC["Service NEW"]
                MY_SEC["Secret NEW"]
                MY_PVC["PVC Template NEW"]
            end
        end
    end
    
    DEP -->|DB_DRIVER=sqlite| PVC_LITE
    DEP -->|DB_DRIVER=postgres| PG_SVC
    DEP -->|DB_DRIVER=mysql| MY_SVC
Loading

Detailed Task Breakdown

Phase 1: Values Configuration

Task Description Files
1.1 Add database.mysql section to values values.yaml
1.2 Configure image settings values.yaml
1.3 Add auth configuration section values.yaml
1.4 Add persistence configuration values.yaml
1.5 Add resource limits/requests values.yaml
1.6 Add MySQL-specific config options values.yaml

Phase 2: MySQL StatefulSet Template

Task Description Files
2.1 Create MySQL StatefulSet template templates/mysql-statefulset.yaml
2.2 Configure container spec templates/mysql-statefulset.yaml
2.3 Add volumeClaimTemplates templates/mysql-statefulset.yaml
2.4 Configure liveness/readiness probes templates/mysql-statefulset.yaml
2.5 Add init containers if needed templates/mysql-statefulset.yaml
2.6 Add conditional rendering templates/mysql-statefulset.yaml

Phase 3: MySQL Service Template

Task Description Files
3.1 Create MySQL Service template templates/mysql-service.yaml
3.2 Configure ClusterIP service templates/mysql-service.yaml
3.3 Add port configuration (3306) templates/mysql-service.yaml
3.4 Add conditional rendering templates/mysql-service.yaml

Phase 4: Secrets Management

Task Description Files
4.1 Create MySQL secrets template templates/mysql-secret.yaml
4.2 Handle root password templates/mysql-secret.yaml
4.3 Handle application password templates/mysql-secret.yaml
4.4 Add conditional rendering templates/mysql-secret.yaml

Phase 5: Proxy Integration

Task Description Files
5.1 Update deployment template for MySQL env vars templates/deployment.yaml
5.2 Add DATABASE_URL generation for MySQL templates/deployment.yaml
5.3 Add secret references templates/deployment.yaml
5.4 Update helpers if needed templates/_helpers.tpl

Phase 6: Example and Documentation

Task Description Files
6.1 Create MySQL example values file examples/values-mysql.yaml
6.2 Update Helm README README.md
6.3 Add installation examples README.md

Values Structure

Database Section Hierarchy

flowchart TB
    subgraph Values["values.yaml"]
        DB[database]
        DB --> TYPE["type: sqlite/postgres/mysql"]
        
        DB --> MYSQL[mysql]
        MYSQL --> ENABLED["enabled: false"]
        MYSQL --> IMAGE[image]
        MYSQL --> AUTH[auth]
        MYSQL --> PERSIST[persistence]
        MYSQL --> RES[resources]
        MYSQL --> EXTRA[extraConfig]
        
        IMAGE --> REPO["repository: mysql"]
        IMAGE --> TAG["tag: 8.0"]
        
        AUTH --> ROOT["rootPassword"]
        AUTH --> DBNAME["database: llmproxy"]
        AUTH --> USER["username: llmproxy"]
        AUTH --> PASS["password"]
        
        PERSIST --> P_EN["enabled: true"]
        PERSIST --> P_SC["storageClass"]
        PERSIST --> P_SZ["size: 10Gi"]
    end
Loading

Template Conditional Logic

flowchart TD
    START[Helm Install]
    CHECK{database.type?}
    
    CHECK -->|mysql| MYSQL_PATH
    CHECK -->|other| OTHER_PATH
    
    subgraph MYSQL_PATH["MySQL Templates Rendered"]
        RENDER_SS[mysql-statefulset.ya...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes sofatutor/llm-proxy#244

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs.
Loading

…mentation

Co-authored-by: mfittko <326798+mfittko@users.noreply.github.com>
Copilot AI changed the title [WIP] Update Helm charts for MySQL deployment support Add MySQL support to Helm chart Jan 2, 2026
Copilot AI requested a review from mfittko January 2, 2026 20:50
@mfittko mfittko marked this pull request as ready for review January 2, 2026 20:50
Copilot AI review requested due to automatic review settings January 2, 2026 20:50
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements MySQL as an optional database backend for Kubernetes deployments via Helm chart, following the existing PostgreSQL pattern. It enables both in-cluster MySQL (for development/testing) and external MySQL (for production) configurations.

Key Changes

  • Adds complete MySQL support including StatefulSet, Service, and Secret templates
  • Implements MySQL connection string generation with TLS support
  • Adds comprehensive validation logic to prevent configuration conflicts
  • Provides example values and documentation for MySQL deployments

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
deploy/helm/llm-proxy/values.yaml Adds MySQL configuration section with auth, persistence, resources, and TLS options mirroring PostgreSQL structure
deploy/helm/llm-proxy/templates/mysql-statefulset.yaml Defines single-replica MySQL StatefulSet with health probes, volume claims, and configurable resources
deploy/helm/llm-proxy/templates/mysql-service.yaml Creates headless ClusterIP service on port 3306 for stable StatefulSet network identity
deploy/helm/llm-proxy/templates/mysql-secret.yaml Manages MySQL credentials with conditional rendering based on existingSecret configuration
deploy/helm/llm-proxy/templates/deployment.yaml Integrates MySQL password injection and DATABASE_URL construction into proxy deployment
deploy/helm/llm-proxy/templates/_helpers.tpl Adds MySQL helper functions for connection URL generation and comprehensive configuration validation
deploy/helm/llm-proxy/examples/values-mysql.yaml Provides annotated example configuration for in-cluster MySQL deployment
deploy/helm/llm-proxy/README.md Documents both external (production) and in-cluster (development) MySQL deployment patterns
deploy/helm/llm-proxy/Chart.yaml Adds MySQL support annotations indicating build tag requirements

Comment on lines 67 to 77
livenessProbe:
exec:
command:
- mysqladmin
- ping
- -h
- localhost
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mysqladmin ping command requires authentication when a root password is set. The probe will fail because no password is provided. Add the -u root and -p${MYSQL_ROOT_PASSWORD} arguments to the probe commands to fix authentication issues.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in cb06290. Added -u root -p${MYSQL_ROOT_PASSWORD} authentication to the liveness probe command using shell execution.

@mfittko
Copy link
Contributor

mfittko commented Jan 2, 2026

@copilot fix the comments yourself.

- Add authentication to mysqladmin ping probes (requires -u root -p$MYSQL_ROOT_PASSWORD)
- Remove invalid MYSQL_* environment variables (only valid as args)
- Fix TLS parameter in connection string (omit when disabled, not tls=false)

Co-authored-by: mfittko <326798+mfittko@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 2, 2026

@copilot fix the comments yourself.

All issues fixed in cb06290:

  1. Added authentication to mysqladmin ping probes
  2. Fixed TLS connection string syntax (omit param when disabled)
  3. Removed invalid MySQL environment variables

Copy link
Contributor

@mfittko mfittko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comprehensive Review: Add MySQL Support to Helm Chart

Summary

This PR adds comprehensive MySQL support to the llm-proxy Helm chart, enabling users to deploy with MySQL as an alternative database backend alongside SQLite and PostgreSQL. The implementation addresses issue #244 as part of the MySQL epic (#240).


✅ Strengths

1. Complete Template Set

The PR provides a full set of Kubernetes resources mirroring the PostgreSQL pattern:

  • mysql-statefulset.yaml (105 lines) - StatefulSet with proper volume management
  • mysql-service.yaml (20 lines) - Headless ClusterIP service for stable network identity
  • mysql-secret.yaml (21 lines) - Secure password storage with base64 encoding

2. Comprehensive Helper Functions (_helpers.tpl)

126 lines of well-structured helper functions:

  • llm-proxy.mysql.host, llm-proxy.mysql.port, llm-proxy.mysql.database
  • llm-proxy.mysql.secretName, llm-proxy.mysql.secretKey, llm-proxy.mysql.rootSecretKey
  • llm-proxy.mysql.url - Constructs the correct MySQL DSN format
  • llm-proxy.validateMysqlConfig - Comprehensive validation with clear error messages

3. Configuration Validation

The validation logic in _helpers.tpl is excellent:

{{- if and $hasInCluster $hasExternal }}
  {{- fail "Configuration error: Cannot use both in-cluster MySQL (mysql.enabled=true) and external MySQL (secrets.databaseUrl) at the same time." }}
{{- end }}

This prevents misconfigurations and provides actionable error messages.

4. Proper TLS Handling

The TLS connection string logic is correct after the fix:

  • Disabled: No tls parameter (not tls=false which is invalid)
  • Enabled: &tls=true
  • Skip verify: &tls=skip-verify

5. Authenticated Health Probes

The StatefulSet uses proper authenticated probes:

command:
- sh
- -c
- mysqladmin ping -h localhost -u root -p${MYSQL_ROOT_PASSWORD}

This addresses the initial review feedback and ensures probes work when MySQL is password-protected.

6. Well-Documented Example

The examples/values-mysql.yaml (128 lines) provides a complete, commented example for development deployments with clear "CHANGE-ME" placeholders.

7. MySQL Config via Args (Not Env Vars)

Correctly passes MySQL configuration as command-line arguments:

args:
{{- if .Values.mysql.extraConfig.maxConnections }}
- --max-connections={{ .Values.mysql.extraConfig.maxConnections }}
{{- end }}

This addresses the feedback that MYSQL_MAX_CONNECTIONS, MYSQL_CHARACTER_SET_SERVER, etc. are not valid environment variables for the official MySQL image.


📝 Observations (Non-Blocking)

1. README TLS Documentation

The README mentions tls=skip-verify as an option:

For production, enable TLS with tls=true or tls=skip-verify (not recommended)

While the "(not recommended)" note is present, consider being more explicit about the security implications of skipping verification.

2. Single-Replica StatefulSet

The MySQL StatefulSet is hardcoded to replicas: 1:

replicas: 1

This is appropriate for simple deployments but may warrant a note that for production HA, users should use an external MySQL cluster (Aurora, RDS, etc.).

3. Storage Class Handling

The special handling for storageClass: "-" to use an empty storageClassName is good:

{{- if (eq "-" .Values.mysql.persistence.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: {{ .Values.mysql.persistence.storageClass | quote }}
{{- end }}

This allows users to explicitly request no storage class.


🔍 Previous Review Comments (All Resolved)

Issue Status
mysqladmin ping missing authentication ✅ Fixed (cb06290)
TLS false invalid syntax ✅ Fixed (cb06290)
Invalid MySQL environment variables ✅ Fixed (cb06290)
Readiness probe auth ✅ Fixed (cb06290)

All 4 review threads from the automated reviewer have been addressed.


📁 Files Changed Summary

File Lines Purpose
templates/mysql-statefulset.yaml +105 (new) MySQL StatefulSet with PVC
templates/_helpers.tpl +126 MySQL helper functions
examples/values-mysql.yaml +128 (new) Example configuration
values.yaml +80 MySQL configuration section
README.md +61 MySQL documentation
templates/mysql-secret.yaml +21 (new) Password secret
templates/mysql-service.yaml +20 (new) Headless service
templates/deployment.yaml +11/-1 MySQL env vars integration
Chart.yaml +4 MySQL annotations

Total: +556 additions, -1 deletion across 9 files


🧪 Testing

The PR description indicates template rendering tests passed:

  • ✅ MySQL StatefulSet renders with authenticated probes
  • ✅ MySQL Service renders as headless ClusterIP
  • ✅ MySQL Secret renders with base64 encoded passwords
  • ✅ DATABASE_URL correctly formatted with/without TLS
  • ✅ Configuration validation catches misconfigured deployments

Verdict: APPROVE

This PR is ready to merge. It provides:

  1. Complete MySQL Helm support following the established PostgreSQL pattern
  2. Proper validation with helpful error messages
  3. Correct TLS handling (fixed after review)
  4. Authenticated health probes (fixed after review)
  5. Comprehensive documentation with examples
  6. All previous review comments resolved

The implementation is consistent with existing chart patterns and provides a solid foundation for MySQL deployments.

@mfittko mfittko merged commit 66ec3dc into main Jan 2, 2026
10 checks passed
@mfittko mfittko deleted the copilot/add-mysql-support-to-helm-chart branch January 2, 2026 21:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants