qinling/doc/source/quick_start.rst
Lingxian Kong b72d57c6c7 Correct devstack config in the doc
etcd service must be disabled in devstack environment.

Change-Id: I327653fb81e408d33327e56dbbc9770a7593f966
2017-09-26 01:08:45 +13:00

10 KiB

Quick Start

Installation

A fast and simple way to try Qinling is to create a Vagrant VM including all related components and dependencies of Qinling service. For quick installation, evaluation, and convenience, Qinling team provides a Vagrantfile in tools/vagrant folder.

Note

You can also install Qinling service in OpenStack devstack environment, please refer to http://qinling.readthedocs.io/en/latest/contributor/development-environment-devstack.html.

Qinling is a FaaS implemented on top of container orchestration system such as Kubernetes, Swarm, etc. Particularly, Kubernetes is a reference backend considering its popularity. So, you need to setup Kubernetes first before installing Qinling. The easiest way to setup Kubernetes is to use Minikube, it runs a single-node Kubernetes cluster inside a VM alongside Qinling vagrant VM, so they can communicate with each other without any network configuration.

Note

In order to manage resources on Kubernetes, it is recommended to install kubectl command line tool.

Qinling can work with OpenStack Keystone for authentication, or it can work without authentication at all. By default, authentication is enabled, set auth_enable = False to enable authentication.

After Kubernetes installation, perform the following commands on your local host.

  1. Setup HTTP proxy to access the Kubernetes API:

    $ kubectl proxy --accept-hosts='.*' --address='0.0.0.0'
    Starting to serve on [::]:8001
  2. Clone Qinling repo and go to vagrant directory:

    $ git clone https://github.com/openstack/qinling.git
    $ cd qinling/tools/vagrant
  3. Modify Qinling sample config file according to your own environment. Suppose your IP address of your local host is 192.168.200.50, default Kubernetes API HTTP proxy port is 8001, and Qinling vagrant VM IP address is 192.168.33.18 (the default value in Vagrantfile):

    $ sed -i 's/KUBERNETES_API_HOST/192.168.200.50/' qinling.conf.sample
    $ sed -i 's/KUBERNETES_API_PORT/8001/' qinling.conf.sample
    $ sed -i 's/QINLING_API_ADDRESS/192.168.33.18/' qinling.conf.sample
  4. Now, start Qinling vagrant VM:

    $ vagrant --version
    Vagrant 1.9.1
    $ vagrant up
    ...
    ==> default: INFO  [alembic.runtime.migration] Context impl MySQLImpl.
    ==> default: INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
    ==> default: INFO  [alembic.runtime.migration] Running upgrade  -> 001, Pike release

    If you see message like the above, congratulations, your own Qinling service is up and running!

Getting started with Qinling

Note

Currently, you can interact with Qinling using python-qinlingclient or sending RESTful API directly. Both ways are described in this guide. httpie is a convenient tool to send HTTP request, it has been installed automatically inside the vagrnat VM.

Perform following commands on your local host, we will create runtime/function/execution during the process.

  1. (Optional) Prepare a docker image including development environment for a specific programming language. For your convenience, there is a pre-built image openstackqinling/python-runtime that you could directly use to create runtime in Qinling. Only Python 2 runtime is supported for now, but it is very easy to add another program language support. If you indeed want to build a new image, run the following commands in qinling repo directory, replace DOCKER_USER with your own docker hub username:

    $ cd runtimes/python2
    $ docker build -t DOCKER_USER/python-runtime .
    $ docker push DOCKER_USER/python-runtime
  2. Create runtime. runtime in Qinling is running environment for a specific language, this resource is supposed to be created/deleted/updated by cloud operator. After creation, check the runtime status until it's available before you execute any functions:

    $ http POST http://192.168.33.18:7070/v1/runtimes name=python2.7 \
      image=DOCKER_USER/python-runtime
    
    HTTP/1.1 201 Created
    Connection: keep-alive
    Content-Length: 194
    Content-Type: application/json
    Date: Fri, 12 May 2017 04:37:08 GMT
    
    {
        "created_at": "2017-05-12 04:37:08.129860",
        "id": "c1d78623-56bf-4487-9a72-1299b2c55e65",
        "image": "DOCKER_USER/python-runtime",
        "name": "python2.7",
        "project_id": "default",
        "status": "creating"
    }
    
    $ http GET http://192.168.33.18:7070/v1/runtimes/c1d78623-56bf-4487-9a72-1299b2c55e65
    
    HTTP/1.1 200 OK
    Connection: keep-alive
    Content-Length: 246
    Content-Type: application/json
    Date: Fri, 12 May 2017 04:37:50 GMT
    
    {
        "created_at": "2017-05-12 04:37:08",
        "description": null,
        "id": "c1d78623-56bf-4487-9a72-1299b2c55e65",
        "image": "DOCKER_USER/python-runtime",
        "name": "python2.7",
        "project_id": "default",
        "status": "available",
        "updated_at": "2017-05-12 04:37:08"
    }

    Using CLI:

    $ openstack runtime create python2.7 DOCKER_USER/python-runtime
    +------------+--------------------------------------+
    | Field      | Value                                |
    +------------+--------------------------------------+
    | id         | c1d78623-56bf-4487-9a72-1299b2c55e65 |
    | name       | python2.7                            |
    | image      | DOCKER_USER/python-runtime           |
    | project_id | default                              |
    | status     | available                            |
    | created_at | 2017-05-12 04:37:08.129860           |
    | updated_at |                                      |
    +------------+--------------------------------------+
  3. Create a customized function package:

    $ mkdir ~/qinling_test
    $ cat <<EOF > ~/qinling_test/main.py
      import requests
      def main(*args, **kwargs):
          r = requests.get('https://api.github.com/events')
          return len(r.json())
      if __name__ == '__main__':
          main()
      EOF
    $ pip install requests -t ~/qinling_test
    $ cd ~/qinling_test
    $ zip -r ~/qinling_test/qinling_test.zip ./*
  4. Create function, runtime_id comes from the output of the above command:

    $ http -f POST http://192.168.33.18:7070/v1/functions name=github_test \
        runtime_id=c1d78623-56bf-4487-9a72-1299b2c55e65 \
        code='{"package": "true"}' \
        package@~/qinling_test/qinling_test.zip
    
    HTTP/1.1 201 Created
    Connection: keep-alive
    Content-Length: 234
    Content-Type: application/json
    Date: Fri, 12 May 2017 04:49:59 GMT
    
    {
        "code": {
            "package": "true"
        },
        "created_at": "2017-05-12 04:49:59.659345",
        "description": null,
        "entry": "main.main",
        "id": "352e4c02-3c6b-4860-9b85-f72344b1f986",
        "name": "github_test",
        "runtime_id": "c1d78623-56bf-4487-9a72-1299b2c55e65"
    }

    Using CLI:

    $ openstack function create github_test \
        c1d78623-56bf-4487-9a72-1299b2c55e65 \
        '{"source": "package"}' \
        --package ~/qinling_test/qinling_test.zip
    +------------+--------------------------------------+
    | Field      | Value                                |
    +------------+--------------------------------------+
    | id         | 352e4c02-3c6b-4860-9b85-f72344b1f986 |
    | name       | github_test                          |
    | count      | 0                                    |
    | code       | {u'source': u'package'}              |
    | runtime_id | c1d78623-56bf-4487-9a72-1299b2c55e65 |
    | entry      | main.main                            |
    | created_at | 2017-05-12 04:49:59.659345           |
    | updated_at |                                      |
    +------------+--------------------------------------+
  5. Invoke the function by specifying function_id:

    $ http POST http://192.168.33.18:7070/v1/executions \
        function_id=352e4c02-3c6b-4860-9b85-f72344b1f986
    
    HTTP/1.1 201 Created
    Connection: keep-alive
    Content-Length: 255
    Content-Type: application/json
    Date: Thu, 11 May 2017 23:46:12 GMT
    
    {
        "created_at": "2017-05-12 04:51:10",
        "function_id": "352e4c02-3c6b-4860-9b85-f72344b1f986",
        "id": "80cd55be-d369-49b8-8bd5-e0bfc1d20d25",
        "input": null,
        "output": "{\"result\": 30}",
        "status": "success",
        "sync": true,
        "updated_at": "2017-05-12 04:51:23"
    }

    Using CLI:

    $ openstack function execution create 352e4c02-3c6b-4860-9b85-f72344b1f986
    +-------------+------------------------------------------------------------+
    | Field       | Value                                                      |
    +-------------+------------------------------------------------------------+
    | id          | 80cd55be-d369-49b8-8bd5-e0bfc1d20d25                       |
    | function_id | 352e4c02-3c6b-4860-9b85-f72344b1f986                       |
    | input       | {}                                                         |
    | output      | {"result": {"duration": 1.2511260509490967, "output": 30}} |
    | status      | success                                                    |
    | sync        | True                                                       |
    | created_at  | 2017-05-12 04:51:10                                        |
    | updated_at  | 2017-05-12 04:51:23                                        |
    +-------------+------------------------------------------------------------+

    If you invoke the same function again, you will find it is much faster due to Qinling cache mechanism.