Build 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.

Objectives

In this tutorial, you’ll learn how to:

Prerequisites

Deploy a Podman Server

  1. Create an Oracle Linux compute instance.

    You can use the default image and shape, provided the shape uses an x86_64 architecture. Select or create a public subnet and assign an IPv4 address.

    This step supports using the Micro shapes available in the Always Free Tier.

  2. Once the instance is running, log in to the instance.

    ssh -i <SSH_KEY> opc@<IP_ADDRESS_OF_PODMAN_SERVER_INSTANCE>
    

    Where:

    • <SSH_KEY> is the private part of your SSH key used when provisioning the compute instance. Example: ~/.ssh/id_rsa
    • <IP_ADDRESS_OF_PODMAN_SERVER_INSTANCE> is the public IP address of the compute instance.

Install and Configure Podman for Remote Access

You can run these commands as the default opc user account on the compute instance or any user with sudo access.

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

    sudo dnf -y update
    
  2. Install the Podman packages or modules.

    Oracle Linux 8:

    sudo dnf module install -y container-tools:ol8
    

    Oracle Linux 9:

    sudo dnf install -y container-tools
    

    The container-tools module or package installs podman and other container tools, including skopeo and buildah. One essential package is container-selinux, which allows running podman as a non-root user on a SELinux-enabled system, which Oracle Linux enables by default.

  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 tutorial.

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

    sudo systemctl status podman.socket
    

    The output shows the socket listening and its location at /run/podman/podman.sock.

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

Deploy an Oracle Cloud Developer Instance

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

OCI lists the Oracle Cloud Developer Image as a Platform image with all the popular developer tools installed, including Git, Node.js, Java, and GraalVM.

  1. Create an Oracle Cloud Developer compute instance.

    Select the Oracle Cloud Developer image and an Ampere shape. Select the same public subnet as the Podman server instance and assign an IPv4 address.

  2. Decide to use Ingress Rules or SSH port-forwarding.

    You can access the demo web application we’ll create in two ways. While you can enable both, you only need to pick one or the other.

(Optional) Create an Ingress Rule

Using an Ingress Rule is a two-step process. This option opens access to the subnet from the internet and continues to grant access to the instance on the specified port even after a reboot. You must first create the rule within OCI and then open the port within firewalld on the Oracle Linux instance.

  1. Add an Ingress Rule to your public subnet.

    The rule should allow inbound traffic on port 5808/tcp from 0.0.0.0/0. The rule takes effect immediately after creation.

  2. Open a new terminal and connect to the Oracle Cloud Developer instance via SSH.

    ssh -i <SSH_KEY> opc@<IP_ADDRESS_OF_ORACLE_CLOUD_DEVELOPER_INSTANCE>
    
  3. Add access to the demo web application.

    sudo firewall-cmd --permanent --add-port=5808/tcp
    sudo firewall-cmd --reload
    
  4. Confirm the changes to the firewall.

    sudo firewall-cmd --list-all
    

    The output shows ports: 5808/tcp available.

Use SSH Port-Forwarding

  1. Open a terminal and connect via SSH to the Oracle Cloud Developer instance.

    The -L option enables local forwarding, which opens a local port to connect through an SSH tunnel to the remote demo web application.

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

Create a Container Image for a Web Application and Run It Locally

  1. Clone the demo application’s Git repository.

    For this tutorial, you will be deploying RasDash, a Node.js based server monitoring web app.

    git clone https://github.com/sykeben/RasDash.git
    
  2. Change to the source code directory.

    cd  ~/RasDash
    
  3. Create a Containerfile to build and serve the web application.

    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
    
  4. Build and run the image on the local instance.

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

    sudo podman build --format docker --tag rasdash:0.3.4-arm64 .
    

    The final line will be unique to your application build.

  5. Run a container using the image.

    sudo podman run --rm --init -detach --name rasdash --publish 5808:5808 localhost/rasdash:0.3.4-arm64
    

    The digest that Podman returns is unique to each container instance.

  6. View the running container.

    sudo podman ps
    

    The output displays the container as Up and running.

  7. View the container logs.

    sudo podman logs rasdash
    

    The output shows the [STATE] Server started.

  8. View the web application.

    Open a browser on your local machine and navigate to http://localhost:5808. If you created the ingress and firewall rules, you could use the Oracle Cloud Developer instance’s public IP address rather than localhost.

    Note: The CPU temperature metric will display -1 as virtual instances in OCI cannot access physical hardware data.

  9. Stop the running container.

    sudo podman stop rasdash
    

Configure Passwordless SSH Between the 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 key pair on the Oracle Cloud Developer instance.

    ssh-keygen -b 4096 -f ~/.ssh/id_rsa -q -N ""
    
  2. Copy the contents of the public key file.

    cat ~/.ssh/id_rsa.pub
    

    Select the output from the cat command and copy it.

  3. Switch to the Podman server instance.

  4. Open the file in vi.

    vi ~/.ssh/authorized_keys
    

    Paste the public key contents into the authorized keys file.

    Save and close the file.

  5. Ensure you apply the correct file system permissions to the SSH directory and files.

    chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys
    
  6. Switch to the Cloud Developer instance.

  7. 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 the following documentation:

    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 session between the Oracle Cloud Developer instance and the Podman server.

  8. Switch to the Podman server instance.

  9. Replace the root user’s authorized keys file.

    cat /home/opc/.ssh/authorized_keys | sudo tee /root/.ssh/authorized_keys
    
  10. Switch to the Cloud Developer instance.

  11. Test if you can SSH with the opc user on the Cloud Developer instance to the root user on the Podman server.

    ssh root@<IP_ADDRESS_OF_PODMAN_SERVER_INSTANCE>
    

    You can exit the session after successfully testing the SSH connection to the Podman server as the root user.

Create a System Connection to the Podman Server

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

    sudo podman system connection add --identity ~/.ssh/id_rsa amd64 ssh://root@<IP_ADDRESS_OF_PODMAN_SERVER_INSTANCE>/run/podman/podman.sock
    

    In the command above, ensure you replace <IP_ADDRESS_OF_PODMAN_SERVER_INSTANCE> with the IP address or hostname of your Podman server.

  2. Verify that you successfully added the connection.

    sudo podman system connection list
    

    The output displays the amd64 connection with the Default value set to true. Podman uses this connection if the system has multiple connections configured.

Build an Image on the Remote Podman Server

You should now be able to use podman --remote to send commands from the Oracle Cloud Developer instance to the remote Podman server instance.

  1. Test by getting the details of the Podman server.

    sudo podman --remote info
    

    The architecture should report as arm64.

  2. Build the remote image.

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

    cd ~/RasDash
    sudo podman --remote build --format docker --tag rasdash:0.3.4-amd64 .
    
  3. Verify that the image exists on the remote Podman server.

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

    sudo podman --remote images
    

    Example Output:

    REPOSITORY                          TAG          IMAGE ID      CREATED        SIZE
    localhost/rasdash                   0.3.4-amd64  3a1b9755ebdd  8 seconds ago  439 MB
    ...
    
  4. Verify local image architecture.

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

    sudo podman inspect rasdash:0.3.4-arm64 | jq -r '.[] | .Architecture'
    

    The local image reports its architecture as arm64.

  5. Check the remote image.

    sudo podman --remote inspect rasdash:0.3.4-amd64 | jq -r '.[] | .Architecture'
    

    The remote image reports as amd64.

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 private 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 tutorial. 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 Tutorial 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 describes the login process required to push images to the Container Registry using the CLI.

  1. Get your username.

    You need a username and authentication token to log in 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 My profile 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 My profile 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 Registry Repository

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

Username Tutorial Placeholder
REGISTRY_NAMESPACE gse00015915
USERNAME 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.

    Create the USER and TOKEN environment variables using your username and token. Ensure you include the <REGISTRY_NAMESPACE> as part of the username.

    export OCIR_INSTANCE="iad.ocir.io"
    export OCIR_NAMESPACE="gse00015915"
    export OCI_USERNAME="luna.user@e1ab5742-7e30-463a-9017-0b48fa54197e"
    export OCIR_USERNAME="$OCIR_NAMESPACE/$OCI_USERNAME"
    export OCI_USER_TOKEN="]y#W_iS9GKC}4l1Gq9Fn"
    
  2. Login to the container registry.

    sudo -E podman login -u $OCIR_USERNAME -p $OCIR_USER_TOKEN $OCIR_INSTANCE
    

    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 tags are:

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

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

    sudo -E podman push rasdash:0.3.4-arm64 docker://$OCIR_INSTANCE/$OCIR_NAMESPACE/demo/rasdash:0.3.4-arm64
    
  2. Push the remote rasdash:0.3.4-amd64 image.

    sudo -E podman --remote push rasdash:0.3.4-amd64 docker://$OCIR_INSTANCE/$OCIR_NAMESPACE/demo/rasdash:0.3.4-amd64
    
  3. Check the Container Registry console.

    Note: Pushing a remote image does not generate local output. Review the Container Registry console for the rasdash:0.3.4-amd64 tag to check if you successfully pushed the image.

    You should see two images in the Container Registry console.

    images

    The 0.3.4-amd64 image:

    images

    The 0.3.4-arm64 image:

    images

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 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, users typically refer to a multi-platform image as a multi-arch image. However, combining images that can run on Windows, macOS, and Linux into a single manifest is also possible.

  1. Create and populate the manifest.

    Create a local manifest list on the Cloud Developer Instance with just the app version in the tag.

    sudo podman manifest create rasdash:0.3.4
    

    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.

    sudo podman manifest inspect rasdash:0.3.4
    
  3. Add the two platform-specific images to the list.

    sudo -E podman manifest add rasdash:0.3.4 docker://$OCIR_INSTANCE/$OCIR_NAMESPACE/demo/rasdash:0.3.4-arm64
    
    sudo -E podman manifest add rasdash:0.3.4 docker://$OCIR_INSTANCE/$OCIR_NAMESPACE/demo/rasdash:0.3.4-amd64
    
  4. Inspect the manifest list.

    sudo podman manifest inspect rasdash:0.3.4
    

    The output is more interesting after adding the images.

    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 stores the platform-specific images.

    sudo -E podman manifest push --all rasdash:0.3.4 docker://$OCIR_INSTANCE/$OCIR_NAMESPACE/demo/rasdash:0.3.4
    

    This action is a quick operation because you pushed the platform-specific images earlier. 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 locally and remotely using the manifest list tag instead of the platform-specific tag.

    sudo -E podman run --rm --detach --init --publish 5808:5808 $OCIR_INSTANCE/$OCIR_NAMESPACE/demo/rasdash:0.3.4
    
  7. Create and run the image remotely.

    sudo -E podman --remote run --rm --detach --init --publish 5808:5808 $OCIR_INSTANCE/$OCIR_NAMESPACE/demo/rasdash:0.3.4
    

Test the Images Using a Browser

Suppose you created the necessary ingress rules and firewalld rules on the instances. In that case, you should be able to open your browser and navigate to http://<PUBLIC_IP_ADDRESS_OF_ORACLE_CLOUD_DEVELOPER_INSTANCE>:5808 and http://<PUBLIC_IP_ADDRESS_OF_PODMAN_SERVER_INSTANCE>: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.

  1. Open an SSH tunnel to the Oracle Cloud Developer instance.

    ssh -L 5808:localhost:5808 -i <SSH_KEY> opc@<IP_ADDRESS_OF_ORACLE_CLOUD_DEVELOPER_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.

  2. Exit out of the SSH tunnel session.

  3. Open an SSH tunnel to the Podman server instance.

    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.

Next Steps

After completing this tutorial, you should now know how to create images that you can deploy from both private and public OCIR repositories. You can use these images in various locations such as Oracle Engine for Kubernetes (OKE) or Oracle Cloud Native Environment. When deploying your images to hosts outside of Oracle Cloud Infrastructure, including Podman Desktop for Mac or Windows, you should ensure the repository is 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.