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