Skip to main content

OKD Single node installation in a disconnected environment

Because of reasons we had to set up a disconnected single node OKD "cluster". This is our brain dump as the OKD documentation sometimes refers to OpenShift image locations, we had to read multiple sections to get it working and we also consulted the OpenShift documentation at https://docs.redhat.com.

Updated on 2026-03-03: Fixed install-config.yaml and create manifest command

First we need to download the oc command in the version we would like to install. OKD provides it on its release page:

To get an overview of releases available for OKD see https://amd64.origin.releases.ci.openshift.org/.

Another option is to extract the oc command from the release image, if you have a version of oc already installed:

oc adm release extract --tools quay.io/okd/scos-release:4.21.0-okd-scos.3

This will also extract the openshift-install tar.gz which we need later to generate the installation manifests and ignition configs.

Next we need the oc-mirror plugin, which is used to mirror the release content to our local registry. We were only able to find the plugin on console.redhat.com. Another option might be to compile the plugin from source code (https://github.com/openshift/oc-mirror/).

We copied the oc command and the oc-mirror plugin to /usr/local/bin/ and made them executable. After that we ran oc mirror --v2 --help to test the installation.

The upstream oc-mirror plugin documentation was also helpful.

As our private registry required authentication, we created a .dockerconfigjson file with the registry credentials:

{
  "auths": {
    "internal.registry": {
      "auth": "<credentials base64 encoded>",
      "email": "you@example.com"
    }
  }
}

You can encode the credentials with:

echo -n "username:password" | base64 -w0

For mirroring all required OKD images to our private registry we created an ImageSetConfiguration:

kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v2alpha1
mirror:
  platform:
    channels:
    - name: 4-scos-stable
      minVersion: 4.21.0-okd-scos.3
      maxVersion: 4.21.0-okd-scos.3
    graph: false
  operators:
    - registry: quay.io/okderators/catalog-index:testing-4.20 (1)
      packages:
       - name: aws-load-balancer-operator
       - name: 3scale-operator
       - name: node-observability-operator
  additionalImages:
   - name: registry.redhat.io/ubi8/ubi:latest
   - name: registry.redhat.io/ubi9/ubi@sha256:20f695d2a91352d4eaa25107535126727b5945bff38ed36a3e59590f495046f0

We used a minimal configuration without operators and additional images, because downloading additional images did not work for us:

kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v2alpha1
mirror:
  platform:
    channels:
    - name: 4-scos-stable (1)
      type: okd
      minVersion: 4.21.0-okd-scos.3 (2)
      maxVersion: 4.21.0-okd-scos.3
    graph: false
  operators: []
  additionalImages: []

The hard part for us was finding the right values for channels and the min/max versions. Once again the OKD release status page was helpful.

Our private registry is based on Harbor for our experiments, but any Docker v2 compatible registry should work. The only thing required is a project within Harbor called openshift and a user/password for pulling/pushing images to this project. The project name might be configurable with oc mirror, but this requires further investigation.

oc mirror wants to verify signatures so we had to download a public key and provide the OCP_SIGNATURE_URL:

curl -LO https://raw.githubusercontent.com/openshift/cluster-update-keys/master/keys/verifier-public-key-openshift-ci-4
export OCP_SIGNATURE_URL="https://storage.googleapis.com/openshift-ci-release/releases/signatures/openshift/release/"
export OCP_SIGNATURE_VERIFICATION_PK="verifier-public-key-openshift-ci-4"

# for debugging add --log-level debug, but we had intermittent errors with this option.
# after removing --log-level debug oc mirror ran without problems
oc mirror -c ImageSetConfiguration.yaml --authfile docker-auth.json --workspace file:///workspace docker://internal.registry --v2

This will create the ImageDigestMirrorSource in /workspace/working-dir/cluster-resources/idms-oc-mirror.yaml and ImageTagMirrorSource custom resources in /workspace/working-dir/cluster-resources/itms-oc-mirror.yaml.

The content of ImageDigestMirrorSource will be reused in the install-config.yaml. This is required to redirect image pulls done by the node from quay.io to our private registry.

Next we need DNS records for our cluster:

  • api.sno.internal

  • api-int.sno.internal

  • *.apps.sno.internal (wildcard DNS entry for applications deployed on the cluster)

Now we prepared the required install-config.yaml file to trigger the openshift-install command. We basically followed Installing a Single Node OpenShift Cluster.

apiVersion: v1
baseDomain: internal
compute:
- hyperthreading: Enabled
  name: worker
  replicas: 0 (1)
controlPlane:
  hyperthreading: Enabled
  name: master
  replicas: 1 (2)
metadata:
  name: okd-sno
networking:
  clusterNetwork:
  - cidr: 10.128.0.0/14
    hostPrefix: 23
  networkType: OVNKubernetes
  serviceNetwork:
  - 172.30.0.0/16
platform:
  none: {}
fips: false
sshKey: 'the key'
bootstrapInPlace: (3)
  installationDisk: /dev/vda
pullSecret: |
  {
    "auths": {
      "registry.internal": {
        "auth": "<username:password base64 encoded>",
        "email": "some@email"
      }
    }
  }
additionalTrustBundle: | (4)
  -----BEGIN CERTIFICATE-----
  ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
  -----END CERTIFICATE-----
ImageDigestSources: (5)
- mirrors:
  - registry.internal/openshift/release
  source: quay.io/okd/scos-content
- mirrors:
  - registry.internal/openshift/release-images
  source: quay.io/okd/scos-release
1We set the number of workers to zero (0). Because this is a SNO installation. Worker nodes could be added later, even for a SNO cluster
2We set the number of master nodes to one (1)
3This tells the installer that we do not have a bootstrap node and it should create one large ignition config file
4If required the CA certificate of our registry. This is required if the registry uses an internal certificate
5ImageDigestSources configures CRIO to redirect requests to quay.io to our private registry.

It’s time to create the installation manifests and ignition configs. We created a directory install, copied the install-config.yaml into this directory and triggered the openshift-install command:

$ mkdir install
$ cp install-config.yaml install/
$ openshift-install --dir=install create single-node-ignition-config

We are now ready to download the installation ISO and to embed our ignition config into it. We also want to set kernel boot arguments to configure the network interface with a static IP address.

curl -L $( ./openshift-install coreos print-stream-json |jq -r ".architectures.x86_64.artifacts.metal.formats.iso.disk.location" ) -o fhcos-live.iso
alias coreos-installer='podman run --privileged --pull always --rm -v /dev:/dev -v /run/udev:/run/udev -v $PWD:/data -w /data quay.io/coreos/coreos-installer:release'
coreos-installer iso ignition embed -fi install/bootstrap-in-place-for-live-iso.ign fcos-live.iso
coreos-installer iso kargs modify --append 'ip=10.0.0.99::10.0.0.1:255.255.255.0:sno.internal:ens33:none:10.0.0.255' fcos-live.iso

We can take a look at the ISO bootstrap config and the kernel arguments with:

coreos-installer iso ignition show fcos-live.iso
coreos-installer iso kargs show fcos-live.iso

For understanding the kernel boot arguments see https://access.redhat.com/solutions/5499911.

The final step is to boot the modified ISO on the target machine and wait for the installation to complete.


Discussion

Previous
Use arrow keys to navigate
Next