Skip to content

Commit

Permalink
Add HRQ documentation
Browse files Browse the repository at this point in the history
Signed-off-by: unknown <[email protected]>
  • Loading branch information
zfrhv committed Jun 11, 2023
1 parent 61562c5 commit 6b0ac44
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 5 deletions.
71 changes: 69 additions & 2 deletions docs/user-guide/concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespaces are, and _why_ they behave the way they do.
* [Basic concepts](#basic)
* [Parents, children, trees and forests](#basic-trees)
* [Full namespaces and subnamespaces](#basic-subns)
* [Hierarchical resource quotas (HRQs)](#hrq)
* [Policy inheritance and object propagation](#basic-propagation)
* [Tree labels and non-propagated policies](#basic-labels)
* [Exceptions and propagation control](#basic-exceptions)
Expand Down Expand Up @@ -87,6 +88,8 @@ namespaces:
as isolation units for their own services. However, namespace creation is a
privileged cluster-level operation, and you typically want to control this
privilege very closely.
* You might want to give some amount of resources to a team (similar to `ResourceQuota`), and they can
distribute those resources between their subnamespaces.
* Finally, you might want to avoid having to find unique names for every
namespace in the cluster.

Expand Down Expand Up @@ -218,6 +221,70 @@ probably not a great idea.
You can create a subnamespace from the command line via `kubectl hns create child
-n parent`.

<a name="hrq">

### Hierarchical resource quotas (HRQs)

***Hierarchical resource quotas are beta in HNC v1.1***

***HRQs are not included by default, to use it install the hrq.yaml file in the [releases -> Assets](https://github.com/kubernetes-sigs/hierarchical-namespaces/releases)***

When you want to give some amount of resources to `team-a`, and want them to be able to
flexibly use resources in any of their subnamespaces, you create a `HierarchicalResourceQuota`
in namespace `team-a`. The sum of all resources from all the subnamespaces of the
members wont be over the amount of resources that is configured in
`HierarchicalResourceQuota` of namespace `team-a`. All of the reasources of `team-a` are
equally shared between the applications in their subnamespaces, which is very efficient.

In addition, you can let an org or team's admin create their own hierarchical
quotas without violating the overall HRQ for their org or team. For example,
if you start with the following structure:
```
company-a
├── organization-a
│ ├── org-a-team-1
│ ├── org-a-team-2
│ ...
├── organization-b
│ ├── org-b-team-1
│ ├── org-b-team-2
│ ...
...
```
Instead of each team asking from the `cluster-admin` to modify their `ResourceQuota`,
you can insert an additional "policy" namespace above each level to hold
the policy objects (like hierarchical quota) that the sub-admin _cannot_
change, while giving them permission to create their own quotas in the
lower level namespaces, like this:
```
company-a-policy
└── company-a
```
And put the resources HRQ in the `company-a-policy` namespace. This will restrict
whole `company-a` to the amount of resources that they are paying for. Then `company-a`
can do similar HRQ with their organizations:
```
company-a-policy (has HRQ)
└── company-a
├── org-a-policy (has HRQ)
│ └── organization-a
├── org-b-policy (has HRQ)
│ └── organization-b
...
```
Lower-level quotas cannot override more restrictive quotas from ancestor namespaces;
the most restrictive quota always wins.
This way each individual can fairly and securely distribute their resources across
their members.

To implement hierarchical quotas, HNC automatically creates `ResourceQuota` objects in each
affected namespace. This is a part of the internal implementation and shouldn't be modified or
inspected. Use the `kubectl hns hrq` command to inspect hierarchical quotas,
or look at the `HierarchicalResourceQuota` object in the ancestor
namespaces.

Note: Decimal point values cannot be specified in HRQ (you can't do `cpu: 1.5` but you can do `cpu: "1.5"` or `cpu: 1500m`). See [#292](https://github.com/kubernetes-sigs/hierarchical-namespaces/issues/292)

<a name="basic-propagation">

### Policy inheritance and object propagation
Expand Down Expand Up @@ -327,7 +394,7 @@ HNC typically propagates _all_ objects of a [specified type](how-to.md#admin-res
from ancestor namespaces to descendant namespaces. However, sometimes this is
too restrictive, and you need to create ***exceptions*** to certain policies. For example:

* A ResourceQuota was propagated to many children, but one child namespace now
* A `ResourceQuota` was propagated to many children, but one child namespace now
has higher requirements than the rest. Rather than getting rid of the quota in
the parent namespace, or raising the limit for everyone, you can stop the
quota in the parent from being propagated to that _one_ child namespace,
Expand All @@ -345,7 +412,7 @@ an object can also control how it is propagated to descendant namespaces.
If you modify an exception - for example, by removing it - this could cause
the object to be propagated to descendants from which it had previously been
excluded. This could cause you to accidentally overwrite objects that were
intended to be exceptions from higher-level policies, like the ResourceQuota
intended to be exceptions from higher-level policies, like the `ResourceQuota`
in the example above. To prevent this, if modifying an exception would cause
HNC to overwrite another object, HNC’s admission controllers will prevent you
from modifying the object, and will identify the objects that would have been
Expand Down
16 changes: 16 additions & 0 deletions docs/user-guide/how-to.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This document describes common tasks you might want to accomplish using HNC.
* [Create a subnamespace](#use-subns-create)
* [Inspect namespace hierarchies](#use-inspect)
* [Propagating policies across namespaces](#use-propagate)
* [Apply hierarchical resource quotas (HRQs)](#use-hrq)
* [Select namespaces based on their hierarchies](#use-select)
* [Delete a subnamespace](#use-subns-delete)
* [Organize full namespaces into a hierarchy](#use-full)
Expand Down Expand Up @@ -186,6 +187,21 @@ permissions. To understand why an object is not being propagated to a namespace,
use `kubectl hns describe <ns>`, where `<ns>` is either the source (ancestor) or
destination (descendant) namespace.

<a name="use-hrq"/>

### Limit Resources over parent namespaces

***Hierarchical resource quotas are beta in HNC v1.1***

***HRQs are not included by default, to use it install the hrq.yaml file in the [releases -> Assets](https://github.com/kubernetes-sigs/hierarchical-namespaces/releases)***

HNC has an object called `HierarchicalResourceQuota` which is a drop-in replacement for `ResourceQuota`
but across all the namespaces in a hierarchy. It allows you to distribute your resources between
teams, and those teams can distribute their resources between their subteams.
[Learn how it works](concepts.md#hierarchical-resource-quota) or see an [quickstart example](quickstart.md#hrq)

Note: Decimal point values cannot be specified in HRQ (you can't do `cpu: 1.5` but you can do `cpu: "1.5"` or `cpu: 1500m`). See [#292](https://github.com/kubernetes-sigs/hierarchical-namespaces/issues/292)

<a name="use-select"/>

### Select namespaces based on their hierarchies
Expand Down
79 changes: 76 additions & 3 deletions docs/user-guide/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ also to all contributors since then.
* [Basic functionality](#basic)
* [Propagating different resources](#resources)
* [Hierarchical network policy](#netpol)
* [Hierarchical resource quotas](#hrq)
* [Subnamespaces deep-dive](#subns)
* [Keeping objects out of certain namespaces](#exceptions)

Expand Down Expand Up @@ -341,7 +342,7 @@ Now we'll create a default network policy that blocks any ingress from other
namespaces:

```bash
cat << EOF | kubectl apply -f -
kubectl apply -f - << EOF
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
Expand Down Expand Up @@ -394,7 +395,7 @@ other. We do this by creating a policy that selects namespaces based on the
that is automatically added by the HNC.

```bash
cat << EOF | kubectl apply -f -
kubectl apply -f - << EOF
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
Expand Down Expand Up @@ -458,6 +459,78 @@ kubectl delete svc s2 -n service-2
kubectl delete pods s2 -n service-2
```

<a name="hrq"/>

### Hierarchical resource quotas

***Hierarchical resource quotas are beta in HNC v1.1***

***HRQs are not included by default, to use it install the hrq.yaml file in the [releases -> Assets](https://github.com/kubernetes-sigs/hierarchical-namespaces/releases)***

_Will demonstrate: Create and delete [HierarchicalResourceQuota](concepts.md#hierarchical-resource-quota)._

Let's assume you own _acme-org_ from the previous example:
```
acme-org
├── [s] team-a
└── [s] team-b
```

You can create a `HierarchicalResourceQuota` in namespace `acme-org`, and the sum of
all subnamespaces resource usage can't go over what is configured in the HRQ.

We will demonstrate how it works using services, but you could also limit `cpu`,
`memory` or any other `ResourceQuota` field.

Creating the HRQ:
```bash
kubectl apply -f - << EOF
kind: HierarchicalResourceQuota
apiVersion: hnc.x-k8s.io/v1alpha2
metadata:
name: acme-org-hrq
namespace: acme-org
spec:
hard:
services: 1
EOF
```

Lets create Service in namespace `team-a`:
```bash
kubectl create service clusterip team-a-svc --clusterip=None -n team-a
```

And when we try to create Service in namespace `team-b`:
```bash
kubectl create service clusterip team-b-svc --clusterip=None -n team-b
```
We get an error:
```
Error from server (Forbidden):
error when creating "STDIN":
admission webhood "resourcesquotasstatus.hnc.x-k8s.io" denied the request:
exceeded hierarchical quota in namespace "acme-org":
"acme-org-hrq", requested: services=1, used: services=1, limited: services=1
```

To view the HRQ usage, simply run:
```bash
kubectl hns hrq -n acme-org
```
You can also view in all namespace:
```bash
kubectl hns hrq --all-namespaces
```

And you can delete the HRQ via simply deleting the CR:
```bash
kubectl delete hrq acme-org-hrq -n acme-org
```

Note: Decimal point values cannot be specified (you can't do `cpu: 1.5` but
you can do `cpu: "1.5"` or `cpu: 1500m`). See [#292](https://github.com/kubernetes-sigs/hierarchical-namespaces/issues/292)

<a name="subns"/>

### Subnamespaces deep dive
Expand Down Expand Up @@ -672,7 +745,7 @@ Of course, the annotation can also be part of the object when you create it:

```bash
kubectl delete secret my-secret -n acme-org
cat << EOF | k create -f -
kubectl create -f - << EOF
apiVersion: v1
kind: Secret
metadata:
Expand Down
37 changes: 37 additions & 0 deletions test/e2e/quickstart_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,43 @@ spec:
RunErrorShouldContain("wget: download timed out", defTimeout, clientCmd, nsTeamB, alpineArgs, wgetArgs)
})

PIt("Create and use HierarchicalResourceQuota", func() {
// set up initial structure
CreateNamespace(nsOrg)
CreateSubnamespace(nsTeamA, nsOrg)
CreateSubnamespace(nsTeamB, nsOrg)

expected := "" + // empty string make go fmt happy
nsOrg + "\n" +
"├── [s] " + nsTeamA + "\n" +
"└── [s] " + nsTeamB
// The subnamespaces takes a bit of time to show up
RunShouldContain(expected, propogationTimeout, "kubectl hns tree", nsOrg)

// create hrq in parent acme-org
hrq:=`# quickstart_test.go: hrq in acme-org
kind: HierarchicalResourceQuota
apiVersion: hnc.x-k8s.io/v1alpha2
metadata:
name: acme-org-hrq
namespace: acme-org
spec:
hard:
services: 1`
MustApplyYAML(hrq)

// create service in team-a
MustRun("kubectl create service clusterip", nsTeamA + "-svc", "--clusterip=None", "-n", nsTeamA)

// show that you can't use resources more than the hrq
MustNotRun("kubectl create service clusterip", nsTeamB + "-svc", "--clusterip=None", "-n", nsTeamB)

// show hrq usage
RunShouldContain("services: 1/1", defTimeout, "kubectl hns hrq", "-n", nsOrg)

MustRun("kubectl delete hrq", nsOrg + "-hrq", "-n", nsOrg)
})

It("Should create and delete subnamespaces", func() {
// set up initial structure
CreateNamespace(nsOrg)
Expand Down

0 comments on commit 6b0ac44

Please sign in to comment.