IBM Cloud Container Service で k8sからwatsonへ連携してみた
このエントリは、Kubernetes Advent Calendar 2017 20日目の記事です。
(6日遅れでした・・・)
はじめに
IBM Cloudのk8sプラットフォームは、IBM Cloud Container Serviceという名称で提供されています。
マネージドなk8sプラットフォームとしてはどこのk8sプラットフォームと遜色ありませんが、
以下がIBM Cloudでk8sを使う最大魅力です。
- IBM Bluemix時代からの資産 CloudFoundry環境アプリとの連携
- IBM Watsonとの連携でコグニティブ環境をコンテナアプリから利用できる
IBM Cloud Container Serviceを使ってみる
IBM Cloud のpay-as-you-goアカウントではクレジッドカードの登録でk8sクラスタのworkernodeが無料で利用できますので、これをきっかけに利用される方が増えるといいなと考えています。
IBM Cloudにはクレジッドカードなしで登録できるライトアカウントが存在しますが、執筆時点ではk8sクラスタが適用外となっているためご注意ください。
事前準備
- IBM Cloud pay-as-you-goアカウントの取得
- k8s クラスタ(IBM Cloud Container Service)のデプロイ
今回はクラスタ名"mycluster"としてデプロイしました。
ライトプラン クラスタ(無料)を利用 - watoson language translatorのデプロイ
今回はサービス名"langtrans-test"としてデプロイしました。
Liteプラン (1,000,000文字まで無料)を利用
- bx(bluemix)コマンドの導入
- kubectlの導入
実際にやってみる
今回ライトプランのkubernetesクラスタはUS-Southにデプロイされていた旧来のものを使用します。
ライトプランの場合地域を選んでデプロイすることができないので、デプロイされた地域をConsole上で確認してから、bxコマンドでログインします。
また、k8sクラスタの動作する地域とCloudFoundryのネームスペースのある地域が同じである必要があるので、注意してください。
ログイン
$ bx login -a api.ng.bluemix.net
API エンドポイント: api.ng.bluemix.net
クラスタの確認
$ bx target --cf
$ bx cs clusters
OK
Name ID State Created Workers Datacenter Version
mycluster fbf0dff***53432***41e3a596997b6a normal 4 weeks ago 1 dal13 1.8.4_1502
kubectl用にクラスタ構成ファイルの読み込み
$ bx cs cluster-config mycluster
コマンド実行結果に出てくる "export KUBECONFIG="をコピーして実行する
$ export KUBECONFIG=/Users/sakaigawa/.bluemix/plugins/container-service/clusters/mycluster/kube-config-dal13-mycluster.yml
Watson Service との連携
watson language translatorを今回のサンプルとして使用します。
文字通り言語翻訳の機能を持っています。
プロジェクトとして"langtrans"という名前でデプロイしたところ、
サービス名は個別にランダム文字が割り当てられたので(12/25時点)、念のため確認コマンドで確認します。
バインド可能なサービス一覧
$ bx service list
'cf services' を起動しています...
[your IBMid] として組織 [your IBMid] / スペース pumpkinheads 内のサービスを取得しています...
OK
名前 サービス プラン バインド済みアプリ 最後の操作
langtrans-language-t-1514215788955 language_translator lite create は成功しました
※もっと出てきます。
サービスをバインドしてみる
では実際にバインド可能なサービス名をコピーして、k8sクラスタへ割り当ててみましょう
今回はlangtrans-language-t-1514215788955
をサービスとしてクラスタへバインドします。
$ bx cs cluster-service-bind mycluster default [service name]
Binding service instance to namespace...
OK
Namespace: default
Secret name: binding-langtrans-language-t-1514215788955
アプリケーションの準備
ここでは、DockerfileとアプリケーションのPHPファイルを準備します。
Dockerfileはお好みでドウゾ(centos+phpを入れてイメージ作る習慣がついてしまったのですいません、長いですが)
Dockerfileの作成
#centos7のイメージを取得
FROM centos:centos7
#Dockerfile作成者
MAINTAINER Shoichiro Sakaigawa sakaigawa@pumpkinheds.jp
#タイムゾーンの設定
RUN /bin/cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
#yumによる必要パッケージのインストール
RUN yum -y install httpd unzip git
# Vulnerability Advisor : Fix PASS_MAX_DAYS, PASS_MIN_DAYS and PASS_MIN_LEN, common-password
RUN mv -f /etc/login.defs /etc/login.defs.orig
RUN sed 's/^PASS_MAX_DAYS.*/PASS_MAX_DAYS 90/' /etc/login.defs.orig > /etc/login.defs
RUN grep -q '^PASS_MIN_DAYS' /etc/login.defs && sed -i 's/^PASS_MIN_DAYS.*/PASS_MIN_DAYS 1/' /etc/login.defs || echo 'PASS_MIN_DAYS 1\n' >> /etc/login.defs
RUN grep -q '^PASS_MIN_LEN' /etc/login.defs && sed -i 's/^PASS_MIN_LEN.*/PASS_MIN_LEN 8/' /etc/login.defs || echo 'PASS_MIN_LEN 9\n' >> /etc/login.defs
RUN grep -q '^password.*required' /etc/pam.d/common-password && sed -i 's/^password.*required.*/password required pam_permit.so minlen=9/' /etc/pam.d/common-password || echo 'password required pam_permit.so minlen=9' >> /etc/pam.d/common-password
#yumリポジトリの追加
RUN yum -y localinstall http://ftp.iij.ad.jp/pub/linux/fedora/epel/epel-release-latest-7.noarch.rpm
RUN yum -y localinstall http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
#yumによるphp7.0インストール
RUN yum install -y --enablerepo=remi --enablerepo=remi-php70 php php-common php-mbstring php-gd php-xml php-xmlrpc php-devel php-cli php-pdo php-mysql php-odbc php-pear php-mcrypt php-pecl-apc
#tmpディレクトリに移動
WORKDIR /tmp/
ADD app /tmp/app
#ディレクトリのリネーム
RUN mv app/* /var/www/html
#ディレクトリの権限変更
RUN chown -R apache:apache /var/www/html/
#httpd.confの変更
RUN sed -i -e 's#AllowOverride None#AllowOverride All#g' /etc/httpd/conf/httpd.conf
#公開ポート
EXPOSE 80
#httpdの実行
CMD ["httpd", "-D", "FOREGROUND"]
PHPファイルの作成
今回はWatsonとの連携を見てもらうためだけを目的としたので、シンプルにJSONデータを投げて返ってきたものをDUMPして出力します。
後ほどdeploy.yamlでWATSON_TL
というシステム変数としてコンテナにサービスバインドした情報を提供します。
<pre>
<?php
echo date('l F d, Y G:i:s').PHP_EOL;
$watson_json_env = getenv('WATSON_TL');
$watson_json_decoded = json_decode($watson_json_env,true);
$url=$watson_json_decoded["url"]."/v2/translate";
$values = array(
'source' => 'en',
'target' => 'ja',
'text' => "Hello, I'm watson language translator. this page now display by IBM Cloud Container Service"
);
$params = json_encode($values);
var_dump($values);
$ch = curl_init();
$options = array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_AUTOREFERER => true,
);
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_HEADER, false);
curl_setopt($ch,CURLOPT_USERPWD, $watson_json_decoded['username']. ":" . $watson_json_decoded['password']);
curl_setopt($ch,CURLOPT_POST, true);
curl_setopt($ch,CURLOPT_POSTFIELDS, $params);
curl_setopt($ch,CURLOPT_VERBOSE, true);
curl_setopt($ch,CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
curl_setopt_array($ch, $options);
$response=curl_exec($ch);
$info=curl_getinfo($ch);
curl_close($ch);
var_dump($response);
?>
</pre>
docker プライベートレポジトリへの接続
Docker-Registoryのプライベート版であるibm cloudのdocker registryへログインし、
名前空間の追加を行い、名前空間に合わせてdocker imageをタグ付きでビルドします。
$ bx cr login
$ bx cr namespace-add sakaigawa
名前空間「sakaigawa」を追加しています...
名前空間「sakaigawa」は正常に追加されました
OK
コンテナのビルド
$ docker build -t registry.ng.bluemix.net/sakaigawa/hellotrans .
ビルドしたコンテナをdocker registryにpushする
$ docker push registry.ng.bluemix.net/sakaigawa/hellotrans
$ bx cr image-list
イメージをリストしています...
リポジトリー 名前空間 タグ ダイジェスト 作成 サイズ 脆弱性の状況
registry.ng.bluemix.net/sakaigawa/hellotrans sakaigawa latest aa4868a89061 15 minutes ago 234 MB OK
OK
Deploy / Serviceの設定を定義する・コミットする
今回はやってみたをメインにするので内容を細かく書きませんが、
Podは1個、ポートはNodePortでロードバランスせずに公開します。
このdeploy.ymlのキモの1つは、image指定の直下にenv
としてWATSON_TL
を登録したことです。
WATSON_TL
は任意の名称で、システム変数としてコンテナに引き継がれます。
先程割り当てた際に表示されたservice bind nameを貼り付けて紐付けます。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: hellotrans-app
spec:
replicas: 1
template:
metadata:
labels:
app: hellotrans-app
spec:
containers:
- name: hellotrans-app
image: registry.ng.bluemix.net/sakaigawa/hellotrans
env:
- name: WATSON_TL
valueFrom:
secretKeyRef:
name: binding-langtrans-language-t-1514215788955
key: binding
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: hellotrans-service
labels:
app: hellotrans-service
spec:
type: NodePort
ports:
- port: 80
selector:
app: hellotrans-app
kubectlでPodのデプロイとServiceのデプロイを実施する。
$ ~/kubectl create -f deploy.yml
deployment "hellotrans-app" created
service "hellotrans-service" created
サーバアドレスを確認する
bx cs workers コマンドでk8s workernode の外部IPを見つけます。
今回はworker1台のライトプランですので複数台のkubernetesクラスタの場合はPodが動作するworkerを特定してからの作業が必要です。
コマンド結果のPublic IPをメモします。
$ bx cs workers ssk8s
OK
ID Public IP Private IP Machine Type State Status Version
kube-dal13-cr64ad7*****aa4dd3bd68ebd8ff8e6005-w1 169.60.151.246 10.186.127.202 free normal Ready 1.8.4_1502
kubectl get svcで外部公開のポート番号を確認する
今回のサンプルでは、コンテナ側が80で公開されており、外部側は:の右側30666であることがわかりました。
$ ~/kubectl get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hellotrans-service 10.10.10.150 <nodes> 80:30666/TCP 1h
kubernetes 10.10.10.1 <none> 443/TCP 3h
結果
以下アドレスを参考に上記のノードIP、ノードポートを確認してアクセスしてみてください。
http://クラスタIP:ポート番号/watson-tl.php
以下の様にArrayで投入した結果が翻訳されて返却されてきました。
Tuesday December 25, 2017 23:25:55
array(3) {
["source"]=>
string(2) "en"
["target"]=>
string(2) "ja"
["text"]=>
string(91) "Hello, I'm watson language translator. this page now display by IBM Cloud Container Service"
}
string(130) "こんにちは、私はwatson言語変換プログラムです。 このページは、IBM Cloud Service Containerによる表示"
まとめ
Watsonサービスは140を超えるサービスが日々進化しています。
このLanguage Translatorもカテゴリや学習をさせることで進化した翻訳プラットフォームが手に入るのではないでしょうか。
アイデア次第では、フォーム入力を利用した同時通訳だったり、クラウドからの通知文を翻訳したり、OSSドキュメンテーションの自動翻訳だったり夢は広がります。