# Installing baremetal sno (single node openshift) ocp disconnected step-by-step Setup server ``` #register system subscription-manager register subscription-manager auto-attach #update system sudo dnf update sudo dnf install /usr/bin/nmstatectl -y #grab oc wget https://mirror.openshift.com/pub/openshift-v4/clients/ocp/latest/openshift-client-linux.tar.gz #grab openshift-install wget https://mirror.openshift.com/pub/openshift-v4/clients/ocp/latest/openshift-install-linux.tar.gz #Extract the client and place in into the path sudo tar xzf openshift-client-linux.tar.gz -C /usr/local/sbin/ oc kubectl sudo tar xzf openshift-install-linux.tar.gz -C /usr/local/sbin openshift-install #validate client and install version and platform oc version openshift-install version ``` :::info Ensure architecture matches the target destination aarch64 for arm or amd64 for x86_64 ::: ``` #set hostname to external dns name sudo nmcli general hostname openshift-repo.example.com ``` Making an offline installation bundle for OpenShift requires [mirroring/downloading the container images](https://docs.openshift.com/container-platform/4.15/installing/disconnected_install/installing-mirroring-disconnected.html) and then [hosting those container images in a container registry](https://docs.openshift.com/container-platform/4.15/installing/disconnected_install/installing-mirroring-creating-registry.html) that is accessible by the cluster nodes. The download process can put the container images into the local filesystem or upload them directly into the container registry. (a USB stick, a directory that will be burnt to a DVD, or a folder that will be uploaded into S3 or similar storage) :::info A minimal download of OpenShift 4.15 requires ~15GB of space. A minimal download of OpenShift Platform Plus requires ~50GB of space. A full download of All OpenShift Operators and versions can be close to 1TB. ::: Lots of good information in this blog - [Mirroring OpenShift Registries: The Easy Way by Ben Schmaus and Daniel Messer (August 23, 2022)](https://cloud.redhat.com/blog/mirroring-openshift-registries-the-easy-way). ## Create DNS Entries Create necessary dns entries for use: mirror-registry.example.com master-0.example.com api.snow-cluster.example.com *.apps.snow-cluster.example.com ## Install `mirror-registry` (aka mini Quay) :::info Recommend running these commands as root then you can login as any user ::: ``` #pull down and extra mirror-registry wget https://developers.redhat.com/content-gateway/rest/mirror/pub/openshift-v4/clients/mirror-registry/latest/mirror-registry.tar.gz tar xvzf mirror-registry.tar.gz ./mirror-registry install --help #setup ### password must be at least 8 characters and contain no whitespace ./mirror-registry install --quayRoot /data/mirror-registry --quayStorage /data/mirror-registry --initUser admin --initPassword 3yHyHFb9ELEavGixZG846 ``` :::info INFO[2023-04-20 14:39:12] Quay installed successfully, config data is stored in ~/quay-install INFO[2023-04-20 14:39:12] Quay is available at https://openshift-repo.example.com:8443 with credentials (admin, 3yHyHFb9ELEavGixZG846) ::: ``` #copy certificates to be trusted sudo cp -v /data/mirror-registry/quay-rootCA/rootCA.pem /etc/pki/ca-trust/source/anchors/ sudo update-ca-trust #****optional cleanup if restarting**** sudo rm /etc/pki/ca-trust/source/anchors/rootCA.pem sudo update-ca-trust #****optional cleanup if restarting**** #test login podman login -u admin -p 3yHyHFb9ELEavGixZG846 $(hostname -f):8443 ``` ### Starting and stopping the `mirror-registry` Running the `./mirror-registry install ...` results in several `systemd` services being created. You can see which services were created like this: ``` systemctl -a | grep quay quay-app.service loaded active running Quay Container quay-pod.service loaded active exited Infra Container for Quay quay-postgres.service loaded active running PostgreSQL Podman Container for Quay quay-redis.service loaded active running Redis Podman Container for Quay ``` These services will automatically start when the system is rebooted. The `quay-redis`, `quay-db`, and `quay-app` services depend on the `quay-pod` service. You can restart everything with one command: ``` systemctl restart quay-pod ``` ## Install the `oc-mirror` plugin ``` wget https://mirror.openshift.com/pub/openshift-v4/x86_64/clients/ocp/stable/oc-mirror.tar.gz mkdir -p $HOME/.local/bin tar xvzf ./oc-mirror.tar.gz -C $HOME/.local/bin chmod a+x $HOME/.local/bin/oc-mirror oc plugin list oc mirror --help ``` ## Add mirror-registry credentials to pull-secret Download your "pull secret" from the Red Hat OpenShift Cluster Manager at https://console.redhat.com/openshift/install/pull-secret. ``` jq . pull-secret.txt mkdir -p $HOME/.docker mv -v pull-secret.txt $HOME/.docker/config.json podman login -u admin -p 3yHyHFb9ELEavGixZG846 --authfile $HOME/.docker/config.json ec2-18-216-214-86.us-east-2.compute.amazonaws.com:8443 # OPTIONAL - remove the Insights & Telemetry connection # https://docs.openshift.com/container-platform/4.12/support/remote_health_monitoring/opting-out-of-remote-health-reporting.html podman logout --authfile $HOME/.docker/config.json cloud.openshift.com # Confirm contents and create a backup jq . $HOME/.docker/config.json cp -v $HOME/.docker/config.json ~/pull-secret.json ``` ## Setup mirror registry file ``` oc-mirror list releases oc-mirror list releases --version 4.15 --channels oc-mirror list operators oc-mirror list operators --version 4.15 --catalogs oc-mirror list operators --version 4.15 \ --catalog registry.redhat.io/redhat/redhat-operator-index:v4.15 \ --package odf-operator \ --channel stable-4.15 oc-mirror init | tee imageset-config.yaml vi imageset-config.yaml #find channels to slim down podman pull registry.redhat.io/redhat/redhat-operator-index:v4.15 podman unshare cd $(podman image mount registry.redhat.io/redhat/redhat-operator-index:v4.15) ls configs jq .name configs/*/catalog.json # browse the metadata of an Operator jq . configs/advanced-cluster-management/catalog.json | less -i #list channels jq '.schema, .name' configs/advanced-cluster-management/catalog.json #When done exit the POD exit ``` ## Sample [imageset-config.yaml](https://raw.githubusercontent.com/pekramp/notes/main/imageset-config.yaml?token=GHSAT0AAAAAACOYPAFY4UBYFHCRKZNL7GDYZO44ITQ) ``` --- kind: ImageSetConfiguration apiVersion: mirror.openshift.io/v1alpha2 archiveSize: 4 storageConfig: local: path: storageoperator mirror: operators: - catalog: registry.redhat.io/redhat/redhat-operator-index:v4.15 packages: - name: quay-bridge-operator channels: - name: stable-3.10 - name: quay-operator channels: - name: stable-3.10 - name: cincinnati-operator channels: - name: v1 - name: cluster-logging channels: - name: stable-5.8 - name: compliance-operator channels: - name: stable - name: web-terminal channels: - name: fast - name: file-integrity-operator channels: - name: stable - name: ocs-operator channels: - name: stable-4.15 - name: local-storage-operator channels: - name: stable additionalImages: - name: registry.redhat.io/rhel9/rhel-guest-image:latest - name: registry.redhat.io/rhel8/rhel-guest-image:latest ``` ## Run the oc-mirror If you are partially disconnected do the following: ``` #prerun #df -h #/ avail 88G #fill the registry time oc mirror --config=imageset-config.yaml docker://openshift-repo.example.com:8443/415-mirror #time #info: Mirroring completed in 19m53.06s (56.23MB/s) #Rendering catalog image "openshift-repo.example.com:8443/415-mirror/redhat/redhat-operator-index:v4.12" with file-based catalog #Writing image mapping to oc-mirror-workspace/results-1682046532/mapping.txt #Writing UpdateService manifests to oc-mirror-workspace/results-1682046532 #Writing CatalogSource manifests to oc-mirror-workspace/results-1682046532 #Writing ICSP manifests to oc-mirror-workspace/results-1682046532 #real 25m39.673s #user 6m9.616s #sys 2m59.360s #postrun #/ avail 25G ``` If you are fully disconnected do the following: ``` oc mirror --config=./imageset-config.yaml file://<path_to_output_directory> ls <path_to_output_directory> mirror_seq1_000000.tar ``` Copy to disconnected environment through approved channels, then on disconnected side: ``` oc mirror --from=./mirror_seq1_000000.tar docker://openshift-repo.example.com:8443/415-mirror ``` ## Get the mirror info for install ``` #cat mirror file cat oc-mirror-workspace/results-1682046532/imageContentSourcePolicy.yaml --- - mirrors: - openshift-repo.example.com:8443/415-mirror/openshift/release source: quay.io/openshift-release-dev/ocp-v4.0-art-dev - mirrors: - openshift-repo.example.com:8443/415-mirror/openshift/release-images source: quay.io/openshift-release-dev/ocp-release ``` ## Create install-config ``` openshift-install create install-config --dir <installation_directory> ``` ## Customize install-config Customize resources Add mirror information Add additionalTrustedBundle Confirm PullSecret has mirror registry info ## Sample [install-config](https://raw.githubusercontent.com/pekramp/notes/main/install-config.yaml?token=GHSAT0AAAAAACOYPAFZNLWR7HOAUKKPLDXGZO4424Q) ``` --- additionalTrustBundlePolicy: Always apiVersion: v1 baseDomain: example.com compute: - architecture: amd64 name: worker replicas: 0 controlPlane: architecture: amd64 name: master platform: replicas: 1 metadata: creationTimestamp: null name: sno-cluster networking: clusterNetwork: - cidr: 10.128.0.0/14 hostPrefix: 23 machineNetwork: - cidr: 10.0.0.0/16 networkType: OVNKubernetes serviceNetwork: - 172.30.0.0/16 platform: none: {} pullSecret: '{"auths":{"cloud.openshift.com":{"auth":"b3B.............."pkramp@redhat.com"}}}' sshKey: | ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMnrXX3IFuW0mCL1VGiDhjrvOG9AeE0jydJaeuodugX2Enbl/mC8tpBUrUrsGT68jPB1FOe3JgRJHqIbB4jYKwc= ec2-user@ec2-18-216-214-86.us-east-2.compute.amazonaws.com additionalTrustBundle: | -----BEGIN CERTIFICATE----- MIIEPTCCAyWgAwIBAgIUX7jN/sfBvpDPPi+hwpc10UcB2h8wDQYJKoZIhvcNAQEL BQAwgYsxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJWQTERMA8GA1UEBwwITmV3IFlv cmsxDTALBgNVBAoMBFF1YXkxETAPBgNVBAsMCERpdmlzaW9uMTowOAYDVQQDDDFl YzItMTgtMjE2LTIxNC04Ni51cy1lYXN0LTIuY29tcHV0ZS5hbWF6b25hd3MuY29t MB4XDTIzMDQyMDIyNDk0NloXDTI2MDIwNzIyNDk0NlowgYsxCzAJBgNVBAYTAlVT MQswCQYDVQQIDAJWQTERMA8GA1UEBwwITmV3IFlvcmsxDTALBgNVBAoMBFF1YXkx ETAPBgNVBAsMCERpdmlzaW9uMTowOAYDVQQDDDFlYzItMTgtMjE2LTIxNC04Ni51 cy1lYXN0LTIuY29tcHV0ZS5hbWF6b25hd3MuY29tMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEA60xdQlOcVH8Hh/de5hZjypLa3OMEEoRXOM7jN9XRaUXr VhywW48b5RSSufPUBPDIrN+WxNlHG1nydOQF0jyxOte8r3qDes71WZNRaOOZzyDT rwC2CUonw9zxgnbgLKt148E1DFVP0DPvPJA3lwbbIUGRR16BOG+SbNFRwsdRBYJ7 AoYBag+akruUfHSAoqk5prOOsbb0LMZT71baiIZctIBDvo3xlvIF1ZWhc5Xm1D4o M4HO0nczA/MNpbFRpu/xTlnm28103ADBEOLxI6/Bx5NOBPA4YwMBsX2VHd+hfc0/ PcsyZiC9y4MMAEvxqfFllIDncLQPns4v52SoK0ERFQIDAQABo4GWMIGTMAsGA1Ud DwQEAwIC5DATBgNVHSUEDDAKBggrBgEFBQcDATA8BgNVHREENTAzgjFlYzItMTgt MjE2LTIxNC04Ni51cy1lYXN0LTIuY29tcHV0ZS5hbWF6b25hd3MuY29tMBIGA1Ud EwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFP0++4S6z3Ytn3hmBDaoEYqcuxlIMA0G CSqGSIb3DQEBCwUAA4IBAQA0514SEnp88b+hq2ADANmPq84cEFq2nO86T7FpKEhq bqH+T8zhGk015Nl4Yca3g7E9RnRROrrRA9bWInNy6C+CwVsxyTIHoc2uOzGjS+cr 9Tb1D4eCZ8ok4KHrZks3GkGYq8c62vFfee10Aj3x25fSiAzakD1q8H4IXOcvRDF+ s8A4EHhwu0mVXASFZ32SIEV+dKYbTWV4r8NCFd/aEJI6w1GilBfKhhnBl57hS8ZW wvcXj6HTtLmSx65ScykWB1Fp0Gbzuvt9DtpPJ/OFe48AGECmKwp5HEB+lLouf6kJ NRsUZrye9cnovP8yIDVReSL1Bg+3/kvIpmNeOv6Lu9Hs -----END CERTIFICATE----- imageContentSources: - mirrors: - openshift-repo.example.com:8443/415-mirror/openshift/release source: quay.io/openshift-release-dev/ocp-v4.0-art-dev - mirrors: - openshift-repo.example.com:8443/415-mirror/openshift/release-images source: quay.io/openshift-release-dev/ocp-release ``` ## Create agent-config ``` openshift-install agent create agent-config-template ``` ## Sample [agent-config](https://raw.githubusercontent.com/pekramp/notes/main/agent-config.yaml?token=GHSAT0AAAAAACOYPAFYXUJ4CRZDHTYHRMH2ZO45NJQ) ``` --- apiVersion: v1beta1 kind: AgentConfig metadata: name: sno-cluster rendezvousIP: 192.168.111.80 hosts: - hostname: master-0 interfaces: - name: eno1 macAddress: 00:ef:44:21:e6:a5 rootDeviceHints: deviceName: /dev/sdb networkConfig: interfaces: - name: eno1 type: ethernet state: up mac-address: 00:ef:44:21:e6:a5 ipv4: enabled: true address: - ip: 192.168.111.80 prefix-length: 23 dhcp: false dns-resolver: config: server: - 192.168.111.1 routes: config: - destination: 0.0.0.0/0 next-hop-address: 192.168.111.2 next-hop-interface: eno1 table-id: 254 ``` ## Backup install-config && agent-config :::info ****Copy to a backup directory before running, files are consumed**** ::: ## Make the agent-based ISO image and boot ``` mkdir ocp415install/ cp ocp415install-backup/install-config.yaml ocp415install/install-config.yaml cp ocp415install-backup/agent-config.yaml ocp415install/agent-config.yaml #create iso openshift-install --dir=ocp415install agent create image #use iso to boot target box #watch install boostrapping openshift-install --dir=ocp415install agent wait-for bootstrap-complete --log-level=debug #watch install complete openshift-install --dir=ocp415install agent wait-for install-complete --log-level=debug #OUTPUT INFO Install complete! INFO To access the cluster as the system:admin user when using 'oc', run 'export KUBECONFIG=/home/myuser/ocp415install/auth/kubeconfig' INFO Access the OpenShift web-console here: https://console-openshift-console.apps.sno-cluster.example.com INFO Login to the console with user: "kubeadmin", and password: "qrPRj-nWGSZ-zjeAU-qWQw9" #Can export KUBECONFIG during install and monitor nodes and cluster operators coming up oc get nodes oc get co ``` ### Disable the default OperatorHub Catalog Sources ``` oc patch OperatorHub cluster --type merge \ --patch '{"spec":{"disableAllDefaultSources":true}}' ``` ### Create a new disconnected Operator Catalog ``` oc get catalogsource --all-namespaces #No resources found oc create -f oc-mirror-workspace/results-1682046532/catalogSource-redhat-operator-index.yaml #catalogsource.operators.coreos.com/redhat-operator-index created ``` ### Troubleshooting ``` oc create configmap trusted-ca-list --from-file=ca-bundle.crt=rootCA.pem -n openshift-config oc patch proxy/cluster --type=merge -p '{"spec":{"trustedCA":{"name":"trusted-ca-list"}}}' #Wait for reboot #Check pullsecret oc get secret/pull-secret -n openshift-config --template='{{index .data ".dockerconfigjson" | base64decode}}' >mypull.json #Copy cp mypull.json my-updated-pull.json #If missing can add with oc registry login --registry="https://openshift-repo.example.com:8443" --auth-basic="admin:3yHyHFb9ELEavGixZG846" --to=my-updated-pull.json #Replace oc set data secret/pull-secret -n openshift-config --from-file=.dockerconfigjson=my-updated-pull.json #delete catalog source oc get catalogsource --all-namespaces oc delete catalogsource redhat-operator-index -n openshift-marketplace ``` ## Cleanup and restart I wanted to find a way to delete all of the Quay images and start over, without changing my CA certificate, or doing `./mirror-registry uninstall ...` I found that I could create a Quay "super user" token and use that on the command line. [Apparently tokens are deprecated](https://docs.quay.io/glossary/access-token.html), but I couldn't figure out how to make a Robot Account work for me. First create a new Organization. I called mine "adminorg", then [follow the instructions to create a token](https://access.redhat.com/documentation/en-us/red_hat_quay/3/html/red_hat_quay_api_guide/using_the_red_hat_quay_api#create_oauth_access_token). ``` # my TOKEN is 40 characters - a robot account's password/"token" is 64 characters export TOKEN="69JPGcPNONd0LEDXyPGDpMHkFwt6GHJRETjFdI7N" # sad that this query doesn't list repos as "org/repo" curl -s -X GET -H "Authorization: Bearer $TOKEN" 'https://ec2-18-216-214-86.us-east-2.compute.amazonaws.com:8443/api/v1/repository?public=true' | jq --raw-output '.repositories[].name' # must delete "org/repo" instead of "repo" curl -s -X DELETE -H "Authorization: Bearer $TOKEN" 'https://ec2-18-216-214-86.us-east-2.compute.amazonaws.com:8443/api/v1/repository/advanced-cluster-security/rhacs-operator-bundle' # list all of the organizations, except the "adminorg" which holds my $TOKEN curl -s -X GET -H "Authorization: Bearer $TOKEN" 'https://ec2-18-216-214-86.us-east-2.compute.amazonaws.com:8443/api/v1/superuser/organizations/' | jq --raw-output '.organizations[].name' | grep -v adminorg # deleting the org removes all repos curl -s -X DELETE -H "Authorization: Bearer $TOKEN" "https://ec2-18-216-214-86.us-east-2.compute.amazonaws.com:8443/api/v1/superuser/organizations/advanced-cluster-security" # delete all of the orgs -- DANGER!!! for ORG in $(curl -s -X GET -H "Authorization: Bearer $TOKEN" 'https://ec2-18-216-214-86.us-east-2.compute.amazonaws.com:8443/api/v1/superuser/organizations/' | jq --raw-output '.organizations[].name' | grep -v adminorg ); do echo "Deleting \"$ORG\" organization..." curl -s -X DELETE -H "Authorization: Bearer $TOKEN" "https://ec2-18-216-214-86.us-east-2.compute.amazonaws.com:8443/api/v1/superuser/organizations/$ORG" done