傀儡子えんじにあ の ぶろぐ

開発や自作PCなんかのやつをのせるやつ

スマートホーム支援LINE BOT

最近スマートホームって流行ってますよね
もはやスマホといえばスマートフォンでなくスマートホームだろってくらいの勢いなわけですが,その流行に乗っかり我が家も順調にスマートホーム化されつつあります
アクチュエータは全部Alexa対応なので声だけで操作可能
ただ、いろんなメーカーのが入り混じってるせいで、家の外から操作しようとすると各メーカーのアプリからじゃないとダメ
これがまあ不便なので、統一されたインターフェースから全部操作できたら楽ですよね
じゃあ何から操作しようかと考えたとき,一番工数少なくて楽そうなのはLINE BOTかなぁと
ついでにいろいろ盛り込んでちょっと作ってみました.

概要

f:id:suzkor:20190918013428p:plain
概要

という感じで主な機能はLambda様が行ってくださってます.
現状の機能としては

  1. 部屋の温湿度情報提供(家に配置したRaspberry Pi + DHT11から取得)
  2. 次のバス時刻情報提供(家⇔最寄り駅の双方向 自作のライブラリ使用)
  3. 天気情報提供(LWWSから取得)
  4. エアコン操作(IFTTT使ってスマートリモコン制御)
  5. チャットボット(A3RTのTalk APIと繋ぐ)

見ての通り,エアコン以外に本来想定してた機能を載せていません.
外から操作したい家電ってエアコン以外なかった

コード

github.com

完成品

f:id:suzkor:20190918012452p:plain
BOT スクショ
いちおう全部動きました
下のリッチメニューが地味に便利でよい

不満なとこ

相変わらずコードが絶望的に汚い
絶対もっときれいに書くやり方あるはず

あと、作ったはいいもののバス時刻取得用の自作のライブラリが仕様上反応遅いのでこれもDynamoDBにキャッシュしとこうかなと思案中

Kubernetes in Docker こと kind の環境構築

Kubernetesの基本については完全に理解したので、実際に触っていろいろやってみたくなりました
そこで実際に環境構築するうえで取れる手段は以下の3つくらいかなぁと

  1. Google Kubernetes Engine や Amazon EKSなんかのパブリッククラウドで使う
  2. Raspberry Pi なんかの安価なPC複数台で実際に作ってみる
  3. 学習用のツールを使う

1は多少とはいえ料金発生しちゃいますし、2は初期投資額がでかい
もちろんそのくらい払えやってのはあるんですがある程度使えるようになるまでは安く済ませたい

ということで、3の学習用ツールに目を付けました
ツールもいろいろあるんですが、後述の通り機能面に若干の不満が
そこで最近知った kind を使って環境構築してみましたので以下まとめ

kind.sigs.k8s.io

kind とは

Kubernetes IN Dockerの略称
k8sをローカルで構築しテストするためのツールの一つ
Windows,Mac,Linuxに対応
k8s公式もこれを使ってテストしてるらしい

他のツールとの相違点

kind以外にもminikubeなんかがある
kind最大の特徴はマルチノードクラスタが作成可能な点

k8sでは、複数のノードが参加して一つのクラスタを構成するのが一般的
しかし、他のツールではシングルノークラスタしか構成できず、限られた機能しか使うことができなかった
kindはマルチノードクラスタが作成可能なため、全てではないがより多くの機能を使用可能

kindの仕組み

kindでは、各ノードとして動作するdockerコンテナをデプロイしてクラスタを構成する
デフォルトで提供されているコンテナは、Ubuntu18.04を元に必要ないサービスを削除してサイズを小さくしたイメージ「node-image」を使用
自身で用意したイメージを使用して構成することもできる

Quick Start

今回はVMware仮想マシン上にマルチノードクラスタを作成し、nginxをデプロイするとこまでやってみます
仮想マシンはUbuntu18.04.3で、メモリ8GB、CPU4コアで動かしてます
メモリは公式によると最低8GB必要で、コア数についての記述は見つかりませんでしたがマルチノードクラスタなら4コアはあげといたほうが無難かと

kindのインストール準備

kindインストールの前に、docker、kubectl、Go言語を使用可能にする必要がありますのでまずはそっちから
とりあえずcurlgccが必要になるので入れておきましょう

$ sudo apt install -y curl gcc
1. dockerのインストール

dockerはapt install

$ sudo apt install -y docker.io
$ docker -v
Docker version 18.09.7, build 2d0083d
$ sudo usermod -aG docker suzkor

最後に、dockerグループにユーザーを追加します
これでdockerは準備完了 グループ変更したので、一回再起動しておきます

2. kubectlのインストール

公式のドキュメントを参考にいれて行きます

$ sudo apt-get update && sudo apt-get install -y apt-transport-https
$ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
$ echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.list
$ sudo apt-get update
$ sudo apt-get install -y kubectl
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.3", GitCommit:"2d3c76f9091b6bec110a5e63777c332469e0cba2", GitTreeState:"clean", BuildDate:"2019-08-19T11:13:54Z", GoVersion:"go1.12.9", Compiler:"gc", Platform:"linux/amd64"}
The connection to the server localhost:8080 was refused - did you specify the right host or port?

サーバーと通信できてないというエラーは出てますが、まあそんなものはないので当然
これでkubectlの準備もできました

3. Go言語のインストール
$ curl -O https://dl.google.com/go/go1.12.9.linux-amd64.tar.gz
$ sudo tar -C /usr/local -xzf go1.12.9.linux-amd64.tar.gz
$ export PATH=$PATH:/usr/local/go/bin
$ export PATH=$PATH:$(go env GOPATH)/bin

最後の2行は起動時毎回必要なので .profile にでも記載しておきましょう
これでGoの準備もできたので、kindを入れていきます

kindのインストール

以下のコマンドですんなり入ります

$ GO111MODULE="on" go get sigs.k8s.io/kind@v0.5.0
$ kind version
v0.5.0

これでインストール完了です

クラスタ作成

まずはテストでシングルノークラスタ作成してみましょう

kind create cluster
Creating cluster "kind" ...
 ✓ Ensuring node image (kindest/node:v1.15.3) 🖼 
 ✓ Preparing nodes 📦 
 ✓ Creating kubeadm config 📜 
 ✓ Starting control-plane 🕹️ 
 ✓ Installing CNI 🔌 
 ✓ Installing StorageClass 💾 
Cluster creation complete. You can now use the cluster with:

export KUBECONFIG="$(kind get kubeconfig-path --name="kind")"
kubectl cluster-info
$ export KUBECONFIG="$(kind get kubeconfig-path --name="kind")"
$ kubectl get nodes
NAME                 STATUS   ROLES    AGE   VERSION
kind-control-plane   Ready    master   96s   v1.15.3

作成後、言われた通りのコマンド実行するとkubectlが通るようになります
見てみると、シングルノードで動いてるのがわかります
というわけでテストはおk 作ったクラスタを削除しましょう

$ kind delete cluster

次は実際にマスター1、ワーカー2のクラスタ作ってみましょう
まずはYAMLクラスタの設定ファイル作ります

kind: Cluster
apiVersion: kind.sigs.k8s.io/v1alpha3
nodes:
- role: control-plane
- role: worker
- role: worker
  extraPortMappings:
  - containerPort: 30000
    hostPort: 80

これでマスターノード(control-plane)とワーカーノード(worker)2つが作られます
extraPortMappingsを設定しておくと、ホストとノードコンテナのポートフォワーディングが設定できます
動作としてはdocker run-pオプションとおんなじだと思う
コンテナポートが30000なのは後で説明します

作成したYAMLファイルをもとにクラスタ作成しましょう

$ kind create cluster --config kind-example.yaml
Creating cluster "kind" ...
 ✓ Ensuring node image (kindest/node:v1.15.3) 🖼
 ✓ Preparing nodes 📦📦📦 
 ✓ Creating kubeadm config 📜 
 ✓ Starting control-plane 🕹️ 
 ✓ Installing CNI 🔌 
 ✓ Installing StorageClass 💾 
 ✓ Joining worker nodes 🚜 
Cluster creation complete. You can now use the cluster with:

export KUBECONFIG="$(kind get kubeconfig-path --name="kind")"
kubectl cluster-info
$ kubectl get nodes
NAME                 STATUS   ROLES    AGE     VERSION
kind-control-plane   Ready    master   2m30s   v1.15.3
kind-worker          Ready    <none>   113s    v1.15.3
kind-worker2         Ready    <none>   113s    v1.15.3

お手軽にマルチノードクラスタができましたね、素晴らしきかな
お次はnginxをデプロイしてみましょう
YAMLマニフェストを作成します

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deplpoy
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template: 
    metadata:
      labels:
        app: nginx 
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80 
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  type: NodePort
  ports:
    - port: 80
      nodePort: 30000 #NodePortのため30000~32767
  selector:
    app: nginx

テスト用なので、とりあえずレプリカ数は1で
ServiceはNodePortでやるので、デフォルトだと30000~32767のポートしか使えません
おとなしく30000にしときましょう 先ほどホストとマッピングしたポートに合わせてください
出来上がったらあとはk8sに丸投げして少し待ったらcurlでホストから確認してみましょう

$ kubectl apply -f nginx-conf.yaml
deployment.apps/nginx-deplpoy created
service/nginx-svc created
$ curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

nginxうごいてる! すごい! らくちん!
しばらくはこれ使ってk8s勉強したいとおもいます

Kubernetesのおべんきょう

いまさらながらKubernetesのお勉強始めました
手始めに、入門Kubernetesを読んでみたので今のとこの自分の理解を忘備録がてらまとめてみます
まあ細かいこと書くのは後に回してとりあえず概要だけですが

Kubernetes(k8s)とは

Dockerなどのコンテナランタイムを用いて、サービスのデプロイ、スケールや運用などを自動化してくれるやつ
もとはGoogleによって開発されており、現在コンテナオーケストレーションツールはほぼk8s一強状態
すごくつよい

主な機能

  1. ロールアウト
    アプリの新バージョンリリース時、一部Podだけアップデートさせることを全体が新バージョンになるまで繰り返す
    Podというのはk8sでの最小単位で、1つ以上のコンテナの集合体
    これならダウンタイムなしにデプロイ可能 おんなじ感じでロールバックもできるよ

  2. スケール
    アプリを提供しているPodの数を増減することで、水平スケーリングが可能
    Podへの割り当てリソースを増減する垂直スケールは未実装 いちおう提供されてる? github.com Pod単位でスケーリングを行うため、1サービス1サーバーというような提供の仕方よりも効率的にマシンのリソースを使用可能

  3. 自動回復
    各Podなどのヘルスチェックを行い、正常に動作していないものを再起動させたりすることが可能
    ヘルスチェックも様々な方法で行うことができ高い汎用性を持ってる
    この機能により高い可用性を誇ってるすごい

アーキテクチャ

まだまだ理解が追い付いてないので細かい部分をはしょった概要図でお茶を濁します

f:id:suzkor:20190815004705p:plain
Kubernetesクラスタ 概要図

  • Cluster
    k8sの最大単位
    複数のnodeからなっていて、これで1つのシステムとして動作する

  • Node
    クラスタを構成するマシンで、MasterとWorkerの2種類が存在

  • Master Node
    クラスタを管理するためのNode
    • etcd
      k8sのリソースの情報を保存しておくKey-Value Store
      これを使ってリソースの永続化を行っている
    • apiserver
      etcdに対しての読み書き操作を行うAPIを提供
      他のコンポーネントは直接ではなく、ここを通してetcdを参照する
      また、ユーザーからのコマンドであるkubeletも同様にこれを通しetcdを参照、変更する
      このユーザーのコマンドもシステムの動作も同じ方法で行うのはk8sの特徴の1つ
      これによって高い拡張性が確保できる
    • scheduler
      各NodeのリソースやPodの情報などを参照し、作成したPodをどのNodeにバインドするかを決定する
    • controller-manager
      そのほかのリソースを管理するためのコントローラのマネージャ
  • Worker Node
    • kubelet
      Node内のPodやそのコンテナ、コンテナイメージなんかの管理を担当
    • proxy
      クラスタ内での通信は仮想IPであるClusterIPを使って行っている
      サービスに対してのロードバランスをホストのiptablesを動的に変更することで行っている

まとめ

とりあえず現状の理解ではこういうものだと思ってます
たぶん間違ってるとことか言葉が足りないとことか多々あるとは思うけどそこは追々

自作PC三世

ブログ飽きてません。論文で忙しかっただけです。

巷で噂の第三世代Ryzen
流石に第四世代i7ではそろそろHaswellおじさん呼ばわりされそうなので買い換えました
実は3か月ほど前からちまちまパーツは買いそろえていたので、ケースとGPU以外は全とっかえ

構成

種類 型番
CPU AMD Ryzen 3700X
クーラー サイズ 風魔 弐
M/B ASRock X470 Master SLI
メモリ G.SKILL SNIPER X 3600MHz 8GB×2
電源 Corsair RM850X 2018
ストレージ1 シリコンパワー SSD PCIe3.0×4 512GB
ストレージ2 SanDisk SSD SATA 480GB×2 RAID0
グラボ GIGABYTE RTX2070
ケース FractalDesign Define R5

f:id:suzkor:20190805022321j:plain
ベンチ台にて試運転の図
汚いけど試運転中
試運転はクーラーはリテール、グラボはGTX970で回してました

CPU

言わずと知れた新生Ryzenのミドルレンジコスパキング 3700X
ロマンで3900Xと迷ったけどお財布が許してくれなかったためこっちに

クーラー

虎徹で有名なサイズのツインタワー型空冷クーラー
NoctuaのNH-D15とか同じくサイズの忍者5とかと迷ったけどやはりお財布と冷却性能で考えた結果これに

M/B

X570にしなかった理由としては値段と機能
PCIe 4.0対応の機器はグラボもSSDも当分買う気はないので安いほうを選択

メモリ

今回唯一失敗したと思ってるのはこれ
F4-3600C19D-16GSXWB DDR4-3600 8GB×2の16GB構成
高騰前に勝ったから1万くらいだったけども、こいつがまあ安定しない
素直に3600Mhzで動くとまでは期待してなかったが、3000Mhzでもブルスクがしょっちゅう起きる
しょうがないので低めに2800で運用中
今度やる気が起きた時に最新BIOSにあげたりプロファイルいじったりで対応予定
だめなら買い替えかなぁ… 3200MHzくらいは何とか出したいところ

電源

以前はクロシコの750W Silverだったけども100W上げてCorsairのGoldへ
特に壊れたりとかはしてなかったけども、買い替えたかったので買い換えた。後悔はしていない。
初めてモジュラー式の電源買ったけど、すっきりしてかなりいい

ストレージ

メインはPCIeのSSD、ゲーム用にSATA SSDのRAID0構成
ほかの大容量ファイルはファイルサーバで管理してるのでストレージはこれだけ
特にこだわりはないので以上

グラボ

RTX2070です
2070 Super? 知らない子ですね…
メインモニタが4Kなせいでゲームしようとすると性能不足で最高画質にならん
次買い換えるならグラボかなぁ

ケース

特に光らせたりはしてないので窓もない地味なやつ
けどフロントパネルの開閉とか高静穏性とかで実は結構気に入ってる
3.5インチシャドウベイも多いので、サーバー機組みなおす時にはこっちに入れようかなと画策中
こないだ誤って梅酒ぶっかけたのですこしべたべたしてるのが難点

ベンチ

とりあえずCPU性能だけ見たいので新しいほうのCinebench

f:id:suzkor:20190805020452p:plain
Cinebench実行結果
スコアは4717とやっぱりかなり高め
DDR4-2133のときは4611と少し下がる

やっぱり8スレッドのi7-4790と比べると圧倒的に早いし満足
ただ財布はかなり薄くなった。後悔はしていない。

IFTTTimer

Alexaでエアコンタイマーをセットしたいときとかあると思うのですよ。
そういうとき、IFTTTにタイマー機能があればできると思ったのですよ。
でも調べた限りではいまのとこそういうのはないみたいなんですよ。
だから少し作ってみたのですよ。

使い方

  1. IFTTTの"That"のほうでWebhooksのMake a web requestを選択
  2. URLはhttps://opqc356q12.execute-api.ap-northeast-1.amazonaws.com/beta/iftttimer
    MethodはPOST
    Content Typeはapplication/json
    Bodyは
{
    "url":"https://maker.ifttt.com/trigger/{EventName}/with/key/{Your_Key}",
    "time":{minutes}
}

としとくと、EventNameに入れたAppletをminutes分後に実行してくれる
minutes分後ってすごく頭悪そう

仕組み

POSTをAWS API Gatewayで受け取ってLambdaのIFTTTimer_setにポイ
IFTTTimer_setはそれをDynamoDBにPUT

import json
from datetime import datetime
import boto3

def lambda_handler(event, context):
    print(event)
    body=json.loads(event["body"])
    timer_time=int(datetime.now().timestamp())+int(body["time"])
    url=body["url"]
    db = boto3.resource('dynamodb')
    table = db.Table('IFTTTimer_TimeTable')
    response = table.put_item(
        Item={
            "time":timer_time,
            "resource":event['resource'],
            "url":url
        }
    )

1分ごとに定期実行されてるIFTTTimer_mainが毎度DBをチェック
時間を過ぎてるものがあったら指定リンクにPOSTしてDBからレコード削除

import boto3
import requests
import json
from datetime import datetime
from boto3.dynamodb.conditions import Key, Attr


def lambda_handler(event, context):
    db=boto3.resource('dynamodb')
    table=db.Table("IFTTTimer_TimeTable")
    response = table.query(KeyConditionExpression=Key("resource").eq("/iftttimer") & Key("time").lte(int(datetime.now().timestamp())))
    print(response["Items"])
    for x in response["Items"]:
        requests.post(x['url'], data = json.dumps({
                "value1":"test"
            }))
        table.delete_item(Key={
            'time': int(x['time']), 
            'resource': x['resource']
        })

詰まったとこ・現状気に入らないとこ

table.queryはパーティションキーとはeq()でしか比較できないらしい
かといってソートキーのみで検索もできない
データベース全然知らないからわからんけども、これが普通なのでしょうか
解決としてパーティションキーを適当な一意のものにしてソートキーに時刻を入れてlte()使ってます
でも力業過ぎてきたない&気持ち悪いから要改善

そもそもなぜIFTTTにはタイマー処理がないんだ

github.com