2018年8月31日金曜日

Google Cloud Functions を使ってみる

概要

Google Cloud Functions は AWS Lambda のようなサービスです
Nodejs などのスクリプトをアップロードしそれをクラウド上でキックすることができます
今回は Nodejs を使って Google Cloud Functions を試してみました
ちなみに Python3.7 もベータですが対応しているようです

Google Cloud Functions は有料のサービスになるので以下の内容を試す場合は留意の上実施してください (と言っても 200 万回コールしない限り無料なので大丈夫だと思いますが)

環境

  • Google Cloud Scripts (2018/08/27 時点)
  • Google Cloud Shell (2018/08/27 時点)

API を有効化

Google Cloud Scripts の API を有効にしましょう
cloud_script1.png

作業ディレクトリの作成

以下の作業は Google Cloud Shell 上で行います

  • mkdir ~/gcf_hello_world
  • cd ~/gcf_hello_world

スクリプトの作成

  • vim index.js
exports.helloGET = (req, res) => {
  res.send('Hello World!');
};

スクリプトのデプロイ

  • gcloud beta functions deploy helloGET --trigger-http

helloGET という名前でデプロイします
コンソールで確認すると以下の通りです
cloud_script2.png

動作確認

スクリプトは専用の URL を GET でコールすることで呼び出すことができます

  • gcloud beta functions describe helloGET

でデプロイしたスクリプトの詳細を取得しましょう
すると httpsTrigger の欄に URL が表示されるのでそれにアクセスしみましょう

  • curl https://us-central1-[project_id].cloudfunctions.net/helloGET

すると「Hello World!」と表示されると思います

HTTP をコールしてみる

少し応用して自分でスクリプトを作成してみます
IFTTT の maker チャネルの URL を呼び出すスクリプトを作成してみます

  • npm init
  • npm install request --save
  • vim index.js
const request = require('request');

exports.testMaker = (req, res) => {
  request.post('https://maker.ifttt.com/trigger/[event]/with/key/[your-maker-key]', function (error, response, body) {
    console.log('error:', error);
  });
  res.status(200).send("Success");
}
  • gcloud beta functions deploy testMaker --trigger-http

cloud_script3.png

  • gcloud beta functions describe testMaker

で後は表示された URL にアクセスすれば Maker チャネルの webhook がコールされます
Google Cloud Functions ではサードパーティ製のライブラリは package.json を追加してあげるだけで使えるようになるようです

お掃除

  • gcloud beta functions delete testMaker

or コンソールから直接スクリプトを削除すれば OK です
Google Cloud Functions の料金は月に 200 万回コールしないと発生しないのでそのままでも料金はかからないと思います

最後に

Google Cloud Functions を試してみました
基本は Nodejs ですが Python もサポートされたので他の言語もそのうちサポートするかもしれません

package.json を使えば自由にサードパーティ製のライブラリが使えるのは嬉しい点です

今回は紹介しませんでしたが他にもリクエストを処理する方法や他の GCP サービスと連携する方法、Github と連携して CI/CD する方法、Webhook として利用する方法などかなり応用が効くようです

Nodejs でサーバサイドを構築しているのであれば移行することで今流行りのサーバレスアーキテクチャの波に乗れるかもしれません

参考サイト

2018年8月30日木曜日

Google Cloud の Stackdriver logging を Ruby から使ってみる

概要

Stackdriver logging はログ情報をクラウドに貯めることができるサービスです
普段アプリを実装するときと同じようにロギングするだけでクラウドにログを貯められます
今回は GCE から Ruby で書き込む方法を紹介します (なぜ GCE からわざわざやっているのかは最後の「トラブルシューティング」のところで説明しています)

環境

  • macOS 10.13.6
  • Ruby 2.5.1p57
  • google-cloud-logging (1.5.2)
  • Google Stackdriver Logging API (2018/08/22 時点)

Stackdriver Logging API を有効にする

ここ から有効にします
まずは API を有効にするプロジェクトを選択します
stackdriver_logging1.png

認証情報は作成する必要はないです
GCE を作成する際に Stackdriver logging API へのアクセスをフルアクセスにすることがで制御します

GCE の Cloud API アクセススコープを設定する

GCE のインスタンスの編集から「Cloud API アクセススコープ」を設定しましょう
これを設定するにはインスタンスが停止状態でなければいけないので一旦停止します
stackdriver_logging4.png

Stackdriver Logging API の部分を「フル」にしましょう

ライブラリインストール

GCE 上で行います
ruby, gem, bundler などがインストールされていない場合はインストールしてください

  • bundle init
  • vim Gemfile
gem "google-cloud-logging"
  • bundle install --path vendor

Rails で使う場合は「stackdriver」というライブラリなのですが今回は Rails は使わないのでこの方法で実装します

サンプルコード

  • vim sd_test.rb
require "google/cloud/logging"

project_id = 'your_project_id'
logging = Google::Cloud::Logging.new project: project_id

entry = logging.entry
entry.payload = "Hello, world!"
entry.log_name = "my-log"
entry.resource.type = "global"

ret = logging.write_entries entry
puts ret

GCE を作成したプロジェクト ID を設定してください

動作確認

  • bundle exec ruby sd_test.rb

で動作するはずです
Stackdriver Logging の画面がから「グローバル」スコープでログを確認すると送信したログがあるのが確認できると思います
stackdriver_logging5.png

おまけ (gcloud コマンドでロギングする)

例えば Google Cloud Shell を使って以下のように実行するだけで Stackdriver にログを貯めることができます
GCE のインスタンスにはデフォルトで gcloud コマンドがインストールされています

  • gcloud logging write my-test-log "A simple entry"

おまけ2 (ログを削除する)

  • gcloud logging logs delete my-test-log

トラブルシューティング

今回は GCE から使いました
実はローカルホストや AWS など他の環境からアクセスする際にはサービスアカウントを作成して API の認証情報を作成する必要があります
それを使ってアクセスすることができるらしいのですが自分が何度やっても以下のエラーでできませんでした

  • The caller does not have permission

作成したサービスアカウントのロールを「オーナー」などにしてみましたがダメでした
ここに書いてある通りに project_id の他に認証用の JSON ファイルを指定してやってみたのですがダメでした
もしかするとサービスアカウントのロール以外にもどこか設定するところがあるのかもしれません

最後に

GCE のインスタンスから Stackdriver Logging API を使ってみました
GCE からであれば簡単に使えます

実は当初はずっとローカルの Mac からやっていたのですがずっとエラーが出たのでドキュメントを見直してみたら GCE or GKE or GAE からやるのが定石ってぽかったので諦めて GCE からやりました

今回は諦めましたができる方法は絶対にあると思うのでもし情報があればコメントいただけると助かります

参考サイト

2018年8月29日水曜日

Google ML Engine を使って tensorflow を動かしてみる

概要

Google ML Engine はクラウド上で学習しモデルを生成し、そのモデルを Tensorflow で実行まで行うことができるプラットフォームです
今回はサンプルの学習データを元にモデルを生成し実際に判定させるところまでやってみました
なお作業はすべて Google Cloud Shell 上で行います
作業中は Google Cloud Shell とのセッションが切断されないように注意してください
作業には料金が発生するの留意の上作業してください

環境

  • Google ML Engine
  • Google Cloud Dataflow
  • Google Cloud Storage
  • Google Cloud Shell (2018/08/28 時点)
  • Python 2.7.13
  • pip 18.0

準備

まずは ML-Engine を使う前の準備をいろいろとします

API 有効化

ML-Engine の API 有効化

ml_engine1.png

Cloud Dataflow の API 有効化
(少し操作が違うのでご注意ください)
ml_engine4.png

学習用のサンプルデータを取得

  • wget https://github.com/GoogleCloudPlatform/cloudml-samples/archive/master.zip
  • unzip master.zip
  • cd cloudml-samples-master/flowers

Python を使うので必要なライブラリをインストールしましょう
なぜか足りないライブラリがあるので手動でインストールします
tensorflow は最新版を使うので upgrade しておきます

  • sudo pip install -r requirements.txt
  • sudo pip install apache_beam[gcp]
  • sudo pip install pillow
  • sudo pip install --upgrade tensorflow

tensorflow の動作確認

  • python

で対話形式で以下を入力してみましょう
エラーなく動作すれば tensorflow のインストールが完了しています

Python 2.7.13 (default, Nov 24 2017, 17:33:09)
[GCC 6.3.0 20170516] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow as tf
>>> hello = tf.constant('Hello, TensorFlow!')
>>> sess = tf.Session()
>>> print(sess.run(hello))
Hello, TensorFlow!
>>> exit()

サービスアカウントの作成

ML Engine の API をコールするので認証用のサービスアカウントを作成します
ml_engine2.png

ダウンロードできた JSON ファイルをクラウドコンソールに配置しましょう
一番簡単なのはファイルの中身をコピペする方法かなと思います
認証用の JSON を環境変数を設定しましょう
[username] の部分は各自変更してください

  • export GOOGLE_APPLICATION_CREDENTIALS="/home/[username]/auth.json"

念の為動作確認でモデルの一覧を表示しましょう
まだ 1 つも作成されてないですが正常に動作することを確認しましょう

  • gcloud ml-engine models list

Cloud Storage にバケットを作成する

学習データや結果は Cloud Storage に配置されるので専用のバケットを作成しましょう

  • PROJECT_ID=$(gcloud config list project --format "value(core.project)")
  • BUCKET_NAME=${PROJECT_ID}-mlengine
  • REGION=us-central1
  • gsutil mb -l $REGION gs://$BUCKET_NAME

これで Cloud Storage のコンソールから確認するとバケットが作成されています
ml_engine3.png

必要な変数の宣言

すべて読み込み専用で宣言します
[your-bucket-name] の部分は先程作成したバケット名に変更してください

  • declare -r BUCKET_NAME="gs://[your-bucket-name]"
  • declare -r REGION="us-central1"
  • declare -r PROJECT_ID=$(gcloud config list project --format "value(core.project)")
  • declare -r JOB_NAME="flowers_${USER}_$(date +%Y%m%d_%H%M%S)"
  • declare -r GCS_PATH="${BUCKET_NAME}/${USER}/${JOB_NAME}"
  • declare -r DICT_FILE=gs://cloud-ml-data/img/flower_photos/dict.txt
  • declare -r MODEL_NAME=flowers
  • declare -r VERSION_NAME=v1

Cloud Dataflow での前処理

ここからは学習に必要な各種データを Cloud Dataflow と python を使って行います

評価データの前処理

まずはテスト用のデータの作成を行います

  • cd cloudml-samples-master/flowers
  • python trainer/preprocess.py --input_dict "$DICT_FILE" --input_path "gs://cloud-ml-data/img/flower_photos/eval_set.csv" --output_path "${GCS_PATH}/preproc/eval" --cloud

結構時間がかかります
Cloud Dataflow のコンソールを見るとジョブが走っているのが確認できると思います
ml_engine5.png

ml_engine6.png

実行中のジョブを確認するには gcloud コマンドでも可能です

*gcloud beta dataflow logs list 2018-08-27_17_50_22-5918041335734527976 --importance=detailed

評価データの作成は 12分7秒 で終了しました
ml_engine7.png

トレーニングデータの前処理

次に学習に必要な訓練データの作成を行います
こちらの方がデータが多いので少し時間がかかります

  • python trainer/preprocess.py --input_dict "$DICT_FILE" --input_path "gs://cloud-ml-data/img/flower_photos/train_set.csv" --output_path "${GCS_PATH}/preproc/train" --cloud

処理が始まると先ほどと同様 Cloud Dataflow 上にジョブが作成されます
完了するまで待ちましょう
15分52秒 かかりました
ml_engine8.png

Cloud Storage 上に評価データとトレーニングデータが作成できました
これを使ってモデルの生成と評価を行います
ml_engine9.png

ML Engine での作業

ここからモデルの生成と評価を ML Engine を使って行います

モデルの生成

gcloud ml-engine jobs submit training "$JOB_NAME" \
    --stream-logs \
    --module-name trainer.task \
    --package-path trainer \
    --staging-bucket "$BUCKET_NAME" \
    --region "$REGION" \
    --runtime-version=1.4\
    -- \
    --output_path "${GCS_PATH}/training" \
    --eval_data_paths "${GCS_PATH}/preproc/eval*" \
    --train_data_paths "${GCS_PATH}/preproc/train*"

先程生成した評価データと訓練データを使います
ML Engine のダッシュボードを開くとモデルを生成するジョブがあることを確認できると思います
ml_engine10.png

実行中のログの確認はコマンド or TensorBoard を使います

  • gcloud ml-engine jobs stream-logs "$JOB_NAME"

or

  • OUTPUT_PATH="${GCS_PATH}/training"
  • tensorboard --logdir=$OUTPUT_PATH --port=8080

Google Cloud Shell の上部にある「ウェブでプレビュー」を選択し 8080 ポートを入力すれば TensorBoard を確認することができます
ml_engine12.png

完了すると以下のようにモデルが生成されます
モデルの生成には 12分23秒 かかりました
ml_engine11.png

モデルのデプロイ

生成したモデルはそのままでは使えません
モデルとしてデプロイした上でバージョンを付与することで利用できます

  • gcloud ml-engine models create "$MODEL_NAME" --regions "$REGION"
  • gcloud ml-engine versions create "$VERSION_NAME" --model "$MODEL_NAME" --origin "${GCS_PATH}/training/model" --runtime-version=1.4

少し時間がかかるので待ちましょう
モデルのデプロイが完了すると ML Engine のモデル一覧に表示されます
ml_engine13.png

モデルの評価

ではテストしてみます
今回は画像の分類なので画像を使ってテストします
まずは対象の画像をダウンロードします

  • gsutil cp gs://cloud-ml-data/img/flower_photos/daisy/100080576_f52e8ee070_n.jpg daisy.jpg

これを ML Engine にリクエストできるように JSON に落とし込みます

  • python -c 'import base64, sys, json; img = base64.b64encode(open(sys.argv[1], "rb").read()); print json.dumps({"key":"0", "image_bytes": {"b64": img}})' daisy.jpg &> request.json

ここで作成された request.json を使って ML Engine にリクエストしてみましょう

  • gcloud ml-engine predict --model ${MODEL_NAME} --json-instances request.json

結果は 99.8% の精度になりました
つまりこの画像は 99.8% の確率で学習した画像だと言えるということです

KEY  PREDICTION  SCORES
0    0           [0.9989761114120483, 0.0001314109977101907, 0.00015020737191662192, 0.0005003452533856034, 0.00022650569735560566, 1.5491037629544735e-05]

お掃除

  • Cloud Storage の対象のバケット
  • ML Engine の対象モデル
  • 対象のサービスアカウント

を削除すれば OK です
Cloud Dataflow ジョブのフロート ML Engine のジョブのフローは削除できないようです
料金もかからないのでそのままでも問題ないですがどうしても削除したい場合はプロジェクトごと削除してください

最後に

Google ML Engine を使って Tensorflow のモデルの生成と評価を行ってみました
学習の前段階では Cloud Dataflow を使って学習データと評価データの生成も行いました
ML Engine の仕組みとしては Cloud Storage にある学習データと評価データと読み込んでモデルを生成するので学習データのと評価データの作成は自身の環境で行って、そのあとで Cloud Storage にアップロードしても問題ないと思います

コーディングした部分は前処理の部分だけでした
つまり別のデータを使って同じように前処理の部分で学習データと評価データを作成できれば同じように学習させることができるということになります

ほぼ Tensorflow の仕組みを知らなくても Tensorflow で使えるモデルを生成することができるので機械学習を知らない人でも気軽に機械学習できるサービスなのかなと思いました

ちなみに今回の作業で掛かったお値段は約 $0.5 ドルでした
学習データや評価データの量がもっと多いと金額もあがってくると思います

参考サイト

2018年8月28日火曜日

Ruby で Google App Engine (GAE) 入門

概要

今更ですが GAE に入門してみました
Ruby アプリを動かします
作業は Google Cloud Shell で進めます
先に記載しておきますが App Engine の default リソースを使用するのでプロジェクトを削除する以外リソースを削除することができないので、もしリソースを削除したい場合はテスト用のプロジェクトを作成してから作業してください

環境

  • Google App Engine (2018/08/23 時点)

準備

デプロイ

  • gcloud app deploy

Updating service [default] (this may take several minutes)... が結構長いです
でしばらくするとデプロイが完了するので

  • gcloud app browse

でブラウザを開いてアプリを確認しましょう

別のアプリをデプロイしてみる

default サービスは削除できないのでそのまま上書きデプロイしてみます

同じようにデプロイが完了したらブラウザでアクセスしてみましょう

お掃除

default のサービスは消せません
また、default のサービスが可動しているインスタンスも削除できません
基本的にはアプリを止めておくしかできません
gae3.png

また CloudStorage にデプロイしたアプリのコンテナイメージが保存されているので、これも削除しておきましょう

アクセスがなければインスタンスが増えることもないので無料枠内で収まるはずです
もしどうしても削除したい場合はプロジェクト自体を削除するしかないようです

最後に

GAE に Ruby アプリをデプロイしてみました
自分のアプリを GAE で動かすには app.yaml を追加してあげるだけで OK です
GAE は現状コンテナで動かすのが定石になっているようです

Dockerfile がすでにある場合は app.yaml の runtimecustom にする必要があるようです
またアプリは 8080 ポートで LISTEN している必要があるようです

ビルドはそこまで時間はかからなかったのですが、デプロイに結構時間がかかるイメージでした
また気になったのは FROM でイメージを取得するのが gcr でなければいけないというドキュメントがあったのですが普通に dockerHub から持ってこれました
公式イメージであれば良いなどがあるのかもしれません

Tips

インスタンスの数を確認

  • gcloud app instances list

アプリのログは Stackdriver Logging に投げられています

参考サイト

2018年8月27日月曜日

Ubuntu16.04 で Master ノード 1 台、Worker ノード 1 台の kubernetes クラスタを構築してみた

概要

過去に minikube を使った k8s の構築や lxd を使った k8s の構築を行いました
今回はもう少し進んで本格的な k8s クラスタを構築してみました
Master ノード 1 台、Worker ノード 1 台の構成です
なお使用する構築ツールは kubeadm になります

環境

  • Ubuntu 16.04
  • docker 18.06.1-ce
  • kubeadm, kubectl, kubelet v1.11.2

Master ノード構築

docker install

  • apt -y update
  • apt -y install apt-transport-https software-properties-common curl
  • curl -s https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
  • add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
  • apt -y update
  • apt -y install docker-ce docker-ce-cli containerd.io

kubeadm, kubelet, kubectl install

  • curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
  • echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" > /etc/apt/sources.list.d/kubernetes.list
  • apt -y update
  • apt-get install -y kubeadm kubelet kubectl

クラスタ初期化

  • swapoff -a
  • kubeadm init --apiserver-advertise-address=116.118.227.170 --pod-network-cidr=10.244.0.0/16

ここで表示される kubeadm join コマンドはメモしておきましょう
pod-network-cidr は flannel を使用するので指定が必須です

操作用のユーザ作成

  • adduser hawk
  • usermod -aG sudo hawk
  • su - hawk
  • mkdir -p $HOME/.kube
  • sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  • sudo chown $(id -u):$(id -g) $HOME/.kube/config

flannel 構築

  • kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

操作用ユーザで行います

Worker ノード構築

docker install

  • apt -y update
  • apt -y install apt-transport-https software-properties-common curl
  • curl -s https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
  • add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
  • apt -y update
  • apt -y install docker-ce docker-ce-cli containerd.io

kubeadm, kubelet, kubectl install

  • curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
  • echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" > /etc/apt/sources.list.d/kubernetes.list
  • apt -y update
  • apt-get install -y kubeadm kubelet kubectl

クラスタ join

  • swapoff -a
  • hostnamectl set-hostname node1
  • kubeadm join 116.118.227.170:6443 --token p06lq6.17gtmq109vk7gxuf --discovery-token-ca-cert-hash sha256:97f82e93d768f0f3ca9494d8d1e3ee6bb5409b3d8e9a3e2b8c371bb57889a6e8

先程 kubeadm init 時にメモした join コマンドを使います
Master と同じホスト名だと join できないので変更します

動作確認

Master ノードに作成した操作用ユーザで行います

  • kubectl get node
NAME      STATUS    ROLES     AGE       VERSION
node1     Ready     <none>    1m        v1.11.2
ubuntu    Ready     master    32m       v1.11.2

ついでにアプリも動かしてみます

  • kubectl create deployment hello-node --image=k8s.gcr.io/echoserver:1.4
  • kubectl expose deployment hello-node --type=NodePort --port=8080

あとは kubectl get pod でコンテナが作成されたらアクセスすれば OK です
アクセス先は NodePort を使っているので、IP が Worker ノードのパブリック IP でポートが NodePort 用のポートです

  • kubectl describe service hello-node
Name:                     hello-node
Namespace:                default
Labels:                   app=hello-node
Annotations:              <none>
Selector:                 app=hello-node
Type:                     NodePort
IP Families:              <none>
IP:                       10.100.104.233
IPs:                      10.100.104.233
Port:                     <unset>  8080/TCP
TargetPort:               8080/TCP
NodePort:                 <unset>  32436/TCP
Endpoints:                192.168.1.3:8080
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

192.168.1.3:8080 がアクセスポートになります

Tips

クラスタからノードを切り離す場合は以下でできます

  • kubeadm reset

全リソースを取得する

  • kubectl get all

トラブルシューティング

うまくクラスタに join できない場合は FW (ufw) の設定などを確認してみてください

swap に関して怒られた場合は上記の手順にあるように swapoff -a してみてください

running with swap on is not supported. Please disable swap

コンテナがうまく起動しない場合は

  • kubectl get pods
  • kubectl describe pod hello-node-546c7dcc87-lp5j7
  • kubectl logs hello-node-546c7dcc87-lp5j7

などでコンテナの状況を確認してみましょう

最後に

Ubuntu16.04 上で Master 1 台+Worker 1 台の kubernetes クラスタを構築してみました
結構簡単にできたのでビックリです
構築用のドキュメントが乱立しており大変なイメージがあったのですが、

あとは同じように Worker ノードを増やしていけば簡単にクラスタを拡張することができます

参考サイト

2018年8月26日日曜日

GCE の無料枠 f1-micro インスタンス作成メモ

概要

GCE の f1-micro は 1 台であれば無料です
いつもリージョンの指定方法などを忘れてのでメモしておきます

環境

  • Google Compute Engine (2018/08/22 時点)

インスタンス作成

gce_free1.png

  • リージョン・・・us-central1
  • ゾーン・・・us-central1-b
  • マシンタイプ・・・micro
  • 永続ディスク・・・30GB

大事なのは上記の選択です
リージョンやストレージのサイズを間違えると Always free ではなくなるので注意してください

静的 IP

「Management, security, disks, networking, sole tenancy」から設定します
DNS など張る場合は付与しましょう
そうでない場合 (検証などで一時的に使うだけなど) は特に設定は不要かなと思います
gce_free2.png

こんな感じです
gce_free3.png

動作確認 (SSH)

Cloud Shell から SSH するコマンドを発行します

  • gcloud compute --project "your-project-id" ssh --zone "us-central1-b" "all"

まだ鍵がない場合は鍵を生成してくれます
パスフレーズを入力しましょう
これで鍵が Cloud Shell 上に保存されます
また「Compute Engine」->「メタデータ」->「SSH 鍵認証」にも公開鍵が登録されています

次に SSH する際は入力したパスフレーズでログインできるようになります
秘密鍵をローカルに持ってくればローカルからでも SSH できます

静的 IP を使っていないときは

IP を開放しましょう
「ネットワーキング」->「VPC ネットワーク」->「外部 IP アドレス」で一覧を表示します
gce_free4.png

あとは選択して「静的アドレスを開放」すれば OK です
gce_free5.png

月に数ドルくらいであれば掛かっても良いという場合にはこれはしなくて OK です

最後に

GCE の f1-micro を無料で使うための設定を紹介しました
GUI でポチポチやるのは面倒なので gcloud コマンドで一発で作成できるようにしておいても良いかなと思います

さすがにスペック的にプロダクションで使うのは厳しいので個人的にはテンポラリーとして使っています
外部からのアクセス確認やある作業をする際の事前のテストサーバとして使っています

本当にありがたいサービスです

参考サイト

2018年8月25日土曜日

Istio を GKE 上にデプロイしてルーティング機能を試してみた

概要

Istio は GKE 上で複数のマイクロサービスを接続、保護、モニタリングするためのフレームワークです
現状何が嬉しいのかさっぱりな状態なのでまずは GKE 上に Istio を展開するところまでやってみました
サンプルアプリも動かしてルーティング機能の挙動も確認しています
また Istio も 1.0.0 になりサンプルの実行方法が若干変わっていたのでその辺りも紹介します

環境

  • Google Kubernetes Engine (2018/08/23 時点)
  • Google Cloud Shell (2018/08/23 時点)
  • Chrome 68.0.3440.106
  • Istio 1.0.0

クラスタ作成

この辺りは特に変わりません
クラスタ内に配置するノードは少しスペックの良いものを選択しています

  • gcloud config set project [project_id]
  • gcloud config set compute/zone us-central1-b
  • gcloud container clusters create istio-tutorial --machine-type=n1-standard-2 --num-nodes=4 --no-enable-legacy-authorization

こんな感じでできます
istio1.png

コマンドの場合は以下で確認できます

  • kubectl get nodes
  • kubectl describe node [node_name]

RBAC (Role-Based Access Control) を有効にする

Istio を使用するのに必須の設定です

  • kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user="$(gcloud config get-value core/account)"

現在のユーザに対して「cluster-admin」のロールを割り当てます

Istio のデプロイ

では Istio をデプロイします

  • wget 'https://github.com/istio/istio/releases/download/1.0.0/istio-1.0.0-linux.tar.gz'
  • tar zvxf istio-1.0.0-linux.tar.gz

でダウンロードし解凍しましょう

  • cd istio-1.0.0
  • export PATH=$PWD/bin:$PATH

これで istioctl というコマンドが使えるようになります

  • istioctl version

でバージョンが確認できます
ではデプロイしましょう
kubernetes 用の YAML 定義ファイル (1.0.0 時点では istio-demo-auth.yaml というファイル名) があるのでこれを元にデプロイします

  • kubectl apply -f install/kubernetes/istio-demo-auth.yaml

いろいろとデプロイがはじまります
完了するまで待ちましょう

デプロイ確認

たくさんデプロイされています
サービスの確認

  • kubectl get service -n istio-system
NAME                       TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)                                                                                                     AGE
grafana                    ClusterIP      10.19.240.8     <none>           3000/TCP                                                                                                    1m
istio-citadel              ClusterIP      10.19.252.88    <none>           8060/TCP,9093/TCP                                                                                           1m
istio-egressgateway        ClusterIP      10.19.245.233   <none>           80/TCP,443/TCP                                                                                              1m
istio-galley               ClusterIP      10.19.249.112   <none>           443/TCP,9093/TCP                                                                                            1m
istio-ingressgateway       LoadBalancer   10.19.253.82    35.226.140.154   80:31380/TCP,443:31390/TCP,31400:31400/TCP,15011:30625/TCP,8060:32560/TCP,15030:31322/TCP,15031:32753/TCP   1m
istio-pilot                ClusterIP      10.19.244.181   <none>           15010/TCP,15011/TCP,8080/TCP,9093/TCP                                                                       1m
istio-policy               ClusterIP      10.19.247.139   <none>           9091/TCP,15004/TCP,9093/TCP                                                                                 1m
istio-sidecar-injector     ClusterIP      10.19.242.130   <none>           443/TCP                                                                                                     1m
istio-statsd-prom-bridge   ClusterIP      10.19.253.240   <none>           9102/TCP,9125/UDP                                                                                           1m
istio-telemetry            ClusterIP      10.19.242.134   <none>           9091/TCP,15004/TCP,9093/TCP,42422/TCP                                                                       1m
jaeger-agent               ClusterIP      None            <none>           5775/UDP,6831/UDP,6832/UDP                                                                                  1m
jaeger-collector           ClusterIP      10.19.248.102   <none>           14267/TCP,14268/TCP                                                                                         1m
jaeger-query               ClusterIP      10.19.244.96    <none>           16686/TCP                                                                                                   1m
prometheus                 ClusterIP      10.19.242.88    <none>           9090/TCP                                                                                                    1m
servicegraph               ClusterIP      10.19.246.229   <none>           8088/TCP                                                                                                    1m
tracing                    ClusterIP      10.19.252.175   <none>           80/TCP                                                                                                      1m
zipkin                     ClusterIP      10.19.241.131   <none>           9411/TCP                                                                                                    1m

Pods の確認

  • kubectl get pods -n istio-system
NAME                                        READY     STATUS    RESTARTS   AGE
grafana-6995b4fbd7-4xvcc                    1/1       Running   0          2m
istio-citadel-54f4678f86-xjb2t              1/1       Running   0          2m
istio-egressgateway-c68bcd889-w2v6h         1/1       Running   0          2m
istio-galley-7bd8b5f88f-zfjmw               1/1       Running   0          2m
istio-ingressgateway-665699c874-sgsh5       1/1       Running   0          2m
istio-pilot-68cbbcd65d-bbcjz                2/2       Running   0          2m
istio-policy-7c5b5bb744-bpjq8               2/2       Running   0          2m
istio-sidecar-injector-85ccf84984-vggk4     1/1       Running   0          2m
istio-statsd-prom-bridge-55965ff9c8-grvzr   1/1       Running   0          2m
istio-telemetry-5b6c57fffc-5lm68            2/2       Running   0          2m
istio-tracing-77f9f94b98-9tt7k              1/1       Running   0          2m
prometheus-7456f56c96-9njld                 1/1       Running   0          2m
servicegraph-684c85ffb9-4qkhh               1/1       Running   0          2m

サンプルアプリのデプロイ

このままだとよくわからないので付属のサンプルアプリをデプロイしてみましょう

  • kubectl apply -f <(istioctl kube-inject -f samples/bookinfo/platform/kube/bookinfo.yaml)

bookinfo.yaml というサンプルがあるのでこれを使います
完了したら内容を確認してみましょう

  • kubectl get services
NAME          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
details       ClusterIP   10.19.250.218   <none>        9080/TCP   45s
kubernetes    ClusterIP   10.19.240.1     <none>        443/TCP    26m
productpage   ClusterIP   10.19.241.109   <none>        9080/TCP   42s
ratings       ClusterIP   10.19.249.41    <none>        9080/TCP   44s
reviews       ClusterIP   10.19.251.116   <none>        9080/TCP   44s

アプリに必要な複数のサービスがデプロイされています

  • kubectl get pods
NAME                              READY     STATUS    RESTARTS   AGE
details-v1-74c6674976-9sw7r       2/2       Running   0          1m
productpage-v1-6f5d648f5b-qgphm   2/2       Running   0          1m
ratings-v1-76bff46c48-r286k       2/2       Running   0          1m
reviews-v1-74fbd7fc56-wqlhr       2/2       Running   0          1m
reviews-v2-864964989d-2vhfh       2/2       Running   0          1m
reviews-v3-5c5c4ff456-bwnww       2/2       Running   0          1m

サービスに対応する Pods も存在しているのがわかります

外部からアクセスできるようにする

これまでのサンプルだとこれでアプリにアクセスできるようになってたのですが 1.0.0 だと ingress するための YAML ファイルがあります
これを実行しないとアプリにアクセスできません

  • kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
  • kubectl get gateway
NAME               AGE
bookinfo-gateway   2m

動作確認

デプロイしたアプリにアクセスしてみます
Istio をデプロイした際に istio-ingressgateway というグローバル IP 付きのロードバランサにぶら下がっています
この IP にアクセスしてみましょう

  • kubectl get service -n istio-system istio-ingressgateway
NAME                   TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)                                                                                                     AGE
istio-ingressgateway   LoadBalancer   10.19.253.82   35.226.140.154   80:31380/TCP,443:31390/TCP,31400:31400/TCP,15011:30625/TCP,8060:32560/TCP,15030:31322/TCP,15031:32753/TCP   13m
  • curl -I http://35.226.140.154/productpage
HTTP/1.1 200 OK
content-type: text/html; charset=utf-8
content-length: 4415
server: envoy
date: Thu, 23 Aug 2018 02:13:17 GMT
x-envoy-upstream-service-time: 1233

ブラウザでアクセスすると以下のような画面になると思います
istio2.png

何度かブラウザを更新すると星の色が赤になったり黒になってりなくなったりすると思います

アプリへのルーティングを設定する

たぶんこれが Istio の機能の一つなんだと思います
ルーティングを切り替えることでアプリにアクセスできるようにしたりできなくしたりすることができます

  • kubectl apply -f samples/bookinfo/networking/destination-rule-all.yaml

これでブラウザにアクセスすると先程のアプリが見えなくなります
再度以下を実行すると見えるようになります

  • kubectl apply -f samples/bookinfo/networking/destination-rule-all-mtls.yaml

こんな感じで kubernetes 上にデプロイした Istio アプリはルーティングルールを YAML で定義することで ON/OFF することができようになるようです

お掃除

1.0.0 になって若干変わっているのでご注意を

  • kubectl -n istio-system delete service istio-ingressgateway
  • gcloud container clusters delete istio-tutorial

最後に

GKE 上に Istio を構築し Istio アプリをデプロイしてみました
またルーティングを使ってアプリへのアクセス制御を行ってみました

kubernetes 上にたくさんのアプリがデプロイされている場合に確かにデモのようなアクセス制御の機能があると便利なのかなと思いました

おそらく触った機能は基礎の基礎なのでもっとたくさんの機能があると思います
ちょっとお金がゴリゴリ掛かるので基本だけにしましたが機会があれば他の機能も試してみたいなと思います

触った率直な感想だと少し「複雑」だなと感じました
kubernetes だけでも大変なのに Istio のことも考えないといけなくなるとかなり学習コストは高いのかなと思います
現状は Istio の動作環境は GKE がメインなので、例えば minikube などでも簡単に動かせるようになればまた違ってくるのかなと思いました

ちなみに 2 時間ほどクラスタは起動していましたが料金は $0.5 もいかないくらいでした

参考サイト

2018年8月24日金曜日

Google Kubernetes Engine を試してみた

概要

GKE (Google Kubernetes Engine) は Google Cloud Platform 上で kubernetes 環境を構築することができるサービスです
過去に GCE というサービスを試しましたがそれが進化して GKE になりました

今回は公式のチュートリアルを試してみました
作業は GUI からではなくすべてコマンドで行います
なおこの作業は有料になるのでご注意ください

環境

  • Google Kubernetes Engine (2018/08/22 時点)
  • Google Cloud Shell (2018/08/22 時点)
  • Chrome 68.0.3440.106

事前準備

  • Google アカウントの取得
  • Google Cloud Platform でプロジェクトの作成
  • 作成したプロジェクトに支払い (クレカ) 情報を紐付ける

は事前に実施しておきましょう
GKE は有料のサービスになるのでプロジェクトに支払い情報がなければいけません

Google Cloud Shell を準備する

gcloud コマンドと kubectl コマンドを使います
ローカルにインストールしても OK ですがブラウザ情報でコマンドを実行することができる「Google Cloud Shell」を今回は使います

新しく Google Cloud Platform のダッシュボード画面を開きます
そして右上の「Active Cloud Shell」を選択すれば OK です
gke1.png

接続までに少し時間がかかるので完了するまで待ちましょう

gcloud コマンドの設定をする

使用するプロジェクトなどを指定します

  • プロジェクトの指定
    • gcloud config set project [project_id]

プロジェクトの設定の確認は gcloud config list で確認できます
Google Cloud Shell を使っていればすでにプロジェクトは作成されていると思います

  • デフォルトリージョンを設定
    • gcloud config set compute/zone asia-south1-b

設定可能なゾーンの一覧は gcloud compute zones list で確認できます
今回は asia-south1-b にしましたがお好きなところをお選びください

クラスタの作成

ではここからが本題になります
まずはクラスタを作成しましょう

  • gcloud container clusters create cluster1

cluster1 という名前のクラスタを作成しています

NAME      LOCATION       MASTER_VERSION  MASTER_IP       MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
cluster1  asia-south1-b  1.9.7-gke.5     35.200.224.251  n1-standard-1  1.9.7-gke.5   3          RUNNING

クラスタ作成されると自動的にコンテナ用のノードも追加されるようです
NUM_NODES が 3 になっていますが 3 台いきなり作成されるようです

ちなみに GUI で確認すると以下のような感じでした
gke2.png

  • gcloud container clusters list

でも確認できます
この時点ですでにお金が発生しているので注意してください

クラスタの認証情報を取得

  • gcloud container clusters get-credentials cluster1

これでクラスタに対して kubectrl コマンドアクセスできるようになります
このあとアプリのデプロイをするのに使います

Fetching cluster endpoint and auth data.
kubeconfig entry generated for cluster1.

.kube/config にファイルとして保存されています

サンプルアプリをデプロイする

hello-app というサンプルアプリがあるのでこれをデプロイします

Deployment を作成する

まずはアプリをデプロイします
デプロイしただけではアプリにアクセスすることができません

  • kubectl run hello-server --image gcr.io/google-samples/hello-app:1.0 --port 8080

イメージはすでに用意してあるサンプルを使用します

deployment "hello-server" created

この情報は GUI 上の「ワークロード」でも確認することができます
gke3.png

  • kubectl get deploy

でも確認できます

デプロイしたアプリを公開する

先程デプロイしたアプリをロードバランサにぶら下げて公開します

  • kubectl expose deployment hello-server --type "LoadBalancer"
service "hello-server" exposed

これでデプロイしたアプリにアクセスすることができます

動作確認

  • kubectl get service hello-server

でアクセスする IP を確認できます

NAME           TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)          AGE
hello-server   LoadBalancer   10.51.240.23   35.200.200.238   8080:31668/TCP   6m

上記の場合であれば http://35.200.200.238:8080 にアクセスすればアプリを確認することができると思います

Hello, world!
Version: 1.0.0
Hostname: hello-server-579859fb5b-sttzx

上記のようなテキストが記載された画面が表示されると思います
これでチュートリアルは終了です

お掃除

このままだとお金が発生し続けてしまうのでリソースを削除しましょう

  • kubectl delete service hello-server
  • gcloud container clusters delete cluster1

Deployment は削除しないでもクラスタを削除できます
クラスタを削除するときは確認の旨が聞かれるので「y」を選択しましょう
これでリソースが削除されます

最後に

Google Kubernetes Engine のチュートリアルを試してみました
画面でポチポチするよりも Google Cloud Shell を使ったほうが簡単にできると思います
チュートリアル自体はかなり簡単な内容なので特に躓く点はないかなと思います
またこれをベースに istio のチュートリアルを行うことも可能です

クラスタ内に生成されるインスタンスが n1-standard-1 というサイズのインスタンスで 3 台作成されたのですが GCE には更に格安な f1-micro というインスタンスがあります
今回は試してないですが、もしこれでクラスタを構築できるならこれの方が安く済むと思います

ちなみに今回のチュートリアルでかかった料金は $0.1 でした (請求金額が翌日にならないとわかりません)
gke4.png

参考サイト

2018年8月23日木曜日

GPG Key を使ってみる

概要

GPG (GNU Privacy Guard) は暗号化のソフトウェアです
データを渡す際にセキュリティを高めるためにあらかじめ GPG で暗号化してから渡したりします
今回は使い方を紹介します

環境

  • Ubuntu 16.04 (A, B)
  • gpg 1.4.20

キーの作成 (A)

  • gpg --gen-key

いろいろ聞かれます
ユーザ名やメールアドレスを入力する必要もあります
以下のような感じで作成しました

  • gpg --list-keys
/root/.gnupg/pubring.gpg
------------------------
pub   2048R/0CEAD198 2018-08-21
uid                  hawksnowlog (admin) <hawksnowlog@gmail.com>
sub   2048R/B62F9EC7 2018-08-21
  • gpg --list-secret-keys
/root/.gnupg/secring.gpg
------------------------
sec   2048R/0CEAD198 2018-08-21
uid                  hawksnowlog (admin) <hawksnowlog@gmail.com>
ssb   2048R/B62F9EC7 2018-08-21

鍵を公開する (A)

  • gpg --send-keys 0CEAD198
gpg: sending key 0CEAD198 to hkp server keys.gnupg.net

公開された鍵を取得する (B)

別のサーバで行います

  • gpg --search-keys "hawksnowlog"
gpg: searching for "hawksnowlog" from hkp server keys.gnupg.net
(1)     hawksnowlog (admin) <hawksnowlog@gmail.com>
          2048 bit RSA key 0CEAD198, created: 2018-08-21
Keys 1-1 of 1 for "hawksnowlog".  Enter number(s), N)ext, or Q)uit > 1
gpg: requesting key 0CEAD198 from hkp server keys.gnupg.net
gpg: key 0CEAD198: public key "hawksnowlog (admin) <hawksnowlog@gmail.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)

検索できると思うので「1」を入力して取得します
(なぜかよくわからないのですがたまに検索できないときがあります、もしかするとサーバ間で鍵データを同期しているため同期が完了してないサーバに問い合わせているからかもしれません)

gpg --list-keys で鍵が登録されているのが確認できると思います

暗号化する (B)

--search-keys で鍵を登録したマシンで行います
暗号化は公開鍵で行い復号化は秘密鍵で行うためです

  • date > hoge.txt
  • gpg -e -r hawksnowlog hoge.txt
gpg: B62F9EC7: There is no assurance this key belongs to the named user

pub  2048R/B62F9EC7 2018-08-21 hawksnowlog (admin) <hawksnowlog@gmail.com>
 Primary key fingerprint: D45E E561 7186 0F93 2D25  0830 76F0 0D80 0CEA D198
      Subkey fingerprint: E67C 4DEA 45E3 19CB 8CC3  DE37 990C 2242 B62F 9EC7

It is NOT certain that the key belongs to the person named
in the user ID.  If you *really* know what you are doing,
you may answer the next question with yes.

Use this key anyway? (y/N) y

hoge.txt.gpg が完成しています

  • file hoge.txt.gpg
hoge.txt.gpg: PGP RSA encrypted session key - keyid: 42220C99 C79E2FB6 RSA (Encrypt or Sign) 2048b .

復号化してみる (A)

秘密鍵があるマシンで行います
先程の hoge.txt.gpg を scp なりメールなりクラウドストレージなりで秘密鍵のあるマシンに移動します
復号化します

  • gpg hoge.txt.gpg
You need a passphrase to unlock the secret key for
user: "hawksnowlog (admin) <hawksnowlog@gmail.com>"
2048-bit RSA key, ID B62F9EC7, created 2018-08-21 (main key ID 0CEAD198)

gpg: gpg-agent is not available in this session
gpg: encrypted with 2048-bit RSA key, ID B62F9EC7, created 2018-08-21
      "hawksnowlog (admin) <hawksnowlog@gmail.com>"

gpg --gen-keys した際にパスレーズを設定している場合は複合する場合に必要になります

これで hoge.txt が復元できました

  • cat hoge.txt
Tue Aug 21 16:30:50 JST 2018

最後に

GPG Key を使ってデータの暗号化と復号化を試してみました
用途としてはデータをリモートの誰かに渡す場合に通信経路が暗号化などされていない場合にファイル自体を暗号化してセキュリティを強化する感じかなと思います

IT リテラルを試すのに「GPG を xxx という名前で公開しているので暗号化してメールで送ってください」ってのも良いかもしれません

一番身近なところだと apt や yum のパッケージを暗号化して配布する場合でしょうか
データの受け渡しなどは最近はクラウドストレージがあるのでわざわざ GPG する必要もないかなと思っています

Tips

keys.gnupg.net に公開した鍵を削除する方法
厳密には失効 (revoke) させるだけ

  • gpg --output revoke.asc --gen-revoke 0CEAD198
  • gpg --import revoke.asc
  • gpg --keyserver keys.gnupg.net --send-keys 0CEAD198

で確認すると revoke 状態になっているはずです

  • gpg --search-keys hawksnowlog
gpg: searching for "hawksnowlog" from hkp server keys.gnupg.net
(1)     hawksnowlog (admin) <hawksnowlog@gmail.com>
          2048 bit RSA key 0CEAD198, created: 2018-08-21 (revoked)

トラブルシューティング

Not enough random bytes available.  Please do some other work to give
the OS a chance to collect more entropy! (Need 294 more bytes)

が出る場合は以下を実行してください

  • apt -y install rng-tools
  • rngd -r /dev/urandom

参考サイト

2018年8月22日水曜日

nginx-rtmp-module で HLS を使う方法

概要

前回、nginx-rtmp-module を使った nginx の構築と rtmp をライブ配信の方法を紹介しました
今回は更にそこから HLS (Http Live Streaming) を使った配信をしてみます
基本は前回と同じなので変更した部分だけ紹介します

環境

サーバ

  • Ubuntu 16.04
  • nginx 1.15.3

配信クライアント

  • macOS X 10.13.5
  • OBS 21.1.1

視聴クライアント

  • macOS X 10.13.5
  • Chrome 68.0.3440.106
  • video.js 7.0

nginx.conf の修正

http ディレクティブに以下を追加します
hls 用の Content-Type を指定します

location /myhls {
    types {
        application/vnd.apple.mpegurl m3u8;
        video/mp2t ts;
    }
    root /tmp;
    add_header Cache-Control no-cache;
}

HLS 用の設定を追記します

rtmp {
    server {
        listen 1935;
        chunk_size 4000;

        application myhls {
            live on;

            record all;
            record_path /tmp/av;
            record_max_size 1K;
            record_unique on;

            hls on;
            hls_path /tmp/myhls;

            allow publish 106.181.187.16;
            deny publish all;

            allow play all;
        }
    }
}

追加しているのは以下の 2 つです

  • hls on・・・ HLS を有効にする
  • hls_path /tmp/myhls・・・hls に変換するテンポラリーディレクトリを指定

/tmp/myhls を変更した場合は location に追加した root /tmp パスも変更してください
また location 自体のパスも変更してください

HLS 用のプレイヤーの作成

rtmp では flash が必須でしたが HLS では不要です
HLS 用のプレイヤーを作成しましょう

  • vim /usr/local/nginx/html/index.html
<html>
  <head>
    <title>HLS livestreaming</title>
    <link href="https://vjs.zencdn.net/7.0/video-js.min.css" rel="stylesheet">
  </head>
  <body>
    <video id=example-video width=1280 height=720
       class="video-js vjs-default-skin" controls>
      <source
         src="http://192.168.100.50/myhls/live.m3u8"
         type="application/x-mpegURL">
    </video>
    <script src="https://vjs.zencdn.net/7.0/video.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/videojs-contrib-hls/5.14.1/videojs-contrib-hls.min.js"></script>
    <script>
      var player = videojs('example-video');
      player.play();
    </script>
  </body>
</html>

source タグで指定する IP の部分は書き換えてください
あとは同じで動作するはずです

動作確認

OBS を起動して配信を開始しましょう
/tmp/myhls 配下にエンコードされた hls 用のファイルが作成されていることがわかると思います

live-0.ts
live-1.ts
live-2.ts
live-3.ts
live-4.ts
live-5.ts
live-6.ts
live.m3u8

エンコードされた live.m3u8 が /myhls/live.m3u8 で見える設定になっているので、それをプレイヤーが受け取って再生する仕組みです

ブラウザに flash がインストールされていない場合でも再生できるのがわかると思います

最後に

nginx-rtmp-module で HLS を使う方法を紹介しました
設定自体は既存の rtmp の設定に HLS のフラグをオンにしディレクトリを作成するだけでした

ただ、HLS 用のプレイヤーを作成する必要はあります
プレイヤーもそうですが、クライアント側で Flash が不要になるというはかなり嬉しい点かなと思います

iOS など Apple のモバイル系 OS では基本 Flash が再生できないので HLS が登場したのも納得できます

参考サイト

2018年8月21日火曜日

nginx-rtmp-module + OBS でライブ配信をしてみる

概要

nginx に RTMP 用のモジュールを追加することでライブ配信することができます
今回は nginx-rtmp-module のインストール方法から OBS を使った配信方法までを紹介したいと思います

環境

サーバ

  • Ubuntu 16.04
  • nginx 1.15.3

配信クライアント

  • macOS X 10.13.5
  • OBS 21.1.1

視聴クライアント

  • macOS X 10.13.5
  • Chrome 68.0.3440.106
  • video.js 7.0

nginx-rtmp-module 入の nginx をインストールする

先に必要なモジュールをインストールします

  • apt -y update
  • apt -y install libpcre3-dev libssl-dev

nginx はソースからインストールする必要があります

/usr/local/nginx/sbin/nginx がバイナリです
/usr/local/nginx/ 配下に設定ファイルやドキュメントルートのディレクトリがあります

nginx.conf の設定

rtmp ディレクティブの設定を入れます
既存の設定はそのまま使うので以下を最後に追記してください

  • vim /usr/local/nginx/conf/nginx.conf
rtmp {
    server {
        listen 1935;
        chunk_size 4000;

        application mytv {
            live on;

            record all;
            record_path /tmp/av;
            record_max_size 1K;
            record_unique on;

            allow publish 192.168.100.50;
            deny publish all;

            allow play all;
        }
    }
}

listen 1935 で rtmp のポートを指定します
application ディレクティブで配信の設定をします
「mytv」の部分は任意の文字列です
配信と視聴の際の URL に使います
live on とすることでライブストリーミングすることができます
nginx-rtmp-module ではビデオオンデマンドによる動画配信もできるのでその場合は live を off にしましょう

record の部分はサーバに録画ファイルを残すかの設定になります
パスや保存されるファイルの命名規則を指定します

allow/deny publish で配信クライアントの IP 制限が行えます
allow/deny play で視聴クライアントの IP 制限ができます

rtmp サーバの起動

  • /usr/local/nginx/sbin/nginx

-s stop を付与することで停止できます
1935 ポートで LISTEN していることを確認しましょう

クライアント設定

視聴側 (HTML + JS )と配信側 (OBS) のクライアントの準備をします

視聴用のクライアントを作成する

ブラウザで使用するので HTML + JS で構築します
今回は video.js + Flash を使って再生します

  • cd cd /usr/local/nginx/html
  • vim index.html
<!DOCTYPE html>
<html lang="en" class="">
<head>
  <link href="https://vjs.zencdn.net/7.0/video-js.min.css" rel="stylesheet">
  <script src="https://vjs.zencdn.net/7.0/video.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/videojs-flash/2.1.1/videojs-flash.min.js"></script>
</head>
<body>
  <video id="rtmp_mytv_mytv" class="video-js vjs-default-skin" controls
   preload="auto" width="640" height="264" data-setup='{}'>
    <source src="rtmp://192.168.100.50:1935/mytv/mytv" type='rtmp/mp4'>
    <p class="vjs-no-js">
      To view this video please enable JavaScript, and consider upgrading to a web browser
      that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a>
    </p>
  </video>
</body>
</html>

とりあえずコピペして source タグの部分を編集すれば動作するはずです
mytv/mytv の後ろの mytv はあとで OBS の設定で使います
好きな文字列で OK です
プレイヤーのサイズが 640x264 で少し小さいので大きくしてもいいかと思います

配信側のクライアントの設定

OBS の設定をします
「Preferences」->「配信」->「カスタムストリーミングサーバー」を設定します
構築した rtmp サーバの URL を入力しましょう
nginx_rtmp_module1.png

そしてストリームキーは先程プレイヤーで指定した mytv/mytv の後ろの部分の文字列を入力しましょう

テストとして映像のソースにスクリーンキャプチャを適当に設定しました
あとは映像の設定や音声の設定は好みでお願いします (デフォルトのままでも動作します)

準備できたら「配信開始」をクリックします
緑のステータスになれば OK です

動作確認

ブラウザで rtmp サーバの 80 番ポートにアクセスしましょう
作成したプレイヤーが表示されると思います

Flash を有効にして video.js の再生ボタン -> Flash の再生ボタンを押すと配信を見れると思います
nginx_rtmp_module2.png

トラブルシューティング

  • No compatible source was found for this media.

以下をプライヤーに追加してみてください
RTMP は Flash が必要になるので以下のスクリプトの読み込みも必要になります
上記で紹介したサンプルにはすでに含まれています

<script src="https://cdnjs.cloudflare.com/ajax/libs/videojs-flash/2.1.1/videojs-flash.min.js"></script>

最後に

nginx + RTMP でライブ配信する方法を紹介しました
結構簡単にできました

Red5 でも RTMP を使ったライブ配信ができますがお手軽さ的にはこちらの方がいいかなと思います
ただ Red5 は他にもいろいろな配信プロトコルをサポートしているので用途に合わせて使い分けると良いかなと思います

参考サイト

2018年8月20日月曜日

Patreon REST API を Ruby から使ってみた

概要

タイトルのとおりです
UI を構築するわけではないので OAuth を使ったログイン画面などは作成しません
今回は自身のアカウントの情報を取得してみたいと思います

環境

  • macOS 10.13.5
  • patreon-ruby 0.5.0
  • Ruby 2.5.1p57

クライアントアプリの登録

https://www.patreon.com/portal/registration/register-clients から登録しましょう
patreon_api1.png

アプリの必要な情報を入力します
patreon_api2.png

アイコンの URL プライバシーポリシーの URL、規約の URL は必須ではありません
以下のように作成できれば OK です
patreon_api3.png

今回は「Creator's Access Token」を使います

Patrons を取得するサンプルコード

Patrons は要するに支援してくれている方々です

require 'patreon'
require 'cgi'

access_token = 'creators_access_token'
api_client = Patreon::API.new(access_token)

campaign_response = api_client.fetch_campaign()
campaign_id = campaign_response.data[0].id

all_pledges = []
cursor = nil
while true do
  page_response = api_client.fetch_page_of_pledges(campaign_id, { :count => 25, :cursor => cursor })
  all_pledges.concat page_response.data
  next_page_link = page_response.links[page_response.data]['next']
  if next_page_link
    parsed_query = CGI::parse(next_page_link)
    cursor = parsed_query['page[cursor]'][0]
  else
    break
  end
end

puts all_pledges.map{ |pledge| { full_name: pledge.patron.full_name, amount_cents: pledge.amount_cents } }

Creator's Access Token を使って API クライアントを作成します
まず fetch_campaign()campaign_id を取得します
campaign_id はいわゆるユーザ ID みたいなものです

次にその ID を元に fetch_page_of_pledges() をコールします
ページネートしながら Patrons を取得することができます
次のページは page_response.links[page_response.data]['next'] で取得しています
これが nil であれば終了してそうでなければ次のページの URL をパースして cursol 情報を取得します

あとは最後に保存した配列の情報 (all_pledges) を map で必要なフィールドだけ取得して表示しています
map しているだけなのでそのまま puts しても OK です

おまけ

ちなみに今回の API であれば curl で簡単に呼べます

curl -XGET \
  -H 'Authorization: Bearer [creators_access_token]' \
  'https://www.patreon.com/api/oauth2/api/campaigns/[campaign_id]/pledges'

最後に

Patreon の REST API を Ruby でコールしてみました
今回はアプリを作成したユーザ自身の情報をしか取得しなかったのでログイン画面を作成しませんでした
もしログインしたユーザの情報を取得したい場合はログイン画面を作成して OAuth 認証してトークンをちゃんと取得して API をコールしてください

参考サイト

2018年8月19日日曜日

Red5 で RTMP を使ってライブ配信してみる

概要

Red5 はオープンソースの動画配信エンジンです
ストリーム配信できるのが特徴です
今回は構築から RTMP を使ったライブ配信の方法まで紹介します
OBS を使うのでプライベート Youtube Live のようなことができるようになります

環境

サーバ

  • Ubuntu 16.04
  • OpenJDK 9 (build 9-internal+0-2016-04-14-195246.buildd.src)
  • Red5 1.0.10 Milestone 9

クライアント

  • macOS X 10.13.5
  • OBS 21.1.1

JDK インストール

Red5 は Java (JDK) がないと動作しません
今回は OpenJDK を使います
OracleJava が良い場合は公式から Linux 版をダウンロードして Ubuntu 上に展開してください

  • apt -y update
  • apt -y instsall openjdk-9-jdk-headless

Red5 インストール

  • mkdir -p /usr/share/red5
  • export RED5_HOME=/usr/share/red5
  • cd $RED5_HOME
  • wget 'https://github.com/Red5/red5-server/releases/download/v1.0.10-M9/red5-server-1.0.10-M9.tar.gz'
  • tar zvxf red5-server-1.0.9-RELEASE.tar.gz
  • mv red5-server/* .

Red5 サーバ起動

  • ./red5.sh &

http://localhost:5080 にアクセスすると Red5 の管理画面が表示されます
ufw などでポートを閉じている場合はオープンしましょう

Flash のインストール

Red5 は動画を再生するのに基本的に Flash で動作します
VOD も Live も変わりません
面倒ですが素直にインストールしましょう
Chrome であれば有効にすれば OK です

ライブ配信してみる

構築が完了したのでライブ配信してみましょう
OBS の設定をしていきます

プロファイルの作成 (任意)

OBS に YoutubeLive や Twitch の配信設定をすでにしている場合は今回の Red5 用にプロファイルを作成するといいでしょう
red5_with_obs1.png

特に上書きしても問題ない場合はプロファイルの作成は必要ありません

ストリーミングサーバの設定

ストリーミングサーバの設定をします
構築した Red5 の RTMP プロトコルを LISETN しているポートを指定します
red5_with_obs2.png

  • URL・・・rtmp://xxx.xxx.xxx.xxx:1935/live
  • ストリームキー・・・testLive

URL の IP 部分は構築した自身の Red5 サーバの IP を指定してください
ストリームキーは動画を再生するときに必要になります
任意の文字列で OK なので好きな文字列を設定してください

出力設定

出力設定をします
この設定は Red5 推奨の設定になります
おそらくデフォルトの設定でも配信はできるはずですが今回は推奨設定を使います
red5_with_obs3.png

  • 出力モード・・・詳細
  • エンコーダ・・・x264 (ストリーミングサービスのエンコーダ設定を適用するにチェック)
  • 出力をリスケールする・・・640x480
  • レート制御・・・VBR
  • ビットレート・・・750
  • CRF・・・23
  • キーフレーム間隔・・・2
  • CPU 使用のプリセット・・・verfast
  • プロファイル・・・baseline
  • チューン・・・fastdecode

こんな感じです

映像配信設定

先程リスケールしたサイズに合わせます
red5_with_obs4.png

スクリーンキャプチャ設定

ライブで配信する際の映像情報を設定します
OBS の場合「ソース」から表示したい映像リソースを追加すれば OK です
今回は適当に「ウィンドウキャプチャ」を追加して Finder の情報を表示しておきます
red5_with_obs5.png

動作確認

これで配信の準備が整ったので配信を開始します

見る側の設定

今回は Red5 のデモで使用しているビューワをそのまま使います
本来であれば自分で HTML + JavaScript を使ってプレイヤーを再生するのですが面倒なのでありものを使います

Red5 のトップ画面にアクセスします
そして「Launch a demo」->「Publisher」->「View demo」と進みます
設定画面になったら

  • Name・・・testLive
  • Location・・・rtmp://xxx.xxx.xxx.xxx:1935/live

と入力します
配信する側も視聴する側も同じ URL とストリームキーにアクセスします
red5_with_obs6.png

入力したら「Connect」ボタンを押せば上記の画面のように接続状態になります (画面の Close ボタンが未接続の場合 Connect になっている)

あとは「Play」ボタンを押せば配信を見れるようになります

配信する側の設定

特にないです
OBSで「配信開始」ボタンを押せば OK です
ステータスが緑になれば Red5 の RTMP に接続され映像の配信が開始されています

この状態で Red5 のプレイヤーで「Play」を押せばライブ配信が見れると思います
red5_with_obs7.png

キャプチャする画面などを変更すればちゃんとプレイヤー側も変わります
ラグですがだいたい 3 - 5 秒くらいありました
この辺りは環境や設定によってもっと改善するとは思います

トラブルシューティング

OBS で配信開始した際に何度も切断される場合があります
以下のような Exception が発生していました

  • ProtocolException: Error during decoding
  • NumberFormatException: For input string: "2.1"

このあたりの Exception が発生してうまく配信開始できない場合は以下が原因です
https://github.com/Red5/red5-server/issues/250

解決方法は 1.0.10 系の Red5 を使いましょう
そのバージョンであれば対処されています

また FW の設定も見直しましょう
OBS が動作している環境から Red5 が動作している RTMP サーバに対して通信できる必要があります
1935 ポートは当然ですが今回は管理画面のプレイヤーを使うので 5080 なども必要です
できれば OBS 環境からはフルアクセスできると良いと思います

最後に

Red5 + OBS を使って自分だけのライブ配信環境を構築してみました
Red5 自体の構築はかなり簡単にできましたが、OBS 側の設定の RTMP の設定に少し苦戦しました

Red5 は再生する側に Flash Player が必要なのでそこは少し残念な感じがします

Red5 にはマルチテナントの機能がないので基本的には 1 Red5 = 1 User になるかなと思います
複数のユーザで 1 つの Red5 を共有したい場合は現状はストリームキーなどで分けるしかないかなと思います

あとはもし Red5 を使って配信するのであればプレイヤーの開発も必要かなと思います
今回はデモ用のプレイヤーを使ったので特にコーディングはしませんでしたが、さすがにあれば丸出しするのは微妙なので実際は専用のプレイヤーを開発する必要があると思います

参考サイト

2018年8月18日土曜日

SKUID を試してみた

概要

SKUID は GMO さんが提供する IDaaS (Identity as a Service) です
様々なサービスのアカウントとパスワードを SKUID で登録することで SKUID にログインするだけで登録したサービスにアクセスできるようになります
今回は登録から基本的な使い方まで試してみました

環境

  • macOS 10.13.6
  • SKUID (2018/08/09 時点)

アカウント登録

まずはアカウント登録をしましょう
企業情報などが必要になりますが、個人で利用の場合はダミーの情報でも大丈夫です
skuid1.png

次の画面で入力情報を確認しましょう
問題なければ登録します
仮登録のメールが登録したアドレスに届くのでチェックしてください
記載の URL をクリックすれば本登録完了です

アプリを追加する

企業 ID とメールアドレス、パスワードを使ってログインしましょう
skuid2.png

するとアプリを追加する流れになるので追加します
執筆時点では 4015 ほどアプリがありました
skuid3.png

今回は Twitter を選択しました
ブラウザですでに Twitter ログインしている場合は一旦ログアウトしましょう

Twitter にログインする情報を登録します
これで Twitter アプリの登録が完了します
skuid4.png

SKUID の Chrome 拡張を入れましょうという画面になるので素直にインストールしましょう
skuid5.png

SKUID はアカウント単位と組織単位でアプリを追加することができます
上記の作業はアカウントに対してアプリを追加しました
組織単位でアプリを追加すると組織に属するアカウントは自動的に組織に追加したアプリを利用することができるようになります (要するに個人で追加する必要がなくなる)

試してみる

とりあえずアプリがインストールされた Twitter アプリを選択してみましょう
skuid6.png

するとアプリに登録した Twitter のログイン情報を使って勝手に Twitter にログインしてくれます
(一瞬ログイン画面が表示されてフォームに情報を入力している感じがするので裏側では直接ブラウザを操作しているのかもしれません)
なので、ユーザは Twitter のアカウントとパスワードをわざわざ入力する必要がありません

なお、すでに別のユーザで Twitter にログインしているとアプリを選択してもアプリに登録したユーザで Twitter にログインできません
すでにログインしているユーザが優先されてしまうので SKUID からログインしたい場合はちゃんとログアウトしておきましょう

次に Chrome 拡張からログインしてみました
ツールバーにあるイカのアイコンを選択すると登録しているアプリが表示されるので Twitter のアイコンを選択してみましょう
skuid7.png

するとブラウザのときと同様にログインが行われます

メンバーを追加してみる

次に組織にメンバーを追加してみましょう
メンバーの追加は管理者権限を持つメンバーがダッシュボードから追加することができます (メンバーの一覧からも追加することができます)
skuid8.png

個別追加か一括追加を選択できます
今回は個別追加を選択します
一括追加は指定のフォーマットの CSV をアップロードすることで登録できるようです
skuid9.png

名前とメールアドレスを入力します
部署と権限を設定します
skuid10.png

あとは内容を確認して問題なければ「登録」しましょう
メールアドレスに SKUID に登録するための招待 URL が送られるのでそこからユーザ登録しましょう
登録する流れは冒頭の「アカウント登録」で紹介した内容と全く同じです
登録したらログインしてみましょう

管理者権限を持つメンバーでダッシュボードを確認するとメンバーが増えているのがわかると思います
skuid11.png

組織にアプリを追加する

組織にアプリを追加し、そのアプリを使うメンバーを追加することでメンバーのアプリの管理を管理者ができるようになります
組織にアプリを追加するにはダッシュボードのアプリの一覧から行います
「アプリ登録」を選択しましょう
skuid12.png

今回も Twitter を登録します
どうやら組織に登録できるアプリのほうが数が多いようです
とりあえず「Twitter パスワード認証」を選択しましょう
skuid13.png

企業アプリの場合 ID/PW などは設定せずただ登録するだけです
ID/PW の設定は各メンバーが行います
skuid14.png

アプリを使用するメンバーを登録する

企業アプリは登録しただけでは使えません
そのアプリを使うメンバーを指定する必要があります
先ほど登録下 Twitter アプリを選択し「メンバー追加」を選択します
skuid15.png

追加するメンバーを選択し登録しましょう
ここでメンバーを選択することでアプリの ACL 的なことが可能になります
skuid16.png

これでメンバーの登録アプリ一覧に行くと Twitter アプリが追加されています
ただまだ ID/PW の登録を行っていないのでグレースケールになっています
skuid17.png

アプリを選択すると ID/PW の画面になるので自身の ID/PW を登録することでメンバーごとの Twitter アカウントでログインすることができるようになります

グループを作成する

グループを追加することで先ほどメンバー単位でアプリへの使用権限を追加しましたが、これがグループ単位でできるようになります
追加は簡単でグループの一覧から「グループ追加」するだけです
skuid18.png

あとはグループの名前と説明を入力しましょう
skuid19.png

作成されたグループにはメンバーはいません
グループの一覧からグループを選択し「メンバー追加」することでメンバーを追加することができます
skuid20.png

レポート機能

レポートはメンバーの登録やグループの登録、アプリの登録など操作の履歴を確認することができます

ダッシュボードの左メニューから「レポート」で確認することができます

サードパーティ連携機能

アプリの種類もそうですが、このサードパーティの機能の充実っぷりがどうかによって IDaaS の優位性が出るかどうか決まると思っています
SKUID の場合無料のプランではほとんどの機能が使用できませんでした
skuid21.png

AD 連携や SAML 認証などメジャーどころは有料で申し込めば使えるようになります
各サービスとの SAML 認証の設定方法などは参考サイトに記載のドキュメントが一番わかりやすいと思います

また細かい設定としてロゴの変更やメンバーのアプリ登録などの ACL を変更することも可能です

最後に

IDaaS である SKUID を試してみました
無料で試せるので興味があれば触ってみると良いかなと思います
サードパーティ連携の機能がほぼ有料で触れなかったのは残念でした

UI はかなりわかりやすく作られていたかなーと思います
操作中はほぼ躓くこと無くやりたいことができたと思います

ただ退会することができなかったのでそれが微妙かなと思いました
公式にはオプションを有効にしない限り無料なので退会の必要はありませんとあり確かにそうなんですが退会できても良いかなと思いました

参考サイト