The document describes an implementation of application packaging system based on helm. We briefly outlines what helm is, problems we have while working with helm, and goals for the rudder.
Helm 2.0 architecture has two components: helm client and tiller server.
- The Helm Client is a command-line client for end users
- The Tiller Server is an in-cluster server that interacts with the Helm client, and interfaces with the Kubernetes API server
The end users use helm client to send charts to tiller server. The tiller server combines a chart and configuration to build a release and installs releases into kubernetes.
During the course of deploying and running helm in production, we've faced a couple of challenges. Following is a list of issues; it is by no means a comprehensive or the "right" list:
- No built-in authorization in tiller. Tiller runs in
kube-system
namespace with high privileges. - Tiller installs releases into kubernetes but doesn't report component status (e.g. Pod, Deployment, etc).
- Helm + Tiller does not follow kubernetes design pattern closely, which makes it less extensible - it is not easy to build extensions on top of Helm.
- Not namespaced. Release has global scope in Helm, but most resources of a release are in namespace scope in Kubernetes. This sometimes can result in name confliction.
- The rollback mechanism is incremental, i.e. a rollback operation will increase the version number. This mechanism is confusing to our users.
To solve the above issues, we designed rudder
coupled with CustomResourceDefinition (CRD).
- The design should follow kubernetes controller pattern.
- Release should be namespaced, and all related resources (except some special kinds, PV) are in a certain namespace. The applications can be isolated between multiple users.
- Status tracking.
A Release
contains a chart and configuration which are combined by rudder to render a manifest of Kubernetes resources. If a valid manifest is generated, rudder increases the version of release.
A ReleaseHistory
is a snapshot of a certain version of a release which is used for rollback.
A release controller watches Release CRDs
in kubernetes cluster.
When a new Release CRD
is created, controller creates a new ReleaseHistory
for the new Release
, and parses the chart
and configuration
to combine them into a kubernetes resources manifest. It then creates all resources in the manifest to install the release into cluster. Finally, controller watches resources' status and embodies them in the status of Release
.
When user updates the Release
, controller figures out those resources need to be deleted, updated, or created, and does the corresponding operation on them. A new version of RelaeseHistory
will be created if Release
is updated successfully.
When user wants to rollback the Release
, controller finds out the requested ReleaseHistory
, and override the Release
with the specific version Release
in it.
When a releasee is deleted, controller will delete all resources and ReleaseHistory
related to it.
There are some external component working around Release CRD
and resources
related to releases, e.g CanaryRelease Controller
and HPA controller
.
So there should be a external status controller to embody the external status in release.
// Release describes a release wich chart and values
type Release struct {
metav1.TypeMeta `json:",inline"`
// +optional
metav1.ObjectMeta `json:"metadata,omitempty"`
// Specification of the desired behavior of the Release
Spec ReleaseSpec `json:"spec,omitempty"`
// Most recently observed status of the Release
// +optional
Status ReleaseStatus `json:"status,omitempty"`
}
// ReleaseSpec describes the basic info of a release
type ReleaseSpec struct {
// Description is the description of current release
Description string `json:"description,omitempty"`
// Template is an archived template data, aka Chart
Template []byte `json:"template,omitempty"`
// Config is the config for parsing template
Config string `json:"config,omitempty"`
// The config this release is rolling back to. Will be cleared after rollback is done.
RollbackTo *ReleaseRollbackConfig `json:"rollbackTo,omitempty"`
}
// ReleaseRollbackConfig describes the rollback config of a release
type ReleaseRollbackConfig struct {
// The version to rollback to. If set to 0, rollbck to the last version.
Version int32 `json:"version,omitempty"`
}
// ReleaseHistory describes a history of a release version
type ReleaseHistory struct {
metav1.TypeMeta `json:",inline"`
// +optional
metav1.ObjectMeta `json:"metadata,omitempty"`
// Specification of the desired behavior of the ReleaseHistory
// +optional
Spec ReleaseHistorySpec `json:"spec,omitempty"`
}
// ReleaseHistorySpec describes the history info of a release
type ReleaseHistorySpec struct {
// Description is the description of current history
Description string `json:"description,omitempty"`
// Version is the version of a history
Version int32 `json:"version,omitempty"`
// Template is an archived template data, aka Chart
Template []byte `json:"template,omitempty"`
// Config is the config for parsing template
Config string `json:"config,omitempty"`
// Manifest is the generated kubernetes resources from template
Manifest string `json:"manifest,omitempty"`
}