Duck typing

Knative enables loose coupling of its components by using duck typing.

Duck typing means that the compatibility of a resource for use in a Knative system is determined by certain properties that are used to identify the resource control plane shape and behaviors. These properties are based on a set of common definitions for different types of resources, called duck types.

Knative can use a resource as if it is the generic duck type, without specific knowledge about the resource type, if:

  • The resource has the same fields in the same schema locations as the common definition specifies
  • The same control or data plane behaviors as the common definition specifies

Some resources can opt in to multiple duck types.

A fundamental use of duck typing in Knative is using object references in resource specs to point to other resources. The definition of the object containing the reference prescribes the expected duck type of the resource being referenced.

Example

In the following example, a Knative Example resource named pointer references a Dog resource named pointee in its spec:

  1. apiVersion: sample.knative.dev/v1
  2. kind: Example
  3. metadata:
  4. name: pointer
  5. spec:
  6. size:
  7. apiVersion: extension.example.com/v1
  8. kind: Dog
  9. name: pointee

If the expected shape of a Sizable duck type is that, in the status, the schema shape is the following:

  1. status:
  2. height: <in centimetres>
  3. weight: <in kilograms>

Now the instance of pointee could look like this:

  1. apiVersion: extension.example.com/v1
  2. kind: Dog
  3. metadata:
  4. name: pointee
  5. spec:
  6. owner: Smith Family
  7. etc: more here
  8. status:
  9. lastFeeding: 2 hours ago
  10. hungry: true
  11. age: 2
  12. height: 60
  13. weight: 20

When the Example resource functions, it only acts on the information in the Sizable duck type shape, and the Dog implementation is free to have the information that makes the most sense for that resource. The power of duck typing is apparent when we extend the system with a new type, for example, Human, if the new resource adheres to the contract set by Sizable.

  1. apiVersion: sample.knative.dev/v1
  2. kind: Example
  3. metadata:
  4. name: pointer
  5. spec:
  6. size:
  7. apiVersion: people.example.com/v1
  8. kind: human
  9. name: pointee
  10. ---
  11. apiVersion: people.example.com/v1
  12. kind: Human
  13. metadata:
  14. name: pointee
  15. spec:
  16. etc: even more here
  17. status:
  18. college: true
  19. hungry: true
  20. age: 22
  21. height: 170
  22. weight: 50

The Example resource is able to apply the logic configured for it, without explicit knowledge of Human or Dog.

Knative Duck Types

Knative defines several duck type contracts that are in use across the project:

Addressable

Addressable is expected to be the following shape:

  1. apiVersion: group/version
  2. kind: Kind
  3. status:
  4. address:
  5. url: http://host/path?query

Binding

With a direct subject, Binding is expected to be in the following shape:

  1. apiVersion: group/version
  2. kind: Kind
  3. spec:
  4. subject:
  5. apiVersion: group/version
  6. kind: SomeKind
  7. namespace: the-namespace
  8. name: a-name

With an indirect subject, Binding is expected to be in the following shape:

  1. apiVersion: group/version
  2. kind: Kind
  3. spec:
  4. subject:
  5. apiVersion: group/version
  6. kind: SomeKind
  7. namespace: the-namespace
  8. selector:
  9. matchLabels:
  10. key: value

Source

With a ref Sink, Source is expected to be in the following shape:

  1. apiVersion: group/version
  2. kind: Kind
  3. spec:
  4. sink:
  5. ref:
  6. apiVersion: group/version
  7. kind: AnAddressableKind
  8. name: a-name
  9. ceOverrides:
  10. extensions:
  11. key: value
  12. status:
  13. observedGeneration: 1
  14. conditions:
  15. - type: Ready
  16. status: "True"
  17. sinkUri: http://host

With a uri Sink, Source is expected to be in the following shape:

  1. apiVersion: group/version
  2. kind: Kind
  3. spec:
  4. sink:
  5. uri: http://host/path?query
  6. ceOverrides:
  7. extensions:
  8. key: value
  9. status:
  10. observedGeneration: 1
  11. conditions:
  12. - type: Ready
  13. status: "True"
  14. sinkUri: http://host/path?query

With ref and uri Sinks, Source is expected to be in the following shape:

  1. apiVersion: group/version
  2. kind: Kind
  3. spec:
  4. sink:
  5. ref:
  6. apiVersion: group/version
  7. kind: AnAddressableKind
  8. name: a-name
  9. uri: /path?query
  10. ceOverrides:
  11. extensions:
  12. key: value
  13. status:
  14. observedGeneration: 1
  15. conditions:
  16. - type: Ready
  17. status: "True"
  18. sinkUri: http://host/path?query