Customize OpenStack container images

This section provides instructions on how to customize the functionality of your MOSK OpenStack services by installing custom system or Python packages into their container images.

The MOSK services are running in Ubuntu-based containers, which can be extended to meet specific requirements or implement specific use cases, for example:

  • Enabling third-party storage driver for OpenStack Cinder

  • Implementing a custom scheduler for OpenStack Nova

  • Adding a custom dashboard to OpenStack Horizon

  • Building your own image importing workflow for OpenStack Glance

Warning

Mirantis cannot be held responsible for any consequences arising from using customized container images. Mirantis does not provide support for such actions, and any modifications to production systems are made at your own risk.

Note

Custom images are pinned in the OpenStackDeployment custom resource. These images do not undergo automatic updates or upgrades. Cloud administrator is responsible for image update during OpenStack updating and upgrading.

Build a custom container image

  1. Create a new directory and switch to it:

    mkdir my-custom-image
    cd my-custom-image
    
  2. Create a Dockerfile:

    touch Dockerfile
    
  3. Specify the location for the base image in the Dockerfile.

    A custom image can be derived from any OpenStack image shipped with MOSK. For locations of the images comprising a specific MOSK release, refer to a corresponding release artifacts page in the Release Notes.

    ARG FROM=<images-base-url>/openstack/<image-name>:<tag>
    FROM $FROM
    

    Note

    Presuming the custom image will need to get rebuilt for every new MOSK release, Mirantis recommends parametrizing the location of its base by introducing the $FROM argument to the Dockerfile.

  4. Instruct the Dockerfile to install additional system packages:

    RUN apt-get update ;\
          apt-get install --no-install-recommends -y <package name> ;\
          apt-get clean -y
    

    If you need to install packages from a third-party repository:

    • Make sure that the add-apt-repository utility is installed:

      RUN apt-get install --no-install-recommends -y software-properties-common
      
    • Add the third-party repository:

      RUN add-apt-repository <repository_name>
      
  5. Instruct the Dockerfile to install additional Python packages:

    Caution

    Rules to comply with when extending MOSK container images with Python packages:

    • Use only Python wheel packaging standard, the older *.egg package type is not supported

    • Honor upper constraints that MOSK defines for its OpenStack packages prerequisites

    1. OpenStack components in every MOSK release are shipped together with their requirements packaged as Python wheels and constraints file. Download and extract these artifacts from the corresponding requirements container image, so that they can be used for building your packages as well. Use the requirements image with the same tag as the base image that you plan to customize:

      docker pull <images-base-url>/openstack/requirements:<tag>
      docker save -o requirements.tar <images-base-url>/openstack/requirements:<tag>
      
      mkdir requirements
      tar -xf requirements.tar -C requirements
      tar -xf requirements/<shasum>/layer.tar -C requirements
      
    2. Build your Python wheel packages using one of the commands below depending on the place where the source code is stored:

      • Build from source:

        pip wheel --no-binary <package> <package> --wheel-dir=custom-wheels -c requirements/dev-upper-constraints.txt
        
      • Build from an upstream pip repository:

        pip wheel <package> --wheel-dir=custom-wheels -c requirements/dev-upper-constraints.txt
        
      • Build from a custom repository:

        pip wheel <package> --extra-index-url <Repo-URL> --wheel-dir=custom-wheels -c requirements/dev-upper-constraints.txt
        
    3. Include the built custom wheel packages and packages for the requirements into the Dockerfile:

      COPY custom-wheels /tmp/custom-wheels
      COPY requirements /tmp/wheels
      
    4. Install the necessary wheel packages to be stored along with other OpenStack components:

      RUN source /var/lib/openstack/bin/activate  ;\
          pip install <package> --no-cache-dir --only-binary :all: --no-compile --find-links /tmp/wheels --find-links /tmp/custom-wheels -c /tmp/wheels/dev-upper-constraints.txt
      
  6. Build the container image from your Dockerfile:

    docker build --tag <user-name>/<repo-name>:<tag> .
    

    When selecting the name for your image, Mirantis recommends following the common practice across major public Docker repositories, that is Docker Hub. The image name should be <user-name>/<repo-name>, where <user-name> is a unique identifier of the user who authored it and <repo-name> is the name of the software shipped.

    Specify the current directory as the build context. Also, use the --tag option to assign the tag to your image. Assigning a tag :<tag> enables you to add multiple versions of the same image to the repository. Unless you assign a tag, it defaults to latest.

    If you are adding Python packages, you can minimize the size of the custom image by building it with the --squash flag. It merges all the image layers into one and instructs the system not to store the cache layers of the wheel packages.

  7. Verify that the image has been built and is present on your system:

    docker image ls
    
  8. Publish the image to the designated registry by its name and tag:

    Note

    Before pushing the image, make sure that you have authenticated with the registry using the docker login command.

    docker push <user-name>/<repo-name>:<tag>
    

Attach a private Docker registry to MOSK Kubernetes underlay

To ensure that the Kubernetes worker nodes in your MOSK cluster can locate and download the custom image, it should be published to a container image registry that the cluster is configured to use.

To configure the MOSK Kubernetes underlay to use your private registry, you need to create a ContainerRegistry resource in the Mirantis Container Cloud API with the registry domain and CA certificate in it, and specify the resource in the Cluster object that corresponds to MOSK.

For the details, refer to the Mirantis Container Cloud documentation:

Inject a custom image into MOSK cluster

To inject a customized OpenStack container into your MOSK cluster, you need to use the spec:services section in the OpenStackDeployment custom resource to override the default location of the container image with your own:

  1. Open the OpenStackDeployment custom resource for editing:

    kubectl -n openstack edit osdpl osh-dev
    
  2. Specify the path to your custom image:

    • For MOSK Dashboard (OpenStack Horizon):

      spec:
       services:
         dashboard:
           horizon:
             values:
               images:
                 tags:
                   horizon: <image_path>
      
    • For the MOSK Block Storage service (OpenStack Cinder):

      spec:
       services:
         block-storage:
           cinder:
             values:
               images:
                 tags:
                   <image_name>: <image_path>
      

HowTo examples

To help you better understand the process, this section provides a few examples illustrating how to add various plugins to MOSK services.

Warning

Mirantis cannot be held responsible for any consequences arising from using storage drivers, plugins, or features that are not explicitly tested or documented with MOSK. Mirantis does not provide support for such configurations as a part of standard product subscription.

Pure Storage driver for OpenStack Cinder

Although the PureStorage driver itself is already included in the cinder system package, you need to install additional dependencies to make it work:

  • System packages: nfs-common

  • Python packages: purestorage

The base image is the MOSK Cinder image cinder:yoga-focal-20230227093206.

Procedure:

  1. Download and extract the requirements from the requirements container image that corresponds to the base image that you plan to customize:

    docker pull mirantis.azurecr.io/openstack/requirements:yoga-focal-20230227093206
    docker save -o requirements.tar mirantis.azurecr.io/openstack/requirements:yoga-focal-20230227093206
    
    mkdir requirements
    tar -xf requirements.tar -C requirements
    tar -xf requirements/f533a79f1d92ad487e5261ed1086a2da75b14c6f91d28fe42dbcf0ceaf0dea70/layer.tar -C requirements
    
  2. Build Python wheels:

    pip wheel purestorage --wheel-dir=custom-wheels -c requirements/dev-upper-constraints.txt
    
  3. Create the Dockerfile:

    ARG FROM=mirantis.azurecr.io/openstack/cinder:yoga-focal-20230227093206
    FROM $FROM
    COPY requirements /tmp/wheels
    COPY custom-wheels /tmp/custom-wheels
    RUN apt-get update ;\
        apt-get install --no-install-recommends -y nfs-common ;\
        source /var/lib/openstack/bin/activate  ;\
        pip install purestorage --no-cache-dir --only-binary :all: --no-compile --find-links /tmp/wheels --find-links /tmp/custom-wheels -c /tmp/wheels/dev-upper-constraints.txt ;\
        apt-get clean -y ;\
        rm -rf \
         /var/cache/debconf/* \
         /var/lib/apt/lists/* \
         /var/log/* \
         /tmp/* \
         /var/tmp/*
    
  4. Build the custom image:

    docker build --squash -t customopenstackimages/cinder-purestorage:yoga-1.0.0 .
    
TrilioVault plugin for OpenStack Horizon

The base image is the MOSK Horizon image horizon:yoga-focal-20230227093206.

Procedure:

  1. Download and extract the requirements from the requirements container image that corresponds to the base image that you plan to customize:

    docker pull mirantis.azurecr.io/openstack/requirements:yoga-focal-20230227093206
    docker save -o requirements.tar mirantis.azurecr.io/openstack/requirements:yoga-focal-20230227093206
    
    mkdir requirements
    tar -xf requirements.tar -C requirements
    tar -xf requirements/f533a79f1d92ad487e5261ed1086a2da75b14c6f91d28fe42dbcf0ceaf0dea70/layer.tar -C requirements
    
  2. Build wheels. This step will be performed automatically because the Trillio repository has tar Python packages that build wheels binaries on installation.

  3. Create the Dockerfile:

    ARG FROM=mirantis.azurecr.io/openstack/horizon:yoga-focal-20230227093206
    FROM $FROM
    COPY requirements /tmp/wheels
    RUN source /var/lib/openstack/bin/activate ;\
        pip install tvault-horizon-plugin workloadmgrclient contegoclient --extra-index-url https://pypi.fury.io/triliodata-dev-5-0-beta --no-cache-dir --no-compile --find-links /tmp/wheels -c /tmp/wheels/dev-upper-constraints.txt ;\
        cp /var/lib/openstack/lib/python3.8/site-packages/dashboards/local/enabled/*.py /var/lib/openstack/lib/python3.8/site-packages/openstack_dashboard/enabled/ ;\
        cp /var/lib/openstack/lib/python3.8/site-packages/dashboards/templatetags/*.py /var/lib/openstack/lib/python3.8/site-packages/openstack_dashboard/templatetags/ ;\
        cp /var/lib/openstack/lib/python3.8/site-packages/dashboards/local/local_settings.d/_001_trilio_dashboard.py  /var/lib/openstack/lib/python3.8/site-packages/openstack_dashboard/local/local_settings.d/ ;\
        rm -rf \
          /var/log/* \
          /tmp/* \
          /var/tmp/*
    
  4. Build the custom image:

    docker build --squash -t customopenstackimages/horizon-trilio:yoga-1.0.0 .
    
FWaaS dashboard for OpenStack Horizon

The base image is the MOSK Horizon image horizon:yoga-focal-20230227093206.

You can install the dashboard source from the neutron-fwaas-dashboard GitHub repository.

Procedure:

  1. Download and extract the requirements from the``requirements`` container image that corresponds to the base image that you plan to customize:

    docker pull mirantis.azurecr.io/openstack/requirements:yoga-focal-20230227093206
    docker save -o requirements.tar mirantis.azurecr.io/openstack/requirements:yoga-focal-20230227093206
    
    mkdir requirements
    tar -xf requirements.tar -C requirements
    tar -xf requirements/f533a79f1d92ad487e5261ed1086a2da75b14c6f91d28fe42dbcf0ceaf0dea70/layer.tar -C requirements
    
  2. Build Python wheels:

    git clone https://opendev.org/openstack/neutron-fwaas-dashboard
    pip wheel neutron-fwaas-dashboard/ neutron-fwaas-dashboard --wheel-dir=custom-wheels --no-deps -c requirements/dev-upper-constraints.txt
    
  3. Create the Dockerfile:

    ARG FROM=mirantis.azurecr.io/openstack/horizon:yoga-focal-20230227093206
    FROM $FROM
    COPY requirements /tmp/wheels
    COPY custom-wheels /tmp/custom-wheels
    RUN source /var/lib/openstack/bin/activate ;\
        pip install neutron-fwaas-dashboard  --no-cache-dir --no-compile --find-links /tmp/wheels --find-links /tmp/custom-wheels -c /tmp/wheels/dev-upper-constraints.txt ;\
        cp /var/lib/openstack/lib/python3.8/site-packages/neutron_fwaas_dashboard/enabled/_70*_*.py /var/lib/openstack/lib/python3.8/site-packages/openstack_dashboard/enabled/ ;\
        rm -rf \
          /var/log/* \
          /tmp/* \
          /var/tmp/*
    
  4. Build the custom image:

    docker build --squash -t customopenstackimages/horizon-fwaas:yoga-1.0.0 .