Create a custom Appsody stack with template for IBM Cloud Object Storage operations

A document store is a common requirement across solutions. For example, a business process management solution for travel approvals and reimbursement may have a requirement where scanned documents are uploaded and stored. When IBM Cloud Object Storage is used as a document store, applications upload and retrieve documents from IBM Cloud Object Storage for processing. This store could be shared between multiple applications.

This tutorial shows you how to create a custom Appsody stack with Python that can be used to build a IBM Cloud Object Storage client as a microservice.

You can deploy the solution you build using the stack to a Red Hat OpenShift cluster on IBM Cloud.

Learning objectives

In this tutorial, you will learn to:

  • Create a custom Appsody stack using Python Flask with support for IBM Cloud Object Storage operations
  • Build and test the stack with sample code
  • Deploy an image to OpenShift cluster on IBM Cloud

Prerequisites

You need the following installed to complete the steps in this tutorial:

Estimated time

Completing this tutorial should take about 30 minutes.

Steps

  1. Create a copy of the Python Flask stack.
  2. Modify the Python Flask stack to add support for object storage operations.
  3. Build the stack.
  4. Create an instance of IBM Cloud Object Storage.
  5. Create an Appsody project using the new stack.
  6. Test.
  7. Deploy to an OpenShift cluster on IBM Cloud.

1. Create a copy of the Python Flask stack

Open a new terminal. Go to the folder where you want to create the new stack contents and then run the command to make a copy of the Python Flask stack:

appsody stack create python-flask-os --copy incubator/python-flask

A folder python-flask-os is created.

2. Modify the Python Flask stack to add support for object storage operations

  1. To modify the stack, create a new template called ostemplate.

     $ cd python-flask-os
     $ cd templates
     $ mkdir ostemplate
    
  2. Add a dependency for the IBM Cloud Object Storage client. In the ostemplate folder you just created, create a file called Pipfile with the following contents:

     [[source]]
     name = "pypi"
     url = "https://pypi.org/simple"
     verify_ssl = true
    
     [dev-packages]
    
     [packages]
     ibm-cos-sdk = '==2.6.3'
    
     [requires]
     python_version = "3.7"
    

    Note: The ibm-cos-sdk version added here is 2.6.3. This can be changed based on the requirement.

  3. Clone the repository for this tutorial

     git clone https://github.com/IBM/appsody-template-object-storage-tutorial.git
    
  4. Copy the files config.ini and osclient.py into the folder ostemplate you created earlier.

    • The file config.ini has the credentials to connect to the IBM Cloud Object Storage service.
    • The file osclient.py has functions to perform operations on IBM Cloud Object Storage.

3. Build the stack

Go to the python-flask-os folder and run the following command:

  appsody stack package

This builds the stack into a local Appsody repository (called dev.local). You can create Appsody projects based on the newly created stack.

4. Create an instance of IBM Cloud Object Storage

  1. Create an instance of IBM Cloud Object Storage.

    createos

  2. Create credentials for the newly created IBM Cloud Object Storage service

    • Click on Credentials
    • Click on New Credential. Make a note of the newly created credential in JSON format.

      createcred

5. Create an Appsody project using the new stack

  1. Create a new empty folder and call it example. Create an Appsody project inside the newly created folder by running the following commands:

      $ cd example
      $ appsody init dev.local/python-flask-os ostemplate
    

    The files Pipfile,osclient.py and config.ini are created under the example folder.

  2. Now it’s time to test the template. Copy the file __init__.py and folder templates from the sources downloaded from GitHub into the example folder

    • The file __init__.py has REST interfaces exposed to test the IBM Cloud Object Storage operations.
    • The templates folder has two HTML files – index.html and display.html that you can use to test the IBM Cloud Object Storage service once the client is configured with credentials. You will use the HTML files in combination with __init__.py to test the IBM Cloud Object Storage operations in this tutorial.
  3. Modify the contents of config.ini with the credentials that you created earlier.

    Credentials we noted earlier on IBM Cloud:

    credentials

    The relevant portions indicated in the credentials are entered into the config.ini as shown below:

    config

  4. Modify the COS_BUCKET_LOCATION appropriately. You can find the list of valid location constraints here.

6. Test

  1. Build and run the project. Go to the example folder and run the following commands:

     $ appsody build
     $ appsody run
    
  2. View the API docs at: http://localhost:8080.

  3. Check the health of the container at : http://localhost:8080/health

{"status":"UP"}
  1. View the metrics for the application at: http://localhost:8080/metrics

     ...
     # HELP requests_for_routes_total Number of requests for specififed routes
     # TYPE requests_for_routes_total counter
     requests_for_routes_total{endpoint="/createbucket",method="GET"} 8.0
     requests_for_routes_total{endpoint="/listcontents",method="GET"} 5.0
     requests_for_routes_total{endpoint="/upload",method="POST"} 3.0
     requests_for_routes_total{endpoint="/getobject",method="GET"} 2.0
     requests_for_routes_total{endpoint="/getimage",method="GET"} 2.0
     requests_for_routes_total{endpoint="/delobject",method="GET"} 2.0
     requests_for_routes_total{endpoint="/deletebucket",method="GET"} 2.0
     # TYPE requests_for_routes_created gauge
     requests_for_routes_created{endpoint="/createbucket",method="GET"} 1.5743067014166722e+09
     requests_for_routes_created{endpoint="/listcontents",method="GET"} 1.5743067104581301e+09
     requests_for_routes_created{endpoint="/upload",method="POST"} 1.574306721774285e+09
     requests_for_routes_created{endpoint="/getobject",method="GET"} 1.57430674282679e+09
     requests_for_routes_created{endpoint="/getimage",method="GET"} 1.5743067433085754e+09
     requests_for_routes_created{endpoint="/delobject",method="GET"} 1.5743067524696794e+09
     requests_for_routes_created{endpoint="/deletebucket",method="GET"} 1.574306767495254e+09
    
  2. Test the stack by opening the URL: http://localhost:8080/home

    Test

7. Deploy to an OpenShift cluster on IBM Cloud

The `appsody build’ command locally builds a Docker image of your Appsody project which you can then deploy to OpenShift.

$ docker images example
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
example             latest              e04e2c3f263f        12 seconds ago      1.09GB
  1. Log in to IBM Cloud

     ibmcloud login
    
  2. Add a namespace to create your own image repository. Replace with your preferred namespace.

     ibmcloud cr namespace-add <my_namespace>
    
  3. To ensure that your namespace is created, run the ibmcloud cr namespace-list command.

     ibmcloud cr namespace-list
    
  4. Tag the Docker image. Replace the placeholder for region with the region of the container registry.

     docker tag dev.local/example:latest <region>.icr.io/<my_namespace>/example:latest
    
  5. Push the Docker images into your namespace. Replace the placeholder for region, namespace with your container registry region and the namespace created earlier.

     ibmcloud cr login
     docker push <region>.icr.io/<my_namespace>/example:latest
    
  6. Log in to OpenShift.

     oc login https://xxxx.containers.cloud.ibm.com:xxxxx --token=xxxxxxxxxxx
    
  7. Create a deployment configuration file example_deployment.yaml with the following contents. Replace the placeholder for region, namespace with your container registry region and the namespace created earlier.

     apiVersion: apps/v1
     kind: Deployment
     metadata:
       name: example-deployment
     spec:
       replicas: 1
       selector:
         matchLabels:
           app: example
       template:
         metadata:
           labels:
             app: example
         spec:
           containers:
           - name: example
             image: <region>.icr.io/<namespace>/example:latest
         ports:
         - containerPort: 8080
           protocol: TCP
     ---
     apiVersion: v1
     kind: Service
     metadata:
       labels:
         app: example
       name: example
     spec:
       ports:
       - port: 8080
         protocol: TCP
         targetPort: 8080
         name: web
       selector:
         app: example
       type: ClusterIP
    
  8. Create the deployment in your cluster.

     oc apply -f example_deployment.yaml
    
  9. Create a route for the service.

    oc expose service/example
    
  10. Get the route for the service

     oc get routes
    

You will see the route to the service as follows:

NAME    HOST/PORT PATH                                                     SERVICES   PORT   TERMINATION   WILDCARD
example            *example-default...us-south.containers.appdomain.cloud*  example             web           None

You can access the service at the URL: http://example-default…us-south.containers.appdomain.cloud/home

8. Conclusion

You have now seen how to create a custom Appsody stack with Python that can be used to build an IBM Cloud Object Storage client as a microservice. Stacks are an easy way to manage consistency and adopt best practices across many applications.

You can read more about creating custom Appsody stacks here.