Configure

Understand default networking capabilities

Understand how networking works out of the box in MicroShift so that you can determine if the default configuration suits your needs or identify where you need to customize it.

MicroShift default networking plugin

The OVN-Kubernetes Container Network Interface (CNI) plugin is the default networking solution for a MicroShift node. OVN-Kubernetes is a virtualized network for pods and services that is based on Open Virtual Network (OVN).

  • Changing the CNI is not supported on MicroShift.

  • Default network configuration and connections are applied automatically in MicroShift with the microshift-networking RPM during installation.

  • A node that uses the OVN-Kubernetes network plugin also runs Open vSwitch (OVS) on the node.

  • OVN-K configures OVS on the node to implement the declared network configuration.

  • Host physical interfaces are not bound by default to the OVN-K gateway bridge, br-ex. You can use standard tools on the host for managing the default gateway, such as the Network Manager CLI (nmcli).

Using configuration files or custom scripts, you can configure the following networking settings:

  • You can use subnet CIDR ranges to allocate IP addresses to pods.

  • You can change the maximum transmission unit (MTU) value.

  • You can configure firewall ingress and egress.

  • You can define network policies in the MicroShift, including ingress and egress rules.

  • You can use the MicroShift Multus plugin to chain other CNI plugins.

  • You can configure or remove the ingress router.

MicroShift networking configuration matrix

The following table summarizes the status of networking features and capabilities that are either present as defaults, supported for configuration, or not available with the MicroShift service:

Table 1. MicroShift networking features and capabilities overview
Network capability Availability Configuration supported

Advertise address

Yes

Yes

Kubernetes network policy

Yes

Yes

Kubernetes network policy logs

Not available

N/A

Load balancing

Yes

Yes

Multicast DNS

Yes

Yes

Network proxies

Yes

CRI-O

Network performance

Yes

MTU configuration

Egress IPs

Not available

N/A

Egress firewall

Not available

N/A

Egress router

Not available

N/A

Firewall

No

Yes

Hardware offloading

Not available

N/A

Hybrid networking

Not available

N/A

IPsec encryption for intra-cluster communication

Not available

N/A

IPv6

Supported

N/A

Ingress router

Yes

Yes

Multiple networks plugin

Yes

Yes

Additional details about networking capabilities
  • Advertise address: If unset, the default value is set to the next immediate subnet after the service network. For example, when the service network is 10.43.0.0/16, the advertiseAddress is set to 10.44.0.0/32.

  • Multicast DNS: You can use the multicast DNS protocol (mDNS) to allow name resolution and service discovery within a Local Area Network (LAN) using multicast exposed on the 5353/UDP port.

  • Network proxies: There is no built-in transparent proxying of egress traffic in MicroShift. Egress must be manually configured.

  • Firewall: Setting up the firewalld service is supported by RHEL for Edge.

  • IPv6: Is supported in both single-stack and dual-stack networks with the OVN-Kubernetes network plugin. You can also use IPv6 by connecting to other networks with the MicroShift Multus CNI plugin.

  • Ingress router: Configure by using the MicroShift config.yaml file.

Default settings

Important

The Generic Device Plugin for MicroShift is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

For more information about the support scope of Red Hat Technology Preview features, see Technology Preview Features Support Scope.

When no config.yaml or configuration snippet exists, MicroShift uses built-in default values. To view these defaults, run microshift show-config.

The following example shows the default configuration settings.

Procedure
  • To see the default values, run the following command:

    $ microshift show-config
    Default values example output in YAML form
    apiServer:
      advertiseAddress: 10.44.0.0/32
      auditLog:
        maxFileAge: 0
        maxFileSize: 200
        maxFiles: 10
        profile: Default
      namedCertificates:
        - certPath: ""
          keyPath: ""
          names:
            - ""
      subjectAltNames: []
      tls:
        cipherSuites:
        minVersion: VersionTLS12
    debugging:
      logLevel: "Normal"
    dns:
      baseDomain: microshift.example.com
    etcd:
      memoryLimitMB: 0
    genericDevicePlugin:
        devices:
            - groups:
                - count: 1
                  paths:
                    - limit: 1
                      mountPath: /dev/ttyACM0
                      path: /dev/ttyACM0
                      permissions: mrw
                      readOnly: false
                      type: Device
                  usbs:
                    - product: ""
                      serial: ""
                      vendor: ""
              name: serial
        domain: device.microshift.io
        status: Disabled
    ingress:
      accessLogging:
        destination:
          type:
          container:
            maxLength: 1024
          syslog:
            address: ""
            facility: ""
            maxLength: 1024
            port: 0
            type: ""
        httpCaptureCookies:
          - matchType: ""
            maxLength: 0
            name: ""
            namePrefix: ""
        httpCaptureHeaders:
          request:
            - maxLength: 0
              name: ""
          response:
            - maxLength: 0
              name: ""
        httpLogFormat: ""
        status: Disabled
      certificateSecret: router-certs-default
      clientTLS:
        allowedSubjectPatterns:
        clientCA:
          name: ""
        clientCertificatePolicy: ""
      defaultHTTPVersion: 1
      forwardedHeaderPolicy: ""
      httpCompression:
        mimeTypes:
          - ""
      httpEmptyRequestsPolicy: Respond
      httpErrorCodePages:
          name: ""
      listenAddress: []
      logEmptyRequests: Log
      ports:
        http: 80
        https: 443
      routeAdmissionPolicy:
        namespaceOwnership: InterNamespaceAllowed
        wildcardPolicy: WildcardPolicyAllowed
      status: Managed
      tlsSecurityProfile:
        type: Intermediate
      tuningOptions:
          clientFinTimeout: "1s"
          clientTimeout: "30s"
          headerBufferBytes: 0
          headerBufferMaxRewriteBytes: 0
          healthCheckInterval: "5s"
          maxConnections: 0
          serverFinTimeout: "1s"
          serverTimeout: "30s"
          threadCount: 0
          tlsInspectDelay: "5s"
          tunnelTimeout: "1h"
    kubelet:
    manifests:
      kustomizePaths:
        - /usr/lib/microshift/manifests
        - /usr/lib/microshift/manifests.d/*
        - /etc/microshift/manifests
        - /etc/microshift/manifests.d/*
    network:
      clusterNetwork:
        - 10.42.0.0/16
      cniPlugin: ""
      multus:
        status: Disabled
      serviceNetwork:
        - 10.43.0.0/16
      serviceNodePortRange: 30000-32767
    node:
      hostnameOverride: ""
      nodeIP: ""
      nodeIPv6: ""
    storage:
      driver: ""
      optionalCsiComponents:
        - ""
    telemetry:
      endpoint: https://infogw.api.openshift.com
      proxy: ""
      status: Enabled

    where:

    apiserver.advertiseAddress

    Specifies the address of the service network.

    network.multus.status

    Specifies the status of the Multus Container Network Interface (CNI).

    node.nodeIP

    Specifies the IP address of the default route.

    storage.driver

    Specifies the storage driver to use. Default null value deploys Logical Volume Managed Storage (LVMS).

    storage.optionalCsiComponents

    Specifies the CSI components to deploy. Default null value deploys snapshot-controller.

Network features

Understand which networking feature are available and which are not for your MicroShift deployments.

Networking features available with MicroShift 4.22 include:

  • Kubernetes network policy

  • Dynamic node IP

  • Custom gateway interface

  • Second gateway interface

  • Node network on specified host interface

  • Blocking external access to NodePort service on specific host interfaces

Networking features not available with MicroShift 4.22:

  • Egress IP/firewall/QoS: disabled

  • Hybrid networking: not supported

  • IPsec: not supported

  • Hardware offload: not supported

IP forward

You must use ip_forward to access network connectivity.

The host network sysctl net.ipv4.ip_forward kernel parameter is automatically enabled by the ovnkube-master container when started. This is required to forward incoming traffic to the CNI. For example, accessing the NodePort service from outside of a node fails if ip_forward is disabled.

MicroShift networking components and services

Understand networking components and services and their operation in MicroShift.

Note

The microshift-networking RPM is a package that automatically pulls in any networking-related dependencies and systemd services to initialize networking, for example, the microshift-ovs-init systemd service.

NetworkManager

NetworkManager is required to set up the initial gateway bridge on the MicroShift node. The NetworkManager and NetworkManager-ovs RPM packages are installed as dependencies to the microshift-networking RPM package, which contains the necessary configuration files. NetworkManager in MicroShift uses the keyfile plugin and is restarted after installation of the microshift-networking RPM package.

microshift-ovs-init

The microshift-ovs-init.service is installed by the microshift-networking RPM package as a dependent systemd service to microshift.service. It is responsible for setting up the OVS gateway bridge.

OVN containers

Two OVN-Kubernetes daemon sets are rendered and applied by MicroShift.

  • ovnkube-master Includes the northd, nbdb, sbdb and ovnkube-master containers.

  • ovnkube-node The ovnkube-node includes the OVN-Controller container.

    After MicroShift starts, the OVN-Kubernetes daemon sets are deployed in the openshift-ovn-kubernetes namespace.

Packaging

OVN-Kubernetes manifests and startup logic are built into MicroShift. The systemd services and configurations included in the microshift-networking RPM are:

  • /etc/NetworkManager/conf.d/microshift-nm.conf for NetworkManager.service

  • /etc/systemd/system/ovs-vswitchd.service.d/microshift-cpuaffinity.conf for ovs-vswitchd.service

  • /etc/systemd/system/ovsdb-server.service.d/microshift-cpuaffinity.conf for ovs-server.service

  • /usr/bin/configure-ovs-microshift.sh for microshift-ovs-init.service

  • /usr/bin/configure-ovs.sh for microshift-ovs-init.service

  • /etc/crio/crio.conf.d/microshift-ovn.conf for the CRI-O service

Bridge mappings

Understand how provider network traffic reaches the physical network through bridge mappings. The following concepts apply:

  • Traffic leaves the provider network and arrives at the br-int bridge.

  • A patch port between br-int and br-ex then allows the traffic to traverse to and from the provider network and the edge network.

  • Kubernetes pods are connected to the br-int bridge through a virtual ethernet pair. One end of the virtual ethernet pair is attached to the pod namespace, and the other end is attached to the br-int bridge.

Network topology

OVN-Kubernetes provides an overlay-based networking implementation. This overlay includes an OVS-based implementation of Service and NetworkPolicy resources.

The overlay network uses the Geneve (Generic Network Virtualization Encapsulation) tunnel protocol. The pod maximum transmission unit (MTU) for the Geneve tunnel is set to the default route MTU if it is not configured.

To configure the MTU, you must set an equal-to or less-than value than the MTU of the physical interface on the host. A less-than value for the MTU makes room for the required information that is added to the tunnel header before it is transmitted.

Important

The MTU value of the OVN overlay networking in MicroShift must be 100 bytes smaller than the MTU value of the base network. If no MTU value is configured, MicroShift autoconfigures the value using the MTU value of the default gateway (Internet Protocol version 4 (IPv4) or Internet Protocol version 6 (IPv6)) of the host. If the auto-configuration does not work correctly, the MTU value can be configured manually. For example, if the MTU value of the network is 9000, the OVN MTU size must be set to 8900.

OVS runs as a systemd service on the MicroShift node. The OVS RPM package is installed as a dependency to the microshift-networking RPM package. OVS starts immediately when the microshift-networking RPM is installed.

317 RHbM OVN topology 0923

Description of the OVN logical components of the virtualized network
OVN node switch

A virtual switch named <node-name>. The OVN node switch is named according to the hostname of the node.

  • In this example, the node-name is microshift-dev.

OVN cluster router

A virtual router named ovn_cluster_router, also known as the distributed router.

  • In this example, the node network is 10.42.0.0/16.

OVN join switch

A virtual switch named join.

OVN gateway router

A virtual router named GR_<node-name>, also known as the external gateway router.

OVN external switch

A virtual switch named ext_<node-name>.

Description of the connections in the network topology figure
  • The north-south traffic between the network service and the OVN external switch ext_microshift-dev is provided through the host kernel by the gateway bridge br-ex.

  • The OVN gateway router GR_microshift-dev is connected to the external network switch ext_microshift-dev through the logical router port 4. Port 4 is attached with the node IP address 192.168.122.14.

  • The join switch join connects the OVN gateway router GR_microshift-dev to the OVN cluster router ovn_cluster_router. The IP address range is 100.62.0.0/16.

    • The OVN gateway router GR_microshift-dev connects to the OVN join switch join through the logical router port 3. Port 3 attaches with the internal IP address 100.64.0.2.

    • The OVN cluster router ovn_cluster_router connects to the join switch join through the logical router port 2. Port 2 attaches with the internal IP address 100.64.0.1.

  • The OVN cluster router ovn_cluster_router connects to the node switch microshift-dev through the logical router port 1. Port 1 is attached with the OVN cluster network IP address 10.42.0.1.

  • The east-west traffic between the pods and the network service is provided by the OVN cluster router ovn_cluster_router and the node switch microshift-dev. The IP address range is 10.42.0.0/24.

  • The east-west traffic between pods is provided by the node switch microshift-dev without network address translation (NAT).

  • The north-south traffic between the pods and the external network is provided by the OVN cluster router ovn_cluster_router and the host network. This router is connected through the ovn-kubernetes management port ovn-k8s-mp0, with the IP address 10.42.0.2.

  • All the pods are connected to the OVN node switch through their interfaces.

    • In this example, Pod 1 and Pod 2 are connected to the node switch through Interface 1 and Interface 2.

Customize networking configuration

After installing MicroShift, customize the default networking settings to match your edge deployment needs. You can configure OVN-Kubernetes options, IPv6 networking, HTTP proxy settings, and hostname resolution.

Create an OVN-Kubernetes configuration file

MicroShift uses built-in default OVN-Kubernetes values if an OVN-Kubernetes configuration file is not created. To apply custom OVN-Kubernetes values such as pod mtu instead of using built-in defaults, you can copy ovn.yaml.default to /etc/microshift/ovn.yaml and edit the file.

Procedure
  1. To create your ovn.yaml file, run the following command:

    $ sudo cp /etc/microshift/ovn.yaml.default /etc/microshift/ovn.yaml
  2. To list the contents of the configuration file you created, run the following command:

    $ cat /etc/microshift/ovn.yaml
    Example YAML file with default maximum transmission unit (MTU) value
    mtu: 1400
  3. To customize your configuration, you can change the MTU value. The table that follows provides details:

    Table 2. Supported optional OVN-Kubernetes configurations for MicroShift
    Field Type Default Description Example

    mtu

    uint32

    auto

    MTU value used for the pods

    1300

    Important

    If you change the mtu configuration value in the ovn.yaml file, you must restart the host that {product-title} is running on to apply the updated setting.

    Example custom ovn.yaml configuration file
    mtu: 1300

Restart the ovnkube-master pod

To replace the ovnkube-master pod with a new instance on MicroShift, you can delete the existing pod in the openshift-ovn-kubernetes namespace. Confirm that a new pod appears when you list pods in that namespace.

Prerequisites
  • The OpenShift CLI (oc) is installed.

  • You have root access to the node.

  • A node installed on infrastructure configured with the OVN-Kubernetes network plugin.

  • The KUBECONFIG environment variable is set.

Procedure
  1. Access the remote node by running the following command:

    $ export KUBECONFIG=$PWD/kubeconfig
  2. Find the name of the ovnkube-master pod that you want to restart by running the following command:

    $ pod=$(oc get pods -n openshift-ovn-kubernetes | awk -F " " '/ovnkube-master/{print $1}')
  3. Delete the ovnkube-master pod by running the following command:

    $ oc -n openshift-ovn-kubernetes delete pod $pod
  4. Confirm that a new ovnkube-master pod is running by using the following command:

    $ oc get pods -n openshift-ovn-kubernetes

    The listing of the running pods shows a new ovnkube-master pod name and age.

Configure the advertise address network flag

The apiserver.advertiseAddress flag specifies the IP address on which to advertise the API server to members of the node. This address must be reachable by the node. You can set a custom IP address here, but you must also add the IP address to a host interface. Customizing this parameter preempts MicroShift from adding a default IP address to the br-ex network interface.

Important

If you customize the advertiseAddress IP address, make sure it is reachable by the node when MicroShift starts by adding the IP address to a host interface.

If unset, the default value is set to the next immediate subnet after the service network. For example, when the service network is 10.43.0.0/16, the advertiseAddress is set to 10.44.0.0/32.

Extending the port range for NodePort services

The serviceNodePortRange setting extends the port range available to NodePort services. This option is useful when specific standard ports under the 30000-32767 range need to be exposed. For example, if your device needs to expose the 1883/tcp MQ Telemetry Transport (MQTT) port on the network because client devices cannot use a different port.

Important

NodePorts can overlap with system ports, causing a malfunction of the system or MicroShift.

Consider the following when configuring the NodePort service ranges:

  • Do not create any NodePort service without an explicit nodePort selection. When an explicit nodePort is not specified, the port is assigned randomly by the kube-apiserver and cannot be predicted.

  • Do not create any NodePort service for any system service port, MicroShift port, or other services you expose on your device HostNetwork.

  • Table one specifies ports to avoid when extending the port range:

    Table 3. Ports to avoid.
    Port Description

    22/tcp

    SSH port

    80/tcp

    OpenShift Router HTTP endpoint

    443/tcp

    OpenShift Router HTTPS endpoint

    1936/tcp

    Metrics service for the openshift-router, not exposed today

    2379/tcp

    etcd port

    2380/tcp

    etcd port

    6443

    Kubernetes API

    8445/tcp

    openshift-route-controller-manager

    9537/tcp

    cri-o metrics

    10250/tcp

    kubelet

    10248/tcp

    kubelet healthz port

    10259/tcp

    kube scheduler

Configure custom hostnames

You can use the hosts file to resolve custom hostnames for pod workloads. This enables applications to resolve fixed hostnames, such as the local machine or external services, by applying /etc/hosts functionality to DNS queries within the node. The functionality is applied by adding specific configuration to the MicroShift configuration YAML file, and completing a service restart.

Prerequisites
  • You installed the OpenShift CLI (oc).

  • You have root access to the node.

Procedure
  1. Edit the MicroShift configuration in the /etc/microshift/config.yaml file.

  2. Add the following hosts configuration at the end of the file:

    dns:
     hosts:
       status: <Enabled|Disabled>
       file: <filepath>
  3. Save your configuration YAML file.

  4. Restart the MicroShift service to activate the configuration changes:

    $ sudo systemctl restart microshift

    After this initial restart, if dns.hosts.status is set to Enabled, MicroShift automatically monitors the dns.hosts.file file for updates. You do not have to restart the MicroShift service until the MicroShift configuration YAML file is changed again.

    Note

    After you save the /etc/hosts file, it takes up to 90 seconds for the change to be active in the pods. During this period, the pods might not properly resolve hostnames.

IPv6 networking with MicroShift

The {product-title} service defaults to IPv4. IPv6 single-stack and IPv4/IPv6 dual-stack networking is available on supported platforms. You configure IPv6 or dual-stack networking in the configuration file.

Consider the following when configuring IPv6 or dual-stack networking with MicroShift:

  • When you set the values for IPv6 in the MicroShift configuration file and restart the service, settings managed by the OVN-Kubernetes network plugin are updated automatically.

  • After migrating to dual-stack networking, both new and existing pods have dual-stack networking enabled.

  • If you require node-wide IPv6 access, such as for the control plane and other services, use the following configuration examples. The MicroShift Multus Container Network Interface (CNI) plugin can enable IPv6 for pods.

  • For dual-stack networking, each MicroShift node network and service network supports up to two values in the node and service network configuration parameters.

Important

Plan for IPv6 before starting MicroShift for the first time. Switching a node to and from different IP families is not supported unless you are migrating a node from default single-stack to dual-stack networking.

If you configure your networking for either IPv6 single stack or IPv4/IPv6 dual stack, you must restart application pods and services. Otherwise pods and services remain configured with the default IP family.

Configure IPv6 single-stack networking

To run MicroShift with IPv6-only networking, you can update the service configuration file and set the network section with your cluster and service CIDRs. You can verify the configuration by checking that pods and services use IPv6 addresses.

Prerequisites
  • You installed the OpenShift CLI (oc).

  • You have root access to the node.

  • Your node uses the OVN-Kubernetes network plugin.

  • The host has an IPv6 address and IPv6 routes, including the default.

Procedure
  1. If you have not done so, make a copy of the provided config.yaml.default file in the /etc/microshift/ directory, renaming it config.yaml.

  2. Keep the new MicroShift config.yaml in the /etc/microshift/ directory. Your config.yaml file is read every time the MicroShift service starts.

    Note

    After you create it, the config.yaml file takes precedence over built-in settings.

  3. Replace the default values in the network section of the MicroShift YAML with your valid values.

    Example single-stack IPv6 networking configuration
    apiServer:
    # ...
    network:
      clusterNetwork:
      - fd01::/48
      serviceNetwork:
      - fd02::/112
    node:
      nodeIP: 2600:1f14:1c48:ee00:2d76:3190:5bc2:5aef
    # ...

    where:

    networking.clusterNetwork

    Specifies a clusterNetwork address with a CIDR value that is less than 64. For example, fd01::/48.

    network.serviceNetwork

    Specifies an IPv6 CIDR with a prefix of 112, for example, fd02::/112. Kubernetes uses only the lowest 16 bits. For a prefix of 112, IP addresses are assigned from 112 to 128 bits.

    node.nodeIP

    Specifies a node IP address. Valid values are IP addresses in the IPv6 address family. You must only specify an IPv6 address when an IPv4 network is also present. If an IPv4 network is not present, the MicroShift service automatically fills in this value upon restart.

  4. Complete any other configurations you require, then start MicroShift by running the following command:

    $ sudo systemctl start microshift
Verification
  1. Retrieve the networks defined in the node resource by running the following command:

    $ oc get node -o jsonpath='{.items[].spec.podCIDRs[]}'
    Example output
    fd01::/48
  2. Retrieve the status of the pods by running the following command:

    $ oc get pod -A -o wide
    Example output
    NAMESPACE                  NAME                                      READY   STATUS    RESTARTS   AGE   IP                      NODE           NOMINATED NODE   READINESS GATES
    kube-system                csi-snapshot-controller-bb7cb654b-rqrt6   1/1     Running   0          65s   fd01:0:0:1::5           microshift-9   <none>           <none>
    openshift-dns              dns-default-cjn66                         2/2     Running   0          62s   fd01:0:0:1::9           microshift-9   <none>           <none>
    openshift-dns              node-resolver-ppnjb                       1/1     Running   0          63s   2001:db9:ca7:ff::1db8   microshift-9   <none>           <none>
    openshift-ingress          router-default-6d97d7b8b6-wdtmg           1/1     Running   0          61s   fd01:0:0:1::8           microshift-9   <none>           <none>
    openshift-ovn-kubernetes   ovnkube-master-gfvp5                      4/4     Running   0          63s   2001:db9:ca7:ff::1db8   microshift-9   <none>           <none>
    openshift-ovn-kubernetes   ovnkube-node-bnpjh                        1/1     Running   0          63s   2001:db9:ca7:ff::1db8   microshift-9   <none>           <none>
    openshift-service-ca       service-ca-5d7bd9db6-j25bd                1/1     Running   0          60s   fd01:0:0:1::4           microshift-9   <none>           <none>
    openshift-storage          lvms-operator-656cd9b59b-bwr47            1/1     Running   0          63s   fd01:0:0:1::7           microshift-9   <none>           <none>
    openshift-storage          vg-manager-f7dmk                          1/1     Running   0          27s   fd01:0:0:1::a           microshift-9   <none>           <none>
  3. Retrieve the status of services by running the following command:

    $ oc get svc -A
    Example output
    NAMESPACE           NAME                            TYPE           CLUSTER-IP   EXTERNAL-IP                                             PORT(S)                      AGE
    default             kubernetes                      ClusterIP      fd02::1      <none>                                                  443/TCP                      3m42s
    openshift-dns       dns-default                     ClusterIP      fd02::a      <none>                                                  53/UDP,53/TCP,9154/TCP       2m58s
    openshift-ingress   router-default                  LoadBalancer   fd02::f2e6   2001:db9:ca7:ff::1db8,fd01:0:0:1::2,fd02::1:0,fd69::2   80:31133/TCP,443:31996/TCP   2m58s
    openshift-ingress   router-internal-default         ClusterIP      fd02::c55e   <none>                                                  80/TCP,443/TCP,1936/TCP      2m58s
    openshift-storage   lvms-operator-metrics-service   ClusterIP      fd02::7afb   <none>                                                  443/TCP                      2m58s
    openshift-storage   lvms-webhook-service            ClusterIP      fd02::d8dd   <none>                                                  443/TCP                      2m58s
    openshift-storage   vg-manager-metrics-service      ClusterIP      fd02::fc1    <none>                                                  443/TCP                      2m58s

Configure IPv6 dual-stack networking before MicroShift starts

To run your MicroShift node with IPv4 and IPv6 dual-stack networking, you can configure the network section in the configuration file before starting the service.

  • The first IP family in the configuration is the primary IP stack in the node.

  • After the node is running with dual-stack networking, enable application pods and add-on services for dual-stack by restarting them.

Important

The OVN-Kubernetes network plugin requires that both IPv4 and IPv6 default routes be on the same network device. IPv4 and IPv6 default routes on separate network devices is not supported.

Important

When using dual-stack networking where IPv6 is required, you cannot use IPv4-mapped IPv6 addresses, such as ::FFFF:198.51.100.1.

Prerequisites
  • You installed the OpenShift CLI (oc).

  • You have root access to the node.

  • Your node uses the OVN-Kubernetes network plugin.

  • The host has both IPv4 and IPv6 addresses and routes, including a default for each.

  • The host has at least two L3 networks, IPv4 and IPv6.

Procedure
  1. If you have not done so, make a copy of the provided config.yaml.default file in the /etc/microshift/ directory, renaming it config.yaml.

  2. Keep the new MicroShift config.yaml in the /etc/microshift/ directory. Your config.yaml file is read every time the MicroShift service starts.

    Note

    After you create it, the config.yaml file takes precedence over built-in settings.

  3. If you have not started MicroShift, replace the default values in the network section of the MicroShift YAML with your valid values.

    Example dual-stack IPv6 networking configuration with network assignments
    apiServer:
    # ...
    apiServer:
      subjectAltNames:
      - 192.168.113.117
      - 2001:db9:ca7:ff::1db8
    network:
      clusterNetwork:
      - 10.42.0.0/16
      - fd01::/48
      serviceNetwork:
      - 10.43.0.0/16
      - fd02::/112
    node:
      nodeIP: 192.168.113.117
      nodeIPv6: 2001:db9:ca7:ff::1db8
    # ...

    where:

    network.clusterNetwork

    Specifies an IPv6 clusterNetwork with a CIDR value that is less than 64.

    network.serviceNetwork

    Specifies an IPv6 CIDR with a prefix of 112. Kubernetes uses only the lowest 16 bits. For a prefix of 112, IP addresses are assigned from 112 to 128 bits.

    node.nodeIP

    Specifies an IPv4 address family.

    node.nodeIPv6

    Specifies an IPv6 address family. Configurable only with dual-stack networking.

  4. Complete any other MicroShift configurations you require, then start MicroShift by running the following command:

    $ sudo systemctl start microshift
  5. Reset the IP family policy for application pods and services as needed, then restart those application pods and services to enable dual-stack networking. See "Resetting the IP family policy for application pods and services" for a simple example.

Verification
  1. You can verify that all of the system services and pods to have two IP addresses, one for each family, by using the following steps:

    1. Retrieve the networks defined in the node resource by running the following command:

      $ oc get pod -n openshift-ingress router-default-5b75594b4-w7w6s -o jsonpath='{.status.podIPs}'
      Example output
      [{"ip":"10.42.0.4"},{"ip":"fd01:0:0:1::4"}]
    2. Retrieve the networks defined by the host network pods by running the following command:

      $ oc get pod -n openshift-ovn-kubernetes ovnkube-master-2fm2k -o jsonpath='{.status.podIPs}'
      Example output
      [{"ip":"192.168.113.117"},{"ip":"2001:db9:ca7:ff::1db8"}]

Migrating a MicroShift node to IPv6 dual-stack networking

To convert a single-stack node to dual-stack node networking that supports IPv4 and IPv6 address families, set two entries in the service and node network parameters in the MicroShift configuration file and restart the service.

  • The first IP family in the configuration is the primary IP stack in the node.

  • MicroShift system pods and services are automatically updated upon MicroShift restart.

  • After the node is migrated to dual-stack networking and has restarted, enable workload pods and services for dual-stack networking by restarting them.

Important

The OVN-Kubernetes network plugin requires that both IPv4 and IPv6 default routes be on the same network device. IPv4 and IPv6 default routes on separate network devices is not supported.

Important

When using dual-stack networking where IPv6 is required, you cannot use IPv4-mapped IPv6 addresses, such as ::FFFF:198.51.100.1.

Prerequisites
  • You installed the OpenShift CLI (oc).

  • You have root access to the node.

  • Your node uses the OVN-Kubernetes network plugin.

  • The host has both IPv4 and IPv6 addresses and routes, including a default for each.

  • The host has at least two L3 networks, IPv4 and IPv6.

Procedure
  1. If you have not done so, make a copy of the provided config.yaml.default file in the /etc/microshift/ directory, renaming it config.yaml.

  2. Keep the new MicroShift config.yaml in the /etc/microshift/ directory. Your config.yaml file is read every time the MicroShift service starts.

    Note

    After you create it, the config.yaml file takes precedence over built-in settings.

  3. Add IPv6 configurations to the network section of the MicroShift YAML with your valid values:

    Warning

    You must keep the same first entry across restarts and migrations. This is true for any migration: single-to-dual stack, or dual-to-single stack. A complete wipe of the etcd database is required if a change to the first entry is needed. This might result in application data loss and is not supported.

    1. Add an IPv6 configuration for a second network in the network section of the MicroShift YAML with your valid values.

    2. Add network assignments to the network section of the MicroShift config.yaml to enable dual stack with IPv6 as secondary network.

      Example dual-stack IPv6 configuration with network assignments
      # ...
      apiServer:
        subjectAltNames:
        - 192.168.113.117
        - 2001:db9:ca7:ff::1db8
      network:
        clusterNetwork:
        - 10.42.0.0/16
        - fd01::/48
        serviceNetwork:
        - 10.43.0.0/16
        - fd02::/112
      node:
        nodeIP: 192.168.113.117
        nodeIPv6: 2001:db9:ca7:ff::1db8
      # ...

      where:

      2001:db9:ca7:ff::1db8

      Specifies an IPv6 node address.

      10.42.0.0/16

      Specifies an IPv4 clusterNetwork address with a CIDR value that is less than 24.

      fd01::/48

      Specifies an IPv6 clusterNetwork address with a CIDR value that is less than 64.

      fd02::/112

      Specifies an IPv6 CIDR with a prefix of 112. Kubernetes uses only the lowest 16 bits. For a prefix of 112, IP addresses are assigned from 112 to 128 bits.

      192.168.113.117

      Specifies an IPv4 node IP address. Maintain the previous IPv4 IP address.

      2001:db9:ca7:ff::1db8

      Specifies an IPv6 node IP address. Must be an IPv6 address family.

  4. Complete any other configurations you require, then restart MicroShift by running the following command:

    $ sudo systemctl restart microshift
  5. Reset the IP family policy for application pods and services as needed, then restart those application pods and services to enable dual-stack networking. See "Resetting the IP family policy for application pods and services" for a simple example.

Verification

You can verify that all of the system services and pods to have two IP addresses, one for each family, by using the following steps:

  1. Retrieve the status of the pods by running the following command:

    $ oc get pod -A -o wide
    Example output
    NAMESPACE                  NAME                                      READY   STATUS    RESTARTS        AGE     IP                NODE           NOMINATED NODE   READINESS GATES
    kube-system                csi-snapshot-controller-bb7cb654b-7s5ql   1/1     Running   0               46m     10.42.0.6         microshift-9   <none>           <none>
    openshift-dns              dns-default-zxkqn                         2/2     Running   0               46m     10.42.0.5         microshift-9   <none>           <none>
    openshift-dns              node-resolver-r2h5z                       1/1     Running   0               46m     192.168.113.117   microshift-9   <none>           <none>
    openshift-ingress          router-default-5b75594b4-228z7            1/1     Running   0               2m5s    10.42.0.3         microshift-9   <none>           <none>
    openshift-ovn-kubernetes   ovnkube-master-bltk7                      4/4     Running   2 (2m32s ago)   2m36s   192.168.113.117   microshift-9   <none>           <none>
    openshift-ovn-kubernetes   ovnkube-node-9ghgs                        1/1     Running   2 (2m32s ago)   46m     192.168.113.117   microshift-9   <none>           <none>
    openshift-service-ca       service-ca-5d7bd9db6-qgwgw                1/1     Running   0               46m     10.42.0.7         microshift-9   <none>           <none>
    openshift-storage          lvms-operator-656cd9b59b-8rpf4            1/1     Running   0               46m     10.42.0.8         microshift-9   <none>           <none>
    openshift-storage          vg-manager-wqmh4                          1/1     Running   2 (2m39s ago)   46m     10.42.0.10        microshift-9   <none>           <none>
  2. Retrieve the networks defined by the OVN-K network plugin by running the following command:

    $ oc get pod -n openshift-ovn-kubernetes ovnkube-master-bltk7 -o jsonpath='{.status.podIPs}'
    Example output
    [{"ip":"192.168.113.117"},{"ip":"2001:db9:ca7:ff::1db8"}]
  3. Retrieve the networks defined in the node resource by running the following command:

    $ oc get pod -n openshift-ingress router-default-5b75594b4-228z7 -o jsonpath='{.status.podIPs}'
    Example output
    [{"ip":"10.42.0.3"},{"ip":"fd01:0:0:1::3"}]
    Note

    To return to single-stack networking, you can remove the second entry to the networks and return to the single stack that was configured before migrating to dual-stack.

Resetting the IP family policy for application pods and services

The default PreferSingleStack value does not change when you migrate the MicroShift node to dual-stack. To enable dual-stack networking in application pods and services on a node that uses dual-stack, set the ipFamilyPolicy field to PreferDualStack or RequireDualStack and restart the pods.

Prerequisites
  • You used the MicroShift config.yaml to define a dual-stack network with an IPv6 address family.

Procedure
  1. Set the spec.ipFamilyPolicy field to a valid value for dual-stack networking in your service or pod by using the following example:

    Example dual-stack network configuration for a service
    kind: Service
    apiVersion: v1
    metadata:
      name: microshift-new-service
      labels: app: microshift-application
    spec:
      type: NodePort
      ipFamilyPolicy: PreferDualStack
    # ...

    where:

    spec.ipFamilyPolicy

    Required. Specifies the IP family policy for the service. Valid values are PreferDualStack and RequireDualStack. The value you set depends on the requirements of your application. PreferSingleStack is the default value for the ipFamilyPolicy field.

  2. Restart any application pods that do not have a hostNetwork defined. Pods that do have a hostNetwork defined do not need to be restarted to update the ipFamilyPolicy value.

    Note

    MicroShift system services and pods are automatically updated when the ipFamilyPolicy value is updated.

OVN-Kubernetes IPv6 and dual-stack limitations

The OVN-Kubernetes network plugin has specific IPv6 and dual-stack networking configuration limitations. These limitations affect gateway configuration, routing layouts, and infrastructure environment stability.

  • For clusters configured for dual-stack networking, both IPv4 and IPv6 traffic must use the same network interface as the default gateway.

    If this requirement is not met, pods on the host in the ovnkube-node daemon set enter the CrashLoopBackOff state.

    If you display a pod with a command such as oc get pod -n openshift-ovn-kubernetes -l app=ovnkube-node -o yaml, the status field has more than one message about the default gateway, as shown in the following output:

    I1006 16:09:50.985852   60651 helper_linux.go:73] Found default gateway interface br-ex 192.168.127.1
    I1006 16:09:50.985923   60651 helper_linux.go:73] Found default gateway interface ens4 fe80::5054:ff:febe:bcd4
    F1006 16:09:50.985939   60651 ovnkube.go:130] multiple gateway interfaces detected: br-ex ens4

    The only resolution is to reconfigure the host networking so that both IP families use the same network interface for the default gateway.

  • For clusters configured for dual-stack networking, both the IPv4 and IPv6 routing tables must contain the default gateway.

    If this requirement is not met, pods on the host in the ovnkube-node daemon set enter the CrashLoopBackOff state.

    If you display a pod with a command such as oc get pod -n openshift-ovn-kubernetes -l app=ovnkube-node -o yaml, the status field has more than one message about the default gateway, as shown in the following output:

    I0512 19:07:17.589083  108432 helper_linux.go:74] Found default gateway interface br-ex 192.168.123.1
    F0512 19:07:17.589141  108432 ovnkube.go:133] failed to get default gateway interface

    The only resolution is to reconfigure the host networking so that both IP families contain the default gateway.

  • If you set the ipv6.disable parameter to 1 in the kernelArgument section of the MachineConfig custom resource (CR) for your cluster, OVN-Kubernetes pods enter a CrashLoopBackOff state. Additionally, updating your cluster to a later version of {product-title} fails because the Network Operator remains on a Degraded state. Red Hat does not support disabling IPv6 addresses for your cluster so do not set the ipv6.disable parameter to 1.

Deploy MicroShift behind an HTTP or HTTPS proxy

To add basic anonymity and security measures to your pods, you can deploy MicroShift behind an HTTP or HTTPS proxy.

You must configure the host operating system to use the proxy service with all components initiating HTTP or HTTPS requests when deploying MicroShift behind a proxy.

All the user-specific workloads or pods with egress traffic, such as accessing cloud services, must be configured to use the proxy. There is no built-in transparent proxying of egress traffic in MicroShift.

Use the RPM-OStree HTTP or HTTPS proxy

To use the HTTP or HTTPS proxy in RPM-OStree, add a Service section to the configuration file and set the http_proxy environment variable for the rpm-ostreed service.

Procedure
  1. Add this setting to the /etc/systemd/system/rpm-ostreed.service.d/00-proxy.conf file:

    [Service]
    Environment="http_proxy=http://$PROXY_USER:$PROXY_PASSWORD@$PROXY_SERVER:$PROXY_PORT/"
  2. Next, reload the configuration settings and restart the service to apply your changes.

    1. Reload the configuration settings by running the following command:

      $ sudo systemctl daemon-reload
    2. Restart the rpm-ostreed service by running the following command:

      $ sudo systemctl restart rpm-ostreed.service

The multicast DNS protocol

To allow name resolution and service discovery within a Local Area Network (LAN) using multicast exposed on the 5353/UDP port, you can use the multicast DNS protocol (mDNS).

MicroShift includes an embedded mDNS server for deployment scenarios in which the authoritative DNS server cannot be reconfigured to point clients to services on MicroShift. The embedded DNS server allows .local domains exposed by MicroShift to be discovered by other elements on the LAN.

Lower latency in MicroShift applications

Latency is the time from an event to its response. You can optimize low latency performance on a MicroShift node by combining configurations, operating system tuning, and workload partitioning to ensure edge devices respond quickly.

Important

The CPU set for management applications, such as the MicroShift service, OVS, CRI-O, MicroShift pods, and isolated cores, must contain all-online CPUs.

Workflow for configuring low latency for MicroShift applications

To configure low latency for applications running in a MicroShift node, you must complete the following tasks:

Required
  • Install the microshift-low-latency RPM.

  • Configure workload partitioning.

  • Configure the kubelet section of the config.yaml file in the /etc/microshift/ directory.

  • Configure and activate a TuneD profile. TuneD is a Red Hat Enterprise Linux (RHEL) service that monitors the host system and optimizes performance under certain workloads.

  • Restart the host.

Optional

Install the MicroShift low latency RPM package

When you install MicroShift, the low latency RPM package is not installed by default. You can install the low latency RPM as an optional package.

Prerequisites
  • You installed the MicroShift RPM.

  • You configured workload partitioning for MicroShift.

Procedure
  • Install the low latency RPM package by running the following command:

    $ sudo dnf install -y microshift-low-latency
    Tip

    Wait to restart the host until after activating your TuneD profile. Restarting the host restarts MicroShift and CRI-O, which applies the low latency manifests and activates the TuneD profile.

Next steps
  1. Configure the kubelet parameter for low latency in the MicroShift config.yaml.

  2. Tune your operating system, for example, configure and activate a TuneD profile.

  3. Optional: Configure automatic activation of your TuneD profile.

  4. Optional: If you are using the x86_64 architecture, install Red Hat Enterprise Linux for Real Time (real-time kernel).

  5. Prepare your workloads for low latency.

Configure kubelet parameters and values in MicroShift

To enable low latency on a MicroShift node, add the required settings to the MicroShift config.yaml file.

Prerequisites
  • You installed the OpenShift CLI (oc).

  • You have root access to the node.

  • You made a copy of the provided config.yaml.default file in the /etc/microshift/ directory, and renamed it config.yaml.

Procedure
  • Add the kubelet configuration to the MicroShift config.yaml file:

    Example passthrough kubelet configuration
    apiServer:
    # ...
    kubelet:
      cpuManagerPolicy: static
      cpuManagerPolicyOptions:
        full-pcpus-only: "true"
      cpuManagerReconcilePeriod: 5s
      memoryManagerPolicy: Static
      topologyManagerPolicy: single-numa-node
      reservedSystemCPUs: 0-1
      reservedMemory:
      - limits:
          memory: 1100Mi
        numaNode: 0
      kubeReserved:
        memory: 500Mi
      systemReserved:
        memory: 500Mi
      evictionHard:
        imagefs.available: "15%"
        memory.available: "100Mi"
        nodefs.available: "10%"
        nodefs.inodesFree: "5%"
      evictionPressureTransitionPeriod: 5m
    # ...
    kubelet

    If you change the CPU or memory managers in the kubelet configuration, you must remove files that cache the previous configuration. Restart the host to remove them automatically, or manually remove the /var/lib/kubelet/cpu_manager_state and /var/lib/kubelet/memory_manager_state files.

    kubelet.cpuManagerPolicy

    The name of the policy to use. Valid values are none and static. Requires the CPUManager feature gate to be enabled. Default value is none.

    kubelet.cpuManagerPolicyOptions.full-pcpus-only

    A set of key=value pairs for setting extra options that fine tune the behavior of the CPUManager policies. The default value is null. Requires both the CPUManager and CPUManagerPolicyOptions feature gates to be enabled.

    kubelet.memoryManagerPolicy

    The name of the policy used by Memory Manager. Case-sensitive. The default value is none. Requires the MemoryManager feature gate to be enabled.

    kubelet.reservedSystemCPUs

    Required. The reservedSystemCPUs value must be the inverse of the offlined CPUs because both values combined must account for all of the CPUs on the system. This parameter is essential to dividing the management and application workloads. Use this parameter to define a static CPU set for the host-level system and Kubernetes daemons, plus interrupts and timers. Then the rest of the CPUs on the system can be used exclusively for workloads.

    kubelet.reservedMemory[0].limits.memory

    The value in reservedMemory[0].limits.memory, 1100 Mi in this example, is equal to kubeReserved.memory + systemReserved.memory + evictionHard.memory.available.

    kubelet.evictionHard

    The evictionHard parameters define under which conditions the kubelet evicts pods. When you change the default value of only one parameter for the evictionHard stanza, the default values of other parameters are not inherited and are set to zero. Provide all the threshold values even when you want to change just one.

    kubelet.evictionHard.imagefs.available

    The imagefs is a filesystem that container runtimes use to store container images and container writable layers. In this example, the evictionHard.imagefs.available parameter means that the pod is evicted when the available space of the image filesystem is less than 15%.

    kubelet.evictionHard.memory.available

    In this example, the evictionHard.memory.available parameter means that the pods are evicted when the available memory of the node drops below 100MiB.

    kubelet.evictionHard.nodefs.available

    In this example, the evictionHard.nodefs.available parameter means that the pods are evicted when the main filesystem of the node has less than 10% available space.

    kubelet.evictionHard.nodefs.inodesFree

    In this example, the evictionHard.nodefs.inodesFree parameter means that the pods are evicted when more than 15% of the node’s main filesystem’s inodes are in use.

    kubelet.evictionPressureTransitionPeriod

    For container garbage collection: The duration to wait before transitioning out of an eviction pressure condition. Setting the evictionPressureTransitionPeriod parameter to 0 configures the default value of 5 minutes.

Verification
  • After you complete the next steps and restart the host, you can use a root-access account to check that your settings are in the config.yaml file in the /var/lib/microshift/resources/kubelet/config/ directory.

Next steps
  1. Enable workload partitioning.

  2. Tune your operating system. For example, configure and activate a TuneD profile.

  3. Optional: Configure automatic enablement of your TuneD profile.

  4. Optional: If you are using the x86_64 architecture, you can install Red Hat Enterprise Linux for Real Time (real-time kernel).

  5. Prepare your MicroShift workloads for low latency.

Enable last-level cache locality in MicroShift

You can align workloads with CPU cores that share the same last-level cache (LLC) to improve performance for latency-sensitive applications. To apply this alignment, enable the Kubernetes CPU Manager option prefer-align-cpus-by-uncorecache.

Important

Last-level cache (LLC) locality is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

For more information about the support scope of Red Hat Technology Preview features, see Technology Preview Features Support Scope.

Warning

This feature is part of a feature gate. After you enable feature gates, you cannot disable them or update Red Hat build of MicroShift (MicroShift), and your cluster can become unstable or lose data. Enable feature gates only in non-production environments.

Procedure
  1. Add the following content to /etc/microshift/config.yaml. If you already have a kubelet section from the earlier section, merge the cpuManagerPolicyOptions entry and ensure the feature gate is present.

    apiServer:
      featureGates:
        featureSet: "CustomNoUpgrade"
        customNoUpgrade:
          enabled:
          - "CPUManagerPolicyBetaOptions"
    kubelet:
      reservedSystemCPUs: "0"
      cpuManagerPolicy: static
      cpuManagerPolicyOptions:
        prefer-align-cpus-by-uncorecache: "true"
  2. To apply the configuration, restart MicroShift by running the following command:

    $ sudo systemctl restart microshift

Tuning Red Hat Enterprise Linux 9

As a Red Hat Enterprise Linux (RHEL) system administrator, you can use the TuneD service to optimize the performance profile of RHEL for a variety of use cases. TuneD monitors and optimizes system performance under certain workloads, including latency performance.

  • Use TuneD profiles to tune your system for different use cases, such as deploying a low-latency MicroShift node.

  • You can modify the rules defined for each profile and customize tuning for a specific device.

  • When you switch to another profile or deactivate TuneD, all changes made to the system settings by the previous profile revert back to their original state.

  • You can also configure TuneD to react to changes in device usage and adjusts settings to improve performance of active devices and reduce power consumption of inactive devices.

Configure the MicroShift TuneD profile

To use low latency with MicroShift workloads, configure a TuneD profile for your host by using the microshift-baseline-variables.conf file provided in the /etc/tuned/ directory.

Prerequisites
  • You have root access to the node.

  • You installed the microshift-low-latency RPM package.

  • Your RHEL host has TuneD installed. See Getting started with TuneD (RHEL documentation).

Procedure
  1. You can use the default microshift-baseline-variables.conf TuneD profile in the /etc/tuned/ directory profile, or create your own to add more tunings.

    Example microshift-baseline-variables.conf TuneD profile
    # Isolate cores 2-7 for running application workloads
    isolated_cores=2-7
    
    # Size of the hugepages
    hugepages_size=2M
    
    # Number of hugepages
    hugepages=0
    
    # Additional kernel arguments
    additional_args=
    
    # CPU set to be offlined
    offline_cpu_set=
    isolated_cores

    Controls which cores should be isolated. By default, 1 core per socket is reserved in MicroShift for housekeeping. The other cores are isolated. Valid values are a core list or range. You can isolate any range, for example: isolated_cores=2,4-7 or isolated_cores=2-23.

    Important

    You must keep only one isolated_cores= variable.

    Note

    The Kubernetes CPU manager can use any CPU to run the workload except the reserved CPUs defined in the kubelet configuration. For this reason it is best that:

    • The sum of the kubelet’s reserved CPUs and isolated cores include all online CPUs.

    • Isolated cores are complementary to the reserved CPUs defined in the kubelet configuration.

    hugepages_size

    Size of the hugepages. Valid values are 2M or 1G.

    additional_args

    Additional kernel arguments, for example, additional_args=console=tty0 console=ttyS0,115200.

    offline_cpu_set

    The CPU set to be offlined.

    Important

    Must not overlap with isolated_cores.

  2. Enable the profile or make changes active, by running the following command:

    $ sudo tuned-adm profile microshift-baseline
  3. Reboot the host to make kernel arguments active.

Verification
  • Optional: You can read the /proc/cmdline file that contains the arguments given to the currently running kernel on start.

    $ cat /proc/cmdline
    Example output
    BOOT_IMAGE=(hd0,msdos2)/ostree/rhel-7f82ccd9595c3c70af16525470e32c6a81c9138c4eae6c79ab86d5a2d108d7fc/vmlinuz-5.14.0-427.31.1.el9_4.x86_64+rt crashkernel=1G-4G:192M,4G-64G:256M,64G-:512M rd.lvm.lv=rhel/root fips=0 console=ttyS0,115200n8 root=/dev/mapper/rhel-root rw ostree=/ostree/boot.1/rhel/7f82ccd9595c3c70af16525470e32c6a81c9138c4eae6c79ab86d5a2d108d7fc/0 skew_tick=1 tsc=reliable rcupdate.rcu_normal_after_boot=1 nohz=on nohz_full=2,4-5 rcu_nocbs=2,4-5 tuned.non_isolcpus=0000000b intel_pstate=disable nosoftlockup hugepagesz=2M hugepages=10
Next steps
  1. Prepare your MicroShift workloads for low latency.

  2. Optional: Configure automatic enablement of your TuneD profile.

  3. Optional: If you are using the x86_64 architecture, you can install Red Hat Enterprise Linux for Real Time (real-time kernel).

Automatically enable the MicroShift TuneD profile

Included in the microshift-low-latency RPM package is a systemd service that you can configure to automatically enable a TuneD profile when the system starts. This ability is particularly useful if you are installing MicroShift in a large fleet of devices.

Prerequisites
  • You installed the microshift-low-latency RPM package on the host.

  • You enabled low latency in the MicroShift config.yaml.

  • You created a TuneD profile.

  • You configured the microshift-baseline-variables.conf file.

Procedure
  1. Configure the tuned.yaml in the /etc/microshift/ directory, for example:

    Example tuned.yaml:

    profile: microshift-baseline
    reboot_after_apply: True
    profile

    Controls which TuneD profile is activated. In this example, the name of the profile is microshift-baseline.

    reboot_after_apply

    Controls whether the host must be rebooted after applying the profile. Valid values are True and False. For example, use the True setting to automatically restart the host after a new ostree commit is deployed.

    Important

    The host is restarted when the microshift-tuned.service runs, but it does not restart the system when a new commit is deployed. You must restart the host to enable a new commit, then the system starts again when the microshift-tuned.service runs on that boot and detects changes to profiles and variables.

    This double-boot can affect rollbacks. Ensure that you adjust the number of reboots in greenboot that are allowed before rollback when using automatic profile activation. For example, if 3 reboots are allowed before a rollback in greenboot, increase that number to 4. See the "Additional resources" list for more information.

  2. Enable the microshift-tuned.service to run on each system start by entering the following command:

    $ sudo systemctl enable microshift-tuned.service
    Important

    If you set reboot_after_apply to True, ensure that a TuneD profile is active and that no other profiles have been activated outside of the MicroShift service. Otherwise, starting the microshift-tuned.service results in a host reboot.

  3. Start the microshift-tuned.service by running the following command:

    $ sudo systemctl start microshift-tuned.service
    Note

    The microshift-tuned.service uses collected checksums to detect changes to selected TuneD profiles and variables. If there are no checksums on the disk, the service activates the TuneD profile and restarts the host. Expect a host restart when first starting the microshift-tuned.service.

Next steps
  • Optional: If you are using the x86_64 architecture, you can install Red Hat Enterprise Linux for Real Time (real-time kernel).

Use Red Hat Enterprise Linux for Real Time

Use the Red Hat Enterprise Linux for Real Time (real-time kernel) for workloads with stringent low-latency determinism requirements for core kernel features. The real-time kernel provides consistent, low-latency determinism and predictable response times.

When considering system tuning, consider the following factors:

  • System tuning is just as important when using the real-time kernel as it is for the standard kernel.

  • Installing the real-time kernel on an untuned system running the standard kernel supplied as part of the RHEL 9 release is not likely to result in any noticeable benefit.

  • Tuning the standard kernel yields 90% of possible latency gains.

  • The real-time kernel provides the last 10% of latency reduction required by the most demanding workloads.

Install the Red Hat Enterprise Linux for Real Time (real-time kernel)

Although the real-time kernel is not necessary for low latency workloads, using the real-time kernel can optimize low latency performance. You can install it on a host by using RPM packages, and include it in a Red Hat Enterprise Linux for Edge (RHEL for Edge) image deployment.

Prerequisites
  • You have a Red Hat subscription that includes Red Hat Enterprise Linux for Real Time (real-time kernel). For example, your host machine is registered and Red Hat Enterprise Linux (RHEL) is attached to a RHEL for Real Time subscription.

  • You are using x86_64 architecture.

Procedure
  1. Enable the real-time kernel repository by running the following command:

    $ sudo subscription-manager repos --enable rhel-9-for-x86_64-rt-rpms
  2. Install the real-time kernel by running the following command:

    $ sudo dnf install -y kernel-rt
  3. Query the real-time kernel version by running the following command:

    $ RTVER=$(rpm -q --queryformat '%{version}-%{release}.%{arch}' kernel-rt | sort | tail -1)
  4. Make a persistent change in GRUB that designates the real-time kernel as the default kernel by running the following command:

    $ sudo grubby --set-default="/boot/vmlinuz-${RTVER}+rt"
  5. Restart the host to activate the real-time kernel.

Next steps
  1. Prepare your MicroShift workloads for low latency.

  2. Optional: Use a blueprint to install the real-time kernel in a RHEL for Edge image.

Install the Red Hat Enterprise Linux for Real Time (real-time kernel) in a Red Hat Enterprise Linux for Edge (RHEL for Edge) image

To configure low latency for a MicroShift node, you can include the real-time kernel in a RHEL for Edge image deployment using image builder.

Prerequisites
  • You have a Red Hat subscription enabled on the host that includes Red Hat Enterprise Linux for Real Time (real-time kernel).

  • You are using the x86_64 architecture.

  • You configured osbuild to use the kernel-rt repository.

Important

A subscription that includes the real-time kernel must be enabled on the host used to build the commit.

Procedure
  • Add the following example blueprint sections to your complete installation blueprint for installing the real-time kernel in a RHEL for Edge image:

    Example blueprint snippet for the real-time kernel
    [[packages]]
    name = "microshift-low-latency"
    version = "*"
    
    # Kernel RT is supported only on the x86_64 architecture
    [customizations.kernel]
    name = "kernel-rt"
    
    [customizations.services]
    enabled = ["microshift", "microshift-tuned"]
    
    [[customizations.files]]
    path = "/etc/microshift/config.yaml"
    data = """
    kubelet:
      cpuManagerPolicy: static
      cpuManagerPolicyOptions:
        full-pcpus-only: "true"
      cpuManagerReconcilePeriod: 5s
      memoryManagerPolicy: Static
      topologyManagerPolicy: single-numa-node
      reservedSystemCPUs: 0-1
      reservedMemory:
      - limits:
          memory: 1100Mi
        numaNode: 0
      kubeReserved:
        memory: 500Mi
      systemReserved:
        memory: 500Mi
      evictionHard:
        imagefs.available: 15%
        memory.available: 100Mi
        nodefs.available: 10%
        nodefs.inodesFree: 5%
      evictionPressureTransitionPeriod: 5m
    """
    
    [[customizations.files]]
    path = "/etc/tuned/microshift-baseline-variables.conf"
    data = """
    # Isolated cores should be complementary to the kubelet configuration reserved CPUs.
    # Isolated and reserved CPUs must contain all online CPUs.
    # Core #3 is for testing offlining, therefore it is skipped.
    isolated_cores=2,4-5
    hugepages_size=2M
    hugepages=10
    additional_args=test1=on test2=true dummy
    offline_cpu_set=3
    """
    
    [[customizations.files]]
    path = "/etc/microshift/tuned.yaml"
    data = """
    profile: microshift-baseline
    reboot_after_apply: True
    """
Next steps
  1. Complete the image building process.

  2. If you have not completed the previous steps for enabling low latency for your MicroShift cluster, do so now. Update the blueprint with the information gathered in those steps.

  3. If you have not configured workload partitioning, do so now.

  4. Prepare your MicroShift workloads for low latency.

Prepare a MicroShift workload for low latency

To use low latency, configure pod annotations to set the microshift-low-latency container runtime configuration for your workloads by using the RuntimeClass feature.

Prerequisites
  • You installed the microshift-low-latency RPM package.

  • You configured workload partitioning.

Procedure
  • Use the following example to set the following annotations in the pod spec:

    cpu-load-balancing.crio.io: "disable"
    irq-load-balancing.crio.io: "disable"
    cpu-quota.crio.io: "disable"
    cpu-load-balancing.crio.io: "disable"
    cpu-freq-governor.crio.io: "<governor>"

    Example pod that runs oslat test:

    apiVersion: v1
    kind: Pod
    metadata:
      name: oslat
      annotations:
        cpu-load-balancing.crio.io: "disable"
        irq-load-balancing.crio.io: "disable"
        cpu-quota.crio.io: "disable"
        cpu-c-states.crio.io: "disable"
        cpu-freq-governor.crio.io: "<governor>"
    spec:
      runtimeClassName: microshift-low-latency
      containers:
      - name: oslat
        image: quay.io/container-perf-tools/oslat
        imagePullPolicy: Always
        resources:
          requests:
            memory: "400Mi"
            cpu: "2"
          limits:
            memory: "400Mi"
            cpu: "2"
        env:
        - name: tool
          value: "oslat"
        - name: manual
          value: "n"
        - name: PRIO
          value: "1"
        - name: delay
          value: "0"
        - name: RUNTIME_SECONDS
          value: "60"
        - name: TRACE_THRESHOLD
          value: ""
        - name: EXTRA_ARGS
          value: ""
        securityContext:
          privileged: true
          capabilities:
            add:
              - SYS_NICE
              - IPC_LOCK
    metadata.annotations.cpu-load-balancing.crio.io

    Disables the CPU load balancing for the pod.

    metadata.annotations.irq-load-balancing.crio.io

    Opts the pod out of interrupt handling (IRQ).

    metadata.annotations.cpu-quota.crio.io

    Disables the CPU completely fair scheduler (CFS) quota at the pod run time.

    metadata.annotations.cpu-c-states.crio.io

    Enables or disables C-states for each CPU. Set the value to disable to provide the best performance for a high-priority pod.

    metadata.annotations.cpu-freq-governor.crio.io

    Sets the cpufreq governor for each CPU. The performance governor is recommended for high-priority workloads.

    spec.runtimeClassName

    The runtimeClassName must match the name of the performance profile configured in the node. For example, microshift-low-latency.

    Note

    Disable CPU load balancing only when the CPU manager static policy is enabled and for pods with guaranteed QoS that use whole CPUs. Otherwise, disabling CPU load balancing can affect the performance of other containers in the node.

    Important

    For the pod to have the Guaranteed QoS class, it must have the same values of CPU and memory in requests and limits. See Guaranteed (Kubernetes upstream documentation)

Reference blueprint for installing Red Hat Enterprise Linux for Real Time (real-time kernel) in a RHEL for Edge image

An image blueprint is a persistent definition of required image customizations that you can use to create multiple builds. You can edit, rebuild, delete, and save the blueprint to easily rebuild images.

Example blueprint used to install the real-time kernel in a RHEL for Edge image
name = "microshift-low-latency"
description = "RHEL 9.4 and MicroShift configured for low latency"
version = "0.0.1"
modules = []
groups = []
distro = "rhel-94"

[[packages]]
name = "microshift"
version = "*"

[[packages]]
name = "microshift-greenboot"
version = "*"

[[packages]]
name = "microshift-networking"
version = "*"

[[packages]]
name = "microshift-selinux"
version = "*"

[[packages]]
name = "microshift-low-latency"
version = "*"

# Kernel RT is only available for x86_64
[customizations.kernel]
name = "kernel-rt"

[customizations.services]
enabled = ["microshift", "microshift-tuned"]

[customizations.firewall]
ports = ["22:tcp", "80:tcp", "443:tcp", "5353:udp", "6443:tcp", "30000-32767:tcp", "30000-32767:udp"]

[customizations.firewall.services]
enabled = ["mdns", "ssh", "http", "https"]

[[customizations.firewall.zones]]
name = "trusted"
sources = ["10.42.0.0/16", "169.254.169.1"]

[[customizations.files]]
path = "/etc/microshift/config.yaml"
data = """
kubelet:
  cpuManagerPolicy: static
  cpuManagerPolicyOptions:
    full-pcpus-only: "true"
  cpuManagerReconcilePeriod: 5s
  memoryManagerPolicy: Static
  topologyManagerPolicy: single-numa-node
  reservedSystemCPUs: 0-1
  reservedMemory:
  - limits:
      memory: 1100Mi
    numaNode: 0
  kubeReserved:
    memory: 500Mi
  systemReserved:
    memory: 500Mi
  evictionHard:
    imagefs.available: 15%
    memory.available: 100Mi
    nodefs.available: 10%
    nodefs.inodesFree: 5%
  evictionPressureTransitionPeriod: 5m
"""

[[customizations.files]]
path = "/etc/tuned/microshift-baseline-variables.conf"
data = """
# Isolated cores should be complementary to the kubelet configuration reserved CPUs.
# Isolated and reserved CPUs must contain all online CPUs.
# Core #3 is for testing offlining, therefore it is skipped.
isolated_cores=2,4-5
hugepages_size=2M
hugepages=10
additional_args=test1=on test2=true dummy
offline_cpu_set=3
"""

[[customizations.files]]
path = "/etc/microshift/tuned.yaml"
data = """
profile: microshift-baseline
reboot_after_apply: True
"""

Enable workload partitioning

To enable workload partitioning on MicroShift, make the following configuration changes:

  • Update the MicroShift config.yaml file to include the kubelet configuration file.

  • Create the CRI-O systemd and configuration files.

  • Create and update the systemd configuration file for the MicroShift and CRI-O services respectively.

Procedure
  1. Update the MicroShift config.yaml file to include the kubelet configuration file to enable and configure CPU Manager for the workloads:

    • Create the kubelet configuration file in the path /etc/kubernetes/openshift-workload-pinning. The kubelet configuration directs the kubelet to modify the node resources based on the capacity and allocatable CPUs.

      kubelet configuration example
      # ...
      {
        "management": {
          "cpuset": "0,6,7" 1
        }
      }
      # ...
      1 The cpuset applies to a machine with 8 VCPUs (4 cores) and is valid throughout the document.
    • Update the MicroShift config.yaml file in the path /etc/microshift/config.yaml. Embed the kubelet configuration in the MicroShift config.yaml file to enable and configure CPU Manager for the workloads.

      MicroShift config.yaml example
      # ...
      kubelet:
        reservedSystemCPUs: 0,6,7 1
        cpuManagerPolicy: static
        cpuManagerPolicyOptions:
          full-pcpus-only: "true" 2
        cpuManagerReconcilePeriod: 5s
      # ...
      1 Exclusive cpuset for the system daemons and the interrupts/timers.
      2 kubelet configuration sets the CPUManagerPolicyOptions option to full-pcpus-only to ensure allocation of whole cores to the containers workload.
  2. Create the CRI-O systemd and configuration files:

    • Create the CRI-O configuration file in the path /etc/crio/crio.conf.d/20-microshift-workload-partition.conf which overrides the default configuration that already exists in the 11-microshift-ovn.conf file.

      CRI-O configuration example
      # ...
      [crio.runtime]
      infra_ctr_cpuset = "0,6,7"
      
      [crio.runtime.workloads.management]
      activation_annotation = "target.workload.openshift.io/management"
      annotation_prefix = "resources.workload.openshift.io"
      resources = { "cpushares" = 0, "cpuset" = "0,6,7" }
      # ...
    • Create the systemd file for CRI-O in the path /etc/systemd/system/crio.service.d/microshift-cpuaffinity.conf.

      CRI-O systemd configuration example
      # ...
      [Service]
      CPUAffinity=0,6,7
      # ...
  3. Create and update the systemd configuration file with CPUAffinity value for the MicroShift and CRI-O services:

    • Create the MicroShift services systemd file in the path /etc/systemd/system/microshift.service.d/microshift-cpuaffinity.conf. MicroShift will be pinned using the systemd CPUAffinity value.

      MicroShift services systemd configuration example
      # ...
      [Service]
      CPUAffinity=0,6,7
      # ...
    • Update the CPUAffinity value in the MicroShift ovs-vswitchd systemd file in the path /etc/systemd/system/ovs-vswitchd.service.d/microshift-cpuaffinity.conf.

      MicroShift ovs-vswitchd systemd configuration example
      # ...
      [Service]
      CPUAffinity=0,6,7
      # ...
    • Update the CPUAffinity value in the MicroShift ovsdb-server systemd file in the path /etc/systemd/system/ovsdb-server.service.d/microshift-cpuaffinity.conf

      MicroShift ovsdb-server systemd configuration example
      # ...
      [Service]
      CPUAffinity=0,6,7
      # ...

Optimize network performance

Improve network performance on your MicroShift node by tuning OVN-Kubernetes settings and leveraging high-performance networking options such as SR-IOV.

Network performance optimizations

By default, three performance optimizations are applied to OVS services to minimize resource consumption:

  • CPU affinity to ovs-vswitchd.service and ovsdb-server.service

  • no-mlockall to openvswitch.service

  • Limit handler and revalidator threads to ovs-vswitchd.service

Create an OVN-Kubernetes configuration file

MicroShift uses built-in default OVN-Kubernetes values if an OVN-Kubernetes configuration file is not created. To apply custom OVN-Kubernetes values such as pod mtu instead of using built-in defaults, you can copy ovn.yaml.default to /etc/microshift/ovn.yaml and edit the file.

Procedure
  1. To create your ovn.yaml file, run the following command:

    $ sudo cp /etc/microshift/ovn.yaml.default /etc/microshift/ovn.yaml
  2. To list the contents of the configuration file you created, run the following command:

    $ cat /etc/microshift/ovn.yaml
    Example YAML file with default maximum transmission unit (MTU) value
    mtu: 1400
  3. To customize your configuration, you can change the MTU value. The table that follows provides details:

    Table 4. Supported optional OVN-Kubernetes configurations for MicroShift
    Field Type Default Description Example

    mtu

    uint32

    auto

    MTU value used for the pods

    1300

    Important

    If you change the mtu configuration value in the ovn.yaml file, you must restart the host that {product-title} is running on to apply the updated setting.

    Example custom ovn.yaml configuration file
    mtu: 1300

Understand the SR-IOV Network Operator

SR-IOV (Single Root I/O Virtualization) is a specification that allows a single physical Peripheral Component Interconnect Express (PCIe) device that supports SR-IOV, for example, a Physical Function (PF), to appear as multiple separate physical devices known as Virtual Functions (VFs). You can directly assign VFs to pods, which bypasses the host operating system network stack, improves throughput, and reduces latency for network intensive workloads.

The integration of the SR-IOV Network Operator and CNI provider into MicroShift enables declarative access to VFs. As a result, you can expose supported SR-IOV devices as specialized resources within your MicroShift pod for more predictable high-speed networking for demanding workloads. The deployed SR-IOV resources operate in the sriov-network-operator namespace.

You do not need to manually configure SR-IOV through the operating system. You can also treat VFs as resources that can be reliably mapped to your containerized applications. These resources reduce manual error and ensure consistent, low-latency networking for critical applications.

Here are the components of SR-IOV functionality:

  • SR-IOV Network Operator: The SR-IOV Network Operator is a Kubernetes component that detects and manages SR-IOV devices. This component exposes the SR-IOV devices as schedulable resources within MicroShift.

  • SR-IOV CNI Provider: This Container Network Interface (CNI) provider works with Multus to assign the exposed VFs to the application pods.

  • Virtual Functions (VFs): VFs are lightweight PCIe functions exposed by the PF that are assigned to pods.

  • NetworkAttachment Definitions: NetworkAttachmentDefinitions are custom resources (CRs) that are used to define the specific network configuration so that application developers can specify the VFs they need access. NetworkAttachmentDefinitions provide the declarative method for accessing VFs.

Install the SR-IOV Network Operator

Install the necessary SR-IOV components to enable MicroShift to discover SR-IOV devices and expose them as resources for scheduling.

Prerequisites
  • You have the required RPM package containing the SR-IOV Network Operator.

Procedure
  1. If provided as an optional RPM, install the required microshift-sriov RPM package.

  2. Restart the MicroShift service to deploy the SR-IOV resources in the sriov-network-operator namespace.

  3. To specify the required VF configuration based on the available hardware, create an SriovNetworkNodePolicy custom resource (CR). For example, save the following YAML as the file policyoneflag-sriov-node-network.yaml:

    apiVersion: sriovnetwork.openshift.io/v1
    kind: SriovNetworkNodePolicy
    metadata:
      name: policyoneflag
      namespace: sriov-network-operator
    spec:
      resourceName: policyoneflag
      nodeSelector:
        node.kubernetes.io/instance-type: rhde
      priority: 10
      numVfs: 5
      nicSelector:
        pfNames: ["ens5"]
      deviceType: "netdevice"
      isRdma: false
    • The metadata.name parameter specifies the name for the custom resource object.

    • The metadata.namespace parameter specifies the namespace where the SR-IOV Network Operator is installed.

    • The spec.resourceName parameter specifies the resource name of the SR-IOV network device plugin. You can create multiple SR-IOV network node policies for a resource name.

    • (Optional) The spec.priority parameter specifies a priority value. The priority is an integer value between 0 and 99. A smaller value receives higher priority. For example, a priority of 10 is a higher priority than 99. The default value is 99.

    • The spec.numVfs parameter specifies the number of the virtual functions (VFs) to create for the SR-IOV physical network device. For an Intel network interface controller (NIC), the number of VFs cannot be larger than the total VFs supported by the device. For a Mellanox NIC, the number of VFs cannot be larger than 127.

    • The spec.nicSelector parameter identifies the device for the Operator to configure. You do not have to specify values for all the parameters. It is recommended to identify the network device with enough precision to avoid selecting a device unintentionally. If you specify rootDevices, you must also specify a value for vendor, deviceID, or pfNames. If you specify both pfNames and rootDevices at the same time, ensure that they refer to the same device. If you specify a value for netFilter, then you do not need to specify any other parameter because a network ID is unique.

    • (Optional) The spec.nicSelector.pfNames parameter specifies an array of one or more physical function (PF) names for the device.

    • (Optional) The spec.deviceType parameter specifies the driver type for the virtual functions. The only allowed value is netdevice.

    • (Optional) The spec.isRDMA parameter configures whether to enable remote direct memory access (RDMA) mode. The default value is false. If the spec.isRdma parameter is set to true, you can continue to use the RDMA-enabled VF as a normal network device. A device can be used in either mode. to configure a Mellanox NIC for use with Fast Datapath DPDK applications, set spec.isRdma to true and additionally set the needVhostNet parameter to true

      Note

      The vfio-pci driver type is not supported.

  4. Create the SriovNetworkNodePolicy object by entering the following command:

    $ oc create -f policyoneflag-sriov-node-network.yaml

    After applying the configuration update, the workload contains the required resources and dependencies for VF access.

  5. To verify that the SR-IOV network device is configured, enter the following command. Replace <node_name> with the name of a node with the SR-IOV network device that you just configured. Expected output shows Succeeded.

    $ oc get sriovnetworknodestates -n sriov-network-operator <node_name> -o jsonpath='{.status.syncStatus}'
  6. Deploy an SriovNetwork custom resource (CR) which references the SriovNetworkNodePolicy CR and insert the metaPlugins configuration, as in the following example CR. The Operator generates a NetworkAttachmentDefinition CR and the VFs become available to the pods. Save the YAML as the file sriov-network-interface-sysctl.yaml.

    apiVersion: sriovnetwork.openshift.io/v1
    kind: SriovNetwork
    metadata:
      name: onevalidflag
      namespace: sriov-network-operator
    spec:
      resourceName: policyoneflag
      networkNamespace: sysctl-tuning-test
      ipam: '{ "type": "static" }'
      capabilities: '{ "mac": true, "ips": true }'
      metaPlugins : |
        {
          "type": "tuning",
          "capabilities":{
            "mac":true
          },
          "sysctl":{
             "net.ipv4.conf.IFNAME.accept_redirects": "1"
          }
        }
    • The metadata.name parameter specifies the name for the object. The SR-IOV Network Operator creates a NetworkAttachmentDefinition object with the same name.

    • The metadata.namespace parameter specifies the namespace where the SR-IOV Network Operator is installed.

    • The spec.resourceName parameter displays the value from the SriovNetworkNodePolicy object that defines the SR-IOV hardware for this additional network.

    • The spec.networkNamespace parameter specifies the target namespace for the SriovNetwork object. Only pods in the target namespace can attach to the additional network.

    • The spec.ipam parameter specifies a configuration object for the IPAM CNI plugin as a YAML block scalar. The plugin manages IP address assignment for the attachment definition.

    • (Optional) The spec.capabilities parameter sets capabilities for the additional network. You can specify "{ "ips": true }" to enable IP address support or "{ "mac": true }" to enable MAC address support.

    • (Optional) The spec.metaPlugins parameter is used to add additional capabilities to the device. In this use case set the type field to tuning. Specify the interface-level network sysctl you want to set in the sysctl field.

  7. Create the SriovNetwork resource by entering the following command:

    $ oc create -f sriov-network-interface-sysctl.yaml
Verification
  1. Confirm that the SR-IOV Network Operator created the NetworkAttachmentDefinition CR by running the following command:

    $ oc get network-attachment-definitions -n <namespace>

    Replace <namespace> with the value for networkNamespace parameter that you specified in the SriovNetwork object, for example, sysctl-tuning-test. The expected output shows the name of the NAD CRD and the creation age in minutes.

    Note

    There might be a delay before the SR-IOV Network Operator creates the CR.

  2. Verify that the tuning CNI is correctly configured and the additional SR-IOV network is attached:

    1. Create a Pod CR. Save the following YAML as the file examplepod.yaml:

      apiVersion: v1
      kind: Pod
      metadata:
        name: tunepod
        namespace: sysctl-tuning-test
        annotations:
          k8s.v1.cni.cncf.io/networks: |-
            [
              {
                "name": "onevalidflag",
                "mac": "0a:56:0a:83:04:0c",
                "ips": ["10.100.100.200/24"]
             }
            ]
      spec:
        containers:
        - name: podexample
          image: centos
          command: ["/bin/bash", "-c", "sleep INF"]
          securityContext:
            runAsUser: 2000
            runAsGroup: 3000
            allowPrivilegeEscalation: false
            capabilities:
              drop: ["ALL"]
        securityContext:
          runAsNonRoot: true
          seccompProfile:
            type: RuntimeDefault
      • The annotations.name parameter specifies the name of the SR-IOV network attachment definition CR.

      • (Optional) The annotations.mac parameter specifies the MAC address for the SR-IOV device that is allocated from the resource type defined in the SR-IOV network attachment definition CR. To use this feature, you also must specify { "mac": true } in the SriovNetwork object.

      • (Optional) The annotations.ips parameter specifies the IP addresses for the SR-IOV device that are allocated from the resource type defined in the SR-IOV network attachment definition CR. Both IPv4 and IPv6 addresses are supported. To use this feature, you also must specify { "ips": true } in the SriovNetwork object.

    2. Create the Pod CR by entering the following command:

      $ oc apply -f examplepod.yaml
    3. Verify that the pod is created by running the following command:

      $ oc get pod -n sysctl-tuning-test
      Example output:
      NAME      READY   STATUS    RESTARTS   AGE
      tunepod   1/1     Running   0          47s
    4. Log in to the pod by running the following command:

      $ oc rsh -n sysctl-tuning-test tunepod
    5. Verify the values of the configured sysctl flag. Find the value net.ipv4.conf.IFNAME.accept_redirects by running the following command:

      $ sysctl net.ipv4.conf.net1.accept_redirects

SR-IOV Network Operator supported devices

The config.yaml file lists the supported network devices for the SR-IOV Network Operator.

SR-IOV Network Operator configuration file
apiVersion: v1
kind: ConfigMap
metadata:
  name: supported-nic-ids
data:
  Intel_i40e_XXV710: "8086 158a 154c"
  Intel_i40e_25G_SFP28: "8086 158b 154c"
  Intel_i40e_10G_X710_SFP: "8086 1572 154c"
  Intel_ixgbe_10G_X550: "8086 1563 1565"
  Intel_ixgbe_82576: "8086 10c9 10ca"
  Intel_i40e_X710_X557_AT_10G: "8086 1589 154c"
  Intel_i40e_10G_X710_BACKPLANE: "8086 1581 154c"
  Intel_i40e_10G_X710_BASE_T: "8086 15ff 154c"
  Intel_i40e_XXV710_N3000: "8086 0d58 154c"
  Intel_i40e_40G_XL710_QSFP: "8086 1583 154c"
  Intel_ice_Columbiaville_E810-CQDA2_2CQDA2: "8086 1592 1889"
  Intel_ice_Columbiaville_E810-XXVDA4: "8086 1593 1889"
  Intel_ice_Columbiaville_E810-XXVDA2: "8086 159b 1889"
  Intel_ice_Columbiaville_E810-XXV_BACKPLANE: "8086 1599 1889"
  Intel_ice_Columbiaville_E810: "8086 1591 1889"
  Intel_ice_Columbiapark_E823C: "8086 188a 1889"
  Intel_ice_Columbiapark_E823L_SFP: "8086 124d 1889"
  Intel_ice_Columbiapark_E823L_BACKPLANE: "8086 124c 1889"
  Intel_ice_Columbiapark_E825C_BACKPLANE: "8086 579c 1889"
  Intel_ice_Columbiapark_E825C_QSFP: "8086 579d 1889"
  Intel_ice_Columbiapark_E825C_SFP: "8086 579e 1889"
  Intel_ice_Connorsville_E830_QSFP: "8086 12d2 1889"
  Intel_ice_Connorsville_E830_SFP: "8086 12d3 1889"
  Intel_ice_Connorsville_E835CC_QSFP: "8086 1249 1889"
  Intel_ice_Connorsville_E835CC_SFP: "8086 124a 1889"
  Nvidia_mlx5_ConnectX-4: "15b3 1013 1014"
  Nvidia_mlx5_ConnectX-4LX: "15b3 1015 1016"
  Nvidia_mlx5_ConnectX-5: "15b3 1017 1018"
  Nvidia_mlx5_ConnectX-5_Ex: "15b3 1019 101a"
  Nvidia_mlx5_ConnectX-6: "15b3 101b 101c"
  Nvidia_mlx5_ConnectX-6_Dx: "15b3 101d 101e"
  Nvidia_mlx5_ConnectX-6_Lx: "15b3 101f 101e"
  Nvidia_mlx5_ConnectX-7: "15b3 1021 101e"
  Nvidia_mlx5_ConnectX-8: "15b3 1023 101e"
  Nvidia_mlx5_MT42822_BlueField-2_integrated_ConnectX-6_Dx: "15b3 a2d6 101e"
  Nvidia_mlx5_MT43244_BlueField-3_integrated_ConnectX-7_Dx: "15b3 a2dc 101e"
  Broadcom_bnxt_BCM57414_2x25G: "14e4 16d7 16dc"
  Broadcom_bnxt_BCM75508_2x100G: "14e4 1750 1806"
  Qlogic_qede_QL45000_50G: "1077 1654 1664"
  Red_Hat_Virtio_network_device: "1af4 1000 1000"
  Red_Hat_Virtio_1_0_network_device: "1af4 1041 1041"
  Marvell_OCTEON_TX2_CN96XX: "177d b200 b203"
  Marvell_OCTEON_TX2_CN98XX: "177d b100 b103"
  Marvell_OCTEON_Fusion_CNF95XX: "177d b600 b603"
  Marvell_OCTEON10_CN10XXX: "177d b900 b903"
  Marvell_OCTEON_Fusion_CNF105XX: "177d ba00 ba03"
  Amazon_Elastic_Network_Adapter: "1d0f ec20 ec20"
Note

For the most up-to-date list of supported cards and compatible {product-title} versions available, see Openshift Single Root I/O Virtualization (SR-IOV) and PTP hardware networks Support Matrix.

Secondary networks in MicroShift

Using the MicroShift Multus CNI plugin, you can add additional interfaces to pods from other networks. With this configuration, you have flexibility when you configure pods that deliver network functionality, such as switching or routing.

During node installation, the default pod network is configured with default values unless you customize the configuration. The default network handles all ordinary network traffic for the node.

Supported secondary networks for network isolation

The following secondary networks are supported in MicroShift 4.22:

  • Bridge: Allows pods on the same host to communicate with each other and the host.

  • IPVLAN: Allows pods on a host to communicate with other hosts.

    • This is similar to a MACVLAN-based secondary network.

    • Each pod shares the same MAC address as the parent physical network interface, unlike a MACVLAN-based secondary network.

  • MACVLAN: Allows pods on a host to communicate with other hosts and the pods on those other hosts by using a physical network interface. Each pod that is attached to a MACVLAN-based secondary network is provided with a unique MAC address.

Note

Setting network policies for secondary networks is not supported.

Use case: Secondary networks for network isolation

You can use an secondary network in situations where network isolation is needed, including control plane and data plane separation. For example, you can configure an secondary interface if you want pods to access a network on the host and also communicate with devices deployed to the edge. These edge devices might be on an isolated operator network or are periodically disconnected.

Isolating network traffic is useful for the following performance and security reasons:

Performance

You can send traffic on two different planes to manage the amount of traffic on each plane.

Security

You can send sensitive traffic onto a network plane that is managed specifically for security considerations, and you can separate private data that must not be shared between tenants or customers.

Important

The Multus CNI plugin is deployed when the MicroShift service starts up. Therefore, a host restart is required if the microshift-multus RPM package is added after MicroShift has started. Restarting ensures that all containers are re-created with Multus annotations.

How secondary networks are implemented

All of the pods in the node still use the node-wide default network to maintain connectivity across the node. Every pod has an eth0 interface that is attached to the node-wide pod network.

  • You can view the interfaces for a pod by using the oc get pod <pod_name> -o=jsonpath='{ .metadata.annotations.k8s\.v1\.cni\.cncf\.io/network-status }' command.

  • If you add secondary network interfaces that use the MicroShift Multus CNI, they are named net1, net2, …​, netN.

  • The CNI configuration is created when the MicroShift Multus DaemonSet starts. This configuration is autogenerated and includes the primary CNI that is the default delegate. For MicroShift, the default CNI is OVN-Kubernetes.

How to attach secondary networks to pods

To attach secondary network interfaces to a pod, you must create and apply configurations that define how the interfaces are attached.

  • You must configure any secondary networks you want to use. Because of individual differences in networks, no default configuration is provided.

  • You must apply YAML manifest to specify each interface by using a NetworkAttachmentDefinition custom resource (CR). A configuration inside each of these CRs defines how that interface is created.

  • CRI-O must be configured to use Multus. A default configuration is included in the microshift-multus RPM.

    • If the Multus CNI is installed on an existing MicroShift instance, the host must be restarted.

    • If the Multus CNI is installed alongside MicroShift, you can add CRs and pods and then start the MicroShift service. Restarting the host in this scenario is not needed.

Configurations for secondary network types

The specific configuration fields for secondary networks is described in the following sections.

Install the Multus CNI plugin on a running node

If you want to attach additional networks to a pod for high-performance network configurations, you can install the MicroShift Multus RPM package. After installation, a host restart is required to re-create all the pods with the Multus annotation.

Important

Uninstalling the Multus CNI plugin is not supported.

Prerequisites
  • You have root access to the host.

Procedure
  1. Install the Multus RPM package by running the following command:

    $ sudo dnf install microshift-multus
    Tip

    If you create your custom resources (CRs) for additional networks now, you can complete your installation and apply configurations with one restart.

  2. To apply the package manifest to an active node, restart the host by running the following command:

    $ sudo systemctl restart
Verification
  • After restarting, ensure that the Multus CNI plugin components are created by running the following command:

    $ oc get pod -A | grep multus
    Example output
    openshift-multus      dhcp-daemon-ktzqf     1/1   Running   0     45h
    openshift-multus      multus-4frf4          1/1   Running   0     45h
Next steps
  1. If you have not done so, configure and apply the additional networks you want to use.

  2. Deploy your applications that use the created CRs.

Configuration for a bridge secondary network

The Bridge CNI plugin JSON configuration object describes the configuration parameters for the Bridge CNI plugin.

The following table details the configuration parameters:

Field Type Description

cniVersion

string

The CNI specification version. A minimum version of 0.3.1 is required.

name

string

The mandatory, unique identifier assigned to this CNI network attachment definition. It is used by the container runtime to select the correct network configuration and serves as the key for persistent resource state management, such as IP address allocations.

type

string

The name of the CNI plugin to configure: bridge.

ipam

object

The configuration object for the IPAM CNI plugin. The plugin manages IP address assignment for the attachment definition.

bridge

string

Optional: Specify the name of the virtual bridge to use. If the bridge interface does not exist on the host, the bridge interface gets created. The default value is cni0.

ipMasq

boolean

Optional: Set to true to enable IP masquerading for traffic that leaves the virtual network. The source IP address for all traffic is rewritten to the bridge’s IP address. If the bridge does not have an IP address, this setting has no effect. The default value is false.

disableContainerInterface

boolean

Optional: Controls the container interface (veth peer inside the netns container). When set to true, the container interface link-state is set to down, you cannot use the IPAM CNI plugin. The default value is false.

isGateway

boolean

Optional: Set to true to assign an IP address to the bridge. The default value is false.

isDefaultGateway

boolean

Optional: Set to true to configure the bridge as the default gateway for the virtual network. The assigned IP address of the bridge is used as the default route. If isDefaultGateway is set to true, isGateway is also set to true automatically. The default value is false.

forceAddress

boolean

Optional: Set to true to allow assignment of a previously assigned IP address to the virtual bridge. When set to false, if an IPv4 address or an IPv6 address from overlapping subsets is assigned to the virtual bridge, an error occurs. The default value is false.

hairpinMode

boolean

Optional: Set to true to allow the virtual bridge to send an Ethernet frame back through the virtual port it was received on. This mode is also known as reflective relay. The default value is false.

promiscMode

boolean

Optional: Set to true to enable promiscuous mode on the bridge. The default value is false.

vlan

integer

Optional: Specify a virtual LAN (VLAN) tag as an integer value. By default, no VLAN tag is assigned.

preserveDefaultVlan

boolean

Optional: Indicates whether the default VLAN must be preserved on the veth end connected to the bridge. Defaults to false.

portIsolation

boolean

Optional: If true, prevents containers on the same bridge from communicating with each other. A container can still reach non-isolated ports. For example, a bridge interface that allows access to the host or an optional uplink that allows access outside the host. The default value is false.

vlanTrunk

list

Optional: Assign a VLAN trunk tag. The default value is none.

mtu

integer

Optional: Set the maximum transmission unit (MTU) to the specified value. The default value is automatically set by the kernel.

enabledad

boolean

Optional: Enables duplicate address detection for the container side veth. The default value is false.

macspoofchk

boolean

Optional: Enables mac spoof check, limiting the traffic originating from the container to the mac address of the interface. The default value is false.

Note

The VLAN parameter configures the VLAN tag on the host end of the veth and also enables the vlan_filtering feature on the bridge interface.

Note

To configure an uplink for an L2 network, you must allow the VLAN on the uplink interface by using the following command:

$  bridge vlan add vid VLAN_ID dev DEV
Bridge CNI plugin configuration example

The following example configures a secondary network named bridge-net:

{
  "cniVersion": "0.3.1",
  "name": "bridge-net",
  "type": "bridge",
  "isGateway": true,
  "vlan": 2,
  "ipam": {
    "type": "dhcp"
    }
}

Configuration for an IPVLAN secondary network

The IPVLAN CNI plugin JSON configuration object describes the configuration parameters for the IPVLAN, ipvlan, CNI plugin. The following table details these parameters:

Field Type Description

cniVersion

string

The CNI specification version. A minimum version of 0.3.1 is required.

name

string

The mandatory, unique identifier assigned to this CNI network attachment definition. It is used by the container runtime to select the correct network configuration and serves as the key for persistent resource state management, such as IP address allocations.

type

string

The name of the CNI plugin to configure: ipvlan.

ipam

object

The configuration object for the IPAM CNI plugin. The plugin manages IP address assignment for the attachment definition. This is required unless the plugin is chained.

mode

string

Optional: The operating mode for the virtual network. The value must be l2, l3, or l3s. The default value is l2.

master

string

Optional: The Ethernet interface to associate with the network attachment. If a master is not specified, the interface for the default network route is used.

mtu

integer

Optional: Set the maximum transmission unit (MTU) to the specified value. The default value is automatically set by the kernel.

linkInContainer

boolean

Optional: Specifies whether the master interface is in the container network namespace or the main network namespace. Set the value to true to request the use of a container namespace master interface.

Important
  • The ipvlan object does not allow virtual interfaces to communicate with the master interface. Therefore the container is not able to reach the host by using the ipvlan interface. Be sure that the container joins a network that provides connectivity to the host, such as a network supporting the Precision Time Protocol (PTP).

  • A single master interface cannot simultaneously be configured to use both macvlan and ipvlan.

  • For IP allocation schemes that cannot be interface agnostic, the ipvlan plugin can be chained with an earlier plugin that handles this logic. If the master is omitted, then the previous result must contain a single interface name for the ipvlan plugin to enslave. If ipam is omitted, then the previous result is used to configure the ipvlan interface.

IPVLAN CNI plugin configuration example

The following example configures a secondary network named ipvlan-net:

{
  "cniVersion": "0.3.1",
  "name": "ipvlan-net",
  "type": "ipvlan",
  "master": "eth1",
  "linkInContainer": false,
  "mode": "l3",
  "ipam": {
    "type": "static",
    "addresses": [
       {
         "address": "192.168.10.10/24"
       }
    ]
  }
}

Configuration for a MACVLAN secondary network

The MACVLAN CNI plugin JSON configuration object describes the configuration parameters for the MAC Virtual LAN (MACVLAN) Container Network Interface (CNI) plugin. The following table describes these parameters:

Field Type Description

cniVersion

string

The CNI specification version. A minimum version of 0.3.1 is required.

name

string

The mandatory, unique identifier assigned to this CNI network attachment definition. It is used by the container runtime to select the correct network configuration and serves as the key for persistent resource state management, such as IP address allocations.

type

string

The name of the CNI plugin to configure: macvlan.

ipam

object

The configuration object for the IPAM CNI plugin. The plugin manages IP address assignment for the attachment definition.

mode

string

Optional: Configures traffic visibility on the virtual network. Must be either bridge, passthru, private, or vepa. If a value is not provided, the default value is bridge.

master

string

Optional: The host network interface to associate with the newly created macvlan interface. If a value is not specified, then the default route interface is used.

mtu

integer

Optional: The maximum transmission unit (MTU) to the specified value. The default value is automatically set by the kernel.

linkInContainer

boolean

Optional: Specifies whether the master interface is in the container network namespace or the main network namespace. Set the value to true to request the use of a container namespace master interface.

Note

If you specify the master key for the plugin configuration, use a different physical network interface than the one that is associated with your primary network plugin to avoid possible conflicts.

MACVLAN CNI plugin configuration example

The following example configures a secondary network named macvlan-net:

{
  "cniVersion": "0.3.1",
  "name": "macvlan-net",
  "type": "macvlan",
  "master": "eth1",
  "linkInContainer": false,
  "mode": "bridge",
  "ipam": {
    "type": "dhcp"
    }
}

IP address management types and additional networks

IP addresses are provisioned for an additional network through an IP Address Management (IPAM) CNI plugin that you configure. Supported IP address provisioning types in MicroShift are host-local, static, and dhcp.

bridge interface specifics

When using the bridge type interface and the dhcp IPAM, a DHCP server listening on the bridged network is required. If you are using a firewall, configuring the firewalld service by running the firewall-cmd --remove-service=dhcp command to allow DHCP traffic on the network zone is also required.

macvlan interface specifics

The macvlan type interface accesses the network that the host is connected to. This means that the interface can receive an IP address from the DHCP server on the host network if the dhcp IPAM plugin is used.

ipvlan interface specifics

The ipvlan interface also has direct access to the host network, but shares a MAC address with the host interface. The ipvlan type interface cannot be used with the dhcp plugin because of the shared MAC address. The IPAM plugin does not support the DHCP protocol with ClientID.

Create a NetworkAttachmentDefinition for an additional network

You can create a NetworkAttachmentDefinition configuration file for an additional network in order to use other CNI plugins.

In this example, a bridge-type interface is used. You can also use the example workflow here that uses host-local IP address management (IPAM) to configure other supported additional network types.

Important

If you use bridge and the dhcp IPAM, a DHCP server listening on the bridged network is required. If you are also using a firewall, configuring the firewalld service to allow DHCP traffic on the network zone is also required. You can run the firewall-cmd --remove-service=dhcp command in this case.

Prerequisites
  • The MicroShift Multus CNI is installed.

  • The OpenShift CLI (oc) is installed.

  • MicroShift is running.

Procedure
  1. Optional: Verify that the MicroShift node is running with the Multus CNI by running the following command:

    $ oc get pods -n openshift-multus
    Example output
    NAME                READY   STATUS    RESTARTS   AGE
    dhcp-daemon-dfbzw   1/1     Running   0          5h
    multus-rz8xc        1/1     Running   0          5h
  2. Create a NetworkAttachmentDefinition configuration file by running the following command and using the following example file for reference:

    $ oc apply -f network-attachment-definition.yaml
    Example NetworkAttachmentDefinition file
    apiVersion: "k8s.cni.cncf.io/v1"
    kind: NetworkAttachmentDefinition
    metadata:
      name: bridge-conf
    spec:
      config: '{
          "cniVersion": "0.4.0",
          "type": "bridge",
          "bridge": "br-test",
          "mode": "bridge",
          "ipam": {
            "type": "host-local",
            "ranges": [
              [
                {
                  "subnet": "10.10.0.0/24",
                  "rangeStart": "10.10.0.20",
                  "rangeEnd": "10.10.0.50",
                  "gateway": "10.10.0.254"
                 }
              ],
              [
                {
                  "subnet": "fd00:IJKL:MNOP:10::0/64",
                  "rangeStart": "fd00:IJKL:MNOP:10::1",
                  "rangeEnd": "fd00:IJKL:MNOP:10::9"
            "dataDir": "/var/lib/cni/br-test"
          }
        }'

    where:

    type

    Specifies a name of the CNI plugin. This example uses the bridge type.

    bridge

    Specifies the name of the bridge on the MicroShift host that is used. The additional interface of the pod is connected to that bridge. If the interface does not exist on the host, the Bridge CNI creates it. If the interface already exists, it is reused. In this example, the name of the interface is br-test.

    ipam

    Specifies the IPAM type.

    ipam.ranges.

    Specifies the IP address range for the additional network. IPv6 addresses can be added to the secondary interface.

    Note

    Using the name of the bridge is specific to the bridge type of plugin. Other plugins use different fields in their NetworkAttachmentDefinitions. For example, the macvlan and ipvlan configurations use master to specify the host interface to attach.

Add a pod to an additional network

You can add a pod to an additional network. At the time a pod is created, additional networks are attached to it. The pod continues to send normal node-related network traffic over the default network.

If you want to attach additional networks to a pod that is already running, you must restart the pod.

Prerequisites
  • The OpenShift CLI (oc) is installed.

  • The node is running.

  • A network defined by a NetworkAttachmentDefinition object that you want to attach the pod to exists.

Procedure
  1. Add an annotation to a Pod YAML file. Only one of the following annotation formats can be used:

    1. To attach an additional network without any customization, add an annotation with the following format. Replace <network> with the name of the additional network to associate with the pod:

      apiVersion: v1
      kind: Pod
      metadata:
        annotations:
          k8s.v1.cni.cncf.io/networks: <network>[,<network>,...]
      # ...

      Replace <network> with the name of each additional network to associate with the pod. To specify more than one additional network, separate each network with a comma. Do not include whitespaces between the commas. If you specify the same additional network multiple times, that pod has multiple network interfaces attached to that network.

      The following example annotation specifies a bridge-type additional network:

      apiVersion: v1
      kind: Pod
      metadata:
        annotations:
          k8s.v1.cni.cncf.io/networks: bridge-conf
      # ...
    2. To attach an additional network with customizations, add an annotation with the following format:

      apiVersion: v1
      kind: Pod
      metadata:
        annotations:
          k8s.v1.cni.cncf.io/networks: |-
            [
              {
                "name": "<network>",
                "namespace": "<namespace>",
                "default-route": ["<default-route>"]
              }
            ]
      # ...

      where:

      name

      Specifies the name of the additional network defined by a NetworkAttachmentDefinition object.

      namespace

      Specifies the namespace where the NetworkAttachmentDefinition object is defined.

      default-route

      Specifies an optional field to provide an override for the default route, such as 192.168.17.1.

  2. To create a Pod YAML file and add the NetworkAttachmentDefinition annotation for an additional network, run the following command and use the example YAML:

    $ oc apply -f ./<test_bridge>.yaml

    Replace <test_bridge> with the pod name that you want to use.

    The following example output shows that the test_bridge pod has been created:

    pod/test_bridge created
    Example test_bridge pod YAML
    apiVersion: v1
    kind: Pod
    metadata:
      name: test_bridge
      annotations:
        k8s.v1.cni.cncf.io/networks: bridge-conf
      labels:
        app: test_bridge
    spec:
      terminationGracePeriodSeconds: 0
      containers:
      - name: hello-microshift
        image: quay.io/microshift/busybox:1.36
        command: ["/bin/sh"]
        args: ["-c", "while true; do echo -ne \"HTTP/1.0 200 OK\r\nContent-Length: 16\r\n\r\nHello MicroShift\" | nc -l -p 8080 ; done"]
        ports:
        - containerPort: 8080
          protocol: TCP
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - ALL
          runAsNonRoot: true
          runAsUser: 1001
          runAsGroup: 1001
          seccompProfile:
            type: RuntimeDefault
  3. Make sure that the NetworkAttachmentDefinition annotation is correct:

    The following example NetworkAttachmentDefinition annotation specifies a bridge-type additional network:

    apiVersion: v1
    kind: Pod
    metadata:
      annotations:
        k8s.v1.cni.cncf.io/networks: bridge-conf
    # ...
  4. Optional: To confirm that the NetworkAttachmentDefinition annotation exists in a Pod YAML, run the following command, replacing <name> with the name of the pod.

    $ oc get pod <name> -o yaml

    Replace <name> with the pod name you want to use. In the following example, <test_bridge> is used.

    In the following example, the test_bridge is attached to the net1 additional network:

    $ oc get pod <test_bridge> -o yaml

    Replace <test_bridge> with the name of the bridge you want to use.

    The following example output shows that the test_bridge pod is attached to the net1 additional network:

    apiVersion: v1
    kind: Pod
    metadata:
      annotations:
        k8s.v1.cni.cncf.io/networks: bridge-conf
        k8s.v1.cni.cncf.io/network-status: |-
          [{
              "name": "ovn-kubernetes",
              "interface": "eth0",
              "ips": [
                  "10.42.0.18"
              ],
              "default": true,
              "dns": {}
          },{
              "name": "bridge-conf",
              "interface": "net1",
              "ips": [
                  "20.2.2.100"
              ],
              "mac": "22:2f:60:a5:f8:00",
              "dns": {}
          }]
      name: pod
      namespace: default
    spec:
    # ...
    status:
    # ...

    The k8s.v1.cni.cncf.io/network-status parameter is a JSON array of objects. Each object describes the status of an additional network attached to the pod. The annotation value is stored as a plain text value.

  5. Verify that the pod is running by running the following command:

    $ oc get pod
    Example output
    NAME          READY   STATUS    RESTARTS   AGE
    test_bridge   1/1     Running   0          81s

Configure an additional network

After you have created the NetworkAttachmentDefinition object and applied it, you can configure an additional network.

In this example, the bridge type additional network is used. You can also use this workflow for other network types.

Prerequisites
  • You created and applied the NetworkAttachmentDefinition object configuration.

Procedure
  1. Verify that the bridge was created on the host by running the following command:

    $ ip a show br-test
    Example output
    22: br-test: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
        link/ether 96:bf:ca:be:1d:15 brd ff:ff:ff:ff:ff:ff
        inet6 fe80::34e2:bbff:fed2:31f2/64 scope link
           valid_lft forever preferred_lft forever
  2. Configure an IP address for the bridge by running the following command:

    $ sudo ip addr add 10.10.0.10/24 dev br-test
  3. Verify that the IP address configuration is added to the bridge by running the following command:

    $ ip a show br-test
    Example output
    22: br-test: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
        link/ether 96:bf:ca:be:1d:15 brd ff:ff:ff:ff:ff:ff
        inet 10.10.0.10/24 scope global br-test
           valid_lft forever preferred_lft forever
        inet6 fe80::34e2:bbff:fed2:31f2/64 scope link
           valid_lft forever preferred_lft forever

    Confirm that the IP address is configured as expected.

  4. Verify the IP address of the pod by running the following command:

    $ oc get pod test-bridge --output=jsonpath='{.metadata.annotations.k8s\.v1\.cni\.cncf\.io/network-status}'
    Example output
    [{
        "name": "ovn-kubernetes",
        "interface": "eth0",
        "ips": [
            "10.42.0.17"
        ],
        "mac": "0a:58:0a:2a:00:11",
        "default": true,
        "dns": {}
    },{
        "name": "default/bridge-conf",
        "interface": "net1",
        "ips": [
            "10.10.0.20"
        ],
        "mac": "82:01:98:e5:0c:b7",
        "dns": {}

    Confirm that the bridge additional network is attached as expected-"default/bridge-conf".

  5. Optional: You can use oc exec to access the pod and confirm its interfaces by using the ip command:

    $ oc exec -ti test-bridge -- ip a
    Example output
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
        inet6 ::1/128 scope host
           valid_lft forever preferred_lft forever
    2: eth0@if21: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
        link/ether 0a:58:0a:2a:00:11 brd ff:ff:ff:ff:ff:ff
        inet 10.42.0.17/24 brd 10.42.0.255 scope global eth0
           valid_lft forever preferred_lft forever
        inet6 fe80::858:aff:fe2a:11/64 scope link
           valid_lft forever preferred_lft forever
    3: net1@if23: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
        link/ether 82:01:98:e5:0c:b7 brd ff:ff:ff:ff:ff:ff
        inet 10.10.0.20/24 brd 10.10.0.255 scope global net1
           valid_lft forever preferred_lft forever
        inet6 fe80::8001:98ff:fee5:cb7/64 scope link
           valid_lft forever preferred_lft forever

    In the example the pod is attached to the 10.10.0.20 IP address on the net1 interface as expected.

  6. Confirm that the connection is working as expected by accessing the HTTP server in the pod from the MicroShift host. Use the following command:

    $ curl 10.10.0.20:8080
    Example output
    Hello MicroShift

Remove a pod from a secondary network

To disconnect a pod from specific network configurations in {product-title}, you can remove the pod from a secondary network. Delete the pod using the oc delete pod command to remove its connection to the secondary network.

Prerequisites
  • A secondary network is attached to the pod.

  • Install the OpenShift CLI (oc).

  • Log in to the cluster.

Procedure
  • Delete the pod by entering the following command:

    $ oc delete pod <name> -n <namespace>

    where:

    <name>

    Specifies the name of the pod.

    <namespace>

    Specifies the namespace that contains the pod.

Troubleshoot Multus networking

If the settings for multiple networks are not configured properly, pods can fail to start. You can check pod network status and the configuration to help you solve a couple common scenarios.

Pod networking cannot be configured

If the Multus CNI plugin cannot apply networking annotations to a pod, the pod does not start. Pods can also fail to start if any of the additional network CNIs fail.

Example error
Warning  NoNetworkFound     0s     multus    cannot find a network-attachment-definitio (asdasd) in namespace (default): network-attachment-definitions.k8s.cni.cncf.io "bad-ref-doesnt-exist" not found

In this case, you can take the following steps to trouble CNI failures:

  • Verify the values in both the NetworkAttachmentDefinitions and the annotations.

  • Remove the annotation to verify whether the pod is created successfully with just the default network. If not, this might indicate a networking problem other than the Multus configuration.

  • If you are a device administrator, you can inspect the crio.service or microshift.service logs, paying special attention to those that are generated by the kubelet.

    For example, the following error from the kubelet shows that the primary CNI is not running. This situation can be caused by pods not starting or because of a CRI-O misconfiguration such as an incorrect cni_default_network setting.

    Example kubelet-generated error
    Feb 06 13:47:31 dev microshift[1494]: kubelet E0206 13:47:31.163290    1494 pod_workers.go:1298] "Error syncing pod, skipping" err="network is not ready: container runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: No CNI configuration file in /etc/cni/net.d/. Has your network provider started?" pod="default/samplepod" podUID="fe0f7f7a-8c47-4488-952b-8abc0d8e2602"
Missing configuration file

Sometimes a pod cannot be created because the annotations reference a NetworkAttachmentDefinition configuration YAML that does not exist. In this case an error such as the following is usually produced:

Example log
cannot find a network-attachment-definition (bad-conf) in namespace (default): network-attachment-definitions.k8s.cni.cncf.io "bad-conf" not found" pod="default/samplepod"`
Example error output
"CreatePodSandbox for pod failed" err="rpc error: code = Unknown desc = failed to create pod network sandbox k8s_samplepod_default_5fa13105-1bfb-4c6b-aee7-3437cfb50e25_0(7517818bd8e85f07b551f749c7529be88b4e7daef0dd572d049aa636950c76c6): error adding pod default_samplepod to CNI network \"multus-cni-network\": plugin type=\"multus\" name=\"multus-cni-network\" failed (add): Multus: [default/samplepod/5fa13105-1bfb-4c6b-aee7-3437cfb50e25]: error loading k8s delegates k8s args: TryLoadPodDelegates: error in getting k8s network for pod: GetNetworkDelegates: failed getting the delegate: getKubernetesDelegate: cannot find a network-attachment-definition (bad-conf) in namespace (default): network-attachment-definitions.k8s.cni.cncf.io \"bad-conf\" not found" pod="default/samplepod"

To fix this error, create and apply the NetworkAttachmentDefinitions YAML.

Provide external access to edge applications

Expose selected services on your MicroShift node to external clients in a controlled, secure, and observable way by using ingress controllers, routes, and router configuration.

Use ingress control in MicroShift

When you create your MicroShift node, each pod and service running on the node is allocated an IP address. These IP addresses are accessible to other pods and services running nearby by default, but are not accessible to external clients. MicroShift uses a minimal implementation of the OpenShift Container Platform IngressController API to enable external access to node services.

With more configuration options, you can fine-tune ingress to meet your specific needs. To use enhanced ingress control, update the parameters in the MicroShift configuration file and restart the service.

Ingress configuration is useful in a variety of ways, for example:

Accommodate server response speed
  • If your application starts processing requests from clients but the connection closes before it can respond, you can set the ingress.tuningOptions.serverTimeout parameter in the configuration file to a higher value to accommodate the speed of the response from the server.

Closing router connections
  • If the router has many connections open because an application running on the node does not close connections properly, you can set the ingress.tuningOptions.serverTimeout and spec.tuningOptions.serverFinTimeout parameters to a lower value, forcing those connections to close sooner.

Verify client certificates
  • If you need to configure the ingress controller to verify client certificates, you can use the ingress.clientTLS parameter to set a clientCA value, which is a reference to a config map. The config map contains the PEM-encoded CA certificate bundle that is used to verify a client’s certificate. Optionally, you can also configure a list of certificate subject filters.

Configure a TLS security profile
  • If you need to configure a TLS security profile for an ingress controller, you can use the ingress.tlsSecurityProfile parameter to specify a default or custom individual TLS security profiles. The TLS security profile defines the minimum TLS version and the TLS ciphers for TLS connections for the ingress controllers. If a TLS security profile is not configured, the default value is based on the TLS security profile set for the API server.

Create policies for new route claims
  • If you need to define a policy for handling new route claims, you can use the routeAdmission parameter to allow or deny claims across namespaces. Set the routeAdmission parameter to describe how hostname claims across namespaces should be handled and to describe how the ingress controller handles routes with wildcard policies.

Customize error pages
  • If you want more than the default error pages, which are usually empty and only return the HTTP status code, configure custom error pages.

Capture HTTP headers or cookies
  • If you want to include the capture of HTTP headers or cookies, configure them in the access logging.

Configure ingress control in MicroShift

To apply detailed ingress control such as timeouts, TLS, and logging in MicroShift, you can update the config.yaml file or add a configuration snippet in the /etc/microshift/config.d/ directory. Replace the default values in the ingress section and restart the service.

Important
  • A config.yaml configuration file takes precedence over built-in settings. The config.yaml file is read every time the MicroShift service starts.

  • Configuration snippet YAMLs take precedence over both built-in settings and the config.yaml configuration file.

Prerequisites
  • You installed the OpenShift CLI (oc).

  • You have root access to the node.

  • Your node uses the OVN-Kubernetes Container Network Interface (CNI) plugin.

Procedure
  1. Apply ingress control settings in one of the two following ways:

    1. Update the MicroShift config.yaml configuration file by making a copy of the provided config.yaml.default file in the /etc/microshift/ directory, naming it config.yaml and keeping it in the source directory.

    2. Use a configuration snippet to apply the ingress control settings you want. To do this, create a configuration snippet YAML file and put it in the /etc/microshift/config.d/ configuration directory.

  2. Replace the default values in the ingress section of the MicroShift YAML with your valid values, or create a configuration snippet file with the sections you need.

    Ingress controller configuration fields with default values
    apiServer:
    # ...
    ingress:
      accessLogging:
        destination:
          container:
            maxLength: 1024
          syslog:
            address: ""
            facility: ""
            maxLength: 1024
            port: 0
          type: ""
        httpCaptureCookies:
          - matchType: ""
            maxLength: 0
            name: ""
            namePrefix: ""
        httpCaptureHeaders:
          request:
            - maxLength: 0
              name: ""
          response:
            - maxLength: 0
              name: ""
        httpLogFormat: ""
        status: Disabled
      certificateSecret: router-certs-custom
      clientTLS:
        allowedSubjectPatterns: []
        clientCA:
          name: ""
        clientCertificatePolicy: ""
      defaultHTTPVersion: 1
      forwardedHeaderPolicy: Append
      httpCompression:
        mimeTypes:
          - ""
      httpEmptyRequestsPolicy: Respond
      httpErrorCodePages:
          name: ""
      listenAddress: []
      logEmptyRequests: Log
      ports:
         http: 80
         https: 443
      routeAdmissionPolicy:
        namespaceOwnership: InterNamespaceAllowed
        wildcardPolicy: WildcardsDisallowed
      status: Managed
      tlsSecurityProfile:
        type:
        custom:
          ciphers:[]
          minTLSVersion:""
        intermediate: {}
        old: {}
      tuningOptions:
        clientFinTimeout: 1s
        clientTimeout: 30s
        headerBufferBytes: 0
        headerBufferMaxRewriteBytes: 0
        healthCheckInterval: 5s
        maxConnections: 0
        serverFinTimeout: 1s
        serverTimeout: 30s
        threadCount: 4
        tlsInspectDelay: 5s
        tunnelTimeout: 1h
    # ...

    See "Ingress controller configuration fields in MicroShift" for more information about each field.

  3. Complete any other configurations you require, then start or restart MicroShift by running one the following commands:

    $ sudo systemctl start microshift
    $ sudo systemctl restart microshift
Verification

After making ingress configuration changes and restarting MicroShift, you can check the age of the router pod to ensure that changes are applied.

  • To check the status of the router pod, run the following command:

    $ oc get pods -n openshift-ingress
    Example output
    NAME                              READY   STATUS    RESTARTS   AGE
    router-default-8649b5bf65-w29cn   1/1     Running   0          6m10s

Ingress controller configuration fields in MicroShift

The following table lists and defines the ingress controller configuration parameters in the MicroShift config.yaml file. You use these parameters when you configure access logging, TLS, timeouts, route admission, and other ingress options.

Table 5. Ingress controller configuration fields definitions table
Parameter Description

ingress

The ingress section of the MicroShift config.yaml file defines the configurable parameters for the implementation of the OpenShift Container Platform IngressController API. All of the following parameters in this table are subsections in the ingress section of the MicroShift config.yaml.

accessLogging

This ingress subsection describes how client requests are logged. If the status field is empty, access logging is disabled. When the status field is set to Enabled, access requests are logged as configured with the accessLogging parameters and the accessLogging.destination.type is automatically set to Container.

  • When enabled, access logging is part of the openshift-router logs. The sos report procedure for MicroShift captures logs from this pod.

accessLogging.destination

A destination for logs. The destination for logs can be a local sidecar container or remote. Default value is null.

accessLogging.destination.type

The type of destination for logs. Valid values are Container or Syslog.

  • Setting this value to Container specifies that logs should go to a sidecar container. When the destination type is set to Container, a container called logs is automatically created. Using container logs means that logs might be dropped if the rate of logs exceeds the container runtime capacity or the custom logging solution capacity. You must have a custom logging solution that reads logs from this sidecar.

  • Setting this value to Syslog specifies that logs are sent to a Syslog endpoint. You must configure a custom Syslog instance and specify an endpoint that can receive Syslog messages. You must have a custom Syslog instance. For example, Getting started with kernel logging.

accessLogging.destination.container

Describes parameters for the Container logging destination type. You must configure a custom logging solution that reads logs from this sidecar.

accessLogging.destination.container.maxLength

Optional configuration. The default value is 1024 bytes. Message length must be at least 480 and not greater than 8192 bytes.

accessLogging.destination.syslog

Describes parameters for the Syslog logging destination type. You must configure a custom Syslog instance with an endpoint that can receive Syslog messages.

accessLogging.destination.syslog.address

Required configuration when the Syslog destination type is set. Valid value is the IP address of the syslog endpoint that receives log messages.

accessLogging.destination.syslog.facility

Optional configuration when the Syslog destination type is set. Specifies the syslog facility of log messages. If this field is empty, the facility is local1. Otherwise, the field must specify one of the following valid syslog facilities: kern, user, mail, daemon, auth, syslog, lpr, news, uucp, cron, auth2`, ftp, ntp, audit, alert, cron2, local0, local1, local2, local3, local4, local5, local6, or local7.

accessLogging.destination.syslog.maxLength

Optional configuration when the Syslog destination type is set. The maximum length of the Syslog message. Message length must be at least 480 and not greater than 4096 bytes. If this field is empty, the maximum length is set to the default value of 1024 bytes.

accessLogging.destination.syslog.port

Required configuration when the Syslog destination type is set. The UDP port number of the syslog endpoint that receives log messages. The default value is 0.

httpCaptureCookies

Specifies HTTP cookies that you want to capture in access logs. If the httpCaptureCookies field is empty, access logs do not capture the cookies. Default value is empty. Configuring ingress.accessLogging.httpCaptureCookies automatically enables ingress access logging. For any cookie that you want to capture, you must also set the matchType and maxLength parameters.

  • For example:

      httpCaptureCookies:
      - matchType: Exact
        maxLength: 128
        name: MYCOOKIE

httpCaptureCookies.matchType

Specifies whether the field name of the cookie exactly matches the capture cookie setting or is a prefix of the capture cookie setting. Valid values are Exact for an exact string match and Prefix for a string prefix match.

  • If you use the Exact setting, you must also specify a name in the httpCaptureCookies.name field.

  • If you use the Prefix setting, you must also specify a prefix in the httpCaptureCookies.namePrefix field. For example, the settings of matchType: Prefix when the namePrefix is "mush" captures a cookie named "mush" or "mushroom" but not one named "room". The first matching cookie is captured.

httpCaptureCookies.maxLength

Specifies the maximum length of the cookie that is logged, which includes the cookie name, cookie value, and one-character delimiter. If the log entry exceeds this length, the value is truncated in the log message. The ingress controller might impose a separate bound on the total length of HTTP headers in a request. The minimum value is 1 byte, maximum value is 1024 bytes. The default value is 0.

httpCaptureCookies.name

Specifies the exact name used for a cookie name match as set in the httpCaptureCookies.matchType parameter. The value must be a valid HTTP cookie name as defined in RFC 6265 section 4.1. The minimum length is 1 byte and the maximum length is 1024 bytes.

httpCaptureCookies.namePrefix

Specifies the prefix for a cookie name match as set in the httpCaptureCookies.matchType parameter. The value must be a valid HTTP cookie name as defined in RFC 6265 section 4.1. The minimum length is 1 byte and the maximum length is 1024 bytes.

httpCaptureHeaders

Defines the HTTP headers that should be captured in the access logs. This field is a list and allows capturing request and response headers independently. When this field is empty, headers are not captured. This option only applies to plain text HTTP connections and to secure HTTP connections for which the ingress controller terminates encryption: for example, edge-terminated or reencrypt connections. Headers cannot be captured for TLS passthrough connections. Configuring the ingress.accessLogging.httpCaptureHeaders parameter automatically enables ingress access logging.

httpCaptureHeaders.request

Specifies which HTTP request headers to capture. When this field is empty, no request headers are captured.

httpCaptureHeaders.request.maxLength

Specifies a maximum length for the header value. When a header value exceeds this length, the value is truncated in the log message. The minimum required value is 1 byte. The ingress controller might impose a separate bound on the total length of HTTP headers in a request.

httpCaptureHeaders.request.name

Specifies a header name. The value must be a valid HTTP header name as defined in RFC 2616 section 4.2. If you configure this value, you must specify maxLength and name values.

httpCaptureHeaders.response

Specifies which HTTP response headers to capture. If this field is empty, no response headers are captured.

httpCaptureHeaders.response.maxLength

Specifies a maximum length for the header value. If a header value exceeds this length, the value is truncated in the log message. The ingress controller might impose a separate bound on the total length of HTTP headers in a request.

httpCaptureHeaders.response.name

Specifies a header name. The value must be a valid HTTP header name as defined in RFC 2616 section 4.2.

httpLogFormat

Specifies the format of the log message for an HTTP request. If this field is empty, log messages use the default HTTP log format. For HAProxy default HTTP log format, see the HAProxy documentation.

status

Specifies whether access is logged or not. Valid values are Enabled and Disabled. Default value is Disabled.

  • When you configure either ingress.accessLogging.httpCaptureHeaders or ingress.accessLogging.httpCaptureCookies, you must set ingress.accessLogging.status to Enabled.

  • When you set the ingress.status field to Enabled, the accessLogging.destination.type is automatically set to Container and the router logs all requests in the logs container.

  • If you set this value to Disabled, the router does not log any requests in the access log.

certificateSecret

A reference to a kubernetes.io/tls type of secret that contains the default certificate that the MicroShift ingress controller serves. When routes do not specify their own certificate, the certificateSecret parameter is used. All secrets used must contain tls.key key file contents and tls.crt certificate file contents.

  • When the certificateSecret parameter is not set, a wildcard certificate is automatically generated and used. The wildcard certificate is valid for the ingress controller default domain and its subdomains. The generated certificate authority (CA) is automatically integrated with the truststore of the node.

  • In-use generated and user-specified certificates are automatically integrated with the MicroShift built-in OAuth server.

clientTLS

Authenticates client access to the node and services. As a result, mutual TLS authentication is enabled. If this parameter is not set, then client TLS is not enabled. You must set the spec.clientTLS.clientCertificatePolicy and spec.clientTLS.clientCA parameters to use client TLS.

clientTLS.AllowedSubjectPatterns

Optional subfield that specifies a list of regular expressions that are matched against the distinguished name on a valid client certificate to filter requests. This parameter is useful when you have client authentication. Use this parameter to cause the ingress controller to reject certificates based on the distinguished name. The Perl Compatible Regular Expressions (PCRE) syntax is required. You must set the spec.clientTLS.clientCertificatePolicy and spec.clientTLS.clientCA parameters to use clientTLS.AllowedSubjectPatterns.

Important

When configured, this field must contain a valid expression or the MicroShift service fails. At least one pattern must match a client certificate’s distinguished name; otherwise, the ingress controller rejects the certificate and denies the connection.

clientTLS.clientCA

Specifies a required config map that is in the openshift-ingress namespace. Required to enable client TLS. The config map must contain a certificate authority (CA) bundle named ca-bundle.pem or the deployment of the default router fails.

clientTLS.clientCA.name

The metadata.name of the config map referenced in the clientTLS.clientCA value.

clientTLS.ClientCertificatePolicy

Required or Optional are valid values. Set to Required to enable client TLS. The ingress controller only checks client certificates for edge-terminated and re-encrypted TLS routes. The ingress controller cannot check certificates for plain text HTTP or passthrough TLS routes.

defaultHTTPVersion

Sets the HTTP version for the ingress controller. The default value is 1 for HTTP 1.1. Setting up a load balancer for HTTP 2 and 3 is recommended.

forwardedHeaderPolicy

Specifies when and how the ingress controller sets the Forwarded, X-Forwarded-For, X-Forwarded-Host, X-Forwarded-Port, X-Forwarded-Proto, and X-Forwarded-Proto-Version HTTP headers. The following values are valid:

  • Append preserves any existing headers by specifying that the ingress controller appends them. 'Append` is the default value.

  • Replace removes any existing headers by specifying that the ingress controller sets the headers.

  • IfNone sets the headers set by specifying that the ingress controller sets the headers if they are not already set.

  • Never preserves any existing headers by specifying that the ingress controller never sets the headers.

httpCompression

Defines the policy for HTTP traffic compression.

httpCompression.mimeTypes

Defines a list of MIME types to which compression should be applied.

  • For example, text/css; charset=utf-8, text/html, text/*, image/svg+xml, application/octet-stream, X-custom/customsub, in the, type/subtype; [;attribute=value] format.

  • Valid types are: application, image, message, multipart, text, video, or a custom type prefaced by X-. To see the full notation for MIME types and subtypes, see RFC1341 (IETF Datatracker documentation).

httpEmptyRequestsPolicy

Describes how HTTP connections are handled if the connection times out before a request is received. Allowed values for this field are Respond and Ignore. The default value is Respond. Empty requests typically come from load-balancer health probes or preconnects and can often be safely ignored. However, network errors and port scans can also cause these requests. Therefore, setting this field to Ignore can impede detection or diagnosis of network problems and detecting intrusion attempts.

  • When the policy is set to Respond, the ingress controller sends an HTTP 400 or 408 response, logs the connection if access logging is enabled, and counts the connection in the appropriate metrics.

  • When the policy is set to Ignore, the http-ignore-probes parameter is added to the HAproxy process configuration. After this parameter is added, the ingress controller closes the connection without sending a response, then either logs the connection or incrementing metrics.

logEmptyRequests

Specifies connections for which no request is received and logged. Log and Ignore are valid values. Empty requests typically come from load-balancer health probes or preconnects and can often be safely ignored. However, network errors and port scans can also cause these requests. Therefore, setting this field to Ignore can impede detection or diagnosis of network problems and detecting intrusion attempts. The default value is Log.

  • Setting this value to Log indicates that an event should be logged.

  • Setting this value to Ignore sets the dontlognull option in the HAproxy configuration.

httpErrorCodePages

Describes custom error code pages. To use this setting, you must configure the httpErrorCodePages.name parameter.

httpErrorCodePages.name

Specifies custom error code pages. You can only customize errors for 503 and 404 page codes. To customize error code pages, specify a ConfigMap name. The ConfigMap object must be in the openshift-ingress namespace and contain keys in the error-page-<error code>.http format where <error code> is an HTTP status code. Each value in the ConfigMap must be the full response, including HTTP headers. The default value of this parameter is null.

ports

Defines default router ports.

ports.http

Default router http port. Must be in range 1-65535. Default value is 80.

ports.https

Default router https port. Must be in range 1-65535. Default value is 443.

routeAdmission

Defines a policy for handling new route claims, such as allowing or denying claims across namespaces.

routeAdmission.namespaceOwnership

Describes how hostname claims across namespaces are handled. The default is InterNamespaceAllowed. The following are valid values:

  • Strict does not allow routes to claim the same hostname across namespaces.

  • InterNamespaceAllowed allows routes to claim different paths of the same hostname across namespaces.

routeAdmission.wildcardPolicy

Controls how the ingress controller handles routes with configured wildcard policies. WildcardsAllowed and WildcardsDisallowed are valid values. Default value is WildcardsDisallowed.

  • WildcardPolicyAllowed means that the ingress controller admits routes with any wildcard policy.

  • WildcardPolicyDisallowed means that the ingress controller admits only routes with a wildcard policy of None.

Important

Changing the wildcard policy from WildcardsAllowed to WildcardsDisallowed causes admitted routes with a wildcard policy of subdomain to stop working. The ingress controller only readmits these routes after they are recreated with a wildcard policy of None.

status

Default router status. Managed or Removed are valid values.

tlsSecurityProfile

tlsSecurityProfile specifies settings for TLS connections for ingress controllers. If not set, the default value is based on the apiservers.config.openshift.io/cluster resource. The TLS 1.0 version of an Old or Custom profile is automatically converted to 1.1 by the ingress controller. Intermediate is the default setting.

  • The minimum TLS version for ingress controllers is 1.1. The maximum TLS version is 1.3.

Note

The TLSProfile status shows the ciphers and the minimum TLS version of the configured security profile. Profiles are intent-based and change over time when new ciphers are developed and existing ciphers are found to be insecure. The usable list can be reduced depending on which ciphers are available to a specific process.

tlsSecurityProfile.custom

User-defined TLS security profile. If you configure this parameter and related parameters, use extreme caution.

tlsSecurityProfile.custom.ciphers

Specifies the cipher algorithms that are negotiated during the TLS handshake. Operators might remove entries their operands do not support.

tlsSecurityProfile.custom.minTLSVersion

Specifies the minimal version of the TLS protocol that is negotiated during the TLS handshake. For example, to use TLS versions 1.1, 1.2 and 1.3, set the value to VersionTLS11. The highest valid value for minTLSVersion is VersionTLS12.

tlsSecurityProfile.intermediate

You can use this TLS profile for a majority of services. Intermediate compatibility (recommended).

tlsSecurityProfile.old

Used for backward compatibility. Old backward compatibility.

tlsSecurityProfile.type

Valid values are Intermediate, Old, or Custom. The Modern value is not supported.

tuningOptions

Specifies options for tuning the performance of ingress controller pods.

tuningOptions.clientFinTimeout

Specifies how long the ingress controller holds a connection open while waiting for a client response before the server closes the connection. The default timeout is 1s.

tuningOptions.clientTimeout

Specifies how long the ingress controller holds a connection open while waiting for a client response. The default timeout is 30s.

tuningOptions.headerBufferBytes

Specifies how much memory is reserved, in bytes, for ingress controller connection sessions. This value must be at least 16384 if HTTP/2 is enabled for the ingress controller. If not set, the default value is 32768 bytes.

Important

Setting this field not recommended because headerBufferMaxRewriteBytes parameter values that are too small can break the ingress controller. Conversely, values for headerBufferMaxRewriteBytes that are too large could cause the ingress controller to use significantly more memory than necessary.

tuningOptions.headerBufferMaxRewriteBytes

Specifies how much memory should be reserved, in bytes, from headerBufferBytes for HTTP header rewriting and appending for ingress controller connection sessions. The minimum value for headerBufferMaxRewriteBytes is 4096. headerBufferBytes must be greater than the headerBufferMaxRewriteBytes value for incoming HTTP requests. If not set, the default value is 8192 bytes.

Important

Setting this field is not recommended because headerBufferMaxRewriteBytes values that are too small can break the ingress controller and headerBufferMaxRewriteBytes that are too large could cause the ingress controller to use significantly more memory than necessary.

tuningOptions.healthCheckInterval

Specifies how long the router waits between health checks, set in seconds. The default is 5s.

tuningOptions.maxConnections

Specifies the maximum number of simultaneous connections that can be established for each HAProxy process. Increasing this value allows each ingress controller pod to handle more connections at the cost of additional system resources. Permitted values are 0, -1, any value within the range 2000 and 2000000, or the field can be left empty.

  • If this field is empty or has the value 0, the ingress controller uses the default value of 50000.

  • If the field has the value of -1, then the HAProxy process dynamically computes a maximum value based on the available ulimits in the running container. This process results in a large computed value that incurs significant memory usage compared to the current default value of 50000.

  • If the field has a value that is greater than the current operating system limit, the HAProxy processes do not start.

  • If you choose a discrete value and the router pod is migrated to a new node, it is possible that the new node does not have an identical ulimit configured. In such cases, the pod fails to start.

  • You can monitor memory usage for router containers with the container_memory_working_set_bytes{container="router",namespace="openshift-ingress"} metric.

  • You can monitor memory usage of individual HAProxy processes in router containers with the container_memory_working_set_bytes{container="router",namespace="openshift-ingress"}/container_processes{container="router",namespace="openshift-ingress"} metric.

tuningOptions.serverFinTimeout

Specifies how long a connection is held open while waiting for the server response to the client that is closing the connection. The default timeout is 1s.

tuningOptions.serverTimeout

Specifies how long a connection is held open while waiting for a server response. The default timeout is 30s.

tuningOptions.threadCount

Specifies the number of threads to create per HAProxy process. Creating more threads allows each ingress controller pod to handle more connections, at the cost of using more system resources. The HAProxy load balancer supports up to 64 threads. If this field is empty, the ingress controller uses the default value of 4 threads.

Important

Setting this field is not recommended because increasing the number of HAProxy threads allows ingress controller pods to use more CPU time under load, and prevent other pods from receiving the CPU resources they need to perform. Reducing the number of threads can cause the ingress controller to perform poorly.

tuningOptions.tlsInspectDelay

Specifies how long the router can hold data to find a matching route. Setting this value too low can cause the router to fall back to the default certificate for edge-terminated, re-encrypted, or passthrough routes, even when using a better-matched certificate. The default inspect delay is 5s.

tuningOptions.tunnelTimeout

Specifies how long a tunnel connection, including websockets, remains open while the tunnel is idle. The default timeout is 1h.

Create a secret for the ingress controller certificateSecret

To secure network traffic with your own certificate, you must create a TLS secret and update the configuration file. This process configures a custom default certificate for the MicroShift ingress router.

Note

Any in-use certificates automatically integrate with the MicroShift built-in OAuth server.

To configure application-level certificates for a Kubernetes Ingress object by using the spec.tls field, follow the procedure in "Creating a route through an Ingress object".

Prerequisites
  • Root access to the MicroShift host.

  • Installation of the OpenShift CLI (oc).

  • A decrypted, non-password-protected TLS private key in Privacy-Enhanced Mail (PEM) format.

  • A PEM-encoded TLS certificate.

  • A valid certificate for the MicroShift apps wildcard where the subjectAltName extension includes DNS names covering *.apps.<nodename>.<domain>.

Note

This procedure only applies to the default ingress router certificate, ingress.certificateSecret.

Procedure
  1. Create a secret that contains the wildcard certificate chain and key:

    $ oc create secret tls <secret> \
         --cert=</path/to/cert.crt> \
         --key=</path/to/cert.key> \
         -n openshift-ingress
    • Replace <secret> with the name of the secret that contains the certificate chain and private key.

    • Replace </path/to/cert.crt> with the path to the certificate chain on your local file system.

    • Replace </path/to/cert.key> with the path to the private key associated with this certificate.

      Important

      The certificate must include the subjectAltName extension showing *.apps.<nodename>.<domain>.

  2. Update the certificateSecret parameter value in the MicroShift configuration YAML with the newly created secret.

  3. Complete any other configurations you require, then start or restart MicroShift by running one of the following commands:

    $ sudo systemctl start microshift
    $ sudo systemctl restart microshift

Configure the TLS security profile for the ingress controller

To configure the TLS security profile for the ingress controller in MicroShift, you can add the spec.tlsSecurityProfile field to the configuration YAML and set a value for the appropriate profile. To apply the changes, restart the service.

Prerequisites
  • You have root access to the MicroShift node.

Procedure
  1. Add the spec.tlsSecurityProfile field to the MicroShift YAML configuration file.

     ...
    spec:
      tlsSecurityProfile:
        type: Custom
        custom:
          ciphers:
          - ECDHE-ECDSA-CHACHA20-POLY1305
          - ECDHE-RSA-CHACHA20-POLY1305
          - ECDHE-RSA-AES128-GCM-SHA256
          - ECDHE-ECDSA-AES128-GCM-SHA256
          minTLSVersion: VersionTLS11
     ...

    where:

    spec.tlsSecurityProfile.type

    Specifies the TLS security profile type (Old, Intermediate, or Custom). The default is Intermediate.

    spec.tlsSecurityProfile.custom

    Specifies the appropriate field for the selected type:

    • old: {}

    • intermediate: {}

    • custom:

    spec.tlsSecurityProfile.custom.ciphers

    Specifies a list of TLS ciphers and minimum accepted TLS version.

    Warning

    If you choose a custom TLS configuration, use extreme caution. Using self-signed TLS certificates can introduce security risks.

  2. Save the file to apply the changes.

  3. Restart MicroShift by running the following command:

    $ sudo systemctl restart microshift

About configuring the router

To make ingress optional, you can configure MicroShift ingress router settings to manage which ports, if any, are exposed to network traffic. Specified routing is an example of ingress load balancing.

  • The default ingress router is always on, running on all IP addresses on the http: 80 and https: 443 ports.

  • Default router settings allow access to any namespace.

Some applications running on top of MicroShift might not require the default router and instead create their own. You can configure the router to control both ingress and namespace access.

Tip

You can check for the presence of the default router in your MicroShift installation before you begin configurations by using the oc get deployment -n openshift-ingress command, which returns the following output:

NAME             READY   UP-TO-DATE   AVAILABLE   AGE
router-default   1/1     1            1           2d23h

Router settings and valid values

Valid values and defaults for ingress router fields in the config.yaml file on MicroShift cover listenAddress, ports, routeAdmissionPolicy, and status.

Example config.yaml router settings
# ...
ingress:
  listenAddress:
    - ""
  ports:
    http: 80
    https: 443
  routeAdmissionPolicy:
    namespaceOwnership: InterNamespaceAllowed
  status: Managed
# ...

where:

ingress.listenAddress

Specifies the single IP address or host name or a list of IP addresses or host names. The default value is the entire network of the host.

ingress.ports

Specifies a single, unique port in the 1 to 65535 range. The values of the ports.http and ports.https fields cannot be the same.

ingress.routeAdmissionPolicy.namespaceOwnership

Specifies whether routes can claim different paths of the same host name across namespaces. The default value is InterNamespaceAllowed.

ingress.status

Specifies whether the ingress ports remain open. The default value is Managed.

Important

The firewalld service is bypassed by the default MicroShift router and by configurations that enable the router. Ingress and egress must be controlled by setting network policies when the router is active.

Disable the router

To disable the router in MicroShift when inbound services are not required, including in industrial IoT environments where pods connect only to southbound operational systems and northbound cloud-data systems, set ingress.status to Removed in the config.yaml file and restart the service.

Prerequisites
  • You installed MicroShift.

  • You created a MicroShift config.yaml file.

  • The OpenShift CLI (oc) is installed.

Tip

If you complete all the configurations that you need to make in the MicroShift config.yaml file at the same time, you can minimize system restarts.

Procedure
  1. Update the value of ingress.status field to Removed in the MicroShift config.yaml file as shown in the following example:

    Example config.yaml ingress stanza
    # ...
    ingress:
      ports:
        http: 80
        https: 443
      routeAdmissionPolicy:
        namespaceOwnership: InterNamespaceAllowed
      status: Removed
    # ...

    where:

    ingress.status

    Specifies whether the ingress ports remain open. When the value is set to Removed, the ports listed in ingress.ports are automatically closed. Any other settings in the ingress stanza are ignored, for example, any values in the routeAdmissionPolicy.namespaceOwnership field.

  2. Restart the MicroShift service by running the following command:

    $ sudo systemctl restart microshift
    Note

    The MicroShift service outputs current configurations during restarts.

Verification
  • After the system restarts, verify that the router has been removed and that ingress is stopped by running the following command:

    $ oc -n openshift-ingress get svc
    Expected output
    No resources found in openshift-ingress namespace.

Configure router ingress

Configure the listenAddress setting if your MicroShift applications need to listen only for data traffic. You can also configure specific ports and IP addresses for network connections. Use the combination required to customize the endpoint configuration for your use case.

Configure router ports

To bind the ingress router to specific HTTP and HTTPS port numbers in MicroShift, you can edit the ingress.ports.http and ingress.ports.https settings in config.yaml file.

Prerequisites
  • You installed MicroShift.

  • You created a MicroShift config.yaml file.

  • The OpenShift CLI (oc) is installed.

Tip

If you complete all the configurations that you need to make in the MicroShift config.yaml file at the same time, you can minimize system restarts.

Procedure
  1. Update the MicroShift config.yaml port values in the ingress.ports.http and ingress.ports.https fields to the ports you want to use:

    Example config.yaml router settings
    # ...
    ingress:
      ports:
        http: 80
        https: 443
      routeAdmissionPolicy:
        namespaceOwnership: InterNamespaceAllowed
      status: Managed
    # ...

    where:

    ingress.ports

    Specifies the HTTP and HTTPS port numbers to bind the ingress router to. This field is customizable. Valid values for both port entries are a single, unique port in the 1-65535 range. The values of the ports.http and ports.https fields cannot be the same.

    status

    Specifies the status of the ingress ports. The default value is Managed. Managed is required for the ingress ports to remain open.

  2. Restart the MicroShift service by running the following command:

    $ sudo systemctl restart microshift

Configure router IP addresses

To limit ingress to selected host IP addresses or network interfaces in MicroShift, you can set the ingress.listenAddress list in your config.yaml file.

You can restrict the network traffic to the router by configuring specific IP addresses. For example:

  • Use cases where the router is reachable only on internal networks, but not on northbound public networks

  • Use cases where the router is reachable only by northbound public networks, but not on internal networks

  • Use cases where the router is reachable by both internal networks and northbound public networks, but on separate IP addresses

Prerequisites
  • You installed MicroShift.

  • You created a MicroShift config.yaml file.

  • The OpenShift CLI (oc) is installed.

Tip

If you complete all the configurations that you need to make in the MicroShift config.yaml file at the same time, you can minimize system restarts.

Procedure
  1. Update the list in the ingress.listenAddress field in the MicroShift config.yaml according to your requirements and as shown in the following examples:

    Default router IP address list
    # ...
    ingress:
      listenAddress:
        - "<host_network>"
    # ...

    where:

    ingress.listenAddress

    Specifies the IP addresses or network interfaces to limit ingress to. The default value is the entire network of the host. To continue to use the default list, remove the listen.Address field from the MicroShift config.yaml file. To customize this parameter, use a list. The list can contain either a single IP address or NIC name or multiple IP addresses and NIC names.

    Important

    You must either remove the listenAddress parameter or add values to it in the form of a list when using the config.yaml file. Do not leave the field empty or MicroShift crashes on restart.

    Example router setting with a single host IP address
    # ...
    ingress:
      listenAddress:
        - 10.2.1.100
    # ...
    Example router setting with a combination of IP addresses and NIC names
    # ...
    ingress:
      listenAddress:
        - 10.2.1.100
        - 10.2.2.10
        - ens3
    # ...
  2. Restart the MicroShift service by running the following command:

    $ sudo systemctl restart microshift
Verification
  • To verify that your settings are applied, make sure that the ingress.listenAddress IP addresses are reachable, then you can curl the route with the destination to one of these load balancer IP address.

Configure the route admission policy

By default, MicroShift allows routes in multiple namespaces to use the same hostname. To prevent routes from claiming the same hostname in different namespaces, you can configure the route admission policy.

Prerequisites
  • You installed MicroShift.

  • You created a MicroShift config.yaml file.

  • You installed the OpenShift CLI (oc).

    Tip

    If you complete all the configurations that you need to make in the MicroShift config.yaml file at the same time, you can minimize system restarts.

Procedure
  1. To prevent routes in different namespaces from claiming the same hostname, update the namespaceOwnership field value to Strict in the MicroShift config.yaml file. See the following example:

    Example config.yaml route admission policy
    # ...
    ingress:
      routeAdmissionPolicy:
        namespaceOwnership: Strict
    # ...

    where:

    ingress.routeAdmissionPolicy.namespaceOwnership

    Specifies the route admission policy. Prevents routes in different namespaces from claiming the same host. Valid values are Strict and InterNamespaceAllowed. If you delete the value in a customized config.yaml, the InterNamespaceAllowed value is set automatically.

  2. To apply the configuration, restart the MicroShift service by running the following command:

    $ sudo systemctl restart microshift

Create an HTTP-based route

To host your application at a public URL by using the basic HTTP routing protocol, create an HTTP-based route. This configuration exposes a service on an unsecured application port, allowing external access without TLS encryption.

A route can either be secure or unsecured, depending on the network security configuration of your application.

The following procedure describes how to create a simple HTTP-based route to a web application, using the hello-microshift application as an example.

Prerequisites
  • You installed the OpenShift CLI (oc).

  • You have access to your MicroShift node.

  • You have a web application that exposes a port and a TCP endpoint listening for traffic on the port.

Procedure
  1. Create a service called hello-microshift by running the following command:

    $ oc expose pod hello-microshift -n $namespace
  2. Create an unsecured route to the hello-microshift application by running the following command:

    $ oc expose svc/hello-microshift --hostname=microshift.com $namespace
Verification
  • Verify that the route resource was created by running the following command:

    $ oc get routes -o yaml <name of resource> -n $namespace
  • namespace: Specifies the route that is named hello-microshift and the namespace is named hello-microshift.

    Sample YAML definition for the created unsecured route
    apiVersion: route.openshift.io/v1
    kind: Route
    metadata:
      name: hello-microshift
      namespace: hello-microshift
    spec:
      host: microshift.com
      port:
        targetPort: 8080
      to:
        kind: Service
        name: hello-microshift

    where:

    spec.host

    Specifies the hostname.

    port.targetPort

    Specifies the target port for the router to map the endpoint port in the service.

    Note

    MicroShift does not use an API that creates a default ingress domain, but instead provides a wildcard for automatically generated domains. Each route can also define a separate hostname.

HTTP Strict Transport Security

To enhance security and optimize website performance, use the HTTP Strict Transport Security (HSTS) policy. This mechanism signals browsers to use only HTTPS traffic on the route host, eliminating the need for HTTP redirects and speeding up user interactions.

When HSTS policy is enforced, HSTS adds a Strict Transport Security header to HTTP and HTTPS responses from the site. You can use the insecureEdgeTerminationPolicy value in a route to redirect HTTP to HTTPS. When HSTS is enforced, the client changes all requests from the HTTP URL to HTTPS before the request is sent, eliminating the need for a redirect.

Cluster administrators can configure HSTS to do the following:

  • Enable HSTS per-route

  • Disable HSTS per-route

  • Enforce HSTS per-domain, for a set of domains, or use namespace labels in combination with domains

Important

HSTS works only with secure routes, either edge-terminated or re-encrypt. The configuration is ineffective on HTTP or passthrough routes.

Enable HTTP Strict Transport Security per-route

To enforce secure HTTPS connections for specific applications, enable HTTP Strict Transport Security (HSTS) on a per-route basis. Applying the haproxy.router.openshift.io/hsts_header annotation to edge and re-encrypt routes ensures that browsers reject unencrypted traffic.

Prerequisites
  • You are logged in to the cluster with a user with administrator privileges for the project.

  • You installed the OpenShift CLI (oc).

Procedure
  • To enable HSTS on a route, add the haproxy.router.openshift.io/hsts_header value to the edge-terminated or re-encrypt route. You can use the oc annotate tool to do this by running the following command. To properly run the command, ensure that the semicolon (;) in the haproxy.router.openshift.io/hsts_header route annotation is also surrounded by double quotation marks ("").

    Example annotate command that sets the maximum age to 31536000 ms (approximately 8.5 hours)
    $ oc annotate route <route_name> -n <namespace> --overwrite=true "haproxy.router.openshift.io/hsts_header=max-age=31536000;\
    includeSubDomains;preload"
    Example route configured with an annotation
    apiVersion: route.openshift.io/v1
    kind: Route
    metadata:
      annotations:
        haproxy.router.openshift.io/hsts_header: max-age=31536000;includeSubDomains;preload
    # ...
    spec:
      host: def.abc.com
      tls:
        termination: "reencrypt"
        ...
      wildcardPolicy: "Subdomain"
    # ...

    where:

    max-age

    Specifies the measurement of the length of time, in seconds, for the HSTS policy. If set to 0, it negates the policy.

    includeSubDomains

    Specifies that all subdomains of the host must have the same HSTS policy as the host. Optional parameter.

    preload

    Specifies that the site is included in the HSTS preload list when max-age is greater than 0. For example, sites such as Google can construct a list of sites that have preload set. Browsers can then use these lists to determine which sites they can communicate with over HTTPS, even before they have interacted with the site. Without preload set, browsers must have interacted with the site over HTTPS, at least once, to get the header. Optional parameter.

Disable HTTP Strict Transport Security per-route

To allow unencrypted connections or troubleshoot access issues, disable HTTP Strict Transport Security (HSTS) for a specific route. Setting the max-age route annotation to 0 instructs browsers to stop enforcing HTTPS requirements on the route host.

Prerequisites
  • You are logged in to the cluster with a user with administrator privileges for the project.

  • You installed the OpenShift CLI (oc).

Procedure
  • To disable HSTS, enter the following to set the max-age value in the route annotation to 0:

    $ oc annotate route <route_name> -n <namespace> --overwrite=true "haproxy.router.openshift.io/hsts_header"="max-age=0"
    Tip

    You can alternatively apply the following YAML to create the config map for disabling HSTS per-route:

    kind: Route
    apiVersion: route.openshift.io/v1
    metadata:
      annotations:
        haproxy.router.openshift.io/hsts_header: max-age=0
  • To disable HSTS for every route in a namespace, enter the following command:

    $ oc annotate route --all -n <namespace> --overwrite=true "haproxy.router.openshift.io/hsts_header"="max-age=0"
Verification
  • To query the annotation for all routes, enter the following command:

    $ oc get route  --all-namespaces -o go-template='{{range .items}}{{if .metadata.annotations}}{{$a := index .metadata.annotations "haproxy.router.openshift.io/hsts_header"}}{{$n := .metadata.name}}{{with $a}}Name: {{$n}} HSTS: {{$a}}{{"\n"}}{{else}}{{""}}{{end}}{{end}}{{end}}'
    Example output
    Name: routename HSTS: max-age=0

Enforce HTTP Strict Transport Security per-domain

To enforce secure communication per-domain, configure routes with a compliant HSTS policy annotation. For upgraded nodes with non-compliant routes, ensure consistent enforcement by updating the source manifests to apply the new security policies.

You cannot use oc expose route or oc create route commands to add a route in a domain that enforces HSTS because the API for these commands does not accept annotations.

Important

HSTS cannot be applied to insecure, or non-TLS, routes.

Prerequisites
  • You have root access to the node.

  • You installed the OpenShift CLI (oc).

Procedure
  • Apply HSTS to all routes in the node by running the following command:

    $ oc annotate route --all --all-namespaces --overwrite=true "haproxy.router.openshift.io/hsts_header"="max-age=31536000;preload;includeSubDomains"
  • Apply HSTS to all routes in a particular namespace by running the following command:

    $ oc annotate route --all -n <my_namespace> --overwrite=true "haproxy.router.openshift.io/hsts_header"="max-age=31536000;preload;includeSubDomains"
  • <my_namespace>: Specify the namespace that you want to use.

Verification
  • Review the HSTS annotations on all routes by running the following command:

    $ oc get route  --all-namespaces -o go-template='{{range .items}}{{if .metadata.annotations}}{{$a := index .metadata.annotations "haproxy.router.openshift.io/hsts_header"}}{{$n := .metadata.name}}{{with $a}}Name: {{$n}} HSTS: {{$a}}{{"\n"}}{{else}}{{""}}{{end}}{{end}}{{end}}'
    Example output
    Name: <_routename_> HSTS: max-age=31536000;preload;includeSubDomains

Throughput issue troubleshooting methods

To diagnose and resolve network throughput issues, such as unusually high latency between specific services, apply troubleshooting methods. Identifying connectivity bottlenecks helps ensure stable application performance within {product-title}.

If pod logs do not reveal any cause of the problem, use the following methods to analyze performance issues:

  • Use a packet analyzer, such as ping or tcpdump to analyze traffic between a pod and its node.

    For example, run the tcpdump tool on each pod while reproducing the behavior that led to the issue. Review the captures on both sides to compare send and receive timestamps to analyze the latency of traffic to and from a pod. Latency can occur in {product-title} if a node interface is overloaded with traffic from other pods, storage devices, or the data plane.

    $ tcpdump -s 0 -i any -w /tmp/dump.pcap host <podip 1> && host <podip 2> 1

    where:

    podip

    Specifies the IP address for the pod. Run the oc get pod <pod_name> -o wide command to get the IP address of a pod.

    The tcpdump command generates a file at /tmp/dump.pcap containing all traffic between these two pods. You can run the analyzer shortly before the issue is reproduced and stop the analyzer shortly after the issue is finished reproducing to minimize the size of the file. You can also run a packet analyzer between the nodes with:

    $ tcpdump -s 0 -i any -w /tmp/dump.pcap port 4789
  • Use a bandwidth measuring tool, such as iperf, to measure streaming throughput and UDP throughput. Locate any bottlenecks by running the tool from the pods first, and then running it from the nodes.

  • In some cases, the cluster might mark the node with the router pod as unhealthy due to latency issues. Use worker latency profiles to adjust the frequency that the cluster waits for a status update from the node before taking action.

  • If your cluster has designated lower-latency and higher-latency nodes, configure the spec.nodePlacement field in the Ingress Controller to control the placement of the router pod.

Use cookies to keep route statefulness

To maintain stateful application traffic during pod restarts or scaling events, configure sticky sessions by using cookies. By using this method, you ensure that all incoming traffic reaches the same endpoint, preventing state loss even if the specific endpoint pod changes.

{product-title} can use cookies to configure session persistence. The Ingress Controller selects an endpoint to handle any user requests, and creates a cookie for the session. The cookie is passed back in the response to the request and the user sends the cookie back with the next request in the session. The cookie tells the Ingress Controller which endpoint is handling the session, ensuring that client requests use the cookie so that they are routed to the same pod.

Note

Cookies cannot be set on passthrough routes, because the HTTP traffic cannot be seen. Instead, a number is calculated based on the source IP address, which determines the backend.

If backends change, the traffic can be directed to the wrong server, making it less sticky. If you are using a load balancer, which hides source IP, the same number is set for all connections and traffic is sent to the same pod.

To enable applications to manage session persistence and load distribution, annotate the route with a custom cookie name. Overwriting the default cookie allows the backend application to identify and delete the specific cookie, forcing endpoint re-selection when necessary.

When a server is overloaded, the server tries to remove the requests from the client and redistribute the requests to other endpoints.

Procedure
  1. Annotate the route with the specified cookie name:

    $ oc annotate route <route_name> router.openshift.io/cookie_name="<cookie_name>"

    where:

    <route_name>

    Specifies the name of the route.

    <cookie_name>

    Specifies the name for the cookie.

    For example, to annotate the route my_route with the cookie name my_cookie:

    $ oc annotate route my_route router.openshift.io/cookie_name="my_cookie"
  2. Capture the route hostname in a variable:

    $ ROUTE_NAME=$(oc get route <route_name> -o jsonpath='{.spec.host}')

    where:

    <route_name>

    Specifies the name of the route.

  3. Save the cookie, and then access the route:

    $ curl $ROUTE_NAME -k -c /tmp/cookie_jar

    Use the cookie saved by the previous command when connecting to the route:

    $ curl $ROUTE_NAME -k -b /tmp/cookie_jar

Path-based routes

To serve multiple applications by using a single hostname, configure path-based routes. This HTTP-based configuration directs traffic to specific services by comparing the URL path component, ensuring requests match the most specific route defined.

The following table shows example routes and their accessibility:

Table 6. Route availability
Route When compared to Accessible

www.example.com/test

www.example.com/test

Yes

www.example.com

No

www.example.com/test and www.example.com

www.example.com/test

Yes

www.example.com

Yes

www.example.com

www.example.com/text

Yes (Matched by the host, not the route)

www.example.com

Yes

Example of an unsecured route with a path
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: route-unsecured
spec:
  host: www.example.com
  path: "/test"
  to:
    kind: Service
    name: service-name
  • spec.host: Specifies the path attribute for a path-based route.

Note

Path-based routing is not available when using passthrough TLS, as the router does not terminate TLS in that case and cannot read the contents of the request.

HTTP header configuration

To customize request and response headers for your applications, configure the Ingress Controller or apply specific route annotations. Understanding the interaction between these configuration methods ensures you effectively manage global and route-specific header policies.

You can also set certain headers by using route annotations. The various ways of configuring headers can present challenges when working together.

Note

You can only set or delete headers within an IngressController or Route CR, you cannot append them. If an HTTP header is set with a value, that value must be complete and not require appending in the future. In situations where it makes sense to append a header, such as the X-Forwarded-For header, use the spec.httpHeaders.forwardedHeaderPolicy field, instead of spec.httpHeaders.actions.

Order of precedence

When the same HTTP header is modified both in the Ingress Controller and in a route, HAProxy prioritizes the actions in certain ways depending on whether it is a request or response header.

  • For HTTP response headers, actions specified in the Ingress Controller are executed after the actions specified in a route. This means that the actions specified in the Ingress Controller take precedence.

  • For HTTP request headers, actions specified in a route are executed after the actions specified in the Ingress Controller. This means that the actions specified in the route take precedence.

For example, a cluster administrator sets the X-Frame-Options response header with the value DENY in the Ingress Controller using the following configuration:

Example IngressController spec
apiVersion: operator.openshift.io/v1
kind: IngressController
# ...
spec:
  httpHeaders:
    actions:
      response:
      - name: X-Frame-Options
        action:
          type: Set
          set:
            value: DENY

A route owner sets the same response header that the cluster administrator set in the Ingress Controller, but with the value SAMEORIGIN using the following configuration:

Example Route spec
apiVersion: route.openshift.io/v1
kind: Route
# ...
spec:
  httpHeaders:
    actions:
      response:
      - name: X-Frame-Options
        action:
          type: Set
          set:
            value: SAMEORIGIN

When both the IngressController spec and Route spec are configuring the X-Frame-Options response header, then the value set for this header at the global level in the Ingress Controller takes precedence, even if a specific route allows frames. For a request header, the Route spec value overrides the IngressController spec value.

This prioritization occurs because the haproxy.config file uses the following logic, where the Ingress Controller is considered the front end and individual routes are considered the back end. The header value DENY applied to the front end configurations overrides the same header with the value SAMEORIGIN that is set in the back end:

frontend public
  http-response set-header X-Frame-Options 'DENY'

frontend fe_sni
  http-response set-header X-Frame-Options 'DENY'

frontend fe_no_sni
  http-response set-header X-Frame-Options 'DENY'

backend be_secure:openshift-monitoring:alertmanager-main
  http-response set-header X-Frame-Options 'SAMEORIGIN'

Additionally, any actions defined in either the Ingress Controller or a route override values set using route annotations.

Special case headers

The following headers are either prevented entirely from being set or deleted, or allowed under specific circumstances:

Table 7. Special case header configuration options
Header name Configurable using IngressController spec Configurable using Route spec Reason for disallowment Configurable using another method

proxy

No

No

The proxy HTTP request header can be used to exploit vulnerable CGI applications by injecting the header value into the HTTP_PROXY environment variable. The proxy HTTP request header is also non-standard and prone to error during configuration.

No

host

No

Yes

When the host HTTP request header is set using the IngressController CR, HAProxy can fail when looking up the correct route.

No

strict-transport-security

No

No

The strict-transport-security HTTP response header is already handled using route annotations and does not need a separate implementation.

Yes: the haproxy.router.openshift.io/hsts_header route annotation

cookie and set-cookie

No

No

The cookies that HAProxy sets are used for session tracking to map client connections to particular back-end servers. Allowing these headers to be set could interfere with HAProxy’s session affinity and restrict HAProxy’s ownership of a cookie.

Yes:

  • the haproxy.router.openshift.io/disable_cookie route annotation

  • the haproxy.router.openshift.io/cookie_name route annotation

Set or delete HTTP request and response headers in a route

You can set or delete certain HTTP request and response headers for compliance purposes or other reasons. You can set or delete these headers either for all routes served by an Ingress Controller or for specific routes.

For example, you might want to enable a web application to serve content in alternate locations for specific routes if that content is written in multiple languages, even if there is a default global location specified by the Ingress Controller serving the routes.

The following procedure creates a route that sets the Content-Location HTTP request header so that the URL associated with the application, https://app.example.com, directs to the location https://app.example.com/lang/en-us. Directing application traffic to this location means that anyone using that specific route is accessing web content written in American English.

Prerequisites
  • You have installed the OpenShift CLI (oc).

  • You are logged into an {product-title} cluster as a project administrator.

  • You have a web application that exposes a port and an HTTP or TLS endpoint listening for traffic on the port.

Procedure
  1. Create a route definition and save it in a file called app-example-route.yaml:

    YAML definition of the created route with HTTP header directives
    apiVersion: route.openshift.io/v1
    kind: Route
    # ...
    spec:
      host: app.example.com
      tls:
        termination: edge
      to:
        kind: Service
        name: app-example
      httpHeaders:
        actions:
          response:
          - name: Content-Location
            action:
              type: Set
              set:
                value: /lang/en-us
    # ...

    where:

    actions

    Specifies the list of actions you want to perform on the HTTP headers.

    response

    Specifies the type of header you want to change. In this case, a response header.

    response.name

    Specifies the name of the header you want to change. For a list of available headers you can set or delete, see HTTP header configuration.

    action.type

    Specifies the type of action being taken on the header. This field can have the value Set or Delete.

    set.value

    When setting HTTP headers, you must provide a value. The value can be a string from a list of available directives for that header, for example DENY, or it can be a dynamic value that will be interpreted using HAProxy’s dynamic value syntax. In this case, the value is set to the relative location of the content.

  2. Create a route to your existing web application using the newly created route definition:

    $ oc -n app-example create -f app-example-route.yaml

    For HTTP request headers, the actions specified in the route definitions are executed after any actions performed on HTTP request headers in the Ingress Controller. This means that any values set for those request headers in a route will take precedence over the ones set in the Ingress Controller. For more information on the processing order of HTTP headers, see HTTP header configuration.

Create a route through an Ingress object

To integrate ecosystem components that require Ingress resources, configure an Ingress object. {product-title} automatically manages the lifecycle of the corresponding route objects, creating and deleting them to ensure seamless connectivity.

Prerequisites
  • If clients must receive a full certificate chain, you must combine the PEM-encoded leaf certificate and intermediates into a single file. Place the leaf certificate first, followed by each issuer in chain order.

  • You confirmed the private key matches the leaf certificate in the tls.crt key.

  • You confirmed the tls.key key has only the private key for the leaf certificate.

  • The certificate Subject Alternative Name (SAN), or the subject CN if no SAN is present, covers every hostname set in spec.rules[].host and spec.tls[].hosts. These values must match for the same host.

  • The private key is not password-encrypted. You must decrypt the key before you create the TLS secret so that {product-title} can read the key material.

  • You created a Secret of type kubernetes.io/tls in the same namespace as the Ingress. The secretName must match the spec.tls[].secretName field. If you have not created the secret, you must do so before you apply the Ingress object.

Procedure
  1. Define an Ingress object in the {product-title} console or by entering the oc create command:

    YAML Definition of an Ingress
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: frontend
      annotations:
        route.openshift.io/termination: "reencrypt"
        route.openshift.io/destination-ca-certificate-secret: secret-ca-cert
    spec:
      rules:
      - host: www.example.com
        http:
          paths:
          - backend:
              service:
                name: frontend
                port:
                  number: 443
            path: /
            pathType: Prefix
      tls:
      - hosts:
        - www.example.com
        secretName: example-com-tls-certificate
    # ...

    where:

    route.openshift.io/termination

    Specifies the route.openshift.io/termination annotation. You can configure the spec.tls.termination parameter of the Route because Ingress does not have this parameter. The accepted values are edge, passthrough, and reencrypt. All other values are silently ignored. When the annotation value is unset, edge is the default route. The TLS certificate details must be defined in the template file to implement the default edge route.

    rules.host

    Specifies an explicit hostname for the Ingress object. Mandatory parameter. You can use the <host_name>.<cluster_ingress_domain> syntax, for example apps.openshiftdemos.com, to take advantage of the *.<cluster_ingress_domain> wildcard DNS record and serving certificate for the cluster. Otherwise, you must ensure that there is a DNS record for the chosen hostname.

    destination-ca-certificate-secret

    Specifies the route.openshift.io/destination-ca-certificate-secret annotation. The annotation can be used on an Ingress object to define a route with a custom destination certificate (CA). The annotation references a kubernetes secret, secret-ca-cert that will be inserted into the generated route.

    1. If you specify the passthrough value in the route.openshift.io/termination annotation, set path to '' and pathType to ImplementationSpecific in the spec:

      apiVersion: networking.k8s.io/v1
      kind: Ingress
      # ...
        spec:
          rules:
          - host: www.example.com
            http:
              paths:
              - path: ''
                pathType: ImplementationSpecific
                backend:
                  service:
                    name: frontend
                    port:
                      number: 443
      # ...
      $ oc apply -f ingress.yaml
    2. To specify a route object with a destination CA from an ingress object, you must create a kubernetes.io/tls or Opaque type secret with a certificate in PEM-encoded format in the data.tls.crt specifier of the secret.

  2. List your routes:

    $ oc get routes

    The result includes an autogenerated route whose name starts with frontend-:

    NAME             HOST/PORT         PATH    SERVICES    PORT    TERMINATION          WILDCARD
    frontend-gnztq   www.example.com           frontend    443     reencrypt/Redirect   None
    YAML definition example of an autogenerated route
    apiVersion: route.openshift.io/v1
    kind: Route
    metadata:
      name: frontend-gnztq
      ownerReferences:
      - apiVersion: networking.k8s.io/v1
        controller: true
        kind: Ingress
        name: frontend
        uid: 4e6c59cc-704d-4f44-b390-617d879033b6
    spec:
      host: www.example.com
      path: /
      port:
        targetPort: https
      tls:
        certificate: |
          -----BEGIN CERTIFICATE-----
          [...]
          -----END CERTIFICATE-----
        insecureEdgeTerminationPolicy: Redirect
        key: |
          -----BEGIN RSA PRIVATE KEY-----
          [...]
          -----END RSA PRIVATE KEY-----
        termination: reencrypt
        destinationCACertificate: |
          -----BEGIN CERTIFICATE-----
          [...]
          -----END CERTIFICATE-----
      to:
        kind: Service
        name: frontend

Create a route using the default certificate through an Ingress object

To generate a secure, edge-terminated route that uses the default ingress certificate, specify an empty TLS configuration in the Ingress object. This configuration overrides the default behavior, preventing the creation of an insecure route.

Prerequisites
  • You have a service that you want to expose.

  • You have access to the OpenShift CLI (oc).

Procedure
  1. Create a YAML file for the Ingress object. In the following example, the file is called example-ingress.yaml:

    YAML definition of an Ingress object
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: frontend
      ...
    spec:
      rules:
        ...
      tls:
      - {}

    where:

    spec.tls

    Specifies the TLS configuration. Use the exact syntax shown to specify TLS without specifying a custom certificate.

  2. Create the Ingress object by running the following command:

    $ oc create -f example-ingress.yaml
Verification
  • Verify that {product-title} has created the expected route for the Ingress object by running the following command:

    $ oc get routes -o yaml
    Example output
    apiVersion: v1
    items:
    - apiVersion: route.openshift.io/v1
      kind: Route
      metadata:
        name: frontend-j9sdd
    # ...
      spec:
      ...
        tls:
          insecureEdgeTerminationPolicy: Redirect
          termination: edge
    # ...

    where:

    metadata.name

    Specifies the name of the route, which includes the name of the Ingress object followed by a random suffix.

    spec.tls

    To use the default certificate, the route should not specify spec.certificate.

    tls.termination

    Specifies the termination policy for the route. The route should specify the edge termination policy.

Create a route using the destination CA certificate in the Ingress annotation

To define a route with a custom destination CA certificate, apply the route.openshift.io/destination-ca-certificate-secret annotation to an Ingress object. This configuration ensures the Ingress Controller uses the specified secret to verify the identity of the destination service.

Prerequisites
  • You have a certificate/key pair in PEM-encoded files, where the certificate is valid for the route host.

  • You have a separate CA certificate in a PEM-encoded file that completes the certificate chain.

  • You have a separate destination CA certificate in a PEM-encoded file.

  • You have a service that you want to expose.

Procedure
  1. Create a secret for the destination CA certificate by entering the following command:

    $ oc create secret generic dest-ca-cert --from-file=tls.crt=<file_path>

    For example:

    $ oc -n test-ns create secret generic dest-ca-cert --from-file=tls.crt=tls.crt
    Example output
    secret/dest-ca-cert created
  2. Add the route.openshift.io/destination-ca-certificate-secret to the Ingress annotations:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: frontend
      annotations:
        route.openshift.io/termination: "reencrypt"
        route.openshift.io/destination-ca-certificate-secret: secret-ca-cert
    ...

    where:

    destination-ca-certificate-secret

    Specifies the route.openshift.io/destination-ca-certificate-secret annotation. The annotation references a Kubernetes secret.

    The Ingress Controller inserts a secret that is referenced in the annotation into the generated route.

    Example output
    apiVersion: route.openshift.io/v1
    kind: Route
    metadata:
      name: frontend
      annotations:
        route.openshift.io/termination: reencrypt
        route.openshift.io/destination-ca-certificate-secret: secret-ca-cert
    spec:
    ...
      tls:
        insecureEdgeTerminationPolicy: Redirect
        termination: reencrypt
        destinationCACertificate: |
          -----BEGIN CERTIFICATE-----
          [...]
          -----END CERTIFICATE-----
    ...

Secure the MicroShift API and control plane

Configure certificates and TLS to ensure that only trusted clients can communicate with the MicroShift API and that traffic is authenticated and encrypted.

Use custom certificate authorities for the MicroShift API server

To enable external clients to verify the MicroShift API server and maintain encrypted connections, you can replace the default internal certificate with a custom server certificate issued by a trusted certificate authority (CA).

By default, clients outside of the node cannot verify the MicroShift-issued API server certificate. You must update the configuration file with the certificate location and relevant domain names to ensure secure access across your network.

The following steps illustrate the workflow for customizing the API server certificate configuration in MicroShift:

  1. Copy the certificates and keys to the preferred directory in the host operating system. Ensure that the files are accessible only with root access.

  2. Update the MicroShift configuration for each custom CA by specifying the certificate names and new fully qualified domain name (FQDN) in the MicroShift /etc/microshift/config.yaml configuration file.

    Each certificate configuration can contain the following values:

    • The certificate file location is a required value.

    • A single common name containing the API server DNS and IP address or IP address range.

      Tip

      In most cases, MicroShift generates a new kubeconfig file for your custom CA that includes the IP address or range that you specify. The exception is when you specify wildcards for the IP address. In this case, MicroShift generates a kubeconfig file with the public IP address of the server. To use wildcards, you must update the kubeconfig file with your specific details.

    • Multiple Subject Alternative Names (SANs) containing the API server DNS and IP addresses or a wildcard certificate.

    • You can list additional DNS names for each certificate.

  3. After the MicroShift service restarts, you must copy the generated kubeconfig files to the client.

  4. Configure additional CAs on the client system. For example, you can update CA bundles in the Red Hat Enterprise Linux (RHEL) truststore.

    Important

    Custom server certificates must be validated against CA data configured in the trust root of the host operating system. For more information, read the following documentation:

  5. The certificates and keys are read from the specified file location on the host. You can test and validate configuration from the client.

    • If any validation fails, MicroShift skips the custom configuration and uses the default certificate to start. The priority is to continue the service uninterrupted. MicroShift logs errors when the service starts. Common errors include expired certificates, missing files, or wrong IP addresses.

  6. External server certificates are not automatically renewed. You must manually rotate your external certificates.

Configure custom certificate authorities

To configure externally generated certificates and domain names by using custom certificate authorities (CAs), add them to the MicroShift /etc/microshift/config.yaml configuration file. You must also configure the host operating system trust root.

Note

Externally generated kubeconfig files are created in the /var/lib/microshift/resources/kubeadmin/<hostname>/kubeconfig directory. If you need to use localhost in addition to externally generated configurations, retain the original kubeconfig file in its default location. The localhost kubeconfig file uses the self-signed certificate authority.

Prerequisites
  • The OpenShift CLI (oc) is installed.

  • You have root access to the node.

  • The certificate authority has issued the custom certificates.

  • A MicroShift /etc/microshift/config.yaml configuration file exists.

Procedure
  1. Copy the custom certificates you want to add to the trust root of the MicroShift host. Ensure that the certificate and private keys are only accessible to MicroShift.

  2. For each custom CA that you need, add an apiServer section called namedCertificates to the /etc/microshift/config.yaml MicroShift configuration file by using the following example:

    apiServer:
      namedCertificates:
       - certPath: ~/certs/api_fqdn_1.crt
         keyPath:  ~/certs/api_fqdn_1.key
       - certPath: ~/certs/api_fqdn_2.crt
         keyPath:  ~/certs/api_fqdn_2.key
         names:
         - api_fqdn_1
         - *.apps.external.com

    where:

    apiServer.namedCertificates.certPath

    Add the full path to the certificate.

    apiServer.namedCertificates.keyPath

    Add the full path to the certificate key.

    apiServer.namedCertificates.names

    Optional. Add a list of explicit DNS names. Leading wildcards are allowed. If no names are listed, the implicit names are extracted from the certificates.

  3. Restart the MicroShift to apply the certificates by running the following command:

    $ systemctl microshift restart
  4. Wait a few minutes for the system to restart and apply the custom server. New kubeconfig files are generated in the /var/lib/microshift/resources/kubeadmin/ directory.

  5. Copy the kubeconfig files to the client. If you specified wildcards for the IP address, update the kubeconfig to remove the public IP address of the server and replace that IP address with the specific wildcard range you want to use.

  6. From the client, use the following steps:

    1. Specify the kubeconfig to use by running the following command:

      $ export KUBECONFIG=~/custom-kubeconfigs/kubeconfig

      Use the location of the copied kubeconfig file as the path.

    2. Check that the certificates are applied by using the following command:

      $ oc --certificate-authority ~/certs/ca.ca get node
      Example output
      oc get node
      NAME                             STATUS   ROLES                         AGE   VERSION
      dhcp-1-235-195.arm.example.com   Ready    control-plane,master,worker   76m   v1.35.4
    3. Add the new CA file to the $KUBECONFIG environment variable by running the following command:

      $ oc config set clusters.microshift.certificate-authority /tmp/certificate-authority-data-new.crt
    4. Verify that the new kubeconfig file contains the new CA by running the following command:

      $ oc config view --flatten
      Example externally generated kubeconfig file
      apiVersion: v1
      clusters:
      - cluster:
          certificate-authority: /tmp/certificate-authority-data-new.crt
          server: https://api.ci-ln-k0gim2b-76ef8.aws-2.ci.openshift.org:6443
        name: ci-ln-k0gim2b-76ef8
      contexts:
      - context:
          cluster: ci-ln-k0gim2b-76ef8
          user:
        name:
      current-context:
      kind: Config
      preferences: {}

      where:

      clusters.cluster.certificate-authority

      The certificate-authority-data section is not present in externally generated kubeconfig files. It is added with the oc config set command used previously.

    5. Verify the subject and issuer of your customized API server certificate authority by running the following command:

      $ curl --cacert /tmp/caCert.pem https://${fqdn_name}:6443/healthz -v
      Example output
      Server certificate:
        subject: CN=kas-test-cert_server
        start date: Mar 12 11:39:46 2024 GMT
        expire date: Mar 12 11:39:46 2025 GMT
        subjectAltName: host "dhcp-1-235-3.arm.eng.rdu2.redhat.com" matched cert's "dhcp-1-235-3.arm.eng.rdu2.redhat.com"
        issuer: CN=kas-test-cert_ca
        SSL certificate verify ok.
      Important

      Either replace the certificate-authority-data in the generated kubeconfig file with the new rootCA or add the certificate-authority-data to the trust root of the operating system. Do not use both methods.

    6. Configure additional CAs in the trust root of the operating system. For example, in the RHEL Client truststore on the client system. The system-wide truststore.

      • Updating the certificate bundle with the configuration that contains the CA is recommended.

      • If you do not want to configure your certificate bundles, you can alternately use the oc login localhost:8443 --certificate-authority=/path/to/cert.crt command, but this method is not preferred.

Custom certificates reserved name values

Certificate problems cause MicroShift to ignore certificates dynamically and log an error. Problems can be caused by:

  • The certificate files do not exist on the disk or are not readable.

  • The certificate is not parsable.

  • The certificate overrides the internal certificates IP addresses or DNS names in a SubjectAlternativeNames (SAN) field. Do not use a reserved name when configuring SANs.

Table 8. Reserved Names values
Address Type Comment

localhost

DNS

127.0.0.1

IP Address

10.42.0.0

IP Address

Node Network

10.43.0.0/16,10.44.0.0/16

IP Address

Service Network

169.254.169.2/29

IP Address

br-ex Network

kubernetes.default.svc

DNS

openshift.default.svc

DNS

svc.cluster.local

DNS

Troubleshoot custom certificates

To troubleshoot the implementation of custom certificates, you can take the following steps.

Procedure
  1. From MicroShift, ensure that the certificate is served by the kube-apiserver and verify that the certificate path is appended to the --tls-sni-cert-key FLAG by running the following command:

    $ journalctl -u microshift -b0 | grep tls-sni-cert-key
    Example output
    Jan 24 14:53:00 localhost.localdomain microshift[45313]: kube-apiserver I0124 14:53:00.649099   45313 flags.go:64] FLAG: --tls-sni-cert-key="[/home/eslutsky/dev/certs/server.crt,/home/eslutsky/dev/certs/server.key;/var/lib/microshift/certs/kube-apiserver-external-signer/kube-external-serving/server.crt,/var/lib/microshift/certs/kube-apiserver-external-signer/kube-external-serving/server.key;/var/lib/microshift/certs/kube-apiserver-localhost-signer/kube-apiserver-localhost-serving/server.crt,/var/lib/microshift/certs/kube-apiserver-localhost-signer/kube-apiserver-localhost-serving/server.key;/var/lib/microshift/certs/kube-apiserver-service-network-signer/kube-apiserver-service-network-serving/server.crt,/var/lib/microshift/certs/kube-apiserver-service-network-signer/kube-apiserver-service-network-serving/server.key
  2. From the client, ensure that the kube-apiserver is serving the correct certificate by running the following command:

    $ openssl s_client -connect <SNI_ADDRESS>:6443 -showcerts | openssl x509 -text -noout -in - | grep -C 1 "Alternative\|CN"

Cleaning up and recreating the custom certificates

You can stop the MicroShift service, clean up the custom certificates, and re-create the custom certificates, to ensure that your system uses the most recent certificate data.

Procedure
  1. Stop the MicroShift services and clean up the custom certificates by running the following command:

    $ sudo microshift-cleanup-data --cert
    Example output
    Stopping MicroShift services
    Removing MicroShift certificates
    MicroShift service was stopped
    Cleanup succeeded
  2. Restart the MicroShift services to recreate the custom certificates by running the following command:

    $ sudo systemctl start microshift

Use TLS with MicroShift

Transport layer security (TLS) profiles provide a way for servers to regulate which ciphers a client can use when connecting to the server. Using TLS helps to ensure that MicroShift applications use cryptographic libraries that do not allow known insecure protocols, ciphers, or algorithms. You can use either the TLS 1.2 or TLS 1.3 security profiles with MicroShift.

MicroShift API server cipher suites apply automatically to the following internal control plane components:

  • API server

  • Kubelet

  • Kube controller manager

  • Kube scheduler

  • etcd

  • Route controller manager

The API server uses the configured minimum TLS version and the associated cipher suites. If you leave the cipher suites parameter empty, the defaults for the configured minimum version are used automatically.

Default cipher suites for TLS 1.2

The following list specifies the default cipher suites for TLS 1.2:

  • TLS_AES_128_GCM_SHA256

  • TLS_AES_256_GCM_SHA384

  • TLS_CHACHA20_POLY1305_SHA256

  • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256

  • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

  • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384

  • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

  • TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256

  • TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256

Default cipher suites for TLS 1.3

The following list specifies the default cipher suites for TLS 1.3:

  • TLS_AES_128_GCM_SHA256

  • TLS_AES_256_GCM_SHA384

  • TLS_CHACHA20_POLY1305_SHA256

Configure TLS for MicroShift

You can choose to use either the TLS 1.2 or TLS 1.3 security profiles with MicroShift for system hardening.

Prerequisites
  • You have access to the node as a root user.

  • MicroShift has either not started for the first time, or is stopped.

  • The OpenShift CLI (oc) is installed.

  • The certificate authority has issued the custom certificates (CAs).

Procedure
  1. Make a copy of the provided config.yaml.default file in the /etc/microshift/ directory, renaming it config.yaml.

  2. Keep the new MicroShift config.yaml in the /etc/microshift/ directory. Your config.yaml file is read every time the MicroShift service starts.

    Note

    After you create it, the config.yaml file takes precedence over built-in settings.

  3. Optional: Use a configuration snippet if you are using an existing MicroShift YAML. See "Using configuration snippets" in the Additional resources section for more information.

  4. Replace the default values in the tls section of the MicroShift YAML with your valid values.

    Example TLS 1.2 configuration
    apiServer:
    # ...
      tls:
        cipherSuites:
        - <cipher_suite_1>
        - ...
        minVersion: VersionTLS12
    # ...

    where:

    apiServer.tls.cipherSuites

    Defaults to the suites of the configured minVersion. If minVersion is not configured, the default value is TLS 1.2. You can specify the cipher suites you want to use from the list of supported cipher suites. All clients connecting to the API server must support the configured cipher suites or the connections fail during the TLS handshake phase. Be sure to add the CA certificate bundle to the list of CA certificates that the TLS client or server trusts.

    apiServer.tls.minVersion

    Specify VersionTLS12 or VersionTLS13.

    Important

    When you choose TLS 1.3 as the minimum TLS version, only the default MicroShift cipher suites can be used. Additional cipher suites are not configurable. If other cipher suites to use with TLS 1.3 are configured, those suites are ignored and overwritten by the MicroShift defaults.

  5. Complete any other additional configurations that you require, then restart MicroShift by running the following command:

    $ sudo systemctl restart microshift

Default cipher suites

Default cipher suites are included with MicroShift for both TLS 1.2 and TLS 1.3. The cipher suites for TLS 1.3 cannot be customized.

Default cipher suites for TLS 1.2

The following list specifies the default cipher suites for TLS 1.2:

  • TLS_AES_128_GCM_SHA256

  • TLS_AES_256_GCM_SHA384

  • TLS_CHACHA20_POLY1305_SHA256

  • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256

  • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

  • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384

  • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

  • TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256

  • TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256

Default cipher suites for TLS 1.3

The following list specifies the default cipher suites for TLS 1.3:

  • TLS_AES_128_GCM_SHA256

  • TLS_AES_256_GCM_SHA384

  • TLS_CHACHA20_POLY1305_SHA256

Configure audit logging for compliance, monitoring, and incident investigation

Configure and retain audit logs that record administrative and API activity so that you can monitor system usage, investigate security incidents, and produce evidence for compliance audits.

About setting limits on audit log files

To prevent logging data from exceeding the storage capacity of far-edge devices, you can set rotation and retention limits for MicroShift audit log files. Configuring the size, number, and age values ensures that host systems maintain the processing space required for node workloads.

The values you set to limit MicroShift audit logs enable you to enforce the size, number, and age limits of audit log backups. Field values are processed independently of one another and without prioritization.

You can set fields in combination to define a maximum storage limit for retained logs. For example:

  • Set both maxFileSize and maxFiles to create a log storage upper limit.

  • Set a maxFileAge value to automatically delete files older than the timestamp in the file name, regardless of the maxFiles value.

Default audit log values

MicroShift includes the following default audit log rotation values:

Table 9. MicroShift default audit log values
Audit log parameter Default setting Definition

maxFileAge:

0

How long log files are retained before automatic deletion. The default value means that a log file is never deleted based on age. This value can be configured.

maxFiles:

10

The total number of log files retained. By default, MicroShift retains 10 log files. The oldest is deleted when an excess file is created. This value can be configured.

maxFileSize:

200

By default, when the audit.log file reaches the maxFileSize limit, the audit.log file is rotated and MicroShift begins writing to a new audit.log file. This value is in megabytes and can be configured.

profile:

Default

The Default profile setting only logs metadata for read and write requests; request bodies are not logged except for OAuth access token requests. If you do not specify this field, the Default profile is used.

The maximum default storage usage for audit log retention is 2000Mb if there are 10 or fewer files.

If you do not specify a value for a field, the default value is used. If you remove a previously set field value, the default value is restored after the next MicroShift service restart.

Important

You must configure audit log retention and rotation in Red Hat Enterprise Linux (RHEL) for logs that are generated by application pods. These logs print to the console and are saved. Ensure that your log preferences are configured for the RHEL /var/log/audit/audit.log file to maintain MicroShift node health.

About audit log policy profiles

To monitor activity and maintain compliance, you can apply audit log profiles that define the level of detail recorded for API server requests. While more comprehensive profiles provide request bodies for troubleshooting, they also increase resource overhead on the host system.

Audit log profiles define how to log requests that come to the OpenShift API server, Kubernetes API server, OpenShift OAuth API server, and OpenShift OAuth server.

{product-title} provides the following predefined audit policy profiles:

Profile Description

Default

Logs only metadata for read and write requests; does not log request bodies except for OAuth access token requests. This is the default policy.

WriteRequestBodies

In addition to logging metadata for all requests, logs request bodies for every write request to the API servers (create, update, patch, delete, deletecollection). This profile has more resource overhead than the Default profile. [1]

AllRequestBodies

In addition to logging metadata for all requests, logs request bodies for every read and write request to the API servers (get, list, create, update, patch). This profile has the most resource overhead. [1]

None

No requests are logged, including OAuth access token requests and OAuth authorize token requests. Custom rules are ignored when this profile is set.

Warning

Do not disable audit logging by using the None profile unless you are fully aware of the risks of not logging data that can be beneficial when troubleshooting issues. If you disable audit logging and a support situation arises, you might need to enable audit logging and reproduce the issue to troubleshoot properly.

  1. Sensitive resources, such as Secret, Route, and OAuthClient objects, are only logged at the metadata level. OpenShift OAuth server events are only logged at the metadata level.

By default, {product-title} uses the Default audit log profile. You can use another audit policy profile that also logs request bodies, but be aware of the increased resource usage such as CPU, memory, and I/O.

Configure audit log values

To manage disk space, you can customize the audit log retention settings in the MicroShift configuration file. Adjusting values such as file age and size ensures that the system retains critical event data without exhausting local storage.

Procedure
  1. Make a copy of the provided config.yaml.default file in the /etc/microshift/ directory, renaming it config.yaml. Keep the new MicroShift config.yaml you create in the /etc/microshift/ directory. The new config.yaml is read whenever the MicroShift service starts. After you create it, the config.yaml file takes precedence over built-in settings.

  2. Replace the default values in the auditLog section of the YAML with your desired valid values.

    Example default auditLog configuration
    apiServer:
    # ....
      auditLog:
        maxFileAge: 7
        maxFileSize: 200
        maxFiles: 1
        profile: Default
    # ....

    where:

    apiServer.auditLog.maxFileAge

    Specifies the maximum time in days that log files are kept. Files older than this limit are deleted. In this example, after a log file is more than 7 days old, it is deleted. The files are deleted regardless of whether or not the live log has reached the maximum file size specified in the maxFileSize field. File age is determined by the timestamp written in the name of the rotated log file, for example, audit-2024-05-16T17-03-59.994.log. When the value is 0, the limit is disabled.

    apiServer.auditLog.maxFileSize

    The maximum audit log file size in megabytes. In this example, the file is rotated as soon as the live log reaches the 200 MB limit. When the value is set to 0, the limit is disabled.

    apiServer.auditLog.maxFiles

    The maximum number of rotated audit log files retained. After the limit is reached, the log files are deleted in order from oldest to newest. In this example, the value 1 results in only 1 file of size maxFileSize being retained in addition to the current active log. When the value is set to 0, the limit is disabled.

    apiServer.auditLog.profile

    Logs only metadata for read and write requests; does not log request bodies except for OAuth access token requests. If you do not specify this field, the Default profile is used.

  3. Optional: To specify a new directory for logs, you can stop MicroShift, and then move the /var/log/kube-apiserver directory to your desired location:

    1. Stop MicroShift by running the following command:

      $ sudo systemctl stop microshift
    2. Move the /var/log/kube-apiserver directory to your desired location by running the following command:

      $ sudo mv /var/log/kube-apiserver <~/kube-apiserver>

      Replace <~/kube-apiserver> with the path to the directory that you want to use.

    3. If you specified a new directory for logs, create a symlink to your custom directory at /var/log/kube-apiserver by running the following command:

      $ sudo ln -s <~/kube-apiserver> /var/log/kube-apiserver

      Replace <~/kube-apiserver> with the path to the directory that you want to use. This enables the collection of logs in sos reports.

  4. If you are configuring audit log policies on a running instance, restart MicroShift by entering the following command:

    $ sudo systemctl restart microshift

Troubleshoot audit log configuration

You can use the following steps to troubleshoot MicroShift custom audit log settings and file locations.

Procedure
  • Check the current values that are configured by running the following command:

    $ sudo microshift show-config --mode effective
    Example output
    auditLog:
        maxFileSize: 200
        maxFiles: 1
        maxFileAge: 7
        profile: AllRequestBodies
  • Check the audit.log file permissions by running the following command:

    $ sudo ls -ltrh /var/log/kube-apiserver/audit.log
    Example output
    -rw-------. 1 root root 46M Mar 12 09:52 /var/log/kube-apiserver/audit.log
  • List the contents of the current log directory by running the following command:

    $ sudo ls -ltrh /var/log/kube-apiserver/
    Example output
    total 6.0M
    -rw-------. 1 root root 2.0M Mar 12 10:56 audit-2024-03-12T14-56-16.267.log
    -rw-------. 1 root root 2.0M Mar 12 10:56 audit-2024-03-12T14-56-49.444.log
    -rw-------. 1 root root 962K Mar 12 10:57 audit.log

Understand how to use sigstore to verify container signatures

To verify image integrity within your MicroShift environment, you can configure the container runtime to use the sigstore signing methodology. This ensures a safer chain of custody by enabling the digital signing and verification of build artifacts.

  • For user-specific images, you must update the configuration file to point to the appropriate public key, or disable signature verification for those image sources.

Important

For disconnected or offline configurations, you must embed the public key contents into the operating system image.

Verify container signatures using sigstore

To secure your MicroShift environment against unauthorized image deployments, you can configure the container runtime to verify container signatures. By using sigstore with Red Hat public keys, you ensure that only authentic, signed images from trusted registries are used.

You can access Red Hat public keys at the following link:

You must use the release key 3 for verifying MicroShift container signatures.

Prerequisites
  • You have admin access to the MicroShift host.

  • You installed MicroShift.

Procedure
  1. Download the relevant public key and save it as /etc/containers/RedHat_ReleaseKey3.pub by running the following command:

    $ sudo curl -sL https://access.redhat.com/security/data/63405576.txt -o /etc/containers/RedHat_ReleaseKey3.pub
  2. To configure the container runtime to verify images from Red Hat sources, edit the /etc/containers/policy.json file to contain the following configuration:

    Example policy JSON file
    {
        "default": [
            {
                "type": "reject"
            }
        ],
        "transports": {
            "docker": {
                "quay.io/openshift-release-dev": [{
                    "type": "sigstoreSigned",
                    "keyPath": "/etc/containers/RedHat_ReleaseKey3.pub",
                    "signedIdentity": {
                        "type": "matchRepoDigestOrExact"
                    }
                }],
                "registry.redhat.io": [{
                    "type": "sigstoreSigned",
                    "keyPath": "/etc/containers/RedHat_ReleaseKey3.pub",
                    "signedIdentity": {
                        "type": "matchRepoDigestOrExact"
                    }
                }]
            }
        }
    }
  3. Configure Red Hat remote registries to use sigstore attachments when pulling images to the local storage, by editing the /etc/containers/registries.d/registry.redhat.io.yaml file to contain the following configuration:

    $ cat /etc/containers/registries.d/registry.redhat.io.yaml
    docker:
         registry.redhat.io:
             use-sigstore-attachments: true
  4. Configure Red Hat remote registries to use sigstore attachments when pulling images to the local storage, by editing the /etc/containers/registries.d/registry.quay.io.yaml file to contain the following configuration:

    $ cat /etc/containers/registries.d/quay.io.yaml
    docker:
      quay.io/openshift-release-dev:
        use-sigstore-attachments: true
  5. Create user-specific registry configuration files if your use case requires signature verification for those image sources. You can use the example here to start with and add your own requirements.

Next steps
  1. If you are using a mirror registry, enable sigstore attachments.

  2. Otherwise, proceed to wiping the local container storage clean.

Enable sigstore attachments for mirror registries

If you are using mirror registries, you must apply additional configuration to enable sigstore attachments and mirroring by digest.

Prerequisites
  • You have admin access to the MicroShift host.

  • You completed the steps in "Verifying container signatures using sigstore."

Procedure
  1. Enable sigstore attachments by creating the /etc/containers/registries.d/mirror.registry.local.yaml file.

    $ cat /etc/containers/registries.d/<mirror.registry.local.yaml>
    docker:
       mirror.registry.local:
            use-sigstore-attachments: true

    Name the <mirror.registry.local.yaml> file after your mirror registry URL.

  2. Enable mirroring by digest by creating the /etc/containers/registries.conf.d/999-microshift-mirror.conf with the following contents:

    $ cat /etc/containers/registries.conf.d/999-microshift-mirror.conf
    [[registry]]
        prefix = "quay.io/openshift-release-dev"
        location = "mirror.registry.local"
        mirror-by-digest-only = true
    
    [[registry]]
        prefix = "registry.redhat.io"
        location = "mirror.registry.local"
        mirror-by-digest-only = true
Next steps
  1. Wipe the local container storage clean.

Wipe local container storage clean

To ensure that container images with sigstore signatures are correctly downloaded and verified, you must clear existing local storage. Removing previous container data prevents configuration conflicts when you update security policies for MicroShift.

Prerequisites
  • You have administrator access to the MicroShift host.

  • You enabled sigstore on your mirror registries.

Procedure
  1. Stop the CRI-O container runtime service and MicroShift by running the following command:

    $ sudo systemctl stop crio microshift
  2. Wipe the CRI-O container runtime storage clean by running the following command:

    $ sudo crio wipe --force
  3. Restart the CRI-O container runtime service and MicroShift by running the following command:

    $ sudo systemctl start crio microshift
Verification

Verify that all pods are running in a healthy state by entering the following command:

$ oc get pods -A
Example output
NAMESPACE                   NAME                                                     READY   STATUS   RESTARTS  AGE
default                     i-06166fbb376f14a8bus-west-2computeinternal-debug-qtwcr  1/1     Running  0		    46m
kube-system                 csi-snapshot-controller-5c6586d546-lprv4                 1/1     Running  0		    51m
openshift-dns               dns-default-45jl7                                        2/2     Running  0		    50m
openshift-dns               node-resolver-7wmzf                                      1/1     Running  0		    51m
openshift-ingress           router-default-78b86fbf9d-qvj9s                          1/1     Running  0		    51m
openshift-ovn-kubernetes    ovnkube-master-5rfhh                                     4/4     Running  0		    51m
openshift-ovn-kubernetes    ovnkube-node-gcnt6                                       1/1     Running  0		    51m
openshift-service-ca        service-ca-bf5b7c9f8-pn6rk                               1/1     Running  0		    51m
openshift-storage           topolvm-controller-549f7fbdd5-7vrmv                      5/5     Running  0		    51m
openshift-storage           topolvm-node-rht2m                                       3/3     Running  0		    50m
Note

This example output shows a basic MicroShift installation. If you installed optional RPMs, the status of pods running those services is displayed in the output.

Secure and control traffic

Control network traffic to your MicroShift node by using firewall rules and network policies so that only authorized services can communicate and your environment meets security and compliance requirements.

About network traffic through the firewall

Firewalld is a networking service that runs in the background and responds to connection requests, creating a dynamic customizable host-based firewall. If you are using Red Hat Enterprise Linux for Edge (RHEL for Edge) with MicroShift, firewalld should be installed and you only need to configure it.

Details are provided in procedures that follow. Overall, you must explicitly allow the following OVN-Kubernetes traffic when the firewalld service is running.

CNI pod to CNI pod

CNI pod to Host-Network pod Host-Network pod to Host-Network pod

CNI pod

The Kubernetes pod that uses the CNI network

Host-Network pod

The Kubernetes pod that uses host network You can configure the firewalld service by using the following procedures. In most cases, firewalld is part of RHEL for Edge installations. If you do not have firewalld, you can install it with the simple procedure in this section.

Important

MicroShift pods must have access to the internal CoreDNS component and API servers.

Install the firewalld service

To install and enable firewalld on your RHEL for Edge host when the package is missing, you can use dnf to install the package and systemctl to enable and start the service. Optionally check for the package with rpm -q firewalld before you install.

Procedure
  1. Optional: Check for firewalld on your system by running the following command:

    $ rpm -q firewalld
  2. If the firewalld service is not installed, run the following command:

    $ sudo dnf install -y firewalld
  3. To start the firewall, run the following command:

    $ sudo systemctl enable firewalld --now

Required firewall settings

An IP address range for the node network must be enabled during firewall configuration. You can use the default values or customize the IP address range. If you choose to customize the node network IP address range from the default 10.42.0.0/16 setting, you must also use the same custom range in the firewall configuration.

Table 10. Firewall IP address settings
IP Range Firewall rule required Description

10.42.0.0/16

No

Host network pod access to other pods

169.254.169.1

Yes

Host network pod access to {product-title} API server

Example commands

The following are examples of commands for settings that are mandatory for firewall configuration:

  • Configure host network pod access to other pods:

    $ sudo firewall-cmd --permanent --zone=trusted --add-source=10.42.0.0/16
  • Configure host network pod access to services backed by Host endpoints, such as the {product-title} API:

    $ sudo firewall-cmd --permanent --zone=trusted --add-source=169.254.169.1

Use optional port settings

To allow external access to services and APIs in MicroShift, you can add custom ports to your firewall configuration. Use the listed ports and protocols as a guide for HTTP, HTTPS, NodePort, mDNS, and API access.

For a complete list of ports and protocols, see "Optional ports".

The following examples show commands to open firewall access for services running on MicroShift.

Procedure
  • To add customized ports to your firewall configuration, use the following command syntax:

    $ sudo firewall-cmd --permanent --zone=public --add-port=<port number>/<port protocol>

    For example, to configure a port for the MicroShift API server, enter the following command:

    $ sudo firewall-cmd --permanent --zone=public --add-port=6443/tcp

    To close unnecessary ports in your MicroShift instance, follow the procedure in "Closing unused or unnecessary ports to enhance network security".

Optional ports

The following table lists the optional ports that are available for use with the MicroShift firewall service.

Table 11. Optional ports
Port(s) Protocol(s) Description

80

TCP

HTTP port used to serve applications through the OpenShift Container Platform router.

443

TCP

HTTPS port used to serve applications through the OpenShift Container Platform router.

5353

UDP

mDNS service to respond for OpenShift Container Platform route mDNS hosts.

30000-32767

TCP

Port range reserved for NodePort services; can be used to expose applications on the LAN.

30000-32767

UDP

Port range reserved for NodePort services; can be used to expose applications on the LAN.

6443

TCP

HTTPS API port for the {product-title} API.

Add services to open ports

To open default ports for predefined services through firewalld on your MicroShift instance, you can use the firewall-cmd command. Add each service with the --add-service option.

Procedure
  1. Optional: You can view all predefined services in firewalld by running the following command

    $ sudo firewall-cmd --get-services
  2. To open a service that you want on a default port, run the following example command:

    $ sudo firewall-cmd --add-service=mdns

Allowing network traffic through the firewall

You can allow network traffic through the firewall by configuring the IP address range and inserting the DNS server to allow internal traffic from pods through the network gateway.

Procedure
  1. Use one of the following commands to set the IP address range:

    1. Configure the IP address range with default values by running the following command:

      $ sudo firewall-offline-cmd --permanent --zone=trusted --add-source=10.42.0.0/16
    2. Configure the IP address range with custom values by running the following command:

      $ sudo firewall-offline-cmd --permanent --zone=trusted --add-source=<custom IP range>
  2. To allow internal traffic from pods through the network gateway, run the following command:

    $ sudo firewall-offline-cmd --permanent --zone=trusted --add-source=169.254.169.1
  3. If you are using a load balancer, allow the IPv6 traffic through the firewall by running the following command:

    $ sudo firewall-cmd --permanent --zone=trusted --add-source=fd01::/48

Applying firewall settings

To apply firewall settings after you have finished configuring network access through the firewall, you can reload the firewall service.

Procedure
  • Restart the firewall and apply the settings by running the following command:

    $ sudo firewall-cmd --reload

Verify firewall settings

After you have restarted the firewall, you can verify your settings by listing them with the firewall-cmd command.

Procedure
  • To verify rules added in the default public zone, such as ports-related rules, run the following command:

    $ sudo firewall-cmd --list-all
  • To verify rules added in the trusted zone, such as IP-range related rules, run the following command:

    $ sudo firewall-cmd --zone=trusted --list-all

Overview of firewall ports when a service is exposed

Firewalld is often active when you run services on MicroShift. This can disrupt certain services on MicroShift because traffic to the ports might be blocked by the firewall. You must ensure that the necessary firewall ports are open if you want certain services to be accessible from outside the host.

There are several options for opening your ports:

  • Services of the NodePort and LoadBalancer type are automatically available with OVN-Kubernetes.

    In these cases, OVN-Kubernetes adds iptables rules so the traffic to the node IP address is delivered to the relevant ports. This is done using the PREROUTING rule chain and is then forwarded to the OVN-K to bypass the firewalld rules for local host ports and services. Iptables and firewalld are backed by nftables in Red Hat Enterprise Linux (RHEL) 9. The nftables rules, which the iptables generates, always have priority over the rules that the firewalld generates.

  • Pods with the HostPort parameter settings are automatically available. This also includes the router-default pod, which uses ports 80 and 443.

    For HostPort pods, the CRI-O config sets up iptables DNAT (Destination Network Address Translation) to the pod’s IP address and port.

These methods function for clients whether they are on the same host or on a remote host. The iptables rules, which are added by OVN-Kubernetes and CRI-O, attach to the PREROUTING and OUTPUT chains. The local traffic goes through the OUTPUT chain with the interface set to the lo type. The DNAT runs before it hits filler rules in the INPUT chain.

Because the MicroShift API server does not run in CRI-O, it is subject to the firewall configurations. You can open port 6443 in the firewall to access the API server in your MicroShift node.

Known firewall issue

To avoid traffic failures after a firewalld reload or restart on MicroShift, run firewall commands before you start Red Hat Enterprise Linux (RHEL). If you must run firewall commands later, restart the ovnkube-master pod in openshift-ovn-kubernetes to restore iptable rules that OVN-Kubernetes manages.

The CNI driver in MicroShift makes use of iptable rules for some traffic flows, such as those using the NodePort service. The iptable rules are generated and inserted by the CNI driver, but are deleted when the firewall reloads or restarts. The absence of the iptable rules breaks traffic flows.

How network policy works in MicroShift

In a node that is using the default OVN-Kubernetes Container Network Interface (CNI) plugin for MicroShift, network isolation is controlled by both firewalld, which is configured on the host, and by NetworkPolicy objects created within MicroShift. Simultaneous use of firewalld and NetworkPolicy is supported.

  • Network policies work only within boundaries of OVN-Kubernetes-controlled traffic, so they can apply to every situation except for hostPort/hostNetwork enabled pods.

  • Firewalld settings also do not apply to hostPort/hostNetwork enabled pods.

  • Firewalld rules run before any NetworkPolicy is enforced.

Warning

Network policy does not apply to the host network namespace. Pods with host networking enabled are unaffected by network policy rules. However, pods connecting to the host-networked pods might be affected by the network policy rules.

Network policies cannot block traffic from localhost.

By default, all pods in a MicroShift node are accessible from other pods and network endpoints. To isolate one or more pods in a node, you can create NetworkPolicy objects to indicate allowed incoming connections. You can create and delete NetworkPolicy objects.

If a pod is matched by selectors in one or more NetworkPolicy objects, then the pod accepts only connections that are allowed by at least one of those NetworkPolicy objects. A pod that is not selected by any NetworkPolicy objects is fully accessible.

A network policy applies to only the TCP, UDP, ICMP, and SCTP protocols. Other protocols are not affected.

The following example NetworkPolicy objects demonstrate supporting different scenarios:

  • Deny all traffic:

    To make a project deny by default, add a NetworkPolicy object that matches all pods but accepts no traffic:

    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata:
      name: deny-by-default
    spec:
      podSelector: {}
      ingress: []
  • Allow connections from the default router, which is the ingress in MicroShift:

    To allow connections from the MicroShift default router, add the following NetworkPolicy object:

    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: allow-from-openshift-ingress
    spec:
      ingress:
      - from:
        - namespaceSelector:
            matchLabels:
              ingresscontroller.operator.openshift.io/deployment-ingresscontroller: default
      podSelector: {}
      policyTypes:
      - Ingress
  • Only accept connections from pods within the same namespace:

    To make pods accept connections from other pods in the same namespace, but reject all other connections from pods in other namespaces, add the following NetworkPolicy object:

    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata:
      name: allow-same-namespace
    spec:
      podSelector: {}
      ingress:
      - from:
        - podSelector: {}
  • Only allow HTTP and HTTPS traffic based on pod labels:

    To enable only HTTP and HTTPS access to the pods with a specific label (role=frontend in following example), add a NetworkPolicy object similar to the following:

    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata:
      name: allow-http-and-https
    spec:
      podSelector:
        matchLabels:
          role: frontend
      ingress:
      - ports:
        - protocol: TCP
          port: 80
        - protocol: TCP
          port: 443
  • Accept connections by using both namespace and pod selectors:

    To match network traffic by combining namespace and pod selectors, you can use a NetworkPolicy object similar to the following:

    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata:
      name: allow-pod-and-namespace-both
    spec:
      podSelector:
        matchLabels:
          name: test-pods
      ingress:
        - from:
          - namespaceSelector:
              matchLabels:
                project: project_name
            podSelector:
              matchLabels:
                name: test-pods

NetworkPolicy objects are additive, which means you can combine multiple NetworkPolicy objects together to satisfy complex network requirements.

For example, for the NetworkPolicy objects defined in previous examples, you can define both allow-same-namespace and allow-http-and-https policies. That configuration allows the pods with the label role=frontend to accept any connection allowed by each policy. That is, connections on any port from pods in the same namespace, and connections on ports 80 and 443 from pods in any namespace.

Example NetworkPolicy object

Reference the example NetworkPolicy object to understand how to configure this object.

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: allow-27107
spec:
  podSelector:
    matchLabels:
      app: mongodb
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: app
    ports:
    - protocol: TCP
      port: 27017

where:

name

The name of the NetworkPolicy object.

spec.podSelector

A selector that describes the pods to which the policy applies. The policy object can only select pods in the project that defines the NetworkPolicy object.

ingress.from.podSelector

A selector that matches the pods from which the policy object allows ingress traffic. The selector matches pods in the same namespace as the NetworkPolicy.

ingress.ports

A list of one or more destination ports on which to accept traffic.

Create a network policy using the CLI

To define granular rules describing ingress or egress network traffic allowed for namespaces in your cluster, you can create a network policy.

Note

If you log in with a user with the cluster-admin role, then you can create a network policy in any namespace in the cluster.

Prerequisites
  • Your cluster uses a network plugin that supports NetworkPolicy objects, such as the OVN-Kubernetes network plugin, with mode: NetworkPolicy set.

  • You installed the OpenShift CLI (oc).

  • You logged in to the cluster with a user with admin privileges.

  • You are working in the namespace that the network policy applies to.

Procedure
  1. Create a policy rule.

    1. Create a <policy_name>.yaml file:

      $ touch <policy_name>.yaml

      where:

      <policy_name>

      Specifies the network policy file name.

    2. Define a network policy in the created file. The following example denies ingress traffic from all pods in all namespaces. This is a fundamental policy, blocking all cross-pod networking other than cross-pod traffic allowed by the configuration of other Network Policies.

      kind: NetworkPolicy
      apiVersion: networking.k8s.io/v1
      spec:
        podSelector: {}
        policyTypes:
        - Ingress
        ingress: []

      The following example configuration allows ingress traffic from all pods in the same namespace:

      kind: NetworkPolicy
      apiVersion: networking.k8s.io/v1
      metadata:
        name: allow-same-namespace
      spec:
        podSelector:
        ingress:
        - from:
          - podSelector: {}
      # ...

      The following example allows ingress traffic to one pod from a particular namespace. This policy allows traffic to pods that have the pod-a label from pods running in namespace-y.

      kind: NetworkPolicy
      apiVersion: networking.k8s.io/v1
      metadata:
        name: allow-traffic-pod
      spec:
        podSelector:
         matchLabels:
            pod: pod-a
        policyTypes:
        - Ingress
        ingress:
        - from:
          - namespaceSelector:
              matchLabels:
                 kubernetes.io/metadata.name: namespace-y
      # ...

      The following example configuration restricts traffic to a service. This policy when applied ensures every pod with both labels app=bookstore and role=api can only be accessed by pods with label app=bookstore. In this example the application could be a REST API server, marked with labels app=bookstore and role=api.

      This example configuration addresses the following use cases:

      • Restricting the traffic to a service to only the other microservices that need to use it.

      • Restricting the connections to a database to only permit the application using it.

        kind: NetworkPolicy
        apiVersion: networking.k8s.io/v1
        metadata:
          name: api-allow
        spec:
          podSelector:
            matchLabels:
              app: bookstore
              role: api
          ingress:
          - from:
              - podSelector:
                  matchLabels:
                    app: bookstore
        # ...
  2. To create the network policy object, enter the following command. Successful output lists the name of the policy object and the created status.

    $ oc apply -f <policy_name>.yaml -n <namespace>

    where:

    <policy_name>

    Specifies the network policy file name.

    <namespace>

    Optional parameter. If you defined the object in a different namespace than the current namespace, the parameter specifices the namespace.

    Successful output lists the name of the policy object and the created status.

    Note

    If you log in to the web console with cluster-admin privileges, you have a choice of creating a network policy in any namespace in the cluster directly in YAML or from a form in the web console.

Create a default deny all network policy

The default deny all network policy blocks all cross-pod networking other than network traffic allowed by the configuration of other deployed network policies and traffic between host-networked pods.

The steps in the procedure enforces a strong deny policy by applying a deny-by-default policy in the my-project namespace.

Warning

Without configuring a NetworkPolicy custom resource (CR) that allows traffic communication, the following policy might cause communication problems across your cluster.

Prerequisites
  • Your cluster uses a network plugin that supports NetworkPolicy objects, such as the OVN-Kubernetes network plugin, with mode: NetworkPolicy set.

  • You installed the OpenShift CLI (oc).

  • You logged in to the cluster with a user with admin privileges.

  • You are working in the namespace that the network policy applies to.

Procedure
  1. Create the following YAML that defines a deny-by-default policy to deny ingress from all pods in all namespaces. Save the YAML in the deny-by-default.yaml file:

    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata:
      name: deny-by-default
      namespace: my-project
    spec:
      podSelector: {}
      ingress: []

    where:

    namespace

    Specifies the namespace in which to deploy the policy. For example, the my-project namespace.

    podSelector

    If this field is empty, the configuration matches all the pods. Therefore, the policy applies to all pods in the my-project namespace.

    ingress

    Where [] indicates that no ingress rules are specified. This causes incoming traffic to be dropped to all pods.

  2. Apply the policy by entering the following command. Successful output lists the name of the policy object and the created status.

    $ oc apply -f deny-by-default.yaml

Create a network policy to allow traffic from external clients

With the deny-by-default policy in place you can proceed to configure a policy that allows traffic from external clients to a pod with the label app=web.

Note

If you log in with a user with the cluster-admin role, then you can create a network policy in any namespace in the cluster.

Follow this procedure to configure a policy that allows external service from the public Internet directly or by using a Load Balancer to access the pod. Traffic is only allowed to a pod with the label app=web.

Prerequisites
  • Your cluster uses a network plugin that supports NetworkPolicy objects, such as the OVN-Kubernetes network plugin, with mode: NetworkPolicy set.

  • You installed the OpenShift CLI (oc).

  • You logged in to the cluster with a user with admin privileges.

  • You are working in the namespace that the network policy applies to.

Procedure
  1. Create a policy that allows traffic from the public Internet directly or by using a load balancer to access the pod. Save the YAML in the web-allow-external.yaml file:

    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    spec:
      policyTypes:
      - Ingress
      podSelector:
        matchLabels:
          app: web
      ingress:
        - {}
  2. Apply the policy by entering the following command. Successful output lists the name of the policy object and the created status.

    $ oc apply -f web-allow-external.yaml

    This policy allows traffic from all resources, including external traffic as illustrated in the following diagram:

    Allow traffic from external clients

Create a network policy allowing traffic to an application from all namespaces

You can configure a policy that allows traffic from all pods in all namespaces to a particular application.

Note

If you log in with a user with the cluster-admin role, then you can create a network policy in any namespace in the cluster.

Prerequisites
  • Your cluster uses a network plugin that supports NetworkPolicy objects, such as the OVN-Kubernetes network plugin, with mode: NetworkPolicy set.

  • You installed the OpenShift CLI (oc).

  • You logged in to the cluster with a user with admin privileges.

  • You are working in the namespace that the network policy applies to.

Procedure
  1. Create a policy that allows traffic from all pods in all namespaces to a particular application. Save the YAML in the web-allow-all-namespaces.yaml file:

    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: web-allow-all-namespaces
      namespace: default
    spec:
      podSelector:
        matchLabels:
          app: web
      policyTypes:
      - Ingress
      ingress:
      - from:
        - namespaceSelector: {}

    where:

    app

    Applies the policy only to app:web pods in default namespace.

    namespaceSelector

    Selects all pods in all namespaces.

    Note

    By default, if you do not specify a namespaceSelector parameter in the policy object, no namespaces get selected. This means the policy allows traffic only from the namespace where the network policy deployes.

  2. Apply the policy by entering the following command. Successful output lists the name of the policy object and the created status.

    $ oc apply -f web-allow-all-namespaces.yaml
Verification
  1. Start a web service in the default namespace by entering the following command:

    $ oc run web --namespace=default --image=nginx --labels="app=web" --expose --port=80
  2. Run the following command to deploy an alpine image in the secondary namespace and to start a shell:

    $ oc run test-$RANDOM --namespace=secondary --rm -i -t --image=alpine -- sh
  3. Run the following command in the shell and observe that the service allows the request:

    # wget -qO- --timeout=2 http://web.default
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    <style>
    html { color-scheme: light dark; }
    body { width: 35em; margin: 0 auto;
    font-family: Tahoma, Verdana, Arial, sans-serif; }
    </style>
    </head>
    <body>
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>
    
    <p>For online documentation and support please refer to
    <a href="http://nginx.org/">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="http://nginx.com/">nginx.com</a>.</p>
    
    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>

Create a network policy allowing traffic to an application from a namespace

You can configure a policy that allows traffic to a pod with the label app=web from a particular namespace.

This configuration is useful in the following use cases:

  • Restrict traffic to a production database only to namespaces that have production workloads deployed.

  • Enable monitoring tools deployed to a particular namespace to scrape metrics from the current namespace.

Note

If you log in with a user with the cluster-admin role, then you can create a network policy in any namespace in the cluster.

Prerequisites
  • Your cluster uses a network plugin that supports NetworkPolicy objects, such as the OVN-Kubernetes network plugin, with mode: NetworkPolicy set.

  • You installed the OpenShift CLI (oc).

  • You logged in to the cluster with a user with admin privileges.

  • You are working in the namespace that the network policy applies to.

Warning

Do not apply the network.openshift.io/policy-group: ingress label to custom namespace or projects. This label is Operator-managed and reserved for {product-title} networking functions. It should not be altered on system-created namespaces.

Using this label can result in intermittent network connectivity drops, unintended application of system NetworkPolicies resource, or configuration drift as the operator attempts to reconcile the state. For custom traffic grouping, always use unique, user-defined labels as shown in the following procedure.

Procedure
  1. Create a policy that allows traffic from all pods in a particular namespaces with a label purpose=production. Save the YAML in the web-allow-prod.yaml file:

    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata:
      name: web-allow-prod
      namespace: default
    spec:
      podSelector:
        matchLabels:
          app: web
      policyTypes:
      - Ingress
      ingress:
      - from:
        - namespaceSelector:
            matchLabels:
              purpose: production

    where:

    app

    Applies the policy only to app:web pods in the default namespace.

    purpose

    Restricts traffic to only pods in namespaces that have the label purpose=production.

  2. Apply the policy by entering the following command. Successful output lists the name of the policy object and the created status.

    $ oc apply -f web-allow-prod.yaml
Verification
  1. Start a web service in the default namespace by entering the following command:

    $ oc run web --namespace=default --image=nginx --labels="app=web" --expose --port=80
  2. Run the following command to create the prod namespace:

    $ oc create namespace prod
  3. Run the following command to label the prod namespace:

    $ oc label namespace/prod purpose=production
  4. Run the following command to create the dev namespace:

    $ oc create namespace dev
  5. Run the following command to label the dev namespace:

    $ oc label namespace/dev purpose=testing
  6. Run the following command to deploy an alpine image in the dev namespace and to start a shell:

    $ oc run test-$RANDOM --namespace=dev --rm -i -t --image=alpine -- sh
  7. Run the following command in the shell and observe the reason for the blocked request. For example, expected output states wget: download timed out.

    # wget -qO- --timeout=2 http://web.default
  8. Run the following command to deploy an alpine image in the prod namespace and start a shell:

    $ oc run test-$RANDOM --namespace=prod --rm -i -t --image=alpine -- sh
  9. Run the following command in the shell and observe that the request is allowed:

    # wget -qO- --timeout=2 http://web.default
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    <style>
    html { color-scheme: light dark; }
    body { width: 35em; margin: 0 auto;
    font-family: Tahoma, Verdana, Arial, sans-serif; }
    </style>
    </head>
    <body>
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>
    
    <p>For online documentation and support please refer to
    <a href="http://nginx.org/">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="http://nginx.com/">nginx.com</a>.</p>
    
    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>

Edit a network policy

To modify existing policy configurations, you can edit a network policy in a namespace. Edit policies by modifying the policy file and applying it with oc apply, or by using the oc edit command directly.

Note

If you log in with cluster-admin privileges, you can edit network policies in any namespace in the cluster.

Note

If you log in with cluster-admin privileges, you can edit network policies in any namespace in the cluster. In the web console, you can edit policies directly in YAML or by using the Actions menu.

Prerequisites
  • Your cluster uses a network plugin that supports NetworkPolicy objects, such as the OVN-Kubernetes network plugin, with mode: NetworkPolicy set.

  • You installed the OpenShift CLI (oc).

  • You are logged in to the cluster with a user with admin privileges.

  • You are working in the namespace where the network policy exists.

Procedure
  1. Optional: To list the network policy objects in a namespace, enter the following command:

    $ oc get network policy -n <namespace>

    where:

    <namespace>

    Optional: Specifies the namespace if the object is defined in a different namespace than the current namespace.

  2. Edit the network policy object.

    1. If you saved the network policy definition in a file, edit the file and make any necessary changes, and then enter the following command.

      $ oc apply -n <namespace> -f <policy_file>.yaml

      where:

      <namespace>

      Optional: Specifies the namespace if the object is defined in a different namespace than the current namespace.

      <policy_file>

      Specifies the name of the file containing the network policy.

    2. If you need to update the network policy object directly, enter the following command:

      $ oc edit network policy <policy_name> -n <namespace>

      where:

      <policy_name>

      Specifies the name of the network policy.

      <namespace>

      Optional: Specifies the namespace if the object is defined in a different namespace than the current namespace.

  3. Confirm that the network policy object is updated.

    $ oc describe networkpolicy <policy_name> -n <namespace>

    where:

    <policy_name>

    Specifies the name of the network policy.

    <namespace>

    Optional: Specifies the namespace if the object is defined in a different namespace than the current namespace.

Delete a network policy using the CLI

You can delete a network policy in a namespace.

Note

If you log in with cluster-admin privileges, you can delete network policies in any namespace in the cluster.

Note

If you log in with cluster-admin privileges, you can delete network policies in any namespace in the cluster. In the web console, you can delete policies directly in YAML or by using the Actions menu.

Prerequisites
  • Your cluster uses a network plugin that supports NetworkPolicy objects, such as the OVN-Kubernetes network plugin, with mode: NetworkPolicy set.

  • You installed the OpenShift CLI (oc).

  • You logged in to the cluster with a user with admin privileges.

  • You are working in the namespace where the network policy exists.

Procedure
  • To delete a network policy object, enter the following command. Successful output lists the name of the policy object and the deleted status.

    $ oc delete networkpolicy <policy_name> -n <namespace>

    where:

    <policy_name>

    Specifies the name of the network policy.

    <namespace>

    Optional parameter. If you defined the object in a different namespace than the current namespace, the parameter specifices the namespace.

View network policies using the CLI

You can examine the network policies in a namespace.

Note

If you log in with cluster-admin privileges, you can edit network policies in any namespace in the cluster.

Note

If you log in with cluster-admin privileges, you can edit network policies in any namespace in the cluster. In the web console, you can edit policies directly in YAML or by using the Actions menu.

Prerequisites
  • You installed the OpenShift CLI (oc).

  • You are logged in to the cluster with a user with admin privileges.

  • You are working in the namespace where the network policy exists.

Procedure
  1. List network policies in a namespace.

    1. To view network policy objects defined in a namespace enter the following command:

      $ oc get networkpolicy
    2. Optional: To examine a specific network policy enter the following command:

      $ oc describe networkpolicy <policy_name> -n <namespace>

      where:

      <policy_name>

      Specifies the name of the network policy to inspect.

      <namespace>

      Optional: Specifies the namespace if the object is defined in a different namespace than the current namespace.

      $ oc describe networkpolicy allow-same-namespace
      Name:         allow-same-namespace
      Namespace:    ns1
      Created on:   2021-05-24 22:28:56 -0400 EDT
      Labels:       <none>
      Annotations:  <none>
      Spec:
        PodSelector:     <none> (Allowing the specific traffic to all pods in this namespace)
        Allowing ingress traffic:
          To Port: <any> (traffic allowed to all ports)
          From:
            PodSelector: <none>
        Not affecting egress traffic
        Policy Types: Ingress

Optimizations for network policy with OVN-Kubernetes network plugin

Learn how to optimize OVN-Kubernetes network policies to reduce flow count and ensure external IP traffic is allowed when needed.

When designing your network policy, refer to the following guidelines:

  • For network policies with the same spec.podSelector spec, it is more efficient to use one network policy with multiple ingress or egress rules, than multiple network policies with subsets of ingress or egress rules.

  • Every ingress or egress rule based on the podSelector or namespaceSelector spec generates the number of OVS flows proportional to number of pods selected by network policy + number of pods selected by ingress or egress rule. Therefore, it is preferable to use the podSelector or namespaceSelector spec that can select as many pods as you need in one rule, instead of creating individual rules for every pod.

    For example, the following policy contains two rules:

    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: test-network-policy
    spec:
      podSelector: {}
      ingress:
      - from:
        - podSelector:
            matchLabels:
              role: frontend
      - from:
        - podSelector:
            matchLabels:
              role: backend

    The following policy expresses those same two rules as one:

    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: test-network-policy
    spec:
      podSelector: {}
      ingress:
      - from:
        - podSelector:
            matchExpressions:
            - {key: role, operator: In, values: [frontend, backend]}

    The same guideline applies to the spec.podSelector spec. If you have the same ingress or egress rules for different network policies, it might be more efficient to create one network policy with a common spec.podSelector spec. For example, the following two policies have different rules:

    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: policy1
    spec:
      podSelector:
        matchLabels:
          role: db
      ingress:
      - from:
        - podSelector:
            matchLabels:
              role: frontend
    ---
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: policy2
    spec:
      podSelector:
        matchLabels:
          role: client
      ingress:
      - from:
        - podSelector:
            matchLabels:
              role: frontend

    The following network policy expresses those same two rules as one:

    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: policy3
    spec:
      podSelector:
        matchExpressions:
        - {key: role, operator: In, values: [db, client]}
      ingress:
      - from:
        - podSelector:
            matchLabels:
              role: frontend

    You can apply this optimization when only multiple selectors are expressed as one. In cases where selectors are based on different labels, it may not be possible to apply this optimization. In those cases, consider applying some new labels for network policy optimization specifically.

NetworkPolicy CR and external IPs in OVN-Kubernetes

In OVN-Kubernetes, the NetworkPolicy custom resource (CR) enforces strict isolation rules. If a service is exposed using an external IP, a network policy can block access from other namespaces unless explicitly configured to allow traffic.

To allow access to external IPs across namespaces, create a NetworkPolicy CR that explicitly permits ingress from the required namespaces and ensures traffic is allowed to the designated service ports. Without allowing traffic to the required ports, access might still be restricted.

Example output
  apiVersion: networking.k8s.io/v1
  kind: NetworkPolicy
  metadata:
    annotations:
    name: <policy_name>
    namespace: openshift-ingress
  spec:
    ingress:
    - ports:
      - port: 80
        protocol: TCP
    - ports:
      - port: 443
        protocol: TCP
    - from:
      - namespaceSelector:
          matchLabels:
          kubernetes.io/metadata.name: <my_namespace>
    podSelector: {}
    policyTypes:
    - Ingress

where:

<policy_name>

Specifies your name for the policy.

<my_namespace>

Specifies the name of the namespace where the policy is deployed.

For more details, see "About network policy".

Understand the Generic Device Plugin

The Generic Device Plugin in {product-title} is a Kubernetes device plugin that enables pods to access host devices such as serial ports, cameras, and sound cards securely. You can use it for edge and IoT workloads that require direct hardware access without elevated container privileges.

The GDP integrates with the kubelet to advertise available devices to the node and facilitate their allocation to pods without requiring elevated privileges within the container itself. It is designed to handle devices that are initialized and managed by the operating system and do not require any special initialization procedures or drivers for a pod to use them.

Here are examples of generic devices that are suitable for the GDP:

  • Serial ports, for example, /dev/ttyUSB*, /dev/ttyACM*.

  • Video cameras, for example, /dev/video0.

  • Sound devices, for example, /dev/snd, /dev/snd/controlC0.

  • USB devices specified by Vendor ID and Product ID, or, optionally, by the device serial number.

The following specialized devices are not suitable for the GDP:

  • Devices that require specific initialization procedures beyond standard operating system management.

  • Specialized hardware that needs additional drivers or kernel modules. Examples of this specialized hardware include GPUs and FPGAs. These types of devices typically require their own specialized device plugins.

Limitations and considerations for the Generic Device Plugin

The Generic Device Plugin in {product-title} has limitations and considerations for exposing host devices. You can use this information to choose suitable devices, configure stable identifiers, and plan for performance.

Devices not suited for the Generic Device Plugin

The GDP is designed for devices that are managed directly by the operating system and do not require special setup procedures. Devices that are not well-suited for the Generic Device Plugin include:

  • Complex hardware requiring specialized drivers such as GPUs (graphics processing units) or FPGAs (field-programmable gate arrays). These types of hardware typically require dedicated device plugins that can perform unique initialization procedures, memory management, or queue resets before a pod can use them.

  • Devices with specific vendor-supplied software stacks. Devices that require a complex software stack or proprietary APIs beyond direct file system access might require a specialized plugin.

Device identification and logging

When you use glob paths, for example, /dev/ttyUSB*, to expose multiple similar devices, the GDP allocates devices based on availability. However, if your application needs to connect to an exactly specified physical device, for example, serial device 3 out of 10, using broad glob paths might be insufficient. In such cases, configure individual device entries in the config.yaml file using more stable and unique identifiers such as:

  • Specific device paths, for example, /dev/video0.

  • Symbolic links provided by the operating system, for example, /dev/serial/by-id/ or /dev/serial/by-path/.

  • USB vendor ID, product ID, and serial number combinations for precise USB device targeting.

Performance considerations

The count parameter in the config.yaml file enables a device group to be scheduled multiple times concurrently. While there are no explicit limits set within the GDP for the count (for example, 1000 for /dev/fuse), the actual performance depends on the host system’s capabilities and the nature of the device itself. Running a very high number of concurrent processes that access the same device might affect performance.

Configure the Generic Device Plugin

The Generic Device Plugin (GDP) is disabled by default in MicroShift. To expose host devices such as serial ports and cameras to pods in {product-title}, you can enable the Generic Device Plugin and define devices in the config.yaml file or create a configuration snippet file such as /etc/microshift/config.d/10-gdp.yaml.

Prerequisites
  • You installed MicroShift.

  • You created a custom config.yaml file in the /etc/microshift directory.

  • You installed the OpenShift CLI (oc).

  • You have sudo privileges on the MicroShift host.

  • You have identified the specific host devices that you want to expose to your MicroShift node. For example, /dev/video0, /dev/ttyUSB*, or USB Vendor/Product IDs.

Procedure
  1. From your CLI using sudo privileges, open /etc/microshift/config.yaml in a text editor.

  2. Locate the genericDevicePlugin section. If it is not present, add it.

  3. Set the status parameter to Enabled and define the devices that should be exposed. Each device definition needs a name and one or more groups. Each group can specify devices using paths, for file-based devices, including glob patterns, or usbs, for USB devices using Vendor/Product IDs. You cannot mix paths and usbs within the same device group.

    GDP fields with default values
    apiServer:
    # ...
    genericDevicePlugin:
      devices:
      - groups:
        - paths:
          - path: /dev/ttyUSB*
          - path: /dev/ttyACM*
        name: serial
      - groups:
        - paths:
          - path: /dev/fuse
        name: fuse
      - groups:
        - usbs:
          - product: "0x7523"
            serial: ""
            vendor: "0x1a86"
        name: converter
      domain: device.microshift.io
      status: Enabled

    where:

    /dev/ttyUSB*

    Specifies the file path for all the USB serial devices that are matched by this glob.

    /dev/ttyACM*

    Specifies the file path for all the ACM serial devices that are matched by this glob.

    /dev/fuse

    Specifies the file path for a fuse device.

    fuse

    Specifies the name of the device.

    0x7523

    Specifies the Product ID for a CH340 serial converter.

    0x1a86

    Specifies the Vendor ID for a CH340 serial converter.

    device.microshift.io

    Specifies the default domain for the GDP.

    Important
    • The output of the microshift show-config parameter might include pre-configured default paths for serial devices even if you have not explicitly configured them in config.yaml. These paths represent the default discovery settings if the Generic Device Plugin is enabled without specific user configuration.

    • For consistency and precise device targeting, especially when dealing with multiple similar devices, consider using stable device paths like /dev/serial/by-id/ or specific USB Vendor, Product, or Serial IDs instead of broad glob patterns like /dev/ttyUSB*.

    • The count parameter in a device group allows a single device, or a set of devices matched by a glob, to be allocated multiple times concurrently to different pods. If omitted, count defaults to 1.

  4. Save the config.yaml file.

  5. Restart the MicroShift service to apply the changes:

    $ sudo systemctl restart microshift

    Allow some time for MicroShift to restart and for the GDP to register its devices with the Kubelet.

Verification
  • You can check the available devices in your node by running the following command:

    $ oc describe node <microshift_node_name> | grep "device.microshift.io"
  • Depending on your configuration, expect output that indicates that the devices are now discoverable and schedulable within your MicroShift node.

    Example output
    Capacity:
     cpu:                                2
     device.microshift.io/audio:         0
     device.microshift.io/capture:       0
     device.microshift.io/custom-device: 1
     device.microshift.io/dummy-video:   0
     device.microshift.io/fuse:          0
     device.microshift.io/serial:        5
     device.microshift.io/video:         0
    Allocatable:
     cpu:                                2
     device.microshift.io/audio:         0
     device.microshift.io/capture:       0
     device.microshift.io/custom-device: 1
     device.microshift.io/dummy-video:   0
     device.microshift.io/fuse:          0
     device.microshift.io/serial:        5
     device.microshift.io/video:         0
    Allocated resources:
     (Total limits may be over 100 percent, i.e., overcommitted.)
     Resource                           Requests     Limits
     --------                           --------     ------
     cpu                                450m (22%)   500m (25%)
     memory                             1550Mi (42%) 500Mi (13%)
     ephemeral-storage                  0 (0%)       0 (0%)
     hugepages-1Gi                      0 (0%)       0 (0%)
     hugepages-2Mi                      0 (0%)       0 (0%)
     device.microshift.io/audio         0            0
     device.microshift.io/capture       0            0
     device.microshift.io/custom-device 1            1
     device.microshift.io/dummy-video   1            1
     device.microshift.io/fuse          0            0
     device.microshift.io/serial        0            0
     device.microshift.io/video         0            0

Deploy applications that use generic devices

After the Generic Device Plugin (GDP) is configured and enabled in MicroShift, you can deploy Kubernetes workloads, such as pods, deployments, or StatefulSets, that request access to the host devices that you have exposed. Devices are made available inside the container without requiring the pod to run with elevated privileges.

Prerequisites
  • You installed MicroShift.

  • You enabled and configured GDP.

  • You installed OpenShift CLI (oc).

Procedure
  1. Define the device request in your Pod specification:

    apiVersion: v1
    kind: Pod
    metadata:
      name: device-app
    spec:
      containers:
      - name: container
        image: <your_application_image>
        command: ["/path/to/your/app"]
        args: ["--device_path=/dev/video0"]
        resources:
          limits:
            device.microshift.io/video: 1
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: ["ALL"]
          runAsNonRoot: true
          seccompProfile:
            type: "RuntimeDefault"

    where:

    spec.containers.image

    Specifies the container image.

    spec.containers.command

    Specifies the command for your application.

    spec.containers.args

    Specifies the arguments for your application. For example, how your application might use the device.

    spec.containers.resources.limits

    Specifies the resource limit for the device. The resource name must follow the pattern device.microshift.io/<device_name>, where <device_name> matches the name that you specified in your configuration file. This example requests one instance of the video device.

    spec.containers.securityContext

    Specifies the privilege escalation. Define and configure with the least privilege value to ensure that the container has only required permissions, such as access to the device file, and to restrict other capabilities for the container.

  2. Deploy the Kubernetes workload by applying the manifest to the MicroShift node by running the following command:

    $ oc apply -f <your_workload_manifest.yaml>

    After the pod is running, the specified host device is available at its original path, or mountPath if specified, inside the container. Your application can then interact with it as if it were a local device.

    For example, if you requested device.microshift.io/serial, which maps to /dev/ttyUSB*, your application might find the device at /dev/ttyUSB0 or a similar path inside the container.

Verification
  • Verify device access by running the following command inside the running pod:

    $ oc exec -it <pod_name> -- ls -l /dev/video0

Generic Device Plugin configuration reference

The Generic Device Plugin configuration reference lists and describes the parameters in the genericDevicePlugin section of the` config.yaml` file in {product-title}. You can use this reference when you enable the GDP and define which host devices to expose.

Table 12. GDP configuration fields definitions table
Parameter Description

genericDevicePlugin

The genericDevicePlugin section of the MicroShift configuration file defines the configurable parameters for the implementation of the MicroShift GenericDevicePlugin API. All of the following parameters in this table are subsections in the genericDevicePlugin section of the MicroShift configuration.

devices

Is a subgroup that lists the device definitions to be exposed by the plugin. Each Device entry contains a 'name' and a list of groups.

devices.groups

Lists device groups. Devices within a group comprise a pool of devices under a common name. When you request a device from that pool, you can receive a device from different defined paths.

devices.groups.count

Specifies how many times this group of devices can be mounted concurrently. If unspecified, Count defaults to 1. Setting a high count, for example, 1000 for /dev/fuse, is possible because are no inherent limits, but performance might be impacted depending on the host’s capabilities and the nature of the device.

devices.groups.paths

Lists the host device file paths. Paths can be glob patterns, for example, /dev/ttyUSB*, in which case each matched device is schedulable Count times. This field is exclusive with usbs; you cannot define both in the same device group.

devices.groups.paths.limit

Specifies up to how many times this device can be used in the group concurrently when other devices in the group yield more matches. For example, if one path in the group matches 5 devices and another matches 1 device but has a limit of 10, then the group provides 5 pairs of devices. When unspecified, the limit defaults to 1.

devices.groups.paths.mountPath

The file path at which the host device should be mounted within the container. When unspecified, mountPath defaults to path.

devices.groups.paths.path

The file path of a device on the host, for example, /dev/video0, /dev/ttyUSB*.

devices.groups.paths.permissions

The file-system permissions given to the mounted device. Applies only to mounts of type Device. Can be one or more of:

* r - allows the container to read from the specified device.

* w - allows the container to write to the specified device.

* m - allows the container to create device files that do not yet exist.

When unspecified, Permissions defaults to mrw.

devices.groups.paths.readOnly

Specifies whether the path should be mounted read-only. The values are true or false. Applies only to mounts of type Mount.

devices.groups.path.type

Describes what type of file-system node this path represents and thus how it should be mounted. The type can be Device or Mount. When unspecified, type defaults to Device.

devices.groups.usbs

Lists the USB specifications that this device group consists of. The vendor and product IDs must always match. The serial ID must match if provided, or skipped if the ID is empty, The usbs field is exclusive with paths.

devices.groups.usbs.product

The USB Product ID of the device to match on, for example, 0x7523.

devices.groups.usbs.serial

The serial number of the device to match on. A USB device must match exactly on all the given attributes to pass.

devices.groups.usbs.vendor

The USB Vendor ID of the device to match on, for example, 0x1a86

devices.name

A unique string representing the kind of device this specification describes, for example, serial, video, or fuse. This name is used in pod resource requests, for example, device.microshift.io/serial.

domain

domain is a subgroup that specifies the domain prefix with which devices are advertised and present in the node. For example, device.microshift.io/serial. The default value is device.microshift.io.

status

status is a subgroup that specifies the default GDP status. Enabled or Disabled are valid values.

Troubleshoot configuration issues

The following entries explain common Generic Device Plugin configuration issues and how to resolve them.

Invalid configuration: failed to parse device

Occurs when you have incorrectly mixed paths and usbs fields within the same groups entry for a device. Each group must exclusively use either paths or usbs to define its devices.

Cannot define both path and usbs at the same time

Occurs when you have incorrectly mixed paths and usbs fields within the same groups entry for a device. Each group must exclusively use either paths or usbs to define its devices.

Ensure host and control plane resilience against application resource exhaustion

Configure strict resource boundaries so that application misbehavior, such as RAM leaks, CPU spikes, or unbounded logs, does not compromise the host operating system or the MicroShift control plane.

Enable workload partitioning

To enable workload partitioning on MicroShift, make the following configuration changes:

  • Update the MicroShift config.yaml file to include the kubelet configuration file.

  • Create the CRI-O systemd and configuration files.

  • Create and update the systemd configuration file for the MicroShift and CRI-O services respectively.

Procedure
  1. Update the MicroShift config.yaml file to include the kubelet configuration file to enable and configure CPU Manager for the workloads:

    • Create the kubelet configuration file in the path /etc/kubernetes/openshift-workload-pinning. The kubelet configuration directs the kubelet to modify the node resources based on the capacity and allocatable CPUs.

      kubelet configuration example
      # ...
      {
        "management": {
          "cpuset": "0,6,7" 1
        }
      }
      # ...
      1 The cpuset applies to a machine with 8 VCPUs (4 cores) and is valid throughout the document.
    • Update the MicroShift config.yaml file in the path /etc/microshift/config.yaml. Embed the kubelet configuration in the MicroShift config.yaml file to enable and configure CPU Manager for the workloads.

      MicroShift config.yaml example
      # ...
      kubelet:
        reservedSystemCPUs: 0,6,7 1
        cpuManagerPolicy: static
        cpuManagerPolicyOptions:
          full-pcpus-only: "true" 2
        cpuManagerReconcilePeriod: 5s
      # ...
      1 Exclusive cpuset for the system daemons and the interrupts/timers.
      2 kubelet configuration sets the CPUManagerPolicyOptions option to full-pcpus-only to ensure allocation of whole cores to the containers workload.
  2. Create the CRI-O systemd and configuration files:

    • Create the CRI-O configuration file in the path /etc/crio/crio.conf.d/20-microshift-workload-partition.conf which overrides the default configuration that already exists in the 11-microshift-ovn.conf file.

      CRI-O configuration example
      # ...
      [crio.runtime]
      infra_ctr_cpuset = "0,6,7"
      
      [crio.runtime.workloads.management]
      activation_annotation = "target.workload.openshift.io/management"
      annotation_prefix = "resources.workload.openshift.io"
      resources = { "cpushares" = 0, "cpuset" = "0,6,7" }
      # ...
    • Create the systemd file for CRI-O in the path /etc/systemd/system/crio.service.d/microshift-cpuaffinity.conf.

      CRI-O systemd configuration example
      # ...
      [Service]
      CPUAffinity=0,6,7
      # ...
  3. Create and update the systemd configuration file with CPUAffinity value for the MicroShift and CRI-O services:

    • Create the MicroShift services systemd file in the path /etc/systemd/system/microshift.service.d/microshift-cpuaffinity.conf. MicroShift will be pinned using the systemd CPUAffinity value.

      MicroShift services systemd configuration example
      # ...
      [Service]
      CPUAffinity=0,6,7
      # ...
    • Update the CPUAffinity value in the MicroShift ovs-vswitchd systemd file in the path /etc/systemd/system/ovs-vswitchd.service.d/microshift-cpuaffinity.conf.

      MicroShift ovs-vswitchd systemd configuration example
      # ...
      [Service]
      CPUAffinity=0,6,7
      # ...
    • Update the CPUAffinity value in the MicroShift ovsdb-server systemd file in the path /etc/systemd/system/ovsdb-server.service.d/microshift-cpuaffinity.conf

      MicroShift ovsdb-server systemd configuration example
      # ...
      [Service]
      CPUAffinity=0,6,7
      # ...

Disable deployments that run CSI snapshot implementations

To prevent the installation of CSI implementation pods, disable the deployments that run CSI snapshot implementations. This configuration conserves system resources by ensuring that snapshot components are not deployed when they are not required.

Important

Use the procedure if you are defining the configuration file before installing and running MicroShift. If MicroShift is already started, the CSI snapshot implementation will be running. You must manually remove the implementation by following the uninstallation instructions.

Note

MicroShift does not delete CSI snapshot implementation pods. You must configure MicroShift to disable installation of the CSI snapshot implementation pods during the startup process.

Procedure
  1. Disable installation of the CSI snapshot controller by entering the optionalCsiComponents value under the storage section of the MicroShift configuration file in /etc/microshift/config.yaml:

    # ...
      storage: {}
    # ...

    where:

    storage

    Specifies the storage details. You can choose to not define optionalCsiComponents. If you do specify the optionalCsiComponents field, valid values include: an empty value ([]) or a single empty string element ([""]), snapshot-controller, or none. A value of none is mutually exclusive with all other values.

    Note

    If the optionalCsiComponents value is empty or null, MicroShift defaults to deploying snapshot-controller.

  2. After the optionalCsiComponents field is specified with a supported value in the config.yaml, start MicroShift by running the following command:

    $ sudo systemctl start microshift
    Note

    MicroShift does not redeploy the disabled components after a restart.

Disable deployments that run the CSI driver implementations

You can disable installation of the CSI implementation pods. MicroShift does not delete CSI driver implementation pods. You must configure MicroShift to disable installation of the CSI driver implementation pods during the startup process.

Important

This procedure is for defining the configuration file before installing and running MicroShift. If MicroShift is already started, then the CSI driver implementation is running. You must manually remove it by following the uninstallation instructions.

Procedure
  1. Disable installation of the CSI driver by entering the driver value under the storage section of the MicroShift configuration file in /etc/microshift/config.yaml:

    # ...
      storage
       driver:
       - "none"
    # ...

    where:

    storage.driver.none

    Specifies the driver to disable. Valid values are none or lvms.

    Note

    By default, the driver value is empty or null and LVMS is deployed.

  2. Start MicroShift after the driver field is specified with a supported value in the /etc/microshift/config.yaml file by running the following command:

    $ sudo systemctl enable --now microshift
    Note

    MicroShift does not redeploy the disabled components after a restart operation.

Maintain system health with the greenboot health check framework

Use the greenboot health check framework to verify that your MicroShift system is healthy at boot time. If problems are detected, greenboot automatically rolls back to a previous working version so that you do not have to fix the system in person at remote edge locations.

How greenboot uses directories to run scripts

Greenboot uses directory-based framework to execute health check scripts during the system boot process. By organizing your custom scripts into specific directories, you can define the boot validation workflow and determine whether the system successfully applies an update or initiates an automated rollback.

Health check scripts run from four /etc/greenboot directories. These scripts run in alphabetical order. Keep this in mind when you configure the scripts for your workloads.

When the system starts, greenboot runs the scripts in the required.d and wanted.d directories. Depending on the outcome of those scripts, greenboot continues the startup or attempts a rollback as follows:

  1. System as expected: When all of the scripts in the required.d directory are successfully run, greenboot runs any scripts present in the /etc/greenboot/green.d directory.

  2. System trouble: If any of the scripts in the required.d directory fail, greenboot runs any prerollback scripts present in the red.d directory, then restarts the system.

Note

Greenboot redirects script and health check output to the system log. When you are logged in, a daily message provides the overall system health output.

Greenboot directories details

You can control how greenboot handles errors by placing your health check scripts in specific directories. The directories determine which scripts are strictly required for a successful boot and which ones can fail without causing a rollback.

Returning a nonzero exit code from any script means that script has failed. Greenboot restarts the system a few times to retry the scripts before attempting to roll back to the previous version.

  • /etc/greenboot/check/required.d contains the health checks that must not fail.

    • If the scripts fail, greenboot retries them three times by default. You can configure the number of retries in the /etc/greenboot/greenboot.conf file by setting the GREENBOOT_MAX_BOOTS parameter to the desired number of retries.

    • After all retries fail, greenboot automatically initiates a rollback if one is available. If a rollback is not available, the system log output shows that manual intervention is required.

    • The 40_microshift_running_check.sh health check script for MicroShift is installed into this directory.

  • /etc/greenboot/check/wanted.d contains health scripts that are allowed to fail without causing the system to be rolled back.

    • If any of these scripts fail, greenboot logs the failure but does not initiate a rollback.

  • /etc/greenboot/green.d contains scripts that run after greenboot has declared the start successful.

  • /etc/greenboot/red.d contains scripts that run after greenboot has declared the startup as failed, including the 40_microshift_pre_rollback.sh prerollback script. This script is executed right before a system rollback. The script performs MicroShift pod and OVN-Kubernetes cleanup to avoid potential conflicts after the system is rolled back to a previous version.

Important

If you customize the values of any environment variable in the /etc/greenboot/greenboot.conf file, these changes can be lost when the greenboot RPM package is updated or downgraded.

  • To retain customizations when building system images with MicroShift, add the greenboot.conf file to a blueprint.

  • To retain customizations when using an RPM installation, apply changes to the greenboot.conf file after you install MicroShift and greenboot RPMs.

Included greenboot health checks

By default, Red Hat Enterprise Linux for Edge (RHEL for Edge) includes a set of built-in greenboot health checks designed to verify functions, such as network connectivity to update repositories and hardware watchdog status. Health check scripts are available in /usr/lib/greenboot/check, a read-only directory in Red Hat Enterprise Linux for Edge (RHEL for Edge) image mode for RHEL systems.

The following health checks are included with the greenboot-default-health-checks framework.

  • Check if repository URLs are still DNS solvable:

    This script is under /usr/lib/greenboot/check/required.d/01_repository_dns_check.sh and ensures that DNS queries to repository URLs are still available.

  • Check if update platforms are still reachable:

    This script is under /usr/lib/greenboot/check/wanted.d/01_update_platform_check.sh and tries to connect and get a 2XX or 3XX HTTP code from the update platforms defined in /etc/ostree/remotes.d.

  • Check if the current boot has been triggered by the hardware watchdog:

    This script is under /usr/lib/greenboot/check/required.d/02_watchdog.sh and checks whether the current boot has been watchdog-triggered or not.

    • If the watchdog-triggered reboot occurs within the grace period, the current boot is marked as red. Greenboot does not trigger a rollback to the previous deployment.

    • If the watchdog-triggered reboot occurs after the grace period, the current boot is not marked as red. Greenboot does not trigger a rollback to the previous deployment.

    • A 24-hour grace period is enabled by default. This grace period can be either disabled by modifying GREENBOOT_WATCHDOG_CHECK_ENABLED in /etc/greenboot/greenboot.conf to false, or configured by changing the GREENBOOT_WATCHDOG_GRACE_PERIOD=number_of_hours variable value in /etc/greenboot/greenboot.conf.

The MicroShift health check script

The 40_microshift_running_check.sh health check script only performs validation of core MicroShift services. Install your customized workload health check scripts in the greenboot directories to ensure successful application operations after system updates. Scripts run in alphabetical order.

MicroShift health checks are listed in the following table:

Table 13. Validation statuses and outcome for MicroShift
Validation Pass Fail

Check that the script runs with root permissions

Next

exit 0

Check that the microshift.service is enabled

Next

exit 0

Wait for the microshift.service to be active (!failed)

Next

exit 1

For each core namespace, wait for readiness of the workload

Next

exit 1

Validation wait period

The wait period in each validation is 10 minutes by default. After the wait period, if the validation has not succeeded, it is declared a failure. This wait period is incrementally increased by the base wait period after each boot in the verification loop.

  • You can override the base-time wait period by setting the MICROSHIFT_WAIT_TIMEOUT_SEC environment variable in the /etc/greenboot/greenboot.conf configuration file. For example, you can change the wait time to 5 minutes by resetting the value to 300 seconds, such as MICROSHIFT_WAIT_TIMEOUT_SEC=300.

Enable systemd journal service data persistency

The default configuration of the systemd journal service stores the data in the volatile /run/log/journal directory. To view system logs across system starts and restarts, you must enable log persistence and set limits on the maximal journal data size.

Procedure
  1. Make the directory by running the following command:

    $ sudo mkdir -p /etc/systemd/journald.conf.d
  2. Create the configuration file by running the following command:

    cat <<EOF | sudo tee /etc/systemd/journald.conf.d/microshift.conf &>/dev/null
    [Journal]
    Storage=persistent
    SystemMaxUse=1G
    RuntimeMaxUse=1G
    EOF
  3. Edit the configuration file values for your size requirements.

Updates and third-party workloads

After the update, you can examine the output of greenboot health checks and determine whether the update was declared valid. This health check can help you determine if the system is working properly.

Health check scripts for updates are installed into the /etc/greenboot/check/required.d directory and are automatically executed during each system start. Exiting scripts with a nonzero status means the system start is declared as failed.

Important

Wait until after an update is declared valid before starting third-party workloads. If a rollback is performed after workloads start, you can lose data. Some third-party workloads create or update data on a device before an update is complete. Upon rollback, the file system reverts to its state before the update.

Check the results of an update

You can view the overall status of system health checks after an update in the system log. After a successful start, greenboot sets the variable boot_success= to 1 in GRUB.

Procedure
  • To access the overall status of system health checks, run the following command:

    $ sudo grub2-editenv - list | grep ^boot_success
    Example output for a successful system start
    boot_success=1
    • If your command returns boot_success=0, either the greenboot health check is still running, or the update is a failure.

Accessing health check output in the system log

If the system update fails or the boot process stops, you can query the system logs for detailed troubleshooting information. These logs provide the detailed steps necessary to troubleshoot failed boot checks.

Procedure
  • To access the results of a health check, run the following command:

    $ sudo journalctl -o cat -u greenboot-healthcheck.service
    Example output of a failed health check
    ...
    ...
    Running Required Health Check Scripts...
    STARTED
    GRUB boot variables:
    boot_success=0
    boot_indeterminate=0
    boot_counter=2
    ...
    ...
    Waiting 600s for MicroShift service to be active and not failed
    FAILURE
    ...
    ...

Accessing prerollback health check output in the system log

When a system update fails and greenboot triggers a rollback, it executes prerollback scripts to clean up services and prevent data conflicts. Using the output of the health check scripts, you can verify that the cleanup tasks are completed successfully before the system reboots into the previous deployment.

For example, check the results of a pre-rollback script using the following procedure.

Procedure
  • To access the results of a prerollback script, run the following command:

    $ sudo journalctl -o cat -u redboot-task-runner.service
    Example output of a prerollback script
    ...
    ...
    Running Red Scripts...
    STARTED
    GRUB boot variables:
    boot_success=0
    boot_indeterminate=0
    boot_counter=0
    The ostree status:
    * rhel c0baa75d9b585f3dd989a9cf05f647eb7ca27ee0dbd4b94fe8c93ed3a4b9e4a5.0
        Version: 9.8
        origin: <unknown origin type>
      rhel 6869c1347b0e0ba1bbf0be750cdf32da5138a1fcbc5a4c6325ab9eb647b64663.0 (rollback)
        Version: 9.8
        origin refspec: edge:rhel/9/x86_64/edge
    System rollback imminent - preparing MicroShift for a clean start
    Stopping MicroShift services
    Removing MicroShift pods
    Killing conmon, pause and OVN processes
    Removing OVN configuration
    Finished greenboot Failure Scripts Runner.
    Cleanup succeeded
    Script '40_microshift_pre_rollback.sh' SUCCESS
    FINISHED
    redboot-task-runner.service: Deactivated successfully.
    Note

    In case of a rollback, the pre-rollback script runs the sudo microshift-cleanup-data --ovn command to prepare the system for a potential software downgrade.

Check updates with a health check script

To verify the success or failure of a recent system update, you can review the output of greenboot health check scripts in the system log after an update.

Procedure
  • To access the result of update checks, run the following command:

    $ sudo grub2-editenv - list | grep ^boot_success
    Example output for a successful update
    boot_success=1
    • If your command returns boot_success=0, either the greenboot health check is still running, or the update is a failure.

How workload health checks work

You can use greenboot health checks to assess the health of your workloads and applications. You can also write your own health check scripts for your applications. Greenboot health checks are helpful on edge devices where direct serviceability is either limited or non-existent.

These additional health checks are useful for software problem detection and automatic system rollbacks.

Workload or application health checks can use the MicroShift basic health check functions already implemented for the MicroShift core services. Creating your own comprehensive scripts for your applications is recommended. For example, you can write one that verifies that a service has started.

You can also use the microshift healthcheck command, which can run checks that the basic functions of the workload are operating as expected.

Important

The following functions related to checking workload health in /usr/share/microshift/functions/greenboot.sh are deprecated and planned for removal in a future release:

  • wait_for

  • namespace_images_downloaded

  • namespace_deployment_ready

  • namespace_daemonset_ready

  • namespace_pods_ready

  • namespace_pods_not_restarting

  • print_failure_logs

  • log_failure_cmd

  • log_script_exit

  • lvmsDriverShouldExist

  • csiComponentShouldBeDeploy

How to use the MicroShift health check command

The microshift healthcheck command checks whether a workload of the provided type exists and verifies its status for the specified timeout duration. The number of ready replicas, that is, pods, must match the expected amount.

To run the microshift healthcheck command successfully, use the following prerequisites:

  • Execute commands from a root user account.

  • Enable the MicroShift service.

You can add the following actions to the microshift healthcheck command:

  • -v=2 to increase verbosity of the output

  • --timeout="${WAIT_TIMEOUT_SECS}s" to override default 600s timeout value

  • --namespace `<namespace> to specify the namespace of the workloads

  • --deployments `<application-deployment> to check the readiness of a specific deployment

    Example command
    $ sudo microshift healthcheck -v=2 --timeout="300s" --namespace busybox --deployments busybox-deployment
    Example output
    ??? I0410 08:54:03.766578    5898 service.go:29] microshift.service is enabled
    ??? I0410 08:54:03.766699    5898 service.go:31] Waiting 5m0s for microshift.service to be ready
    ??? I0410 08:54:03.768794    5898 service.go:38] microshift.service is ready
    ??? I0410 08:54:03.770585    5898 utils.go:34] Waiting for 1 goroutines
    ??? I0410 08:54:03.770955    5898 workloads.go:94] Waiting 5m0s for deployment/busybox-deployment in busybox
    ??? I0410 08:54:03.777830    5898 workloads.go:132] Deployment/busybox-deployment in busybox is ready
    ??? I0410 08:54:03.777858    5898 healthcheck.go:75] Workloads are ready

The microshift healthcheck command also accepts the following additional parameters to specify other kinds of workloads:

  • --daemonsets

  • --statefulsets

  • These options take a comma-delimited list of resources, for example, --daemonsets ovnkube-master,ovnkube-node.

Alternatively, a --custom option can be used with a JSON string, for example:

$ sudo microshift healthcheck --custom '{"openshift-storage":{"deployments":
    ["lvms-operator"], "daemonsets": ["vg-manager"]}, "openshift-ovn-kubernetes":
    {"daemonsets": ["ovnkube-master", "ovnkube-node"]}}'
Example output
??? I0410 08:54:25.291059    5979 service.go:29] microshift.service is enabled
??? I0410 08:54:25.291167    5979 service.go:31] Waiting 5m0s for microshift.service to be ready
??? I0410 08:54:25.293188    5979 service.go:38] microshift.service is ready
??? I0410 08:54:25.294331    5979 workloads.go:58] Waiting 5m0s for daemonset/ovnkube-node in openshift-ovn-kubernetes
??? I0410 08:54:25.294351    5979 workloads.go:58] Waiting 5m0s for daemonset/ovnkube-master in openshift-ovn-kubernetes
??? I0410 08:54:25.294331    5979 workloads.go:58] Waiting 5m0s for daemonset/vg-manager in openshift-storage
??? I0410 08:54:25.294341    5979 workloads.go:94] Waiting 5m0s for deployment/lvms-operator in openshift-storage
??? I0410 08:54:25.309739    5979 workloads.go:89] Daemonset/ovnkube-node in openshift-ovn-kubernetes is ready
??? I0410 08:54:25.310213    5979 workloads.go:89] Daemonset/vg-manager in openshift-storage is ready
??? I0410 08:54:25.310731    5979 workloads.go:132] Deployment/lvms-operator in openshift-storage is ready
??? I0410 08:54:25.311017    5979 workloads.go:89] Daemonset/ovnkube-master in openshift-ovn-kubernetes is ready
??? I0410 08:54:25.311189    5979 healthcheck.go:52] Workloads are ready

How to create a health check script for your application

You can create workload or application health check scripts in the text editor of your choice. Save the scripts in the /etc/greenboot/check/required.d directory.

When a script in the /etc/greenboot/check/required.d directory exits with an error, greenboot triggers a reboot in an attempt to heal the system.

Note

Any script in the /etc/greenboot/check/required.d directory triggers a reboot if it exits with an error.

If your health check logic requires any post-check steps, you can also create additional scripts and save them in the relevant greenboot directories. For example:

  • You can also place shell scripts you want to run after a boot has been declared successful in /etc/greenboot/green.d.

  • You can place shell scripts you want to run after a boot has been declared failed in /etc/greenboot/red.d. For example, if you have steps to heal the system before restarting, you can create scripts for your use case and place them in the /etc/greenboot/red.d directory.

Workload max duration or timeout script example

You can use the MicroShift core services health check script as a template to write your own health check scripts for your applications.

Basic prerequisites for creating a health check script
  • The workload must be installed.

  • You must have root access.

Example and functional requirements

You can start with the following example health check script. Add to it for your use case. In your custom workload health check script, you must define the relevant namespace, deployment, daemonset, and statefulset.

Important

Choose a name prefix for your application that ensures it runs after the 40_microshift_running_check.sh script, which implements the MicroShift health check procedure for its core services.

Example greenboot health check script
#!/bin/bash
set -e

SCRIPT_NAME=$(basename $0)

# Load the workload health check functions library
source /usr/share/microshift/functions/greenboot.sh

# Stop the script if the user running it is not 'root'
if [ $(id -u) -ne 0 ] ; then
    echo "The '${SCRIPT_NAME}' script must be run with the 'root' user privileges"
    exit 1
fi

echo "STARTED"

# Set the wait timeout for the current check based on the boot counter
WAIT_TIMEOUT_SECS=$(get_wait_timeout)

/usr/bin/microshift healthcheck -v=2 --timeout="${WAIT_TIMEOUT_SECS}s" --namespace busybox --deployments busybox-deployment
Important

Functions related to checking workload health previously included in the /usr/share/microshift/functions/greenboot.sh script file are deprecated. You can write a custom script, or use the microshift healthcheck command with various options instead. See "How workload health check scripts work" for more information.

Test a workload health check script

You can look at the output of the greenboot workload health check script to see how it works. While the output varies with the host system type, the example outputs for Red Hat Enterprise Linux (RHEL) system types are included for reference only.

Prerequisites
  • You have root access.

  • You installed a workload.

  • You created a health check script for the workload.

  • The MicroShift service is enabled.

Procedure
  1. To test that greenboot is running a health check script file, reboot the host by running the following command:

    $ sudo reboot
  2. Examine the output of greenboot health checks by running the following command:

    $ sudo journalctl -o cat -u greenboot-healthcheck.service
    Note

    MicroShift core service health checks run before the workload health checks.

    Example output for an image mode for RHEL system
    Starting greenboot Health Checks Runner...
    Running Required Health Check Scripts...
    Script '00_required_scripts_start.sh' SUCCESS
    Running Wanted Health Check Scripts...
    Script '00_wanted_scripts_start.sh' SUCCESS
    Running Required Health Check Scripts...
    --------------------
    DEPRECATION NOTICE:
    /usr/share/microshift/functions/greenboot.sh is now deprecated and will be removed in future release.
    As a replacement consider using 'microshift healthcheck' command
    --------------------
    STARTED
    GRUB boot variables:
    boot_success=0
    Greenboot variables:
    GREENBOOT_WATCHDOG_CHECK_ENABLED=true
    MICROSHIFT_GREENBOOT_FAIL_MARKER=/run/microshift-greenboot-healthcheck-failed
    System installation type:
    bootc
    System installation status:
    bootcHost
    ??? I0403 11:54:30.526488     979 service.go:29] microshift.service is enabled
    ??? I0403 11:54:30.527145     979 service.go:31] Waiting 10m0s for microshift.service to be ready
    ??? I0403 11:58:52.530299     979 service.go:38] microshift.service is ready
    ??? I0403 11:58:52.532292     979 net.go:79] host gateway IP address: 192.168.112.125
    ??? I0403 11:58:52.555077     979 microshift_core_workloads.go:71] vgs reported: {"report":[{"vg":[{"vg_name":"rhel"}]}],"log":[]}
    ??? I0403 11:58:52.555138     979 microshift_core_workloads.go:93] Detected 1 volume group (rhel) - LVMS is expected
    ??? I0403 11:58:52.555143     979 microshift_core_workloads.go:126] Configured optional CSI components: []
    ??? I0403 11:58:52.555147     979 microshift_core_workloads.go:117] At least one CSI Component is enabled
    ??? I0403 11:58:52.555770     979 utils.go:34] Waiting for 9 goroutines
    ??? I0403 11:58:52.555791     979 workloads.go:94] Waiting 10m0s for deployment/service-ca in openshift-service-ca
    ??? I0403 11:58:52.555890     979 workloads.go:58] Waiting 10m0s for daemonset/ovnkube-master in openshift-ovn-kubernetes
    ??? I0403 11:58:52.555999     979 workloads.go:94] Waiting 10m0s for deployment/router-default in openshift-ingress
    ??? I0403 11:58:52.556096     979 workloads.go:58] Waiting 10m0s for daemonset/dns-default in openshift-dns
    ??? I0403 11:58:52.556244     979 workloads.go:58] Waiting 10m0s for daemonset/ovnkube-node in openshift-ovn-kubernetes
    ??? I0403 11:58:52.556330     979 workloads.go:94] Waiting 10m0s for deployment/lvms-operator in openshift-storage
    ??? I0403 11:58:52.556382     979 workloads.go:58] Waiting 10m0s for daemonset/vg-manager in openshift-storage
    ??? I0403 11:58:52.556425     979 workloads.go:94] Waiting 10m0s for deployment/csi-snapshot-controller in kube-system
    ??? I0403 11:58:52.556474     979 workloads.go:58] Waiting 10m0s for daemonset/node-resolver in openshift-dns
    ??? I0403 11:58:52.574284     979 workloads.go:89] Daemonset/ovnkube-node in openshift-ovn-kubernetes is ready
    ??? I0403 11:58:52.574344     979 workloads.go:89] Daemonset/dns-default in openshift-dns is ready
    ??? I0403 11:59:12.871058     979 workloads.go:89] Daemonset/node-resolver in openshift-dns is ready
    ??? I0403 11:59:12.871621     979 workloads.go:89] Daemonset/ovnkube-master in openshift-ovn-kubernetes is ready
    ??? I0403 11:59:12.871748     979 workloads.go:132] Deployment/csi-snapshot-controller in kube-system is ready
    ??? I0403 11:59:25.175015     979 workloads.go:132] Deployment/service-ca in openshift-service-ca is ready
    ??? I0403 11:59:42.559264     979 workloads.go:132] Deployment/lvms-operator in openshift-storage is ready
    ??? I0403 11:59:52.557786     979 workloads.go:132] Deployment/router-default in openshift-ingress is ready
    ??? I0403 11:59:52.558489     979 workloads.go:89] Daemonset/vg-manager in openshift-storage is ready
    ??? I0403 11:59:52.558505     979 healthcheck.go:28] MicroShift is ready
    Script '40_microshift_running_check.sh' SUCCESS
    --------------------
    DEPRECATION NOTICE:
    /usr/share/microshift/functions/greenboot.sh is now deprecated and will be removed in future release.
    Planned removal: MicroShift 4.21
    As a replacement consider using 'microshift healthcheck' command
    --------------------
    STARTED
    GRUB boot variables:
    boot_success=0
    Greenboot variables:
    GREENBOOT_WATCHDOG_CHECK_ENABLED=true
    MICROSHIFT_GREENBOOT_FAIL_MARKER=/run/microshift-greenboot-healthcheck-failed
    System installation type:
    bootc
    System installation status:
    bootcHost
    ??? I0403 11:59:52.750474    4059 service.go:29] microshift.service is enabled
    ??? I0403 11:59:52.750873    4059 service.go:31] Waiting 10m0s for microshift.service to be ready
    ??? I0403 11:59:52.752273    4059 service.go:38] microshift.service is ready
    ??? I0403 11:59:52.753263    4059 utils.go:34] Waiting for 1 goroutines
    ??? I0403 11:59:52.753393    4059 workloads.go:94] Waiting 10m0s for deployment/kserve-controller-manager in redhat-ods-applications
    ??? I0403 12:00:02.755475    4059 workloads.go:132] Deployment/kserve-controller-manager in redhat-ods-applications is ready
    ??? I0403 12:00:02.755605    4059 healthcheck.go:75] Workloads are ready
    Script '41_microshift_running_check_ai_model_serving.sh' SUCCESS
    --------------------
    DEPRECATION NOTICE:
    /usr/share/microshift/functions/greenboot.sh is now deprecated and will be removed in future release.
    Planned removal: MicroShift 4.21
    As a replacement consider using 'microshift healthcheck' command
    --------------------
    STARTED
    GRUB boot variables:
    boot_success=0
    Greenboot variables:
    GREENBOOT_WATCHDOG_CHECK_ENABLED=true
    MICROSHIFT_GREENBOOT_FAIL_MARKER=/run/microshift-greenboot-healthcheck-failed
    System installation type:
    bootc
    System installation status:
    bootcHost
    ??? I0403 12:00:02.896949    4128 service.go:29] microshift.service is enabled
    ??? I0403 12:00:02.897208    4128 service.go:31] Waiting 10m0s for microshift.service to be ready
    ??? I0403 12:00:02.899492    4128 service.go:38] microshift.service is ready
    ??? I0403 12:00:02.900279    4128 utils.go:34] Waiting for 2 goroutines
    ??? I0403 12:00:02.900363    4128 workloads.go:94] Waiting 10m0s for deployment/istiod-openshift-gateway-api in openshift-gateway-api
    ??? I0403 12:00:02.900948    4128 workloads.go:94] Waiting 10m0s for deployment/servicemesh-operator3 in openshift-gateway-api
    ??? I0403 12:00:42.913338    4128 workloads.go:132] Deployment/servicemesh-operator3 in openshift-gateway-api is ready
    ??? I0403 12:01:12.902297    4128 workloads.go:132] Deployment/istiod-openshift-gateway-api in openshift-gateway-api is ready
    ??? I0403 12:01:12.902418    4128 healthcheck.go:75] Workloads are ready
    Script '41_microshift_running_check_gateway_api.sh' SUCCESS
    --------------------
    DEPRECATION NOTICE:
    /usr/share/microshift/functions/greenboot.sh is now deprecated and will be removed in future release.
    Planned removal: MicroShift 4.21
    As a replacement consider using 'microshift healthcheck' command
    --------------------
    STARTED
    GRUB boot variables:
    boot_success=0
    Greenboot variables:
    GREENBOOT_WATCHDOG_CHECK_ENABLED=true
    MICROSHIFT_GREENBOOT_FAIL_MARKER=/run/microshift-greenboot-healthcheck-failed
    System installation type:
    bootc
    System installation status:
    bootcHost
    ??? I0403 12:01:13.057998    4772 service.go:29] microshift.service is enabled
    ??? I0403 12:01:13.058107    4772 service.go:31] Waiting 10m0s for microshift.service to be ready
    ??? I0403 12:01:13.059839    4772 service.go:38] microshift.service is ready
    ??? I0403 12:01:13.060617    4772 utils.go:34] Waiting for 2 goroutines
    ??? I0403 12:01:13.060644    4772 workloads.go:58] Waiting 10m0s for daemonset/dhcp-daemon in openshift-multus
    ??? I0403 12:01:13.060686    4772 workloads.go:58] Waiting 10m0s for daemonset/multus in openshift-multus
    ??? I0403 12:01:13.069341    4772 workloads.go:89] Daemonset/multus in openshift-multus is ready
    ??? I0403 12:01:13.069450    4772 workloads.go:89] Daemonset/dhcp-daemon in openshift-multus is ready
    ??? I0403 12:01:13.069503    4772 healthcheck.go:75] Workloads are ready
    Script '41_microshift_running_check_multus.sh' SUCCESS
    --------------------
    DEPRECATION NOTICE:
    /usr/share/microshift/functions/greenboot.sh is now deprecated and will be removed in future release.
    Planned removal: MicroShift 4.21
    As a replacement consider using 'microshift healthcheck' command
    --------------------
    STARTED
    GRUB boot variables:
    boot_success=0
    Greenboot variables:
    GREENBOOT_WATCHDOG_CHECK_ENABLED=true
    MICROSHIFT_GREENBOOT_FAIL_MARKER=/run/microshift-greenboot-healthcheck-failed
    System installation type:
    bootc
    System installation status:
    bootcHost
    ??? I0403 12:01:13.206381    4804 service.go:29] microshift.service is enabled
    ??? I0403 12:01:13.206583    4804 service.go:31] Waiting 10m0s for microshift.service to be ready
    ??? I0403 12:01:13.207979    4804 service.go:38] microshift.service is ready
    ??? I0403 12:01:13.208717    4804 utils.go:34] Waiting for 2 goroutines
    ??? I0403 12:01:13.208779    4804 workloads.go:94] Waiting 10m0s for deployment/catalog-operator in openshift-operator-lifecycle-manager
    ??? I0403 12:01:13.209285    4804 workloads.go:94] Waiting 10m0s for deployment/olm-operator in openshift-operator-lifecycle-manager
    ??? I0403 12:01:13.215578    4804 workloads.go:132] Deployment/catalog-operator in openshift-operator-lifecycle-manager is ready
    ??? I0403 12:01:13.215673    4804 workloads.go:132] Deployment/olm-operator in openshift-operator-lifecycle-manager is ready
    ??? I0403 12:01:13.215684    4804 healthcheck.go:75] Workloads are ready
    Script '50_microshift_running_check_olm.sh' SUCCESS
    Running Wanted Health Check Scripts...
    Finished greenboot Health Checks Runner.
    Example partial output for a RHEL for Edge system
    #...
    GRUB boot variables:
    boot_success=0
    boot_indeterminate=0
    Greenboot variables:
    GREENBOOT_WATCHDOG_CHECK_ENABLED=true
    MICROSHIFT_WAIT_TIMEOUT_SEC=600
    System installation type:
    ostree
    System installation status:
    * rhel 19619bd269094510180c845c44d0944fd9aa15925376f249c4d680a3355e51ae.0
        Version: 9.8
        origin refspec: edge:rhel-9.8-microshift-4.22
    #...
    Example partial output for an RPM system
    #...
    GRUB boot variables:
    boot_success=1
    boot_indeterminate=0
    Greenboot variables:
    GREENBOOT_WATCHDOG_CHECK_ENABLED=true
    System installation type:
    RPM
    System installation status:
    Not an ostree / bootc system
    #...

Check the status of greenboot health checks

You can check the status of greenboot health checks before making changes to the system or while troubleshooting. By using helpful commands to verify that greenboot scripts have finished running.

Procedure
  • Check the current greenboot health check status by running the following command:

    $ systemctl show --property=SubState --value greenboot-healthcheck.service

    where:

    start

    Greenboot checks are still running.

    exited

    Checks have passed and greenboot has exited. Greenboot runs the scripts in the green.d directory when the system is in a healthy state.

    failed

    Checks have not passed. Greenboot runs the scripts in the red.d directory when the system is in this state and restarts the system.

  • Check the numerical exit code of the greenboot health check service by running the following command:

    $ systemctl show --property=ExecMainStatus --value greenboot-healthcheck.service

    An exit code of 0 means the health check succeeded. A non-zero exit code means the health check failed.

  • To see a report showing a message about boot status, such as Boot Status is GREEN - Health Check SUCCESS, use the following command:

    $ cat /run/motd.d/boot-status
    Example output
    Boot Status is GREEN - Health Check SUCCESS

Test new Kubernetes features in MicroShift

Use feature gates to test new Kubernetes features for potential use in your MicroShift deployments. Feature gates let you experiment with upcoming Kubernetes capabilities to evaluate their potential benefits for specific edge use cases.

Understand feature gates for MicroShift

As an application developer for edge computing environments, you can now experiment with upcoming Kubernetes features to evaluate their potential benefits for specific use cases.

By using feature gates, you can test various enhancements that might improve performance in your resource-constrained edge environments. For example, you can try advanced CPU management, enhanced scheduling features, or experimental storage options.

Warning

When you trial new features using feature gates, your MicroShift can become unstable or lose data. Enable feature gates only in non-production environments.

When planning to use feature gates for development, consider the following details:

  • After you specify feature gates, you cannot update MicroShift.

  • If your configuration is not valid, MicroShift can fail to start.

  • The Kubernetes components you enable handle feature gate validation.

  • Feature gates are disabled by default in MicroShift. After you enable feature gates, you cannot disable them.

Use feature gates for MicroShift

To use feature gates in your development environment, you must specify them in the config.yaml file or create a configuration snippet file. You must also configure the feature set you want to work with.

Important
  • A config.yaml configuration file takes precedence over built-in settings. The config.yaml file is read every time the MicroShift service starts.

  • Configuration snippet YAMLs take precedence over both built-in settings and the config.yaml configuration file.

  • After you enable feature gates, you cannot disable them.

Prerequisites
  • You installed MicroShift.

  • You installed the OpenShift CLI (oc).

  • You have sudo privileges on the MicroShift host.

Procedure
  1. Apply features gates in one of the two following ways:

    1. Update the MicroShift config.yaml configuration file by making a copy of the provided config.yaml.default file in the /etc/microshift/ directory. Name it config.yaml and keep it in the source directory.

    2. Use a configuration snippet to apply the ingress control settings you want. To do this, create a configuration snippet YAML file and put it in the /etc/microshift/config.d/ configuration directory. For example, /etc/microshift/config.d/10-feature-gate.yaml.

  2. Replace the default values in the xyz section of the MicroShift YAML with your valid values, or create a configuration snippet file with the sections you need.

    Feature gates configuration with example values
    # ...
    apiServer:
      featureGates:
        featureSet: TechPreviewNoUpgrade
    # ...
    apiServer:
      featureGates:
        featureSet: CustomNoUpgrade
        customNoUpgrade:
          enabled:
          - "CPUManagerPolicyAlphaOptions"
          - "MemoryQoS"
          disabled:
          - "SomeDefaultEnabledFeature"
    # ...
  3. Use the following configuration rules:

    1. You must set the featureSet field when configuring feature gates.

    2. When you use customNoUpgrade feature, you must set the featureSet to CustomNoUpgrade. The customNoUpgrade field is only valid when featureSet: CustomNoUpgrade.

    3. If you have a support exception for a customized node, make sure that the custom feature you want to use appears in the specialHandlingSupportExceptionRequired field and is enabled. The custom feature must also be enabled in the customNoUpgrade field.

      Note

      If a feature is enabled in the specialHandlingSupportExceptionRequired field, your customized node can upgrade in the same manner as a supported node.

      Custom feature example configuration
      # ...
      apiServer:
         featureGates:
           featureSet: customNoUpgrade
           customNoUpgrade:
             enabled:
             - "SomeFeature"
           specialHandlingSupportExceptionRequired:
             enabled:
             - "SomeFeature"
      # ...
  4. Configure any settings required for the feature set you want to work with.

  5. Restart MicroShift to apply the configuration changes by running the following command:

    $ sudo systemctl restart microshift

Configure MicroShift with the configuration file

MicroShift uses a YAML configuration file to control networking, API server behavior, node settings, and other runtime options. You can customize MicroShift by editing the default configuration file or by providing configuration snippets that are merged at startup. Understanding the configuration file structure and parameters helps you tailor MicroShift to your deployment requirements.

Configuring Red Hat Device Edge

The MicroShift configuration file, config.yaml, centralizes Red Hat Device Edge and service settings for your single-node edge platform. To create a custom configuration, you can copy the installed config.yaml.default file and rename it to config.yaml.

MicroShift and Red Hat Enterprise Linux (RHEL) work together to bring a lighter-weight, single-node Kubernetes to the edge. This combination means that there is a single node that is both control-plane and worker. It also means that the operating system handles many functions. You add features by installing optional RPMs or Operators. In many cases, you must configure the operating system or other resources in addition to the MicroShift service.

Bringing these components together is the MicroShift configuration file, config.yaml. The configuration file customizes your application platform and enables advanced functionality.

Using the default configuration file

A config.yaml.default file is installed automatically. You can copy this file, rename it config.yaml, and use it as the starting point for your custom configuration.

Configuring platform features

You can use the MicroShift configuration file to control and customize platform features. For example:

Ingress

Ingress is available by default, but you can add advanced functions such as TLS and route admission specifications by using parameters in the MicroShift configuration file.

Storage

If you do not need storage, you can disable the built-in storage provider by using the MicroShift configuration file. If you do want to use the built-in storage provider, you must make your adjustments in the lvmd.config file. The role of the MicroShift configuration file in this case is to set whether you use the default storage provider.

Advanced networking functions

Advanced networking functions, such as using multiple networks. The Multus package is an installable RPM, but you set up access by using the MicroShift configuration file to set parameters. In addition, you must configure network settings on your networks through the host.

Note

You can also add features that operate without configurations to the MicroShift config.yaml file. For example, you can install and configure GitOps for application management without configuring MicroShift.

The MicroShift configuration file

At startup, MicroShift checks the system-wide /etc/microshift/ directory for a configuration file named config.yaml. If the configuration file does not exist in the directory, built-in default values are used to start the service.

You must use the MicroShift configuration file in combination with host and, sometimes, application and service settings. Ensure that you configure each function in tandem when you adjust settings for your MicroShift node.

For your convenience, a config.yaml.default file ready for your inputs is automatically installed.

Default settings
Important

The Generic Device Plugin for MicroShift is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

For more information about the support scope of Red Hat Technology Preview features, see Technology Preview Features Support Scope.

When no config.yaml or configuration snippet exists, MicroShift uses built-in default values. To view these defaults, run microshift show-config.

The following example shows the default configuration settings.

Procedure
  • To see the default values, run the following command:

    $ microshift show-config
    Default values example output in YAML form
    apiServer:
      advertiseAddress: 10.44.0.0/32
      auditLog:
        maxFileAge: 0
        maxFileSize: 200
        maxFiles: 10
        profile: Default
      namedCertificates:
        - certPath: ""
          keyPath: ""
          names:
            - ""
      subjectAltNames: []
      tls:
        cipherSuites:
        minVersion: VersionTLS12
    debugging:
      logLevel: "Normal"
    dns:
      baseDomain: microshift.example.com
    etcd:
      memoryLimitMB: 0
    genericDevicePlugin:
        devices:
            - groups:
                - count: 1
                  paths:
                    - limit: 1
                      mountPath: /dev/ttyACM0
                      path: /dev/ttyACM0
                      permissions: mrw
                      readOnly: false
                      type: Device
                  usbs:
                    - product: ""
                      serial: ""
                      vendor: ""
              name: serial
        domain: device.microshift.io
        status: Disabled
    ingress:
      accessLogging:
        destination:
          type:
          container:
            maxLength: 1024
          syslog:
            address: ""
            facility: ""
            maxLength: 1024
            port: 0
            type: ""
        httpCaptureCookies:
          - matchType: ""
            maxLength: 0
            name: ""
            namePrefix: ""
        httpCaptureHeaders:
          request:
            - maxLength: 0
              name: ""
          response:
            - maxLength: 0
              name: ""
        httpLogFormat: ""
        status: Disabled
      certificateSecret: router-certs-default
      clientTLS:
        allowedSubjectPatterns:
        clientCA:
          name: ""
        clientCertificatePolicy: ""
      defaultHTTPVersion: 1
      forwardedHeaderPolicy: ""
      httpCompression:
        mimeTypes:
          - ""
      httpEmptyRequestsPolicy: Respond
      httpErrorCodePages:
          name: ""
      listenAddress: []
      logEmptyRequests: Log
      ports:
        http: 80
        https: 443
      routeAdmissionPolicy:
        namespaceOwnership: InterNamespaceAllowed
        wildcardPolicy: WildcardPolicyAllowed
      status: Managed
      tlsSecurityProfile:
        type: Intermediate
      tuningOptions:
          clientFinTimeout: "1s"
          clientTimeout: "30s"
          headerBufferBytes: 0
          headerBufferMaxRewriteBytes: 0
          healthCheckInterval: "5s"
          maxConnections: 0
          serverFinTimeout: "1s"
          serverTimeout: "30s"
          threadCount: 0
          tlsInspectDelay: "5s"
          tunnelTimeout: "1h"
    kubelet:
    manifests:
      kustomizePaths:
        - /usr/lib/microshift/manifests
        - /usr/lib/microshift/manifests.d/*
        - /etc/microshift/manifests
        - /etc/microshift/manifests.d/*
    network:
      clusterNetwork:
        - 10.42.0.0/16
      cniPlugin: ""
      multus:
        status: Disabled
      serviceNetwork:
        - 10.43.0.0/16
      serviceNodePortRange: 30000-32767
    node:
      hostnameOverride: ""
      nodeIP: ""
      nodeIPv6: ""
    storage:
      driver: ""
      optionalCsiComponents:
        - ""
    telemetry:
      endpoint: https://infogw.api.openshift.com
      proxy: ""
      status: Enabled

    where:

    apiserver.advertiseAddress

    Specifies the address of the service network.

    network.multus.status

    Specifies the status of the Multus Container Network Interface (CNI).

    node.nodeIP

    Specifies the IP address of the default route.

    storage.driver

    Specifies the storage driver to use. Default null value deploys Logical Volume Managed Storage (LVMS).

    storage.optionalCsiComponents

    Specifies the CSI components to deploy. Default null value deploys snapshot-controller.

Using custom settings

To create custom configurations, make a copy of the config.yaml.default file that is given in the /etc/microshift/ directory, renaming it config.yaml. Keep this file in the /etc/microshift/ directory, and then you can change supported settings that override the defaults before starting or restarting MicroShift.

If you have just a few changes to make to the default settings, consider using configuration drop-in snippets as an alternative method.

Important

Restart MicroShift after changing any configuration settings to have them take effect. The config.yaml file is read only when MicroShift starts.

Separate restarts

Applications and other optional services used with your MicroShift node might also need to be restarted separately to apply configuration changes throughout the node. For example, when making changes to certain networking settings, you must stop and restart service and application pods to apply those changes. See each procedure for the task you are completing for more information.

Tip

If you add all of the configurations you need at the same time, you can minimize system restarts.

Parameters and values for the MicroShift config.yaml file

The following table explains MicroShift configuration YAML parameters and valid values for each:

Table 14. MicroShift config.yaml parameters
Field Type Description

advertiseAddress

string

A string that specifies the IP address from which the API server is advertised to members of the node. The default value is calculated based on the address of the service network.

auditLog.maxFileAge

number

How long log files are stored before automatic deletion. The default value of 0 in the maxFileAge parameter means a log file is never deleted based on age. You can configure this value.

auditLog.maxFileSize

number

By default, when the audit.log file reaches the maxFileSize limit, the audit.log file is rotated and MicroShift begins writing to a new audit.log file. You can configure this value.

auditLog.maxFiles

number

The total number of log files kept. By default, MicroShift retains 10 log files. The oldest is deleted when an excess file is created. You can configure this value.

auditLog.profile

Default, WriteRequestBodies, AllRequestBodies, or None

Logs only metadata for read and write requests; does not log request bodies except for OAuth access token requests. If you do not specify this field, the Default profile is used.

namedCertificates

list

Defines externally generated certificates and domain names by using custom certificate authorities.

namedCertificates.certPath

path

The full path to the certificate.

namedCertificates.keyPath

path

The full path to the certificate key.

namedCertificates.names

list

Optional. Add a list of explicit DNS names. Leading wildcards are allowed. If you do not list names, the implicit names are extracted from the certificates.

subjectAltNames

Fully qualified domain names (FQDNs), wildcards such as *.domain.com, or IP addresses.

Subject Alternative Names for API server certificates. SANs indicate all of the domain names and IP addresses that are secured by a certificate.

tls

list

Defines the transport later protocol (TLS) used and the cipher suites allowed. Provides security for the exposed MicroShift API server and internal control plane endpoints.

tls.cipherSuites

string

Lists the allowed cipher suites that the API server accepts and serves. Defaults to the cipher suites allowed with the TLS specification set in the tls.minVersion parameter.

tls.minVersion

VersionTLS12 or VersionTLS13

Specifies the minimum version of TLS to serve from the API server. The default value is VersionTLS12.

debugging.logLevel

Normal, Debug, Trace, or TraceAll

Log verbosity. The default value is Normal.

dns.baseDomain

valid domain

Base domain of the node. All managed DNS records are subdomains of this base.

dns.hosts.status

Enabled, Disabled

Default set to Disabled when not configured.

dns.hosts.file

String

Filepath by default set to /etc/hosts.

etcd.memoryLimitMB

number

By default, etcd uses as much memory as needed to handle the load on the system. However, in memory constrained systems, it might be preferred or necessary to limit the amount of memory etcd can to use at a given time.

generic.Device.Plugin.devices

groups

Lists the device definitions to be exposed by the plugin. Each Device entry contains a 'name' and a list of groups.

generic.Device.Plugin.devices.groups

count, paths, 'usbs'

Lists device groups. Devices within a group comprise a pool of devices under a common name. When you request a device from that pool, you can receive a device from different defined paths.

generic.Device.Plugin.devices.groups.count

number

Specifies how many times this group of devices can be mounted concurrently. If unspecified, Count defaults to 1. Setting a high count, for example, 1000 for /dev/fuse, is possible because there are no inherent limits, but performance might be affected depending on the host capabilities and the nature of the device.

generic.Device.Plugin.devices.groups.paths

string

Lists the host device file paths. Paths can be glob patterns. For example, /dev/ttyUSB, in which case each matched device is schedulable Count times. This field is exclusive with usbs. You cannot define both parameters in the same device group.

generic.Device.Plugin.devices.groups.paths.limit

number

Specifies up to how many times this device can be used in the group concurrently when other devices in the group yield more matches. For example, if one path in the group matches 5 devices and another matches 1 device, but has a limit of 10, then the group provides 5 pairs of devices. When unspecified, the limit defaults to 1.

generic.Device.Plugin.devices.groups.paths.mountPath

string

The file path at which the host device should be mounted within the container. When unspecified, mountPath defaults to path.

generic.Device.Plugin.devices.groups.paths.path

string

The file path of a device on the host. For example, /dev/video0, /dev/ttyUSB*.

generic.Device.Plugin.devices.groups.paths.permissions

r, w, m

The file-system permissions given to the mounted device. Applies only to mounts of type Device. Can be one or more of:

  • r allows the container to read from the specified device.

  • w allows the container to write to the specified device.

  • m allows the container to create device files that do not yet exist.

When unspecified, the value defaults to mrw.

generic.Device.Plugin.devices.groups.paths.readOnly

true, false

Specifies whether the path should be mounted read-only. Applies only to mounts of type Mount.

generic.Device.Plugin.devices.groups.paths.type

Device, Mount

Describes what type of file-system node this path represents and thus how it should be mounted. When unspecified, type defaults to Device.

generic.Device.Plugin.devices.groups.usbs

string

Lists the USB specifications that this device group consists of. The vendor and product IDs must always match. The serial ID must match if provided, or skipped if the ID is empty. The usbs field is exclusive with paths.

generic.Device.Plugin.devices.groups.usbs.product

string

The USB Product ID of the device to match on. For example, 0x7523.

generic.Device.Plugin.devices.groups.usbs.serial

string

The serial number of the device to match on. A USB device must match exactly on all the given attributes to pass.

generic.Device.Plugin.devices.groups.usbs.vendor

string

The USB Vendor ID of the device to match on. For example, 0x1a86.

generic.Device.Plugin.devices.name

string

A unique string representing the kind of device this specification describes. For example, serial, video, or fuse. This name is used in pod resource requests. For example, device.microshift.io/serial.

generic.Device.Plugin.domain

string

Specifies the domain prefix with which devices are advertised and present in the node. For example, device.microshift.io/serial. The default value is device.microshift.io.

generic.Device.Plugin.status

Enabled, Disabled

Specifies the default GDP status.

ingress.certificateSecret

string

A reference to a secret that contains the default certificate that is served by the ingress controller. When routes do not specify their own certificate, certificateSecret is used.

The secret must contain the following keys and data:

  • tls.crt: certificate file contents

  • tls.key: key file contents

If you do not set one of these values, a wildcard certificate is automatically generated and used. The certificate is valid for the ingress controller domain and subdomains fields, and the generated CA for the certificate is automatically integrated with the truststore for the node.

Any certificate in use is automatically integrated in the MicroShift OAuth server.

ingress.clientTLS

AllowedSubjectPatterns, spec.clientTLS.ClientCA, spec.clientTLS.clientCertificatePolicy

Authenticates client access to the node and services. Mutual TLS authentication is enabled when using these settings. If you do not set values for the spec.clientTLS.clientCertificatePolicy and spec.clientTLS.ClientCA required subfields, client TLS is not enabled.

ingress.clientTLS.AllowedSubjectPatterns

list in PCRE syntax

Optional subfield which specifies a list of regular expressions that are matched against the distinguished name on a valid client certificate to filter requests. Use this parameter to cause the ingress controller to reject certificates based on the distinguished name. The Perl Compatible Regular Expressions (PCRE) syntax is required. If you configure this field, it must contain a valid expression or the MicroShift service fails. At least one pattern must match a client certificate’s distinguished name; otherwise, the ingress controller rejects the certificate and denies the connection.

ingress.clientTLS.ClientCA

string

Required subfield that specifies a config map in the openshift-ingress namespace. The config map must contain a CA certificate bundle.

ingress.clientTLS.ClientCertificatePolicy

Required, Optional

Required subfield that creates a secure route using reencrypt TLS termination with a custom certificate. You must have a certificate/key pair in PEM-encoded files, where the certificate is valid for the route host. The ingress controller only checks client certificates for edge-terminated and reencrypt TLS routes. Certificates for plain text HTTP or passthrough TLS routes are not checked with this setting.

ingress.defaultHTTPVersion

number

Determines the default HTTP version to be used for ingress. The default value is 1, which is the HTTP/1.1 protocol.

ingress.forwardedHeaderPolicy

Append, Replace, IfNone, Never

Specifies when and how the ingress controller sets the Forwarded, X-Forwarded-For, X-Forwarded-Host, X-Forwarded-Port, X-Forwarded-Proto, and X-Forwarded-Proto-Version HTTP headers. The default value is Append.

  • Append specifies that the ingress controller appends existing headers.

  • Replace specifies that the ingress controller sets the headers and replaces any existing Forwarded or X-Forwarded-* headers.

  • IfNone specifies that the ingress controller sets headers if they are not already set.

  • Never specifies that ingress controller never sets the headers, preserving any existing headers.

ingress.httpCompression

object

Defines a policy for HTTP traffic compression. There is no HTTP compression by default.

ingress.httpCompression.mimeTypes

array or null

A list of MIME types to compress. When the list is empty, the ingress controller does not apply any compression. To define a list, use the format of the Content-Type definition in RFC 1341 that specifies the type and subtype of data in the body of a message and the native encoding of the data. For example, Content-Type := type \"/\" subtype *[\";\" parameter].

  • The value of Content-Type can be one of the following types: application, audio, image, message, multipart, text, video, or a custom type preceded by \"X-\" and followed by a token. The token must be defined in one of the following ways:

  • The token is a string of at least one character, and does not contain white spaces, control characters, or any of the characters in the tspecials set.

  • The tspecials set contains the characters ()\u003c\u003e@,;:\\\"/[]?.=.

  • The subtype in Content-Type is also a token.

  • The optional parameters following the subtype are defined as token \"=\" (token / quoted-string).

  • The quoted-string, as defined in RFC 822, is surrounded by double quotes and can contain white spaces plus any character except \\, \", and CR. The quoted-string can also contain any single ASCII character if it is escaped by the following characters: \\.",.

Not all MIME types benefit from compression, but HAProxy uses resources to try to compress files when compression is configured. Generally speaking, text formats such as html, ccs, and js benefit from compression. Spending CPU resources to compress file types that are already compressed, such as images, audio, and video, is probably not worth the limited benefit.

ingress.httpEmptyRequestsPolicy

Respond or Ignore

The default value is Respond. Describes how HTTP connections should be handled if the connection times out before a request is received. These connections typically come from the health probes of a load balancer service or a web browser’s speculative connections, such as a preconnect.

  • If the field is set to Respond, the ingress controller sends an "HTTP 400" or "408" response, logs the connection if access logging is enabled, and counts the connection in the appropriate metrics.

  • If the field is set to Ignore, the ingress controller closes the connection without sending a response, logging the connection, or incrementing metrics. Setting this field to Ignore might impede detection and diagnosis of problems or intrusions, especially when timed-out connections are caused by network errors or port scans. In both cases, logging empty requests can be useful for diagnosing errors and detecting intrusion attempts.

ingress.listenAddress

IP address, NIC name, or multiple

Value defaults to the entire network of the host. The valid configurable value is a list that can be either a single IP address or NIC name or multiple IP addresses and NIC names.

ingress.logEmptyRequests

Log or Ignore

The default value is Log. Specifies how connections on which empty requests are received are logged. These connections typically come from the health probes of a load balancer service health or a web browser’s speculative connections, such as a preconnect. Logging typical requests might be undesirable, but requests can also be caused by network errors or port scans, in which case logging can be useful for diagnosing errors and detecting intrusion attempts.

ingress.ports.http

80

The default port shown. Configurable. Valid value is a single, unique port in the 1-65535 range. The values of the ports.http and ports.https fields cannot be the same.

ingress.ports.https

443

The default port shown. Configurable. Valid value is a single, unique port in the 1-65535 range. The values of the ports.http and ports.https fields cannot be the same.

ingress.routeAdmissionPolicy

namespaceOwnership or wildcardPolicy

Defines a policy for handling new route claims, such as allowing or denying claims across namespaces. By default, allows routes to claim different paths of the same hostname across namespaces.

ingress.routeAdmissionPolicy.namespaceOwnership

Strict or InterNamespaceAllowed

Describes how hostname claims across namespaces should be handled. The default value is InterNamespaceAllowed. Specifying Strict prevents routes in different namespaces from claiming the same hostname. If the value is deleted in a customized MicroShift config.yaml file, the InterNamespaceAllowed value is automatically set.

  • Strict: does not allow routes to claim the same hostname across namespaces.

  • InterNamespaceAllowed: allows routes to claim different paths of the same hostname across namespaces.

ingress.routeAdmissionPolicy.wildcardPolicy

WildcardsAllowed or WildcardsDisallowed

Describes how routes with wildcard policies are handled by the ingress controller.

  • WildcardsAllowed: Indicates routes with any wildcard policy are admitted by the ingress controller.

  • WildcardsDisallowed: Indicates only routes with a wildcard policy of None are admitted by the ingress controller. Updating wildcardPolicy from WildcardsAllowed to WildcardsDisallowed causes admitted routes with a wildcard policy of Subdomain to stop working. These routes must be recreated to a wildcard policy of None to be readmitted by the ingress controller. WildcardsDisallowed is the default setting.

ingress.status

Managed or Removed

Router status. The default is Managed.

ingress.tlsSecurityProfile

object

Specifies settings for ingress controllers TLS connections. If you do not set one, the default value is based on the apiservers.config.openshift.io/cluster resource.

ingress.tlsSecurityProfile.type

Old, Intermediate, Modern, Custom

Specifies the profile type for the TLS Security. The default value is Intermediate.

When using the Old, Intermediate, and Modern profile types, the effective profile configuration is subject to change between releases. For example, given a specification to use the Intermediate profile deployed on release X.Y.Z, an upgrade to release X.Y.Z+1 might cause a new profile configuration to be applied to the ingress controller, resulting in a rollout.

ingress.tlsSecurityProfile.minTLSVersion

number

Specifies the TLS version for ingress controllers.

The minimum TLS version is 1.1, and the maximum TLS version is 1.3.

  • Ciphers and the minimum TLS version of the configured security profile are reflected in the TLSProfile status.

  • The ingress controller converts the TLS 1.0 of an Old or Custom profile to 1.1.

ingress.tuningOptions

Objects

Specifies options for tuning the performance of ingress controller pods.

ingress.tuningOptions.clientFinTimeout

string with format duration

Defines how long a connection is held open while waiting for a client response to the server/backend before closing the connection. The default timeout is 1s, which is 1 second.

ingress.tuningOptions.clientTimeout

string with format duration

Defines how long a connection is held open while waiting for a client response. The default timeout is 30s, which is 30 seconds.

ingress.tuningOptions.headerBufferBytes

An integer with the format of int32; 16384 is the minimum value when HTTP/2 is enabled.

Describes how much memory in bytes must be reserved for IngressController connection sessions. The default value is 32768 in bytes.

  • Setting this field is generally not recommended because headerBufferBytes values that are too small can break the IngressController and headerBufferBytes values that are too large can cause the IngressController to use significantly more memory than necessary.

ingress.tuningOptions.headerBufferMaxRewriteBytes

integer, formatted int32; 4096 is the minimum value

Describes how much memory in bytes must be reserved from headerBufferBytes for HTTP header rewriting and appending for IngressController connection sessions. The default value is 8192 bytes. Incoming HTTP requests are limited to the headerBufferBytes bytes minus the headerBufferMaxRewriteBytes bytes, meaning that the value of headerBufferBytes must be greater than the value of headerBufferMaxRewriteBytes.

  • Setting this field is generally not recommended because headerBufferMaxRewriteBytes values that are too small can break the IngressController and headerBufferMaxRewriteBytes values that are too large can cause the IngressController to use significantly more memory than necessary.

ingress.tuningOptions.healthCheckInterval: ""

string with pattern: ^(0|((\\.[0-9])?(ns|us|µs|μs|ms|s|m|h))+)$

The default healthCheckInterval value is 5s, which is 5 seconds. This parameter value defines how long the router waits between two consecutive health checks on the router’s configured backends. The minimum allowed value is 1s and the maximum allowed value is 2147483647ms, which is 24.85 days.

  • This value is applied globally as a default for all routes, but can be overridden per-route by the route annotation router.openshift.io/haproxy.health.check.interval.

  • Requires an unsigned duration string of decimal numbers, each with an optional fraction and unit suffix, such as 300ms, 1.5h or 2h45m. Valid time units are ns, us (or µs U+00B5 or μs U+03BC), ms, s, m, h.

  • Setting this parameter value to less than 5s can cause excess traffic due to too frequent TCP health checks and accompanying SYN packet storms.

  • Setting this parameter value too high can result in increased latency because of backend servers that are no longer available, but have not yet been detected as such.

  • An empty or 0 value means "no opinion" and the ingress controller chooses a default. Note that the default value might change in future releases.

ingress.tuningOptions.maxConnections

integer, valid values are: empty, 0, -1, and the range 2000-2000000

The default value is 0. defines the maximum number of simultaneous connections that can be established per HAProxy process. Increasing this value allows each ingress controller pod to handle more connections at the cost of additional system resources being consumed.

  • If this field is empty or 0, the IngressController uses the default value of 50000, but the default is subject to change in future releases.

  • If the value is -1, then HAProxy dynamically computes a maximum value based on the available resources set with ulimit values in the running container. Selecting -1, which means auto, results in a large value being computed, and therefore each HAProxy process incurs significant memory usage compared with the current default of 50000.

  • Setting a value that is greater than the current operating system limit prevents the HAProxy process from starting.

  • You can monitor memory usage for router containers with the following metric:

    container_memory_working_set_bytes{container=`router`,namespace=`openshift-ingress`}`
  • You can monitor memory usage of individual `HAProxy`processes in router containers with the following metric:

    container_memory_working_set_bytes{container=`router`,namespace=`openshift-ingress`}/container_processes{container=`router`,namespace=`openshift-ingress`}

ingress.tuningOptions.serverFinTimeout

string in the format duration

Defines how long a connection is held open while waiting for a server or backend response to the client before closing the connection. The default timeout is 1s.

ingress.tuningOptions.serverTimeout

string in the format duration

Defines how long a connection is held open while waiting for a server or backend response. The default timeout is 30s.

ingress.tuningOptions.threadCount

integer in the form int32; minimum value is 1, maximum is 64

Defines the number of threads created per HAProxy process. The default value is 4. If this field is empty, the default value is used.

  • Setting this field is generally not recommended. Creating more threads allows each ingress controller pod to handle more connections at the cost of more system resources being used. Increasing the number of HAProxy threads allows the ingress controller pods to use more CPU time under load, potentially starving other pods if set too high. Conversely, reducing the number of threads may cause the ingress controller to perform poorly.

ingress.tuningOptions.tlsInspectDelay

string in the format duration

Defines how long the router can hold data to find a matching route. Setting this interval with too short a value can cause the router to revert to the default certificate for edge-terminated clients or re-encrypt routes, even when a better-matching certificate could be used.

  • The default inspect delay is 5s which is 5 seconds, which is expected to be sufficient for most cases. Increasing the value of this configuration specifically for high-latency networks can cause a delay in finishing the SSL handshake. Any configured value must be transparent to your application.

ingress.tuningOptions.tunnelTimeout

string in the format duration

Defines how long a tunnel connection, including websockets, are held open while the tunnel is idle. The default timeout is 1h, which is 1 hour.

kubelet

See the MicroShift low-latency instructions

Parameter for passthrough configuration of the kubelet node agent. Used for low-latency configuration. The default value is null.

manifests

list of paths

The locations on the file system to scan for kustomization files to use to load manifests. Set to a list of paths to scan only those paths. Set to an empty list to disable loading manifests. The entries in the list can be glob patterns to match multiple subdirectories. The default values are /usr/lib/microshift/manifests, /usr/lib/microshift/manifests.d/, /etc/microshift/manifests, and /etc/microshift/manifests.d/.

network.clusterNetwork

IP address block

A block of IP addresses from which pod IP addresses are allocated. IPv4 is the default network. Dual-stack entries are supported. The first entry in this field is immutable after MicroShift starts. The default range is 10.42.0.0/16.

network.cniPlugin

String

Deploys the Open Virtual Networking - Kubernetes (OVN-K) network plugin as the default container network interface (CNI) when empty or set to "ovnk". Supported values are empty, "" or "ovnk". Setting to "none" removes the CNI and is not recommended. Only OVN-K is managed by MicroShift.

network.multus.status

string

Controls the deployment of the Multus Container Network Interface (CNI). The default status is Disabled. If you set the value to Enabled, the Multus CNI cannot be deleted.

network.serviceNetwork

IP address block

A block of virtual IP addresses for Kubernetes services. IP address pool for services. IPv4 is the default. Dual-stack entries are supported. The first entry in this field is immutable after MicroShift starts. The default range is 10.43.0.0/16.

network.serviceNodePortRange

range

The port range allowed for Kubernetes services of type NodePort. If you do not specify the range, the default range of 30000-32767 is used. Services without a NodePort specified are automatically allocated one from this range. This parameter can be updated after MicroShift starts.

node.hostnameOverride

string

The name of the node. The default value is the hostname. If non-empty, this string is used to identify the node instead of the hostname. This value is immutable after MicroShift starts.

node.nodeIP

IPv4 address

The IPv4 address of the node. The default value is the IP address of the default route.

nodeIPv6

IPv6 address

The IPv6 address for the node for dual-stack configurations. Cannot be configured in single stack for either IPv4 or IPv6. The default is an empty value or null.

storage.driver

none or lvms

The default value is empty. An empty value or null field defaults to LVMS deployment.

storage.optionalCsiComponents

array

The default value is null or an empty array. A null or empty array defaults to deploying snapshot-controller. Expected values are csi-snapshot-controller or none. A value of none is mutually exclusive with all other values.

telemetry.endpoint

https://infogw.api.openshift.com

The endpoint where telemetry data is sent. No user or private data is included in the metrics reported. The default value is https://infogw.api.openshift.com.

telemetry.status

Enabled

Telemetry status, which can be Enabled or Disabled. The default value is Enabled.

Configure the advertise address network flag

The apiserver.advertiseAddress flag specifies the IP address on which to advertise the API server to members of the node. This address must be reachable by the node. You can set a custom IP address here, but you must also add the IP address to a host interface. Customizing this parameter preempts MicroShift from adding a default IP address to the br-ex network interface.

Important

If you customize the advertiseAddress IP address, make sure it is reachable by the node when MicroShift starts by adding the IP address to a host interface.

If unset, the default value is set to the next immediate subnet after the service network. For example, when the service network is 10.43.0.0/16, the advertiseAddress is set to 10.44.0.0/32.

Extending the port range for NodePort services

The serviceNodePortRange setting extends the port range available to NodePort services. This option is useful when specific standard ports under the 30000-32767 range need to be exposed. For example, if your device needs to expose the 1883/tcp MQ Telemetry Transport (MQTT) port on the network because client devices cannot use a different port.

Important

NodePorts can overlap with system ports, causing a malfunction of the system or MicroShift.

Consider the following when configuring the NodePort service ranges:

  • Do not create any NodePort service without an explicit nodePort selection. When an explicit nodePort is not specified, the port is assigned randomly by the kube-apiserver and cannot be predicted.

  • Do not create any NodePort service for any system service port, MicroShift port, or other services you expose on your device HostNetwork.

  • Table one specifies ports to avoid when extending the port range:

    Table 15. Ports to avoid.
    Port Description

    22/tcp

    SSH port

    80/tcp

    OpenShift Router HTTP endpoint

    443/tcp

    OpenShift Router HTTPS endpoint

    1936/tcp

    Metrics service for the openshift-router, not exposed today

    2379/tcp

    etcd port

    2380/tcp

    etcd port

    6443

    Kubernetes API

    8445/tcp

    openshift-route-controller-manager

    9537/tcp

    cri-o metrics

    10250/tcp

    kubelet

    10248/tcp

    kubelet healthz port

    10259/tcp

    kube scheduler

Configure custom hostnames

You can use the hosts file to resolve custom hostnames for pod workloads. This enables applications to resolve fixed hostnames, such as the local machine or external services, by applying /etc/hosts functionality to DNS queries within the node. The functionality is applied by adding specific configuration to the MicroShift configuration YAML file, and completing a service restart.

Prerequisites
  • You installed the OpenShift CLI (oc).

  • You have root access to the node.

Procedure
  1. Edit the MicroShift configuration in the /etc/microshift/config.yaml file.

  2. Add the following hosts configuration at the end of the file:

    dns:
     hosts:
       status: <Enabled|Disabled>
       file: <filepath>
  3. Save your configuration YAML file.

  4. Restart the MicroShift service to activate the configuration changes:

    $ sudo systemctl restart microshift

    After this initial restart, if dns.hosts.status is set to Enabled, MicroShift automatically monitors the dns.hosts.file file for updates. You do not have to restart the MicroShift service until the MicroShift configuration YAML file is changed again.

    Note

    After you save the /etc/hosts file, it takes up to 90 seconds for the change to be active in the pods. During this period, the pods might not properly resolve hostnames.

How configuration snippets work

Configuration snippets in {product-title} are YAML files in /etc/microshift/config.d/ that merge with the existing configuration at runtime. You can use them to change one or two settings without editing the main config file.

You must restart MicroShift for new configurations to apply.

To return to previous values, you can delete a configuration snippet and restart MicroShift.

At runtime, the YAML files inside /etc/microshift/config.d are merged into the existing MicroShift configuration, whether that configuration is a result of default values or a user-created config.yaml file. You do not need to create a config.yaml file to use a configuration snippet.

Files in the snippet directory are sorted in lexicographical order and run sequentially. You can use numerical prefixes for snippets so that each is read in the order you want. The last-read file takes precedence when there is more than one YAML for the same parameter.

Important

Configuration snippets take precedence over both default values and a customized config.yaml configuration file.

Examples of configuration snippet lists or arrays

Lists and arrays in {product-title} configuration snippets are overwritten, not merged.

For example, you can replace a SAN or list of SANs by creating an additional snippet for the same field that is read after the first:

MicroShift configuration directory contents

/etc/microshift/config.yaml.default or /etc/microshift/config.yaml

Example MicroShift configuration snippet directory contents

/etc/microshift/config.d/10-san.yaml and /etc/microshift/config.d/20-san.yaml

Example 10-san.yaml snippet
apiServer:
  subjectAltNames:
    - host1
    - host2
Example 20-san.yaml snippet
apiServer:
  subjectAltNames:
    - hostZ
Example configuration result
apiServer:
  subjectAltNames:
    - hostZ

If you want to add a value to an existing list, you can add it to an existing snippet. For example, to add hostZ to an existing list of SANs, edit the snippet you have instead of creating a new one:

Example 10-san.yaml snippet
apiServer:
  subjectAltNames:
    - host1
    - host2
    - hostZ
Example configuration result
apiServer:
  subjectAltNames:
    - host1
    - host2
    - hostZ

Example configuration snippets that are objects

Object fields in {product-title} are merged together when you use a configuration snippet.

Example 10-advertiseAddress.yaml snippet
apiServer:
  advertiseAddress: "microshift-example"
Example 20-audit-log.yaml snippet
apiServer:
  auditLog:
    maxFileAge: 12
Example configuration result
apiServer:
  advertiseAddress: "microshift-example"
  auditLog:
    maxFileAge: 12

Examples of mixed configuration snippets

When you use mixed configuration snippets in {product-title}, object fields merge and the last-read snippet replaces list values. File order controls which list entries apply.

In the following example, the values of both advertiseAddress and auditLog.maxFileAge fields merge into the configuration, but only the c.com and d.com subjectAltNames values are retained. This happens because the numbering in the filename indicates that the c.com and d.com values are higher priority.

Example 10-advertiseAddress.yaml snippet
apiServer:
  advertiseAddress: "microshift-example"
Example 20-audit-log.yaml snippet
apiServer:
  auditLog:
    maxFileAge: 12
Example 30-SAN.yaml snippet
apiServer:
  subjectAltNames:
    - a.com
    - b.com
Example 40-SAN.yaml snippet
apiServer:
  subjectAltNames:
    - c.com
    - d.com
Example configuration result
apiServer:
  advertiseAddress: "microshift-example"
  auditLog:
    maxFileAge: 12
  subjectAltNames:
    - c.com
    - d.com

Configure networking for a fully disconnected host

When MicroShift runs on a host with no external network connectivity, you must configure networking so that the node can resolve container image references and reach cluster-internal services. This includes configuring the OVN-Kubernetes network plugin for disconnected operation and, if needed, reverting network configuration changes.

Preparing networking for fully disconnected hosts

To run MicroShift on a fully disconnected host with no external network connectivity, you prepare a persistent hostname, loopback IP addressing, DNS, and /etc/hosts entries before you apply MicroShift network configuration.

Typically this means that the device does not have an attached network interface controller (NIC) to provide a subnet. These steps can also be completed on a host with a NIC that is removed after setup. You can also automate these steps on a host that does not have a NIC by using the %post phase of a Kickstart file.

Important

Configuring networking settings for disconnected environments is necessary because MicroShift requires a network device to support node communication. To meet this requirement, you must configure MicroShift networking settings to use the "fake" IP address you assign to the system loopback device during setup.

Procedure summary

To run MicroShift on a disconnected host, the following steps are required:

Prepare the host
  • Stop MicroShift if it is currently running and clean up changes the service has made to the network.

  • Set a persistent hostname.

  • Add a “fake” IP address on the loopback interface.

  • Configure DNS to use the fake IP as local name server.

  • Add an entry for the hostname to /etc/hosts.

Update the MicroShift configuration
  • Define the nodeIP parameter as the new loopback IP address.

  • Set the .node.hostnameOverride parameter to the persistent hostname.

For the changes to take effect
  • Disable the default NIC if attached.

  • Restart the host or device.

After starting, MicroShift runs using the loopback device for intra-node communication.

Configuring the networking settings for fully disconnected hosts

To configure the networking settings for running MicroShift on a fully disconnected host, you must prepare the host, update the networking configuration, then restart to apply the new settings. All commands are executed from the host CLI.

Prerequisites
  • RHEL 9 or newer.

  • MicroShift 4.16 or newer.

  • Access to the host CLI.

  • A valid IP address chosen to avoid both internal and potential future external IP conflicts when running MicroShift.

  • MicroShift networking settings are set to defaults.

Important

The following procedure is for use cases in which access to the MicroShift node is not required after devices are deployed in the field. There is no remote node access after the network connection is removed.

Procedure
  1. Add a fake IP address to the loopback interface by running the following command:

    $ IP="10.44.0.1"

    The fake IP address used in this example is "10.44.0.1".

    $ sudo nmcli con add type loopback con-name stable-microshift ifname lo ip4 ${IP}/32
    Note

    Any valid IP works if it avoids both internal MicroShift and potential future external IP conflicts. This can be any subnet that does not collide with the MicroShift node subnet or is be accessed by other services on the device.

  2. Configure the DNS interface to use the local name server by setting modifying the settings to ignore automatic DNS and reset it to the local name server:

    1. Bypass the automatic DNS by running the following command:

      $ sudo nmcli conn modify stable-microshift ipv4.ignore-auto-dns yes
    2. Point the DNS interface to use the local name server:

      $ sudo nmcli conn modify stable-microshift ipv4.dns "10.44.1.1"
  3. Get the hostname of the device by running the following command:

    $ NAME="$(hostnamectl hostname)"
  4. Add an entry for the hostname of the node in the /etc/hosts file by running the following command:

    $ echo "$IP $NAME" | sudo tee -a /etc/hosts >/dev/null
  5. Update the MicroShift configuration file by adding the following YAML snippet to /etc/microshift/config.yaml:

    sudo tee /etc/microshift/config.yaml > /dev/null <<EOF
    node:
      hostnameOverride: $(echo $NAME)
      nodeIP: $(echo $IP)
    EOF
  6. MicroShift is now ready to use the loopback device for intra-node communications. Finish preparing the device for offline use.

    1. If the device currently has a NIC attached, disconnect the device from the network.

    2. Shut down the device and disconnect the NIC.

    3. Restart the device for the offline configuration to take effect.

  7. Restart the MicroShift host to apply the configuration changes by running the following command:

    $ sudo systemctl reboot

    This step restarts the node. Wait for the greenboot health check to report the system healthy before implementing verification.

Verification

At this point, network access to the MicroShift host has been severed. If you have access to the host terminal, you can use the host CLI to verify that the node has started in a stable state.

  1. Verify that the MicroShift node is running by entering the following commands:

    $ export KUBECONFIG=/var/lib/microshift/resources/kubeadmin/kubeconfig
    $ sudo -E oc get pods -A
    Example output
    NAMESPACE                  NAME                                       READY   STATUS    RESTARTS      AGE
    kube-system                csi-snapshot-controller-74d566564f-66n2f   1/1     Running   0             1m
    openshift-dns              dns-default-dxglm                          2/2     Running   0             1m
    openshift-dns              node-resolver-dbf5v                        1/1     Running   0             1m
    openshift-ingress          router-default-8575d888d8-xmq9p            1/1     Running   0             1m
    openshift-ovn-kubernetes   ovnkube-master-gcsx8                       4/4     Running   1             1m
    openshift-ovn-kubernetes   ovnkube-node-757mf                         1/1     Running   1             1m
    openshift-service-ca       service-ca-7d7c579f54-68jt4                1/1     Running   0             1m
    openshift-storage          topolvm-controller-6d777f795b-bx22r        5/5     Running   0             1m
    openshift-storage          topolvm-node-fcf8l                         4/4     Running   0             1m

Restoring MicroShift networking settings to default

To remove networking customizations and return the network to default settings, stop MicroShift and run a clean-up script.

Prerequisites
  • RHEL 9 or newer.

  • MicroShift 4.14 or newer.

  • Access to the host CLI.

Procedure
  1. Stop the MicroShift service by running the following command:

    $ sudo systemctl stop microshift
  2. Stop the kubepods.slice systemd unit by running the following command:

    $ sudo systemctl stop kubepods.slice
  3. MicroShift installs a helper script to undo network changes made by OVN-K. Run the cleanup script by entering the following command:

    $ sudo /usr/bin/microshift-cleanup-data --ovn