Once a custom resource is installed, users can create and access its objects using
kubectl
When you combine a custom resource with a custom controller, custom resources
provide a true declarative API.
A declarative API
allows you to declare or specify the desired state of your resource and tries to
keep the current state of Kubernetes objects in sync with the desired state.
Custom controllers can work with any kind of resource,
but they are especially effective when combined with custom resources.
The
Operator pattern combines custom
resources and custom controllers.
the API represents a desired state, not an exact state.
define configuration of applications or infrastructure.
The main operations on the objects are CRUD-y (creating, reading, updating and deleting).
The client says "do this", and then gets an operation ID back, and has to check a separate Operation object to determine completion of the request.
The natural operations on the objects are not CRUD-y.
High bandwidth access (10s of requests per second sustained) needed.
Use a ConfigMap if any of the following apply
You want to put the entire config file into one key of a configMap.
You want to perform rolling updates via Deployment, etc., when the file is updated.
Use a secret for sensitive data, which is similar to a configMap but more secure.
You want to build new automation that watches for updates on the new object, and then CRUD other objects, or vice versa.
You want the object to be an abstraction over a collection of controlled resources, or a summarization of other resources.
CRDs are simple and can be created without any programming.
Aggregated APIs are subordinate API servers that sit behind the primary API server
CRDs allow users to create new types of resources without adding another API server
Defining a CRD object creates a new custom resource with a name and schema that you specify.
The name of a CRD object must be a valid
DNS subdomain name
each resource in the Kubernetes API requires code that handles REST requests and manages persistent storage of objects.
The main API server delegates requests to you for the custom resources that you handle,
making them available to all of its clients.
The new endpoints support CRUD basic operations via HTTP and kubectl
Custom resources consume storage space in the same way that ConfigMaps do.
Aggregated API servers may use the same storage as the main API server
CRDs always use the same authentication, authorization, and audit logging as the built-in resources of your API server.
most RBAC roles will not grant access to the new resources (except the cluster-admin role or any role created with wildcard rules).
CRDs and Aggregated APIs often come bundled with new role definitions for the types they add.
"Riemann aggregates events from your servers and applications with a powerful stream processing language. Send an email for every exception in your app. Track the latency distribution of your web app. See the top processes on any host, by memory and CPU. Combine statistics from every Riak node in your cluster and forward to Graphite. Track user activity from second to second."
use the StatefulSet workload controller to maintain identity for each of the pods, and to use Persistent Volumes to persist data so it can survive a service restart.
a way to extend Kubernetes functionality with application specific logic using custom resources and custom controllers.
An Operator can automate various features of an application, but it should be specific to a single application
Kubebuilder is a comprehensive development kit for building and publishing Kubernetes APIs and Controllers using CRDs
Design declarative APIs for operators, not imperative APIs. This aligns well with Kubernetes APIs that are declarative in nature.
With declarative APIs, users only need to express their desired cluster state, while letting the operator perform all necessary steps to achieve it.
scaling, backup, restore, and monitoring. An operator should be made up of multiple controllers that specifically handle each of the those features.
the operator can have a main controller to spawn and manage application instances, a backup controller to handle backup operations, and a restore controller to handle restore operations.
each controller should correspond to a specific CRD so that the domain of each controller's responsibility is clear.
If you keep a log for every container, you will likely end up with unmanageable amount of logs.
integrate application-specific details to the log messages such as adding a prefix for the application name.
you may have to use external logging tools such as Google Stackdriver, Elasticsearch, Fluentd, or Kibana to perform the aggregations.
adding labels to metrics to facilitate aggregation and analysis by monitoring systems.
a more viable option is for application pods to expose a metrics HTTP endpoint for monitoring tools to scrape.
A good way to achieve this is to use open-source application-specific exporters for exposing Prometheus-style metrics.
long-term archival. These archival destinations are not visible to or configurable by the app, and instead are completely managed by the execution environment.
Most significantly, the stream can be sent to a log indexing and analysis system such as Splunk, or a general-purpose data warehousing system such as Hadoop/Hive.
In a cluster, logs should have a separate storage and lifecycle independent of nodes, pods, or containers. This concept is called cluster-level logging.
Cluster-level logging architectures require a separate backend to store, analyze, and query logs
Kubernetes
does not provide a native storage solution for log data.
use kubectl logs --previous to retrieve logs from a previous instantiation of a container.
A container engine handles and redirects any output generated to a containerized application's stdout and stderr streams
The Docker JSON logging driver treats each line as a separate message.
By default, if a container restarts, the kubelet keeps one terminated container with its logs.
An important consideration in node-level logging is implementing log rotation,
so that logs don't consume all available storage on the node
You can also set up a container runtime to
rotate an application's logs automatically.
The two kubelet flags container-log-max-size and container-log-max-files can be used to configure the maximum size for each log file and the maximum number of files allowed for each container respectively.
The kubelet and container runtime do not run in containers.
On machines with systemd, the kubelet and container runtime write to journald. If
systemd is not present, the kubelet and container runtime write to .log files
in the /var/log directory.
System components inside containers always write
to the /var/log directory, bypassing the default logging mechanism.
Kubernetes does not provide a native solution for cluster-level logging
Use a node-level logging agent that runs on every node.
implement cluster-level logging by including a node-level logging agent on each node.
the logging agent is a container that has access to a directory with log files from all of the application containers on that node.
the logging agent must run on every node, it is recommended to run the agent
as a DaemonSet
Node-level logging creates only one agent per node and doesn't require any changes to the applications running on the node.
Containers write stdout and stderr, but with no agreed format. A node-level agent collects these logs and forwards them for aggregation.
Each sidecar container prints a log to its own stdout or stderr stream.
It is not recommended to write log entries with different formats to the same log
stream
writing logs to a file and
then streaming them to stdout can double disk usage.
If you have
an application that writes to a single file, it's recommended to set
/dev/stdout as the destination
it's recommended to use stdout and stderr directly and leave rotation
and retention policies to the kubelet.
Using a logging agent in a sidecar container can lead
to significant resource consumption. Moreover, you won't be able to access
those logs using kubectl logs because they are not controlled
by the kubelet.
run one or two control plane instances per failure zone,
scaling those instances vertically first and then scaling horizontally after reaching
the point of falling returns to (vertical) scale.
Kubernetes
nodes do not automatically steer traffic towards control-plane endpoints that are in the
same failure zone
store Event objects in a separate
dedicated etcd instance.
start and configure additional etcd instance
Kubernetes resource limits
help to minimize the impact of memory leaks and other ways that pods and containers can
impact on other components.
Addons' default limits are typically based on data collected from experience running
each addon on small or medium Kubernetes clusters.
When running on large
clusters, addons often consume more of some resources than their default limits.
Many addons scale horizontally - you add capacity by running more pods
The VerticalPodAutoscaler can run in recommender mode to provide suggested
figures for requests and limits.
Some addons run as one copy per node, controlled by a DaemonSet: for example, a node-level log aggregator.
VerticalPodAutoscaler is a custom resource that you can deploy into your cluster
to help you manage resource requests and limits for pods.
The cluster autoscaler
integrates with a number of cloud providers to help you run the right number of
nodes for the level of resource demand in your cluster.
The addon resizer
helps you in resizing the addons automatically as your cluster's scale changes.