Showing posts with label Docker. Show all posts
Showing posts with label Docker. Show all posts

Friday, December 25, 2020

Build your own COVID-19 Data Analytics Leveraging Open Source - Serverless Fn & Autonomous Database

Firstly, a huge thanks to all the frontline workers, healthcare professionals, technology contributions, non-profit organizations and everyone else who are fighting the pandemic everyday amidst the risks involved and more importantly the sacrifices - including the most important thing that can never be retrieved - TIME.

As Oracle Cloud continues to aid COVID-19 vaccine research & trials and also help manage the COVID-19 vaccine distribution program, I came up with a simple (humble) contribution that helps analyze and report COVID-19 data.

Although there are several dashboards and reports readily available on the web, they cater to a specific region, locale & metric. For example, what if? one would like to understand the total COVID-19 cases reported in Belarus on/up-to a specific date sliced by total tests conducted, new cases that were tested positive, hospitalization ratio per million against a median age group?

Data is publicly available but making sense of it is the key. In this article, we will see how we can build our own COVID-19 analytics - leveraging simple & popular open source tools and technology with the help of public cloud (Eg. Autonomous Database in Oracle Cloud - that is auto-managed, auto-tuned & auto-patched) [PS: You can also replace Autonomous DB with MySQL]. What's more? - we can potentially achieve this for free with the Always Free cloud instance.

Let's quickly take a look at the high-level solution architecture;


Each component of this architecture is designed to be loosely coupled and can be replaced or further enhanced for functionality/convenience. For instance, I have leveraged Apache open-source serverless Fn project that natively runs on Oracle Cloud - this can be replaced with a Node.js or java code running on K8s-Docker container. Similarly, the Autonomous Database can be replaced with a MySQL DB 

Let's take a look at the key components of this solution;

1) Source dataset [Courtesy: Our World in Data]

"Our World in Data" offers COVID-19 data in a variety of data formats and most importantly offers daily updates - so we can keep our analytics up-to-date.

In our case, we get the dataset in csv format here

2) Python script deployed on Oracle Fn

I have leveraged the Oracle Cloud Functions (based on Apache Fn) serverless platform to deploy the simple python script to download the COVID-19 dataset into an object storage bucket.

The choice of Oracle Cloud Functions is particularly helpful in this case because I don't have to manage any infrastructure or deal with packaging the docker container and version control them. It lets me focus only on the business logic. Also, it supports a variety of programming languages natively including Python, Go & Java. Most importantly, it has built-in security and offers out of the box support for event notifications & triggers and ability to expose functions as APIs.

Pre-Req: 

Create a dynamic group for Oracle Functions and ensure you have a policy defined in your compartment/tenancy for Oracle Functions the ability to access / read csv in the object storage bucket

Instances that meet the criteria defined by any of these rules will be included in the dynamic group.

ALL {resource.type = 'fnfunc', resource.compartment.id = 'ocid1.compartment.oc1..abcdefgxyz'}

Allow dynamic-group FnDynamicGroup to manage objects in compartment sathya.ag

Let's create an Oracle Functions application;

Oracle Cloud -> Developer Services -> Functions -> Create Application & give it a name

Applications lets us group several Oracle Functions. To create a serverless function;

For quick setup, you can leverage the Cloud Shell under the Getting Started instructions to deploy the following python code. Oracle functions platform packages the code as a docker container, uploads the docker image to the default Oracle Cloud docker registry and automatically deploys it as a serverless function with an invoke endpoint.

import io
import json
import oci
import csv
import requests
import logging
import os
import urllib.request

from fdk import response

def progress_callback(bytes_uploaded):
    print("{} additional bytes uploaded".format(bytes_uploaded))

def handler(ctx, data: io.BytesIO=None):
    logging.getLogger().info("Got incoming request")
    signer = oci.auth.signers.get_resource_principals_signer()
    object_name = bucket_name = namespace = ""
    try:
        cfg = ctx.Config()
        input_bucket = cfg["input-bucket"]
        processed_bucket = cfg["processed-bucket"]
        input_csv = cfg["input-csv"]
        object_name = cfg["object-name"]
    except Exception as e:
        print('Missing function parameters: bucket_name', flush=True)
        raise
    logging.getLogger().info("before calling load data {0} {1} {2}".format(input_bucket,
 input_csv, object_name))
    
    
    logging.getLogger().info("download start!")
    filename, headers = urllib.request.urlretrieve(input_csv, filename="/tmp/covid.csv")
    logging.getLogger().info("download complete!")
    
    load_data(signer, namespace, input_bucket, filename, object_name)
    #move_object(signer, namespace, input_bucket, processed_bucket, object_name)

    return response.Response(
        ctx, 
        response_data=json.dumps({"status": "Success"}),
        headers={"Content-Type": "application/json"}
    )
    
def load_data(signer, namespace, bucket_name, input_csv, object_name):
    logging.getLogger().info("inside load data function {0} {1} {2}".format(signer, 
namespace, bucket_name))
    client = oci.object_storage.ObjectStorageClient(config={}, signer=signer)
    try:
        print("INFO - About to read object {0} from local folder and upload to bucket {1}
...".format(object_name, bucket_name), flush=True)
        namespace = client.get_namespace().data
        
        # Use UploadManager to do multi-part upload of file, with 3 Parallel uploads
        logging.getLogger().info("before calling uploadmanager")
        upload_manager = oci.object_storage.UploadManager(client, 
allow_parallel_uploads=True, parallel_process_count=3)
        response = upload_manager.upload_file(namespace, bucket_name, object_name, 
input_csv, progress_callback=progress_callback)
        logging.getLogger().info("response status {0}".format(response.status))
        if (response.status == 200):
            
            message = "Successfully  uploaded %s in bucket %s." % (object_name, 
bucket_name)
            return True

    except Exception as e:
        logging.getLogger().info("exception message {0}".format(e))
        message = " Image upload Failed  in bucket %s. " % bucket_name
        if "oci" in e.__class__.__module__:
            if hasattr(e, 'message'):
                message = message + e.message
            else:
                message = message + repr(e)
                print(message)
        return False

In the configuration section, provide the key value pairs that can be dynamically processed by Oracle Functions at invoke.

3) COVID Dataset in Object Storage

Let's verify if the COVID-19 dataset is successfully downloaded into our object storage bucket.

4) Loading COVID-19 dataset into Autonomous Database

Since we are leveraging Oracle Cloud Autonomous DB, we can leverage the OOTB cloud SQL package to load data from an external object storage bucket. Another variant of this approach could be to leverage the csv data in object storage as an external table and ADB lets you query on the csv data directly.

Again, the choice for Autonomous Database helps us focus only on loading and querying the dataset and not have to worry about the underlying infrastructure, patching & maintenance. I like to think of Autonomous DB as a "serverless" database.

Execute the DBMS_CLOUD.COPY_DATA procedure to load data from object storage into ADB. [Ensure you have the base table created to hold the COVID-19 dataset]

BEGIN
 DBMS_CLOUD.COPY_DATA(
    table_name =>'COVID',
    credential_name =>'JSON_CRED_AG',
    file_uri_list =>'YOUR OBJECT STORAGE BUCKET URI',
    format => json_object('type' value 'CSV', 'ignoremissingcolumns' value 'true', 
'delimiter' value ',', 'blankasnull' value 'true', 'skipheaders' value '1', 'dateformat' value 'YYYY-MM-DD')
 );
END;
/

5) Analytics Dashboard

Now that we have our data in a database, we can leverage any analytics / reporting engine to make sense of the data and generate dynamic reports. In our case, we leverage Oracle Analytics and/or Oracle Data Visualization.



Wednesday, February 8, 2017

Zero-2-Eventing in minutes: Dockerize Apache Kafka on Oracle Container Cloud

Messaging platform with extreme scaling, fault-tolerance, replication, parallelism, real-time streaming and load balancing - Apache Kafka is arguably the most commonly used distributed messaging platform today.

A few weeks ago, I was working with one of my customers on their enterprise cloud strategy. They are one of the largest retail brands in the US. As part of their rationalization exercise and "Pivot to the Cloud" strategy, their Kafka event hub had to be containerized and deployed on cloud infrastructure.

The idea of this blog post is to walk you through running a full-stack Docker based Apache Kafka + Zookeeper cluster on Oracle Container Cloud in a matter of minutes without having to deal with the complex infrastructure/network setup, Docker toolset installs, upgrades and maintenance.

If you are new to Oracle Container Cloud, please refer to my earlier blog here.

If you would like to get a feel of the Oracle Container Cloud service, head out to https://cloud.oracle.com/en_US/tryit and request a fully-featured instance.

Once you are logged-in as a cloud administrator, click on Container Cloud Service from the list of services available on the cloud dashboard.

In the Oracle Container Cloud Service console, click "Create Service" to create a new Container Cloud Service instance.

Define the service details on the "Create Service" page. Click Next and Confirm.

Give it a few minutes and you will find a Container Manager Node and Worker Nodes provisioned for use. Click on the service to explore the service details.

Click on the hamburger menu on the container service and choose "Container Console" to open the service administrator console. Login using the administrator user (provided during the service creation).

For users of Apache Kafka on Docker, you would be aware of tens of publicly available containers.

If you are looking to have a simple single container Kafka service where Zookeeper and Kafka brokers co-exist on a single container, I have found spotify/kafka easy to setup & use.
For the more complex multi-tier setup, where Zookeeper and Kafka brokers run on dedicated container nodes, wurstmeister/kafka is the most popular option.

Since, I want to demonstrate how to provision a production grade Kafka stack on Oracle Container Cloud, we will go with the wurstmeister/kafka docker image

Go to the Services section and click "New Service" button. You can see that OCCS offers multiple options to define a service container;

  1. Builder: For the not-so-tech-savvy users where you can simply enter service details and OCCS takes care of building the docker commands for you
  2. Docker Run: If you are a Docker pro, you can simply head out to this tab and enter your Docker Run commands directly. This is also a great option, if you already have existing Docker setup which allows you to simply copy paste your Docker Run command
  3. YAML: For the YAML lovers, you can also define your service using YAML constructs

The cool thing is that, you can use any / either / a combination of these options to define and create your container service. Any changes you make on any of these will reflect immediately on the other automagically.

Let's use the "Builder" tab to define our first Kafka service.

Service Name: Provide a name for the Kafka service. Notice that the service ID is automatically generated which will be used to uniquely identify our service.

Service Description: Describe the service. Eg., My Kafka Event Hub.
Notice that this would automatically create a environment variable "occs:description"

Scheduler: Determines how & where containers will be provisioned across hosts.

Availability: Define availability of the service based on pool, host or tags.

Image: Enter "wurstmeister/kafka" (without quotes).
Since this is a public image available on docker hub, OCCS can pull this automatically. Remember you can also pull from private docker registries that you might have. If so, head over to "Registries" section on the main console to add your docker registry.

Command: If you want to run some commands on container startup that goes here.

In the "Available Options" panel, choose "Ports". This will add a new "Ports" section to your Builder panel. Click "Add". This will define on what port our Kafka service would run.
Leave the IP field empty (this would default to the container IP based on the host it would run - determined dynamically). Enter host port as 9092, container port as 9092 and choose TCP for protocol.
Your first Kafka service should look like below.

Now, head over to the "Docker Run" and "YAML" tabs and notice the service definition created automagically in the background while we were defining the service. Click "Save" to exit.

Let's now create another definition for our Zookeeper service. Kafka uses Zookeeper for cluster and member management.
Follow the same steps as earlier to create the new Zookeeper service which would run on port 2181.

Your Zookeeper service should look like below. Save & Exit.

Now that we have our Kafka and Zookeeper services ready, time to link them up together for our full-fledged Kafka stack on cloud.

Go to "Stacks" section and click "New Stack".
Note: This is the Docker Compose feature. If you already had your Docker Compose YAML files, you can simply copy-paste here to stack up your services.

Provide the new stack a name: MyKafkaStack (This would create a stack id automatically to uniquely identify the stack).

Notice all the services displayed on the right under the "Available Services" section.

Similar to the "Service" definition, "Stacks" offer 2 modes to define and create stacks. Either drag & drop services on UI (or) click on "Advanced Editor" to wire services using YAML constructs. Even better, use a combination of both.
Let's use a combination.

Let's drag & drop MyKafka and MyZookeeper services on to the "Stacks" screen.

Click on "Advanced Editor" to open the YAML composer. Immediately notice that the YAML script is generated based on the service we composed on the UI (drag & drop).

The Kafka service requires a few environment variables to be set to expose itself for external connectivity. Add the following environment variables to the YAML editor under the "MyKafka" service.

- "KAFKA_ADVERTISED_HOST_NAME={{hostip_for_interface .HostIPs \"public_ip\"}}"
- KAFKA_ADVERTISED_PORT=9092
- "KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181"

Note: We want the stack to run on "Any Host" irrespective of IP address changes. The expression above will fetch the IP address of the host dynamically at run-time. You can leverage the "Tips & Tricks" option in the editor to see some tips & examples.

Define the links under the "MyKafka" service to link it to our Zookeeper container, using the YAML construct below;

links:
    -"MyZookeeper:zookeeper"

Ensure that your stack editor looks like below and click Done to exit. Save to exit the stack editor.

Note: A link is shown on the UI indicating the Kafka service is "linked" to the Zookeeper.

OCCS offers a convenient single-click deployment of stacks. Click "Deploy" next to the "MyKafkaStack" to deploy both Kafka and Zookeeper services.

On successful deployment, you should see 2 healthy services running. Note that OCCS allows you to define health checks on containers.

You can also define "webhooks" for your Continuous Integration (CI) / Continuous Delivery (CD) capabilities.

Let's quickly test our new Kafka stack. I am using my local Kafka command line client to test my Kafka service. First create a new topic, start the producer and consumer scripts in your terminals.

We just deployed a Apache Kafka Zookeeper Docker stack on Oracle Cloud. You can now start scaling your Kafka cluster, add more container/hosts and dynamically scale up/down and use this as your cloud-based event hub.

In my next blog, we will see how to rapidly deploy a LAMP stack application on Oracle Container Cloud. Stay Tuned!

Tuesday, February 7, 2017

Simplify Cloud Native, Microservices DevOps with Oracle Container Cloud

"Containers" are becoming the new normal and an indispensable part of cloud native / microservices development. If you are new to the concept of containers, open a new tab and google. Container benefits are out of scope of this article.
With respect to cloud-native development, containers provide DevOps 2 huge benefits;

  • Robust foundation for microservices "style" architecture & scalability
  • Environment parity (Dev-Test-Prod) and seamless hybrid deployment

All things considered, containers are great for "Dev". Are they good for "Ops"?

With even more services to manage, monitor & maintain, containers certainly pose some challenges unless you have a robust, easy to provision management and monitoring platform.

Oracle Container Cloud Service aims to solve exactly that problem. With comprehensive tooling to compose, deploy, orchestrate and manage container-based apps, Oracle container cloud enables rapid creation, deployment & management of enterprise-grade container infrastructure.

Let's take a peek under the hood;

Spin-up or Tear-down containers at-will:

Whether you are looking to quickly setup an infrastructure for testing your container apps or setting up a production-grade container infrastructure to run your apps, you can do it all with just a few clicks.

Oracle container cloud automatically provisions a manager node which will act as the "container management" server and you have the ability to configure the shape and size of the hosts on which your containers would run - called "worker nodes".

Group or Assign hosts to different pools for resource segregation using the "Resource Pools" feature.

In addition, "Tags" feature allows you to tag your resource pools, hosts, services and deployments. Tags provide fine-grained control over hosts/resource pools on which a service/stack can be deployed on.

Discover & Manage DNS information of all your running docker containers from the "Service Discovery" page.

BYOD (Bring Your Own Docker containers) or Start with example stacks:

Oracle container cloud links to the public docker hub registry out-of-the-box where you can pull from thousands of docker images. Whether you have a public docker repository or a private docker hub, you can add them to the container cloud docker registry.

If you are new to Docker containers, you can jumpstart with some of the in-built example services and stacks - Nginx, Apache HTTP server, Mongo, MySQL, MariaDB, Busybox, HAProxy, Wordpress etc..

Focus on building your apps and service stacks:

As I mentioned earlier, the operational complexity with containers and microservices is with the complex orchestration scripts, dependency management, scaling and deployment. Oracle container cloud stands-out in this respect - providing the ability to create single-click deployment of the entire stack, built-in service discovery, quick import existing Docker Run / Docker Compose YAML and on-click scale - all from a single pane of glass.

When it's time to fly:

After successful deployment of Docker containers, it's highly critical to gain insight into your container apps and services.
Oracle Container Cloud offers simple yet powerful monitoring & management dashboards to monitor container/host performance, container health, event audit logs. To top it, OCCS also maintains the running state of the app with self-healing application deployments.

Any modern cloud offering is never complete without REST APIs. OCCS offers complete suite of REST APIs to configure, deploy, administer, monitor, orchestrate & scale your container apps/services.

In my next article here, I will walk you through on how to deploy a full-stack Apache Kafka service with Zookeeper in minutes.

Eager to get started? Get a free trial of the Oracle Container Cloud here and let me know your feedback.