Mirroring images with a portable storage device

You can make the operators for IBM Cloud Pak for Integration available to a cluster that has no internet connectivity by using a portable storage device. First mirror the images to the portable storage device using a machine that has internet connectivity. Next connect the portable storage device to a machine that is connected to the restricted network environment and mirror the images to a registry within that environment for use by the Red Hat OpenShift cluster.

Overview

Prerequisites

  • Install an OpenShift 4.6 cluster(see Operating environment).

  • Prepare a Docker registry and make it available. For more information, see Prepare a Docker registry.

  • A Docker registry must be set up on an external host that is connected to the internet. For more information, see Prepare a Docker registry.

  • A portable storage device that has sufficient storage must be attached to the external host. For more information, see Prepare an external host.

  • cloudctl version 3.6.1-2002 or later is required.

Prepare a Docker registry

A local Docker registry is used to store all images in your restricted environment. You must create such a registry and ensure that it meets the following requirements:

  • Supports Docker Manifest V2, Schema 2.

  • Is accessible from your OpenShift cluster nodes.

  • Has the username and password of a user who can write to the target registry from the internal host.

  • Has the username and password of a user who can read from the target registry that is on the OpenShift cluster nodes.

  • Allows path separators in the image name.

An example of a simple registry is included in Creating a mirror registry for installation in a restricted network in the OpenShift documentation.

Note: The internal Red Hat OpenShift registry is not compliant with Docker Manifest V2, Schema 2, so it is not suitable for use as a private registry for restricted environments.

Verify that you:

  • Have the credentials of a user who can write and create repositories. The internal host uses these credentials.

  • Have the credentials of a user who can read all repositories. The OpenShift cluster uses these credentials.

Prepare an external host

Prepare an external host that can be connected to the internet. Attach a portable storage device to the host. The storage device is later connected to the local Docker registry in the air-gapped environment.

  • The external host must be on a Linux x86_64 platform, or any operating system that the IBM Cloud Pak CLI and the OpenShift CLI supports.

  • The external host locale must be set to English.

The portable device must have sufficient storage to hold all of the software that is to be transferred to the local Docker registry.

Complete these steps on your external host:

  1. Install OpenSSL version 1.11.1 or higher.

  2. Install Docker or Podman.

  • To install Docker (for example, on Red Hat® Enterprise Linux®), run these commands:

    yum check-update
    yum install docker
  • To install Podman, see Podman Installation Instructions.

  1. Install httpd-tools.

yum install httpd-tools
  1. Install the IBM Cloud Pak CLI. Install the latest version of the binary file for your platform. For more information, see cloud-pak-cli.

    1. Download the binary file.

      wget https://github.com/IBM/cloud-pak-cli/releases/latest/download/<binary-file-name>

      For example, wget https://github.com/IBM/cloud-pak-cli/releases/latest/download/cloudctl-linux-amd64.tar.gz.

    2. Extract the binary file.

    tar -xf <binary-file-name>
    1. Run the following commands to modify and move the file.

    chmod 755 <file-name>
    mv <file-name> /usr/local/bin/cloudctl
    1. Confirm that cloudctl is installed:

    cloudctl --help

    The cloudctl usage is displayed.

  2. Install the oc OpenShift CLI tool. For more information, see Getting started with the CLI in the Red Hat OpenShift documentation.

  3. Install the skopeo CLI version 1.0.0 or higher. For more information, see Installing skopeo from packages.

  4. Create a directory that serves as the offline store.

    Following is an example directory, which is used in the subsequent steps.

    mkdir $HOME/offline
    Note: This offline store must be persistent to avoid transferring data more than once. The persistence also helps to run the mirroring process multiple times or on a schedule.

Create environment variables for the installer and image inventory

On your external host, create the following environment variables with the installer image name and the image inventory.

export CASE_NAME=ibm-cp-integration
export CASE_VERSION=2.1.0
export CASE_ARCHIVE=${CASE_NAME}-${CASE_VERSION}.tgz
export CASE_INVENTORY_SETUP=operator
export OFFLINEDIR=$HOME/offline
export OFFLINEDIR_ARCHIVE=offline.tgz
export CASE_REMOTE_PATH=https://github.com/IBM/cloud-pak/raw/master/repo/case/${CASE_ARCHIVE}
export CASE_LOCAL_PATH=$OFFLINEDIR/$CASE_ARCHIVE

export PORTABLE_DOCKER_REGISTRY_HOST=127.0.0.1
export PORTABLE_DOCKER_REGISTRY_PORT=443
export PORTABLE_DOCKER_REGISTRY=$PORTABLE_DOCKER_REGISTRY_HOST:$PORTABLE_DOCKER_REGISTRY_PORT
export PORTABLE_DOCKER_REGISTRY_USER=localuser
export PORTABLE_DOCKER_REGISTRY_PASSWORD=l0calPassword!
export PORTABLE_DOCKER_REGISTRY_PATH=$OFFLINEDIR/imageregistry

Download the installer and image inventory

Download the installer and image inventory to the external registry host.

cloudctl case save \
  --case $CASE_REMOTE_PATH \
  --outputdir $OFFLINEDIR

Mirror the images to the external host

Complete these steps to mirror the images from the internet to the external host:

  1. Store authentication credentials for all source Docker registries.

    See Applying your entitlement key for how to obtain your entitlement key.

    After obtaining your entitlement key, run the following command to configure credentials for the IBM Entitled Registry:

    cloudctl case launch \
       --case $HOME/offline/${CASE_ARCHIVE} \
       --inventory ${CASE_INVENTORY_SETUP} \
       --action configure-creds-airgap \
       --args "--registry cp.icr.io --user cp --pass <entitlement key> --inputDir $HOME/offline"

    The command stores and caches the registry credentials in a file on your file system in the $HOME/.airgap/secrets location.

  2. Store authentication credentials of the Docker registry that is running on the external host.

    cloudctl case launch \
      --case $CASE_LOCAL_PATH \
      --inventory $CASE_INVENTORY_SETUP \
      --action configure-creds-airgap \
      --args "--registry $PORTABLE_DOCKER_REGISTRY --user $PORTABLE_DOCKER_REGISTRY_USER --pass $PORTABLE_DOCKER_REGISTRY_PASSWORD"

    The command stores and caches the registry credentials in a file on your file system in the $HOME/.airgap/secrets location.

  3. Run a Docker registry service on localhost.

    a. Initialize the Docker registry.

    cloudctl case launch \
      --case $CASE_LOCAL_PATH \
      --inventory $CASE_INVENTORY_SETUP \
      --action init-registry \
      --args "--registry $PORTABLE_DOCKER_REGISTRY_HOST --user $PORTABLE_DOCKER_REGISTRY_USER --pass $PORTABLE_DOCKER_REGISTRY_PASSWORD --dir $PORTABLE_DOCKER_REGISTRY_PATH"

    b. Start the Docker registry.

    cloudctl case launch \
      --case $CASE_LOCAL_PATH \
      --inventory $CASE_INVENTORY_SETUP \
      --action start-registry \
      --args "--registry $PORTABLE_DOCKER_REGISTRY_HOST --port $PORTABLE_DOCKER_REGISTRY_PORT --user $PORTABLE_DOCKER_REGISTRY_USER --pass $PORTABLE_DOCKER_REGISTRY_PASSWORD --dir $PORTABLE_DOCKER_REGISTRY_PATH"
  4. Mirror the images to the registry on the external host.

    cloudctl case launch \
      --case $CASE_LOCAL_PATH \
      --inventory $CASE_INVENTORY_SETUP \
      --action mirror-images \
      --args "--registry $PORTABLE_DOCKER_REGISTRY --inputDir $OFFLINEDIR"

(Optional) Save the Docker registry image

If your air-gapped network doesn’t have a Docker registry image, you can save the image on the portable device and copy it later to the host in your air-gapped environment.

docker save docker.io/library/registry:2.6 -o $PORTABLE_DOCKER_REGISTRY_PATH/registry-image.tar

Copy the saved offline data to an external storage device

  1. Connect the portable storage device, such as a USB drive or external HDD, to this external host.

  2. Archive the offline data for transfer:

    tar -cvzf $OFFLINEDIR_ARCHIVE -C $OFFLINEDIR .
  3. Copy the preceding TAR file to the portable storage.

    This portable storage device should be physically transferred from the machine that has a public internet connection to the machine that has no internet connectivity.

Log in to the internal host that has access to the Openshift Container Platform cluster

The following steps need to be run from this internal host, which is in your air-gapped network, unless otherwise noted.

The internal host must be connected to both the portable storage device and the Openshift Container Platform cluster.

Log in to the Openshift Container Platform cluster as a cluster administrator

Following is an example command to log in to the Openshift Container Platform cluster:

oc login <cluster host:port> --username=<cluster admin user> --password=<cluster admin password>

Create a Kubernetes namespace for the Cloud Pak

Create an environment variable with a namespace to install, then create the namespace. For example:

export NAMESPACE=cp4i
oc create namespace ${NAMESPACE}

Prepare the internal host and extract images

Note: Don't use the tilde within double quotation marks in any command. For example, don’t use args "--registry <registry> --user <registry userid> --pass {registry password} --inputDir ~/offline". The tilde doesn’t expand and your commands might fail.
  1. Create environment variables with the local Docker registry connection information.

export CASE_NAME=ibm-cp-integration
export CASE_VERSION=2.1.0
export CASE_ARCHIVE=${CASE_NAME}-${CASE_VERSION}.tgz
export CASE_INVENTORY_SETUP=operator
export OFFLINEDIR=$HOME/offline
export OFFLINEDIR_ARCHIVE=offline.tgz
export CASE_REMOTE_PATH=https://github.com/IBM/cloud-pak/raw/master/repo/case/${CASE_ARCHIVE}
export CASE_LOCAL_PATH=$OFFLINEDIR/$CASE_ARCHIVE

export PORTABLE_DOCKER_REGISTRY_HOST=127.0.0.1
export PORTABLE_DOCKER_REGISTRY_PORT=443
export PORTABLE_DOCKER_REGISTRY=$PORTABLE_DOCKER_REGISTRY_HOST:$PORTABLE_DOCKER_REGISTRY_PORT
export PORTABLE_DOCKER_REGISTRY_USER=localuser
export PORTABLE_DOCKER_REGISTRY_PASSWORD=l0calPassword!
export PORTABLE_DOCKER_REGISTRY_PATH=$OFFLINEDIR/imageregistry

export LOCAL_DOCKER_REGISTRY_HOST=<IP_or_FQDN_of_local_docker_registry>
export LOCAL_DOCKER_REGISTRY_PORT=443
export LOCAL_DOCKER_REGISTRY=$LOCAL_DOCKER_REGISTRY_HOST:$LOCAL_DOCKER_REGISTRY_PORT
export LOCAL_DOCKER_REGISTRY_USER=<username>
export LOCAL_DOCKER_REGISTRY_PASSWORD=<password>
  1. Extract the transferred offline data from the portable storage device.

    mkdir -p $OFFLINEDIR
    tar -xvf $OFFLINEDIR_ARCHIVE -C $OFFLINEDIR
  2. Set up the registry.

    Run the local, Docker registry as a container. The registry then points to the Docker file system directory that is transferred from the external host.

    cloudctl case launch \
      --case $CASE_LOCAL_PATH \
      --inventory $CASE_INVENTORY_SETUP \
      --action start-registry \
      --args "--registry $PORTABLE_DOCKER_REGISTRY_HOST --port $PORTABLE_DOCKER_REGISTRY_PORT --user $PORTABLE_DOCKER_REGISTRY_USER --pass $PORTABLE_DOCKER_REGISTRY_PASSWORD --dir $PORTABLE_DOCKER_REGISTRY_PATH"
  3. Set up registry credentials for mirroring.

    • Store credentials of the registry that is running on the internal host (created in previous step)

      cloudctl case launch \
        --case $CASE_LOCAL_PATH \
        --inventory $CASE_INVENTORY_SETUP \
        --action configure-creds-airgap \
        --args "--registry $PORTABLE_DOCKER_REGISTRY --user $PORTABLE_DOCKER_REGISTRY_USER --pass $PORTABLE_DOCKER_REGISTRY_PASSWORD"
    • Store credentials of the registry that will serve images to the cluster/workloads.

      cloudctl case launch \
        --case $CASE_LOCAL_PATH \
        --inventory $CASE_INVENTORY_SETUP \
        --action configure-creds-airgap \
        --args "--registry $LOCAL_DOCKER_REGISTRY --user $LOCAL_DOCKER_REGISTRY_USER --pass $LOCAL_DOCKER_REGISTRY_PASSWORD"

Mirror the images and configure the cluster

Mirror the images to the target registry that is on your Openshift cluster and configure the cluster.

  1. Mirror the images from the internal host registry to the target registry on your cluster.

    cloudctl case launch \
      --case $CASE_LOCAL_PATH \
      --inventory $CASE_INVENTORY_SETUP \
      --action mirror-images \
      --args "--fromRegistry $PORTABLE_DOCKER_REGISTRY --registry $LOCAL_DOCKER_REGISTRY --inputDir $OFFLINEDIR"
  2. Configure a global image pull secret and ImageContentSourcePolicy.

    cloudctl case launch \
      --case $CASE_LOCAL_PATH \
      --namespace $NAMESPACE \
      --inventory $CASE_INVENTORY_SETUP \
      --action configure-cluster-airgap \
      --args "--registry $LOCAL_DOCKER_REGISTRY --inputDir $OFFLINEDIR"
    Note: In Openshift Container Platform version 4.6, this step restarts all cluster nodes. The cluster resources might be unavailable until the time the new pull secret is applied.
  3. Verify that the ImageContentSourcePolicy resource is created.

    oc get imageContentSourcePolicy
  4. Optional: If you use an insecure registry, you must add the local registry to the cluster insecureRegistries list.

    oc patch image.config.openshift.io/cluster --type=merge -p '{"spec":{"registrySources":{"insecureRegistries":["'$LOCAL_DOCKER_REGISTRY']}}}'
  5. Verify your cluster node status.

    oc get nodes

After the imageContentsourcePolicy and global image pull secret are applied, you might see the node status as Ready, Scheduling, or Disabled. Wait until all the nodes show a Ready status.

Create the CatalogSource

CP4I can be installed by adding the CatalogSource for the mirrored operators to your cluster and using OLM to install the operators.

  1. Create a catalog source.

    This command adds the CatalogSource for the components to your cluster, so the cluster can access them from the private registry:

    cloudctl case launch \
        --case $HOME/offline/${CASE_ARCHIVE} \
        --inventory ${CASE_INVENTORY_SETUP} \
        --action install-catalog \
        --namespace ${NAMESPACE} \
        --args "--registry ${LOCAL_DOCKER_REGISTRY} --inputDir $HOME/offline --recursive"
  2. Verify that the CatalogSource for the Cloud Pak installer operator is created.

    oc get pods -n openshift-marketplace
    oc get catalogsource -n openshift-marketplace

Next steps

Once the CatalogSource is installed, the next step is to install the operators. See Installing operators.