Ruby で カウントダウン Twitter BOT 作って Scaleway の Docker で動かす- 前半(ただしWIP)

大事な日までのカウントダウンを毎日 tweet してくれる BOTRuby で作成して Scaleway サーバで動かそうと思います。こんな感じでつぶやきます。

モチベーション

どうしてそんなものを作る気になったのか?とか「大事な日」とは何の日なの?とかは、いろいろあって、ここでは公にできないのですが、とりあえず、その日までの過ごし方が重要なので「その日に向かって日々頑張ろう!!」的な気持ちを継続するために、本 BOT に毎日つぶやいてもらいます。

また Scaleway とはフランスの格安サーバ会社で、ベアメタルなサーバが 日本円で 400円/月くらいからレンタルできるのが特徴です。2年ほど前に kawasaki.rb の LT で教えてもらって気になっていたやつです。

今回はサーバ上の Docker コンテナにアプリを入れて動かすつもりです。

www.scaleway.com

Twitter Bot の作成

Ruby では twitter という Gem があって、これを利用すればあっさりと実現できます。以下、簡単に実装の流れを説明します。

1)Twitter API 利用するアプリケーション登録

Twitter に投稿するためには Twitter API を利用する必要がありますが、そのためには、アプリケーション登録をする必要があります。ということで、さっそく Twitter developers へログインしてアプリケーション情報を登録します。

Welcome — Twitter Developers

注意点として、今回はTwitter 投稿するので、Access Level を “Read and write” にしておく必要があります。

アプリの情報が登録できたら、アプリが利用する Twitter API の認証と認可に必要な Consumer の情報と Access Token の情報を取得できます。
具体的には、下記の4つの情報をコピーします。

  1. Consumer Key (API Key)
  2. Consumer Secret (API Secret)
  3. Access Token
  4. Access Token Secret

2)Twitter Bot のコーディング

twitter Gem を使用した Twitter 投稿処理は、次のコードが基本となります。

require 'twitter'

client = Twitter::REST::Client.new(
    consumer_key:        'YOUR-CONSUMER-KEY',
    consumer_secret:     'YOUR-CONSUMER-SECRET',
    access_token:        'YOUR-ACCESS-TOKEN',
    access_token_secret: 'YOUR-ACCESS_TOKEN_SECRET'
)
client.update 'Some Tweet Message ...'

consumer_key、consumer_secret、access_token、access_token_secret の各値は、Twitter developers で登録したアプリケーションの情報をセットしてください。

私の場合は、大事な日までのカウントダウンを呟いてもらわなくてはなりませんので、その辺りも含めて(現在)以下のコードになってます。

require 'twitter'
require 'date'
require 'yaml'

# SayTwitter
class Tweeter
  def initialize(config)
    @config = config
  end

  def say(message)
    client = Twitter::REST::Client.new(
      consumer_key:     @config['tweet']['consumer_key'],
      consumer_secret:  @config['tweet']['consumer_secret'],
      access_token:     @config['tweet']['access_token'],
      access_token_secret: @config['tweet']['access_token_secret']
    )
    client.update message
  end
end

# Countdown Class
class CountDown
  def initialize(config)
    @config = config
  end

  def post
    the_day = Date.new(@config['theday']['year'],
                       @config['theday']['month'],
                       @config['theday']['day'])
    boring_days = (the_day - Date.today).to_i

    # Say to Twitter
    message = "Hi! just #{boring_days} days left until the Special Day."
    yield message
  end
end

# Load CONFIG FILE
CONFIG_FILE = 'countdown_bot.yml'.freeze
config = YAML.load_file(CONFIG_FILE)

countdown = CountDown.new(config)
tweet = Tweeter.new(config)

# Tweet Count Down Message
countdown.post do |message|
  tweet.say message
end

consumer_key、consumer_secret、access_token、access_token_secret などの情報は、外部 YAML ファイルで定義するようにしています。コード全体は、github のページ を参照してください。

Scaleway サーバの作成

アプリは作成できたので、これを動作させるサーバを Scaleway 上に準備します。前提として、今回も 400円/月 の範囲で活用したいと思います。

1)C1 サーバ + docker イメージで試してみる

まずは、Scaleway の C1 という ARM CORE のベアメタルサーバで一番チープな構成(400円/月)で試してみます。

f:id:ngzm:20170426183844p:plain

サーバで稼働するOSイメージは、ubuntu などメジャーなデストリビューションから選択できます。

f:id:ngzm:20170426183909p:plain

また、あらかじめミドルウェアまで入ったOSイメージも用意されています。こうなると PaaS みたいです。

f:id:ngzm:20170426183913p:plain

今回は、Docker コンテナでアプリを動かすので、OSのイメージは Dokcer を選択してオーケストレーションします。こうして、しばらくするとマシンが立ち上がってきました。起動できたので、次は Docker コンテナを作成しますが、とりあえず Docker -v でバージョンを確認すると Version 1.12 でした。現在の最新版が 1.17 系なので、ちょっと古いですね。

続いて、ruby:latest イメージを pull して、docker run してみます。するとナゾの go-lang エラーがばんばん出ました。

# docker run --rm -it ubuntu:trusty

panic: standard_init_linux.go:175: exec user process caused "exec format error" [recovered]
    panic: standard_init_linux.go:175: exec user process caused "exec format error"

goroutine 1 [running, locked to thread]:
panic(0x3339c8, 0x10747800)
    /usr/local/go/src/runtime/panic.go:481 +0x330
github.com/urfave/cli.HandleAction.func1(0x107c5958)
    /go/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/urfave/cli/app.go:478 +0x328
...
... 以下省略
...

よく見ると、Docker コンテナのフォーマットエラーとか何とか書いてあります。とにかくうまく動きません。

2)C1 サーバ + ubuntu イメージで試してみる

どうもダメなので、一旦サーバを破棄して、C1 サーバ + ubuntu xenial (16.04 LTS) イメージ でサーバを作って、そこに Docker を入れて試してみます。無事に Docker のインストールまで完了したので、 そのバージョンを確認すると Version 1.17 最新版です。

まずは、Docker の動作確認用コンテナ “Hello World” で動作確認してみます、すると、さっきと同様に go-lang のエラーが発生!それでも、あきらめずに、ruby:latest イメージで docker run してみますと、やっぱりエラーとなりうまく動きませんでした。

3)C1 サーバ の問題

どうしてもダメなので、C1 サーバのドキュメントをちゃんとみて見ると、その CPU は「ARM v7」であると書いてありました。

f:id:ngzm:20170426183855p:plain

「ARM v7」って?さらに調べたところ、どうやら 32bit CPU らしき情報を発見!なるほど、32 bit なら docker は動かないですね。この事実が分かるまで2〜3時間かかってしまいました。

せっかくのベアメタルサーバなのに、これでは目的が達成できなません。ちなみに、これより上位の構成(当然お金も高くなる)であれば、64bit のCPUを採用しているので、あとは金で解決するか・・いや止めよう

4)VC1s サーバ + docker イメージで試してみる

Scaleway はベアメタルなサーバ以外にも、一般的な仮装サーバの提供も行なっており、それであれば、約400円/月 かつ 64bit の環境が使えます。

f:id:ngzm:20170426183905p:plain

ということで、ベアメタルサーバは諦め、仮装サーバ VC1s での実現を目指します。OSイメージはとりあえず Docker で行きます。

と、無事にマシンが起動できました。そこで、先ほどと同様 “Hello World” コンテナで動作確認をしてみると無事に成功しました。今度は大丈夫そうです。 ということで、ruby:latest イメージを pull して docker run で Ruby コンテナを実行させると、きちんと irb が起動しました。

# docker run --rm -it ruby:latest
irb(main):001:0>
irb(main):002:0* puts "Hello!!"
Hello!!
=> nil

とりあえず、現在はここまでの状況です。明日以降で Ruby で作成した Twitter BOT を Scaleway のVC1s サーバ + Docker に乗せて動かす作業を行います。

ここまでのまとめ

  • twitter Gem を使うと簡単に RubyTwitter API 使えそう
  • Scaleway サーバで Docker を動かすなら C1 サーバは使えない
  • 大事な日まで心折れずにがんばろう

後半につづく

2017/4/30 - 後半の記事を書きましたのでお知らせいたします。

ngzm.hateblo.jp

macOS Sierra にしたら photoanalysisd というプロセスでホットになった

Sierra にしてしばらく遊んでたら、どうも常時CPU使用率が7割以上回っている様子で、MAC BOOK がホットになったので、どのプロセスが原因なのか見てみました。

どうも photoanalysisd というプロセスですね。

検索してみると、なるほど 「photoanalysisd 暴走」 というタイトルの記事がたくさんありました。どうやら、一時中断もできるが、しばらく放っておくとそのうちおさまるとの噂です。ならばと、そのまま数日間放置していたら、なんとなく静かになりました。

と安心したのも束の間、続いて mediaanalysisd という第二の刺客が現れ、こいつは4割くらい CPU を占有するようになりました。私はあまり動画とか保存していなかったのもあってか、mediaanalysisd の暴走は数時間で解消しました。

ということで今ここ。次は 何analysisd が暴走するのだろうか?

macOS Sierra に Karabiner-Elements 入れて「英数」キーを「Command」にして、単独で押した時は「英数」として認識させた話

2017/07/08 追記

本エントリは 2016年12月現在の情報です。それから半年+α 経って、ついに本家の Karabiner-Elements で同機能がサポートされました。その詳細を、次のエントリに記載しましたので、今後はこちらを参考にしてください。

ngzm.hateblo.jp

以下、当時の情報です。

はじめに

タイトル長い。。

MAC OS Sierra がリリースされてはや3ヶ月。"そろそろアップデートしないとなー"と思いつつも、これまで Karabiner にお世話になっていたこともありなかなかバージョンアップに踏み切れずいたのですが、、先日、改めて調べてみると Karabiner-Elements でいけそうな気配を感じたので、思い切って Sierra にアップデートしました!!という、その時の話です。

すなわち、MAC OS Sierra にアップデートした後、Karabiner-Elements でタイトルのようなことをゴニョゴニョしたときのメモです。

これまで Karabiner にお世話になっていたこと

自宅のMACでは日本語キーボードを使っています。なので、別に Karabiner 使わなくても何とかなるのですが、日本語キーボードは英語キーボードに比べ、左「Command」キーの位置が左に寄り過ぎていて気に食わない、そこで、できれば「英数」キーを左「Command」キー的に利用したい。さらに単独で「英数」キーや左「Command」キーを押した時は「英数」として認識してほしいというのが私の願望でして、その願望をうまいこと叶えてくれていたのが Karabiner でございました。

また、会社では英語キーボードを使用しており、単独で左「Command」キーを押した時は「英数」として、右「Command」の時は「かな」として認識してもらわないと、なおのこと日本語切り替えに困惑する訳でありまして、やっぱし karabiner の導入は必須となってしまうのです。

今回導入した Karabiner-Elements について

「英数」キーを左「Command」キー的に利用したいというのは、本家の Karabiner-elements でも問題なく実現できるのですが、単独で「英数」キーや左「Command」キーを押した時は「英数」として認識させるということはできませんでした。

ここで諦める訳にはいかないので、さらに調査を進めてみると、wwwjfy さんが単独で何かのキーを押した場合だけ、特別な認識をさせるという、いわゆる「StandAlone Key」という機能を開発されていて、これをマージすればよさげなことが分かりました。さっそくマージだ!とビルド環境を整備していた矢先、なんと wwwjfy さんご自身でマージ版のインストールパッケージご提供されておりましたよ。至れり尽くせり、ありがたや。

github.com

ということで、「StandAlone Key」がマージされた Karabiner-Elements を Sierra にインストールしました。

Karabiner-Elements の設定内容

無事にインストールが完了したら、まず最初にキーボードの種類をきちんと設定します。現在 Karabiner-Elements の “Keybord Type” のデフォルトが、英語配列になってますので、日本語配列のキーボードを利用する場合は、"Keybord Type" を “JIS” に変更する必要があります。以下のように Karabiner-Elements の設定画面上で設定します。

f:id:ngzm:20161222003352p:plain

続いてキースワップを設定します。今回は「英数」キーを左「Command」として認識するように設定します。こちらも Karabiner-Elements の設定画面上から行います。

f:id:ngzm:20161222003357p:plain

そしていよいよ StandAlone Key の設定です。すなわち、単独で「英数」キーや左「Command」キーを押した時は「英数」として認識させます。これについては、Karabiner−Elements の設定画面で設定できないので、定義ファイルを直接編集して行います。定義ファイルは ~/.karabiner.d/configuration/karabiner.json *1です。これに以下の定義を追加します。

   "standalone_keys" : {
       "left_command" : "japanese_eisuu"
    }

一部だけだとよく分からないので、ここまでの設定が反映された karabiner.json 全体を以下に示します。

{
    "profiles": [
        {
            "devices": [
                {
                    "disable_built_in_keyboard_if_exists": false,
                    "identifiers": {
                        "is_keyboard": true,
                        "is_pointing_device": false,
                        "product_id": 599,
                        "vendor_id": 1452
                    },
                    "ignore": false,
                    "keyboard_type": 42
                },
                {
                    "disable_built_in_keyboard_if_exists": false,
                    "identifiers": {
                        "is_keyboard": true,
                        "is_pointing_device": false,
                        "product_id": 627,
                        "vendor_id": 1452
                    },
                    "ignore": false,
                    "keyboard_type": 42
                }
            ],
            "fn_function_keys": {
                "f1": "vk_consumer_brightness_down",
                "f10": "mute",
                "f11": "volume_down",
                "f12": "volume_up",
                "f2": "vk_consumer_brightness_up",
                "f3": "vk_mission_control",
                "f4": "vk_launchpad",
                "f5": "vk_consumer_illumination_down",
                "f6": "vk_consumer_illumination_up",
                "f7": "vk_consumer_previous",
                "f8": "vk_consumer_play",
                "f9": "vk_consumer_next"
            },
            "name": "Default profile",
            "selected": true,
            "simple_modifications": {
                "japanese_eisuu": "left_command"
            },
            "standalone_keys" : {
              "left_command" : "japanese_eisuu"
            }
        }
    ]
}

一番下にある定義が、StandAlone Key の設定ですね。。

さて、これでOKかテストして、うまくいきましたよ。今回は、「英数」と左「command」キーだけでやって見ましたが、「かな」と右「command」でも同様に設定可能です。

また、英語キーボードの場合でも、この StandAlone Key を使えば「Commnd」キー単独の時は「かな」や「英数」となるように設定できるので便利かと思います。

ご注意

このエントリは2016年12月20日時点のことなので、将来は状況が変わっているためご注意ください。

なお、wwwjfy さんの StandAlone Key 機能は、現在のところ、本家の Karabiner−Elements に Pull Request が上がっております。こちらがマージされれば、本家の正式版でも同様の設定が可能になるはずです。楽しみですね。

*1: 2017年4月現在では、~/.config/karabiner/karabiner.json に変更されています

Homebrew で nodebrew をインストールしたら少々はまった

MAC OS 10.11 の MAC BOOK PRO にて。

タイトルどおりはまったのでメモ。はまった内容ですが、普通に Homebrew から nodebrew をインストールして、

$ brew install nodebrew

PATH を追加しろとか言ってくるので、その通りに PATH を設定して、さぁ stable版 node を入れようとしたら、次のエラーに遭遇したのでした。

$ nodebrew install stable

Fetching: https://nodejs.org/dist/v6.6.0/node-v6.6.0.tar.gz
Warning: Failed to create the file
Warning: /Users/naoki/.nodebrew/src/v6.6.0/node-v6.6.0.tar.gz: No such file or
Warning: directory

curl: (23) Failed writing body (0 != 940)
download failed: https://nodejs.org/dist/v6.6.0/node-v6.6.0.tar.gz

ちょっと調べてみると、どうやら同じエラーに遭遇した先輩がたくさんいる模様。原因は、 $HOME/.nodebrew が作成されていなかったから? ということで、それ作成してリトライ。

$ mkdir ~/.nodebrew
$ nodebrew install stable

Fetching: https://nodejs.org/dist/v6.6.0/node-v6.6.0.tar.gz
Warning: Failed to create the file
Warning: /Users/naoki/.nodebrew/src/v6.6.0/node-v6.6.0.tar.gz: No such file or
Warning: directory

curl: (23) Failed writing body (0 != 940)
download failed: https://nodejs.org/dist/v6.6.0/node-v6.6.0.tar.gz

あらっ?またか。
どうやら $HOME/.nodebrew/src も必要なようです。でも、なんだかこのまま行くと、「あれも」「これも」という感じで、次々に同様の作業を繰り返す気がします。なのでさらに調査してみます。。

すると、今回の正解らしき情報が得られました。それは、わざわざ手でこれらのディレクトリを作るのではなく、コマンド nodebrew setup をたたくということです。

$ nodebrew setup

Fetching nodebrew...
Installed nodebrew in $HOME/.nodebrew

========================================
Export a path to nodebrew:

export PATH=$HOME/.nodebrew/current/bin:$PATH
========================================

これで nodebrew の実行に必要な環境がセットアップできたはずです。

$ ls ~/.nodebrew

completions/ current@     default/     iojs/        node/        nodebrew*    src/

よさそうですね。再度、node 安定版をインストールしてみます。

$ nodebrew install stable

Fetching: https://nodejs.org/dist/v6.6.0/node-v6.6.0.tar.gz
######################################################################## 100.0%
creating  ./icu_config.gypi

... (省略)
...

$ nodebrew use v6.6.0
use v6.6.0

$ nodebrew ls
v6.6.0

current: v6.6.0

うまくいきました。done。

【補足】nodebrew は、環境変数 NODEBREW_ROOT で node のインストール先を変更できますが、このときも nodebrew setup を実行すると一発で必要な環境が作成されるので非常に便利。ぜひ覚えておきましょう。

川崎RUBY会議の運営(会場係)をやりました

2016年8月20日に「川崎RUBY会議01」が開催されました。私は会場係として運営に参加いたしました。

regional.rubykaigi.org

こっちは twitter まとめ

togetter.com

運営に参加したきっかけ

数年前から毎月第4水曜日に「kawasaki.rb」という地域RUBY勉強会を行っていまして、今回は、kawasaki.rb の主催者である @chezou さんが「川崎RUBY会議01やるよ!!!」とお声を掛けてくださったのが始まりです。わたしは、kawasaki.rb の会場として会社の会議室を提供することが多かったので、そのご縁もあって、このRUBY会議の会場係として運営に参加させてもらったのでした。

参加者の皆さんのレポートご紹介

さっさとブログ書けばいいのに、忙しいとか何とかでグズグズしていたら既に1週間以上経過してしまいました。そうこうしている間に、参加者のすごい皆さんがいろいろな素敵なレポートを書いてくださいましたので、ここでは、私などがぐたぐた書くよりも、それらレポートをまとめ的にご紹介したいと思います。

最初にご紹介するのは、基調講演をしていただいた @mametter さんのブログです。@mametter さんの講演は「Ruby で高速なプログラムを書く」ということで、「Optcarrot」というファミコンソフト(NES)のRUBYエミュレータを開発した経験から、いかにしてプログラムを高速化すべきか?という非常に参考になるお話しでした。高速化する上での心構えとか必見ですね。コミッタおそるべしです。

d.hatena.ne.jp

お次は、@ryonext さんのレポートです。そういえば、この前の kawasaki.rb でもためになる話を聞かせてもらいました。あざました。

ryonext.hatenablog.com

続いては @koic さんのブログです。懇親会で初めて知り合ったのですがとても楽しい人でした。紹興酒カメと果敢に戦っていた姿が印象的で、また機会があればぜひ飲みたいですね。

koic.hatenablog.com

こちらは、「RubyRoombaをハックする」というタイトルで発表された @kon_yu さんのレポートです。ルンバと猫の組み合わせが最強なので、ぜひ動画見てほしいです。

konyu.hatenablog.com

そしてこちらは「Railsエンジニアが サーバーレスアーキテクチャに 手を出したよ」を発表した @pachirel さん。個人的に興味ありありだったのでありがたいお話でした。

pachirel.hatenablog.com

次は、一緒に運営した @Peranikov さんのレポートです。ペラちゃんは 「Rubyistを誘うScalaの世界 2.0」という ScalaRUBYではなく?)の話を発表した人でもあります。相変わらず面白い人だ。

norizabuton.hateblo.jp

そしてここでのトリはやはり主催者である @chezou さんのブログです。会場の件とかご心配おかけしました。本当にお疲れさまでした。
サイトリンクになぜか Elixir本の画像・・

chezou.hatenablog.com

しばらくすると、本家のるびまレポートが出るので楽しみに待っていましょう。

会場の様子とかの写真

せっかく会場係やったので設営した会場とか懇親会の写真でも貼って終わりにします。

会場設営の様子 f:id:ngzm:20160828165428j:plain

エントランスのポスター(かわいい) f:id:ngzm:20160828163522j:plain

会場の張り紙 f:id:ngzm:20160828165423j:plain

始まる前にインドカレー食って会場に戻るところ(スタッフTシャツもかわいい) f:id:ngzm:20160828163520j:plain

Java 勉強会もやってた f:id:ngzm:20160828163521j:plain

セッション中 f:id:ngzm:20160828163523j:plain

懇親会にでた紹興酒カメの封印を解くお店の大将 f:id:ngzm:20160828163524j:plain

紹興酒カメを飲み干した記念 f:id:ngzm:20160828163519j:plain

とにかく最高に楽しい1日でした。運営やらせてもらって本当によかったです!