IBM Developer

Tutorial

Run multiple OCI container workloads on IBM Hyper Protect Virtual Servers for VPC

Use Kubernetes Pod descriptors in a Hyper Protect Virtual Servers contract

By Abhiram Kulkarni, Divya K Konoor, Anbazhagan Mani, Kalaiarasan Panneerselvam, Seenu Suvarna

If you’re running IBM Hyper Protect Virtual Servers, you’ve already put security at the top of your priority list. Hyper Protect Virtual Servers protects sensitive Linux workloads from internal and external threats.

In this tutorial, you'll learn how to run multiple OCI container-based workloads on an instance of IBM Hyper Protect Virtual Servers for VPC (Virtual Private Cloud). (Review our previous tutorial on how to bring up a single OCI container on Hyper Protect Virtual Servers.) Note that multi-OCI container support is available for Hyper Protect Virtual Servers only with Podman play kube (Pod descriptors). It is not available with a docker-compose file.

The Open Container Initiative, or OCI, is "an open governance structure for the express purpose of creating open industry standards around container formats and runtimes."

This tutorial will show you how to use Kubernetes Pod descriptors in a Hyper Protect Virtual Servers contract. (For Pod descriptor details, see the Kubernetes documentation.)

You will start by running a single OCI container and then learn how to run multiple containers.

Notes:

  • Hyper Protect Virtual Servers for VPC supports multiple containers only with Pod descriptors, which means that if you want to run only one container on Hyper Protect Virtual Servers, you can either use Docker Compose or a Pod descriptor. However, if you want to run multiple containers, you must use Pod descriptors with the Hyper Protect Virtual Servers contract.
  • The contract workload section can either have containers defined with Docker Compose or Podman play kube, but not both, within the same contract.

We will cover the following use cases:

  • Bring up a single container (PostgreSQL) workload on Hyper Protect Virtual Servers using play
  • Bring up multiple container-based workloads on Hyper Protect Virtual Servers using play

Prerequisites

Estimated time

This tutorial will take approximately 30 minutes to complete, including the preparation time, depending on your previous experience working with pod definition files. Creating the Hyper Protect Virtual Servers instance should take only a few seconds.

Steps

Step 1. Construct a Pod definition file

In a previous tutorial, you learned how a PostgreSQL container can be defined using a Docker Compose file with Hyper Protect Virtual Servers. Now you'll explore how to use a Pod descriptor for the same container.

The first step is to create a Pod definition file with the container details.

  1. Create a directory called pod_postgres:

    root@podman-postgres:~# mkdir pod_postgres
    root@podman-postgres:~# cd pod_postgres/
    root@podman-postgres:~/pod_postgres# ls
    root@podman-postgres:~/pod_postgres#
    
  2. Create a simple pod YAML file called pod_postgres.yaml with the following content. This example shows the publicly available container image for PostgreSQL. Note: The example is for your reference only. See the official Red Hat documentation to learn more about Pod definition files.

    apiVersion: v1
    kind: Pod
    metadata:
     name: postgresdb
    spec:
     containers:
     - name: postgres
       image: docker.io/library/postgres:12@sha256:429c57f9ae8f379601df6df7448b0c2c8df4da23d7ba2cb57fee8da8f262eda0
       env:
        - name: POSTGRES_HOST_AUTH_METHOD
           valueFrom:
            configMapKeyRef:
             name: env-user
             key: POSTGRES_HOST_AUTH_METHOD
        - name: POSTGRES_PASSWORD
           valueFrom: 
            configMapKeyRef:
             name: env-user
             key: POSTGRES_PASSWORD
        ports:
         - containerPort: 5432
           hostPort: 5432
        restartpolicy: Always
    
  3. Create a file named configmaps_postgres.yaml with the following contents. Note: You must include a kind attribute with a value of ConfigMap. Use a password of your choice for the POSTGRES_PASSWORD environment variable's value. The following example uses passw0rd.

    
     apiVersion: v1
     kind: ConfigMap
     metadata:
         name: env-user
     data:
         POSTGRES_HOST_AUTH_METHOD: trust
         POSTGRES_PASSWORD: passw0rd
    
  4. Review the folder structure to ensure it looks like the following example, with both the newly created files within the same directory:

    
    root@podman-postgres:~/pod_postgres# ls -l
    total 8
    -rw-r--r-- 1 root root 129 Nov 21 08:53 configmaps_postgres.yaml
    -rw-r--r-- 1 root root 596 Nov 21 08:50 pod_postgres.yaml
    
  5. Validate that the files are in the correct format by running them in your local environment where podman is installed.

    1. Start the PostgreSQL workload using the podman play kube command.
    2. Optional: You can also use a LinuxONE Virtual Server Instance to set up podman and run the following command if a local environment is not available. (See Bringing up container-based workloads on LinuxONE zVSI to learn more about how to create a LinuxONE Virtual Server instance.)

       root@podman-postgres:~/pod_postgres# podman play kube pod_postgres.yaml --configmap ./configmaps_postgres.yaml
       Trying to pull docker.io/library/postgres@sha256:429c57f9ae8f379601df6df7448b0c2c8df4da23d7ba2cb57fee8da8f262eda0...
       Getting image source signatures
       Copying blob 9595ad34963d done  
       Copying blob a7cd1b5b2e3c done  
       Copying blob 1c2e5a5a3305 done  
       Copying blob aeb5658447e2 done  
       Copying blob fe2887f3dc6c done  
       Copying blob acaae8b3f317 done  
       Copying blob 31d443c42a10 done  
       Copying blob 9e57daa6420a done  
       Copying blob e08ed989481b done  
       Copying blob d62a513ca1cd done  
       Copying blob cfe91422bc2d done  
       Copying blob a4a8c236b9a9 done  
       Copying blob 1f11052fcdc0 done  
       Copying config c6bf1b141f done  
       Writing manifest to image destination
       Storing signatures
       Pod:
       336a5645bc3e3a6a8cd83c02592b505c7ffd17f6b9d26592ff34eda3b372b5b1
       Container:
       7410865682a8de1d07ec6ca20114a80140e339a30d3b17a064868b6a53471afa
      
    3. Check that the pod and container are running as expected using the following commands.

      root@podman-postgres:~/pod_postgres# podman pod ps
       POD ID        NAME        STATUS      CREATED      INFRA ID      # OF CONTAINERS
       336a5645bc3e  postgresdb  Running     6 hours ago  00d0b39e6ef4  2
      
       root@podman-postgres:~/pod_postgres# podman ps
       CONTAINER ID  IMAGE                                                                                               COMMAND     CREATED      STATUS          PORTS                   NAMES
       7410865682a8  docker.io/library/postgres@sha256:429c57f9ae8f379601df6df7448b0c2c8df4da23d7ba2cb57fee8da8f262eda0  postgres    6 hours ago  Up 6 hours ago  0.0.0.0:5432->5432/tcp  postgresdb-postgres
      
  6. When the PostgreSQL container is running in your local environment, you need to check whether it's accessible (either locally or remotely). Note: You might have to install the following packages before you can start using the psql utility.

     sudo apt install postgresql-client-common
     sudo apt install postgresql-client
     psql -h <PostgreSQL host IP> -p 5432 -U postgres
    

Now that you have validated your Pod descriptor files in a local environment, you can prepare to use it with Hyper Protect Virtual Servers for VPC.

Step 2. Run PostgreSQL container-based workloads

In the following steps, you'll create a contract with the Pod descriptors. In the previous tutorial, we discussed the different sections of a Hyper Protect Virtual Servers contract, specifically env and workload. For this tutorial, the contents of the env section remain unchanged. Only the workload section changes when you switch to using Pod descriptors.

The workload section of the contract can either have the compose or play subsection. The Hyper Protect Virtual Servers instance internally uses either Docker Compose or Podman play kube to manage the OCI containers, depending on which subsection is used.

See Run container-based workloads on IBM Hyper Protect Virtual Servers for VPC to learn more about how to create a Hyper Protect Virtual Servers for VPC instance from IBM Cloud.

For more details on the play subsection, see the IBM Cloud VPC documentation.

  1. To create a .tar file of the pod descriptors that you created previously, run the following command:

    
    root@podman-postgres:~/pod_postgres# tar czvf pod.tgz *
    configmaps_postgres.yaml
    pod_postgres.yaml
    
  2. Convert the .tar file to base64 format:

    
    root@podman-postgres:~/pod_postgres# base64 -w0 pod.tgz > pod.b64
    root@podman-postgres:~/pod_postgres# cat pod.b64
     H4sIAAAAAAAAA+3UX2/aMBAA8DznU/gLtHUc5w9+Gtq6IU0VCOj2iC6xQyOSOLIDFd9+hgFllJY9dJ2m3e8l8fkUX5ycc90U5byG1s5abbu5UfZ6DXXlvSHqxJxvr87plTIaeAGPWEITNwg96gY08gh9yyJesrQdGEI8o3X3Wt6l+X8UtOU3ZWypG0FWgb8oGynIx+1PcQetX6sOJHQgfEIaqJUgqlldLa0y/j48Gk6mX8a3k9nA3cz699PB7O52Ohh+EqQzbnePU0b9yeT7cOymWrD2kRrp/+0N+M+1Wv65xt+50P9BwPiu/+OEJ5Hr/zCIE+z/93C2/0danun8/W8iM9+2Kt9M5LrpoGzcAzajq5NEFyKkrGHuYlLnC2WuS31TlZkBs77ZZ4mAfbAPwKJYcNbLo6TogUqLMOnFNJBFLIuE8zSjOctTWXAJLJRJBizPXKpSqYS0YDFTEuh2QXdAie3NU0EvHlG7PEJWUC3VZ6NrcQhtXu7nKfhVrceqOJp5dhYezSzU+vKCzwrbH4xnCiK/V9ErJZ3U9MtarTadfdqvwwcdubggEQ/Z4UkP7oOdhN3nc93Ttboqc7dEv3qEtcUjHSGEEEIIIYQQQgghhBBCCCGEEHpnPwADkUAAA==
    
  3. Add the base 64 content created in the previous step to the contract workload section (at workload > play > archive).

    
     workload: |
     type: workload
     play:
         archive: H4sIAAAAAAAAA+3UX2/aMBAA8DznU/gLtHUc5w9+Gtq6IU0VCOj2iC6xQyOSOLIDFd9+hgFllJY9dJ2m3e8l8fkUX5ycc90U5byG1s5abbu5UfZ6DXXlvSHqxJxvr87plTIaeAGPWEITNwg96gY08gh9yyJesrQdGEI8o3X3Wt6l+X8UtOU3ZWypG0FWgb8oGynIx+1PcQetX6sOJHQgfEIaqJUgqlldLa0y/j48Gk6mX8a3k9nA3cz699PB7O52Ohh+EqQzbnePU0b9yeT7cOymWrD2kRrp/+0N+M+1Wv65xt+50P9BwPiu/+OEJ5Hr/zCIE+z/93C2/0danun8/W8iM9+2Kt9M5LrpoGzcAzajq5NEFyKkrGHuYlLnC2WuS31TlZkBs77ZZ4mAfbAPwKJYcNbLo6TogUqLMOnFNJBFLIuE8zSjOctTWXAJLJRJBizPXKpSqYS0YDFTEuh2QXdAie3NU0EvHlG7PEJWUC3VZ6NrcQhtXu7nKfhVrceqOJp5dhYezSzU+vKCzwrbH4xnCiK/V9ErJZ3U9MtarTadfdqvwwcdubggEQ/Z4UkP7oOdhN3nc93Ttboqc7dEv3qEtcUjHSGEEEIIIYQQQgghhBBCCCGEEHpnPwADkUAAA==
    
  4. Combine the workload section with the env section. (For details on creating the contract and sections, see the previous tutorial.)

    
     env: |
      type: env
      logging:
       logDNA:
        hostname: syslog-x.us-south.logging.cloud.ibm.com
        ingestionKey: axxxxxxxxxxx3
        port: 6514
      workload: |
       type: workload
       play:
         archive: H4sIAAAAAAAAA+3UX2/aMBAA8DznU/gLtHUc5w9+Gtq6IU0VCOj2iC6xQyOSOLIDFd9+hgFllJY9dJ2m3e8l8fkUX5ycc90U5byG1s5abbu5UfZ6DXXlvSHqxJxvr87plTIaeAGPWEITNwg96gY08gh9yyJesrQdGEI8o3X3Wt6l+X8UtOU3ZWypG0FWgb8oGynIx+1PcQetX6sOJHQgfEIaqJUgqlldLa0y/j48Gk6mX8a3k9nA3cz699PB7O52Ohh+EqQzbnePU0b9yeT7cOymWrD2kRrp/+0N+M+1Wv65xt+50P9BwPiu/+OEJ5Hr/zCIE+z/93C2/0danun8/W8iM9+2Kt9M5LrpoGzcAzajq5NEFyKkrGHuYlLnC2WuS31TlZkBs77ZZ4mAfbAPwKJYcNbLo6TogUqLMOnFNJBFLIuE8zSjOctTWXAJLJRJBizPXKpSqYS0YDFTEuh2QXdAie3NU0EvHlG7PEJWUC3VZ6NrcQhtXu7nKfhVrceqOJp5dhYezSzU+vKCzwrbH4xnCiK/V9ErJZ3U9MtarTadfdqvwwcdubggEQ/Z4UkP7oOdhN3nc93Ttboqc7dEv3qEtcUjHSGEEEIIIYQQQgghhBBCCCGEEHpnPwADkUAAA==
    
  5. See the previous tutorial for instructions on how to create an instance of Hyper Protect Virtual Servers for VPC and substitute the contract that you just created:

     ~# psql -h <floating ip or VM ip>  -p 5432 -U postgres
     psql (12.16 (Ubuntu 12.16-0ubuntu0.20.04.1), server 12.12 (Debian 12.12-1.pgdg110+1))
     Type "help" for help.
    

Step 3. Prepare to run multiple OCI containers

You will use the play subsection of workload to create a contract that can bring up multiple containers on Hyper Protect Virtual Servers for VPC. You'll enhance the contract that you created in the previous step to add support for multiple containers.

The following example has a ReactJS app container definition added to the descriptor, along with the PostgreSQL definition:


apiVersion: v1
kind: Pod
metadata:
  name: myapp
spec:
  containers:

- name: postgres.   #container 1 spec
    image: docker.io/library/postgres:12@sha256:429c57f9ae8f379601df6df7448b0c2c8df4da23d7ba2cb57fee8da8f262eda0
    env:
  - name: POSTGRES_HOST_AUTH_METHOD
        valueFrom:
         configMapKeyRef:
           name: env-user
           key: POSTGRES_HOST_AUTH_METHOD
  - name: POSTGRES_PASSWORD
        valueFrom:
         configMapKeyRef:
            name: env-user
            key: POSTGRES_PASSWORD
    ports:
  - containerPort: 5432
        hostPort: 5432
    restartpolicy: Always
  - name: react-nodejs-app.  #container 2 spec
      image: docker.io/{reponame}/myreactapp:0.0.1@sha256:94bf6cae0902b33b6840e045fd2bae212f0bd538776b325a6daff123a1bf5
    env:
    - name: POSTGRES_PASSWORD
        valueFrom:
         configMapKeyRef:
            name: env-user
            key: POSTGRES_PASSWORD
    - name: POSTGRES_PORT
        valueFrom:
         configMapKeyRef:
            name: env-user
            key: POSTGRES_PORT
     ports:
    - containerPort: 5173
        hostPort: 80
     restartpolicy: Always

Summary

In this tutorial, you've learned how to use the play subsection of a contract to prepare to run multiple OCI containers on an instance of Hyper Protect Virtual Servers for VPC.

Watch for future tutorials, where we will explore additional features of Hyper Protect Virtual Servers for VPC.

Next steps

Now that you understand how to configure Hyper Protect Virtual Servers contracts and run multiple OCI containers on a single instance, continue to explore Hyper Protect Virtual Servers resources: