MicroShift 4.19 Installation Guide on Hetzner (x86_64)

This guide explains how to install and configure MicroShift 4.19 on a Hetzner Cloud server running AlmaLinux 9.5. It includes system setup, container runtime configuration, networking, TLS setup with Certbot, and sample application deployments.


🖥️ 1. Server & System Preparation

1.1 System Details

Verify that you’re running on the correct architecture and OS version.

uname -m && cat /etc/os-release

Expected output:

x86_64
NAME="AlmaLinux"
VERSION="9.5 (Teal Serval)"
...

✅ Confirms your server is running AlmaLinux 9.5 on x86_64, which is required for MicroShift 4.19.


1.2 Cgroups and Kernel Settings

Check if cgroup2 is mounted and required subsystems are enabled.

mount | grep cgroup2
cat /proc/cgroups

🛠️ cgroup2 must be active. Ensure memory and cpuset controllers are listed. If not, you may need to append systemd.unified_cgroup_hierarchy=1 to the GRUB kernel parameters and reboot.


1.3 Disable Swap

Disable swap immediately and permanently.

swapoff -a
sed -i.bak '/swap/d' /etc/fstab

⚠️ Kubernetes-based systems require swap to be disabled for proper memory management. This change also removes swap entries from /etc/fstab to persist across reboots.


1.4 Enable Kernel Modules and Sysctl Parameters

Load required modules now and configure them to auto-load at boot.

modprobe overlay
modprobe br_netfilter
modprobe openvswitch
echo -e "overlay\nbr_netfilter\nopenvswitch" > /etc/modules-load.d/microshift.conf

📦 These modules are essential for container networking and Open vSwitch integration.

Now apply necessary sysctl settings and make them persistent:

sysctl -w net.ipv4.ip_forward=1
sysctl -w net.bridge.bridge-nf-call-iptables=1

cat > /etc/sysctl.d/99-microshift.conf <<EOF
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
EOF

🌐 Enables IP forwarding and bridge network filtering — required for Kubernetes networking components.


1.5 NetworkManager and Firewall

Install and configure NetworkManager with OVS plugin, and disable firewalld.

dnf install -y NetworkManager NetworkManager-ovs
systemctl enable --now NetworkManager
systemctl disable --now firewalld

🔌 NetworkManager is used for consistent container networking. ❌ firewalld is disabled to prevent it from interfering with Kubernetes-managed iptables rules.


🛠️ 2. Installing MicroShift and TLS

2.1 Add Repositories

Add the necessary repositories for MicroShift and its dependencies.

sudo tee /etc/yum.repos.d/ocp-deps-4.19.repo > /dev/null <<EOF
[openshift-4.19-dependencies]
name=OpenShift 4.19 BETA
baseurl=https://mirror.openshift.com/pub/openshift-v4/x86_64/dependencies/rpms/4.19-el9-beta/
enabled=1
gpgcheck=0
EOF
sudo tee /etc/yum.repos.d/microshift-4.19.repo > /dev/null <<EOF
[microshift-4.19]
name=MicroShift 4.19 BETA RPMs
baseurl=https://mirror.openshift.com/pub/openshift-v4/x86_64/microshift/ocp-dev-preview/latest-4.19/el9/os/
enabled=1
gpgcheck=0
EOF
dnf clean all && dnf makecache

📦 These custom repositories provide the pre-release packages required to install MicroShift 4.19 and its OpenShift dependencies.


2.2 Install MicroShift & Dependencies

Install MicroShift, CRI-O (container runtime), and networking plugins.

dnf install -y microshift cri-o cri-tools containernetworking-plugins
rpm -q microshift microshift-networking cri-o openvswitch3.4

🛠️ These packages form the MicroShift stack. The rpm -q lines verify the correct versions were installed.


2.3 Configure Pull Secret

MicroShift uses a pull secret to fetch container images from Red Hat registries.

mkdir -p /etc/crio/
echo '<YOUR_PULL_SECRET_JSON>' > /etc/crio/openshift-pull-secret
chmod 600 /etc/crio/openshift-pull-secret

🔐 Replace <YOUR_PULL_SECRET_JSON> with your Red Hat pull secret. This file must have secure permissions to prevent unauthorized access.


2.4 Start Services & Setup kubeconfig

Start the core services and configure access to the cluster via kubectl.

systemctl enable --now crio
systemctl enable --now microshift
curl -k https://127.0.0.1:6443/healthz

🚀 This starts the container runtime (crio) and MicroShift. The curl command checks if the Kubernetes API is reachable.

Now configure your local kubectl access:

mkdir -p ~/.kube
sudo cp /var/lib/microshift/resources/kubeadmin/kubeconfig ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config

kubectl get nodes
kubectl get pods -n kube-system -o wide

📋 These commands copy the kubeconfig for the cluster and verify that the node and core pods are running.


2.5 Expose Router via NodePort

Create a NodePort service to expose the OpenShift router to external traffic.

oc create -n openshift-ingress -f - <<'EOF'
apiVersion: v1
kind: Service
metadata:
  name: router
  namespace: openshift-ingress
spec:
  type: NodePort
  selector:
    ingresscontroller.operator.openshift.io/deployment-ingresscontroller: default
  ports:
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30080
  - name: https
    port: 443
    targetPort: 443
    nodePort: 30443
EOF

🌍 This exposes the ingress router on ports 30080 and 30443, making your apps reachable over HTTP/HTTPS from outside the server.


🔐 2.6 TLS Setup with Certbot

Install Certbot & Cloudflare Plugin

dnf install -y epel-release
dnf install -y snapd
systemctl enable --now snapd.socket
ln -s /var/lib/snapd/snap /snap
snap install --classic certbot
snap set certbot trust-plugin-with-root=ok
snap install certbot-dns-cloudflare

Cloudflare API Credentials

echo "dns_cloudflare_api_token = YOUR_API_TOKEN" > /root/.cloudflare.ini
chmod 600 /root/.cloudflare.ini

Issue Certificate

export PATH=$PATH:/snap/bin
certbot certonly   --dns-cloudflare   --dns-cloudflare-credentials /root/.cloudflare.ini   --dns-cloudflare-propagation-seconds 60   -d "microshift.josephvillalba.com" -d "*.microshift.josephvillalba.com"   --agree-tos -m "[email protected]" --no-eff-email

🌐 2.7 NGINX Reverse Proxy

dnf install -y nginx

/etc/nginx/conf.d/microshift.conf:

upstream microshift_router {
    server 127.0.0.1:30080;
}

server {
    listen 80;
    server_name microshift.josephvillalba.com *.microshift.josephvillalba.com;
    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name microshift.josephvillalba.com *.microshift.josephvillalba.com;
    ssl_certificate     /etc/letsencrypt/live/microshift.josephvillalba.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/microshift.josephvillalba.com/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    location / {
        proxy_pass http://127.0.0.1:30080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto https;
    }
}
systemctl enable --now nginx
setsebool -P httpd_can_network_connect 1
chcon -Rt httpd_cert_t /etc/letsencrypt/live

🧩 2.8 Configure MicroShift TLS Integration

kubectl create namespace demo
oc project demo

kubectl -n openshift-ingress delete secret wildcard-microshift --ignore-not-found
kubectl -n openshift-ingress create secret tls wildcard-microshift   --cert=/etc/letsencrypt/live/microshift.josephvillalba.com/fullchain.pem   --key=/etc/letsencrypt/live/microshift.josephvillalba.com/privkey.pem

Edit /etc/microshift/config.yaml:

apiServer:
  advertiseAddress: "95.217.163.238"
  namedCertificates:
    - certPath: "/etc/letsencrypt/live/microshift.josephvillalba.com/fullchain.pem"
      keyPath:  "/etc/letsencrypt/live/microshift.josephvillalba.com/privkey.pem"
      names:
        - "microshift.josephvillalba.com"
        - "*.microshift.josephvillalba.com"

ingress:
  certificateSecret: wildcard-microshift
systemctl restart microshift

🌈 3. Deploy Hello World App

nginx-hello.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: hello-index
  namespace: demo
data:
  index.html: |
    <html><body style="font-family:sans-serif;text-align:center;">
      <h1>Hello from <b>Nginx</b> on MicroShift 4.19!</h1>
    </body></html>
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-hello
  namespace: demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-hello
  template:
    metadata:
      labels:
        app: nginx-hello
    spec:
      containers:
      - name: nginx
        image: nginxinc/nginx-unprivileged:stable-alpine
        ports:
        - containerPort: 8080
        volumeMounts:
        - name: html
          mountPath: /usr/share/nginx/html
        - name: cache
          mountPath: /var/cache/nginx
      volumes:
      - name: html
        configMap:
          name: hello-index
      - name: cache
        emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-hello-svc
  namespace: demo
spec:
  selector:
    app: nginx-hello
  ports:
  - name: http
    port: 80
    targetPort: 8080
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: nginx-hello-route
  namespace: demo
spec:
  host: hello.microshift.josephvillalba.com
  to:
    kind: Service
    name: nginx-hello-svc
  port:
    targetPort: http
  tls:
    termination: edge
kubectl apply -f nginx-hello.yaml

Visit: https://hello.microshift.josephvillalba.com


🧪 3.1 Optional: Root-Powered NGINX Pod

apiVersion: v1
kind: ConfigMap
metadata:
  name: hello-root-index
  namespace: demo
data:
  index.html: |
    <html><body style="font-family:sans-serif;text-align:center;">
      <h1>Hello from <b>Nginx (root)</b> on MicroShift 4.19!</h1>
    </body></html>
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-root
  namespace: demo
spec:
  replicas: 1
  selector:
    matchLabels: { app: nginx-root }
  template:
    metadata:
      labels: { app: nginx-root }
    spec:
      serviceAccountName: nginx-root         # ← uses SA with anyuid
      containers:
      - name: nginx
        image: nginx:stable-alpine           # classic image with UID 0
        securityContext:
          runAsUser: 0                        # ← runs as root
        ports:
        - containerPort: 80
        volumeMounts:
        - name: html
          mountPath: /usr/share/nginx/html
      volumes:
      - name: html
        configMap:
          name: hello-root-index
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-root-svc
  namespace: demo
spec:
  selector: { app: nginx-root }
  ports:
  - name: http
    port: 80
    targetPort: 80
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: nginx-root-route
  namespace: demo
spec:
  host: hello-root.microshift.josephvillalba.com
  to:
    kind: Service
    name: nginx-root-svc
  port:
    targetPort: http
  tls:
    termination: edge
kubectl apply -f nginx-root.yaml
kubectl rollout status deploy/nginx-root -n demo
kubectl get pod -n demo -l app=nginx-root
kubectl get route nginx-root-route -n demo -o wide

Visit: https://hello-root.microshift.josephvillalba.com


✅ Done! Your MicroShift 4.19 environment is live and secure.

Leave a Reply

Your email address will not be published. Required fields are marked *