Step-by-Step OKD Installation on Azure VM

Here’s a complete step-by-step guide for installing OKD (the upstream OpenShift) on a single Azure VM — this is an SNO (Single Node OpenShift/OKD) style install using the Agent-Based Installer.


Prerequisites

Local machine (your laptop/workstation)

  • openshift-install binary (OKD build)
  • oc CLI
  • az CLI, authenticated to your Azure subscription
  • ssh-keygen key pair ready

Azure VM spec (minimum for SNO)

ResourceMinimum
vCPUs8
RAM16 GB (32 GB recommended)
OS Disk120 GB SSD
OSRHCOS (installed by OKD — you don’t pick the OS)

Step 1 — Create the Azure VM (bare metal style)

# Variables
RG="okd-snо-rg"
LOCATION="canadacentral"
VM_NAME="okd-sno"
VNET="okd-vnet"
SUBNET="okd-subnet"
# Resource group
az group create --name $RG --location $LOCATION
# VNet + Subnet
az network vnet create \
--resource-group $RG \
--name $VNET \
--address-prefix 10.0.0.0/16 \
--subnet-name $SUBNET \
--subnet-prefix 10.0.1.0/24
# Public IP (static)
az network public-ip create \
--resource-group $RG \
--name okd-pip \
--sku Standard \
--allocation-method Static
# NSG + rules
az network nsg create --resource-group $RG --name okd-nsg
for PORT in 22 80 443 6443 22623; do
az network nsg rule create \
--resource-group $RG \
--nsg-name okd-nsg \
--name "allow-$PORT" \
--priority $((1000 + PORT % 1000)) \
--destination-port-ranges $PORT \
--access Allow --protocol Tcp
done
# NIC
az network nic create \
--resource-group $RG \
--name okd-nic \
--vnet-name $VNET \
--subnet $SUBNET \
--public-ip-address okd-pip \
--network-security-group okd-nsg
# VM (no OS — we'll boot from ISO)
az vm create \
--resource-group $RG \
--name $VM_NAME \
--nics okd-nic \
--size Standard_D8s_v3 \
--os-disk-size-gb 120 \
--image "RedHat:RHEL:8-lvm-gen2:latest" \ # placeholder — replaced by RHCOS
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_rsa.pub \
--storage-sku Premium_LRS

In practice for OKD SNO you boot from the agent ISO — the VM image above is just to get the disk. We’ll write RHCOS over it.


Step 2 — Get the OKD installer & pull secret

# Download latest OKD release
OKD_VERSION="4.15.0-0.okd-2024-03-10-010116"
wget https://github.com/okd-project/okd/releases/download/${OKD_VERSION}/openshift-install-linux-${OKD_VERSION}.tar.gz
tar xvf openshift-install-linux-*.tar.gz
sudo mv openshift-install /usr/local/bin/
# Pull secret — OKD uses a fake/empty one (no Red Hat subscription needed)
# Use this minimal pull secret:
cat > pull-secret.json << 'EOF'
{"auths":{"fake":{"auth":"aWQ6cGFzcw=="}}}
EOF

Step 3 — Generate install-config.yaml

mkdir ~/okd-install
cat > ~/okd-install/install-config.yaml << EOF
apiVersion: v1
baseDomain: yourdomain.com # e.g. azure.example.com
metadata:
name: okd-sno # cluster name
compute:
- name: worker
replicas: 0 # SNO = 0 workers
controlPlane:
name: master
replicas: 1 # SNO = 1 master
platform:
baremetal: {}
platform:
none: {} # Agent-based uses "none"
pullSecret: '{"auths":{"fake":{"auth":"aWQ6cGFzcw=="}}}'
sshKey: '$(cat ~/.ssh/id_rsa.pub)'
EOF

Step 4 — Generate the Agent ISO

# Copy install-config (installer consumes it)
cp ~/okd-install/install-config.yaml ~/okd-install/
# Generate agent-config.yaml for SNO
cat > ~/okd-install/agent-config.yaml << EOF
apiVersion: v1alpha1
kind: AgentConfig
metadata:
name: okd-sno
rendezvousIP: 10.0.1.10 # VM's private IP
hosts:
- hostname: okd-sno
role: master
interfaces:
- name: eth0
macAddress: "$(az network nic show -g $RG -n okd-nic --query 'macAddress' -o tsv | tr '[:upper:]' '[:lower:]')"
networkConfig:
interfaces:
- name: eth0
type: ethernet
state: up
ipv4:
enabled: true
address:
- ip: 10.0.1.10
prefix-length: 24
dhcp: false
dns-resolver:
config:
server:
- 168.63.129.16 # Azure DNS
routes:
config:
- destination: 0.0.0.0/0
next-hop-address: 10.0.1.1
next-hop-interface: eth0
EOF
# Generate the ISO
openshift-install agent create image --dir ~/okd-install/
# Output: ~/okd-install/agent.x86_64.iso

Step 5 — Boot the VM from the Agent ISO

# Upload ISO to Azure Storage
az storage account create --name okdiso$RANDOM --resource-group $RG --sku Standard_LRS
STORAGE_ACCOUNT=$(az storage account list -g $RG --query '[0].name' -o tsv)
az storage container create --name isos --account-name $STORAGE_ACCOUNT
az storage blob upload \
--account-name $STORAGE_ACCOUNT \
--container-name isos \
--name agent.iso \
--file ~/okd-install/agent.x86_64.iso
ISO_URL=$(az storage blob url \
--account-name $STORAGE_ACCOUNT \
--container-name isos \
--name agent.iso -o tsv)
# Attach as virtual DVD and set boot order
az vm disk attach \
--resource-group $RG \
--vm-name $VM_NAME \
--new --sku Premium_LRS \
--lun 1 --size-gb 2 # not needed — use virtual media approach below
# Easier: use az vm run-command or Serial Console to dd the ISO to disk
# OR use Azure's trusted launch + boot from ISO via az vm boot-diagnostics

Tip for Azure: The cleanest approach is to use a Gen1 VM and attach the ISO as a managed disk image, or use dd via serial console to write the ISO to a secondary disk and set it as the boot device in BIOS via Azure Serial Console.

# On the VM via Serial Console — write ISO to disk and reboot
sudo dd if=/dev/cdrom of=/dev/sda bs=512k status=progress
# OR if uploaded as blob, stream directly:
sudo curl -o /dev/sdb "$ISO_URL"
sudo reboot

Step 6 — DNS records (critical)

OKD requires these DNS records pointing to your VM’s public IP:

api.okd-sno.yourdomain.com → <public-ip>
*.apps.okd-sno.yourdomain.com → <public-ip>
PUBLIC_IP=$(az network public-ip show -g $RG -n okd-pip --query ipAddress -o tsv)
echo "Set these DNS A records to: $PUBLIC_IP"
echo " api.okd-sno.yourdomain.com"
echo " *.apps.okd-sno.yourdomain.com"

Step 7 — Monitor the install

# Watch installation progress from your local machine
openshift-install agent wait-for bootstrap-complete --dir ~/okd-install/ --log-level=info
# Then wait for full install completion
openshift-install agent wait-for install-complete --dir ~/okd-install/ --log-level=info
# Expected output when done:
# INFO Install complete!
# INFO To access the cluster as the system:admin user use 'export KUBECONFIG=...'
# INFO Access the OpenShift web-console: https://console-openshift-console.apps.okd-sno.yourdomain.com
# INFO Login to the console with user: kubeadmin, and password: XXXXX-XXXXX-XXXXX-XXXXX

Step 8 — Access the cluster

export KUBECONFIG=~/okd-install/auth/kubeconfig
# Verify
oc get nodes
# NAME STATUS ROLES AGE VERSION
# okd-sno Ready control-plane,master,worker 10m v1.28.x
oc get clusteroperators # all should be Available=True
oc whoami # system:admin
# Web console
# https://console-openshift-console.apps.okd-sno.yourdomain.com
# user: kubeadmin
# pass: cat ~/okd-install/auth/kubeadmin-password

Common Issues

ProblemFix
Bootstrap never completesCheck DNS — api.* record is the most common miss
Pods stuck PendingSNO has no workers — ensure replicas: 0 for compute
CrashLoopBackOff on etcdVM has < 16 GB RAM or disk I/O too slow (use Premium SSD)
Console unreachableNSG missing port 443 or *.apps wildcard DNS not set
Clock skew errorsSync VM time — Azure VMs can drift during install

Total install time: ~45–60 minutes after the VM boots from the ISO. The bulk of that is the cluster operators coming up one by one.

Leave a Reply