Running Lastest Skopeo On RHEL 7

Image by Erich Westendarp from Pixabay

We live in a world full of constraints. This is particularly true when we deal with enterprise IT. Recently I had a project, where the following little problem blocked the progress.

We are allocated a Redhat Enterprise Linux 7.x system, where we have to mirror some container images from the internet for the consumption of the local usage. The tool provided by the commercial software performed well to download the images. But at the last step, it could not proceed to label the images because it relies on Skopeo to list the tags first. The list tags function of Skopeo is only available after V1.0, while in the RHEL os that we are working on, the Skopeo is only at 0.1.41. We could not update the version due to this version of Skopeo is the last version provided for RHEL 7 as indicated in this URL by Redhat,

… This is planned to be the final release of RHEL 7 with major new features in the container tools software stack. This means Podman will not be updated beyond 1.6.4, Buildah will not be updated beyond 1.11.6, and Skopeo will not be updated beyond 0.1.41.

We will not have RHEL 8 box immediately, so we are stuck.

Though we can not run the latest Skopeo, we can run the latest container version of Skopeo. There is a registry.redhat.io/rhel8/skopeo:8.5 available.

We can intercept all the Skopeo command call, rerun it in the container format with Podman. The bash code for this idea is shown as below,

#!/bin/bash
PARSED_OPTIONS=$(/root/skopeo/parser $* | grep Parsed= | cut -d '=' -f 2)
cmd="podman run --network host --add-host {{ .hostname}}:{{ .hostip}} $PARSED_OPTIONS -it registry.redhat.io/rhel8/skopeo:8.5 skopeo $*"#echo $cmd >> /tmp/skopeo.log
eval $cmd

The $* represents all the arguments from the original Skope command, we pass it to the podman run command.

Before it the container version Skopeo really work, we use the host network so that the container Skopeo can access the host network just as the normal Skopeo running on the host. We also add the local hostname/IP pair to the /etc/hosts in the container, so that the Skopeo in the container is able to resolve the host’s hostname before accessing it.

We have to run the podman in root for this use case.

The Skopeo command may access some files from the file system, for example as below,

skopeo list-tags --authfile ${AUTH_DATA_PATH}/auth.json --cert-dir ${AUTH_DATA_PATH}/certs docker://${image}

In the container version of Skope, we will need to map the host files/directories through volume mapping, by adding the following argument in the podman run command, such as

-v ${fullpath_on_host}:${fullpath_in_container}

When doing the volume mapping, the path must be absolute, the relative path will not work.

To make things simple, we can map the files into the container using the exact same name from the host,

-v ${fullpath_on_host}:${fullpath_in_host}

By doing this, we will be able to use the same Skopeo command arguments for the container. No change is required for these arguments.

Let's create a simple Golang program to parse the arguments and output the result for the podman usage.

package mainimport (
"fmt"
"os"
"path/filepath"
"strings"
)
func getAbsPath(path string) (string, error) {
absPath, err := filepath.Abs(path)
if err != nil {
return "", err
}
return absPath, nil
}
func main() {
var authPath, certPath string
for index, arg := range os.Args {
if arg == "--authfile" {
authPath = os.Args[index+1]
}
if arg == "--cert-dir" {
certPath = os.Args[index+1]
}
}
var err error
if authPath != "" {
authPath, err = getAbsPath(authPath)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
if certPath != "" {
certPath, err = getAbsPath(certPath)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
var sb strings.Builder
if authPath != "" {
sb.WriteString(fmt.Sprintf("-v %s:%s:z", authPath, authPath))
}
if certPath != "" {
sb.WriteString(fmt.Sprintf(" -v %s:%s:z", certPath, certPath))
}
fmt.Printf("Parsed=%s\n", sb.String())
}

Basically, when we see the argument that is interested in, we get its next argument and retrieve its OS absolute path. Finally, output the podman run arguments for volume mapping. It is noticed that on the RedHat system, where the SELinux is turned on, we append a “:z” option in the volume mapping to allow the container to access the host file systems.

The wrapping script will then get this argument and use it in the podman run command.

With this walk-around, we are now able to run the latest version of Skopeo in RHEL7.

Problem resolved.

Cloud explorer