Skip to content
Back to skills

Helm Charts Setup

ASecurity

Create and manage Helm charts for Todo application deployment

  • 666 stars
  • 0 votes
  • 0 copies
  • 5 views
  • Added February 9, 2026
devopsgobashnextjsnodefastapidockerkubernetesgitapidatabase

Works with

  • vscode
  • api
  • mcp

Security analysis

A100/100

Scanned February 12, 2026

npx -y skills add majiayu000/claude-skill-registry --skill helm-charts-setup --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Helm Charts Setup?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Helm Charts Setup
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/majiayu000-helm-charts-setup/badge)](https://www.skillsdirectory.com/skills/majiayu000-helm-charts-setup)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: helm-charts-setup
description: Create and manage Helm charts for Todo application deployment
allowed-tools: Bash, Write, Read, Glob, Edit
---

# Helm Charts Setup Skill

## Quick Start

1. **Read Phase 4 Constitution** - `prompts/constitution-prompt-phase-4.md`
2. **Create Helm chart structure** - Use `helm create` or manual structure
3. **Write templates** - Convert K8s manifests to Helm templates
4. **Create values files** - Separate for dev, staging, production
5. **Test and install** - Verify chart works on Minikube

## Helm Chart Structure

```
helm/todo-app/
├── Chart.yaml
├── values.yaml
├── values-dev.yaml
├── values-staging.yaml
├── values-prod.yaml
├── .helmignore
├── templates/
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── configmap.yaml
│   ├── secret.yaml
│   ├── hpa.yaml
│   └── serviceaccount.yaml
└── tests/
    └── test-connection.yaml
```

## Chart.yaml

```yaml
apiVersion: v2
name: todo-app
description: A Helm chart for Todo Chatbot - Evolution of Todo Phase 4
type: application
version: 1.0.0
appVersion: "1.0.0"
keywords:
  - todo
  - chatbot
  - nextjs
  - fastapi
  - mcp
  - kubernetes
maintainers:
  - name: Developer
    email: dev@example.com
home: https://github.com/username/todo-web-hackthon
icon: https://raw.githubusercontent.com/username/todo-web-hackthon/main/assets/logo.png
sources:
  - https://github.com/username/todo-web-hackthon
```

## .helmignore

```
# Patterns to ignore when packaging
*.md
.git
.gitignore
tests/
*.tgz
node_modules/
__pycache__/
venv/
.env
.vscode/
.idea/
```

## Values.yaml

```yaml
# Default values for todo-app

# Global configuration
global:
  namespace: todo-app
  imagePullPolicy: IfNotPresent
  registry: docker.io

# Frontend configuration
frontend:
  enabled: true
  replicaCount: 2
  image:
    repository: username/todo-frontend
    tag: "latest"
    pullPolicy: IfNotPresent
  service:
    type: NodePort
    port: 80
    targetPort: 3000
  resources:
    requests:
      cpu: 100m
      memory: 128Mi
    limits:
      cpu: 500m
      memory: 256Mi
  autoscaling:
    enabled: false
    minReplicas: 2
    maxReplicas: 5
    targetCPUUtilizationPercentage: 70
  env:
    NODE_ENV: production
    NEXT_PUBLIC_API_URL: ""
    NEXT_PUBLIC_MCP_URL: ""

# Backend configuration
backend:
  enabled: true
  replicaCount: 2
  image:
    repository: username/todo-backend
    tag: "latest"
    pullPolicy: IfNotPresent
  service:
    type: ClusterIP
    port: 8000
  resources:
    requests:
      cpu: 200m
      memory: 256Mi
    limits:
      cpu: 1000m
      memory: 512Mi
  autoscaling:
    enabled: false
    minReplicas: 2
    maxReplicas: 5
    targetCPUUtilizationPercentage: 70
  env:
    DATABASE_URL: ""
    GEMINI_API_KEY: ""
    BETTER_AUTH_SECRET: ""
    MCP_SERVER_URL: ""

# MCP Server configuration
mcpServer:
  enabled: true
  replicaCount: 1
  image:
    repository: username/todo-mcp-server
    tag: "latest"
    pullPolicy: IfNotPresent
  service:
    type: ClusterIP
    port: 8001
  resources:
    requests:
      cpu: 100m
      memory: 64Mi
    limits:
      cpu: 300m
      memory: 128Mi
  env:
    GEMINI_API_KEY: ""

# Ingress configuration
ingress:
  enabled: true
  className: nginx
  annotations: {}
  hosts:
    - host: todo.local
      paths:
        - path: /
          pathType: Prefix
  tls: []

# Service Account
serviceAccount:
  create: true
  annotations: {}
  name: ""

# Dapr configuration (Phase 5)
dapr:
  enabled: false
  config: app-config
```

## Values Files by Environment

### values-dev.yaml (Minikube Local)
```yaml
global:
  registry: ""  # Use local images

frontend:
  replicaCount: 1
  resources:
    requests:
      cpu: 50m
      memory: 64Mi
    limits:
      cpu: 250m
      memory: 128Mi

backend:
  replicaCount: 1
  resources:
    requests:
      cpu: 100m
      memory: 128Mi
    limits:
      cpu: 500m
      memory: 256Mi

mcpServer:
  replicaCount: 1

ingress:
  enabled: true
  hosts:
    - host: todo.local
      paths:
        - path: /
          pathType: Prefix
```

### values-staging.yaml (Pre-production)
```yaml
global:
  registry: docker.io

frontend:
  replicaCount: 2
  autoscaling:
    enabled: true

backend:
  replicaCount: 2
  autoscaling:
    enabled: true

mcpServer:
  replicaCount: 1
```

### values-prod.yaml (Production)
```yaml
global:
  registry: ghcr.io  # GitHub Container Registry

frontend:
  replicaCount: 3
  autoscaling:
    enabled: true
    minReplicas: 3
    maxReplicas: 10
    targetCPUUtilizationPercentage: 70

backend:
  replicaCount: 3
  autoscaling:
    enabled: true
    minReplicas: 3
    maxReplicas: 10
    targetCPUUtilizationPercentage: 70

ingress:
  enabled: true
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
  tls:
    - secretName: todo-tls
      hosts:
        - todo.example.com
  hosts:
    - host: todo.example.com
      paths:
        - path: /
          pathType: Prefix
```

## Template Files

### _helpers.tpl

```yaml
{{- /*
Expand the name of the chart.
*/}}
{{- define "todo-app.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{- /*
Create a default fully qualified app name.
*/}}
{{- define "todo-app.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{- /*
Create chart name and version as used by the chart label.
*/}}
{{- define "todo-app.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{- /*
Common labels
*/}}
{{- define "todo-app.labels" -}}
helm.sh/chart: {{ include "todo-app.chart" . }}
{{ include "todo-app.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{- /*
Selector labels
*/}}
{{- define "todo-app.selectorLabels" -}}
app.kubernetes.io/name: {{ include "todo-app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
```

### templates/deployment.yaml

```yaml
{{- if .Values.frontend.enabled }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "todo-app.fullname" . }}-frontend
  namespace: {{ .Release.Namespace }}
  labels:
    {{- include "todo-app.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.frontend.replicaCount }}
  selector:
    matchLabels:
      app: frontend
      {{- include "todo-app.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        app: frontend
        {{- include "todo-app.selectorLabels" . | nindent 8 }}
    spec:
      containers:
      - name: frontend
        image: "{{ .Values.global.registry }}/{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag }}"
        imagePullPolicy: {{ .Values.frontend.image.pullPolicy }}
        ports:
        - name: http
          containerPort: {{ .Values.frontend.service.targetPort }}
          protocol: TCP
        env:
        - name: NODE_ENV
          value: {{ .Values.frontend.env.NODE_ENV | quote }}
        {{- range $key, $value := .Values.frontend.env }}
        {{- if ne $key "NODE_ENV" }}
        - name: {{ $key }}
          value: {{ $value | quote }}
        {{- end }}
        {{- end }}
        resources:
          {{- toYaml .Values.frontend.resources | nindent 10 }}
        livenessProbe:
          httpGet:
            path: /
            port: {{ .Values.frontend.service.targetPort }}
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /
            port: {{ .Values.frontend.service.targetPort }}
          initialDelaySeconds: 5
          periodSeconds: 5
{{- end }}
```

### templates/service.yaml

```yaml
{{- if .Values.frontend.enabled }}
---
apiVersion: v1
kind: Service
metadata:
  name: {{ include "todo-app.fullname" . }}-frontend
  namespace: {{ .Release.Namespace }}
  labels:
    {{- include "todo-app.labels" . | nindent 4 }}
spec:
  type: {{ .Values.frontend.service.type }}
  selector:
    app: frontend
    {{- include "todo-app.selectorLabels" . | nindent 4 }}
  ports:
  - name: http
    port: {{ .Values.frontend.service.port }}
    targetPort: {{ .Values.frontend.service.targetPort }}
    protocol: TCP
{{- end }}
```

### templates/hpa.yaml

```yaml
{{- if and .Values.frontend.enabled .Values.frontend.autoscaling.enabled }}
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: {{ include "todo-app.fullname" . }}-frontend
  namespace: {{ .Release.Namespace }}
  labels:
    {{- include "todo-app.labels" . | nindent 4 }}
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: {{ include "todo-app.fullname" . }}-frontend
  minReplicas: {{ .Values.frontend.autoscaling.minReplicas }}
  maxReplicas: {{ .Values.frontend.autoscaling.maxReplicas }}
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: {{ .Values.frontend.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
```

### templates/configmap.yaml

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "todo-app.fullname" . }}-config
  namespace: {{ .Release.Namespace }}
  labels:
    {{- include "todo-app.labels" . | nindent 4 }}
data:
  MCP_SERVER_URL: "http://{{ include "todo-app.fullname" . }}-mcp-server:8001"
  {{- if .Values.frontend.enabled }}
  NEXT_PUBLIC_API_URL: "http://{{ include "todo-app.fullname" . }}-backend:8000"
  NEXT_PUBLIC_MCP_URL: "http://{{ include "todo-app.fullname" . }}-mcp-server:8001"
  {{- end }}
```

### templates/secret.yaml

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: {{ include "todo-app.fullname" . }}-secrets
  namespace: {{ .Release.Namespace }}
  labels:
    {{- include "todo-app.labels" . | nindent 4 }}
type: Opaque
stringData:
  GEMINI_API_KEY: {{ .Values.backend.env.GEMINI_API_KEY | default "" | quote }}
  BETTER_AUTH_SECRET: {{ .Values.backend.env.BETTER_AUTH_SECRET | default "" | quote }}
  {{- if .Values.backend.env.DATABASE_URL }}
  DATABASE_URL: {{ .Values.backend.env.DATABASE_URL | quote }}
  {{- end }}
```

### templates/ingress.yaml

```yaml
{{- if .Values.ingress.enabled }}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ include "todo-app.fullname" . }}-ingress
  namespace: {{ .Release.Namespace }}
  labels:
    {{- include "todo-app.labels" . | nindent 4 }}
  {{- with .Values.ingress.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
spec:
  {{- if .Values.ingress.className }}
  ingressClassName: {{ .Values.ingress.className }}
  {{- end }}
  rules:
  {{- range .Values.ingress.hosts }}
  - host: {{ .host }}
    http:
      paths:
      {{- range .paths }}
      - path: {{ .path }}
        pathType: {{ .pathType }}
        backend:
          service:
            name: {{ include "todo-app.fullname" $ }}-frontend
            port:
              number: {{ $.Values.frontend.service.port }}
      {{- end }}
  {{- end }}
  {{- if .Values.ingress.tls }}
  tls:
  {{- toYaml .Values.ingress.tls | nindent 2 }}
  {{- end }}
{{- end }}
```

### templates/NOTES.txt

```txt
Thank you for installing {{ .Chart.Name }}!

Your release is named {{ .Release.Name }}.

To learn more about the release, try:

  $ helm status {{ .Release.Name }}

To get the application URL:

  {{- if .Values.ingress.enabled }}
  http://{{ (index .Values.ingress.hosts 0).host }}
  {{- else }}
  Run: kubectl port-forward svc/{{ include "todo-app.fullname" . }}-frontend 8080:80
  {{- end }}

To upgrade the release:

  $ helm upgrade {{ .Release.Name }} .

To rollback the release:

  $ helm rollback {{ .Release.Name }}
```

## Helm Commands

```bash
# Create new chart
helm create todo-app

# Lint chart
helm lint helm/todo-app

# Package chart
helm package helm/todo-app

# Install chart
helm install todo-app ./helm/todo-app \
  --namespace todo-app \
  --create-namespace \
  -f helm/todo-app/values-dev.yaml

# Upgrade chart
helm upgrade todo-app ./helm/todo-app \
  -f helm/todo-app/values-prod.yaml

# Get release status
helm status todo-app

# Get release values
helm get values todo-app

# Get release history
helm history todo-app

# Rollback
helm rollback todo-app [REVISION]

# Uninstall
helm uninstall todo-app

# List all releases
helm list --all-namespaces

# Dry run (preview)
helm upgrade --dry-run --debug todo-app ./helm/todo-app
```

## kubectl-ai Integration

```bash
# Using kubectl-ai with Helm
kubectl-ai "install todo-app helm chart to production namespace"
kubectl-ai "upgrade todo-app with new image tag v1.2.0"
kubectl-ai "scale frontend using helm"
kubectl-ai "analyze helm release for issues"
kubectl-ai "optimize helm values for cost reduction"
```

## Verification Checklist

After creating Helm chart:
- [ ] Chart.yaml has correct API version (v2)
- [ ] All templates use proper helper functions
- [ ] Values file has all configurable parameters
- [ ] .helmignore excludes unnecessary files
- [ ] NOTES.txt provides helpful information
- [ ] Helm lint passes without warnings
- [ ] Chart can be packaged successfully
- [ ] Chart installs on Minikube
- [ ] All services are accessible
- [ ] Upgrades work without issues

## Troubleshooting

| Issue | Cause | Fix |
|--------|--------|-----|
| Template fails | Invalid Helm syntax | Run `helm lint` to find errors |
| Values not applied | Wrong values path | Use `-f` flag with correct path |
| Release fails | Missing secrets | Create secrets separately or use `--set-file` |
| Can't upgrade | Existing release conflict | Use `helm upgrade` instead of `install` |
| Ingress not working | Wrong annotations | Verify ingress controller is installed |

## CI/CD Integration

### GitHub Actions Example
```yaml
- name: Build and push Docker images
  run: |
    docker build -t ghcr.io/${{ github.repository }}/frontend:${{ github.sha }} ./frontend
    docker build -t ghcr.io/${{ github.repository }}/backend:${{ github.sha }} ./backend
    docker build -t ghcr.io/${{ github.repository }}/mcp-server:${{ github.sha }} ./backend
    echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
    docker push ghcr.io/${{ github.repository }}/frontend:${{ github.sha }}
    docker push ghcr.io/${{ github.repository }}/backend:${{ github.sha }}
    docker push ghcr.io/${{ github.repository }}/mcp-server:${{ github.sha }}

- name: Deploy with Helm
  run: |
    helm upgrade --install todo-app ./helm/todo-app \
      --namespace todo-app \
      --create-namespace \
      --set global.registry=ghcr.io \
      --set frontend.image.tag=${{ github.sha }} \
      --set backend.image.tag=${{ github.sha }} \
      --set mcpServer.image.tag=${{ github.sha }} \
      -f helm/todo-app/values-prod.yaml
```

## Next Steps

After Helm chart creation:
1. Test on Minikube with values-dev.yaml
2. Test on staging cluster with values-staging.yaml
3. Prepare for production deployment with values-prod.yaml
4. Add Dapr annotations for Phase 5

## References

- [Helm Documentation](https://helm.sh/docs/)
- [Helm Best Practices](https://helm.sh/docs/chart_best_practices/)
- [Helm Template Guide](https://helm.sh/docs/chart_template_guide/)
- [Phase 4 Constitution](../../../prompts/constitution-prompt-phase-4.md)
- [Phase 4 Plan](../../../prompts/plan-prompt-phase-4.md)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.