apiserver.config.openshift.io
After installing OKD, you can further expand and customize your cluster to your requirements.
You complete most of the cluster configuration and customization after you deploy your OKD cluster. A number of configuration resources are available.
If you install your cluster on IBM Z®, not all features and functions are available. |
You modify the configuration resources to configure the major features of the cluster, such as the image registry, networking configuration, image build behavior, and the identity provider.
For current documentation of the settings that you control by using these resources, use
the oc explain
command, for example oc explain builds --api-version=config.openshift.io/v1
All cluster configuration resources are globally scoped (not namespaced) and named cluster
.
Resource name | Description |
---|---|
|
Provides API server configuration such as certificates and certificate authorities. |
|
Controls the identity provider and authentication configuration for the cluster. |
|
Controls default and enforced configuration for all builds on the cluster. |
|
Configures the behavior of the web console interface, including the logout behavior. |
|
Enables FeatureGates so that you can use Tech Preview features. |
|
Configures how specific image registries should be treated (allowed, disallowed, insecure, CA details). |
|
Configuration details related to routing such as the default domain for routes. |
|
Configures identity providers and other behavior related to internal OAuth server flows. |
|
Configures how projects are created including the project template. |
|
Defines proxies to be used by components needing external network access. Note: not all components currently consume this value. |
|
Configures scheduler behavior such as profiles and default node selectors. |
These configuration resources are cluster-scoped instances, named cluster
, which control the behavior of a specific component as
owned by a particular Operator.
Resource name | Description |
---|---|
|
Controls console appearance such as branding customizations |
|
Configures OpenShift image registry settings such as public routing, log levels, proxy settings, resource constraints, replica counts, and storage type. |
|
Configures the Samples Operator to control which example image streams and templates are installed on the cluster. |
These configuration resources represent a single instance of a particular component. In some cases, you can request multiple instances by creating multiple instances of the resource. In other cases, the Operator can use only a specific resource instance name in a specific namespace. Reference the component-specific documentation for details on how and when you can create additional resource instances.
Resource name | Instance name | Namespace | Description |
---|---|---|---|
|
|
|
Controls the Alertmanager deployment parameters. |
|
|
|
Configures Ingress Operator behavior such as domain, number of replicas, certificates, and controller placement. |
You use these resources to retrieve information about the cluster. Some configurations might require you to edit these resources directly.
Resource name | Instance name | Description |
---|---|---|
|
|
In OKD 4.15, you must not customize the |
|
|
You cannot modify the DNS settings for your cluster. You can view the DNS Operator status. |
|
|
Configuration details allowing the cluster to interact with its cloud provider. |
|
|
You cannot modify your cluster networking after installation. To customize your network, follow the process to customize networking during installation. |
After you deploy your OKD cluster, you can add worker nodes to scale cluster resources. There are different ways you can add worker nodes depending on the installation method and the environment of your cluster.
For installer-provisioned infrastructure clusters, you can manually or automatically scale the MachineSet
object to match the number of available bare-metal hosts.
To add a bare-metal host, you must configure all network prerequisites, configure an associated baremetalhost
object, then provision the worker node to the cluster. You can add a bare-metal host manually or by using the web console.
For user-provisioned infrastructure clusters, you can add worker nodes by using a Fedora or FCOS ISO image and connecting it to your cluster using cluster Ignition config files. For RHEL worker nodes, the following example uses Ansible playbooks to add worker nodes to the cluster. For RHCOS worker nodes, the following example uses an ISO image and network booting to add worker nodes to the cluster.
For clusters managed by the Assisted Installer, you can add worker nodes by using the Red Hat OpenShift Cluster Manager console, the Assisted Installer REST API or you can manually add worker nodes using an ISO image and cluster Ignition config files.
If you incorrectly sized the worker nodes during deployment, adjust them by creating one or more new compute machine sets, scale them up, then scale the original compute machine set down before removing them.
MachineSet
objects describe OKD nodes with respect to the cloud or machine provider.
The MachineConfigPool
object allows MachineConfigController
components to define and provide the status of machines in the context of upgrades.
The MachineConfigPool
object allows users to configure how upgrades are rolled out to the OKD nodes in the machine config pool.
The NodeSelector
object can be replaced with a reference to the MachineSet
object.
To add or remove an instance of a machine in a compute machine set, you can manually scale the compute machine set.
This guidance is relevant to fully automated, installer-provisioned infrastructure installations. Customized, user-provisioned infrastructure installations do not have compute machine sets.
Install an OKD cluster and the oc
command line.
Log in to oc
as a user with cluster-admin
permission.
View the compute machine sets that are in the cluster by running the following command:
$ oc get machinesets -n openshift-machine-api
The compute machine sets are listed in the form of <clusterid>-worker-<aws-region-az>
.
View the compute machines that are in the cluster by running the following command:
$ oc get machine -n openshift-machine-api
Set the annotation on the compute machine that you want to delete by running the following command:
$ oc annotate machine/<machine_name> -n openshift-machine-api machine.openshift.io/delete-machine="true"
Scale the compute machine set by running one of the following commands:
$ oc scale --replicas=2 machineset <machineset> -n openshift-machine-api
Or:
$ oc edit machineset <machineset> -n openshift-machine-api
You can alternatively apply the following YAML to scale the compute machine set:
|
You can scale the compute machine set up or down. It takes several minutes for the new machines to be available.
By default, the machine controller tries to drain the node that is backed by the machine until it succeeds. In some situations, such as with a misconfigured pod disruption budget, the drain operation might not be able to succeed. If the drain operation fails, the machine controller cannot proceed removing the machine. You can skip draining the node by annotating |
Verify the deletion of the intended machine by running the following command:
$ oc get machines
Random
, Newest
, and Oldest
are the three supported deletion options. The default is Random
, meaning that random machines are chosen and deleted when scaling compute machine sets down. The deletion policy can be set according to the use case by modifying the particular compute machine set:
spec:
deletePolicy: <delete_policy>
replicas: <desired_replica_count>
Specific machines can also be prioritized for deletion by adding the annotation machine.openshift.io/delete-machine=true
to the machine of interest, regardless of the deletion policy.
By default, the OKD router pods are deployed on workers. Because the router is required to access some cluster resources, including the web console, do not scale the worker compute machine set to |
Custom compute machine sets can be used for use cases requiring that services run on specific nodes and that those services are ignored by the controller when the worker compute machine sets are scaling down. This prevents service disruption. |
You can use default cluster-wide node selectors on pods together with labels on nodes to constrain all pods created in a cluster to specific nodes.
With cluster-wide node selectors, when you create a pod in that cluster, OKD adds the default node selectors to the pod and schedules the pod on nodes with matching labels.
You configure cluster-wide node selectors by editing the Scheduler Operator custom resource (CR). You add labels to a node, a compute machine set, or a machine config. Adding the label to the compute machine set ensures that if the node or machine goes down, new nodes have the label. Labels added to a node or machine config do not persist if the node or machine goes down.
You can add additional key/value pairs to a pod. But you cannot add a different value for a default key. |
To add a default cluster-wide node selector:
Edit the Scheduler Operator CR to add the default cluster-wide node selectors:
$ oc edit scheduler cluster
apiVersion: config.openshift.io/v1
kind: Scheduler
metadata:
name: cluster
...
spec:
defaultNodeSelector: type=user-node,region=east (1)
mastersSchedulable: false
1 | Add a node selector with the appropriate <key>:<value> pairs. |
After making this change, wait for the pods in the openshift-kube-apiserver
project to redeploy. This can take several minutes. The default cluster-wide node selector does not take effect until the pods redeploy.
Add labels to a node by using a compute machine set or editing the node directly:
Use a compute machine set to add labels to nodes managed by the compute machine set when a node is created:
Run the following command to add labels to a MachineSet
object:
$ oc patch MachineSet <name> --type='json' -p='[{"op":"add","path":"/spec/template/spec/metadata/labels", "value":{"<key>"="<value>","<key>"="<value>"}}]' -n openshift-machine-api (1)
1 | Add a <key>/<value> pair for each label. |
For example:
$ oc patch MachineSet ci-ln-l8nry52-f76d1-hl7m7-worker-c --type='json' -p='[{"op":"add","path":"/spec/template/spec/metadata/labels", "value":{"type":"user-node","region":"east"}}]' -n openshift-machine-api
You can alternatively apply the following YAML to add labels to a compute machine set:
|
Verify that the labels are added to the MachineSet
object by using the oc edit
command:
For example:
$ oc edit MachineSet abc612-msrtw-worker-us-east-1c -n openshift-machine-api
MachineSet
objectapiVersion: machine.openshift.io/v1beta1
kind: MachineSet
...
spec:
...
template:
metadata:
...
spec:
metadata:
labels:
region: east
type: user-node
...
Redeploy the nodes associated with that compute machine set by scaling down to 0
and scaling up the nodes:
For example:
$ oc scale --replicas=0 MachineSet ci-ln-l8nry52-f76d1-hl7m7-worker-c -n openshift-machine-api
$ oc scale --replicas=1 MachineSet ci-ln-l8nry52-f76d1-hl7m7-worker-c -n openshift-machine-api
When the nodes are ready and available, verify that the label is added to the nodes by using the oc get
command:
$ oc get nodes -l <key>=<value>
For example:
$ oc get nodes -l type=user-node
NAME STATUS ROLES AGE VERSION
ci-ln-l8nry52-f76d1-hl7m7-worker-c-vmqzp Ready worker 61s v1.28.5
Add labels directly to a node:
Edit the Node
object for the node:
$ oc label nodes <name> <key>=<value>
For example, to label a node:
$ oc label nodes ci-ln-l8nry52-f76d1-hl7m7-worker-b-tgq49 type=user-node region=east
You can alternatively apply the following YAML to add labels to a node:
|
Verify that the labels are added to the node using the oc get
command:
$ oc get nodes -l <key>=<value>,<key>=<value>
For example:
$ oc get nodes -l type=user-node,region=east
NAME STATUS ROLES AGE VERSION
ci-ln-l8nry52-f76d1-hl7m7-worker-b-tgq49 Ready worker 17m v1.28.5
If the cluster administrator has performed latency tests for platform verification, they can discover the need to adjust the operation of the cluster to ensure stability in cases of high latency. The cluster administrator need change only one parameter, recorded in a file, which controls four parameters affecting how supervisory processes read status and interpret the health of the cluster. Changing only the one parameter provides cluster tuning in an easy, supportable manner.
The Kubelet
process provides the starting point for monitoring cluster health. The Kubelet
sets status values for all nodes in the OKD cluster. The Kubernetes Controller Manager (kube controller
) reads the status values every 10 seconds, by default.
If the kube controller
cannot read a node status value, it loses contact with that node after a configured period. The default behavior is:
The node controller on the control plane updates the node health to Unhealthy
and marks the node Ready
condition`Unknown`.
In response, the scheduler stops scheduling pods to that node.
The Node Lifecycle Controller adds a node.kubernetes.io/unreachable
taint with a NoExecute
effect to the node and schedules any pods on the node for eviction after five minutes, by default.
This behavior can cause problems if your network is prone to latency issues, especially if you have nodes at the network edge. In some cases, the Kubernetes Controller Manager might not receive an update from a healthy node due to network latency. The Kubelet
evicts pods from the node even though the node is healthy.
To avoid this problem, you can use worker latency profiles to adjust the frequency that the Kubelet
and the Kubernetes Controller Manager wait for status updates before taking action. These adjustments help to ensure that your cluster runs properly if network latency between the control plane and the worker nodes is not optimal.
These worker latency profiles contain three sets of parameters that are pre-defined with carefully tuned values to control the reaction of the cluster to increased latency. No need to experimentally find the best values manually.
You can configure worker latency profiles when installing a cluster or at any time you notice increased latency in your cluster network.
Worker latency profiles are four different categories of carefully-tuned parameters. The four parameters which implement these values are node-status-update-frequency
, node-monitor-grace-period
, default-not-ready-toleration-seconds
and default-unreachable-toleration-seconds
. These parameters can use values which allow you control the reaction of the cluster to latency issues without needing to determine the best values using manual methods.
Setting these parameters manually is not supported. Incorrect parameter settings adversely affect cluster stability. |
All worker latency profiles configure the following parameters:
Specifies how often the kubelet posts node status to the API server.
Specifies the amount of time in seconds that the Kubernetes Controller Manager waits for an update from a kubelet before marking the node unhealthy and adding the node.kubernetes.io/not-ready
or node.kubernetes.io/unreachable
taint to the node.
Specifies the amount of time in seconds after marking a node unhealthy that the Kube API Server Operator waits before evicting pods from that node.
Specifies the amount of time in seconds after marking a node unreachable that the Kube API Server Operator waits before evicting pods from that node.
The following Operators monitor the changes to the worker latency profiles and respond accordingly:
The Machine Config Operator (MCO) updates the node-status-update-frequency
parameter on the worker nodes.
The Kubernetes Controller Manager updates the node-monitor-grace-period
parameter on the control plane nodes.
The Kubernetes API Server Operator updates the default-not-ready-toleration-seconds
and default-unreachable-toleration-seconds
parameters on the control plane nodes.
Although the default configuration works in most cases, OKD offers two other worker latency profiles for situations where the network is experiencing higher latency than usual. The three worker latency profiles are described in the following sections:
With the Default
profile, each Kubelet
updates it’s status every 10 seconds (node-status-update-frequency
). The Kube Controller Manager
checks the statuses of Kubelet
every 5 seconds (node-monitor-grace-period
).
The Kubernetes Controller Manager waits 40 seconds for a status update from Kubelet
before considering the Kubelet
unhealthy. If no status is made available to the Kubernetes Controller Manager, it then marks the node with the node.kubernetes.io/not-ready
or node.kubernetes.io/unreachable
taint and evicts the pods on that node.
If a pod on that node has the NoExecute
taint, the pod is run according to tolerationSeconds
. If the pod has no taint, it will be evicted in 300 seconds (default-not-ready-toleration-seconds
and default-unreachable-toleration-seconds
settings of the Kube API Server
).
Profile | Component | Parameter | Value |
---|---|---|---|
Default |
kubelet |
|
10s |
Kubelet Controller Manager |
|
40s |
|
Kubernetes API Server Operator |
|
300s |
|
Kubernetes API Server Operator |
|
300s |
Use the MediumUpdateAverageReaction
profile if the network latency is slightly higher than usual.
The MediumUpdateAverageReaction
profile reduces the frequency of kubelet updates to 20 seconds and changes the period that the Kubernetes Controller Manager waits for those updates to 2 minutes. The pod eviction period for a pod on that node is reduced to 60 seconds. If the pod has the tolerationSeconds
parameter, the eviction waits for the period specified by that parameter.
The Kubernetes Controller Manager waits for 2 minutes to consider a node unhealthy. In another minute, the eviction process starts.
Profile | Component | Parameter | Value |
---|---|---|---|
MediumUpdateAverageReaction |
kubelet |
|
20s |
Kubelet Controller Manager |
|
2m |
|
Kubernetes API Server Operator |
|
60s |
|
Kubernetes API Server Operator |
|
60s |
Use the LowUpdateSlowReaction
profile if the network latency is extremely high.
The LowUpdateSlowReaction
profile reduces the frequency of kubelet updates to 1 minute and changes the period that the Kubernetes Controller Manager waits for those updates to 5 minutes. The pod eviction period for a pod on that node is reduced to 60 seconds. If the pod has the tolerationSeconds
parameter, the eviction waits for the period specified by that parameter.
The Kubernetes Controller Manager waits for 5 minutes to consider a node unhealthy. In another minute, the eviction process starts.
Profile | Component | Parameter | Value |
---|---|---|---|
LowUpdateSlowReaction |
kubelet |
|
1m |
Kubelet Controller Manager |
|
5m |
|
Kubernetes API Server Operator |
|
60s |
|
Kubernetes API Server Operator |
|
60s |
To change a worker latency profile to deal with network latency, edit the node.config
object to add the name of the profile. You can change the profile at any time as latency increases or decreases.
You must move one worker latency profile at a time. For example, you cannot move directly from the Default
profile to the LowUpdateSlowReaction
worker latency profile. You must move from the Default
worker latency profile to the MediumUpdateAverageReaction
profile first, then to LowUpdateSlowReaction
. Similarly, when returning to the Default
profile, you must move from the low profile to the medium profile first, then to Default
.
You can also configure worker latency profiles upon installing an OKD cluster. |
To move from the default worker latency profile:
Move to the medium worker latency profile:
Edit the node.config
object:
$ oc edit nodes.config/cluster
Add spec.workerLatencyProfile: MediumUpdateAverageReaction
:
node.config
objectapiVersion: config.openshift.io/v1
kind: Node
metadata:
annotations:
include.release.openshift.io/ibm-cloud-managed: "true"
include.release.openshift.io/self-managed-high-availability: "true"
include.release.openshift.io/single-node-developer: "true"
release.openshift.io/create-only: "true"
creationTimestamp: "2022-07-08T16:02:51Z"
generation: 1
name: cluster
ownerReferences:
- apiVersion: config.openshift.io/v1
kind: ClusterVersion
name: version
uid: 36282574-bf9f-409e-a6cd-3032939293eb
resourceVersion: "1865"
uid: 0c0f7a4c-4307-4187-b591-6155695ac85b
spec:
workerLatencyProfile: MediumUpdateAverageReaction (1)
# ...
1 | Specifies the medium worker latency policy. |
Scheduling on each worker node is disabled as the change is being applied.
Optional: Move to the low worker latency profile:
Edit the node.config
object:
$ oc edit nodes.config/cluster
Change the spec.workerLatencyProfile
value to LowUpdateSlowReaction
:
node.config
objectapiVersion: config.openshift.io/v1
kind: Node
metadata:
annotations:
include.release.openshift.io/ibm-cloud-managed: "true"
include.release.openshift.io/self-managed-high-availability: "true"
include.release.openshift.io/single-node-developer: "true"
release.openshift.io/create-only: "true"
creationTimestamp: "2022-07-08T16:02:51Z"
generation: 1
name: cluster
ownerReferences:
- apiVersion: config.openshift.io/v1
kind: ClusterVersion
name: version
uid: 36282574-bf9f-409e-a6cd-3032939293eb
resourceVersion: "1865"
uid: 0c0f7a4c-4307-4187-b591-6155695ac85b
spec:
workerLatencyProfile: LowUpdateSlowReaction (1)
# ...
1 | Specifies use of the low worker latency policy. |
Scheduling on each worker node is disabled as the change is being applied.
When all nodes return to the Ready
condition, you can use the following command to look in the Kubernetes Controller Manager to ensure it was applied:
$ oc get KubeControllerManager -o yaml | grep -i workerlatency -A 5 -B 5
# ...
- lastTransitionTime: "2022-07-11T19:47:10Z"
reason: ProfileUpdated
status: "False"
type: WorkerLatencyProfileProgressing
- lastTransitionTime: "2022-07-11T19:47:10Z" (1)
message: all static pod revision(s) have updated latency profile
reason: ProfileUpdated
status: "True"
type: WorkerLatencyProfileComplete
- lastTransitionTime: "2022-07-11T19:20:11Z"
reason: AsExpected
status: "False"
type: WorkerLatencyProfileDegraded
- lastTransitionTime: "2022-07-11T19:20:36Z"
status: "False"
# ...
1 | Specifies that the profile is applied and active. |
To change the medium profile to default or change the default to medium, edit the node.config
object and set the spec.workerLatencyProfile
parameter to the appropriate value.
Control plane machine sets provide management capabilities for control plane machines that are similar to what compute machine sets provide for compute machines. The availability and initial status of control plane machine sets on your cluster depend on your cloud provider and the version of OKD that you installed. For more information, see Getting started with control plane machine sets.
You can create a compute machine set to create machines that host only infrastructure components, such as the default router, the integrated container image registry, and components for cluster metrics and monitoring. These infrastructure machines are not counted toward the total number of subscriptions that are required to run the environment.
In a production deployment, it is recommended that you deploy at least three compute machine sets to hold infrastructure components. Both OpenShift Logging and Red Hat OpenShift Service Mesh deploy Elasticsearch, which requires three instances to be installed on different nodes. Each of these nodes can be deployed to different availability zones for high availability. A configuration like this requires three different compute machine sets, one for each availability zone. In global Azure regions that do not have multiple availability zones, you can use availability sets to ensure high availability.
For information on infrastructure nodes and which components can run on infrastructure nodes, see Creating infrastructure machine sets.
To create an infrastructure node, you can use a machine set, assign a label to the nodes, or use a machine config pool.
For sample machine sets that you can use with these procedures, see Creating machine sets for different clouds.
Applying a specific node selector to all infrastructure components causes OKD to schedule those workloads on nodes with that label.
In addition to the compute machine sets created by the installation program, you can create your own to dynamically manage the machine compute resources for specific workloads of your choice.
Deploy an OKD cluster.
Install the OpenShift CLI (oc
).
Log in to oc
as a user with cluster-admin
permission.
Create a new YAML file that contains the compute machine set custom resource (CR) sample and is named <file_name>.yaml
.
Ensure that you set the <clusterID>
and <role>
parameter values.
Optional: If you are not sure which value to set for a specific field, you can check an existing compute machine set from your cluster.
To list the compute machine sets in your cluster, run the following command:
$ oc get machinesets -n openshift-machine-api
NAME DESIRED CURRENT READY AVAILABLE AGE
agl030519-vplxk-worker-us-east-1a 1 1 1 1 55m
agl030519-vplxk-worker-us-east-1b 1 1 1 1 55m
agl030519-vplxk-worker-us-east-1c 1 1 1 1 55m
agl030519-vplxk-worker-us-east-1d 0 0 55m
agl030519-vplxk-worker-us-east-1e 0 0 55m
agl030519-vplxk-worker-us-east-1f 0 0 55m
To view values of a specific compute machine set custom resource (CR), run the following command:
$ oc get machineset <machineset_name> \
-n openshift-machine-api -o yaml
apiVersion: machine.openshift.io/v1beta1
kind: MachineSet
metadata:
labels:
machine.openshift.io/cluster-api-cluster: <infrastructure_id> (1)
name: <infrastructure_id>-<role> (2)
namespace: openshift-machine-api
spec:
replicas: 1
selector:
matchLabels:
machine.openshift.io/cluster-api-cluster: <infrastructure_id>
machine.openshift.io/cluster-api-machineset: <infrastructure_id>-<role>
template:
metadata:
labels:
machine.openshift.io/cluster-api-cluster: <infrastructure_id>
machine.openshift.io/cluster-api-machine-role: <role>
machine.openshift.io/cluster-api-machine-type: <role>
machine.openshift.io/cluster-api-machineset: <infrastructure_id>-<role>
spec:
providerSpec: (3)
...
1 | The cluster infrastructure ID. | ||
2 | A default node label.
|
||
3 | The values in the <providerSpec> section of the compute machine set CR are platform-specific. For more information about <providerSpec> parameters in the CR, see the sample compute machine set CR configuration for your provider. |
Create a MachineSet
CR by running the following command:
$ oc create -f <file_name>.yaml
View the list of compute machine sets by running the following command:
$ oc get machineset -n openshift-machine-api
NAME DESIRED CURRENT READY AVAILABLE AGE
agl030519-vplxk-infra-us-east-1a 1 1 1 1 11m
agl030519-vplxk-worker-us-east-1a 1 1 1 1 55m
agl030519-vplxk-worker-us-east-1b 1 1 1 1 55m
agl030519-vplxk-worker-us-east-1c 1 1 1 1 55m
agl030519-vplxk-worker-us-east-1d 0 0 55m
agl030519-vplxk-worker-us-east-1e 0 0 55m
agl030519-vplxk-worker-us-east-1f 0 0 55m
When the new compute machine set is available, the DESIRED
and CURRENT
values match. If the compute machine set is not available, wait a few minutes and run the command again.
See Creating infrastructure machine sets for installer-provisioned infrastructure environments or for any cluster where the control plane nodes are managed by the machine API. |
Requirements of the cluster dictate that infrastructure, also called infra
nodes, be provisioned. The installer only provides provisions for control plane and worker nodes. Worker nodes can be designated as infrastructure nodes or application, also called app
, nodes through labeling.
Add a label to the worker node that you want to act as application node:
$ oc label node <node-name> node-role.kubernetes.io/app=""
Add a label to the worker nodes that you want to act as infrastructure nodes:
$ oc label node <node-name> node-role.kubernetes.io/infra=""
Check to see if applicable nodes now have the infra
role and app
roles:
$ oc get nodes
Create a default cluster-wide node selector. The default node selector is applied to pods created in all namespaces. This creates an intersection with any existing node selectors on a pod, which additionally constrains the pod’s selector.
If the default node selector key conflicts with the key of a pod’s label, then the default node selector is not applied. However, do not set a default node selector that might cause a pod to become unschedulable. For example, setting the default node selector to a specific node role, such as You can alternatively use a project node selector to avoid cluster-wide node selector key conflicts. |
Edit the Scheduler
object:
$ oc edit scheduler cluster
Add the defaultNodeSelector
field with the appropriate node selector:
apiVersion: config.openshift.io/v1
kind: Scheduler
metadata:
name: cluster
spec:
defaultNodeSelector: node-role.kubernetes.io/infra="" (1)
# ...
1 | This example node selector deploys pods on infrastructure nodes by default. |
Save the file to apply the changes.
You can now move infrastructure resources to the newly labeled infra
nodes.
For information on how to configure project node selectors to avoid cluster-wide node selector key conflicts, see Project node selectors.
If you need infrastructure machines to have dedicated configurations, you must create an infra pool.
Creating a custom machine configuration pool overrides default worker pool configurations if they refer to the same file or unit. |
Add a label to the node you want to assign as the infra node with a specific label:
$ oc label node <node_name> <label>
$ oc label node ci-ln-n8mqwr2-f76d1-xscn2-worker-c-6fmtx node-role.kubernetes.io/infra=
Create a machine config pool that contains both the worker role and your custom role as machine config selector:
$ cat infra.mcp.yaml
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfigPool
metadata:
name: infra
spec:
machineConfigSelector:
matchExpressions:
- {key: machineconfiguration.openshift.io/role, operator: In, values: [worker,infra]} (1)
nodeSelector:
matchLabels:
node-role.kubernetes.io/infra: "" (2)
1 | Add the worker role and your custom role. |
2 | Add the label you added to the node as a nodeSelector . |
Custom machine config pools inherit machine configs from the worker pool. Custom pools use any machine config targeted for the worker pool, but add the ability to also deploy changes that are targeted at only the custom pool. Because a custom pool inherits resources from the worker pool, any change to the worker pool also affects the custom pool. |
After you have the YAML file, you can create the machine config pool:
$ oc create -f infra.mcp.yaml
Check the machine configs to ensure that the infrastructure configuration rendered successfully:
$ oc get machineconfig
NAME GENERATEDBYCONTROLLER IGNITIONVERSION CREATED
00-master 365c1cfd14de5b0e3b85e0fc815b0060f36ab955 3.2.0 31d
00-worker 365c1cfd14de5b0e3b85e0fc815b0060f36ab955 3.2.0 31d
01-master-container-runtime 365c1cfd14de5b0e3b85e0fc815b0060f36ab955 3.2.0 31d
01-master-kubelet 365c1cfd14de5b0e3b85e0fc815b0060f36ab955 3.2.0 31d
01-worker-container-runtime 365c1cfd14de5b0e3b85e0fc815b0060f36ab955 3.2.0 31d
01-worker-kubelet 365c1cfd14de5b0e3b85e0fc815b0060f36ab955 3.2.0 31d
99-master-1ae2a1e0-a115-11e9-8f14-005056899d54-registries 365c1cfd14de5b0e3b85e0fc815b0060f36ab955 3.2.0 31d
99-master-ssh 3.2.0 31d
99-worker-1ae64748-a115-11e9-8f14-005056899d54-registries 365c1cfd14de5b0e3b85e0fc815b0060f36ab955 3.2.0 31d
99-worker-ssh 3.2.0 31d
rendered-infra-4e48906dca84ee702959c71a53ee80e7 365c1cfd14de5b0e3b85e0fc815b0060f36ab955 3.2.0 23m
rendered-master-072d4b2da7f88162636902b074e9e28e 5b6fb8349a29735e48446d435962dec4547d3090 3.2.0 31d
rendered-master-3e88ec72aed3886dec061df60d16d1af 02c07496ba0417b3e12b78fb32baf6293d314f79 3.2.0 31d
rendered-master-419bee7de96134963a15fdf9dd473b25 365c1cfd14de5b0e3b85e0fc815b0060f36ab955 3.2.0 17d
rendered-master-53f5c91c7661708adce18739cc0f40fb 365c1cfd14de5b0e3b85e0fc815b0060f36ab955 3.2.0 13d
rendered-master-a6a357ec18e5bce7f5ac426fc7c5ffcd 365c1cfd14de5b0e3b85e0fc815b0060f36ab955 3.2.0 7d3h
rendered-master-dc7f874ec77fc4b969674204332da037 5b6fb8349a29735e48446d435962dec4547d3090 3.2.0 31d
rendered-worker-1a75960c52ad18ff5dfa6674eb7e533d 5b6fb8349a29735e48446d435962dec4547d3090 3.2.0 31d
rendered-worker-2640531be11ba43c61d72e82dc634ce6 5b6fb8349a29735e48446d435962dec4547d3090 3.2.0 31d
rendered-worker-4e48906dca84ee702959c71a53ee80e7 365c1cfd14de5b0e3b85e0fc815b0060f36ab955 3.2.0 7d3h
rendered-worker-4f110718fe88e5f349987854a1147755 365c1cfd14de5b0e3b85e0fc815b0060f36ab955 3.2.0 17d
rendered-worker-afc758e194d6188677eb837842d3b379 02c07496ba0417b3e12b78fb32baf6293d314f79 3.2.0 31d
rendered-worker-daa08cc1e8f5fcdeba24de60cd955cc3 365c1cfd14de5b0e3b85e0fc815b0060f36ab955 3.2.0 13d
You should see a new machine config, with the rendered-infra-*
prefix.
Optional: To deploy changes to a custom pool, create a machine config that uses the custom pool name as the label, such as infra
. Note that this is not required and only shown for instructional purposes. In this manner, you can apply any custom configurations specific to only your infra nodes.
After you create the new machine config pool, the MCO generates a new rendered config for that pool, and associated nodes of that pool reboot to apply the new configuration. |
Create a machine config:
$ cat infra.mc.yaml
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
metadata:
name: 51-infra
labels:
machineconfiguration.openshift.io/role: infra (1)
spec:
config:
ignition:
version: 3.2.0
storage:
files:
- path: /etc/infratest
mode: 0644
contents:
source: data:,infra
1 | Add the label you added to the node as a nodeSelector . |
Apply the machine config to the infra-labeled nodes:
$ oc create -f infra.mc.yaml
Confirm that your new machine config pool is available:
$ oc get mcp
NAME CONFIG UPDATED UPDATING DEGRADED MACHINECOUNT READYMACHINECOUNT UPDATEDMACHINECOUNT DEGRADEDMACHINECOUNT AGE
infra rendered-infra-60e35c2e99f42d976e084fa94da4d0fc True False False 1 1 1 0 4m20s
master rendered-master-9360fdb895d4c131c7c4bebbae099c90 True False False 3 3 3 0 91m
worker rendered-worker-60e35c2e99f42d976e084fa94da4d0fc True False False 2 2 2 0 91m
In this example, a worker node was changed to an infra node.
See Node configuration management with machine config pools for more information on grouping infra machines in a custom pool.
After creating an infrastructure machine set, the worker
and infra
roles are applied to new infra nodes. Nodes with the infra
role are not counted toward the total number of subscriptions that are required to run the environment, even when the worker
role is also applied.
However, when an infra node is assigned the worker role, there is a chance that user workloads can get assigned inadvertently to the infra node. To avoid this, you can apply a taint to the infra node and tolerations for the pods that you want to control.
If you have an infra node that has the infra
and worker
roles assigned, you must configure the node so that user workloads are not assigned to it.
It is recommended that you preserve the dual |
Configure additional MachineSet
objects in your OKD cluster.
Add a taint to the infra node to prevent scheduling user workloads on it:
Determine if the node has the taint:
$ oc describe nodes <node_name>
oc describe node ci-ln-iyhx092-f76d1-nvdfm-worker-b-wln2l
Name: ci-ln-iyhx092-f76d1-nvdfm-worker-b-wln2l
Roles: worker
...
Taints: node-role.kubernetes.io/infra:NoSchedule
...
This example shows that the node has a taint. You can proceed with adding a toleration to your pod in the next step.
If you have not configured a taint to prevent scheduling user workloads on it:
$ oc adm taint nodes <node_name> <key>=<value>:<effect>
For example:
$ oc adm taint nodes node1 node-role.kubernetes.io/infra=reserved:NoSchedule
You can alternatively apply the following YAML to add the taint:
|
This example places a taint on node1
that has key node-role.kubernetes.io/infra
and taint effect NoSchedule
. Nodes with the NoSchedule
effect schedule only pods that tolerate the taint, but allow existing pods to remain scheduled on the node.
If a descheduler is used, pods violating node taints could be evicted from the cluster. |
Add the taint with NoExecute Effect along with the above taint with NoSchedule Effect:
$ oc adm taint nodes <node_name> <key>=<value>:<effect>
For example:
$ oc adm taint nodes node1 node-role.kubernetes.io/infra=reserved:NoExecute
You can alternatively apply the following YAML to add the taint:
|
This example places a taint on node1
that has the key node-role.kubernetes.io/infra
and taint effect NoExecute
. Nodes with the NoExecute
effect schedule only pods that tolerate the taint. The effect will remove any existing pods from the node that do not have a matching toleration.
Add tolerations for the pod configurations you want to schedule on the infra node, like router, registry, and monitoring workloads. Add the following code to the Pod
object specification:
tolerations:
- effect: NoSchedule (1)
key: node-role.kubernetes.io/infra (2)
value: reserved (3)
- effect: NoExecute (4)
key: node-role.kubernetes.io/infra (5)
operator: Exists (6)
value: reserved (7)
1 | Specify the effect that you added to the node. |
2 | Specify the key that you added to the node. |
3 | Specify the value of the key-value pair taint that you added to the node. |
4 | Specify the effect that you added to the node. |
5 | Specify the key that you added to the node. |
6 | Specify the Exists Operator to require a taint with the key node-role.kubernetes.io/infra to be present on the node. |
7 | Specify the value of the key-value pair taint that you added to the node. |
This toleration matches the taint created by the oc adm taint
command. A pod with this toleration can be scheduled onto the infra node.
Moving pods for an Operator installed via OLM to an infra node is not always possible. The capability to move Operator pods depends on the configuration of each Operator. |
Schedule the pod to the infra node using a scheduler. See the documentation for Controlling pod placement onto nodes for details.
See Controlling pod placement using the scheduler for general information on scheduling a pod to a node.
Some of the infrastructure resources are deployed in your cluster by default. You can move them to the infrastructure machine sets that you created.
You can deploy the router pod to a different compute machine set. By default, the pod is deployed to a worker node.
Configure additional compute machine sets in your OKD cluster.
View the IngressController
custom resource for the router Operator:
$ oc get ingresscontroller default -n openshift-ingress-operator -o yaml
The command output resembles the following text:
apiVersion: operator.openshift.io/v1
kind: IngressController
metadata:
creationTimestamp: 2019-04-18T12:35:39Z
finalizers:
- ingresscontroller.operator.openshift.io/finalizer-ingresscontroller
generation: 1
name: default
namespace: openshift-ingress-operator
resourceVersion: "11341"
selfLink: /apis/operator.openshift.io/v1/namespaces/openshift-ingress-operator/ingresscontrollers/default
uid: 79509e05-61d6-11e9-bc55-02ce4781844a
spec: {}
status:
availableReplicas: 2
conditions:
- lastTransitionTime: 2019-04-18T12:36:15Z
status: "True"
type: Available
domain: apps.<cluster>.example.com
endpointPublishingStrategy:
type: LoadBalancerService
selector: ingresscontroller.operator.openshift.io/deployment-ingresscontroller=default
Edit the ingresscontroller
resource and change the nodeSelector
to use the infra
label:
$ oc edit ingresscontroller default -n openshift-ingress-operator
spec:
nodePlacement:
nodeSelector: (1)
matchLabels:
node-role.kubernetes.io/infra: ""
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/infra
value: reserved
- effect: NoExecute
key: node-role.kubernetes.io/infra
value: reserved
1 | Add a nodeSelector parameter with the appropriate value to the component you want to move. You can use a nodeSelector in the format shown or use <key>: <value> pairs, based on the value specified for the node. If you added a taint to the infrastructure node, also add a matching toleration. |
Confirm that the router pod is running on the infra
node.
View the list of router pods and note the node name of the running pod:
$ oc get pod -n openshift-ingress -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
router-default-86798b4b5d-bdlvd 1/1 Running 0 28s 10.130.2.4 ip-10-0-217-226.ec2.internal <none> <none>
router-default-955d875f4-255g8 0/1 Terminating 0 19h 10.129.2.4 ip-10-0-148-172.ec2.internal <none> <none>
In this example, the running pod is on the ip-10-0-217-226.ec2.internal
node.
View the node status of the running pod:
$ oc get node <node_name> (1)
1 | Specify the <node_name> that you obtained from the pod list. |
NAME STATUS ROLES AGE VERSION
ip-10-0-217-226.ec2.internal Ready infra,worker 17h v1.28.5
Because the role list includes infra
, the pod is running on the correct node.
You configure the registry Operator to deploy its pods to different nodes.
Configure additional compute machine sets in your OKD cluster.
View the config/instance
object:
$ oc get configs.imageregistry.operator.openshift.io/cluster -o yaml
apiVersion: imageregistry.operator.openshift.io/v1
kind: Config
metadata:
creationTimestamp: 2019-02-05T13:52:05Z
finalizers:
- imageregistry.operator.openshift.io/finalizer
generation: 1
name: cluster
resourceVersion: "56174"
selfLink: /apis/imageregistry.operator.openshift.io/v1/configs/cluster
uid: 36fd3724-294d-11e9-a524-12ffeee2931b
spec:
httpSecret: d9a012ccd117b1e6616ceccb2c3bb66a5fed1b5e481623
logging: 2
managementState: Managed
proxy: {}
replicas: 1
requests:
read: {}
write: {}
storage:
s3:
bucket: image-registry-us-east-1-c92e88cad85b48ec8b312344dff03c82-392c
region: us-east-1
status:
...
Edit the config/instance
object:
$ oc edit configs.imageregistry.operator.openshift.io/cluster
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
namespaces:
- openshift-image-registry
topologyKey: kubernetes.io/hostname
weight: 100
logLevel: Normal
managementState: Managed
nodeSelector: (1)
node-role.kubernetes.io/infra: ""
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/infra
value: reserved
- effect: NoExecute
key: node-role.kubernetes.io/infra
value: reserved
1 | Add a nodeSelector parameter with the appropriate value to the component you want to move. You can use a nodeSelector in the format shown or use <key>: <value> pairs, based on the value specified for the node. If you added a taint to the infrasructure node, also add a matching toleration. |
Verify the registry pod has been moved to the infrastructure node.
Run the following command to identify the node where the registry pod is located:
$ oc get pods -o wide -n openshift-image-registry
Confirm the node has the label you specified:
$ oc describe node <node_name>
Review the command output and confirm that node-role.kubernetes.io/infra
is in the LABELS
list.
The monitoring stack includes multiple components, including Prometheus, Thanos Querier, and Alertmanager. The Cluster Monitoring Operator manages this stack. To redeploy the monitoring stack to infrastructure nodes, you can create and apply a custom config map.
Edit the cluster-monitoring-config
config map and change the nodeSelector
to use the infra
label:
$ oc edit configmap cluster-monitoring-config -n openshift-monitoring
apiVersion: v1
kind: ConfigMap
metadata:
name: cluster-monitoring-config
namespace: openshift-monitoring
data:
config.yaml: |+
alertmanagerMain:
nodeSelector: (1)
node-role.kubernetes.io/infra: ""
tolerations:
- key: node-role.kubernetes.io/infra
value: reserved
effect: NoSchedule
- key: node-role.kubernetes.io/infra
value: reserved
effect: NoExecute
prometheusK8s:
nodeSelector:
node-role.kubernetes.io/infra: ""
tolerations:
- key: node-role.kubernetes.io/infra
value: reserved
effect: NoSchedule
- key: node-role.kubernetes.io/infra
value: reserved
effect: NoExecute
prometheusOperator:
nodeSelector:
node-role.kubernetes.io/infra: ""
tolerations:
- key: node-role.kubernetes.io/infra
value: reserved
effect: NoSchedule
- key: node-role.kubernetes.io/infra
value: reserved
effect: NoExecute
k8sPrometheusAdapter:
nodeSelector:
node-role.kubernetes.io/infra: ""
tolerations:
- key: node-role.kubernetes.io/infra
value: reserved
effect: NoSchedule
- key: node-role.kubernetes.io/infra
value: reserved
effect: NoExecute
kubeStateMetrics:
nodeSelector:
node-role.kubernetes.io/infra: ""
tolerations:
- key: node-role.kubernetes.io/infra
value: reserved
effect: NoSchedule
- key: node-role.kubernetes.io/infra
value: reserved
effect: NoExecute
telemeterClient:
nodeSelector:
node-role.kubernetes.io/infra: ""
tolerations:
- key: node-role.kubernetes.io/infra
value: reserved
effect: NoSchedule
- key: node-role.kubernetes.io/infra
value: reserved
effect: NoExecute
openshiftStateMetrics:
nodeSelector:
node-role.kubernetes.io/infra: ""
tolerations:
- key: node-role.kubernetes.io/infra
value: reserved
effect: NoSchedule
- key: node-role.kubernetes.io/infra
value: reserved
effect: NoExecute
thanosQuerier:
nodeSelector:
node-role.kubernetes.io/infra: ""
tolerations:
- key: node-role.kubernetes.io/infra
value: reserved
effect: NoSchedule
- key: node-role.kubernetes.io/infra
value: reserved
effect: NoExecute
monitoringPlugin:
nodeSelector:
node-role.kubernetes.io/infra: ""
tolerations:
- key: node-role.kubernetes.io/infra
value: reserved
effect: NoSchedule
- key: node-role.kubernetes.io/infra
value: reserved
effect: NoExecute
1 | Add a nodeSelector parameter with the appropriate value to the component you want to move. You can use a nodeSelector in the format shown or use <key>: <value> pairs, based on the value specified for the node. If you added a taint to the infrastructure node, also add a matching toleration. |
Watch the monitoring pods move to the new machines:
$ watch 'oc get pod -n openshift-monitoring -o wide'
If a component has not moved to the infra
node, delete the pod with this component:
$ oc delete pod -n openshift-monitoring <pod>
The component from the deleted pod is re-created on the infra
node.
The cluster autoscaler adjusts the size of an OKD cluster to meet its current deployment needs. It uses declarative, Kubernetes-style arguments to provide infrastructure management that does not rely on objects of a specific cloud provider. The cluster autoscaler has a cluster scope, and is not associated with a particular namespace.
The cluster autoscaler increases the size of the cluster when there are pods that fail to schedule on any of the current worker nodes due to insufficient resources or when another node is necessary to meet deployment needs. The cluster autoscaler does not increase the cluster resources beyond the limits that you specify.
The cluster autoscaler computes the total memory, CPU, and GPU on all nodes the cluster, even though it does not manage the control plane nodes. These values are not single-machine oriented. They are an aggregation of all the resources in the entire cluster. For example, if you set the maximum memory resource limit, the cluster autoscaler includes all the nodes in the cluster when calculating the current memory usage. That calculation is then used to determine if the cluster autoscaler has the capacity to add more worker resources.
Ensure that the |
Every 10 seconds, the cluster autoscaler checks which nodes are unnecessary in the cluster and removes them. The cluster autoscaler considers a node for removal if the following conditions apply:
The node utilization is less than the node utilization level threshold for the cluster. The node utilization level is the sum of the requested resources divided by the allocated resources for the node. If you do not specify a value in the ClusterAutoscaler
custom resource, the cluster autoscaler uses a default value of 0.5
, which corresponds to 50% utilization.
The cluster autoscaler can move all pods running on the node to the other nodes. The Kubernetes scheduler is responsible for scheduling pods on the nodes.
The cluster autoscaler does not have scale down disabled annotation.
If the following types of pods are present on a node, the cluster autoscaler will not remove the node:
Pods with restrictive pod disruption budgets (PDBs).
Kube-system pods that do not run on the node by default.
Kube-system pods that do not have a PDB or have a PDB that is too restrictive.
Pods that are not backed by a controller object such as a deployment, replica set, or stateful set.
Pods with local storage.
Pods that cannot be moved elsewhere because of a lack of resources, incompatible node selectors or affinity, matching anti-affinity, and so on.
Unless they also have a "cluster-autoscaler.kubernetes.io/safe-to-evict": "true"
annotation, pods that have a "cluster-autoscaler.kubernetes.io/safe-to-evict": "false"
annotation.
For example, you set the maximum CPU limit to 64 cores and configure the cluster autoscaler to only create machines that have 8 cores each. If your cluster starts with 30 cores, the cluster autoscaler can add up to 4 more nodes with 32 cores, for a total of 62.
If you configure the cluster autoscaler, additional usage restrictions apply:
Do not modify the nodes that are in autoscaled node groups directly. All nodes within the same node group have the same capacity and labels and run the same system pods.
Specify requests for your pods.
If you have to prevent pods from being deleted too quickly, configure appropriate PDBs.
Confirm that your cloud provider quota is large enough to support the maximum node pools that you configure.
Do not run additional node group autoscalers, especially the ones offered by your cloud provider.
The horizontal pod autoscaler (HPA) and the cluster autoscaler modify cluster resources in different ways. The HPA changes the deployment’s or replica set’s number of replicas based on the current CPU load. If the load increases, the HPA creates new replicas, regardless of the amount of resources available to the cluster. If there are not enough resources, the cluster autoscaler adds resources so that the HPA-created pods can run. If the load decreases, the HPA stops some replicas. If this action causes some nodes to be underutilized or completely empty, the cluster autoscaler deletes the unnecessary nodes.
The cluster autoscaler takes pod priorities into account. The Pod Priority and Preemption feature enables scheduling pods based on priorities if the cluster does not have enough resources, but the cluster autoscaler ensures that the cluster has resources to run all pods. To honor the intention of both features, the cluster autoscaler includes a priority cutoff function. You can use this cutoff to schedule "best-effort" pods, which do not cause the cluster autoscaler to increase resources but instead run only when spare resources are available.
Pods with priority lower than the cutoff value do not cause the cluster to scale up or prevent the cluster from scaling down. No new nodes are added to run the pods, and nodes running these pods might be deleted to free resources.
Cluster autoscaling is supported for the platforms that have machine API available on it.
This ClusterAutoscaler
resource definition shows the parameters and sample values for the cluster autoscaler.
apiVersion: "autoscaling.openshift.io/v1"
kind: "ClusterAutoscaler"
metadata:
name: "default"
spec:
podPriorityThreshold: -10 (1)
resourceLimits:
maxNodesTotal: 24 (2)
cores:
min: 8 (3)
max: 128 (4)
memory:
min: 4 (5)
max: 256 (6)
gpus:
- type: nvidia.com/gpu (7)
min: 0 (8)
max: 16 (9)
- type: amd.com/gpu
min: 0
max: 4
logVerbosity: 4 (10)
scaleDown: (11)
enabled: true (12)
delayAfterAdd: 10m (13)
delayAfterDelete: 5m (14)
delayAfterFailure: 30s (15)
unneededTime: 5m (16)
utilizationThreshold: "0.4" (17)
1 | Specify the priority that a pod must exceed to cause the cluster autoscaler to deploy additional nodes. Enter a 32-bit integer value. The podPriorityThreshold value is compared to the value of the PriorityClass that you assign to each pod. |
2 | Specify the maximum number of nodes to deploy. This value is the total number of machines that are deployed in your cluster, not just the ones that the autoscaler controls. Ensure that this value is large enough to account for all of your control plane and compute machines and the total number of replicas that you specify in your MachineAutoscaler resources. |
3 | Specify the minimum number of cores to deploy in the cluster. |
4 | Specify the maximum number of cores to deploy in the cluster. |
5 | Specify the minimum amount of memory, in GiB, in the cluster. |
6 | Specify the maximum amount of memory, in GiB, in the cluster. |
7 | Optional: Specify the type of GPU node to deploy. Only nvidia.com/gpu and amd.com/gpu are valid types. |
8 | Specify the minimum number of GPUs to deploy in the cluster. |
9 | Specify the maximum number of GPUs to deploy in the cluster. |
10 | Specify the logging verbosity level between 0 and 10 . The following log level thresholds are provided for guidance:
If you do not specify a value, the default value of |
11 | In this section, you can specify the period to wait for each action by using any valid ParseDuration interval, including ns , us , ms , s , m , and h . |
12 | Specify whether the cluster autoscaler can remove unnecessary nodes. |
13 | Optional: Specify the period to wait before deleting a node after a node has recently been added. If you do not specify a value, the default value of 10m is used. |
14 | Optional: Specify the period to wait before deleting a node after a node has recently been deleted. If you do not specify a value, the default value of 0s is used. |
15 | Optional: Specify the period to wait before deleting a node after a scale down failure occurred. If you do not specify a value, the default value of 3m is used. |
16 | Optional: Specify a period of time before an unnecessary node is eligible for deletion. If you do not specify a value, the default value of 10m is used. |
17 | Optional: Specify the node utilization level. Nodes below this utilization level are eligible for deletion.
The node utilization level is the sum of the requested resources divided by the allocated resources for the node, and must be a value greater than |
When performing a scaling operation, the cluster autoscaler remains within the ranges set in the The minimum and maximum CPUs, memory, and GPU values are determined by calculating those resources on all nodes in the cluster, even if the cluster autoscaler does not manage the nodes. For example, the control plane nodes are considered in the total memory in the cluster, even though the cluster autoscaler does not manage the control plane nodes. |
To deploy a cluster autoscaler, you create an instance of the ClusterAutoscaler
resource.
Create a YAML file for a ClusterAutoscaler
resource that contains the custom resource definition.
Create the custom resource in the cluster by running the following command:
$ oc create -f <filename>.yaml (1)
1 | <filename> is the name of the custom resource file. |
The machine autoscaler adjusts the number of Machines in the compute machine sets that you deploy in an OKD cluster. You can scale both the default worker
compute machine set and any other compute machine sets that you create. The machine autoscaler makes more Machines when the cluster runs out of resources to support more deployments. Any changes to the values in MachineAutoscaler
resources, such as the minimum or maximum number of instances, are immediately applied to the compute machine set they target.
You must deploy a machine autoscaler for the cluster autoscaler to scale your machines. The cluster autoscaler uses the annotations on compute machine sets that the machine autoscaler sets to determine the resources that it can scale. If you define a cluster autoscaler without also defining machine autoscalers, the cluster autoscaler will never scale your cluster. |
This MachineAutoscaler
resource definition shows the parameters and sample values for the machine autoscaler.
apiVersion: "autoscaling.openshift.io/v1beta1"
kind: "MachineAutoscaler"
metadata:
name: "worker-us-east-1a" (1)
namespace: "openshift-machine-api"
spec:
minReplicas: 1 (2)
maxReplicas: 12 (3)
scaleTargetRef: (4)
apiVersion: machine.openshift.io/v1beta1
kind: MachineSet (5)
name: worker-us-east-1a (6)
1 | Specify the machine autoscaler name. To make it easier to identify which compute machine set this machine autoscaler scales, specify or include the name of the compute machine set to scale. The compute machine set name takes the following form: <clusterid>-<machineset>-<region> . |
||
2 | Specify the minimum number machines of the specified type that must remain in the specified zone after the cluster autoscaler initiates cluster scaling. If running in AWS, GCP, Azure, OpenStack, or vSphere, this value can be set to 0 . For other providers, do not set this value to 0 .
You can save on costs by setting this value to
|
||
3 | Specify the maximum number machines of the specified type that the cluster autoscaler can deploy in the specified zone after it initiates cluster scaling. Ensure that the maxNodesTotal value in the ClusterAutoscaler resource definition is large enough to allow the machine autoscaler to deploy this number of machines. |
||
4 | In this section, provide values that describe the existing compute machine set to scale. | ||
5 | The kind parameter value is always MachineSet . |
||
6 | The name value must match the name of an existing compute machine set, as shown in the metadata.name parameter value. |
To deploy a machine autoscaler, you create an instance of the MachineAutoscaler
resource.
Create a YAML file for a MachineAutoscaler
resource that contains the custom resource definition.
Create the custom resource in the cluster by running the following command:
$ oc create -f <filename>.yaml (1)
1 | <filename> is the name of the custom resource file. |
OKD uses Linux control group version 2 (cgroup v2) in your cluster.
cgroup v2 is the current version of the Linux cgroup API. cgroup v2 offers several improvements over cgroup v1, including a unified hierarchy, safer sub-tree delegation, new features such as Pressure Stall Information, and enhanced resource management and isolation. However, cgroup v2 has different CPU, memory, and I/O management characteristics than cgroup v1. Therefore, some workloads might experience slight differences in memory or CPU usage on clusters that run cgroup v2.
You can change between cgroup v1 and cgroup v2, as needed. Enabling cgroup v1 in OKD disables all cgroup v2 controllers and hierarchies in your cluster.
In Telco, clusters using |
You have a running OKD cluster that uses version 4.12 or later.
You are logged in to the cluster as a user with administrative privileges.
Enable cgroup v1 on nodes:
Edit the node.config
object:
$ oc edit nodes.config/cluster
Add spec.cgroupMode: "v1"
:
node.config
objectapiVersion: config.openshift.io/v2
kind: Node
metadata:
annotations:
include.release.openshift.io/ibm-cloud-managed: "true"
include.release.openshift.io/self-managed-high-availability: "true"
include.release.openshift.io/single-node-developer: "true"
release.openshift.io/create-only: "true"
creationTimestamp: "2022-07-08T16:02:51Z"
generation: 1
name: cluster
ownerReferences:
- apiVersion: config.openshift.io/v2
kind: ClusterVersion
name: version
uid: 36282574-bf9f-409e-a6cd-3032939293eb
resourceVersion: "1865"
uid: 0c0f7a4c-4307-4187-b591-6155695ac85b
spec:
cgroupMode: "v1" (1)
...
1 | Enables cgroup v1. |
Check the machine configs to see that the new machine configs were added:
$ oc get mc
NAME GENERATEDBYCONTROLLER IGNITIONVERSION AGE
00-master 52dd3ba6a9a527fc3ab42afac8d12b693534c8c9 3.2.0 33m
00-worker 52dd3ba6a9a527fc3ab42afac8d12b693534c8c9 3.2.0 33m
01-master-container-runtime 52dd3ba6a9a527fc3ab42afac8d12b693534c8c9 3.2.0 33m
01-master-kubelet 52dd3ba6a9a527fc3ab42afac8d12b693534c8c9 3.2.0 33m
01-worker-container-runtime 52dd3ba6a9a527fc3ab42afac8d12b693534c8c9 3.2.0 33m
01-worker-kubelet 52dd3ba6a9a527fc3ab42afac8d12b693534c8c9 3.2.0 33m
97-master-generated-kubelet 52dd3ba6a9a527fc3ab42afac8d12b693534c8c9 3.2.0 33m
99-worker-generated-kubelet 52dd3ba6a9a527fc3ab42afac8d12b693534c8c9 3.2.0 33m
99-master-generated-registries 52dd3ba6a9a527fc3ab42afac8d12b693534c8c9 3.2.0 33m
99-master-ssh 3.2.0 40m
99-worker-generated-registries 52dd3ba6a9a527fc3ab42afac8d12b693534c8c9 3.2.0 33m
99-worker-ssh 3.2.0 40m
rendered-master-23d4317815a5f854bd3553d689cfe2e9 52dd3ba6a9a527fc3ab42afac8d12b693534c8c9 3.2.0 10s (1)
rendered-master-23e785de7587df95a4b517e0647e5ab7 52dd3ba6a9a527fc3ab42afac8d12b693534c8c9 3.2.0 33m
rendered-worker-5d596d9293ca3ea80c896a1191735bb1 52dd3ba6a9a527fc3ab42afac8d12b693534c8c9 3.2.0 33m
rendered-worker-dcc7f1b92892d34db74d6832bcc9ccd4 52dd3ba6a9a527fc3ab42afac8d12b693534c8c9 3.2.0 10s
1 | New machine configs are created, as expected. |
Check that the new kernelArguments
were added to the new machine configs:
$ oc describe mc <name>
apiVersion: machineconfiguration.openshift.io/v2
kind: MachineConfig
metadata:
labels:
machineconfiguration.openshift.io/role: worker
name: 05-worker-kernelarg-selinuxpermissive
spec:
kernelArguments:
systemd.unified_cgroup_hierarchy=0 (1)
systemd.legacy_systemd_cgroup_controller=1 (2)
1 | Disables cgroup v2. |
2 | Enables cgroup v1 in systemd. |
Check the nodes to see that scheduling on the nodes is disabled. This indicates that the change is being applied:
$ oc get nodes
NAME STATUS ROLES AGE VERSION
ci-ln-fm1qnwt-72292-99kt6-master-0 Ready,SchedulingDisabled master 58m v1.28.5
ci-ln-fm1qnwt-72292-99kt6-master-1 Ready master 58m v1.28.5
ci-ln-fm1qnwt-72292-99kt6-master-2 Ready master 58m v1.28.5
ci-ln-fm1qnwt-72292-99kt6-worker-a-h5gt4 Ready,SchedulingDisabled worker 48m v1.28.5
ci-ln-fm1qnwt-72292-99kt6-worker-b-7vtmd Ready worker 48m v1.28.5
ci-ln-fm1qnwt-72292-99kt6-worker-c-rhzkv Ready worker 48m v1.28.5
After a node returns to the Ready
state, start a debug session for that node:
$ oc debug node/<node_name>
Set /host
as the root directory within the debug shell:
sh-4.4# chroot /host
Check that the sys/fs/cgroup/cgroup2fs
file is present on your nodes. This file is created by cgroup v1:
$ stat -c %T -f /sys/fs/cgroup
cgroup2fs
You can turn on a subset of the current Technology Preview features on for all nodes in the cluster by editing the FeatureGate
custom resource (CR).
You can use the FeatureGate
custom resource (CR) to enable specific feature sets in your cluster. A feature set is a collection of OKD features that are not enabled by default.
You can activate the following feature set by using the FeatureGate
CR:
TechPreviewNoUpgrade
. This feature set is a subset of the current Technology Preview features. This feature set allows you to enable these Technology Preview features on test clusters, where you can fully test them, while leaving the features disabled on production clusters.
Enabling the |
The following Technology Preview features are enabled by this feature set:
External cloud providers. Enables support for external cloud providers for clusters on vSphere, AWS, Azure, and GCP. Support for OpenStack is GA. This is an internal feature that most users do not need to interact with. (ExternalCloudProvider
)
Shared Resources CSI Driver in OpenShift Builds. Enables the Container Storage Interface (CSI). (CSIDriverSharedResource
)
Swap memory on nodes. Enables swap memory use for OKD workloads on a per-node basis. (NodeSwap
)
OpenStack Machine API Provider. This gate has no effect and is planned to be removed from this feature set in a future release. (MachineAPIProviderOpenStack
)
Insights Operator. Enables the InsightsDataGather
CRD, which allows users to configure some Insights data gathering options. The feature set also enables the DataGather
CRD, which allows users to run Insights data gathering on-demand. (InsightsConfigAPI
)
Retroactive Default Storage Class. Enables OKD to retroactively assign the default storage class to PVCs if there was no default storage class when the PVC was created.(RetroactiveDefaultStorageClass
)
Dynamic Resource Allocation API. Enables a new API for requesting and sharing resources between pods and containers. This is an internal feature that most users do not need to interact with. (DynamicResourceAllocation
)
Pod security admission enforcement. Enables the restricted enforcement mode for pod security admission. Instead of only logging a warning, pods are rejected if they violate pod security standards. (OpenShiftPodSecurityAdmission
)
StatefulSet pod availability upgrading limits. Enables users to define the maximum number of statefulset pods unavailable during updates which reduces application downtime. (MaxUnavailableStatefulSet
)
Admin Network Policy and Baseline Admin Network Policy. Enables AdminNetworkPolicy
and BaselineAdminNetworkPolicy
resources, which are part of the Network Policy V2 API, in clusters running the OVN-Kubernetes CNI plugin. Cluster administrators can apply cluster-scoped policies and safeguards for an entire cluster before namespaces are created. Network administrators can secure clusters by enforcing network traffic controls that cannot be overridden by users. Network administrators can enforce optional baseline network traffic controls that can be overridden by users in the cluster, if necessary. Currently, these APIs support only expressing policies for intra-cluster traffic. (AdminNetworkPolicy
)
MatchConditions
is a list of conditions that must be met for a request to be sent to this webhook. Match conditions filter requests that have already been matched by the rules, namespaceSelector, and objectSelector. An empty list of matchConditions
matches all requests. (admissionWebhookMatchConditions
)
Gateway API. To enable the OKD Gateway API, set the value of the enabled
field to true
in the techPreview.gatewayAPI
specification of the ServiceMeshControlPlane
resource.(gateGatewayAPI
)
gcpLabelsTags
vSphereStaticIPs
routeExternalCertificate
automatedEtcdBackup
gcpClusterHostedDNS
vSphereControlPlaneMachineset
dnsNameResolver
machineConfigNodes
metricsServer
installAlternateInfrastructureAWS
sdnLiveMigration
mixedCPUsAllocation
managedBootImages
onClusterBuild
signatureStores
You can use the OKD web console to enable feature sets for all of the nodes in a cluster by editing the FeatureGate
custom resource (CR).
To enable feature sets:
In the OKD web console, switch to the Administration → Custom Resource Definitions page.
On the Custom Resource Definitions page, click FeatureGate.
On the Custom Resource Definition Details page, click the Instances tab.
Click the cluster feature gate, then click the YAML tab.
Edit the cluster instance to add specific feature sets:
Enabling the |
apiVersion: config.openshift.io/v1
kind: FeatureGate
metadata:
name: cluster (1)
# ...
spec:
featureSet: TechPreviewNoUpgrade (2)
1 | The name of the FeatureGate CR must be cluster . |
2 | Add the feature set that you want to enable:
|
After you save the changes, new machine configs are created, the machine config pools are updated, and scheduling on each node is disabled while the change is being applied.
You can verify that the feature gates are enabled by looking at the kubelet.conf
file on a node after the nodes return to the ready state.
From the Administrator perspective in the web console, navigate to Compute → Nodes.
Select a node.
In the Node details page, click Terminal.
In the terminal window, change your root directory to /host
:
sh-4.2# chroot /host
View the kubelet.conf
file:
sh-4.2# cat /etc/kubernetes/kubelet.conf
# ...
featureGates:
InsightsOperatorPullingSCA: true,
LegacyNodeRoleBehavior: false
# ...
The features that are listed as true
are enabled on your cluster.
The features listed vary depending upon the OKD version. |
You can use the OpenShift CLI (oc
) to enable feature sets for all of the nodes in a cluster by editing the FeatureGate
custom resource (CR).
You have installed the OpenShift CLI (oc
).
To enable feature sets:
Edit the FeatureGate
CR named cluster
:
$ oc edit featuregate cluster
Enabling the |
apiVersion: config.openshift.io/v1
kind: FeatureGate
metadata:
name: cluster (1)
# ...
spec:
featureSet: TechPreviewNoUpgrade (2)
1 | The name of the FeatureGate CR must be cluster . |
2 | Add the feature set that you want to enable:
|
After you save the changes, new machine configs are created, the machine config pools are updated, and scheduling on each node is disabled while the change is being applied.
You can verify that the feature gates are enabled by looking at the kubelet.conf
file on a node after the nodes return to the ready state.
From the Administrator perspective in the web console, navigate to Compute → Nodes.
Select a node.
In the Node details page, click Terminal.
In the terminal window, change your root directory to /host
:
sh-4.2# chroot /host
View the kubelet.conf
file:
sh-4.2# cat /etc/kubernetes/kubelet.conf
# ...
featureGates:
InsightsOperatorPullingSCA: true,
LegacyNodeRoleBehavior: false
# ...
The features that are listed as true
are enabled on your cluster.
The features listed vary depending upon the OKD version. |
Back up etcd, enable or disable etcd encryption, or defragment etcd data.
By default, etcd data is not encrypted in OKD. You can enable etcd encryption for your cluster to provide an additional layer of data security. For example, it can help protect the loss of sensitive data if an etcd backup is exposed to the incorrect parties.
When you enable etcd encryption, the following OpenShift API server and Kubernetes API server resources are encrypted:
Secrets
Config maps
Routes
OAuth access tokens
OAuth authorize tokens
When you enable etcd encryption, encryption keys are created. You must have these keys to restore from an etcd backup.
Etcd encryption only encrypts values, not keys. Resource types, namespaces, and object names are unencrypted. If etcd encryption is enabled during a backup, the |
The following encryption types are supported for encrypting etcd data in OKD:
Uses AES-CBC with PKCS#7 padding and a 32 byte key to perform the encryption. The encryption keys are rotated weekly.
Uses AES-GCM with a random nonce and a 32 byte key to perform the encryption. The encryption keys are rotated weekly.
You can enable etcd encryption to encrypt sensitive resources in your cluster.
Do not back up etcd resources until the initial encryption process is completed. If the encryption process is not completed, the backup might be only partially encrypted. After you enable etcd encryption, several changes can occur:
|
You can encrypt the etcd database in either AES-GCM or AES-CBC encryption.
To migrate your etcd database from one encryption type to the other, you can modify the API server’s |
Access to the cluster as a user with the cluster-admin
role.
Modify the APIServer
object:
$ oc edit apiserver
Set the spec.encryption.type
field to aesgcm
or aescbc
:
spec:
encryption:
type: aesgcm (1)
1 | Set to aesgcm for AES-GCM encryption or aescbc for AES-CBC encryption. |
Save the file to apply the changes.
The encryption process starts. It can take 20 minutes or longer for this process to complete, depending on the size of the etcd database.
Verify that etcd encryption was successful.
Review the Encrypted
status condition for the OpenShift API server to verify that its resources were successfully encrypted:
$ oc get openshiftapiserver -o=jsonpath='{range .items[0].status.conditions[?(@.type=="Encrypted")]}{.reason}{"\n"}{.message}{"\n"}'
The output shows EncryptionCompleted
upon successful encryption:
EncryptionCompleted
All resources encrypted: routes.route.openshift.io
If the output shows EncryptionInProgress
, encryption is still in progress. Wait a few minutes and try again.
Review the Encrypted
status condition for the Kubernetes API server to verify that its resources were successfully encrypted:
$ oc get kubeapiserver -o=jsonpath='{range .items[0].status.conditions[?(@.type=="Encrypted")]}{.reason}{"\n"}{.message}{"\n"}'
The output shows EncryptionCompleted
upon successful encryption:
EncryptionCompleted
All resources encrypted: secrets, configmaps
If the output shows EncryptionInProgress
, encryption is still in progress. Wait a few minutes and try again.
Review the Encrypted
status condition for the OpenShift OAuth API server to verify that its resources were successfully encrypted:
$ oc get authentication.operator.openshift.io -o=jsonpath='{range .items[0].status.conditions[?(@.type=="Encrypted")]}{.reason}{"\n"}{.message}{"\n"}'
The output shows EncryptionCompleted
upon successful encryption:
EncryptionCompleted
All resources encrypted: oauthaccesstokens.oauth.openshift.io, oauthauthorizetokens.oauth.openshift.io
If the output shows EncryptionInProgress
, encryption is still in progress. Wait a few minutes and try again.
You can disable encryption of etcd data in your cluster.
Access to the cluster as a user with the cluster-admin
role.
Modify the APIServer
object:
$ oc edit apiserver
Set the encryption
field type to identity
:
spec:
encryption:
type: identity (1)
1 | The identity type is the default value and means that no encryption is performed. |
Save the file to apply the changes.
The decryption process starts. It can take 20 minutes or longer for this process to complete, depending on the size of your cluster.
Verify that etcd decryption was successful.
Review the Encrypted
status condition for the OpenShift API server to verify that its resources were successfully decrypted:
$ oc get openshiftapiserver -o=jsonpath='{range .items[0].status.conditions[?(@.type=="Encrypted")]}{.reason}{"\n"}{.message}{"\n"}'
The output shows DecryptionCompleted
upon successful decryption:
DecryptionCompleted
Encryption mode set to identity and everything is decrypted
If the output shows DecryptionInProgress
, decryption is still in progress. Wait a few minutes and try again.
Review the Encrypted
status condition for the Kubernetes API server to verify that its resources were successfully decrypted:
$ oc get kubeapiserver -o=jsonpath='{range .items[0].status.conditions[?(@.type=="Encrypted")]}{.reason}{"\n"}{.message}{"\n"}'
The output shows DecryptionCompleted
upon successful decryption:
DecryptionCompleted
Encryption mode set to identity and everything is decrypted
If the output shows DecryptionInProgress
, decryption is still in progress. Wait a few minutes and try again.
Review the Encrypted
status condition for the OpenShift OAuth API server to verify that its resources were successfully decrypted:
$ oc get authentication.operator.openshift.io -o=jsonpath='{range .items[0].status.conditions[?(@.type=="Encrypted")]}{.reason}{"\n"}{.message}{"\n"}'
The output shows DecryptionCompleted
upon successful decryption:
DecryptionCompleted
Encryption mode set to identity and everything is decrypted
If the output shows DecryptionInProgress
, decryption is still in progress. Wait a few minutes and try again.
Follow these steps to back up etcd data by creating an etcd snapshot and backing up the resources for the static pods. This backup can be saved and used at a later time if you need to restore etcd.
Only save a backup from a single control plane host. Do not take a backup from each control plane host in the cluster. |
You have access to the cluster as a user with the cluster-admin
role.
You have checked whether the cluster-wide proxy is enabled.
You can check whether the proxy is enabled by reviewing the output of |
Start a debug session as root for a control plane node:
$ oc debug --as-root node/<node_name>
Change your root directory to /host
in the debug shell:
sh-4.4# chroot /host
If the cluster-wide proxy is enabled, export the NO_PROXY
, HTTP_PROXY
, and HTTPS_PROXY
environment variables by running the following commands:
$ export HTTP_PROXY=http://<your_proxy.example.com>:8080
$ export HTTPS_PROXY=https://<your_proxy.example.com>:8080
$ export NO_PROXY=<example.com>
Run the cluster-backup.sh
script in the debug shell and pass in the location to save the backup to.
The |
sh-4.4# /usr/local/bin/cluster-backup.sh /home/core/assets/backup
found latest kube-apiserver: /etc/kubernetes/static-pod-resources/kube-apiserver-pod-6
found latest kube-controller-manager: /etc/kubernetes/static-pod-resources/kube-controller-manager-pod-7
found latest kube-scheduler: /etc/kubernetes/static-pod-resources/kube-scheduler-pod-6
found latest etcd: /etc/kubernetes/static-pod-resources/etcd-pod-3
ede95fe6b88b87ba86a03c15e669fb4aa5bf0991c180d3c6895ce72eaade54a1
etcdctl version: 3.4.14
API version: 3.4
{"level":"info","ts":1624647639.0188997,"caller":"snapshot/v3_snapshot.go:119","msg":"created temporary db file","path":"/home/core/assets/backup/snapshot_2021-06-25_190035.db.part"}
{"level":"info","ts":"2021-06-25T19:00:39.030Z","caller":"clientv3/maintenance.go:200","msg":"opened snapshot stream; downloading"}
{"level":"info","ts":1624647639.0301006,"caller":"snapshot/v3_snapshot.go:127","msg":"fetching snapshot","endpoint":"https://10.0.0.5:2379"}
{"level":"info","ts":"2021-06-25T19:00:40.215Z","caller":"clientv3/maintenance.go:208","msg":"completed snapshot read; closing"}
{"level":"info","ts":1624647640.6032252,"caller":"snapshot/v3_snapshot.go:142","msg":"fetched snapshot","endpoint":"https://10.0.0.5:2379","size":"114 MB","took":1.584090459}
{"level":"info","ts":1624647640.6047094,"caller":"snapshot/v3_snapshot.go:152","msg":"saved","path":"/home/core/assets/backup/snapshot_2021-06-25_190035.db"}
Snapshot saved at /home/core/assets/backup/snapshot_2021-06-25_190035.db
{"hash":3866667823,"revision":31407,"totalKey":12828,"totalSize":114446336}
snapshot db and kube resources are successfully saved to /home/core/assets/backup
In this example, two files are created in the /home/core/assets/backup/
directory on the control plane host:
snapshot_<datetimestamp>.db
: This file is the etcd snapshot. The cluster-backup.sh
script confirms its validity.
static_kuberesources_<datetimestamp>.tar.gz
: This file contains the resources for the static pods. If etcd encryption is enabled, it also contains the encryption keys for the etcd snapshot.
If etcd encryption is enabled, it is recommended to store this second file separately from the etcd snapshot for security reasons. However, this file is required to restore from the etcd snapshot. Keep in mind that etcd encryption only encrypts values, not keys. This means that resource types, namespaces, and object names are unencrypted. |
For large and dense clusters, etcd can suffer from poor performance if the keyspace grows too large and exceeds the space quota. Periodically maintain and defragment etcd to free up space in the data store. Monitor Prometheus for etcd metrics and defragment it when required; otherwise, etcd can raise a cluster-wide alarm that puts the cluster into a maintenance mode that accepts only key reads and deletes.
Monitor these key metrics:
etcd_server_quota_backend_bytes
, which is the current quota limit
etcd_mvcc_db_total_size_in_use_in_bytes
, which indicates the actual database usage after a history compaction
etcd_mvcc_db_total_size_in_bytes
, which shows the database size, including free space waiting for defragmentation
Defragment etcd data to reclaim disk space after events that cause disk fragmentation, such as etcd history compaction.
History compaction is performed automatically every five minutes and leaves gaps in the back-end database. This fragmented space is available for use by etcd, but is not available to the host file system. You must defragment etcd to make this space available to the host file system.
Defragmentation occurs automatically, but you can also trigger it manually.
Automatic defragmentation is good for most cases, because the etcd operator uses cluster information to determine the most efficient operation for the user. |
The etcd Operator automatically defragments disks. No manual intervention is needed.
Verify that the defragmentation process is successful by viewing one of these logs:
etcd logs
cluster-etcd-operator pod
operator status error log
Automatic defragmentation can cause leader election failure in various OpenShift core components, such as the Kubernetes controller manager, which triggers a restart of the failing component. The restart is harmless and either triggers failover to the next running instance or the component resumes work again after the restart. |
etcd member has been defragmented: <member_name>, memberID: <member_id>
failed defrag on member: <member_name>, memberID: <member_id>: <error_message>
A Prometheus alert indicates when you need to use manual defragmentation. The alert is displayed in two cases:
When etcd uses more than 50% of its available space for more than 10 minutes
When etcd is actively using less than 50% of its total database size for more than 10 minutes
You can also determine whether defragmentation is needed by checking the etcd database size in MB that will be freed by defragmentation with the PromQL expression: (etcd_mvcc_db_total_size_in_bytes - etcd_mvcc_db_total_size_in_use_in_bytes)/1024/1024
Defragmenting etcd is a blocking action. The etcd member will not respond until defragmentation is complete. For this reason, wait at least one minute between defragmentation actions on each of the pods to allow the cluster to recover. |
Follow this procedure to defragment etcd data on each etcd member.
You have access to the cluster as a user with the cluster-admin
role.
Determine which etcd member is the leader, because the leader should be defragmented last.
Get the list of etcd pods:
$ oc -n openshift-etcd get pods -l k8s-app=etcd -o wide
etcd-ip-10-0-159-225.example.redhat.com 3/3 Running 0 175m 10.0.159.225 ip-10-0-159-225.example.redhat.com <none> <none>
etcd-ip-10-0-191-37.example.redhat.com 3/3 Running 0 173m 10.0.191.37 ip-10-0-191-37.example.redhat.com <none> <none>
etcd-ip-10-0-199-170.example.redhat.com 3/3 Running 0 176m 10.0.199.170 ip-10-0-199-170.example.redhat.com <none> <none>
Choose a pod and run the following command to determine which etcd member is the leader:
$ oc rsh -n openshift-etcd etcd-ip-10-0-159-225.example.redhat.com etcdctl endpoint status --cluster -w table
Defaulting container name to etcdctl.
Use 'oc describe pod/etcd-ip-10-0-159-225.example.redhat.com -n openshift-etcd' to see all of the containers in this pod.
+---------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+---------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| https://10.0.191.37:2379 | 251cd44483d811c3 | 3.5.9 | 104 MB | false | false | 7 | 91624 | 91624 | |
| https://10.0.159.225:2379 | 264c7c58ecbdabee | 3.5.9 | 104 MB | false | false | 7 | 91624 | 91624 | |
| https://10.0.199.170:2379 | 9ac311f93915cc79 | 3.5.9 | 104 MB | true | false | 7 | 91624 | 91624 | |
+---------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
Based on the IS LEADER
column of this output, the https://10.0.199.170:2379
endpoint is the leader. Matching this endpoint with the output of the previous step, the pod name of the leader is etcd-ip-10-0-199-170.example.redhat.com
.
Defragment an etcd member.
Connect to the running etcd container, passing in the name of a pod that is not the leader:
$ oc rsh -n openshift-etcd etcd-ip-10-0-159-225.example.redhat.com
Unset the ETCDCTL_ENDPOINTS
environment variable:
sh-4.4# unset ETCDCTL_ENDPOINTS
Defragment the etcd member:
sh-4.4# etcdctl --command-timeout=30s --endpoints=https://localhost:2379 defrag
Finished defragmenting etcd member[https://localhost:2379]
If a timeout error occurs, increase the value for --command-timeout
until the command succeeds.
Verify that the database size was reduced:
sh-4.4# etcdctl endpoint status -w table --cluster
+---------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+---------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| https://10.0.191.37:2379 | 251cd44483d811c3 | 3.5.9 | 104 MB | false | false | 7 | 91624 | 91624 | |
| https://10.0.159.225:2379 | 264c7c58ecbdabee | 3.5.9 | 41 MB | false | false | 7 | 91624 | 91624 | | (1)
| https://10.0.199.170:2379 | 9ac311f93915cc79 | 3.5.9 | 104 MB | true | false | 7 | 91624 | 91624 | |
+---------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
This example shows that the database size for this etcd member is now 41 MB as opposed to the starting size of 104 MB.
Repeat these steps to connect to each of the other etcd members and defragment them. Always defragment the leader last.
Wait at least one minute between defragmentation actions to allow the etcd pod to recover. Until the etcd pod recovers, the etcd member will not respond.
If any NOSPACE
alarms were triggered due to the space quota being exceeded, clear them.
Check if there are any NOSPACE
alarms:
sh-4.4# etcdctl alarm list
memberID:12345678912345678912 alarm:NOSPACE
Clear the alarms:
sh-4.4# etcdctl alarm disarm
You can use a saved etcd
backup to restore a previous cluster state or restore a cluster that has lost the majority of control plane hosts.
If your cluster uses a control plane machine set, see "Troubleshooting the control plane machine set" for a more simple |
When you restore your cluster, you must use an |
Access to the cluster as a user with the cluster-admin
role through a certificate-based kubeconfig
file, like the one that was used during installation.
A healthy control plane host to use as the recovery host.
SSH access to control plane hosts.
A backup directory containing both the etcd
snapshot and the resources for the static pods, which were from the same backup. The file names in the directory must be in the following formats: snapshot_<datetimestamp>.db
and static_kuberesources_<datetimestamp>.tar.gz
.
For non-recovery control plane nodes, it is not required to establish SSH connectivity or to stop the static pods. You can delete and recreate other non-recovery, control plane machines, one by one. |
Select a control plane host to use as the recovery host. This is the host that you will run the restore operation on.
Establish SSH connectivity to each of the control plane nodes, including the recovery host.
kube-apiserver
becomes inaccessible after the restore process starts, so you cannot access the control plane nodes. For this reason, it is recommended to establish SSH connectivity to each control plane host in a separate terminal.
If you do not complete this step, you will not be able to access the control plane hosts to complete the restore procedure, and you will be unable to recover your cluster from this state. |
Copy the etcd
backup directory to the recovery control plane host.
This procedure assumes that you copied the backup
directory containing the etcd
snapshot and the resources for the static pods to the /home/core/
directory of your recovery control plane host.
Stop the static pods on any other control plane nodes.
You do not need to stop the static pods on the recovery host. |
Access a control plane host that is not the recovery host.
Move the existing etcd pod file out of the kubelet manifest directory by running:
$ sudo mv -v /etc/kubernetes/manifests/etcd-pod.yaml /tmp
Verify that the etcd
pods are stopped by using:
$ sudo crictl ps | grep etcd | egrep -v "operator|etcd-guard"
If the output of this command is not empty, wait a few minutes and check again.
Move the existing kube-apiserver
file out of the kubelet manifest directory by running:
$ sudo mv -v /etc/kubernetes/manifests/kube-apiserver-pod.yaml /tmp
Verify that the kube-apiserver
containers are stopped by running:
$ sudo crictl ps | grep kube-apiserver | egrep -v "operator|guard"
If the output of this command is not empty, wait a few minutes and check again.
Move the existing kube-controller-manager
file out of the kubelet manifest directory by using:
$ sudo mv -v /etc/kubernetes/manifests/kube-controller-manager-pod.yaml /tmp
Verify that the kube-controller-manager
containers are stopped by running:
$ sudo crictl ps | grep kube-controller-manager | egrep -v "operator|guard"
If the output of this command is not empty, wait a few minutes and check again.
Move the existing kube-scheduler
file out of the kubelet manifest directory by using:
$ sudo mv -v /etc/kubernetes/manifests/kube-scheduler-pod.yaml /tmp
Verify that the kube-scheduler
containers are stopped by using:
$ sudo crictl ps | grep kube-scheduler | egrep -v "operator|guard"
If the output of this command is not empty, wait a few minutes and check again.
Move the etcd
data directory to a different location with the following example:
$ sudo mv -v /var/lib/etcd/ /tmp
If the /etc/kubernetes/manifests/keepalived.yaml
file exists and the node is deleted, follow these steps:
Move the /etc/kubernetes/manifests/keepalived.yaml
file out of the kubelet manifest directory:
$ sudo mv -v /etc/kubernetes/manifests/keepalived.yaml /tmp
Verify that any containers managed by the keepalived
daemon are stopped:
$ sudo crictl ps --name keepalived
The output of this command should be empty. If it is not empty, wait a few minutes and check again.
Check if the control plane has any Virtual IPs (VIPs) assigned to it:
$ ip -o address | egrep '<api_vip>|<ingress_vip>'
For each reported VIP, run the following command to remove it:
$ sudo ip address del <reported_vip> dev <reported_vip_device>
Repeat this step on each of the other control plane hosts that is not the recovery host.
Access the recovery control plane host.
If the keepalived
daemon is in use, verify that the recovery control plane node owns the VIP:
$ ip -o address | grep <api_vip>
The address of the VIP is highlighted in the output if it exists. This command returns an empty string if the VIP is not set or configured incorrectly.
If the cluster-wide proxy is enabled, be sure that you have exported the NO_PROXY
, HTTP_PROXY
, and HTTPS_PROXY
environment variables.
You can check whether the proxy is enabled by reviewing the output of |
Run the restore script on the recovery control plane host and pass in the path to the etcd
backup directory:
$ sudo -E /usr/local/bin/cluster-restore.sh /home/core/assets/backup
...stopping kube-scheduler-pod.yaml
...stopping kube-controller-manager-pod.yaml
...stopping etcd-pod.yaml
...stopping kube-apiserver-pod.yaml
Waiting for container etcd to stop
.complete
Waiting for container etcdctl to stop
.............................complete
Waiting for container etcd-metrics to stop
complete
Waiting for container kube-controller-manager to stop
complete
Waiting for container kube-apiserver to stop
..........................................................................................complete
Waiting for container kube-scheduler to stop
complete
Moving etcd data-dir /var/lib/etcd/member to /var/lib/etcd-backup
starting restore-etcd static pod
starting kube-apiserver-pod.yaml
static-pod-resources/kube-apiserver-pod-7/kube-apiserver-pod.yaml
starting kube-controller-manager-pod.yaml
static-pod-resources/kube-controller-manager-pod-7/kube-controller-manager-pod.yaml
starting kube-scheduler-pod.yaml
static-pod-resources/kube-scheduler-pod-8/kube-scheduler-pod.yaml
The cluster-restore.sh script must show that etcd
, kube-apiserver
, kube-controller-manager
, and kube-scheduler
pods are stopped and then started at the end of the restore process.
The restore process can cause nodes to enter the |
Check the nodes to ensure they are in the Ready
state.
Run the following command:
$ oc get nodes -w
NAME STATUS ROLES AGE VERSION
host-172-25-75-28 Ready master 3d20h v1.28.5
host-172-25-75-38 Ready infra,worker 3d20h v1.28.5
host-172-25-75-40 Ready master 3d20h v1.28.5
host-172-25-75-65 Ready master 3d20h v1.28.5
host-172-25-75-74 Ready infra,worker 3d20h v1.28.5
host-172-25-75-79 Ready worker 3d20h v1.28.5
host-172-25-75-86 Ready worker 3d20h v1.28.5
host-172-25-75-98 Ready infra,worker 3d20h v1.28.5
It can take several minutes for all nodes to report their state.
If any nodes are in the NotReady
state, log in to the nodes and remove all of the PEM files from the /var/lib/kubelet/pki
directory on each node. You can SSH into the nodes or use the terminal window in the web console.
$ ssh -i <ssh-key-path> core@<master-hostname>
pki
directorysh-4.4# pwd
/var/lib/kubelet/pki
sh-4.4# ls
kubelet-client-2022-04-28-11-24-09.pem kubelet-server-2022-04-28-11-24-15.pem
kubelet-client-current.pem kubelet-server-current.pem
Restart the kubelet service on all control plane hosts.
From the recovery host, run:
$ sudo systemctl restart kubelet.service
Repeat this step on all other control plane hosts.
Approve the pending Certificate Signing Requests (CSRs):
Clusters with no worker nodes, such as single-node clusters or clusters consisting of three schedulable control plane nodes, will not have any pending CSRs to approve. You can skip all the commands listed in this step. |
Get the list of current CSRs by running:
$ oc get csr
NAME AGE SIGNERNAME REQUESTOR CONDITION csr-2s94x 8m3s kubernetes.io/kubelet-serving system:node:<node_name> Pending (1) csr-4bd6t 8m3s kubernetes.io/kubelet-serving system:node:<node_name> Pending (1) csr-4hl85 13m kubernetes.io/kube-apiserver-client-kubelet system:serviceaccount:openshift-machine-config-operator:node-bootstrapper Pending (2) csr-zhhhp 3m8s kubernetes.io/kube-apiserver-client-kubelet system:serviceaccount:openshift-machine-config-operator:node-bootstrapper Pending (2) ...
1 | A pending kubelet serving CSR, requested by the node for the kubelet serving endpoint. |
2 | A pending kubelet client CSR, requested with the node-bootstrapper node bootstrap credentials. |
Review the details of a CSR to verify that it is valid by running:
$ oc describe csr <csr_name> (1)
1 | <csr_name> is the name of a CSR from the list of current CSRs. |
Approve each valid node-bootstrapper
CSR by running:
$ oc adm certificate approve <csr_name>
For user-provisioned installations, approve each valid kubelet service CSR by running:
$ oc adm certificate approve <csr_name>
Verify that the single member control plane has started successfully.
From the recovery host, verify that the etcd
container is running by using:
$ sudo crictl ps | grep etcd | egrep -v "operator|etcd-guard"
3ad41b7908e32 36f86e2eeaaffe662df0d21041eb22b8198e0e58abeeae8c743c3e6e977e8009 About a minute ago Running etcd 0 7c05f8af362f0
From the recovery host, verify that the etcd
pod is running by using:
$ oc -n openshift-etcd get pods -l k8s-app=etcd
NAME READY STATUS RESTARTS AGE
etcd-ip-10-0-143-125.ec2.internal 1/1 Running 1 2m47s
If the status is Pending
, or the output lists more than one running etcd
pod, wait a few minutes and check again.
If you are using the OVNKubernetes
network plugin, you must restart ovnkube-controlplane
pods.
Delete all of the ovnkube-controlplane
pods by running:
$ oc -n openshift-ovn-kubernetes delete pod -l app=ovnkube-control-plane
Verify that all of the ovnkube-controlplane
pods were redeployed by using:
$ oc -n openshift-ovn-kubernetes get pod -l app=ovnkube-control-plane
If you are using the OVN-Kubernetes network plugin, restart the Open Virtual Network (OVN) Kubernetes pods on all the nodes one by one. Use the following steps to restart OVN-Kubernetes pods on each node:
Restart OVN-Kubernetes pods in the following order:
|
Validating and mutating admission webhooks can reject pods. If you add any additional webhooks with the Alternatively, you can temporarily set the |
Remove the northbound database (nbdb) and southbound database (sbdb). Access the recovery host and the remaining control plane nodes by using Secure Shell (SSH) and run:
$ sudo rm -f /var/lib/ovn-ic/etc/*.db
Restart the OpenVSwitch services. Access the node by using Secure Shell (SSH) and run the following command:
$ sudo systemctl restart ovs-vswitchd ovsdb-server
Delete the ovnkube-node
pod on the node by running the following command, replacing <node>
with the name of the node that you are restarting:
$ oc -n openshift-ovn-kubernetes delete pod -l app=ovnkube-node --field-selector=spec.nodeName==<node>
Verify that the ovnkube-node
pod is running again with:
$ oc -n openshift-ovn-kubernetes get pod -l app=ovnkube-node --field-selector=spec.nodeName==<node>
It might take several minutes for the pods to restart. |
Delete and re-create other non-recovery, control plane machines, one by one. After the machines are re-created, a new revision is forced and etcd
automatically scales up.
If you use a user-provisioned bare metal installation, you can re-create a control plane machine by using the same method that you used to originally create it. For more information, see "Installing a user-provisioned cluster on bare metal".
Do not delete and re-create the machine for the recovery host. |
If you are running installer-provisioned infrastructure, or you used the Machine API to create your machines, follow these steps:
Do not delete and re-create the machine for the recovery host. For bare metal installations on installer-provisioned infrastructure, control plane machines are not re-created. For more information, see "Replacing a bare-metal control plane node". |
Obtain the machine for one of the lost control plane hosts.
In a terminal that has access to the cluster as a cluster-admin user, run the following command:
$ oc get machines -n openshift-machine-api -o wide
Example output:
NAME PHASE TYPE REGION ZONE AGE NODE PROVIDERID STATE
clustername-8qw5l-master-0 Running m4.xlarge us-east-1 us-east-1a 3h37m ip-10-0-131-183.ec2.internal aws:///us-east-1a/i-0ec2782f8287dfb7e stopped (1)
clustername-8qw5l-master-1 Running m4.xlarge us-east-1 us-east-1b 3h37m ip-10-0-143-125.ec2.internal aws:///us-east-1b/i-096c349b700a19631 running
clustername-8qw5l-master-2 Running m4.xlarge us-east-1 us-east-1c 3h37m ip-10-0-154-194.ec2.internal aws:///us-east-1c/i-02626f1dba9ed5bba running
clustername-8qw5l-worker-us-east-1a-wbtgd Running m4.large us-east-1 us-east-1a 3h28m ip-10-0-129-226.ec2.internal aws:///us-east-1a/i-010ef6279b4662ced running
clustername-8qw5l-worker-us-east-1b-lrdxb Running m4.large us-east-1 us-east-1b 3h28m ip-10-0-144-248.ec2.internal aws:///us-east-1b/i-0cb45ac45a166173b running
clustername-8qw5l-worker-us-east-1c-pkg26 Running m4.large us-east-1 us-east-1c 3h28m ip-10-0-170-181.ec2.internal aws:///us-east-1c/i-06861c00007751b0a running
1 | This is the control plane machine for the lost control plane host, ip-10-0-131-183.ec2.internal . |
Delete the machine of the lost control plane host by running:
$ oc delete machine -n openshift-machine-api clustername-8qw5l-master-0 (1)
1 | Specify the name of the control plane machine for the lost control plane host. |
A new machine is automatically provisioned after deleting the machine of the lost control plane host.
Verify that a new machine has been created by running:
$ oc get machines -n openshift-machine-api -o wide
Example output:
NAME PHASE TYPE REGION ZONE AGE NODE PROVIDERID STATE
clustername-8qw5l-master-1 Running m4.xlarge us-east-1 us-east-1b 3h37m ip-10-0-143-125.ec2.internal aws:///us-east-1b/i-096c349b700a19631 running
clustername-8qw5l-master-2 Running m4.xlarge us-east-1 us-east-1c 3h37m ip-10-0-154-194.ec2.internal aws:///us-east-1c/i-02626f1dba9ed5bba running
clustername-8qw5l-master-3 Provisioning m4.xlarge us-east-1 us-east-1a 85s ip-10-0-173-171.ec2.internal aws:///us-east-1a/i-015b0888fe17bc2c8 running (1)
clustername-8qw5l-worker-us-east-1a-wbtgd Running m4.large us-east-1 us-east-1a 3h28m ip-10-0-129-226.ec2.internal aws:///us-east-1a/i-010ef6279b4662ced running
clustername-8qw5l-worker-us-east-1b-lrdxb Running m4.large us-east-1 us-east-1b 3h28m ip-10-0-144-248.ec2.internal aws:///us-east-1b/i-0cb45ac45a166173b running
clustername-8qw5l-worker-us-east-1c-pkg26 Running m4.large us-east-1 us-east-1c 3h28m ip-10-0-170-181.ec2.internal aws:///us-east-1c/i-06861c00007751b0a running
1 | The new machine, clustername-8qw5l-master-3 is being created and is ready after the phase changes from Provisioning to Running . |
It might take a few minutes for the new machine to be created. The etcd
cluster Operator will automatically sync when the machine or node returns to a healthy state.
Repeat these steps for each lost control plane host that is not the recovery host.
Turn off the quorum guard by entering:
$ oc patch etcd/cluster --type=merge -p '{"spec": {"unsupportedConfigOverrides": {"useUnsupportedUnsafeNonHANonProductionUnstableEtcd": true}}}'
This command ensures that you can successfully re-create secrets and roll out the static pods.
In a separate terminal window within the recovery host, export the recovery kubeconfig
file by running:
$ export KUBECONFIG=/etc/kubernetes/static-pod-resources/kube-apiserver-certs/secrets/node-kubeconfigs/localhost-recovery.kubeconfig
Force etcd
redeployment.
In the same terminal window where you exported the recovery kubeconfig
file, run:
$ oc patch etcd cluster -p='{"spec": {"forceRedeploymentReason": "recovery-'"$( date --rfc-3339=ns )"'"}}' --type=merge (1)
1 | The forceRedeploymentReason value must be unique, which is why a timestamp is appended. |
When the etcd
cluster Operator performs a redeployment, the existing nodes are started with new pods similar to the initial bootstrap scale up.
Turn the quorum guard back on by entering:
$ oc patch etcd/cluster --type=merge -p '{"spec": {"unsupportedConfigOverrides": null}}'
You can verify that the unsupportedConfigOverrides
section is removed from the object by running:
$ oc get etcd/cluster -oyaml
Verify all nodes are updated to the latest revision.
In a terminal that has access to the cluster as a cluster-admin
user, run:
$ oc get etcd -o=jsonpath='{range .items[0].status.conditions[?(@.type=="NodeInstallerProgressing")]}{.reason}{"\n"}{.message}{"\n"}'
Review the NodeInstallerProgressing
status condition for etcd
to verify that all nodes are at the latest revision. The output shows AllNodesAtLatestRevision
upon successful update:
AllNodesAtLatestRevision
3 nodes are at revision 7 (1)
1 | In this example, the latest revision number is 7 . |
If the output includes multiple revision numbers, such as 2 nodes are at revision 6; 1 nodes are at revision 7
, this means that the update is still in progress. Wait a few minutes and try again.
After etcd
is redeployed, force new rollouts for the control plane. kube-apiserver
will reinstall itself on the other nodes because the kubelet is connected to API servers using an internal load balancer.
In a terminal that has access to the cluster as a cluster-admin
user, run:
Force a new rollout for kube-apiserver
:
$ oc patch kubeapiserver cluster -p='{"spec": {"forceRedeploymentReason": "recovery-'"$( date --rfc-3339=ns )"'"}}' --type=merge
Verify all nodes are updated to the latest revision.
$ oc get kubeapiserver -o=jsonpath='{range .items[0].status.conditions[?(@.type=="NodeInstallerProgressing")]}{.reason}{"\n"}{.message}{"\n"}'
Review the NodeInstallerProgressing
status condition to verify that all nodes are at the latest revision. The output shows AllNodesAtLatestRevision
upon successful update:
AllNodesAtLatestRevision
3 nodes are at revision 7 (1)
1 | In this example, the latest revision number is 7 . |
If the output includes multiple revision numbers, such as 2 nodes are at revision 6; 1 nodes are at revision 7
, this means that the update is still in progress. Wait a few minutes and try again.
Force a new rollout for the Kubernetes controller manager by running the following command:
$ oc patch kubecontrollermanager cluster -p='{"spec": {"forceRedeploymentReason": "recovery-'"$( date --rfc-3339=ns )"'"}}' --type=merge
Verify all nodes are updated to the latest revision by running:
$ oc get kubecontrollermanager -o=jsonpath='{range .items[0].status.conditions[?(@.type=="NodeInstallerProgressing")]}{.reason}{"\n"}{.message}{"\n"}'
Review the NodeInstallerProgressing
status condition to verify that all nodes are at the latest revision. The output shows AllNodesAtLatestRevision
upon successful update:
AllNodesAtLatestRevision
3 nodes are at revision 7 (1)
1 | In this example, the latest revision number is 7 . |
If the output includes multiple revision numbers, such as 2 nodes are at revision 6; 1 nodes are at revision 7
, this means that the update is still in progress. Wait a few minutes and try again.
Force a new rollout for the kube-scheduler
by running:
$ oc patch kubescheduler cluster -p='{"spec": {"forceRedeploymentReason": "recovery-'"$( date --rfc-3339=ns )"'"}}' --type=merge
Verify all nodes are updated to the latest revision by using:
$ oc get kubescheduler -o=jsonpath='{range .items[0].status.conditions[?(@.type=="NodeInstallerProgressing")]}{.reason}{"\n"}{.message}{"\n"}'
Review the NodeInstallerProgressing
status condition to verify that all nodes are at the latest revision. The output shows AllNodesAtLatestRevision
upon successful update:
AllNodesAtLatestRevision
3 nodes are at revision 7 (1)
1 | In this example, the latest revision number is 7 . |
If the output includes multiple revision numbers, such as 2 nodes are at revision 6; 1 nodes are at revision 7
, this means that the update is still in progress. Wait a few minutes and try again.
Verify that all control plane hosts have started and joined the cluster.
In a terminal that has access to the cluster as a cluster-admin
user, run the following command:
$ oc -n openshift-etcd get pods -l k8s-app=etcd
etcd-ip-10-0-143-125.ec2.internal 2/2 Running 0 9h
etcd-ip-10-0-154-194.ec2.internal 2/2 Running 0 9h
etcd-ip-10-0-173-171.ec2.internal 2/2 Running 0 9h
To ensure that all workloads return to normal operation following a recovery procedure, restart all control plane nodes.
On completion of the previous procedural steps, you might need to wait a few minutes for all services to return to their restored state. For example, authentication by using Consider using the
Issue the following command to display your authenticated user name:
|
If your OKD cluster uses persistent storage of any form, a state of the cluster is typically stored outside etcd. It might be an Elasticsearch cluster running in a pod or a database running in a StatefulSet
object. When you restore from an etcd backup, the status of the workloads in OKD is also restored. However, if the etcd snapshot is old, the status might be invalid or outdated.
The contents of persistent volumes (PVs) are never part of the etcd snapshot. When you restore an OKD cluster from an etcd snapshot, non-critical workloads might gain access to critical data, or vice-versa. |
The following are some example scenarios that produce an out-of-date status:
MySQL database is running in a pod backed up by a PV object. Restoring OKD from an etcd snapshot does not bring back the volume on the storage provider, and does not produce a running MySQL pod, despite the pod repeatedly attempting to start. You must manually restore this pod by restoring the volume on the storage provider, and then editing the PV to point to the new volume.
Pod P1 is using volume A, which is attached to node X. If the etcd snapshot is taken while another pod uses the same volume on node Y, then when the etcd restore is performed, pod P1 might not be able to start correctly due to the volume still being attached to node Y. OKD is not aware of the attachment, and does not automatically detach it. When this occurs, the volume must be manually detached from node Y so that the volume can attach on node X, and then pod P1 can start.
Cloud provider or storage provider credentials were updated after the etcd snapshot was taken. This causes any CSI drivers or Operators that depend on the those credentials to not work. You might have to manually update the credentials required by those drivers or Operators.
A device is removed or renamed from OKD nodes after the etcd snapshot is taken. The Local Storage Operator creates symlinks for each PV that it manages from /dev/disk/by-id
or /dev
directories. This situation might cause the local PVs to refer to devices that no longer exist.
To fix this problem, an administrator must:
Manually remove the PVs with invalid devices.
Remove symlinks from respective nodes.
Delete LocalVolume
or LocalVolumeSet
objects (see Storage → Configuring persistent storage → Persistent storage using local volumes → Deleting the Local Storage Operator Resources).
Understand and configure pod disruption budgets.
A pod disruption budget allows the specification of safety constraints on pods during operations, such as draining a node for maintenance.
PodDisruptionBudget
is an API object that specifies the minimum number or
percentage of replicas that must be up at a time. Setting these in projects can
be helpful during node maintenance (such as scaling a cluster down or a cluster
upgrade) and is only honored on voluntary evictions (not on node failures).
A PodDisruptionBudget
object’s configuration consists of the following key
parts:
A label selector, which is a label query over a set of pods.
An availability level, which specifies the minimum number of pods that must be available simultaneously, either:
minAvailable
is the number of pods must always be available, even during a disruption.
maxUnavailable
is the number of pods can be unavailable during a disruption.
A |
The default setting for |
You can check for pod disruption budgets across all projects with the following:
$ oc get poddisruptionbudget --all-namespaces
The following example contains some values that are specific to OKD on AWS. |
NAMESPACE NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
openshift-apiserver openshift-apiserver-pdb N/A 1 1 121m
openshift-cloud-controller-manager aws-cloud-controller-manager 1 N/A 1 125m
openshift-cloud-credential-operator pod-identity-webhook 1 N/A 1 117m
openshift-cluster-csi-drivers aws-ebs-csi-driver-controller-pdb N/A 1 1 121m
openshift-cluster-storage-operator csi-snapshot-controller-pdb N/A 1 1 122m
openshift-cluster-storage-operator csi-snapshot-webhook-pdb N/A 1 1 122m
openshift-console console N/A 1 1 116m
#...
The PodDisruptionBudget
is considered healthy when there are at least
minAvailable
pods running in the system. Every pod above that limit can be evicted.
Depending on your pod priority and preemption settings, lower-priority pods might be removed despite their pod disruption budget requirements. |
You can use a PodDisruptionBudget
object to specify the minimum number or
percentage of replicas that must be up at a time.
To configure a pod disruption budget:
Create a YAML file with the an object definition similar to the following:
apiVersion: policy/v1 (1)
kind: PodDisruptionBudget
metadata:
name: my-pdb
spec:
minAvailable: 2 (2)
selector: (3)
matchLabels:
name: my-pod
1 | PodDisruptionBudget is part of the policy/v1 API group. |
2 | The minimum number of pods that must be available simultaneously. This can
be either an integer or a string specifying a percentage, for example, 20% . |
3 | A label query over a set of resources. The result of matchLabels and
matchExpressions are logically conjoined. Leave this parameter blank, for example selector {} , to select all pods in the project. |
Or:
apiVersion: policy/v1 (1)
kind: PodDisruptionBudget
metadata:
name: my-pdb
spec:
maxUnavailable: 25% (2)
selector: (3)
matchLabels:
name: my-pod
1 | PodDisruptionBudget is part of the policy/v1 API group. |
2 | The maximum number of pods that can be unavailable simultaneously. This can
be either an integer or a string specifying a percentage, for example, 20% . |
3 | A label query over a set of resources. The result of matchLabels and
matchExpressions are logically conjoined. Leave this parameter blank, for example selector {} , to select all pods in the project. |
Run the following command to add the object to project:
$ oc create -f </path/to/file> -n <project_name>
When you use pod disruption budgets (PDBs) to specify how many pods must be available simultaneously, you can also define the criteria for how unhealthy pods are considered for eviction.
You can choose one of the following policies:
Running pods that are not yet healthy can be evicted only if the guarded application is not disrupted.
Running pods that are not yet healthy can be evicted regardless of whether the criteria in the pod disruption budget is met. This policy can help evict malfunctioning applications, such as ones with pods stuck in the CrashLoopBackOff
state or failing to report the Ready
status.
It is recommended to set the |
Create a YAML file that defines a PodDisruptionBudget
object and specify the unhealthy pod eviction policy:
pod-disruption-budget.yaml
fileapiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-pdb
spec:
minAvailable: 2
selector:
matchLabels:
name: my-pod
unhealthyPodEvictionPolicy: AlwaysAllow (1)
1 | Choose either IfHealthyBudget or AlwaysAllow as the unhealthy pod eviction policy. The default is IfHealthyBudget when the unhealthyPodEvictionPolicy field is empty. |
Create the PodDisruptionBudget
object by running the following command:
$ oc create -f pod-disruption-budget.yaml
With a PDB that has the AlwaysAllow
unhealthy pod eviction policy set, you can now drain nodes and evict the pods for a malfunctioning application guarded by this PDB.
Unhealthy Pod Eviction Policy in the Kubernetes documentation