Skip to content

πŸ“¦ Kubernetes Installed PackagesΒΆ

Muppy makes deploying Helm packages into Kubernetes clusters straightforward, through an intuitive graphical interface. Users manage all of their packages directly from the Muppy interface.

🧩 Muppy Meta Package (m2p)¢

Muppy also offers the Muppy Meta Packages (m2p).
An m2p is a tool that simplifies deploying complex applications on Kubernetes, by grouping several Docker containers and their configuration into a single package, called a metapackage.

That metapackage is made of parts β€” modular sub-components representing services, their dependencies and their parameters. Thanks to this structure, even users with little Kubernetes experience can deploy advanced applications smoothly and quickly.


🧱 The components of a deployment¢

Deploying a package relies on the following elements:

  • πŸ“¦ K8s Package: the definition of the package to deploy (a Helm chart, or Kubernetes files applied with kubectl)
    β†’ for Helm, it includes the default values (values.yaml)

  • 🧾 K8s Package Profile: for metapackages, the profiles define:

  • the parts the package is made of
  • the default resources (limits, replicas)
  • the dashboards used for configuration
  • the available versions and the upgrade strategies

  • πŸ“ Installed Package: an instance of a K8s Package deployed in a Kubernetes cluster, with the parameters defined in a K8s Package Profile

  • πŸ“š Config Journal: the log of the Helm operations performed on a package (deployment history, upgrades, diffs, …)


πŸ”„ A package's life cycleΒΆ

  • πŸ†• Creation (to be documented)
  • πŸ› οΈ Installation / Modification
  • ✏️ Edit (Update)
  • πŸš€ Upgrade (version bump)
  • ❌ Deletion (to be documented)

✏️ Modification¢

Two kinds of modification are possible:

1. Edit / UpdateΒΆ

Changes handled directly by Helm:

  • changes to the values
  • part configuration
  • network or dashboard settings

Muppy automatically detects the differences between the current configuration and the desired one, and displays the "Drifted values" indicator.

These changes are applied on the next helm upgrade.

Every helm upgrade is recorded in the Config Journal, with: - the values used - the diff against the previous version


2. πŸš€ Package UpgradeΒΆ

For the cases where an update affects the databases, or requires stopping the application, Muppy offers an advanced version-bump mechanism: Package Release Upgrade.

Available through:

  • πŸ§™ the β€œPackage Release Upgrade” wizard
  • βš™οΈ the CI/CD API

Based on SEMVER version management, it can:

  • identify the version profiles
  • run migration scripts
  • apply the changes safely

πŸ“˜ Version profilesΒΆ

A profile holds:

  • πŸ”§ the definition of the parts
  • πŸ“Š the associated dashboards
  • πŸ§ͺ a migration script (if needed)
  • πŸ“‹ the criteria for applying it

πŸ§™β€β™‚οΈ How the Package Release Upgrade worksΒΆ

Unlike a plain helm upgrade, the version upgrade wizard expects:

  • 🎯 the K8s Profile to apply
  • ♻️ Reload Values (boolean): reload the default values from the profile
  • 🧹 Reset Values Overload (boolean): reset, or merge, the customised values

πŸ” The upgrade, step by stepΒΆ

If the profile to deploy differs from the one currently in place, the version bump follows these steps:

  1. βœ… Profile change
    The new K8s Package Profile is assigned to the instance.

  2. βš™οΈ Execution of onchange__k8s_package_profile_id()
    This method does the following:

    • calls reload_mpy_meta_config_yaml() to reload the parts configuration:

      • from the profile, or
      • failing that, from the package
    • updates the fields:

      • default_path
      • default_path_debug
      • healthcheck_path
      • fqdn_hostname_smart_config_id (if present in the new profile)
  3. 🧩 Applying the dashboards
    The dashboards defined in the new profile are put in place.

    ⚠️ Existing values are preserved
    The values previously entered in the dashboards are preserved by default.

  4. ♻️ Reload Values (if enabled)

    • reloads the dashboard's values from the profile
    • reloads the content of the values file from the package
  5. 🧹 Reset Values Overload (if enabled)

    • if enabled: the Values Overload section is replaced by the new values
    • otherwise: the new values are merged with the existing ones
  6. 🧬 Computing the final values
    The combined result (default values + overloads) is injected into Final Values.

  7. πŸš€ Deployment
    The helm upgrade command runs with the Final Values.


🧬 The Upgrade Job, and what decides whether it runs¢

When a version change needs the database migrated, the upgrade does not simply swap the image. It runs an Upgrade Job: a Kubernetes Job that executes the profile's migration command in a pod carrying the new image, before the application comes back.

The sequence around it:

  1. πŸ’Ύ Backup β€” if the profile has Backup before upgrade, a pg_dump of the Release's databases is taken first. A Release with no database logs it and carries on.
  2. ⏸️ Stop β€” the parts that hold a connection to the database go to 0 replica while the Job runs (a cronjob part is suspended instead). Which parts those are is declared per part in the Parts Config: the default is to stop, and a part can opt out β€” a Tailscale sidecar, for instance, keeps its pod throughout.
  3. 🧬 The Job β€” it runs, and the upgrade waits for it, up to Upgrade Job Timeout.
  4. ▢️ Restart β€” a second helm upgrade restores the replicas and moves the images.

A failed Job leaves the parts stopped, on purpose

If the Job fails or times out, the stopped parts are not restarted: the database may be half migrated, and starting the application on it is the very thing the stop exists to prevent. The Release then carries Parts stopped for the upgrade, and Resume after stop is what brings them back β€” once you have dealt with the database.

🎚️ Upgrade Job Trigger¢

Whether the Job runs at all is the profile's Upgrade Job Trigger. It compares the version currently deployed against the profile's App Version:

Trigger The Job runs when…
Disabled never
SEMVER Major change the major number differs. The pre-release suffix is not looked at
SEMVER Minor change the major or the minor differs. The pre-release suffix is not looked at
Any SEMVER change the two versions differ at all β€” the patch number and the pre-release suffix included
Always every time, even onto the same version

Pre-release suffixes: Major and Minor do not see them

18.5.0-beta.1 and 18.5.0-beta.2 share their major, their minor and their patch. A profile set to SEMVER Major change or SEMVER Minor change therefore sees no change between them and skips the migration entirely β€” silently, since skipping is a normal outcome.

A profile that deploys branch builds needs Any SEMVER change or Always.


🧱 Upgrading a Pack8s¢

A Pack8s is the same application deployed on several clusters: one primary Release that serves the traffic, and followers sitting at 0 replica ready to take over. They share one database β€” the primary's cluster accepts writes, the followers are wired to standbys that replay it and refuse every write.

Two consequences, and both bite:

  • every member carries the same name, so searching Releases by name returns several rows on several clusters. There is no the Release β€” there is the pack;
  • upgrading one member alone leaves the pack on two versions, which is exactly the state a failover turns into an incident: the application comes back on the old image, over a database the other member already migrated.

So a Pack8s is upgraded as a pack, not member by member. One gesture carries every member onto the target profile, primary first, and the members are serialised β€” a member starts only once the previous one has finished, not merely started.

Only the primary migrates the database

The pack has a single database, so the Upgrade Job runs on the primary and on it alone. A follower is wired to a standby that refuses every write; its own Job would fail and leave that member stopped for nothing.

A failed primary stops the pack there

If the primary's upgrade fails, the followers do not start. That is deliberate: nothing should run over a database that may be half migrated. Deal with the database, then release the remaining members by hand.


πŸ§ͺ Development ModeΒΆ

A checkbox on the Release (Dashboard tab) that mounts a persistent volume holding the application code, so a fix made inside a running pod survives a restart. Commit it, and CI/CD rebuilds the image for the parts that do not carry the volume.

It is not Debug Mode:

Debug Mode Development Mode
Scope one part the whole Release
What runs debug_config.command (code-server, sleep) the application, normally
Purpose get a shell or an IDE inside a part keep the code across restarts

They combine: a Release in Development Mode serves from the volume, and you can additionally put one part in Debug Mode to edit through code-server. With Development Mode off, the Release provisions no development storage at all.

Requires mpy-metapackage β‰₯ 3.1.0, and a Parts Config declaring the volume β€” see the m2p documentation for the declaration itself.

Changing the volume declaration is not a simple edit

A Parts Config lives in three places, and each keeps its own copy. After editing the reference template you must walk the whole chain, in this order:

  1. Sync Package from Registry on the Package β€” only if the chart itself changed
  2. Reload from Template on the Package Profile
  3. Reload Parts Config, then Sync Parts Config, on the Release

Skip a step and the deployment silently keeps the previous definition.

And a PVC's accessModes and storageClassName are immutable: changing them on a deployed Release makes the next upgrade fail with "spec is immutable after creation". The only way out is deleting the claim by hand, which destroys its contents.


❌ Deletion¢

To be documented later