The `cert-issuer-name` and `cert-issuer-kind` properties point an app's generated `Certificate` at a cert-manager issuer created outside of Dokku, allowing certificates to be issued through solvers the built-in letsencrypt integration cannot use, such as `dns01` for wildcard certificates. Setting an issuer enables https on its own, as a manually managed issuer has no email for Dokku to configure. An imported certificate still takes precedence, and `letsencrypt-server false` remains the single off switch. Dokku warns before a build starts when the referenced issuer is absent from the cluster, without blocking the deploy. Wildcard domains no longer collide with their apex domain when generating ingress names, and `letsencrypt-server` values are now validated when set rather than at deploy time.
Sysctls the kernel does not namespace, such as `vm.max_map_count`, cannot be set from a pod spec and previously had no answer beyond editing `/etc/sysctl.d` on each host by hand. `scheduler-k3s:node-sysctls:set` now applies them through a privileged daemonset, which reaches nodes joined later and reapplies after a reboot. Sysctls may be scoped to a node profile, with a profile scope inheriting the global values and overriding them on conflict so that every node is covered by exactly one daemonset. Clearing a sysctl stops dokku managing it but does not restore the previous value, which persists until the node reboots.
Node profiles controlled how a node joined the cluster but left no trace on the node afterwards, so a profile could not be selected against with `kubectl`, a `nodeSelector`, or a node affinity rule. Nodes joined without a profile are left unlabeled, and the server node created by `scheduler-k3s:initialize` never carries the label since it does not pass through `scheduler-k3s:cluster:add`.
The `letsencrypt-email-prod` and `letsencrypt-email-stag` properties can now be set per app in addition to globally, resolving app-level before the global value for the app's selected `letsencrypt-server`. An app that sets its own email renders a namespaced cert-manager `Issuer` using that email, while apps without an override continue to use the shared `ClusterIssuer` with the global email.
Chart property names containing `/` failed because per-key flat-file storage interpreted the slash as a filesystem path separator, and any move to line-based storage would silently truncate multi-line values. A new `PropertyMap*` helper family in `common` persists each map as a single JSON file so both `/` in keys and `\n` in values round-trip losslessly. Chart overrides move to `chart-overrides.<chart>` and an idempotent `TriggerInstall` migration rewrites any legacy `chart.<chart>.<key>` files into the new layout. The deprecated `scheduler-k3s:set --global chart.*` form is rerouted through the same map storage so it does not silently orphan writes. Closes#8717.
The scheduler-k3s plugin exposes `annotations:set` and `labels:set` but no matching report subcommands, so scripts could not inspect the configured state for idempotent management without reading the property files directly. The new `scheduler-k3s:annotations:report` and `scheduler-k3s:labels:report` surface the configured entries with stdout, JSON, single-flag query, and `--process-type` / `--resource-type` filtering, mirroring the recently added `scheduler-k3s:charts:report`. The literal `GlobalProcessType` value `--global` is rendered as `global` in report keys to avoid leading dashes. The `scheduler-k3s:autoscaling-auth:report` command is updated alongside to loop over every app when no app and no `--global` flag is provided, matching the convention used by `scheduler-k3s:report`.
Node profiles can be used to specify repetitive options for clusters, making it easier to add specific types of instances quickly.
This PR additionally fixes kubelet-args specification - the same key can be specified multiple times, such as when specifying custom sysctl rules.
If a global vector-sink property on the logs plugin is set, we will use that to configure a log sink (defaulting to console output otherwise). Note that the actual configuration still needs to be a valid DSN representing a Vector log sink.
While this does not support pinning log sinks to specific apps, it opens up integration for those who use a single k3s cluster in shared tenancy.
There is a bug in the Keda project that caused Keda to incorrectly handle empty trigger lists. If self-managing the ScaledObject when using an HTTPScaledObject, an external-push trigger must be created.
This change additionally updates the chart to fix any potential bugs in usage of keda.
The ingress-nginx ingress implementation is the standard ingress in the Kubernetes community, and it doesn't make sense for us to stray from that just to utilize the k3s default.
In the future, we might drop k3s, but this works well for now.
This will provide the possibility for users to talk to existing kubernetes clusters, thereby removing one of the biggest reasons for having the old scheduler-kubernetes plugin around.
While this will now more or less require a local docker login - which can be overridden by setting the image-pull-secrets property - this ensures every deploy has a valid context.
One annoying thing is that the secret is per-app vs global, meaning that if the secret must be rotated, all apps need to be redeployed. A future change can fix that by deploying a global secret, or if folks really desire, this can be done by setting the image-pull-secrets property on the app/globally.
This utilizes a Kubernetes Job to start a pod in order to take advantage of completed Job cleanup in Kubernetes. It also properly handles interactivity by ensuring the container has a TTY.
Note that there is currently no provision for parsing docker arguments and translating them into their Kubernetes equivalents.
The big feature missing from deployments today is healthchecks, which require extra parsing of the app.json format since the healthchecks there aren't immediately serializable to kubernetes deployment healthchecks.
Other smaller missing functionality from the existing OSS kubernetes scheduler are:
- The ability to set custom pod annotations
- The ability to set custom deployment annotations
- The ability to mount volumes
Exposing these pieces of functionality will come at a later date, if at all.