Openshift

Run MicroShift on Fedora 45 / 44: Red Hat’s Edge OpenShift

MicroShift is Red Hat’s single-node OpenShift for edge devices, and the Fedora instructions most guides still give will install a four-year-old build. The @redhat-et/microshift COPR keeps adding chroots for every new Fedora release, but its last real build is MicroShift 4.8 from April 2022. On Fedora 45 the install reported Transaction failed, yet left that 2022 build installed, and it started when asked. The current route on Fedora is the upstream MicroShift project’s RPMs, which run Kubernetes on OKD images in about a minute, and then break on the first reboot unless you undo one change their installer makes.

Original content from computingforgeeks.com - post 15744

We tested in October 2026 on Fedora 45 and Fedora 44 Cloud images in VMs with 4 vCPUs and 4 GB of RAM, using upstream MicroShift 4.22 (Kubernetes v1.35.8) and the 4.20 release (Kubernetes v1.33.6). Red Hat’s supported build on RHEL needs a MicroShift subscription; we cover what changes there but did not run it.

Understand what MicroShift is

MicroShift runs the OpenShift and Kubernetes control plane in one microshift process next to CRI-O, and deploys the OpenShift router, DNS and service CA as pods. You get OpenShift APIs such as Routes and Security Context Constraints without the operators, console and multi-node machinery of a full cluster. That trade is the whole point: it runs where OpenShift can’t, on a small box that has to boot unattended.

BuildWhere it runsImagesSupport
Red Hat build of MicroShiftRHEL 9.8 (4.22); RHEL 10.2 as Technology PreviewOpenShift, needs a pull secretMicroShift subscription
Upstream MicroShift (microshift-io)Fedora, CentOS Stream 9 and 10, UbuntuOKD, no pull secretCommunity
@redhat-et/microshift COPRLists Fedora 43 to rawhideLast build 4.8 (2022)None, abandoned

On Fedora, use the upstream build, and know what it is. Its README describes it as intended for upstream development and testing, built from MicroShift’s sources with OKD images in place of Red Hat’s. On Fedora it uses the Kindnet CNI rather than OVN-Kubernetes, which the project only supports on CentOS. If you need the supported product, plan on RHEL 9.8 rather than RHEL 10, because Red Hat’s own compatibility matrix lists MicroShift 4.22 on RHEL 10.2 as Technology Preview. For lighter Kubernetes without OpenShift APIs, compare it with the options in our k0s, k3s and MicroK8s comparison.

Skip the old Fedora COPR

We ran the COPR install that older guides give, on a fresh Fedora 45 VM, to see what a reader gets today. It resolved and installed, then the package scriptlet failed.

[15/16] Installing microshift-0:4.8.0-2 100% | 394.1 MiB/s | 144.2 MiB |  00m00s
>>> Running %post scriptlet: microshift-0:4.8.0-2022_04_20_141053.fc37.x86_64
>>> Non-critical error in %post scriptlet: microshift-0:4.8.0-2022_04_20_141053.fc37.x86_64
>>> [RPM] %post(microshift-4.8.0-2022_04_20_141053.fc37.x86_64) scriptlet failed, exit status 3
[16/16] Installing runc-2:1.5.2-3.fc45. 100% |   4.8 MiB/s |   9.6 MiB |  00m02s
Transaction failed: Rpm transaction failed.

Despite the failure, rpm -q microshift reported the 4.8 build installed and the service started when we asked it to. That makes it worse than a clean failure, because a reader sees a running cluster and does not notice it is four years behind on Kubernetes and security fixes. If you followed those steps before, remove it before anything else.

sudo systemctl stop microshift
sudo dnf remove -y microshift microshift-selinux cri-o cri-tools1.37
sudo dnf copr disable -y @redhat-et/microshift
sudo dnf copr remove -y @redhat-et/microshift
sudo rm -rf /var/lib/microshift

Install upstream MicroShift on Fedora

Upstream MicroShift publishes RPMs on its GitHub releases page and an install script that does the rest. Download the script and read it before you run it as root. It is short, and you’ll need to know what it changes later.

curl -fsSL -o quickrpm.sh https://microshift-io.github.io/microshift/quickrpm.sh
less quickrpm.sh

On Fedora the script and its post-install step change more than the package list suggests:

  • Install microshift, microshift-kindnet and microshift-topolvm from a temporary local repo, without weak dependencies
  • Pull CRI-O and openshift-clients from OpenShift’s el9 mirror, then delete that repo file
  • Create a 1 GB loop-file volume group, myvg1, re-attached by a systemd drop-in on every start
  • Download the CNI plugins tarball from GitHub into /usr/libexec/cni
  • Install firewalld and write rules offline, without starting it
  • Disable openvswitch and systemd-resolved, and write /etc/sysctl.d/99-microshift.conf

The firewall and resolver changes do nothing until the next reboot, and both cause trouble then, so the section after the install undoes or adjusts them. Two more things to know before you run it. The RPMs install without signature checks, and dnf says so: Warning: skipped OpenPGP checks for 8 packages from repositories: microshift-local, openshift-mirror-beta. And from the next boot, firewalld allows only SSH on port 22, mDNS, DHCPv6 and the cluster ports, so anything else already listening on the machine, including SSH on a custom port, is cut off. Run the script.

sudo bash quickrpm.sh

It took 1 minute 11 seconds on a fresh Fedora 45 VM and 1 minute 13 seconds on Fedora 44, installing 29 packages, then 9 more for firewalld and its dependencies, and ended with this summary.

MicroShift is running on the host
LVM disk:  /var/lib/microshift-okd/lvmdisk.image
VG name:   myvg1

To verify that MicroShift pods are up and running, run the following command:
 - sudo kubectl get pods -A --kubeconfig /var/lib/microshift/resources/kubeadmin/kubeconfig

To uninstall MicroShift, run the following command:
 - curl -s https://microshift-io.github.io/microshift/quickclean.sh | sudo bash

Every MicroShift package is an el9 build, and so are CRI-O and openshift-clients, which came from the OpenShift mirror rather than Fedora. Because the script deletes that mirror’s repo file once it finishes, those packages get no updates from any repository afterwards; updating means running the script again.

microshift-4.22.0_202610071017_g0a516b4eb_4.22.0_okd_scos.ec.16-1.el9.x86_64
microshift-kindnet-4.22.0_202610071017_g0a516b4eb_4.22.0_okd_scos.ec.16-1.el9.x86_64
microshift-topolvm-4.22.0_202610071017_g0a516b4eb_4.22.0_okd_scos.ec.16-1.el9.x86_64
cri-o-1.35.9-12.rhaos4.22.git4c168db.el9.x86_64
openshift-clients-4.22.0-202609170632.p2.gd0f23b1.assembly.stream.el9.x86_64

Pin a release tag

Look at the version string: ec.16 marks an engineering candidate build of 4.22, and that is what the project’s latest release tag pointed at. For a box you want to keep stable, pin the newest release without the ec suffix instead, by passing it in the TAG variable. Keep the project’s own caveat in mind, though: even the 4.20 tag reported a nightly OpenShift base (Base OCP Version: 4.20.0-0.nightly-2025-12-25-211554), so pinning buys you repeatability, not a supported release.

# pin: https://github.com/microshift-io/microshift/releases
sudo TAG=4.20.0_g153ff0ca9_4.20.0_okd_scos.16 bash quickrpm.sh

On Fedora 44 the pinned install took 1 minute 28 seconds and brought up Kubernetes v1.33.6 with CRI-O 1.33, and all ten system pods were running within five minutes. Check the releases page for the newest tag before you copy that one.

Check the cluster

Copy the kubeconfig MicroShift generates into your own account so you can run oc without sudo. Our kubectl cheat sheet covers the everyday commands, and oc accepts the same ones.

mkdir -p ~/.kube
sudo cat /var/lib/microshift/resources/kubeadmin/kubeconfig > ~/.kube/config
chmod 600 ~/.kube/config
oc get nodes

The node reported NotReady at first and Ready two to three minutes after the service started. Give it that long before you start debugging.

NAME     STATUS   ROLES                         AGE    VERSION
edge03   Ready    control-plane,master,worker   3m5s   v1.35.8

System pods cover DNS, ingress, the service CA, Kindnet, kube-proxy and TopoLVM. Here is the pinned 4.20 node once it had settled; yours should look like this, with nothing in Pending or ContainerCreating.

NAMESPACE              NAME                                       READY   STATUS    RESTARTS   AGE
kube-kindnet           kube-kindnet-ds-jjp97                      1/1     Running   0          4m50s
kube-proxy             kube-proxy-dvjkj                           1/1     Running   0          4m49s
kube-system            csi-snapshot-controller-848495b6bb-24pnz   1/1     Running   0          4m57s
openshift-dns          dns-default-bp77b                          2/2     Running   0          4m59s
openshift-dns          node-resolver-zbr75                        1/1     Running   0          5m
openshift-ingress      router-default-6dfbc68898-lr988            1/1     Running   0          4m57s
openshift-service-ca   service-ca-748fdc966d-dkt2j                1/1     Running   0          4m57s
topolvm-system         topolvm-controller-8556c57b9d-m6ldz        5/5     Running   0          4m48s
topolvm-system         topolvm-lvmd-0-7pgqq                       1/1     Running   0          4m48s
topolvm-system         topolvm-node-84zvn                         3/3     Running   0          4m48s

Its footprint is small enough for real edge hardware. On the 4 GB Fedora 45 VM with a demo app running, the microshift process used 495 MiB and CRI-O 93 MiB, and the whole machine had 1.3 GB in use. On disk, the fresh node’s root filesystem held 2.9 GB in total, with 1.9 GB of that in container storage, so Red Hat’s minimum of 2 cores, 2 GB of RAM and 10 GB of storage plus your workloads leaves real room. Expect some restarts on a box this small: the TopoLVM controller’s sidecars restart whenever they log leader election lost, and on our 4 GB Fedora 45 node they kept doing so intermittently, 28 restarts across five containers in about an hour, without the cluster leaving Ready. Give a node that will carry real workloads more memory than the minimum.

Fix DNS and the firewall before the first reboot

Everything above works until the machine restarts. When we rebooted after a plain install, the Fedora 45 node’s pods stayed in ContainerCreating, and three of the Fedora 44 node’s did too. The installer had disabled systemd-resolved, and Fedora’s /etc/resolv.conf is a symlink into the resolver’s runtime directory, so after the reboot it pointed at nothing.

active inactive active
lrwxrwxrwx. 1 root root 39 Sep 23 17:43 /etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf
cat: /etc/resolv.conf: No such file or directory

Read the first line as firewalld, systemd-resolved and MicroShift. The pod events named the problem directly: Failed to create pod sandbox: open /etc/resolv.conf: no such file or directory. The host had no DNS either, so image pulls would have failed next. The upstream script disables the resolver for its bootc container images, where it gets in the way of host name resolution; on a normal Fedora host you want it back.

Re-enable it and restart MicroShift right after the install. The restart matters: MicroShift writes the kubelet configuration each time it starts, and only points pods at the resolver’s upstream list, /run/systemd/resolve/resolv.conf, when systemd-resolved is running at that moment. In the same step, open HTTP and HTTPS for the router. firewalld is installed but not running yet, so use firewall-offline-cmd, the same tool the installer used:

systemctl is-enabled firewalld
systemctl is-active firewalld
sudo systemctl enable --now systemd-resolved
sudo systemctl restart microshift
sudo firewall-offline-cmd --zone=public --add-service=http --add-service=https
sudo firewall-offline-cmd --zone=public --list-services

On our fresh Fedora 45 VM, firewalld reported enabled and inactive, which is the state the offline tool is for, and the public zone then listed HTTP and HTTPS.

enabled
inactive
Created symlink '/etc/systemd/system/sockets.target.wants/systemd-resolved-monitor.socket' → '/usr/lib/systemd/system/systemd-resolved-monitor.socket'.
success
dhcpv6-client http https mdns ssh

We tested Fedora Cloud images, where firewalld is not installed beforehand. On a host where firewalld is already running, such as Fedora Server or Workstation, the offline tool is the wrong one, because it is only meant for a stopped daemon. Check which zone your interface uses with sudo firewall-cmd --get-active-zones, since those editions default to their own zones rather than public, add the services there with sudo firewall-cmd --permanent, and run sudo firewall-cmd --reload, which is also what activates the rules the installer wrote offline. We did not test those editions. Before the first reboot the resolver is still running, so the restart is a safeguard there; it is what actually fixes a node you are recovering after it already rebooted. That was the trap we fell into first: enabling the resolver while MicroShift kept running left the pods on the old configuration, and CoreDNS could not reach the host’s stub resolver from inside the pod network.

[ERROR] plugin/errors: 2 quay.io. A: read udp 127.0.0.1:43382->127.0.0.53:53: read: connection refused
[ERROR] plugin/errors: 2 quay.io. AAAA: read udp 127.0.0.1:44743->127.0.0.53:53: read: connection refused
[ERROR] plugin/errors: 2 quay.io. A: read udp 127.0.0.1:60366->127.0.0.53:53: read: connection refused

If you’d rather keep the resolver disabled, pointing /etc/resolv.conf at NetworkManager’s list of real servers also survived a reboot on both releases: sudo ln -sf ../run/NetworkManager/no-stub-resolv.conf /etc/resolv.conf. We recommend re-enabling systemd-resolved because it leaves Fedora’s default resolver setup intact.

Reboot and confirm the fix holds

Reboot now, while it’s convenient, rather than finding out during an outage. After sudo systemctl reboot and two minutes for MicroShift to start, check the resolver, the services, the firewall and the kubelet’s DNS setting:

ls -l /etc/resolv.conf | cut -c40-
getent hosts quay.io >/dev/null && echo "DNS ok"
systemctl is-active firewalld systemd-resolved microshift | paste -sd" "
sudo firewall-cmd --zone=public --list-services
oc get pods -A | grep -vc " Running "
sudo grep -rh resolvConf /var/lib/microshift/resources/kubelet/config/ | head -1

Every line came back healthy. The 1 is the header line of oc get pods, meaning no pod was in any state other than Running:

 /etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf
DNS ok
active active active
dhcpv6-client http https mdns ssh
1
resolvConf: "/run/systemd/resolve/resolv.conf"

Then decide what else the LAN should reach. The installer opened 6443 for the API server plus 2379 and 2380 for etcd, which it opens because multi-node setups need them. A single node does not, and closing them left our cluster Ready with routes still answering. Keep 6443 only if you run oc from another machine, since anyone holding the kubeconfig can manage the cluster.

sudo firewall-cmd --permanent --zone=public --remove-port=2379/tcp --remove-port=2380/tcp
sudo firewall-cmd --reload
sudo firewall-cmd --zone=public --list-ports

Deploy an app and expose it with a Route

MicroShift includes the OpenShift router, so an app gets a hostname without an ingress controller of your own. Create a namespace, a deployment from the UBI Apache image and a Route.

oc create namespace demo
oc -n demo create deployment hello --image=registry.access.redhat.com/ubi9/httpd-24 --port=8080
oc -n demo rollout status deployment/hello --timeout=180s
oc -n demo expose deployment/hello --port=8080
oc -n demo expose service/hello --hostname=hello.edge01.example.com
oc -n demo get route,pods -o wide

Once the router picks it up, the Route shows as admitted.

NAME                             HOST                       ADMITTED   SERVICE   TLS
route.route.openshift.io/hello   hello.edge01.example.com   True       hello     

Test it from another machine with the hostname in the Host header, or add the name to DNS. The router listens on the node’s address, not on loopback: our curl to 127.0.0.1 on the node itself got no answer, while the same request from the LAN worked. Replace the address with your node’s IP.

curl -s -H "Host: hello.edge01.example.com" http://10.0.1.170/ | grep -o "<title>[^<]*"

The response was Apache’s test page, which the UBI image serves with HTTP 403 while its document root has no index page. A 403 here means routing works; a connection refused means HTTP is still closed in the firewall.

<title>Test Page for the HTTP Server on Red Hat Enterprise Linux

Add persistent storage with TopoLVM

Upstream’s install makes topolvm-provisioner the default storage class, backed by the 1 GB myvg1 volume group on a loop file. That is enough to test with; for real data, give MicroShift a proper disk or partition for the volume group. Our new demo namespace carried pod-security.kubernetes.io/enforce: restricted labels. The hello Deployment ran there without any security settings, but a bare Pod we created directly was rejected with violates PodSecurity "restricted:latest": allowPrivilegeEscalation != false. Save this as pvc.yaml, which includes the settings the profile requires.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data
  namespace: demo
spec:
  accessModes: [ReadWriteOnce]
  resources:
    requests:
      storage: 256Mi
---
apiVersion: v1
kind: Pod
metadata:
  name: writer
  namespace: demo
spec:
  containers:
    - name: writer
      image: registry.access.redhat.com/ubi9/ubi-minimal
      command: ["sh", "-c", "date > /data/stamp && cat /data/stamp && sleep 3600"]
      securityContext:
        allowPrivilegeEscalation: false
        runAsNonRoot: true
        capabilities:
          drop: ["ALL"]
        seccompProfile:
          type: RuntimeDefault
      volumeMounts:
        - name: data
          mountPath: /data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: data

Apply it and check that the claim binds and the pod can write.

oc apply -f pvc.yaml
oc -n demo wait --for=condition=Ready pod/writer --timeout=180s
oc -n demo get pvc data
oc -n demo logs writer
sudo lvs myvg1

TopoLVM created a logical volume in myvg1, rounding the 256Mi request up to 300Mi.

NAME   STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          VOLUMEATTRIBUTESCLASS   AGE
data   Bound    pvc-99aef795-4105-4a5f-a7cf-10d0eecc5a3c   300Mi      RWO            topolvm-provisioner   <unset>                 22s
Sat Oct 17 00:17:11 UTC 2026
  LV                                   VG    Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  fe0fd084-54ce-4d16-ad44-def790115a72 myvg1 -wi-ao---- 300.00m                                                    

With a 1 GB volume group, three claims like this use most of it. The WaitForFirstConsumer binding mode also means a claim stays Pending until a pod uses it, which is normal rather than a sign of trouble.

Run Red Hat’s MicroShift on RHEL instead

Red Hat’s supported product installs from its own repositories and differs from the upstream build in three ways you’ll notice:

  • An active MicroShift subscription and the rhocp repositories
  • A pull secret in /etc/crio/openshift-pull-secret
  • Storage from an LVM volume group you leave free when you install RHEL

Red Hat’s install guide for 4.22 enables rhocp-4.22-for-rhel-9-$(uname -m)-rpms and fast-datapath-for-rhel-9-$(uname -m)-rpms, locks the host with sudo subscription-manager release --set=9.8 and then runs sudo dnf install -y microshift. Commands that enable rhocp repositories for RHEL 10 with an older MicroShift version, as some guides show, do not match any supported combination in the compatibility matrix. Follow the Red Hat build of MicroShift documentation for the full steps; we didn’t have a MicroShift subscription to test them. The resolver problem above comes from the upstream post-install script, which Red Hat’s install procedure does not use.

Uninstall MicroShift

Upstream ships a matching clean-up script. Download and run it the same way as the installer.

curl -fsSL -o quickclean.sh https://microshift-io.github.io/microshift/quickclean.sh
sudo bash quickclean.sh

It took 18 seconds and removed the packages, /var/lib/microshift, the myvg1 volume group, the sysctl file and root’s kubeconfig link. It left the rest of the post-install changes in place. Afterwards our Fedora 44 machine still had systemd-resolved disabled, firewalld enabled and the pod network listed as a trusted source. Its /etc/resolv.conf link still pointed at the NetworkManager file from our earlier workaround.

disabled enabled
 /etc/resolv.conf -> ../run/NetworkManager/no-stub-resolv.conf
firewalld-2.4.4-1.fc44.noarch
package containernetworking-plugins is not installed
10.42.0.0/16 169.254.169.1

The containernetworking-plugins line explains a leftover you won’t see in the package list: because Fedora’s package was absent, the installer unpacked the CNI plugins from GitHub into /usr/libexec/cni, and the clean-up script leaves those files, along with your own ~/.kube/config. To take the firewall back to its earlier state, remove the trusted sources and the cluster ports:

sudo firewall-cmd --permanent --zone=trusted --remove-source=10.42.0.0/16 --remove-source=169.254.169.1
sudo firewall-cmd --permanent --zone=public --remove-port=6443/tcp --remove-port=2379/tcp --remove-port=2380/tcp
sudo firewall-cmd --reload

Afterwards both lists came back empty. Re-enable the resolver with sudo systemctl enable --now systemd-resolved if you disabled it, and remove firewalld if the machine didn’t use it before. On a dedicated edge box you can leave all of this in place; none of it matters without MicroShift.

If you want the OpenShift console and operators on a developer laptop rather than an edge runtime, OpenShift Local (CRC) on Fedora is the better fit for you. For a multi-node cluster, see our guide to an OKD cluster on Fedora CoreOS. If the edge device itself should be image based, the upstream project also publishes bootc container images, the same model Fedora CoreOS uses for its own updates.

Keep reading

Best UI Applications for Managing Docker Containers Containers Best UI Applications for Managing Docker Containers Install Docker and Run Containers on Ubuntu 24.04|22.04 Containers Install Docker and Run Containers on Ubuntu 24.04|22.04 Install UniFi OS Server on Ubuntu 24.04 LTS Containers Install UniFi OS Server on Ubuntu 24.04 LTS CapRover Docker Install on Debian 13: Deploy Your First App Containers CapRover Docker Install on Debian 13: Deploy Your First App Best OpenShift Books for Admins and EX280 Candidates Books Best OpenShift Books for Admins and EX280 Candidates AWS Costs Explained: What Actually Charges You (April 2026) AWS AWS Costs Explained: What Actually Charges You (April 2026)

Leave a Comment

Press ESC to close