Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Jimmy-Xu/0362361f113d14c09cea0021458653b1 to your computer and use it in GitHub Desktop.
Save Jimmy-Xu/0362361f113d14c09cea0021458653b1 to your computer and use it in GitHub Desktop.
Installing OpenWhisk on Ubuntu Server 16.04

Configuring the OpenWhisk server

This guide contains instructions on manually setting up Openwhisk and CouchDB on a fresh Ubuntu 16.04 server.

The guide is based on the OpenWhisk Ansible README, which at the time of writing is missing some key steps and gotchas - hence this new guide.

1. Dependencies

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git python-pip python-setuptools build-essential libssl-dev libffi-dev python-dev software-properties-common
sudo pip install --upgrade pip
sudo pip install ansible==2.4.1.0

Install Docker:

sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
sudo apt-add-repository 'deb https://apt.dockerproject.org/repo ubuntu-xenial main'
sudo apt-get install docker-engine -y
sudo usermod -aG docker $USER

$ docker -v
Docker version 17.05.0-ce, build 89658be

//enable remote api, http proxy
sudo mkdir /etc/systemd/system/docker.service.d
cat > /etc/systemd/system/docker.service.d/remote-api.conf <<EOF
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:8118/"
Environment="NO_PROXY=localhost,127.0.0.1"
ExecStart=
ExecStart=/usr/bin/dockerd --debug -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock
EOF

sudo systemctl daemon-reload
sudo service docker restart

//view dockerd log
sudo journalctl -u docker.service -f | grep Calling

You can check whether Docker is running via sudo service docker status. Also, importantly, make sure to enable the remote API.

2. CouchDB

We're using a self-hosted CouchDB here, but you can choose to skip this step and use an ephemeral CouchDB or Cloudant instead.

sudo add-apt-repository ppa:couchdb/stable -y
sudo apt-get update
sudo apt-get install couchdb -y

Secure the database and add an admin user:

sudo service couchdb stop
sudo chown -R couchdb:couchdb /usr/share/couchdb /etc/couchdb /usr/bin/couchdb
sudo chmod -R 0770 /usr/share/couchdb /etc/couchdb /usr/bin/couchdb
sudo service couchdb start
curl -X PUT localhost:5984/_config/admins/USERNAME -d '"PASSWORD"'

Set the reduce_limit property to false (as per OpenWhisk instructions):

curl -X PUT localhost:5984/_config/query_server_config/reduce_limit -d '"false"' -u USERNAME:PASSWORD

Also set bind_address=0.0.0.0 in /etc/couchdb/local.ini and restart via sudo service couchdb restart to access CouchDB from Docker containers: running curl <your CouchDB IP>:5984 should now output CouchDB info.

3. OpenWhisk

Important! Run the following Ansible commands with the root user (e.g. via sudo su -), since using another username seems to mess up the database table names!

git clone https://github.com/openwhisk/openwhisk.git
cd openwhisk
(cd tools/ubuntu-setup && ./all.sh)
===> 
installing basics: ntp, git, zip
installing python dependences: pip, argcomplete, couchdb
installing java: oracle-java8
install scala
installing docker  ====》 since docker was installed above,  the docker install script can be disabled here
installing ansible

Configure our database parameters:

cd ansible
export OW_DB=CouchDB
export OW_DB_PROTOCOL=http
export OW_DB_HOST=<the IP of your CouchDB server (should be accessible from Docker containers)>
export OW_DB_PORT=5984
export OW_DB_USERNAME=USERNAME
export OW_DB_PASSWORD=PASSWORD

//test access couchdb
$ curl $OW_DB_HOST:$OW_DB_PORT
{"couchdb":"Welcome","uuid":"44460abe48f7a3eaf21af8fbf8363093","version":"1.6.1","vendor":{"name":"Ubuntu","version":"16.04"}}


ansible-playbook setup.yml

Build

Now db_local.ini should contain the correct DB settings. Let's continue with building OpenWhisk (it'll take a while):

ansible-playbook prereq.yml
cd ~/openwhisk
./gradlew distDocker

====>
BUILD SUCCESSFUL in ?????s
44 actionable tasks: 31 executed, 13 up-to-date

Deploy

And deploying it:

cd ansible
ansible-playbook initdb.yml
ansible-playbook wipe.yml
ansible-playbook apigateway.yml
ansible-playbook openwhisk.yml
ansible-playbook postdeploy.yml
$ docker ps
CONTAINER ID        IMAGE                        COMMAND                  CREATED             STATUS              PORTS                                                              NAMES
0149a3f5f33f        nginx:1.11                   "nginx -g 'daemon ..."   About an hour ago   Up About an hour    0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, 0.0.0.0:8443->8443/tcp   nginx
8b63ba543d70        whisk/nodejs6action:latest   "/bin/sh -c 'node ..."   About an hour ago   Up About an hour                                                                       wsk1_5_prewarm_nodejs6
960f9c3099e4        whisk/nodejs6action:latest   "/bin/sh -c 'node ..."   About an hour ago   Up About an hour                                                                       wsk0_5_prewarm_nodejs6
c02926fc8604        whisk/nodejs6action:latest   "/bin/sh -c 'node ..."   About an hour ago   Up About an hour                                                                       wsk1_3_prewarm_nodejs6
ef7f2d5e6947        whisk/nodejs6action:latest   "/bin/sh -c 'node ..."   About an hour ago   Up About an hour                                                                       wsk0_4_prewarm_nodejs6
df1c90bb12b2        whisk/invoker:latest         "/bin/sh -c 'exec ..."   About an hour ago   Up About an hour    0.0.0.0:12002->8080/tcp                                            invoker1
0a48e32adb16        whisk/invoker:latest         "/bin/sh -c 'exec ..."   About an hour ago   Up About an hour    0.0.0.0:12001->8080/tcp                                            invoker0
2be1cec82dec        whisk/controller:latest      "/bin/sh -c 'expor..."   About an hour ago   Up About an hour    0.0.0.0:8000->2551/tcp, 0.0.0.0:10001->8080/tcp                    controller0
0b48b19bfac5        whisk/controller:latest      "/bin/sh -c 'expor..."   About an hour ago   Up About an hour    0.0.0.0:8001->2551/tcp, 0.0.0.0:10002->8080/tcp                    controller1
3bbac39d2e79        ches/kafka:0.10.2.1          "/start.sh"              About an hour ago   Up About an hour    7203/tcp, 0.0.0.0:9092->9092/tcp                                   kafka
e4cd9c1d4001        zookeeper:3.4                "/docker-entrypoin..."   About an hour ago   Up About an hour    2888/tcp, 0.0.0.0:2181->2181/tcp, 3888/tcp                         zookeeper
cc740909178b        openwhisk/apigateway:0.8.2   "/usr/local/bin/du..."   About an hour ago   Up About an hour    80/tcp, 8423/tcp, 0.0.0.0:9000->9000/tcp, 0.0.0.0:9001->8080/tcp   apigateway
c73a0ebf3305        redis:3.2                    "docker-entrypoint..."   About an hour ago   Up About an hour    0.0.0.0:6379->6379/tcp                                             redis

FAQ: $ go godep: error downloading dep (golang.org/x/sys/unix): unrecognized import path "golang.org/x/sys/unix" ===> https://github.com/Jimmy-Xu/incubator-openwhisk (patch)

Config CLI

  • set apihost
  • set auth key
$ cd ~/openwhisk
$ ./bin/wsk property set --apihost 172.17.0.1
ok: whisk API host set to 172.17.0.1

$ ./bin/wsk property set --auth `cat ansible/files/auth.guest`
ok: whisk auth set. Run 'wsk property get --auth' to see the new value.

use action

$ cd ~/openwhisk
$ ./bin/wsk -i sdk install docker

$ tree dockerSkeleton/
dockerSkeleton/
├── buildAndPush.sh
├── Dockerfile
├── example.c
└── README.md

$ cat dockerSkeleton/example.c
#include <stdio.h>
int main(int argc, char *argv[]) {
    printf("This is an example log message from an arbitrary C program!\n");
    printf("{ \"msg\": \"Hello from arbitrary C program!\", \"args\": %s }",
           (argc == 1) ? "undefined" : argv[1]);


$ docker login -u xjimmyshcn -p <password>
$ cd dockerSkeleton
$ ./buildAndPush.sh xjimmyshcn/blackboxdemo

$ cd ..
$ docker images xjimmyshcn/blackboxdemo
REPOSITORY                TAG                 IMAGE ID            CREATED             SIZE
xjimmyshcn/blackboxdemo   latest              6b5a7df02bab        13 minutes ago      110MB

//creaete action
$ ./bin/wsk -i action create example --docker xjimmyshcn/blackboxdemo
ok: created action example

$ ./bin/wsk -i action list
actions
/guest/example                                                         private blackbox

//invoke action
$ ./bin/wsk -i action invoke --result example --param payload Hyper
or
$ ./bin/wsk -i action invoke --result /guest/example --param payload Hyper
{
    "args": {
        "payload": "Hyper"
    },
    "msg": "Hello from arbitrary C program!"
}

$ docker ps
CONTAINER ID        IMAGE                        COMMAND                  CREATED             STATUS              PORTS                                                              NAMES
f3fa8e797890        xjimmyshcn/blackboxdemo      "/bin/bash -c 'cd ..."   14 seconds ago      Up 13 seconds                                                                          wsk1_5_guest_example
//the container above will keep 10 minutes

$ docker logs wsk1_5_guest_example
This is an example log message from an arbitrary C program!
XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX
XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX

//watch dockerd log
$ sudo journalctl -u docker.service -f | grep Calling
Nov 17 06:18:34 osboxes dockerd[1863]: time="2017-11-17T06:18:34.990026565-05:00" level=debug msg="Calling POST /v1.24/images/create?fromImage=xjimmyshcn%2Fblackboxdemo&tag=latest"
Nov 17 06:18:40 osboxes dockerd[1863]: time="2017-11-17T06:18:40.130948535-05:00" level=debug msg="Calling POST /v1.24/containers/create?name=wsk1_5_guest_example"
Nov 17 06:18:40 osboxes dockerd[1863]: time="2017-11-17T06:18:40.352035305-05:00" level=debug msg="Calling POST /v1.24/containers/f3fa8e7978902237352f953eaccaae54007dc49e2c3a93030da40839d3af1e37/start"
Nov 17 06:28:45 osboxes dockerd[1863]: time="2017-11-17T06:28:45.128940066-05:00" level=debug msg="Calling DELETE /v1.24/containers/f3fa8e7978902237352f953eaccaae54007dc49e2c3a93030da40839d3af1e37?force=1"

use package

$ ./bin/wsk -i package list  /guest

$ ./bin/wsk -i package list  /whisk.system
packages
/whisk.system/weather                                                  shared
/whisk.system/watson-textToSpeech                                      shared
/whisk.system/utils                                                    shared
/whisk.system/websocket                                                shared
/whisk.system/watson-speechToText                                      shared
/whisk.system/combinators                                              shared
/whisk.system/samples                                                  shared
/whisk.system/watson-translator                                        shared
/whisk.system/github                                                   shared
/whisk.system/slack                                                    shared

//create package: https://github.com/apache/incubator-openwhisk/blob/master/docs/packages.md#creating-a-package 
$ ./bin/wsk -i package create custom
ok: created package custom

$ ./bin/wsk -i package get --summary custom
package /guest/custom
   (parameters: none defined)

//Share a package
$ ./bin/wsk -i package update custom --shared yes
ok: updated package custom

$ ./bin/wsk -i package get custom | grep publish
    "publish": true,


//create action in custom package
$ ./bin/wsk -i action create custom/identity identity.js
ok: created action custom/identity

$ ./bin/wsk -i action create custom/example --docker xjimmyshcn/blackboxdemo
$ ./bin/wsk -i action invoke --result custom/example --param payload Hyper

invoke action via curl

export NAMESPACE=guest
export AUTH='Authorization: Basic '`./bin/wsk -i property get --auth | awk '{printf("%s", $3)}' | base64 --wrap=0`
export TYPE="Content-Type: application/json"
$ curl -s -k -H "$TYPE" -H "$AUTH" https://172.17.0.1/api/v1/namespaces/$NAMESPACE | jq ".packages"
[
  {
    "name": "custom",
    "binding": false,
    "publish": true,
    "annotations": [],
    "version": "0.0.3",
    "namespace": "guest"
  }
]

$ curl -s -k -H "$TYPE" -H "$AUTH" https://172.17.0.1/api/v1/namespaces/$NAMESPACE/actions | jq "."
[
  {
    "name": "example",
    "publish": false,
    "annotations": [
      {
        "key": "exec",
        "value": "blackbox"
      }
    ],
    "version": "0.0.1",
    "namespace": "guest/custom"
  },
  {
    "name": "identity",
    "publish": false,
    "annotations": [
      {
        "key": "exec",
        "value": "nodejs:6"
      }
    ],
    "version": "0.0.1",
    "namespace": "guest/custom"
  },
  {
    "name": "example",
    "publish": false,
    "annotations": [
      {
        "key": "exec",
        "value": "blackbox"
      }
    ],
    "version": "0.0.1",
    "namespace": "guest"
  },
  {
    "name": "hello",
    "publish": false,
    "annotations": [
      {
        "key": "exec",
        "value": "nodejs:6"
      }
    ],
    "version": "0.0.1",
    "namespace": "guest"
  }
]

//asynchronous
$ curl -s -k -H "$TYPE" -H "$AUTH" -X POST -d '{"payload":"Hyper"}' https://172.17.0.1/api/v1/namespaces/$NAMESPACE/actions/example
{"activationId":"4936a64ad1c14f2db6a64ad1c1ff2d1d"}

//synchronous
$ curl -s -k -H "$TYPE" -H "$AUTH" -X POST -d '{"payload":"Hyper"}' https://172.17.0.1/api/v1/namespaces/$NAMESPACE/actions/example?blocking=true | jq ".response.result"
{
  "args": {
    "payload": "Hyper"
  },
  "msg": "Hello from arbitrary C program!"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment