Deployers need to follow some rules in order to work together with the landscaper. The purpose of this documentation is to define the contract between deployers and the landscaper so that developers who want to create their own deployer know which requirements they have to fulfill.
Index
- What is a Deployer
- Structure of a Deploy Item
- How is a Deployer expected to act?
- How is a Deployer installed
A 'deployer' is basically a kubernetes controller that watches resources of the type deployitems.landscaper.gardener.cloud
.
Deploy Items have a unique type (.spec.type
) that describes the supported deployment or installation method and is
also the identifier for the corresponding deployer.
For example: Among the basic deployers that come with the landscaper is a helm
deployer, which reacts on deploy items
of type landscaper.gardener.cloud/helm
and is able to deploy, update, and delete helm charts. Another one would be
the manifest
deployer, which manages basic kubernetes manifests which are contained in the corresponding deploy items.
A deploy item looks like this:
apiVersion: landscaper.gardener.cloud/v1alpha1
kind: DeployItem
metadata:
name: manifest-di
namespace: default
spec:
type: landscaper.gardener.cloud/kubernetes-manifest
target:
name: my-target
context: "default" # reference to the Context object in the same namespace.
config:
apiVersion: manifest.deployer.landscaper.gardener.cloud/v1alpha1
kind: ProviderConfiguration
manifests:
- apiVersion: v1
kind: Namespace
metadata:
name: foo
This example shows a manifest deploy item that will create a namespace called foo
when applied. Check out the
example deploy items for more examples of deploy items.
The type of the deploy item is defined in spec.type
. It determines which deployer is responsible for this deploy item.
The manifest deployer will only handle deploy items of type landscaper.gardener.cloud/kubernetes-manifest
and it
should be the only deployer that watches for this type.
Deployers may reference a target in spec.target
. Targets usually contain credentials for accessing the environment
that is targeted by this type of deploy item. The manifest deployer targets kubernetes clusters, so this target will
contain a kubeconfig pointing to the cluster where the namespace should be created. Not all deploy items target
kubernetes clusters though, for example the terraform
deployer can also target IAAS accounts. There might be cases in
which multiple deployers of the same type exists, e.g. if there is a fenced environment that is not accessible from the
outside. In this case, the landscaper and a manifest deployer could run outside of it and another manifest deployer
could run within the fenced environment to deploy manifests there. The target then determines which deployer handles
which deploy item.
The content of spec.config
depends on its type. It is only read and evaluated by the corresponding deployer.
In this example the configuration for a manifest deploy item consists of a list of kubernetes manifests.
Once handled by its deployer, a status similar to this one will be attached to the deploy item:
status:
deployItemPhase: Succeeded
jobID: "fgkjjdfd..."
jobIDFinished: "fgkjjdfd..."
observedGeneration: 1
phase: Succeeded
lastReconcileTime: "2021-04-15T12:10:51Z"
deployer:
nname: "my-deployer"
identity: "some unique identity"
version: "v0.0.1"
providerStatus:
apiVersion: manifest.deployer.landscaper.gardener.cloud/v1alpha1
kind: ProviderStatus
managedResources:
- policy: manage
resource:
apiVersion: v1
kind: Namespace
name: foo
namespace: ""
If errors occurred while handling the deploy item, the status will contain an error message:
status:
deployItemPhase: Failed
jobID: "fgkjjdfd..."
jobIDFinished: "fgkjjdfd..."
observedGeneration: 1
phase: Failed
lastError:
codes:
- ERR_TIMEOUT
lastTransitionTime: "2021-03-24T12:36:21Z"
lastUpdateTime: "2021-03-24T12:36:21Z"
message: no deployer has reconciled this deployitem within 300 seconds
operation: WaitingForPickup
reason: PickupTimeout
The most interesting part of the status is the deployItemPhase
, the jobId
, the jobIdFinished
and lastReconcileTime
.
The Landscaper interacts with the deployer using these fields. A deployer is only allowed to process a deploy item if
jobId
is not equal to jobIdFinished
. This way the Landscaper informs the deployer about processing a deploy item.
If jobId
is not equal to jobIdFinished
and deployItemPhase
is either empty, or has the value Succeeded
or Failed
,
the deployer is allowed to process the deploy item. Then it must set deployItemPhase
on Processing
or Deleting
depending on if the item should be just reconciled or deleted/uninstalled. This signals the Landscaper that the deployer
has picked up the deploy item. Furthermore, the deployer must set lastReconcileTime
on the current time. The Landscaper
checks a deploy item regularly and if lastReconcileTime
is to old, it sees that the responsible deployer does not
finish within the specified timeframe and sets the deploy item on failed (see).
When the reconcile or the deletion of the deploy item succeeded or failed, the deployer is required to set
deployItemPhase
on Succeeded
or Failed
and jobIdFinished
on the value of jobId
. This must be done in one
atomic update operation because it is required that if jobId
and jobIdFinished
are equal, the deployItemPhase
must
be Succeeded
or Failed
. This informs the Landscaper, that the deployer has finished processing the deploy item and
only then the Landscaper is allowed to trigger a new operation by updating the jobId
again.
The deletion of deploy items is triggered by the Landscaper. The deployers are only responsible to uninstall the deployed artefacts and remove the finalizers of the deploy item if the uninstallation was successful.
When the deployer starts working on a deploy item, it could use the status field phase
to report its internal
processing state, whereby the following values are allowed:
Init
: This is more of a transition phase that shows that the deploy item is about to be handled by a deployer.Progressing
: The deploy item is currently being processed by its deployer.Deleting
: Similar toProcessing
, but instead of being applied, the deploy item is being deleted.Succeeded
: The deploy item successfully finished processing.Failed
: The deployer finished processing the deploy item, but it was not successful. Whenever this state is set, there should be further information on what went wrong in thestatus.lastError
field.
Not only a deployer, but also the landscaper interacts with deploy items. To avoid conflicts between deployers and the landscaper, the deployer is expected to follow these steps in the given order:
A deployer's reconcile loop will be triggered for changes to any deploy item, not only the ones that are handled by this deployer. The deployer has to make sure that it only handles deploy items of its own type. A deployer must never modify a deploy item of another type in any way!
As explained above, even if the type is correct, the deployer might still not be responsible for the deploy item, so the target has to be checked too, if any.
A deployer is only allowed to process a deploy item if jobId
is not equal to jobIdFinished
. The detailed protocol
between the landscaper and the deployer was described above.
Now the deployer should do its magic. First it must set the status field lastReconcileTime
on the current time thereby
signaling the Landscaper that a deployer has picked up the deploy item.
As long as the deployer is actually doing something - or waiting for something - deployItemPhase
must be set on
Processing
or Deleting
and jobId
remains different from jobIdFinished
.
Some deployers need to store information in the deploy item's status during or after processing it.
A deploy item is deleted by Landscaper. The deployer see this at the deletion timestamp. In such a situation, the deployer should uninstall the artefacts from the target and if this was successfull remove the finalizers from the deploy item.
There is the following important annotation that needs to be handled by the deployer in case of a deletion:
landscaper.gardener.cloud/delete-without-uninstall: true
: If this annotation is set at the deploy item and the deploy item is deleted by the Landscaper, the deployer should only remove the finalizer from the deploy item without uninstalling the deployed artefacts.
If the deployer successfully finished the task described by the deploy item, the deployer is required to set
deployItemPhase
on Succeeded
and jobIdFinished
on the value of jobId
.
If it wasn't successfully and has given up trying, deployItemPhase
has to be set on Failed
and jobIdFinished
on the value of jobId
.
A Deployer is basically a Kubernetes controller that watches DeployItems. By default, it's up to the administrator to install and update the deployers.
As most deployer have a similar way to be installed, Landscaper offers a convenient way how to install and manage the complete lifecycle of a deployer. This LM (Lifecycle Management) also includes the management of different deployers across fenced environments.
A deployer has to implement the DLM contract (Deployer Lifecycle Management) to be managed by the landscaper. For a technical overview about the DLM see here.
The DLM contract describes that the Installation of a Deployer has to be defined using a Blueprint
(Component Descriptor + Blueprint).
By default, the agent comes with a helm deployer so that all deployers can be installed using deploy items of type
landscaper.gardener.cloud/helm
. If other deployitems are needed to install your deployer, another deployer
registration should be created for that deployer. With that the deployers will install each other as long there are no
cyclic dependencies between them.
The DLM offers some environment specific imports for the deployer blueprint:
apiVersion: landscaper.gardener.cloud/v1alpha1
kind: Blueprint
imports:
- name: cluster # target to the host cluster
type: target
targetType: landscaper.gardener.cloud/kubernetes-cluster
- name: landscaperCluster # target to the cluster running the landscaper resources.
type: target
targetType: landscaper.gardener.cloud/kubernetes-cluster
required: false
- name: releaseName
type: data
schema:
type: string
- name: releaseNamespace
type: data
schema:
type: string
- name: identity
type: data
schema:
type: string
- name: targetSelectors # defaulted to the "landscaper.gardener.cloud/environment" annotation
type: data
schema:
type: array
items:
type: object
properties:
targets:
type: array
items:
type: object
annotations:
type: array
items:
type: object
labels:
type: array
items:
type: object
Other imports can be freely used and configured using the InstallationTemplate
in the DeployerRegistration
.
apiVersion: landscaper.gardener.cloud/v1alpha1
kind: DeployerRegistration
metadata:
name: my-deployer
spec:
# describe the deploy items types the deployer iis able to reconcile
types: ["my-deploy-item-type"]
installationTemplate:
componentDescriptor:
...
blueprint:
...
imports:
data: [ ]
targets: [ ]
importDataMappings: {}