OpenWhisk on Ubuntu 16.10をためしてみる

首題の通り、OpenWhiskをUbuntu 16.10マシン1台で動かしてみたのでメモ。

# はじめに
諸事情により急ぎでOpenWhiskのローカル環境を用意しようと思い、Ubuntuマシンを立てました。
なにも気にせず仮想マシンを用意してしまったので、バージョンは16.10 (kernelは4.8)でした。

```bash
$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.10
DISTRIB_CODENAME=yakkety
DISTRIB_DESCRIPTION="Ubuntu 16.10"`
```

だけど、システム要件ははっきりしておらず、[Setting up OpenWhisk on Ubuntu server(s)](https://github.com/apache/incubator-openwhisk/blob/master/tools/ubuntu-setup/README.md)には14.04.03での導入手順例があるのみ。

過去の[OpenWhisk Advent Calendar](http://qiita.com/advent-calendar/2016/openwhisk) を見たり、Webで検索すると、16.04で導入できなかったような書き込みがある。ちょっと心配。。

まあ最近ヌルSE状態なので、久しぶりに問題判別スキルを磨くためにも、このまま進めてみました。
先入観なしで作業を進めたかったので、今回は先人のハマりポイントはあえて見ずに実施してみました。

# 実際にやってみた
まっさらなOSからのスタートです。

## 導入前の下準備
エチケットとしてまずはAPTライブラリのインデックスを更新し、パッケージを最新の状態にします。

```bash
$ sudo apt-get update
$ sudo apt-get upgrade
```

OpenWhiskのソースコードをGitリポジトリから引っ張ってくるため、gitコマンドを使えるようにします。

```bash
$ sudo apt-get install git -y
```

また、Gitリポジトリから持ってきたソースからビルド処理を行う際に以下のライブラリが先に導入されていないと後で怒られるので、事前に導入しておきます。

```bash
$ sudo apt-get -y install gcc make build-essential libssl-dev libffi-dev python-dev
```

そのほか、Ubuntu固有の環境セットアップ処理でpythonのpipが導入されるのですが、バージョンが古いと怒られるので、事前に手動で導入し、バージョンを更新しておきます。(更新してもprereq処理で警告は出るんですが。。)

```bash
# pipを使えるようにして
$ sudo apt-get -y install python-pip
# バージョン確認し
$ pip --version
pip 8.1.2 from /usr/lib/python2.7/dist-packages (python 2.7)
# 古いので更新する
$ pip install --upgrade pip
Collecting pip
  Downloading pip-9.0.1-py2.py3-none-any.whl (1.3MB)
    100% |████████████████████████████████| 1.3MB 883kB/s 
Installing collected packages: pip
Successfully installed pip-8.1.2
You are using pip version 8.1.2, however version 9.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
openwhisk@ubuntu:~$ pip --version
pip 9.0.1 from /home/openwhisk/.local/lib/python2.7/site-packages (python 2.7)

```

## OpenWhiskのコードを持ってくる
Gitリポジトリからソースをクローンでローカルに持ってきます。

```bash
$ git clone https://github.com/apache/incubator-openwhisk.git openwhisk
Cloning into 'openwhisk'...
remote: Counting objects: 20207, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 20207 (delta 0), reused 0 (delta 0), pack-reused 20204
Receiving objects: 100% (20207/20207), 51.27 MiB | 3.16 MiB/s, done.
Resolving deltas: 100% (11031/11031), done.
Checking connectivity... done.
```

完了したら、ディレクトリを移動し、以下のようなディレクトリ構成になっているかを確認します。

```bash
$ cd openwhisk
$ ls
CONTRIBUTING.md  LICENSE.txt  ansible  common  docs    gradlew      sdk              tests
CREDITS.txt      README.md    bin      core    gradle  gradlew.bat  settings.gradle  tools
```

## Docker導入の設定を変更する
ここがミソその1。ソースを見ていると、OpenWhiskのUbuntu固有の環境セットアップ関連のbashスクリプトを読むと、明らかに14.04前提の書き方になっているので、修正。Dockerなので手動で導入した方が個人的には良いかなと思うんですけどね。。

```bash
# バックアップを取って
$ cp -p tools/ubuntu-setup/docker.sh tools/ubuntu-setup/docker.sh.org
# dockerのセットアップスクリプトを編集し
$ vi tools/ubuntu-setup/docker.sh
# 差分を確認します
$ diff tools/ubuntu-setup/docker.sh tools/ubuntu-setup/docker.sh.org
7c7
< sudo sh -c "echo deb https://apt.dockerproject.org/repo ubuntu-yakkety main  > /etc/apt/sources.list.d/docker.list"
---
> sudo sh -c "echo deb https://apt.dockerproject.org/repo ubuntu-trusty main  > /etc/apt/sources.list.d/docker.list"
17c17
< sudo apt-get install -y --force-yes docker-engine
---
> sudo apt-get install -y --force-yes docker-engine=1.12.0-0~trusty
```

Trustyになっている部分を16.10のYakketyに変更すれば良いです。また、docker-engineのバージョンも古いので、いったんバージョン縛りは外しました。コンテナーで動くのだからAPI周りが大きく変わらない限りはOpenWhiskは動くはず!!

## Ubuntu固有の環境セットアップ処理
以下はドキュメントに従い、tools/ubuntu-setup配下にあるall.shを叩きます。

```bash
$ cd tools/ubuntu-setup && ./all.sh
*** installing basics
Etc/UTC
:
  python version = 2.7.12+ (default, Sep 17 2016, 12:08:02) [GCC 6.2.0 20160914]
ansible-playbook 2.3.0.0
  config file = 
  configured module search path = Default w/o overrides
  python version = 2.7.12+ (default, Sep 17 2016, 12:08:02) [GCC 6.2.0 20160914]
25612 finished with status 0 

install all with total errors number 0
```

はい、上手くいきました!! (# 実際には依存関係周りで何回か実行し直しました。。上述したものが事前に入って入れば問題ないはずです。)

## ビルドする
OpenWhiskのホームディレクトリをカレントにして、gradlewコマンドを叩きます。「BUILD SUCCESSFUL」が出てくれば成功です。自分の環境では約30分かけてDockerイメージのビルドなどが行われていました。

```bash
$ sudo ./gradlew distDocker
Downloading https://services.gradle.org/distributions/gradle-3.5-bin.zip
:
BUILD SUCCESSFUL

Total time: 29 mins 9.802 secs
```

## Docker Hostの設定書き換え
ここがミソその2。上述したセットアップスクリプトではDocker HostでRemote APIを公開する設定が入っていません。なので、そのまま進むと最終的に以下のようなエラーが発生してしまいます。

>fatal: [172.17.0.1]: FAILED! => {"changed": false, "content": "", "failed": true, "msg": "Status code was not [200]: Request failed: <urlopen error [Errno 111] 接続を拒否されました>", "redirected": false, "status": -1, "url": "http://172.17.0.1:4243/info"}

ですので、dockerdの構成ファイルを以下のように書き換えます:

```bash
$ sudo vi /lib/systemd/system/docker.service 
$ cat /lib/systemd/system/docker.service 
:
# for containers run by docker
# 元々の設定をコメントして
#ExecStart=/usr/bin/dockerd -H fd://
# Remote APIをExposeするように設定
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:4243 -H unix:///var/run/docker.sock -H fd://
ExecReload=/bin/kill -s HUP $MAINPID
```

設定したらリロードして、dockerdを再起動します。

```bash
# リロードして
$ sudo systemctl daemon-reload 
# 再起動
$ sudo service docker restart
# 4243ポートをListenしているか確認して
$ sudo netstat -anp |grep 4243
tcp6       0      0 :::4243                 :::*                    LISTEN      20101/dockerd    
# 一応curlでAPIエンドポイントを突く
$ curl http://localhost:4243/version
{"Version":"17.05.0-ce","ApiVersion":"1.29","MinAPIVersion":"1.12","GitCommit":"89658be","GoVersion":"go1.7.5","Os":"linux","Arch":"amd64","KernelVersion":"4.8.0-26-generic","BuildTime":"2017-05-04T22:15:36.071254972+00:00"}
```

下準備は全て完了です。あとはデプロイするだけ。

## デプロイする
ここはもう道なりに進めば良いだけです。Ephemeralなcouchdbの構成で試した限りでは特になにもありませんでした。Docker環境さえ整っていればどうってことはないのです。

```bash
# configを生成し
$ ansible-playbook -i environments/local setup.yml 
# prereqを流す
$ ansible-playbook -i environments/local prereq_build.yml
```

ここで注意が1つ。prereq_buildは必ず失敗します。。
「install headers for kernel 4.4.0-31」の処理がエラーの原因なのですが、そもそも今の検証環境のカーネル・レベルは4.8だし、古いし、あまり以降の処理に関わるような部分じゃなさそうだったので今回は無視で進めました。

```bash
# 今回はテストなので、デフォルトのままcouchdbを導入し
$ sudo ansible-playbook -i environments/local couchdb.yml
# DBを初期化し
$ sudo ansible-playbook -i environments/local initdb.yml 
# wipeして
$ sudo ansible-playbook -i environments/local wipe.yml
# OpenWhisk環境をセットアップする
$ sudo ansible-playbook -i environments/local openwhisk.yml
:
PLAY RECAP ***************************************************************************************************************************************
172.17.0.1                 : ok=51   changed=38   unreachable=0    failed=0   
ansible                    : ok=6    changed=3    unreachable=0    failed=0   

********** 
=============================================================================== 
nginx : pull the nginx:1.11 image -------------------------------------- 15.30s
consul : wait until the Consul Server/Agent in this host is up and running --- 7.37s
kafka : wait until the Zookeeper in this host is up and running --------- 7.27s
invoker : wait until Invoker is up and running -------------------------- 5.81s
controller : wait until the Controller in this host is up and running --- 5.53s
kafka : wait until the kafka server started up -------------------------- 5.31s
kafka : create the active-ack and health topic -------------------------- 3.23s
consul : pull the consul:0.7.0 image ------------------------------------ 2.65s
kafka : pull the zookeeper:3.4 image ------------------------------------ 2.65s
kafka : pull the ches/kafka:0.10.0.1 image ------------------------------ 2.50s
routemgmt : install route management actions ---------------------------- 1.88s
kafka : create the invoker topics --------------------------------------- 1.53s
Gathering Facts --------------------------------------------------------- 1.38s
sdk : copy docker sdk to dockerSkeleton in scratch space ---------------- 0.99s
consul : (re)start consul server/agent ---------------------------------- 0.98s
consul : fill consul kv ------------------------------------------------- 0.91s
nginx : (re)start nginx ------------------------------------------------- 0.84s
nginx : copy cert files from local to remote in nginx config directory --- 0.77s
cli : run Docker -------------------------------------------------------- 0.72s
kafka : (re)start kafka ------------------------------------------------- 0.69s
```

導入後はDockerコンテナーがこれだけ動いています:

```bash
$ sudo docker ps
CONTAINER ID        IMAGE                        COMMAND                  CREATED             STATUS              PORTS                                                                                                                                                  NAMES
9df4c97bf79c        nginx:1.11                   "nginx -g 'daemon ..."   9 minutes ago       Up 9 minutes        0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, 0.0.0.0:8443->8443/tcp                                                                                       nginx
9e03206f5794        whisk/nodejs6action:latest   "/bin/sh -c 'node ..."   9 minutes ago       Up 9 minutes                                                                                                                                                               wsk0_6_warmJsContainer_20170527T073229905Z
b60dc5965062        whisk/nodejs6action:latest   "/bin/sh -c 'node ..."   9 minutes ago       Up 9 minutes                                                                                                                                                               wsk0_5_whisksysteminvokerHealthTestAction001_20170527T073229384Z
fafeba708cc7        whisk/nodejs6action:latest   "/bin/sh -c 'node ..."   9 minutes ago       Up 9 minutes                                                                                                                                                               wsk0_3_warmJsContainer_20170527T073227074Z
9b9715b45af4        whisk/nodejs6action:latest   "/bin/sh -c 'node ..."   9 minutes ago       Up 9 minutes                                                                                                                                                               wsk0_2_whisksysteminvokerHealthTestAction001_20170527T073226625Z
80a11f7cea5d        whisk/nodejs6action:latest   "/bin/sh -c 'node ..."   9 minutes ago       Up 9 minutes                                                                                                                                                               wsk0_1_warmJsContainer_20170527T073226020Z
a6525c951142        whisk/invoker:latest         "/bin/sh -c 'exec ..."   9 minutes ago       Up 9 minutes        0.0.0.0:12001->8080/tcp                                                                                                                                invoker0
95b7983299af        whisk/controller:latest      "/bin/sh -c 'contr..."   9 minutes ago       Up 9 minutes        0.0.0.0:10001->8080/tcp                                                                                                                                controller
9acd3d931a96        ches/kafka:0.10.0.1          "/start.sh"              9 minutes ago       Up 9 minutes        7203/tcp, 0.0.0.0:9092->9092/tcp                                                                                                                       kafka
cb388cab0d5d        zookeeper:3.4                "/docker-entrypoin..."   10 minutes ago      Up 10 minutes       2888/tcp, 0.0.0.0:2181->2181/tcp, 3888/tcp                                                                                                             zookeeper
f7b6d10a3d0c        gliderlabs/registrator       "/bin/registrator ..."   10 minutes ago      Up 10 minutes                                                                                                                                                              registrator
c9f79bd12215        consul:0.7.0                 "docker-entrypoint..."   10 minutes ago      Up 10 minutes       0.0.0.0:8300-8302->8300-8302/tcp, 0.0.0.0:8400->8400/tcp, 0.0.0.0:8301-8302->8301-8302/udp, 0.0.0.0:8500->8500/tcp, 0.0.0.0:8600->8600/udp, 8600/tcp   consul
c674f20cf5fc        couchdb:1.6                  "tini -- /docker-e..."   11 minutes ago      Up 11 minutes       0.0.0.0:5984->5984/tcp                                                                                                                                 couchdb
```

導入後のpostDeploy処理も忘れずに実施します。

```bash
$ sudo ansible-playbook -i environments/local postdeploy.yml
:
PLAY RECAP ******************************************************************************************************************************************************************
ansible                    : ok=10   changed=4    unreachable=0    failed=0   

********** 
=============================================================================== 
download the catalog repository to the catalog location if necessary ---- 2.36s
install the catalog from the catalog location --------------------------- 1.83s
Gathering Facts --------------------------------------------------------- 0.64s
write whisk.properties template to openwhisk_home ----------------------- 0.51s
Gathering Facts --------------------------------------------------------- 0.38s
ensure catalog_location directory exists -------------------------------- 0.25s
include ----------------------------------------------------------------- 0.05s
set_fact ---------------------------------------------------------------- 0.04s
set_fact ---------------------------------------------------------------- 0.04s
set_fact ---------------------------------------------------------------- 0.04s
```

特にエラーなしです。OK!!

## 動作確認
あとはwskコマンドで動作確認するだけです。ますは認証キーのセットアップをして、

```bash
$ ./bin/wsk property set --auth $(cat ansible/files/auth.whisk.system) --apihost 172.17.0.1
ok: whisk auth set. Run 'wsk property get --auth' to see the new value.
ok: whisk API host set to 172.17.0.1
```

パッケージの確認をします。

```bash
$ ./bin/wsk package list --insecure
packages
/whisk.system/utils                                                    shared
/whisk.system/watson-translator                                        shared
/whisk.system/watson-textToSpeech                                      shared
/whisk.system/watson-speechToText                                      shared
/whisk.system/weather                                                  shared
/whisk.system/slack                                                    shared
/whisk.system/samples                                                  shared
/whisk.system/combinators                                              shared
/whisk.system/github                                                   shared
/whisk.system/websocket                                                shared
/whisk.system/apimgmt                                                  private
/whisk.system/routemgmt                                                private
```

そして、テスト用にechoアクションを実行します。

```bash
$ bin/wsk action invoke /whisk.system/utils/echo -p message hello --result --insecure
{
    "message": "hello"
}
```

はい、問題なく完了です!!

# 終わりに
とりあえずUbuntu 16.10でも導入できることは確認できました。
一部エラーは無視しましたが。。

過去の記事では16.04で導入できない話がありましたが、おそらくは当時公開していたソースに問題があったのではないかなと思っています。比較してないのでなんともですが。
色々検証してみて、16.10だと動かないようなものが見つかったら記事更新します!!

17.04でも同様なのかなと思ったりしましたが、OpenWhiskの導入がメインではないので、機会があれば試そうかな、レベルとしておきます。