This Helm chart deploys the AnsibleForms application and its MySQL database on Kubernetes. It is designed for flexibility, security, and ease of use in both development and production environments.
- Deploys AnsibleForms and MySQL with configurable images and resources
- Handles all sensitive data (DB credentials, admin credentials, encryption secret) via Kubernetes Secrets
- All application environment variables are configurable via
values.yaml - Storage class and size for both server and MySQL are configurable
- Supports both dynamic provisioning (StorageClass-based) and pre-created static PVs
- Ingress is optional and highly customizable (hostname, TLS, annotations, etc.)
- Service type (ClusterIP, LoadBalancer, NodePort) is configurable, with support for static LoadBalancer IPs
- (Optional) Support for managing
forms.yaml,forms/*.yamldefinitions, andcustom.jsvia ConfigMaps
git clone https://github.com/ansibleguy76/ansibleforms-helm
cp ./ansibleforms-helm/values.yaml my_values.yamlUpdate the my_values.yaml to your taste.
application:
server:
env:
HTTPS: 1 # auto sets port to 443
ENCRYPTION_SECRET: "Abc123Abc123Abc123Abc123Abc123Abc1" # optional but recommended, 32 chars random string
storage:
server:
className: longhorn # example dynamic StorageClass
size: 5Gi
mysql:
className: longhorn
size: 5Gi
service:
server:
type: LoadBalancer
loadbalancer:
ip: 10.0.0.1 # AnsibleForms will be available at https://10.0.0.1application:
server:
env:
HTTPS: 0 # auto sets ports on 80 or 443
# ...other env vars (see values.yaml for all options)
ENCRYPTION_SECRET: "Abc123Abc123Abc123Abc123Abc123Abc1"
ADMIN_USERNAME: admin
ADMIN_PASSWORD: MyAppPassword1!!
mysql:
user: root
password: MyDbPassword1!!
storage:
server:
className: nfs-csi # just an example storage provider
size: 1Gi
mysql:
className: nfs-csi-nomap # just an example storage provider
size: 1Gi
container:
server:
image: ansibleguy/ansibleforms:betav6
resources:
limits:
cpu: "0.5"
memory: 512Mi
requests:
cpu: "0.25"
memory: 256Mi
mysql:
image: mysql:latest
resources:
limits:
cpu: "0.5"
memory: 512Mi
requests:
cpu: "0.25"
memory: 256Mi
service:
server:
type: ClusterIP # service is exposed with ingress
mysql:
type: ClusterIP
ingress:
enabled: true # enable ingress
className: nginx
hostname: ansibleforms.example.com
path: /
pathType: Prefix
tls:
enabled: true
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/rewrite-target: /
issuer: letsencrypt-prod
extraHosts: [] # ["other.example.com"]
extraPaths: [] # [{ path: /api, serviceName: server, servicePort: 80 }]
extraAnnotations: {}The chart supports two storage modes for both server and mysql:
- Dynamic provisioning (default) – uses a Kubernetes StorageClass to dynamically provision PVs.
- Static PVs – binds to pre-created PersistentVolumes by name.
Dynamic provisioning is the default mode. You typically configure:
storage:
server:
className: longhorn # or any other existing StorageClass
size: 5Gi
static:
enabled: false
mysql:
className: longhorn
size: 5Gi
static:
enabled: false- If
storage.<component>.classNameis set, the PVC will use that StorageClass. - If
classNameis omitted, the cluster's default StorageClass (if any) will be used. static.enabled: false(default) means novolumeNameis set, so the cluster can bind the PVC to dynamically provisioned PVs.
If you prefer to manage your own PersistentVolumes (for example, an NFS export or a hostPath PV), you can pre-create a PV and then tell the chart to bind to it.
Example: pre-create a static PV for MySQL:
apiVersion: v1
kind: PersistentVolume
metadata:
name: ansibleforms-mysql-pv
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteMany
storageClassName: "" # empty for static binding
persistentVolumeReclaimPolicy: Retain
nfs:
server: 10.0.0.10
path: /exports/ansibleforms-mysqlThen configure the chart to use it:
storage:
mysql:
size: 5Gi
static:
enabled: true
volumeName: ansibleforms-mysql-pv # must match the PV metadata.name
storageClassName: "" # must match the PV storageClassNameWhen static.enabled: true:
- The PVC will include a
volumeName(defaulting to<release>-mysql-pv/<release>-server-pvifvolumeNameis empty). - The PVC will use
static.storageClassName(or""if not provided). - This binds the PVC directly to the specified pre-created PV.
You can configure the same pattern for the server volume:
storage:
server:
size: 5Gi
static:
enabled: true
volumeName: ansibleforms-server-pv
storageClassName: ""If you do not need static PVs, simply leave static.enabled: false and use the dynamic provisioning mode.
AnsibleForms uses a main configuration file (forms.yaml) and can also load additional form definitions from a forms/ directory inside the persistent folder. It also supports a custom.js file for client-side customization, typically mounted at /app/dist/src/functions/custom.js as described in the AnsibleForms FAQ.
This chart provides optional values to mount those files from ConfigMaps:
forms:
configMap:
enabled: true
name: ansibleforms-forms # ConfigMap containing the main forms.yaml
key: forms.yaml # key in the ConfigMap
mountPath: /app/dist/persistent/forms.yaml
extraFormsConfigMap:
enabled: true
name: ansibleforms-forms-defs # ConfigMap containing multiple form YAMLs
mountPath: /app/dist/persistent/forms # mounted as a directory
customJs:
enabled: true
name: ansibleforms-custom-js # ConfigMap containing custom.js
key: custom.js # key in the ConfigMap
mountPath: /app/dist/src/functions/custom.jsWhen any of the enabled flags are false (the default), the chart behaves as before and does not mount the corresponding ConfigMap.
The following ConfigMap provides the main forms.yaml file, which defines categories, roles, and constants:
---
apiVersion: v1
kind: ConfigMap
metadata:
name: ansibleforms-forms
namespace: ansibleforms
data:
forms.yaml: |
categories:
- name: Default
icon: bars
- name: Demo
icon: heart
- name: Maintenance
icon: cogs
- name: Internal
icon: cogs
- name: Vmware
icon: cogs
roles:
- name: admin
groups:
- local/admins
- ldap/k8admins
- name: demo
groups:
- local/demo
- name: public
groups: []
- name: internal
groups:
- ldap/internal
users:
- ldap/FRoca
constants:
AF_PLAYBOOKS: /app/dist/persistent/playbooksWith the forms.configMap values set as shown earlier, this forms.yaml will be mounted at /app/dist/persistent/forms.yaml, which is the default location used by AnsibleForms.
You can keep each form definition in a separate YAML file within a second ConfigMap. Each key under data: becomes a file inside /app/dist/persistent/forms/:
---
apiVersion: v1
kind: ConfigMap
metadata:
name: ansibleforms-forms-defs
namespace: ansibleforms
data:
awx-call-user_creation.yaml: |
name: User Creation
type: awx
template: "jt-or_myawesomeor-create_user"
roles:
- internal
categories:
- Internal
help: "Form to create FTP users"
description: "Launch ftp user creation"
fields:
- name: survey_user
label: Username
type: text
required: true
- name: survey_password
label: Password
type: text
required: true
- name: survey_type
label: Type
type: enum
values:
- name: general
value: general
- name: av
value: av
required: true
# more forms here, one per key:
# otherform.yaml: |
# name: ...
# ...To inject a custom.js file into AnsibleForms, create a ConfigMap like:
---
apiVersion: v1
kind: ConfigMap
metadata:
name: ansibleforms-custom-js
namespace: ansibleforms
data:
custom.js: |
// Example custom JavaScript for AnsibleForms
window.afCustom = window.afCustom || {};
window.afCustom.onFormLoad = function (form) {
console.log("Form loaded:", form.name);
};With forms.customJs.enabled: true and the values shown above, this file will be mounted at /app/dist/src/functions/custom.js, matching the location described in the AnsibleForms documentation.
Depending on your environment, choose an existing namespace or choose to create a new one.
helm install ansibleforms ./ansibleforms-helm -f ./my_values.yaml -n ansibleforms --create-namespace- Use
--setor--set-fileto hide secrets - Consider using external secret management solutions (Vault, SOPS, etc.) for highly sensitive data
- All environment variables can be set in
env:. - All resource limits, storage, and service types are configurable.
- Ingress can be enabled/disabled and fully customized.
- Storage can be backed by dynamic StorageClasses or static PVs as needed.
- Forms configuration (
forms.yamland additionalforms/*.yaml) andcustom.jscan be managed via ConfigMaps as shown above.
- Pods/services are named and discoverable by their service name within the namespace.
- For a full list of environment variables and their meanings, see the comments in
values.yamlor visit the AnsibleForms documentation.