When developing modules, you may want to pull and deploy a module bypassing the release channels. The ModulePullOverride resource is used for this purpose.

An example of ModulePullOverride:

apiVersion: deckhouse.io/v1alpha2
kind: ModulePullOverride
metadata:
  name: <module-name>
spec:
  imageTag: <tag of the module image>
  scanInterval: <image digest check interval. Default: 15s>

Requirements for the resource parameters:

  • The module name (metadata.name) must match the module name in the ModuleSource (.status.modules.[].name).

  • The container image tag (spec.imageTag) can be anything, e.g., pr333, my-branch.

The spec.scanInterval time interval (optional) defines the interval for scanning images in the registry. The default interval is 15 seconds. To force scan you can change the interval or set the renew="" annotation on ModulePullOverride.

You can get the result of applying ModulePullOverride in the message (column MESSAGE) when retrieving ModulePullOverride information. The value Ready indicates the successful application of ModulePullOverride parameters. Any other value indicates conflict.

Example of absence of conflicts when using ModulePullOverride:

$ kubectl get modulepulloverrides.deckhouse.io 
NAME      UPDATED   MESSAGE
example1  10s       Ready

Requirements for the module:

  • The module must exist; otherwise the message for ModulePullOverride will be The module not found.

    An example:

    $ kubectl get modulepulloverrides.deckhouse.io 
    NAME      UPDATED   MESSAGE
    example1  10s       The module not found
    
  • The module must not be embedded Deckhouse module; otherwise the message in ModulePullOverride will be The module is embedded.

    An example:

    $ kubectl get modulepulloverrides.deckhouse.io 
    NAME           UPDATED  MESSAGE
    ingress-nginx  10s      The module is embedded
    
  • The module must be enabled; otherwise, the message for ModulePullOverride will be The module disabled.

    An example:

    $ kubectl get modulepulloverrides.deckhouse.io 
    NAME     UPDATED   MESSAGE
    example  7s        The module disabled
    
  • The module must have a source; otherwise the message at ModulePullOverride will be The module does not have an active source.

    An example:

    $ kubectl get modulepulloverrides.deckhouse.io 
    NAME       UPDATED   MESSAGE
    example    12s       The module does not have an active source
    
  • The source for the module must exist; otherwise the message for ModulePullOverride will be The source not found.

    An example:

    $ kubectl get modulepulloverrides.deckhouse.io 
    NAME       UPDATED   MESSAGE
    example    12s       The source not found
    

To update the module without waiting for the next update cycle to begin, you can execute the following command:

kubectl annotate mpo <name> renew=""

How it works

After creating ModulePullOverride, the corresponding module will not consider ModuleUpdatePolicy, and will also not load and create ModuleRelease objects. The module will be loaded upon every change of the imageDigest parameter, after which it will be applied in the cluster. The ModuleSource status will have overridden: true, which indicates that ModulePullOverride is being used instead of ModuleUpdatePolicy. Also, the corresponding Module object will have an IsOverridden field in its status, and the module version from imageTag.

An example:

apiVersion: deckhouse.io/v1alpha1
kind: Module
metadata:
  creationTimestamp: "2024-11-18T15:34:15Z"
  generation: 16
  labels:
    deckhouse.io/epoch: "1326105356"
  name: example
  resourceVersion: "230347744"
  uid: 7111cee7-50cd-4ecf-ba20-d691b13b0f59
properties:
  availableSources:
  - example
  releaseChannel: Stable
  requirements:
    deckhouse: '> v1.63.0'
    kubernets: '> v1.30.0'
  source: example
  version: mpo-tag
  weight: 910
status:
  conditions:
  - lastProbeTime: "2024-12-03T15:57:20Z"
    lastTransitionTime: "2024-12-03T15:57:20Z"
    status: "True"
    type: EnabledByModuleConfig
  - lastProbeTime: "2024-12-03T15:59:58Z"
    lastTransitionTime: "2024-12-03T15:57:26Z"
    status: "True"
    type: EnabledByModuleManager
  - lastProbeTime: "2024-12-03T15:59:58Z"
    lastTransitionTime: "2024-12-03T15:56:23Z"
    status: "True"
    type: IsReady
  - lastProbeTime: "2024-12-03T15:59:48Z"
    lastTransitionTime: "2024-12-03T15:56:47Z"
    status: "True"
    type: IsOverridden
  phase: Ready

The module will keep running after ModulePullOverride is removed. But if there is a ModuleUpdatePolicy for the module, new releases of the module (ModuleRelease) will be pulled to replace the current “developer version”.

An example

  1. Suppose there are two modules, echo and hello-world, defined in ModuleSource. The update policy is set for them, and they are pulled in and installed in DKP:

    apiVersion: deckhouse.io/v1alpha1
    kind: ModuleSource
    metadata:
      name: test
    spec:
      registry:
        ca: ""
        dockerCfg: someBase64String==
        repo: registry.example.com/deckhouse/modules
        scheme: HTTPS
    status:
      modules:
      - name: echo
        policy: test-alpha
      - name: hello-world
        policy: test-alpha
      modulesCount: 2
    
  2. Enable the module and create ModulePullOverride for the echo module:

    apiVersion: deckhouse.io/v1alpha2
    kind: ModulePullOverride
    metadata:
      name: echo
    spec:
      imageTag: main-patch-03354
    

After creating ModulePullOverride, the image tag registry.example.com/deckhouse/modules/echo:main-patch-03354 will be used for the module (ms:spec.registry.repo/mpo:metadata.name:mpo:spec.imageTag).

  1. The ModulePullOverride will change with each update of the module:

    apiVersion: deckhouse.io/v1alpha2
    kind: ModulePullOverride
    metadata:
      name: echo
    spec:
      imageTag: main-patch-03354
      scanInterval: 15s
    status:
      imageDigest: sha256:ed958cc2156e3cc363f1932ca6ca2c7f8ae1b09ffc1ce1eb4f12478aed1befbc
      message: "Ready"
      updatedAt: "2023-12-07T08:41:21Z"
    

    where:

    • imageDigest is the unique identifier of the container image that was pulled.
    • lastUpdated is the time when the image was last pulled.
  2. In this case, ModuleSource would look as follows:

    apiVersion: deckhouse.io/v1alpha1
    kind: ModuleSource
    metadata:
      name: test
    spec:
      registry:
        ca: ""
        dockerCfg: someBase64String==
        repo: registry.example.com/deckhouse/modules
        scheme: HTTPS
    status:
      modules:
      - name: echo
        overridden: true
      - name: hello-world
        policy: test-alpha
      modulesCount: 2
    

Module artifacts in the container registry

After a module has been built, its artifacts must be pushed to the container registry at a path that is the source path for pulling and running modules in DKP. The path where module artifacts are pushed to the registry is specified in the ModuleSource resource.

Below is an example of the container image hierarchy after pushing the module-1 and modules-2 module artifacts into the registry:

registry.example.io
📁 modules-source
├─ 📁 module-1
│  ├─ 📦 v1.23.1
│  ├─ 📦 d4bf3e71015d1e757a8481536eeabda98f51f1891d68b539cc50753a-1589714365467
│  ├─ 📦 e6073b8f03231e122fa3b7d3294ff69a5060c332c4395e7d0b3231e3-1589714362300
│  ├─ 📦 v1.23.2
│  └─ 📁 release
│     ├─ 📝 v1.23.1
│     ├─ 📝 v1.23.2
│     ├─ 📝 alpha
│     └─ 📝 beta
└─ 📁 module-2
   ├─ 📦 v0.30.147
   ├─ 📦 d4bf3e71015d1e757a8481536eeabda98f51f1891d68b539cc50753a-1589714365467
   ├─ 📦 e6073b8f03231e122fa3b7d3294ff69a5060c332c4395e7d0b3231e3-1589714362300
   ├─ 📦 v0.31.1
   └─ 📁 release
      ├─ 📝 v0.30.147
      ├─ 📝 v0.31.1
      ├─ 📝 alpha
      └─ 📝 beta

The container registry must support a nested repository structure. See the requirements section for more details.

Below is a list of commands for working with the module source. The examples use the crane tool. Follow the instructions to install it. For macOS, use brew.

crane ls <REGISTRY_URL>/<MODULE_SOURCE>

An example:

$ crane ls registry.example.io/modules-source
module-1
module-2
crane ls <REGISTRY_URL>/<MODULE_SOURCE>/<MODULE_NAME>

An example:

$ crane ls registry.example.io/modules-source/module-1
v1.23.1
d4bf3e71015d1e757a8481536eeabda98f51f1891d68b539cc50753a-1589714365467
e6073b8f03231e122fa3b7d3294ff69a5060c332c4395e7d0b3231e3-1589714362300
v1.23.2

In the example above, there are two module images and two application container images in module-1.

crane export <REGISTRY_URL>/<MODULE_SOURCE>/<MODULE_NAME>:<MODULE_TAG> - | tar -tf -

An example:

crane export registry.example.io/modules-source/module-1:v1.23.1 - | tar -tf -

The output will be quite large.

crane export <REGISTRY_URL>/<MODULE_SOURCE>/<MODULE_NAME>:<MODULE_TAG> - | tar -Oxf - images_digests.json

An example:

$ crane export registry.example.io/modules-source/module-1:v1.23.1 -  | tar -Oxf - images_digests.json
{
  "backend": "sha256:fcb04a7fed2c2f8def941e34c0094f4f6973ea6012ccfe2deadb9a1032c1e4fb",
  "frontend": "sha256:f31f4b7da5faa5e320d3aad809563c6f5fcaa97b571fffa5c9cab103327cc0e8"
}
crane ls <REGISTRY_URL>/<MODULE_SOURCE>/<MODULE_NAME>/release

An example:

$ crane ls <REGISTRY_URL>/<MODULE_SOURCE>/<MODULE_NAME>/release
v1.23.1
v1.23.2
alpha
beta

In the example above, there are two releases in the container registry; two release channels, alpha and beta, are also used:

crane export <REGISTRY_URL>/<MODULE_SOURCE>/<MODULE_NAME>/release:alpha - | tar -Oxf - version.json

An example:

$ crane export registry.example.io/modules-source/module-1/release:alpha - | tar -Oxf - version.json
{"version":"v1.23.2"}