HelmUp is a Kubernetes-based utility designed to upgrade the configuration of both community-maintained and self-owned Helm charts.
Helmup is an innovative tool designed for Ops Engineers, making Helm chart upgrades effortless and efficient.
As an Ops Engineer, you often need to upgrade Helm chart versions for various reasons:
- Security Fixes
- New Features
- Staying Up-to-Date
- And More...
To streamline this process, we created HELMUP!
Leveraging AI, Helmup scans your GitHub repositories, identifies all your Helm charts, and searches online for the latest updates. Once a new version is found, the AI engine automatically updates your files and values, and then:
- Creates a Pull Request (PR) in your GitHub repository
- Optionally generates a Jira ticket
- Optionally sends notifications via Slack or Microsoft Teams
Helmup is built on a microservices architecture, consisting of three core components:
- Engine: Handles the AI and upgrade mechanism
- Scraper: Scans your GitHub repository for Helm charts
- Notifications: Manages notifications through MS Teams or Slack
Chart Type | Upgrade Description |
---|---|
Self-owned Charts |
Upgrade to a predefined, desired Kubernetes version. |
Community-maintained Charts |
Upgrade to the next available version. |
⚠️ Note: The helmup Application is designed to work on Values.yaml files resides in a Git Repo (Gitops style.)
We currently not supprting any other installation methods for helm (For example, using --set). Upcomming feature in the CLI.
- OpenAI/ChatGPT token - for use in the engine. How to create this token?
Note: All models versions are supported. Best performence with ChatGPT 4.0
- GitHub Token - To scrape customer Repo. How to create this token?
Optionally:
- Slack / Teams Webhook Token
- Jira token
The application expects a k8s secret "helmup-secret" with the following keys:
["openai_token", "github_token", "jira_token"(Optional), "webhook_url"(Optional) ]
We provided a convinient way to use ExternSecrets
application to retreive them. If used externally, make sure to create a secret named helmup-secret
with these keys!
See Mandatory Secrets section for more info!
-
Access the Helm Chart:
Go directly to the Helmup Helm chart on ArtifactHub. -
Download the Latest Version:
helm repo add sirrend https://sirrend.github.io/helmup/releases/ helm repo update helm pull sirrend/helmup
-
Install or Upgrade:
You can now proceed to install or upgrade the Helm chart using the downloaded version.helm upgrade --install <release-name> sirrend/helmup --version 0.1.0
Helmup applications supports both using a pre-defined k8s secret, OR using the external-secrets operator.
Note: If using a pre-defined k8s secret, please make sure to set the following values:
- global.secretNameOverride="<Your_predefined_secret_name>"
- global.externalSecret.enabled="false"
Secret Key | Required | Secret Name | Description | Comment |
---|---|---|---|---|
openai_token |
true | helmup-secret |
Your personal OPENAI token to be used in the engine. | Supports any version model. Preferrable ChatGPT 4.0 How to create this token? |
github_token |
true | helmup-secret |
Your persoanl github token to be used to scrape the git repo. | How to create this token? |
jira_token |
false | helmup-secret |
Your Jira token to be used to open Jira tickets (Optional). | |
webhook_url |
false | helmup-secret |
Your webhook URL for Slack / MS Teams only (Optional). | Create Slack Webhook URL |
Global
Key | Type | Default | Description |
---|---|---|---|
global.appConfig.github.CUSTOMER_NAME | string | "sirrend" |
Required: Github account / project name |
global.appConfig.github.GIT_BRANCH | string | "main" |
Required: Github branch name to scrape |
global.appConfig.github.GIT_REPOSITORY_NAME | string | "kuba_test" |
Required: Github repo name |
global.appConfig.github.GIT_REPOSITORY_URL | string | "https://github.com/sirrend/kuba_test.git" |
Required: Github repository URL |
global.appConfig.jira.enabled | bool | true |
Required: Whether to enable jira notifications / tickets creation |
global.appConfig.jira.project_key | string | "SI" |
The jira project key |
global.appConfig.jira.server_url | string | "https://sirrend.atlassian.net/" |
The jira server URL |
global.appConfig.jira.username | string | "yuvalpress@gmail.com" |
Jira username |
global.appConfig.notifications.enabled | bool | true |
Required: Whether or not to send notification via channels (slack or teams - as configured in the notifications section) |
global.appConfig.notifications.type | string | "slack" |
Valid options are ["slack", "teams", "None"] |
global.appConfig.reformat_helm_templates | bool | true |
Whether or not to improve the helm manifest using AI capabilities. Recommended! |
global.appConfig.target_kube_version | string | "1.30.0" |
|
global.appConfig.upgrade_majors | string | "disabled" |
Whether or not to upgrade major chart's versions |
global.externalSecret.backendType | string | "secretsManager" |
Specify the secretStoreRef, e.g., secretsManager for AWS Secrets Manager |
global.externalSecret.enabled | bool | true |
Required: Support for external secrets operator: Enables/Disables externalSecret to be imported to the namespace. Conflicts with "secretNameOverride" |
global.externalSecret.refreshInterval | string | "30h" |
Speficy the refresh interval for the secret |
global.externalSecret.secretKeyGithub | string | "sirrend-github-token" |
The secret name to pull from SecretStore for the Github token |
global.externalSecret.secretKeyJira | string | "sirrend-jira-token" |
The secret name to pull from SecretStore for the Jira token |
global.externalSecret.secretKeyNotificationsWebhookUrl | string | "sirrend-slack-webhook-secret" |
The secret name to pull from SecretStore for the notifications channel (slack/teams) webhhok url |
global.externalSecret.secretKeyOpenAI | string | "chatgpt-token" |
The secret name to pull from SecretStore for the openAI chatgpt token |
global.externalSecret.secretStoreRef | object | {"kind":"ClusterSecretStore","name":"aws-secrets-manager"} |
Specify the secretStoreRef |
global.externalSecret.secretTemplate | object | {"annotations":{},"data":{},"labels":{},"type":"Opaque"} |
externalSecret template |
global.externalSecret.secretVersion | string | "" |
Optional |
global.secretNameOverride | string | "" |
If using a self-defined secret, specify its name |
Applications
Key | Type | Default | Description |
---|---|---|---|
engine.affinity | object | {} |
|
engine.autoscaling.enabled | bool | false |
|
engine.autoscaling.maxReplicas | int | 10 |
Max number of pods to run |
engine.autoscaling.minReplicas | int | 1 |
Min number of pods to run |
engine.autoscaling.targetCPUUtilizationPercentage | int | 80 |
The threshold of CPU utilization to scale up upom |
engine.fullnameOverride | string | "" |
|
engine.image.pullPolicy | string | "Always" |
imagePullPolicy - Highly recommended to leave this as Always |
engine.image.repository | string | "sirrend/helmup-engine" |
Repository for the helmup-engine image |
engine.image.tag | string | "0.1.13" |
The helmup-engine image tag to use |
engine.imagePullSecrets | list | [] |
A list of image pull secret names to use |
engine.ingress.annotations | object | {} |
|
engine.ingress.className | string | "" |
From Kubernetes 1.18+ this field is supported in case your ingress controller supports it. When set, you do not need to add the ingress class as annotation. |
engine.ingress.enabled | bool | false |
Enables an ingress object for the application |
engine.ingress.hosts[0].host | string | "chart-example.local" |
|
engine.ingress.hosts[0].paths[0].path | string | "/" |
|
engine.ingress.hosts[0].paths[0].pathType | string | "ImplementationSpecific" |
|
engine.ingress.tls | list | [] |
|
engine.livenessProbe.enabled | bool | true |
|
engine.livenessProbe.failureThreshold | int | 3 |
|
engine.livenessProbe.initialDelaySeconds | int | 15 |
|
engine.livenessProbe.path | string | "/healthcheck" |
Please do not change this |
engine.livenessProbe.periodSeconds | int | 300 |
|
engine.livenessProbe.port | int | 8090 |
|
engine.livenessProbe.timeoutSeconds | int | 5 |
|
engine.nameOverride | string | "engine" |
|
engine.nodeSelector | object | {} |
|
engine.podAnnotations | object | {} |
Extra annotations for the engine pod |
engine.podLabels | object | {} |
|
engine.podSecurityContext | object | {} |
Defines the podSecurityContext for the engine pod |
engine.readinessProbe.enabled | bool | false |
|
engine.readinessProbe.failureThreshold | int | 3 |
|
engine.readinessProbe.initialDelaySeconds | int | 20 |
|
engine.readinessProbe.path | string | "/healthcheck" |
Please do not change this |
engine.readinessProbe.periodSeconds | int | 10 |
|
engine.readinessProbe.port | int | 8090 |
|
engine.readinessProbe.timeoutSeconds | int | 5 |
|
engine.replicaCount | int | 1 |
Number of engine pods to run |
engine.resources | object | {} |
A resources block for the engine pod |
engine.securityContext | object | {} |
The container securityContext for the controller container |
engine.service.port | int | 80 |
The port to run the dashboard engine on |
engine.service.type | string | "ClusterIP" |
The type of the engine service |
engine.serviceAccount.annotations | object | {} |
Extra annotations for the service account that will be created |
engine.serviceAccount.automount | bool | true |
If true, the service account will be mounted automatically |
engine.serviceAccount.create | bool | true |
If true, a service account will be created for the controller. If set to false, uses default serviceAccount |
engine.serviceAccount.name | string | "" |
The name of an existing service account to use for the controller |
engine.startupProbe.enabled | bool | true |
|
engine.startupProbe.failureThreshold | int | 3 |
|
engine.startupProbe.initialDelaySeconds | int | 10 |
|
engine.startupProbe.path | string | "/healthcheck" |
Please do not change this |
engine.startupProbe.periodSeconds | int | 10 |
|
engine.startupProbe.port | int | 8090 |
|
engine.startupProbe.timeoutSeconds | int | 5 |
|
engine.tolerations | list | [] |
|
engine.volumeMounts | list | [] |
Extra volumes for the engine pod |
engine.volumes | list | [] |
Extra volume mounts for the engine container |
notifications.affinity | object | {} |
|
notifications.enabled | bool | true |
|
notifications.fullnameOverride | string | "" |
|
notifications.image.pullPolicy | string | "Always" |
imagePullPolicy - Highly recommended to leave this as Always |
notifications.image.repository | string | "sirrend/helmup-notifications-service" |
Repository for the helmup-notifications-service image |
notifications.image.tag | string | "0.1.3" |
The helmup-github-scraper image tag to use |
notifications.imagePullSecrets | list | [] |
A list of image pull secret names to use |
notifications.livenessProbe.enabled | bool | true |
|
notifications.livenessProbe.failureThreshold | int | 3 |
|
notifications.livenessProbe.initialDelaySeconds | int | 15 |
|
notifications.livenessProbe.path | string | "/health" |
Please do not change this |
notifications.livenessProbe.periodSeconds | int | 300 |
|
notifications.livenessProbe.port | int | 9000 |
|
notifications.livenessProbe.timeoutSeconds | int | 5 |
|
notifications.nameOverride | string | "notifications-service" |
|
notifications.nodeSelector | object | {} |
|
notifications.podAnnotations | object | {} |
Extra annotations for the notifications pod |
notifications.podLabels | object | {} |
|
notifications.podSecurityContext | object | {} |
Defines the podSecurityContext for the notifications pod |
notifications.readinessProbe.enabled | bool | false |
|
notifications.readinessProbe.failureThreshold | int | 3 |
|
notifications.readinessProbe.initialDelaySeconds | int | 20 |
|
notifications.readinessProbe.path | string | "/health" |
Please do not change this |
notifications.readinessProbe.periodSeconds | int | 30 |
|
notifications.readinessProbe.port | int | 9000 |
|
notifications.readinessProbe.timeoutSeconds | int | 5 |
|
notifications.replicaCount | int | 1 |
Number of engine pods to run |
notifications.resources | object | {} |
A resources block for the notifications pod |
notifications.securityContext | object | {} |
The container securityContext for the controller container |
notifications.service.port | int | 80 |
The port to run the dashboard engine on |
notifications.service.type | string | "ClusterIP" |
The type of the engine service |
notifications.serviceAccount.annotations | object | {} |
Extra annotations for the service account that will be created |
notifications.serviceAccount.automount | bool | true |
If true, the service account will be mounted automatically |
notifications.serviceAccount.create | bool | true |
If true, a service account will be created for the controller. If set to false, uses default serviceAccount |
notifications.serviceAccount.name | string | "" |
The name of an existing service account to use for the controller |
notifications.startupProbe.enabled | bool | false |
|
notifications.startupProbe.failureThreshold | int | 3 |
|
notifications.startupProbe.initialDelaySeconds | int | 30 |
|
notifications.startupProbe.path | string | "/health" |
Please do not change this |
notifications.startupProbe.periodSeconds | int | 10 |
|
notifications.startupProbe.port | int | 9000 |
|
notifications.startupProbe.timeoutSeconds | int | 5 |
|
notifications.tolerations | list | [] |
|
notifications.volumeMounts | list | [] |
Extra volumes for the notifications pod |
notifications.volumes | list | [] |
Extra volume mounts for the notifications container |
scraper.affinity | object | {} |
|
scraper.cronJobExpression | string | "0 0 * * *" |
Required: the cronJob expressions to scrape the git repo |
scraper.failedJobsHistoryLimit | int | 1 |
Required: failed job history limit |
scraper.fullnameOverride | string | "" |
|
scraper.image.pullPolicy | string | "Always" |
imagePullPolicy - Highly recommended to leave this as Always |
scraper.image.repository | string | "sirrend/helmup-github-scraper" |
Repository for the helmup-github-scraper image |
scraper.image.tag | string | "0.1.4" |
The helmup-github-scraper image tag to use |
scraper.imagePullSecrets | list | [] |
A list of image pull secret names to use |
scraper.nameOverride | string | "github-scraper" |
|
scraper.nodeSelector | object | {} |
|
scraper.podAnnotations | object | {} |
Extra annotations for the scraper pod |
scraper.podLabels | object | {} |
|
scraper.podSecurityContext | object | {} |
Defines the podSecurityContext for the scraper pod |
scraper.replicaCount | int | 1 |
Number of engine pods to run |
scraper.resources | object | {} |
A resources block for the scraper pod |
scraper.securityContext | object | {} |
The container securityContext for the scraper container |
scraper.serviceAccount.annotations | object | {} |
Extra annotations for the service account that will be created |
scraper.serviceAccount.automount | bool | true |
If true, the service account will be mounted automatically |
scraper.serviceAccount.create | bool | true |
If true, a service account will be created for the controller. If set to false, uses default serviceAccount |
scraper.serviceAccount.name | string | "" |
The name of an existing service account to use for the controller |
scraper.successfulJobsHistoryLimit | int | 3 |
Required: successful job history limit |
scraper.tolerations | list | [] |
|
scraper.volumeMounts | list | [] |
Extra volumes for the scraper pod |
scraper.volumes | list | [] |
Extra volume mounts for the scraper container |
- Visit GitHub and sign in with your credentials.
- In the upper-right corner of any page, click on your profile photo, then select Settings from the dropdown menu.
- Scroll down to the bottom of the left sidebar and click on Developer settings.
- In the left sidebar, click on Personal access tokens.
- Then click on Tokens (classic).
- Click the Generate new token (Classic) button.
- Add a descriptive note to identify what this token will be used for.
- Select an expiration date for your token if you want it to automatically expire after a certain period. GitHub recommends setting a token expiration to keep your account secure.
- In the Select scopes section, check the box for repo. This will give the token full control of private repositories, including the ability to read and write to repositories, as well as access to issues and pull requests.
-
After selecting the necessary permissions, scroll down and click the Generate token button.
-
Copy your new personal access token. You won’t be able to see it again once you leave this page.
- Store your token securely. Treat it like a password—never share it publicly or expose it in your code. If your token is ever compromised, revoke it immediately and generate a new one.
- Security: Always keep your token secure. Do not hard-code it directly into your source files. Use environment variables or secret management tools.
- Revoking a Token: If you no longer need the token or if it is compromised, return to the Tokens (classic) section under Developer settings and click Delete next to the token to revoke it.
- Permissions: Be cautious with the permissions you assign to a token. Only grant the minimum permissions necessary for your use case.
To create a token for OpenAI's GPT models, including ChatGPT, you'll need to follow these steps to generate an API key through OpenAI:
If you don't already have an OpenAI account, you'll need to create one. Visit OpenAI's website and sign up for an account.
Once you've logged in to your OpenAI account, navigate to the API dashboard.
In the API dashboard, you will see an option to create a new API key. Click the "Create new secret key" button.
A new API key will be generated. Make sure to copy and save this key in a secure place, as it will not be shown again.
You can use this API key to authenticate requests to OpenAI's API endpoints. In your application or script, use this key to make requests to the OpenAI API, allowing you to access GPT-3.5, GPT-4, or other models.
- Security: Treat your API key like a password. Keep it private and never share it publicly. If your key is compromised, you can regenerate it from the API dashboard.
- Rate Limits and Usage: Be aware of OpenAI's rate limits and usage policies, which depend on your plan. You can monitor your usage on the same dashboard where you created the key.
- Billing: Ensure you understand the billing structure. Depending on your usage and the model you use, costs may vary. OpenAI provides details on pricing on their pricing page.
- Go to Slack and sign in with your workspace credentials.
- Visit the Slack API: Incoming Webhooks page.
- Click the Create an App button.
- In the pop-up window, select From scratch.
- Enter a name for your app (e.g., "My Webhook App").
- Select the Slack workspace where you want to install the app, then click Create App.
- Once your app is created, you will be redirected to the app settings page.
- In the left sidebar, click on Incoming Webhooks.
- Toggle the Activate Incoming Webhooks switch to On.
- Scroll down to the Webhook URLs for Your Workspace section.
- Click the Add New Webhook to Workspace button.
- You will be redirected to a page where you can select a channel to post messages to. Choose the appropriate channel from the dropdown list.
- Click the Allow button to grant your app permission to post in the selected channel.
- After allowing permissions, you will be redirected back to the Incoming Webhooks settings page.
- You will see a new webhook URL under the Webhook URLs for Your Workspace section.
- Copy the webhook URL. This is the URL you'll use to send messages to Slack from your external applications.
- To test your webhook, you can use a tool like
curl
or Postman to send a POST request. - Here's an example using
curl
in the terminal:curl -X POST -H 'Content-type: application/json' --data '{"text":"Hello, Slack!"}' YOUR_WEBHOOK_URL
- Upgrade capability for targeting specific community-chart versions.
- Enhanced UI for managing and visualizing the current state of charts.
- Extended support for additional notification channels and methods.
Stay tuned for more updates and improvements!
Name | Website | |
---|---|---|
Sirrend | business@sirrend.com | https://www.sirrend.io/ |