kubernetes-sigs / application Goto Github PK
View Code? Open in Web Editor NEWApplication metadata descriptor CRD
License: Apache License 2.0
Application metadata descriptor CRD
License: Apache License 2.0
The current instructions could use some improvement.
A few suggestions:
I think both of them can manage applications in Kubernetes, what is the difference of those two projects?
The Application resource is intended to be used by UIs. One of the most useful features of those is reporting the health of the displayed resources.
The "status" of the application (for the sake of discussion, let's simplify to either "OK" or "Error") can be generated in one of the following ways:
Each of the approaches carries some trade-offs:
Pros:
Cons:
Pros:
Cons:
NOTE: this could be an optional approach, with a default fallback being any of the other approaches.
Pros:
Cons:
Pros:
Cons:
What logic should the application controller provide?
Would be great to see a roadmap for this project. What are you planning to do next and in what timeframe?
One of the test is failing when it is executed
make docker-build IMG=my-app-operator
go generate ./pkg/... ./cmd/...
go fmt ./pkg/... ./cmd/...
go vet ./pkg/... ./cmd/...
go run vendor/sigs.k8s.io/controller-tools/cmd/controller-gen/main.go all
CRD manifests generated under '/Users/dabou/Code/go-workspace/src/github.com/kubernetes-sigs/application/config/crds'
RBAC manifests generated under '/Users/dabou/Code/go-workspace/src/github.com/kubernetes-sigs/application/config/rbac'
go test ./pkg/... ./cmd/... -coverprofile cover.out
? github.com/kubernetes-sigs/application/pkg/apis [no test files]
? github.com/kubernetes-sigs/application/pkg/apis/app [no test files]
ok github.com/kubernetes-sigs/application/pkg/apis/app/v1beta1 11.795s coverage: 9.1% of statements
ok github.com/kubernetes-sigs/application/pkg/component 0.053s coverage: 40.0% of statements
? github.com/kubernetes-sigs/application/pkg/controller [no test files]
2019/02/05 19:25:35 *v1beta1.Application/default/foo Validating spec
2019/02/05 19:25:35 *v1beta1.Application/default/foo Applying defaults
2019/02/05 19:25:35 *v1beta1.Application/default/foo(cmpnt:app) { reconciling component
2019/02/05 19:25:35 *v1beta1.Application/default/foo(cmpnt:app) Expected Resources:
2019/02/05 19:25:35 *v1beta1.Application/default/foo(cmpnt:app) Observed Resources:
2019/02/05 19:25:35 *v1beta1.Application/default/foo(cmpnt:app) Reconciling Resources:
2019/02/05 19:25:35 *v1beta1.Application/default/foo(cmpnt:app) } reconciling component
2019/02/05 19:25:35 *v1beta1.Application/default/foo Validating spec
2019/02/05 19:25:35 *v1beta1.Application/default/foo Applying defaults
2019/02/05 19:25:35 *v1beta1.Application/default/foo(cmpnt:app) { reconciling component
2019/02/05 19:25:35 *v1beta1.Application/default/foo(cmpnt:app) Expected Resources:
2019/02/05 19:25:35 *v1beta1.Application/default/foo(cmpnt:app) Observed Resources:
2019/02/05 19:25:35 *v1beta1.Application/default/foo(cmpnt:app) Reconciling Resources:
2019/02/05 19:25:35 *v1beta1.Application/default/foo(cmpnt:app) } reconciling component
--- FAIL: TestReconcile (5.23s)
application_controller_test.go:77:
Timed out after 5.004s.
Expected success, but got an error:
<*errors.StatusError | 0xc0002b55f0>: {
ErrStatus: {
TypeMeta: {Kind: "", APIVersion: ""},
ListMeta: {SelfLink: "", ResourceVersion: "", Continue: ""},
Status: "Failure",
Message: "Deployment.apps \"foo-deployment\" not found",
Reason: "NotFound",
Details: {
Name: "foo-deployment",
Group: "apps",
Kind: "Deployment",
UID: "",
Causes: nil,
RetryAfterSeconds: 0,
},
Code: 404,
},
}
Deployment.apps "foo-deployment" not found
FAIL
coverage: 75.0% of statements
FAIL github.com/kubernetes-sigs/application/pkg/controller/application 16.850s
? github.com/kubernetes-sigs/application/pkg/customresource [no test files]
ok github.com/kubernetes-sigs/application/pkg/finalizer 0.043s coverage: 94.7% of statements
? github.com/kubernetes-sigs/application/pkg/genericreconciler [no test files]
ok github.com/kubernetes-sigs/application/pkg/kbcontroller 0.031s coverage: 0.0% of statements
ok github.com/kubernetes-sigs/application/pkg/resource 0.063s coverage: 27.8% of statements
? github.com/kubernetes-sigs/application/cmd/manager [no test files]
make: *** [test] Error 1
Proposal is for adopting resources that match the AppCRD selectors.
# Flag that indicates matched resources must be adopted
.spec.adopt: true
In some use cases where application crd is used, the tooling explicitly sets OwnerReference of the objects (that match appcrd selectors) to point to the Application object.
Can we make this automatic controller by a flag that is turned off by default.
The objective of this proposal is to provide a mechanism to aggregate the status of an Application. We propose a mechanism to compute the readiness, availability, errors, and disruptions associated with an Application. As black and white box health monitoring are a complicated topic that deserves its own treatment, we do not address it in this proposal.
.status
of a resource to communicate information about its readiness. This allows existing CRDs to opt into the scheme without breaking compatibility with existing tooling and to evolve to use fields. Additionally, it provides a mechanism to provide additional, human readable, information with respect to the status of an Application's components.Conditions are used across the Kubernetes API surface in order to indicate the condition of a resource as its controllerseeks to realize the declared intent in its specification. They are described by the golang struct below. Throughout this proposal we use conditions in conjunction with fields.
type Condition struct {
// Type is the type of the condition.
Type ComponentConditionType `json:"type"`
// Status is one of True, False, Unknown.
Status v1.ConditionStatus `json:"status"`
// LastTransitionTime is the last time the condition's status changed.
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
// Reason is the reason for the condition's last transition.
Reason string `json:"reason,omitempty"`
// Message is a human readable message indicating details about the transition.
Message string `json:"message,omitempty"`
}
From the perspective of Pods, readiness indicates the ability of the Pod to receive network traffic. It also indicates that the resource, from the perspective of the control loops that act on it, is ready for use. We use the same semantics for the components of an Application. Readiness for an Application implies that all of its components are ready. That is, an Application is ready if and only if all of its components are ready. Components that contain no user declared desired state (i.e. have no spec) (e.g. ConfigMaps and Secrets) are always ready post creation.
status.ready=true
or by including a condition like {"type":"Ready","status":"true"}
in the resource's status.conditions
.status.ready=false
or by including a condition like {"type":"Ready","status":"false"}
in the resource's status.conditions
.status.ready=true
and including a condition like {"type":"Ready","status":"false"}
) the value of the field takes precedence.status.ready=true
and including a condition like {"type":"Ready","status":"false","message":"RDBMs is ready for use."}
provides a user readable message about the readiness of the resource).From the perspective of Deployments, and many out of tree resources, availability, indicates that all Pods in the related to the resource remain ready after some configurable duration. This notion is useful for application components in general as indication that the resource is unlikely to fall victim to infant mortality after creation or mutation. We use availability for an Application's components in this context. As availability is not applicable to all components, it is not aggregated for an Application.
status.available=true
or by including a condition like {"type":"Available","status":"true"}
in the resource's status.conditions
.status.available=false
or by including a condition like {"type":"Available","status":"false"}
in the resource's status.conditions
.status.availabile=true
and including a condition like {"type":"Available","status":"false"}
) the value of the field takes precedence.Kubernetes control loops communicate that they have observed modifications of the declared desired state contained in a resource by setting its status.observedGeneration
to its generation
. A resource for which this is true is said to be observed.
status.observedGeneration
to the value of meta.generantion
to communicate that they have observed the creation of, or a mutation to, a resource they control.Kubernetes control loop use various methods to communicate that reconciliation between a resources specification and the observed state of the system is progressing. Deployments, and many non-core resources, communicate this using the Progressing
condition. For an Application, progressing components indicate that the application is updating.
status.progress
to a true or to a non-negative 32-bit floating point number between in [0,100] (e.g status.progress=true
or status.progress=99.9
).{"type":"Progressing","status":"true"}
in the resource's status.conditions
.status.progressing=true
and including a condition like {"type":"Progressing","status":"false"}
) the value of the field takes precedence.Application components may be affected by planned or unplanned disruptions. For instance the destruction of a Node may disrupt many replicated Pod sets. The application controller MAY use other resources, e.g PodDisruptionBudgets, to add this condition to a resource's status, and the controller for a resource MAY communicate this directly by adding such a condition.
{"type":"Disruption","status":"true","reason":"Node unavailable","message":"Auto-scaling in progress"}
.At any point in their lifetime controller may encounter errors when realizing the declared intent of the user. The are communicating using the status.conditions
of the resource.
{"type":"Error","status":"true","reason":"Controller Wedged","message":"SharedInformer sycn failing."}
.Resources and controllers that wish to be compatible with the Application Controller status computation need only implement the following.
.spec
contains no declarative intent. It is always ready..status
field..status
field MUST indicate readiness..status
field MAY indicate availability..status
field SHOULD indicate observation by the controller..status
field MAY contain conditions.status.conditions
field.status.conditions
field.The core resources do not all conform to the schema above. In the future, we may modify them to do so. For the time being, the following describes how the Application controller will compute the status of these resources.
.spec.replicas
is equal to .status.readyReplicas
is equal to .status.replicas
and all are greater than zero..status.conditions
contains an Available
condition.spec.conditions
contains a Progressing
condition..status.observedGeneration
is equal to spec.generation
.Failure
conditions are converted to Error
conditions..spec.replicas
is equal to .status.replicas
and .status.readyReplicas
and all are greater than zero..spec.replicas
is equal to .status.replicas
and .status.availableReplicas
and all are greater than zero..spec.replicas
is not equal to .status.replicas
..status.obloadbalancerservedGeneration
is equal to spec.generation
.ReplicaFailure
conditions will be converted to Error
conditions..spec.replicas
is equal to .status.replicas
and .status.readyReplicas
and all are greater than zero..status.currentReplicas
is not equal to status.updateReplicas
or if.status.replicas
is not equal to .spec.replicas
..status.observedGeneration
is equal to spec.generation
..status.currentNumberScheduled
is equal to .status.desiredNumberScheduled
and .status.numberReady
and all are greater than 0..status.currentNumberScheduled
is equal to .status.desiredNumberScheduled
and .status.numberAvailable
and all are greater than 0.status.numberUpdated
is greater than 0..status.observedGeneration
is equal to spec.generation
.Ready
condition..status.loadbalancer.ingress
list is not empty..status.loadbalancer.ingerss
is not empty.Ready
when its .status.phase
is Bound
. This may seem strange as PVC implements a Ready
phase, but a PVC is not useful to the application until it is bound, and most errors post creation and during binding.This section contains the proposed modifications to the API. Here, we modify the ApplicationStatus type to report the observed status of its components. Each ComponetStatus
contains a link, resource identifying information, and the ComponentConditions
of the components indicated by the Application's .Spec.ComponentKinds
and .Spec.Selector
. The status of the applications components is used to compute ApplicationConditions
that apply to the application as a whole.
// ComponentConditionType indicates the type of a ComponentCondition.
type ComponentConditionType string
const (
// ComponentAvailable indicates that the component is available. This is used by controller to indicate that the
// resource has been ready for a sufficient period of time after creation or mutation that it is unlikely to suffer
// from infant mortality.
ComponentAvailable ComponentConditionType = "Available"
// ComponentReady indicates that component is ready to use.
ComponentReady = "Ready"
// ComponentProgressing is used to communicate that a component is in updating (i.e. A Deployment with a Rollout in
// progress or a StatefulSet with a RollingUpdate in progress).
ComponentProgressing = "Progressing"
// ComponentDisrupted is used to indicate that the component is affected by a planned or unplanned disruption.
ComponentDisrupted = "Disrupted"
// Error is used to communicate and error condition for a component.
ComponentError = "Error"
)
// ComponentCondition represents the condition of a component of an application. It is modeled after the Conditions
// use for the Kubernetes workloads objects.
type ComponentCondition struct {
// Type is the type of the condition.
Type ComponentConditionType `json:"type"`
// Status is one of True, False, Unknown.
Status v1.ConditionStatus `json:"status"`
// LastTransitionTime is the last time the condition's status changed.
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
// Reason is the reason for the condition's last transition.
Reason string `json:"reason,omitempty"`
// Message is a human readable message indicating details about the transition.
Message string `json:"message,omitempty"`
}
// ComponentStatus contains the status of a generic component selected by the Application.
type ComponentStatus struct {
// Name is the name of the component to which the condition pertains.
Name string `json:"name"` ComponentConditionTyp
// Namespace is the name containing the component to which the condition pertains.
Namespace string `json:"namespace,omitempty"`
// GroupKind indicates the group and kind of the component.
GroupKind metav1.GroupKind `json:groupKind"`
// Link is a link to the resource that represents the component.
Link string `json:"link,omitempty"`
// Available indicates that the component is available. This is used by controller to indicate that the
// resource has been ready for a sufficient period of time after creation or mutation that it is unlikely to suffer
// from infant mortality.
Available *bool `json:"available,omitempty"`
// tReady indicates that component is ready to use.
Ready *bool `json:"ready,omitempty"`
// Progressing is used to communicate that a component is in updating (i.e. A Deployment with a Rollout in
// progress or a StatefulSet with a RollingUpdate in progress).
Progressing *bool `json:"progressing,bool"`
// Observed indicates that the controller for the component's resource has observed the current generation.
// (i.e .Meta.Generation == .Status.ObservedGeneration)
Observed bool = `json:"observed,omitempty"`
// Conditions contains the conditions that are applicable to the component.
Conditions [] ComponentCondition `json:"conditions,omitempty"`
}
// ApplicationConditionType indicates the type of an application condition.
type ApplicationConditionType string
const (
// ApplicationError is used to communicate that an Application has an Error condition.
ApplicationError ApplicationConditionType = "Error"
)
// ApplicationCondition represents the condition of an Application.
type ApplicationCondition struct {
// Type is the type of the condition.
Type ApplicationConditionType `json:"type"`
// Status is one of True, False, Unknown.
Status v1.ConditionStatus `json:"status"`
// LastTransitionTime is the last time the condition's status changed.
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
// Reason is the reason for the condition's last transition.
Reason string `json:"reason,omitempty"`
// Message is a human readable message indicating details about the transition.
Message string `json:"message,omitempty"`
}
type ApplicationStatus struct {
// Ready indicates that all of an Application's components are Available.
Ready *bool `json:"available,omitempty"`
// Updating is used to communicate that a component is in updating (i.e. A Deployment with a Rollout in
// progress or a StatefulSet with a RollingUpdate in progress.
Updating *bool `json:"progressing,bool"`
// Conditions is a list of ApplicationConditions for the application.
Conditions [] ApplicationCondition
//ComponentStatus is a list of the statues of the applications components.
Components [] ComponentStatus
}
The Application controller will periodically list the applications residing on the API Server. For each Application resource the controller will do the following.
spec.assemblyPhase
of the Application is pending the controller will not update the .status
of the Application. This allows application installers time apply all necessary components prior to application status computation..spec.componentKinds
.
.status.components
of the Application.Progressing
the status.updating
field is set to true.status.ready
field is set to true.status.ready
field is set to false.apiVersion: app.k8s.io/v1beta1
kind: Application
metadata:
name: "wordpress-01"
labels:
app.kubernetes.io/name: "wordpress-01"
spec:
type: "wordpress"
selector:
matchLabels:
app.kubernetes.io/name: "wordpress-01"
componentKinds:
- group: core
kind: Service
- group: apps
kind: StatefulSet
version: "4.9.4"
description: "WordPress is open source software you can use to create a beautiful website, blog, or app."
icons:
- src: "https://s.w.org/style/images/about/WordPress-logotype-wmark.png"
type: "image/png"
size: "1000x1000"
- src: "https://s.w.org/style/images/about/WordPress-logotype-standard.png"
type: "image/png"
size: "2000x680"
maintainers:
- name: Kenneth Owens
email: [email protected]
owners:
- name: Kenneth Owens
email: [email protected]
keywords:
- "cms"
- "blog"
- "wordpress"
links:
- description: About
url: "https://wordpress.org/"
- description: Web Server Dashboard
url: "https://metrics/internal/wordpress-01/web-app"
- description: Mysql Dashboard
url: "https://metrics/internal/wordpress-01/mysql"
status:
ready: true
updating: false
components:
- name: wordpress-mysql-hvc
namespace: default
groupKind: Service
link: /apis/v1/namespaces/default/services/wordpress-mysql-hvc
ready: true
- name: wordpress-mysql
namespace: default
groupKind: apps/StatefulSet
link: /apis/apps/v1/namespaces/default/statefulsets/wordpress-mysql
ready: true
avialable: true
- name: wordpress-webserver-svc
namespace: default
groupKind: Service
link: /apis/v1/namespaces/default/services/wordpress-webserver-svc
ready: true
- name: wordpress-webserver
namespace: default
groupKind: apps/StatefulSet
link: /apis/apps/v1/namespaces/default/statefulsets/wordpress-webserver
ready: true
avialable: true
This project needs some clear docs on:
I imagine there are others. This is just a first pass.
Move the code base to the new release of kube-builder.
This would be useful to start implementing features in AppCRD.
The structure for maintainers
is:
maintainers:
- name: Kenneth Owens
email: [email protected]
The structure for owners
is:
owners:
- "Kenneth Owens [email protected]"
We should make these consistent. I didn't create a PR because I wasn't sure of the naming to use internally. I could use the Maintainer
struct but the name isn't a great fit. Any ideas on the naming?
Many apps provide a primary link (e.g. PhpMyAdmin, WordPress admin, IP address) that is the user's main destination. It looks like this link is typically put into "infoItems" array. Would it be useful to define an attribute for 'primaryLink', so it is easier to identify and highlight in a UI?
The current application definition combines the description for a kind of an application with the selector for finding an instance of that kind of application.
We were thinking about how to use the application definition for OLM, which has many of the same metadata needs as in the Application CRD. The fact that both metadata and selector are combined makes it hard to re-use for us.
For reference, here's the example application in the Readme:
apiVersion: app.k8s.io/v1beta1
kind: Application
metadata:
name: "wordpress-01"
labels:
app.kubernetes.io/name: "wordpress-01"
app.kubernetes.io/version: "3"
spec:
selector:
matchLabels:
app.kubernetes.io/name: "wordpress-01"
componentKinds:
- group: core
kind: Service
- group: apps
kind: Deployment
- group: apps
kind: StatefulSet
descriptor:
version: "4.9.4"
description: "WordPress is open source software you can use to create a beautiful website, blog, or app."
icons:
- src: "https://example.com/wordpress.png"
type: "image/png"
type: "wordpress"
maintainers:
- name: Kenneth Owens
email: [email protected]
owners:
- "Kenneth Owens [email protected]"
keywords:
- "cms"
- "blog"
- "wordpress"
links:
- description: About
url: "https://wordpress.org/"
- description: Web Server Dashboard
url: "https://metrics/internal/wordpress-01/web-app"
- description: Mysql Dashboard
url: "https://metrics/internal/wordpress-01/mysql"
I'd like to propose splitting this into two objects; one which represents the application kind, and one which selects a particular instance of that application.
For the example above, this would look like:
Description of Application Type: (note missing selector and name change)
apiVersion: app.k8s.io/v1beta1
kind: ApplicationMetadata
metadata:
name: "wordpress"
labels:
app.kubernetes.io/name: "wordpress"
app.kubernetes.io/version: "3"
spec:
version: "4.9.4"
description: "WordPress is open source software you can use to create a beautiful website, blog, or app."
icons:
- src: "https://example.com/wordpress.png"
type: "image/png"
type: "wordpress"
maintainers:
- name: Kenneth Owens
email: [email protected]
owners:
- "Kenneth Owens [email protected]"
keywords:
- "cms"
- "blog"
- "wordpress"
links:
- description: About
url: "https://wordpress.org/"
- description: Web Server Dashboard
url: "https://metrics/internal/wordpress-01/web-app"
- description: Mysql Dashboard
url: "https://metrics/internal/wordpress-01/mysql"
and a selector for a specific instance of that application type:
apiVersion: app.k8s.io/v1beta1
kind: ApplicationSelector
metadata:
name: "wordpress-01"
labels:
app.kubernetes.io/metadata: "wordpress"
spec:
metadata: "wordpress"
selector:
matchLabels:
app.kubernetes.io/name: "wordpress-01"
componentKinds:
- group: core
kind: Service
- group: apps
kind: Deployment
- group: apps
kind: StatefulSet
status:
assemblyPhase: "Pending"
I can then stamp out multiple instances (say, a production
and a staging
) without replicating all of the metadata between them.
There is a discuss on Helm charts on how applications can collect analytics on not. It dawned on me that may be there should be a field for setting link to a privacy policy document in the application CRD. Is the Links
field enough for that?
ref: helm/charts#4697 (comment)
cc: @mattfarina
Application CRD has a list of GroupKinds and a LabelSelector to logically group live objects in the cluster. The Application CRD also provides a way to attach descriptive metadata to the logical grouping.
This proposes to enhance Application CRD controller to provide status tracking for the objects that match the selectors. This dramatically simplifies the status tracking requirements for a client that uses Application CRD.
The proposal is to add a reconciler that creates watches for the GroupKinds that the application CRD refers to. The reconciler then inspects the matching objects and updates the aggregate status in the Application CRD.
Please review the attached proposal: #77
There are at least two ways to deal with garbage collection of application resources. The first, and simplest, approach is to inject owner reference into each component of the application using the Name, APIVersion, and Kind of the Application CRD. This would work as follows. There is no need to worry about injecting OwnerReferences into intermediate or children objects (e.g. If an OwnerReference is injected into a Deployment, chain garbage collection will delete its ReplicaSets and their Pods). When the Application is deleted the Garbage Collector will delete all Orphaned children. While this has the benefit of simplicity, it has a few drawbacks.
Another approach would be to construct a graph based controller using the Application's Selector and appropriate labels on children objects to indicate ownership. This controller would watch for the creation of all objects in the system and establish ownership by automatically injecting OwnerReferences. As above, when the Application object is deleted, the Garbage Collector will delete its children.This mitigates the need for tools to inject OwnerReferences, and it ensures that the Garbage Collector will not delete an Application's children prior to creation of the Application (i.e. there need not be a serialized ordering between observation of Application creation and the creation of its children), but it has drawbacks as well.
Another option is to begin with user tool injected OwnerReferences, and, when the full requirements of Garbage Collection become well understood after some period of production usage, automate the process by adding OwnerReference marking in the Application controller. The controller can be implemented in a way that is strictly backward compatible with user injected OwnerReference. In fact, in order function properly it must be compatible with user injected OwnerReferences.
What is the current scope of the first release?
What information do we want to store in the Status fields?
I think that the doc should be updated/improved to mention which command should be first executed to install the missing vendor packages as I get this error during docker build
imagebuilder -t my-image -f Dockerfile.controller .
--> Image golang:1.9.3 was not found, pulling ...
--> Pulled 0/8 layers, 1% complete
--> Pulled 1/8 layers, 16% complete
--> Pulled 2/8 layers, 29% complete
--> Pulled 2/8 layers, 46% complete
--> Pulled 3/8 layers, 55% complete
--> Pulled 4/8 layers, 58% complete
--> Pulled 5/8 layers, 71% complete
--> Pulled 6/8 layers, 84% complete
--> Pulled 7/8 layers, 90% complete
--> Pulled 7/8 layers, 98% complete
--> Pulled 8/8 layers, 100% complete
--> Extracting
--> FROM golang:1.9.3 as builder
--> ENV TEST_ASSET_DIR /usr/local/bin
--> ENV TEST_ASSET_KUBECTL $TEST_ASSET_DIR/kubectl
--> ENV TEST_ASSET_KUBE_APISERVER $TEST_ASSET_DIR/kube-apiserver
--> ENV TEST_ASSET_ETCD $TEST_ASSET_DIR/etcd
--> ENV TEST_ASSET_URL https://storage.googleapis.com/k8s-c10s-test-binaries
--> RUN curl ${TEST_ASSET_URL}/etcd-Linux-x86_64 --output $TEST_ASSET_ETCD
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 16.9M 100 16.9M 0 0 2198k 0 0:00:07 0:00:07 --:--:-- 2340k
--> RUN curl ${TEST_ASSET_URL}/kube-apiserver-Linux-x86_64 --output $TEST_ASSET_KUBE_APISERVER
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 200M 100 200M 0 0 2438k 0 0:01:24 0:01:24 --:--:-- 2268k
--> RUN curl https://storage.googleapis.com/kubernetes-release/release/v1.9.2/bin/linux/amd64/kubectl --output $TEST_ASSET_KUBECTL
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 64.2M 100 64.2M 0 0 2507k 0 0:00:26 0:00:26 --:--:-- 2561k
--> RUN chmod +x $TEST_ASSET_ETCD
--> RUN chmod +x $TEST_ASSET_KUBE_APISERVER
--> RUN chmod +x $TEST_ASSET_KUBECTL
--> WORKDIR /go/src/github.com/kubernetes-sigs/application
--> COPY pkg/ pkg/
--> COPY cmd/ cmd/
--> COPY vendor/ vendor/
--> RUN go build -a -o controller-manager ./cmd/controller-manager/main.go
pkg/apis/app/v1alpha1/application_types.go:21:2: cannot find package "k8s.io/kubernetes/pkg/apis/core" in any of:
/go/src/github.com/kubernetes-sigs/application/vendor/k8s.io/kubernetes/pkg/apis/core (vendor tree)
/usr/local/go/src/k8s.io/kubernetes/pkg/apis/core (from $GOROOT)
/go/src/k8s.io/kubernetes/pkg/apis/core (from $GOPATH)
running 'go build -a -o controller-manager ./cmd/controller-manager/main.go' failed with exit code 1
After doing a dep ensure
, I get another error
...
--> RUN go build -a -o controller-manager ./cmd/controller-manager/main.go
# github.com/kubernetes-sigs/application/pkg/inject
pkg/inject/inject.go:17:14: undefined: "github.com/kubernetes-sigs/application/vendor/github.com/kubernetes-sigs/kubebuilder/pkg/inject/args".Injector
running 'go build -a -o controller-manager ./cmd/controller-manager/main.go' failed with exit code 2
Remark : Build executed against master branch of this repo
I'm recording this, in part for myself, to convert the html table to a markdown table in the readme. This is an easy one if someone else wants to pick it up.
Note README states type for maintainers and owners is the same:
However, in install.yaml they are dissimilar:
maintainers:
items:
properties:
email:
type: string
name:
type: string
url:
type: string
type: object
type: array
and
owners:
items:
type: string
type: array
type:
type: string
Moreover,
samples/application.yaml assumes maintainers and owners are the same type:
maintainers:
- name: Kenneth Owens
email: [email protected]
owners:
- name: Kenneth Owens
email: [email protected]
Interestingly, samples/application.yaml successfully creates an application object on Kubernetes 1.8.0,
but it fails on Kubernetes 1.9.1 with this error:
spec.descriptor.owners in body must be of type string: "object"
I didn't try other versions. But it's apparent the definition in install.yaml should be the same. I fixed this in my local repo and would happily create a PR, but my company has not yet given me approval to sign the Contributor License Agreement (CLA) for this project.
This issue captures one of the threads on #4 where it was proposed to allow the Application to reference values/properties from Secret, ConfigMap, Ingress or Service.
Some quotes from the thread:
From @deustis: "[...]On the topic of credentials, we might want to establish a pattern for referencing Secrets. A very common getting started experience for an off-the-shelf app is trying to locate the password for an admin dashboard[...]"
@huyhg proposed simple templating system, where the template itself would live in spec and interpolated template would live in status.
@prydonius prefers enumerating reference types explicitly (Secret, ConfigMap, Ingress, Service)
@deustis proposed a templating system that would live in in spec but the evaluation would be the client responsibility (like @huyhg's proposal, but with no interpolation into spec). Also, the individual fields of the referenced objects would be selected using jsonpath.
@konryd pointed out that secret's values are typically evaluated on startup.
I am not clear what values from within the Application CRD will be used to select the objects that will define my Application within the cluster.
My assumption is that values defined in the Application CRD will be used to query cluster objects which will then define my Application.
Is the selector the single value spec.selector or is the selection also limited by spec.componentKinds?
Is the selection does by the Application controller and/or by the third party tool? The tool provider would get the selector from the CRD and then query for the objects?
The InfoItemSource
allows to identify the type of the information we want to capture using an InfoItem
. This information is defined using the InfoItemSourceType.
Unfortunately, the existing list of const
as defined hereafter does not include the Kubernetes type: EnvVarFrom
[1].
Existing Source's types
type InfoItemSource struct {
// Type of source.
Type InfoItemSourceType `json:"type,omitempty"`
...
}
// InfoItemSourceType is a string
type InfoItemSourceType string
// Constants for info type
const (
SecretKeyRefInfoItemSourceType InfoItemSourceType = "SecretKeyRef"
ConfigMapKeyRefInfoItemSourceType InfoItemSourceType = "ConfigMapKeyRef"
ServiceRefInfoItemSourceType InfoItemSourceType = "ServiceRef"
IngressRefInfoItemSourceType InfoItemSourceType = "IngressRef"
)
We propose to extend the list of the InfoItemSourceType
const in order to include the EnvVarFromSource
const (
EnvVarFromSourceRefInfoItemSourceType InfoItemSourceType = "EnvVarFromSourceRef" // Refer to either a Secret or ConfigMap
)
[1] : https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.13/#envvarsource-v1-core
WDYT @ant31 @barney-s @mattfarina ?
We need to add CI that runs against master and pull requests.
Deployment
ReplicaSet and ReplicationController
StatefulSet
DaemonSet
Pod
Ingress
Service
PersistentVolumeClaim
In README.md spec.componentKinds lack descriptions for the 'group' key. This seems to be either empty, core
or apps
in the samples. Please describe.
Also the GroupKind is written as a link, but the link target does not exists.
The InfoItem
allows to define human readable key,value pair containing important information about how to access the Application.
One of the most important information which is represented by the K8s Env Var [1] is currently missing.
Such EnvVar are used by many java, nodejs, ... applications when they are deployed as they will let by example to configure a Datasource to access a database (e.g : database name, username, password, ...), client accessing a Messaging broker, jvm, ...
By adopting a new InfoItemSourceType
and InfoItemSource
we could define such a list of key/value pairs as defined using an Envs
array
Proposition
type InfoItemSource struct {
// Type of source.
Type InfoItemSourceType `json:"type,omitempty"`
...
Envs []Env `json:"envs,omitempty"`
}
type Env struct {
Name string `json:"name,omitempty"`
Value string `json:"value,omitempty"`
}
// Constants for info type
const (
EnvVarInfoItemSourceType InfoItemSourceType = "EnVar"
[1] : https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.13/#envvar-v1-core
WDYT @ant31 @barney-s @mattfarina ?
Issue #7 is about putting OwnerReference
onto components that comprise an Application
. I would like to use this issue to open some discussion on the ownership between custom resources and Applications
. Here's a scenario: suppose there's a CRD for a type of applications, which need a set of Kubernetes resources to run, e.g., a StatefulSet, some Service, and also some other resources. The corresponding Kubernetes operator watches instances of the CRD kind and creates the necessary resources for each newly created custom resource instance. When creating the resources, the operator adds an OwnerReference
to each of the resources referencing the instance. The reason for this is when the user deletes the custom resource object, the resources get garbage collected.
Additionally, to allow components of each application instance to be logically grouped, an Application
instance is also created by the operator. So the Application
instance is created as a result of the operator seeing the custom resource instance and it probably makes sense to have the custom resource object "owns" the Application
instance. However, it might also makes sense (although debatable I guess) the other way around if the custom resource instance is owned by the Application
instance as part of the logic group of components supporting the application. The former is straightforward to realize but the latter faces the same problem #7 discussed.
I would like to hear others' thoughts on this.
Proposed: add namespace qualification to 'componentKinds'
Discussion:
It is abundantly clear that cloud native applications may be comprised of resources from multiple namespaces.
Scenarios:
One scenario is that an Application corresponds exactly to a set of resources that are deployed together, and deployed to the same namespace. This scenario is most easily described as a single team, deploying multiple resources with a single helm chart, all to the same namespace.
Another scenario is that an Application corresponds to a set of resources, some of which are deployed together (e.g. single team, as above), as well as others that are deployed separately (perhaps shared services) by other teams. We should not assume all teams deploy to the same namespace.
For example, my stock-trader application is comprised of these components:
The preceding list makes the point that an application's components - the very ones the user wants to regard as being part of their application - may be deployed as part of the principle application (i.e. stocktrader, in this example), as well as include services deployed by other teams (e.g. loyalty and messaging).
To describe an application whose components are in various namespaces requires a way to specify that fact. I propose we add namespace to componentKinds, e.g., like this:
componentKinds
- group: deployments-stocktrader
kind: Deployment
namespace: stocktrader
- group: deployments-loyalty
kind: Deployment
namespace: loyalty
- group: deployments-services
kind: Deployment
namespace: services
The original KEP proposed the following notion of application Dependencies
// ApplicationSpec defines the specification for an Application.
type ApplicationSpec struct {
// Existing fields omitted for brevity
// Dependencies is a list of Applications on which this Application depends.
Dependencies [] string
}
// ApplicationStatus defines controllers the observed state of Application
type ApplicationStatus struct {
// ObservedGeneration is used by the Application Controller to report the last Generation of an Application
// that it has observed.
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
// Installed is a list of the currently installed components and dependencies for an Application as
// observed by the controller.
Installed []string `json:"installed,omitempty"`
}
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// Application
// +k8s:openapi-gen=true
// +resource:path=applications
// The Application object acts as an aggregator for components that comprise an Application. Its
// Spec.ComponentGroupKinds indicate the GroupKinds of the components the comprise the Application. Its Spec. Selector
// is used to list and watch those components. All components of an Application should be labeled such the Application's
// Spec. Selector matches.
type Application struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
// The specification object for the Application.
Spec ApplicationSpec `json:"spec,omitempty"`
// The status object for the Application.
Status ApplicationStatus `json:"status,omitempty"`
}
The notion of Dependencies is necessarily namespace bound by this definition. The application controller would simply track the components of the installed application through their life-cycle and update the Status.Installed list when a dependent component is created.
As per the email sent to kubernetes-dev[1], please create a SECURITY_CONTACTS
file.
The template for the file can be found in the kubernetes-template repository[2].
A description for the file is in the steering-committee docs[3], you might need
to search that page for "Security Contacts".
Please feel free to ping me on the PR when you make it, otherwise I will see when
you close this issue. :)
Thanks so much, let me know if you have any questions.
(This issue was generated from a tool, apologies for any weirdness.)
[1] https://groups.google.com/forum/#!topic/kubernetes-dev/codeiIoQ6QE
[2] https://github.com/kubernetes/kubernetes-template-project/blob/master/SECURITY_CONTACTS
[3] https://github.com/kubernetes/community/blob/master/committee-steering/governance/sig-governance-template-short.md
As a follow-on to 28fd24c, update example.yaml
to nest relevant information into a descriptor
block.
I'm a bit confused about how the Application operator populates a list of components from an Application
This code is responsible to get the components of a resource
components := rsrc.Components()
for _, component := range components {
but if I look to the code developed
// Components returns components for this resource
func (a *Application) Components() []component.Component {
c := []component.Component{}
c = append(c, component.Component{
Handle: a,
Name: "app",
CR: a,
OwnerRef: a.OwnerRef(),
})
return c
}
a Component
is appended to the list and the Component
is always created using the current application
Questions :
ComponentGroupKinds
of the spec is to group the k8s resources created or to be created for an application ?The template project has a structure that should be adopted here. An OWNERS file, contributing guide, CoC, and so forth should be added.
I do not understand the concept trying to be conveyed below. Could you please clarify?
In the README.md file, under the This can be used by, the first bullet item: Application operators who want to center what they operate on applications,
Fix make deploy to use the latest image and with appropriate rbac for the controller.
The ApplicationSpec type includes the field spec.componentKinds
to group under a name, related kubernetes resources such as Service, StatefulSet, ConfigMap, Secret ... describing globally what the application is composed
// ApplicationSpec defines the specification for an Application.
type ApplicationSpec struct {
// ComponentGroupKinds is a list of Kinds for Application's components (e.g. Deployments, Pods, Services, CRDs). It
// can be used in conjunction with the Application's Selector to list or watch the Applications components.
ComponentGroupKinds []metav1.GroupKind `json:"componentKinds,omitempty"`
If we use this Application custom resource to install/configure the environment on kubernetes to deploy the resources needed using a controller or operator, then it is important to have also a specialised type able to :
Example: As a user, I would like to install a Spring Boot application using the version 1.5.15 of the framework and would like to access it externally using a route. The default port of the service is 8080. To convert this requirement into a component's type, then the following object could be created
apiVersion: component.k8s.io/v1alpha1
kind: Component
metadata:
name: my-spring-boot
spec:
deployment: innerloop
packaging: jar
type: application
runtime: spring-boot
version: 1.5.15
exposeService: true
The advantage to have such component
custom resource is that we could be able with a UI or CLI to display the information in a more readable way
kubectl application describe
NAME Category Type Version Source Visible Externally
payment-frontend runtime nodejs 0.8 local yes
payment-backend runtime spring-boot 1.5.15 binary no
payment-database service db-postgresql-apb dev no
Component's type proposition
type ComponentSpec struct {
// The name represents a human readable string describing from a business perspective what this component is related to
// Example : payment-frontend, retail-backend
Name string
// The packagingMode refers to the archive file's type which has been used to package the code
// Example : jar, war, ...
PackagingMode string
// The type is related to how the component is installed, as a pod, job, statefulset
Type string
// DeploymentMode indicates the strategy to be adopted to install the resources into a namespace
// and next to create a pod. 2 strategies are currently supported; inner and outer loop
// where outer loop refers to a build of the code and the packaging of the application into a container's image
// while the inner loop will install a pod's running a supervisord daemon used to trigger actions such as : assemble, run, ...
DeploymentMode string `json:"deployment,omitempty"`
// Runtime is the framework used to start within the container the application
// It corresponds to one of the following values: spring-boot, vertx, tornthail, nodejs
Runtime string `json:"runtime,omitempty"`
// To indicate if we want to expose the service out side of the cluster as a route
ExposeService bool `json:"exposeService,omitempty"`
// Cpu is the cpu to be assigned to the pod's running the application
Cpu string `json:"cpu,omitempty"`
// Cpu is the memory to be assigned to the pod's running the application
Memory string `json:"memory,omitempty"`
// Port is the HTTP/TCP port number used within the pod by the runtime
Port int32 `json:"port,omitempty"`
// The storage allows to specify the capacity and mode of the volume (ReadWrite) to be mounted for the pod
Storage Storage `json:"storage,omitempty"`
// The list of the images created according to the DeploymentMode to install the loop
Images []Image `json:"image,omitempty"`
// Array of env variables containing extra/additional info to be used to configure the runtime
Envs []Env `json:"env,omitempty"`
// List of services consumed by the runtime and created as service instance from a Service Catalog
Services []Service
// The features represents a capability that it is required to have, to install to allow the component
// to operate with by example a Prometheus backend system to collect metrics, an OpenTracing datastore
// to centralize the traces/logs of the runtime, to deploy a servicemesh, ...
Features []Feature
}
The readme makes several references to Application resources or components in the cluster
In the Kubernetes documentation, the only reference to components is related to the binary components needed to deliver a functioning Kubernetes cluster.
In the Kubernetes documentation, a resource is defined as "A resource is an endpoint in the Kubernetes API that stores a collection of API objects of a certain kind."
I would like to propose that we try to use Kubernetes terminology as much as possible,
Should the readme examples listed above for components and resources be documented as objects (Kubernete Objects)?
Why is the assemblyPhase
part of the spec
of the application CRD and not the status
? It's not something that a user would set, right?
I followed the instructions, and get this error:
$ kubebuilder
2018/09/06 14:33:51 kubebuilder must be run from the project root under $GOPATH/src/<package>.
Current GOPATH=/Users/subhash/gopath.
Current directory=/Users/subhash
I'm using Mac High Sierra.
I'd separate the metadata fields about an application, like description, keywords...
from the fields holding some logic like matchLabels
, componentKinds
.
First, it's more clear for the user and tools authors to spot what is informative only and what is modifying the behavior of the controller
Second, the descriptor spec could be more easily reused by other project and integrated to different CRD.
related comment (from the kinflate initial PR): kubernetes/kubernetes#52570 (comment)
type Application struct {
// Metadata about the app.
descriptor Descriptor
...
}
// Descriptor is a convenience struct gathering metadata to support
// Manifest search, browse and updates.
type Descriptor struct {
Name string
Version string
Description string
Icon string
Keywords []string
Homepage string
...
}
If a company have multiple cluster, how does Application replicate to all clusters?
Is tooling for generating Application resources (maybe from a set of YAMLs or something similar) in-scope for this project?
Currently ingressRef
supports only HTTP protocol. I would like to have there HTTPS protocol as well.
Current state:
- name: WordPress site address
type: Reference
valueFrom:
ingressRef:
name: $APP_INSTANCE_NAME-wordpress-ingress
Preferred state:
- name: WordPress site address
type: Reference
valueFrom:
ingressRef:
name: $APP_INSTANCE_NAME-wordpress-ingress
protocol: HTTPS
I think the same needs could be with serviceRef
as well.
This syntax requires me to label all resources that belong to an app with the same label (both key and value). This might be hard for external pieces, that I don't want can't change easily.
spec:
selector:
matchLabels:
app.kubernetes.io/name: "wordpress-01"
Why can't we also support this:
spec:
selector:
matchExpressions:
key: app
operator: in
values: ["foo", "bar", "baz"]
The existing code of the application_controller.go
sets the recommended k8s labels [1]
here in the code
const (
NameLabelKey = "app.kubernetes.io/name"
VersionLabelKey = "app.kubernetes.io/version"
InstanceLabelKey= "app.kubernetes.io/instance"
PartOfLabelKey= "app.kubernetes.io/part-of"
ComponentLabelKey= "app.kubernetes.io/component"
ManagedByLabelKey= "app.kubernetes.io/managed-by"
)
to decorate a k8s resource created but don't use it within the controller_application
code to annotate the Deployment resource.
I propose to add them when the labels are added here [2] in the code to support their usage and explain what is the value of each label.
[1] https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/#labels
[2] https://github.com/kubernetes-sigs/application/blob/master/pkg/controller/application/application_controller.go#L133
Feel free to rename the repo
Looking into the Application definition, how do we manage common metadata for sample type of application. For example if we have a lot of "SpringBoot" applications, some of the metadata should be same, it will be duplicated in each same type of application and it will be hard to maintain.
Red Hat and the Kubernetes open source community today share the Operator Framework โ an open source toolkit designed to manage Kubernetes native applications, called Operators, in a more effective, automated, and scalable way.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.