Bookmark this page

Chapter 6.  Enable Developer Self-Service

Abstract

Goal

Configure clusters for safe self-service by developers from multiple teams, and disallow self-service if operations staff must provision projects.

Objectives
  • Configure compute resource quotas and Kubernetes resource count quotas per project and cluster-wide.

  • Configure default and maximum compute resource requirements for pods per project.

  • Configure default quotas, limit ranges, role bindings, and other restrictions for new projects, and the allowed users to self-provision new projects.

Sections
  • Project and Cluster Quotas (and Guided Exercise)

  • Per-Project Resource Constraints: Limit Ranges (and Guided Exercise)

  • The Project Template and the Self-Provisioner Role (and Guided Exercise)

Lab
  • Enable Developer Self-Service

Project and Cluster Quotas

Objectives

  • Configure compute resource quotas and Kubernetes resource count quotas per project and cluster-wide.

Limiting Workloads

Kubernetes clusters can run heterogeneous workloads across many compute nodes. By using Kubernetes role-based access control (RBAC), cluster administrators can allow users to create workloads on their own. Although RBAC can limit the kinds of resources that users can create, administrators might want further measures to ensure correct operation of the cluster.

Clusters have limited resources, such as CPU, RAM, and storage. If workloads on a cluster exceed the available resources, then workloads might not work correctly. A cluster that is configured to autoscale might also incur unwanted economic costs if the cluster scales to accommodate unexpected workloads.

To help with this issue, Kubernetes workloads can reserve resources and declare resource limits. Workloads can specify the following properties:

Resource limits

Kubernetes can limit the resources that a workload consumes. Workloads can specify an upper bound of the resources that they expect to use under normal operation. If a workload malfunctions or has unexpected load, then resource limits prevent the workload from consuming an excessive amount of resources and impacting other workloads.

Resource requests

Workloads can declare their minimum required resources. Kubernetes tracks requested resources by workloads, and prevents deployments of new workloads if the cluster has insufficient resources. Resource requests ensure that workloads get their needed resources.

These measures prevent workloads from affecting other workloads. However, cluster administrators might need to prevent other risks.

For example, users might mistakenly create unwanted workloads. The resource requests of those unwanted workloads can prevent legitimate workloads from executing.

By dividing workloads into namespaces, Kubernetes can offer enhanced protection features. The namespace structure often mirrors the organization that runs the cluster. Kubernetes introduces resource quotas to limit resource usage by the combined workloads in a namespace.

Resource Quotas

Kubernetes administrators can create resources of the ResourceQuota type in a namespace for this purpose. When a resource quota exists in a namespace, Kubernetes prevents the creation of workloads that exceed the quota.

Whereas quota features in other systems often act on users or groups of users, Kubernetes resource quotas act on namespaces.

apiVersion: v1
kind: ResourceQuota
metadata:
  name: memory
  namespace: example
spec:
  hard: 1
    limits.memory: 4Gi
    requests.memory: 2Gi
  scopes: {} 2
  scopeSelector: {} 3

1

The hard key lists restrictions.

2 3

The scopes and scopeSelector keys define which namespace resources the quota applies to. This course does not cover those keys.

The following sections describe the compute and object count quotas that you can include in the hard key. Other components can define other quotas and enforce them.

Compute Resource Quotas

You can set the following compute quotas:

  • limits.cpu

  • limits.memory

  • requests.cpu

  • requests.memory

Limit quotas interact with resource limits, and request quotas interact with resource requests.

Limit quotas control the maximum compute resources that the workloads in a namespace can consume. Consider a namespace where all workloads have a memory limit. No individual workload can consume enough memory to cause a problem. However, because users can create any number of workloads, the workloads of a namespace can consume enough memory to cause a problem for workloads in other namespaces. If you set a namespace memory usage limit, then the workloads in the namespace cannot consume more memory than this limit.

Request quotas control the maximum resources that workloads in a namespace can reserve. If you do not set namespace request quotas, then a single workload can request any quantity of resources, such as RAM or CPU. This request can cause further requests in other namespaces to fail. By setting namespace request quotas, the total requested resources by workloads in a namespace cannot exceed the quota.

Excessive quotas can cause resource underutilization and can limit workload performance unnecessarily.

After setting any compute quota, all workloads must define the corresponding request or resource limit. For example, if you create a limits.cpu quota, then the workloads that you create require the resources.limits.cpu key.

Object Count Quotas

A quota can also limit the number of resources of a given type in a namespace. For example, you can create a quota that prevents the creation of more than 10 deployments in a namespace.

Clusters store resource definitions in a backing store. Kubernetes backing stores are databases, and like any other database, the more data that they store, the more resources are needed for adequate performance. Namespaces with many resources can impact Kubernetes performance. Additionally, any process that creates cluster resources might malfunction and create unwanted resources.

Setting object count quotas can limit the damage from accidents, and maintain adequate cluster performance.

Note

Red Hat validates the performance of OpenShift up to a specific number of objects in a set of configurations. If you are planning a large cluster, then these results can help you to size the cluster and to establish object count quotas.

See the references section for more information.

Some Kubernetes resources might affect external systems. For example, creating a persistent volume might create an entity in the storage provider. Many persistent volumes might cause issues in the storage provider. Examine the systems that your cluster interacts with to learn about possible resource constraints, and establish object count quotas to prevent issues.

Use the count/resource_type syntax to set a quota for resources of the core group. Use the oc api-resources command with an empty api-group parameter to list resources of the core group.

[user@host ~]$ oc api-resources --api-group=""  --namespaced=true
NAME                     SHORTNAMES   APIVERSION   NAMESPACED   KIND
bindings                              v1           true         Binding
...output omitted...

For resources in other groups, use the count/resource_type.group syntax.

Kubernetes initially supported quotas for a limited set of resource types. These quotas do not use the count/resource_type syntax. You might find a services quota instead of a count/services quota. The Resource Quotas reference further describes these quotas.

Applying Project Quotas

Navigate to AdministrationResourceQuotas to create a resource quota from the web console. The YAML editor loads an example resource quota that you can edit for your needs.

You can also use the oc command to create a resource quota. The oc command can create resource quotas without requiring a complete resource definition. Execute the oc create resourcequota --help command to display examples and help for creating resource quotas without a complete resource definition.

For example, execute the following command to create a resource quota that limits the number of pods in a namespace:

[user@host ~]$ oc create resourcequota example --hard=count/pods=1
resourcequota/example created

The previous command is equivalent to creating a resource quota with the following definition:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: example
spec:
  hard:
    count/pods: "1"

After creating a resource quota, the status key in the resource describes the current values and limits in the quota.

[user@host ~]$ oc get quota example -o yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  creationTimestamp: "2024-01-30T17:59:52Z"
  name: example
  namespace: default
  resourceVersion: "193658"
  uid: df12b484-4e78-4920-acb4-e04ab286a4a1
spec:
  hard:
    count/pods: "1"
status:
  hard:
    count/pods: "1"
  used:
    count/pods: "0"

The oc get and oc describe commands show resource quota information in a custom format. The oc get command displays the status of the quota in resource lists:

[user@host ~]$ oc get quota
NAME      AGE     REQUEST           LIMIT
example   9m54s   count/pods: 1/1

Resource quotas generate the kube_resourcequota metric. You can examine this metric for planning and trend analysis.

Figure 6.1:

The kube_resourcequota metric

Troubleshooting Resource Quotas

Because resource quotas are extensible, Kubernetes cannot verify that a resource quota is correct. For example, the following command creates a resource quota that has no effect:

[user@host ~]$ oc create resourcequota example --hard=count/deployment=1
resourcequota/example created

The correct syntax for limiting the number of deployments is count/deployments.apps.

To ensure that a resource quota is correct, you can use the following procedures:

  • Create a quota with an artificially low value in a testing environment, and ensure that the resource quota has an effect.

  • Review the quota status.

    For example, if a namespace contains a deployment, then an incorrectly defined resource quota shows 0 deployments:

    [user@host ~]$ oc get resourcequota
    NAME      AGE     REQUEST                 LIMIT
    example   2m47s   count/deployment: 0/1

    However, a correctly defined resource quota shows the deployment:

    [user@host ~]$ oc get resourcequota
    NAME      AGE   REQUEST                       LIMIT
    example   4s    count/deployments.apps: 1/1

Exceeding a quota often produces an error immediately. For example, if you create a deployment that exceeds the deployment quota, then the deployment creation fails.

[user@host ~]$ oc create deployment --image=nginx hello
error: failed to create deployment: deployments.apps "hello" is forbidden: exceeded quota: example, requested: count/deployments.apps=1, used: count/deployments.apps=1, limited: count/deployments.apps=1

However, some quotas do not cause operations to fail immediately. For example, if you set a resource quota for pods, then creating a deployment appears to succeed, but the deployment never becomes available. When a resource quota is acting indirectly, namespace events might provide further information.

[user@host ~]$ oc get event --sort-by .metadata.creationTimestamp
LAST SEEN   TYPE      REASON              OBJECT                        MESSAGE
...output omitted...
10s         Normal    ScalingReplicaSet   deployment/hello              Scaled up replica set hello-5cdfd9c858 to 1
9s          Warning   FailedCreate        replicaset/hello-5cdfd9c858   Error creating: pods "hello-5cdfd9c858-zsgn9" is forbidden: exceeded quota: example, requested: count/pods=1, used: count/pods=1, limited: count/pods=1
5s          Warning   FailedCreate        replicaset/hello-5cdfd9c858   (combined from similar events): Error creating: pods "hello-5cdfd9c858-h2dv4" is forbidden: exceeded quota: example, requested: count/pods=1, used: count/pods=1, limited: count/pods=1

The web console also shows quota information. Navigate to AdministrationResourceQuotas to view resource quotas and their status. The project pages on both the developer and administrator perspectives also show the quotas that apply to a specific project.

Creating Quotas Across Multiple Projects

Cluster administrators can use resource quotas to apply restrictions to namespaces.

Resource restrictions often follow organization structure. Although namespaces often reflect organization structure, cluster administrators might apply restrictions to resources without being limited to a single namespace.

For example, a group of developers manages many namespaces. Namespace quotas can limit RAM usage per namespace. However, a cluster administrator cannot limit total RAM usage by all workloads that the group of developers manages.

OpenShift introduces cluster resource quotas for those scenarios.

Cluster resource quotas follow a similar structure to namespace resource quotas. However, cluster resource quotas use selectors to choose which namespaces the quota applies to.

Cluster resource quotas selectors use set-based requirements.

The following example shows a cluster resource quota:

apiVersion: quota.openshift.io/v1
kind: ClusterResourceQuota
metadata:
  name: example
spec:
  quota: 1
    hard:
      limits.cpu: 4
  selector: 2
    annotations: {}
    labels:
      matchLabels:
        kubernetes.io/metadata.name: example

1

The quota key contains the quota definition. This key follows the structure of the ResourceQuota specification. The hard key is nested inside the quota key, instead of being directly nested inside the spec key as in resource quotas.

2

The selector key defines which namespaces the cluster resource quota applies to. Other Kubernetes features, such as services and network policies, use the same selectors.

Navigate to AdministrationCustomResourceDefinitions to create a cluster resource quota with the web console.

You can also use the oc command to create a cluster quota. The oc command can create quotas without requiring a complete resource definition. Execute the oc create clusterresourcequota --help command to display examples and help about creating cluster resource quotas without a complete resource definition.

For example, execute the following command to create a resource quota that limits total CPU requests. The quota limits the total CPU requests on namespaces that have the group label with the dev value.

[user@host ~]$ oc create clusterresourcequota example --project-label-selector=group=dev --hard=requests.cpu=10
clusterresourcequota/example created

Cluster resource quotas collect total resource usage across namespaces and enforce the limits. The following example shows the status of the previous cluster resource quota:

apiVersion: quota.openshift.io/v1
kind: ClusterResourceQuota
metadata:
  name: example
spec:
  quota:
    hard:
      requests.cpu: "10"
  selector:
    annotations: null
    labels:
      matchLabels:
        group: dev
status:
  namespaces: 1
  - namespace: example-3
    status:
      hard:
        requests.cpu: "10"
      used:
        requests.cpu: 500m
  - namespace: example-2
    status:
      hard:
        requests.cpu: "10"
      used:
        requests.cpu: 250m
_...output omitted..._
  total: 2
    hard:
      requests.cpu: "10"
    used:
      requests.cpu: 2250m

1

The namespaces key lists the namespaces that the quota applies to. For each namespace, the used key shows the current utilization.

2

The total key aggregates the data in the namespaces key.

Users might not have read access to cluster resource quotas. OpenShift creates resources of the AppliedClusterResourceQuota type in namespaces that are affected by cluster resource quotas. Project administrators can review quota usage by reviewing the AppliedClusterResourceQuota resources. For example, use the oc describe command to view the cluster resource quotas that apply to a specific namespace:

[user@host ~]$ oc describe AppliedClusterResourceQuota -n example-2
Name:		example
Created:	9 minutes ago
Labels:		<none>
Annotations:	<none>
Namespace Selector: ["example-3" "example-2" "example-4" "example-1"]
Label Selector: group=dev
AnnotationSelector: map[]
Resource	Used	Hard
--------	----	----
requests.cpu	2250m	10

Note

The --all-namespaces argument to oc commands such as the get and describe commands does not work with AppliedClusterResourceQuota resources. These resources are listed only when you select a namespace.

Navigate to AdministrationResourceQuotas to view quotas and their status. This page displays cluster quotas along with namespace quotas. Although you can view resources of the ClusterResourceQuota type and create resources of the ResourceQuota type in the ResourceQuotas page, you cannot create objects of the ClusterResourceQuota in this page.

The project pages on both the developer and administrator perspectives also show the cluster quotas that apply to a specific project.

References

For more information, refer to the Quotas chapter in the Red Hat OpenShift Container Platform 4.14 Building Applications documentation at https://access.redhat.com/documentation/en-us/openshift_container_platform/4.14/html-single/building_applications/index#quotas

For more information about object counts, refer to the Planning Your Environment According to Object Maximums chapter in the Red Hat OpenShift Container Platform 4.14 Scalability and Performance documentation at https://access.redhat.com/documentation/en-us/openshift_container_platform/4.14/html-single/scalability_and_performance/index#planning-your-environment-according-to-object-maximums

Requests and Limits

Resource Quotas

Revision: do280-4.14-08d11e1