Building multi-platform container images using Podman on Oracle Linux

Introduction

This demo shows the creation of a multi-platform container image using Podman on Oracle Linux 8 or later.

Objectives

In this lab, you’ll:

What Do You Need?

Deploy an x86_64-based Podman Server

  1. Launch either an Intel or AMD based compute instance running Oracle Linux 8.

    Note: Ensure the instance is connected to a public subnet and has an IPv4 address assigned.

    This step supports using the Always Free Tier eligible VM.Standard.E2.Micro shapes.

  2. Once the server is running, login to the instance.

    ssh -i <SSH_KEY> opc@<IP_ADDRESS_OF_PODMAN_SERVER_INSTANCE>
    

    Where:

    • <SSH_KEY> is the SSH key you configured when provisiong the instance. Example: ~/.ssh/id_rsa
    • <IP_ADDRESS_OF_PODMAN_SERVER_INSTANCE> is the IP address of the Oracle Linux 8 instance.

    Note: No additional ingress ports need to be configured as the Podman Server only requires SSH access.

Install and configure Podman for remote access

Run the following commands as the opc user.

  1. Update the system with all the latest security fixes and errata.

    sudo dnf -y update
    
  2. Install the ol8 stream of the container-tools module, which contains the latest versions of podman, buildah, skopeo, runc, crun and conmon as well their dependencies including container-selinux all built and tested together.

    sudo dnf -y module install container-tools:ol8
    
  3. Enable the Podman socket.

    Systemd will listen on that socket and fire up an instance of Podman whenever a remote client activates it. When the connection closes, SystemD will shut down the Podman instance.

    Note: It is possible to configure remote Podman access in rootless mode, but that is beyond the scope of this demo/tutorial.

  4. Enable the Podman socket.

    sudo systemctl enable --now podman.socket
    
  5. Verify the path for the socket.

    [opc@instance ~]$ sudo systemctl status podman.socket
    ● podman.socket - Podman API Socket
       Loaded: loaded (/usr/lib/systemd/system/podman.socket; enabled; vendor preset: disabled)
       Active: active (listening) since Wed 2021-07-28 20:32:06 GMT; 11s ago
        Docs: man:podman-system-service(1)
       Listen: /run/podman/podman.sock (Stream)
       CGroup: /system.slice/podman.socket
    
    Jul 28 20:32:06 bg-2021-07-28-202004-0 systemd[1]: Listening on Podman API Socket.
    

That’s it but stay logged on to the Podman Server instance to perform SSH passwordless configuration later in this lab.

Deploy the Oracle Cloud Developer Image on an Oracle Ampere A1 Arm compute instance

Oracle Ampere A1 Compute is a high-performance platform combining Oracle Cloud Infrastructure and Ampere Altra Arm processors. It provides deterministic performance, proven security, and a broad developer ecosystem that includes popular tools and environments (OS, Kubernetes - OKE , SDKs and CLIs).

The Oracle Cloud Developer Image is now listed as a Platform image. It has all the popular developer tools installed, including git, node.js, java and graal, support, etc.

To access the demo web application remotely, you can either add an Ingress Rule to allow inbound traffic on port 5808/tcp from 0.0.0.0/0 to the security list associated with your public subnet, or use port-forwarding via SSH.

Use Ingress Rules

If you create an ingress rule, you will also need to configure firewalld on the instance to allow that port:

  1. Add access to port 5808.

    sudo firewall-cmd --permanent --add-port=5808/tcp
    sudo firewall-cmd --reload
    
  2. Confirm the firewall change has been made.

    [opc@instance ~]$ sudo firewall-cmd --list-all
    public (active)
      target: default
      icmp-block-inversion: no
      interfaces: enp0s5
      sources:
      services: ssh
      ports: 5808/tcp
      protocols:
      masquerade: no
      forward-ports:
      source-ports:
      icmp-blocks:
      rich rules:
    

Use SSH port-forwarding

If you plan on using SSH port-forwarding:

  1. Login to the instance using the ssh -L option.

    ssh -L 5808:localhost:5808 -i <SSH_KEY> opc@<IP_ADDRESS_OF_CLOUD_DEV_INSTANCE>
    

    Where:

    • -L defines the use of a local port-forward.
    • The first 5808 is the local port on the ssh client machine used in the tunnel.
    • localhost:5808 is the host and port of the service on the remote machine used in the tunnel.
    • <SSH_KEY> is the SSH key you configured when provisiong the instance. Example: ~/.ssh/id_rsa
    • <IP_ADDRESS_OF_CLOUD_DEV_INSTANCE> is the IP address of the Oracle Cloud Developer instance.

Once you’ve connected via SSH to your Oracle Cloud Developer Instance, continue on to the next lab section.

Create a container image for your application and run it locally

In this section, you will clone a demo application from GitHub and create a container to run that application on your two Oracle Cloud Infrastructure instances.

  1. Clone the Git repo and create a Containerfile.

    For this tutorial, you will be deploying RasDash, a Node.js based server monitoring web app. To grab the source code, run:

    [opc@cloud-developer-instance ~]$ git clone https://github.com/sykeben/RasDash.git
    Cloning into 'RasDash'...
    remote: Enumerating objects: 1210, done.
    remote: Counting objects: 100% (57/57), done.
    remote: Compressing objects: 100% (41/41), done.
    remote: Total 1210 (delta 12), reused 51 (delta 8), pack-reused 1153
    Receiving objects: 100% (1210/1210), 3.93 MiB | 35.63 MiB/s, done.
    Resolving deltas: 100% (429/429), done.
    
  2. Change to the RasDash directory and create a Containerfile that will build and serve the web application.

    $ cd ~/RasDash
    $ cat << EOF > Containerfile
    FROM ghcr.io/oracle/oraclelinux8-nodejs:14
    
    COPY . /app
    
    WORKDIR /app
    
    RUN npm install && \
        npm test
    
    CMD ["/usr/bin/node", "app.js", "service"]
    
    EOF
    
  3. Build and run the image on the local instance.

    Build the container image locally using podman and tag the image with the version of the application and architecture of the platform. This will be useful later when you push each platform image to the Oracle Cloud Infrastructure Registry and when you create a manifest of the two platform images.

    [opc@cloud-developer-instance ~]$ sudo podman build --format docker --tag rasdash:0.3.4-arm64 .
    STEP 1: FROM ghcr.io/oracle/oraclelinux8-nodejs:14
    Getting image source signatures
    Copying blob c3b8d81686e4 done
    Copying blob e8c01484bb98 done
    Copying blob a21bf021f718 done
    Copying config a15b4b1174 done
    Writing manifest to image destination
    Storing signatures
    STEP 2: COPY . /app
    --> 16d95c778fe
    STEP 3: WORKDIR /app
    --> 41fb2afcef7
    STEP 4: RUN npm install &&     npm test
    added 60 packages from 43 contributors and audited 60 packages in 1.733s
    found 2 moderate severity vulnerabilities
      run `npm audit fix` to fix them, or `npm audit` for details
    
    > RasDash@0.3.4 test /app
    > node test.js
    
    [STATE] Spawning server process...
    [INFO ] Server process spawned.
    [INFO ] Configuring server events...
    [INFO ] Prepping to test...
    [INFO ] Waiting 3 seconds for server to come online.
    [INFO ] Testing server...
    [DATA ] Online: OK
    [DATA ] Main Dash: OK
    [DATA ] About Page: OK
    [DATA ] CPU Temp: OK
    [DATA ] RAM Usage: OK
    [STATE] RESULTS: Everything seems to be OK.
    [STATE] Finishing up...
    [STATE] Server exited with code 0.
    --> 353146e7004
    STEP 5: CMD ["/usr/bin/node", "app.js", "service"]
    STEP 6: COMMIT rasdash:0.3.4-arm64
    --> 228e26a6391
    228e26a63911bee998fbd903c6ea959b0e0471b6412ffd279844e3b69beb2b92
    

    The final line will be unique to your build of the application.

  4. Run a container using the image.

    [opc@cloud-developer-instance ~]$ sudo podman run --rm --init -detach --name rasdash --publish 5808:5808 localhost/rasdash:0.3.4-arm64
    072cb1501eff109a02caa6cad7931e650101b20c47365dca3ec07124b203d97c
    

    The digest that is returned by Podman is uniqe to each container instance.

  5. View the running container.

    [opc@cloud-developer-instance ~]$ sudo podman ps
    CONTAINER ID  IMAGE                          COMMAND               CREATED         STATUS             PORTS                   NAMES
    072cb1501eff  localhost/rasdash:0.3.4-arm64  /usr/bin/node app...  26 seconds ago  Up 26 seconds ago  0.0.0.0:5808->5808/tcp  rasdash
    
  6. View the logs.

    [opc@cloud-developer-instance ~]$ sudo podman logs rasdash
    [STATE] Starting RasDash in service mode.
    [INFO ] Initializing API...
    [INFO ] Configuring API requests...
    [INFO ] Initializing application...
    [STATE] API mounted to application.
    [INFO ] Configuring application requests...
    [INFO ] Starting server on port 5808...
    [STATE] Server started.
    
  7. Open a browser on your local machine and navigate to http://localhost:5808 to view the web application.

    Note: The CPU temperature metric will display -1 as virtual instances in Oracle Cloud Infrastructure do not have access to any physical hardware data.

Configure passwordless SSH equivalence between your two instances

Podman communicates using SSH between instances for security purposes. For a more seamless experience, create a public/private key pair on your Cloud Developer instance and copy that to the Podman Remote server so you can ssh from the developer instance without being prompted for a password.

  1. Generate a public/private keypair on the Oracle Cloud Developer instance.

    [opc@cloud-developer-instance]$ ssh-keygen -b 4096 -f ~/.ssh/id_rsa -q -N ""
    
  2. Copy the content from ~/.ssh/id_rsa.pub on the Oracle Cloud Developer instance.

    [opc@cloud-developer-instance]$ cat ~/.ssh/id_rsa.pub
    

    Copy the entire contents of the public key shown in the console.

  3. Switch to the Podman Server instance and paste the copied content into the /home/opc/.ssh/authorized_keys file.

    Open the file in vi.

    [opc@podman-server]$ vi ~/.ssh/authorized_keys
    

    Paste the contents of the public key copied from the console. The save and close the file.

  4. While still on the Podman Server instance, ensure the correct file system permissions are applied to the ~/.ssh directory and the ~/.ssh/id_rsa and ~/.ssh/authorized_keys files.

    [opc@podman-server]$ chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys
    
  5. Switch to the Cloud Developer instance and test if you can ssh to the Podman Server as the opc user without requiring a password.

    Note: If you have any issues, refer to Generating Pairs of Authentication Keys by Using the ssh-keygen Command and Enabling Remote System Access Without Requiring a Password in the Oracle Linux Connecting to Remote Systems With OpenSSH documentation.

    [opc@cloud-developer-instance]$ ssh opc@<IP_ADDRESS_OF_PODMAN_SERVER_INSTANCE>
    

    After you have verified that you can connect without requiring a password, be sure to exit the ssh connection between the Oracle Cloud Developer instance to the Podman Server.

  6. Switch to the Podman Server instance and replace the /root/.ssh/authorized_keys file.

    [opc@podman-server ]$ cat /home/opc/.ssh/authorized_keys | sudo tee /root/.ssh/authorized_keys
    
  7. Switch to the Cloud Developer instance and test if you can ssh from the opc user to the root user on the Podman Server.

    [opc@cloud-developer-instance]$ ssh root@<IP_ADDRESS_OF_PODMAN_SERVER_INSTANCE>
    

Once you’ve connected via SSH to your Podman Server Instance as root, continue on to the next lab section.

Create a system connection to the Podman Server

NOTE: Ensure you’re in the terminal of your Oracle Cloud Developer instance.

  1. Create a system connection between the Podman client on your Oracle Cloud Developer instance and the Podman service running on your Podman Server.

    sudo podman system connection add --identity ~/.ssh/id_rsa amd64 ssh://<podman-server-ip>/run/podman/podman.sock
    
  2. Verify that the connection was added.

    [opc@cloud-developer-instance]$ sudo podman system connection list
    Name    Identity               URI
    amd64*  /home/opc/.ssh/id_rsa  ssh://root@<podman-server-ip>:22/run/podman/podman.sock
    

    The * next to the name denotes the default connection if you have multiple connections configured.

Run commands and build your image on the remote Podman Server

NOTE: Ensure you’re in the terminal of your Oracle Cloud Developer instance.

You should now be able to use podman --remote to send commands to the remote instance.

  1. Test by getting the details of your Podman Server.

    [opc@cloud-developer-instance]$ sudo podman --remote info
    host:
      arch: amd64
      buildahVersion: 1.19.8
      cgroupManager: systemd
      cgroupVersion: v1
      conmon:
        package: conmon-2.0.26-3.module+el8.4.0+20195+0a4a4953.x86_64
        path: /usr/bin/conmon
        version: 'conmon version 2.0.26, commit: 9ef46ac10f1c8cd2ebbb917f962a154ba3956e63'
      cpus: 2
      distribution:
        distribution: '"ol"'
        version: "8.4"
      eventLogger: file
      hostname: podman-server
      idMappings:
        gidmap: null
        uidmap: null
      kernel: 5.4.17-2102.202.5.el8uek.x86_64
      linkmode: dynamic
      memFree: 10832736256
      memTotal: 15426166784
      ociRuntime:
        name: runc
        package: runc-1.0.0-73.rc93.module+el8.4.0+20195+0a4a4953.x86_64
        path: /usr/bin/runc
        version: |-
          runc version spec: 1.0.2-dev
          go: go1.15.7
          libseccomp: 2.5.1
      os: linux
      security:
        apparmorEnabled: false
        capabilities: CAP_NET_RAW,CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_NET_BIND_SERVICE,CAP_SETFCAP,CAP_SETGID,CAP_SETPCAP,CAP_SETUID,CAP_SYS_CHROOT
        rootless: false
        seccompEnabled: true
        selinuxEnabled: true
      slirp4netns:
        executable: ""
        package: ""
        version: ""
      swapFree: 4294963200
      swapTotal: 4294963200
      uptime: 1h 32m 0.74s (Approximately 0.04 days)
    registries:
      search:
      - container-registry.oracle.com
      - docker.io
      - registry.fedoraproject.org
      - quay.io
      - registry.centos.org
    store:
      configFile: /etc/containers/storage.conf
      containerStore:
        number: 0
        paused: 0
        running: 0
        stopped: 0
      graphDriverName: overlay
      graphOptions:
        overlay.mountopt: nodev,metacopy=on
      graphRoot: /var/lib/containers/storage
      graphStatus:
        Backing Filesystem: xfs
        Native Overlay Diff: "false"
        Supports d_type: "true"
        Using metacopy: "true"
      imageStore:
        number: 0
      runRoot: /run/containers/storage
      volumePath: /var/lib/containers/storage/volumes
    version:
      APIVersion: 3.0.0
      Built: 1623414869
      BuiltTime: Fri Jun 11 12:34:29 2021
      GitCommit: ""
      GoVersion: go1.15.7
      OsArch: linux/amd64
      Version: 3.0.2-dev
    
  2. Build your image for amd64

    Podman will copy the entire context to the remote instance automatically.

    [opc@cloud-developer-instance]$ cd ~/RasDash
    [opc@cloud-developer-instance]$ sudo podman --remote build --format docker --tag rasdash:0.3.4-amd64 .
    STEP 1: FROM ghcr.io/oracle/oraclelinux8-nodejs:14
    Getting image source signatures
    Copying blob sha256:c1561565b5ac157c67cefd0a13039efdc9f249479d51f0b39cbd7f3e1302b57a
    Copying blob sha256:1da50e1664e1b58d93182fe5af093c642668ec93f67fcd8215b9c1979930b84d
    Copying blob sha256:792675cb62f795ec1e366691a77b5a8822b192ef92ae7e7ff02239533b643094
    Copying config sha256:6fbfa038db26f2191b57226094861be130bda7af13d76b55ef2ec4c10075d316
    Writing manifest to image destination
    Storing signatures
    STEP 2: COPY . /app
    --> ef8b6000efb
    STEP 3: WORKDIR /app
    --> 64ccb3cebd4
    STEP 4: RUN npm install &&     npm test
    added 60 packages from 43 contributors and audited 60 packages in 2.487s
    found 2 moderate severity vulnerabilities
      run `npm audit fix` to fix them, or `npm audit` for details
    
    > RasDash@0.3.4 test /app
    > node test.js
    
    [STATE] Spawning server process...
    [INFO ] Server process spawned.
    [INFO ] Configuring server events...
    [INFO ] Prepping to test...
    [INFO ] Waiting 3 seconds for server to come online.
    [INFO ] Testing server...
    [DATA ] Online: OK
    [DATA ] Main Dash: OK
    [DATA ] About Page: OK
    [DATA ] RAM Usage: OK
    [DATA ] CPU Temp: OK
    [STATE] RESULTS: Everything seems to be OK.
    [STATE] Finishing up...
    [STATE] Server exited with code 0.
    --> 96e14ed1988
    STEP 5: CMD ["/usr/bin/node", "app.js", "service"]
    STEP 6: COMMIT rasdash:0.3.4-amd64
    --> dbb7ecf05cc
    dbb7ecf05cc635c13f8f98dcf4b410f05b81a31f368f738906f10b6ea10087ed
    
  3. Verify image exists on the remote Podman Server.

    NOTE: Podman does not copy the created image back to the client machine, so if you run sudo podman images the image will not be listed. However, it is available on the remote machine.

    [opc@cloud-developer-instance]$ sudo podman --remote images
    REPOSITORY                          TAG          IMAGE ID      CREATED         SIZE
    localhost/rasdash                   0.3.4-amd64  dbb7ecf05cc6  50 seconds ago  193 MB
    ghcr.io/oracle/oraclelinux8-nodejs  14           6fbfa038db26  4 days ago      181 MB
    
  4. Verify image architecutre

    The final method of validating that each image has been built for (and on) a specific platform and architecture, use jq to extract the value of the Architecture field in the manifest of each image.

    [opc@cloud-developer-instance]$ sudo podman inspect rasdash:0.3.4-arm64 | jq -r '.[] | .Architecture'
    arm64
    

    Then check the remote image:

    [opc@cloud-developer-instance]$ sudo podman --remote inspect rasdash:0.3.4-amd64 | jq -r '.[] | .Architecture'
    amd64
    

Once you have each platform image created, you can move onto the next lab.

Create a Container Registry repository

In the Oracle Cloud Infrastructure Console, navigate to the Container Registry section and create a repository to store your multi-platform application.

For more details, see Creating a Repository in the Oracle Cloud Infrastructure Documentation.

  1. Create the demo/rasdash repository.

    create repo

  2. Review the details of the new repository.

    repo details

Gather the Container Registry repository credentials

The following table provides example values used in subsequent steps in this lab. The iad example is the region key for US East (Ashburn) region. If your region is Germany Central (Frankfurt), the region key is fra. Refer to the Regions and Availability Domains documentation for a complete table listing available region keys.

Registry Data Lab placeholder Notes
REGISTRY_NAMESPACE gse00015915 Displayed in the repository info panel as “Namespace”
REPOSITORY_NAME demo/rasdash Displayed under the compartment name
OCIR_INSTANCE iad.ocir.io Use <region>.ocir.io

See Pushing Images Using the Docker CLI if needed. This procedure also describes the login process required to push images to Container Registry using the CLI.

  1. Get your username.

    You need a username and authentication token to login to the container registry. To obtain the username, in the top-right corner of the Oracle Cloud Infrastructure console, open the Profile menu (User menu icon) and then click User Settings to view the details.

    Copy and save the username, including the tenancy-namespace displayed in the console.

    user

  2. Generate an Auth Token.

    Scroll down the “User Details” page in the console and select Auth Tokens under “Resources”.

    Select the “Generate Token” button and provide a description of demo for the new token.

    gen token

    After you generate the token, be sure to copy and save the token.

    copy token

Login to the Container Registory repository

The following table provides example values used in subsequent steps in this lab.

Username Lab placeholder
REGISTRY_NAMESPACE gse00015915
USERNAME oracleidentitycloudservice/luna.user@e1ab5742-7e30-463a-9017-0b48fa54197e
TOKEN ]y#W_iS9GKC}4l1Gq9Fn
OCIR_INSTANCE iad.ocir.io
  1. Create environment variables for use in the podman login command.

    Using your username and token, create the USER and TOKEN environment variables. Ensure you include the <REGISTRY_NAMESPACE> as part of the username.

    $ export USER="gse00015915/oracleidentitycloudservice/luna.user@e1ab5742-7e30-463a-9017-0b48fa54197e"
    $ export TOKEN="]y#W_iS9GKC}4l1Gq9Fn"
    
  2. Login to the container registry.

    [opc@cloud-developer-instance]$ sudo podman login -u $USER -p $TOKEN iad.ocir.io
    Login Succeeded!
    

    Note: The remote instance will automatically inherit the auth credentials from the client instance.

Push the platform images

In this example, the final repository URIs with platform-specific tag are:

Podman can push local images to remote registries without the image needing to be tagged beforehard.

  1. Push the local rasdash/0.3.4-arm64 image.

    [opc@cloud-developer-instance]$ sudo podman push rasdash:0.3.4-arm64 docker://iad.ocir.io/gse00015915/demo/rasdash:0.3.4-arm64
    Getting image source signatures
    Copying blob e2139ee39b4c done
    Copying blob 654f58d01fac done
    Copying blob 2f78ee744a8c done
    Copying blob f4753659db57 done
    Copying blob 57f6de05e468 done
    Copying config 228e26a639 done
    Writing manifest to image destination
    Storing signatures
    
  2. Push the remote rasdash:0.3.4-amd64 image.

    [opc@cloud-developer-instance]$ sudo podman --remote push rasdash:0.3.4-amd64 docker://iad.ocir.io/gse00015915/demo/rasdash:0.3.4-amd64
    
  3. Check the Container Registry console.

    Note: Pushing a remote image does not generate local output. Check the image was successfully pushed by checking the Container Registry console for the rasdash:0.3.4-amd64 tag.

    In the Container Registry console, you should see 2 images - 0.3.4-amd64 and 0.3.4-arm64.

    images

Once you have two images visible under your demo/rasdash repository, you can move on to the next lab.

Create and push a manifest list to the Container Registry

Now that you have two platform images, it’s time to create a manifest list to enable container runtimes the ability to select the appropriate image for their platform, which is a combination of the operating system and architecture.

Because most container images are Linux-based, a multi-platform image is often referred to as a multi-arch image, but it’s also possible to combine images that can run on Windows, macoS and Linux into a single manifest.

  1. Create and populate the manifest.

    On the Cloud Developer Instance, create a local manifest list with just the app version in the tag.

    [opc@cloud-developer-instance]$ sudo podman manifest create rasdash:0.3.4
    c335c5790c1429318afcdfe8041110c9d664faaabe922d44dbf5aa4cd334fa90
    

    As before, the checksum output is unique to the manifest you create and will not match the one above.

  2. Inspect the manifest list to reveal what mediaType is being used and its member images.

    [opc@cloud-developer-instance]$ sudo podman manifest inspect rasdash:0.3.4
    {
        "schemaVersion": 2,
        "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
        "manifests": null
    }
    
  3. Add the two platform-specific images to the list.

    [opc@cloud-developer-instance]$ sudo podman manifest add rasdash:0.3.4 docker://iad.ocir.io/gse00015915/demo/rasdash:0.3.4-arm64
    c335c5790c1429318afcdfe8041110c9d664faaabe922d44dbf5aa4cd334fa90
    
    [opc@cloud-developer-instance]$ sudo podman manifest add rasdash:0.3.4 docker://iad.ocir.io/gse00015915/demo/rasdash:0.3.4-amd64
    c335c5790c1429318afcdfe8041110c9d664faaabe922d44dbf5aa4cd334fa90
    
  4. Inspect the manifest list.

    [opc@cloud-developer-instance]$ sudo podman manifest inspect rasdash:0.3.4
    {
        "schemaVersion": 2,
        "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
        "manifests": [
            {
                "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
                "size": 1082,
                "digest": "sha256:4bad046cb63793381b853eb76bdf38e7dbc788a0bb22584ddbb9cf592e392dff",
                "platform": {
                    "architecture": "arm64",
                    "os": "linux"
                }
            },
            {
                "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
                "size": 1082,
                "digest": "sha256:9ea288587214153dd6cbd6ec3bad38115988db3498c98174b683b52ca9d6eefc",
                "platform": {
                    "architecture": "amd64",
                    "os": "linux"
                }
            }
        ]
    }
    

    The output is more interesting now that the images have been added.

    For maximum compatibility, you added the --format docker parameter to each build command, which instructs Podman to create the image using the Docker Image Manifest V2, Schema 2 (v2s2) specification instead of the Open Container Initiative Image Manifest Specification which Podman will use by default.

    Because the manifests are using the v2s2 specification, Podman uses the associated v2s2 Manifest List specification instead of the Open Container Initiative Image Index Specification.

    The default container runtimes used by both cloud-based managed Kubernetes services including Oracle Engine for Kubernetes (OKE) and on-premise self-hosted Kubernetes distributions are compatible with both specifications.

  5. Push the manifest list to the Container Registry

    Now that you have created the manifest list, you can push it to the same Container Registry repository that’s storing the platform-specific images.

    [opc@cloud-developer-instance]$ sudo podman manifest push --all rasdash:0.3.4 docker://iad.ocir.io/gse00015915/demo/rasdash:0.3.4
    Getting image list signatures
    Copying 2 of 2 images in list
    Copying image sha256:4bad046cb63793381b853eb76bdf38e7dbc788a0bb22584ddbb9cf592e392dff (1/2)
    Getting image source signatures
    Copying blob 679d2db9c557 skipped: already exists
    Copying blob 54cd63300179 skipped: already exists
    Copying blob 4c48cda5b625 skipped: already exists
    Copying blob 26293fa94781 skipped: already exists
    Copying blob 94294e75da8d [--------------------------------------] 0.0b / 0.0b
    Copying config 228e26a639 [====================================] 2.7KiB / 2.7KiB
    Writing manifest to image destination
    Storing signatures
    Copying image sha256:9ea288587214153dd6cbd6ec3bad38115988db3498c98174b683b52ca9d6eefc (2/2)
    Getting image source signatures
    Copying blob 77fd2456db0f skipped: already exists
    Copying blob acb6f7f8e40a skipped: already exists
    Copying blob 1a77e1609215 skipped: already exists
    Copying blob c672a6fc89f8 skipped: already exists
    Copying blob 633f0a770611 [--------------------------------------] 0.0b / 0.0b
    Copying config dbb7ecf05c [====================================] 2.7KiB / 2.7KiB
    Writing manifest to image destination
    Storing signatures
    Writing manifest list to image destination
    Storing list signatures
    

    Because you pushed the platform-specific images earlier, this is a very quick operation. The Container Registry just links the manifest list to the existing images.

  6. Create and Run the image locally.

    You can now run an instance of the image both locally and remotely using the manifest list tag instead of the platform-specific tag.

    [opc@cloud-developer-instance]$ sudo podman run --rm --detach --init --publish 5808:5808 docker://iad.ocir.io/gse00015915/demo/rasdash:0.3.4
    Trying to pull docker://iad.ocir.io/gse00015915/demo/rasdash:0.3.4...
    Getting image source signatures
    Copying blob 54cd63300179 skipped: already exists
    Copying blob 94294e75da8d skipped: already exists
    Copying blob 679d2db9c557 skipped: already exists
    Copying blob 4c48cda5b625 skipped: already exists
    Copying blob 26293fa94781 [--------------------------------------] 0.0b / 0.0b
    Copying config 228e26a639 done
    Writing manifest to image destination
    Storing signatures
    [STATE] Starting RasDash in service mode.
    [INFO ] Initializing API...
    [INFO ] Configuring API requests...
    [INFO ] Initializing application...
    [STATE] API mounted to application.
    [INFO ] Configuring application requests...
    [INFO ] Starting server on port 5808...
    [STATE] Server started.
    
  7. Create and Run the image remotely.

    [opc@cloud-developer-instance]$ sudo podman --remote run --rm --detach --init --publish 5808:5808 docker://iad.ocir.io/gse00015915/demo/rasdash:0.3.4
    Trying to pull iad.ocir.io/gse00015915/demo/rasdash:0.3.4...
    Getting image source signatures
    Copying blob sha256:77fd2456db0fd579268c16176841e22ba6fc9de7444bf26e0c620748ce3e9b52
    Copying blob sha256:633f0a770611d579a5162d320aa01c2ebc2b9816d6f9012603102fdc4ffbc687
    Copying blob sha256:acb6f7f8e40aa7c28bdbba3f90b22503316bfd8a040225da4f819b8468586dce
    Copying blob sha256:1a77e160921552a3be65d8cddb341bfca17a56a3c69af8a5c951ba869c8c5c7f
    Copying blob sha256:c672a6fc89f8047979e6a569af30e8efad3bdac743c84e4f92d7e80e33b78c08
    Copying config sha256:dbb7ecf05cc635c13f8f98dcf4b410f05b81a31f368f738906f10b6ea10087ed
    Writing manifest to image destination
    Storing signatures
    de28d7f7fbd9897a7f4ed17845dcecf7a5e291696bfe6d5603444809267711e7
    
  8. Test images using your browser

    If you created the necessary ingress and firewalld rules on the instances, you should be able to open your browser and navigate to http://arm64-instance-ip:5808 and http://amd64-instance-up:5808 to open the RasDash web application running on each instance.

    Otherwise, you can use SSH port-forwarding as before by creating two tunnels from your local machine.

    ssh -L 5808:localhost:5808 -i <SSH_KEY> opc@<IP_ADDRESS_OF_CLOUD_DEV_INSTANCE>
    

    Open a browser on your local machine and navigate to http://localhost:5808 to view the arm64-based web application on the Cloud Development instance.

    Exit out of the ssh tunnel session.

    ssh -L 5808:localhost:5808 -i <SSH_KEY> opc@<IP_ADDRESS_OF_PODMAN_SERVER_INSTANCE>
    

    Refresh the browser on your local machine pointing to http://localhost:5808 to view the amd64-based web application on the Podman Server instance.

You can deploy images from both private and public OCIR repositories to Oracle Engine for Kubernetes (OKE). To deploy your image to hosts external to Oracle Cloud Infrastructure, including Docker Desktop for Mac or Windows, the repository must be public.

More Learning Resources

Explore other labs on docs.oracle.com/learn or access more free learning content on the Oracle Learning YouTube channel. Additionally, visit education.oracle.com/learning-explorer to become an Oracle Learning Explorer.

For product documentation, visit Oracle Help Center.