アルパカログ

カスタマーサポート(CS)とエンジニアリングを掛け算したいCRE(Customer Reliability Engineering)エンジニアが気になる技術や思ったことなど。

Googleクラウド初心者がGCP無料枠でLINE Botを動かすための要点まとめ

manji602さんがGCP無料枠を使っておもしろそうなことをやっていたので私も何か作ってみようと思い、夫婦円満を願って家族のLINEグループに妻の好きな猫をLINE Botで導入することにしました。

私はGoogleクラウドはGAEが出た頃に少し触ったくらいで、当初は確かJavaPythonしか使えず「AWSの方が自由度があって良いな」と思っていたのですが、今回初めてGCPを触ってみると、インターフェースがシンプルでわかりやすく使いやすいと感じました。

そこで、Googleクラウド初心者の私がGCP無料枠の範囲でLINE Botを動かすまでの要点をまとめておこうと思います。

下図は今回作ったシステムの構成です。

f:id:otoyo0122:20180111183004p:plain

GCP

GCPの設定についてはGCPで無料枠のサーバを立るときに、初見でハマりそうなところがわかりやすく説明してくれています。

今回はSinatraを使うためRubyをインストールしました。おおまかには次のような手順です。

  1. GCEでusリージョンにf1-microインスタンスを立てる
  2. SSHのポート変更 (ネットワークタグ)
  3. IPアドレスの固定
  4. Ruby & RubyGemsのインストール

DNS設定

所有しているドメインから固定したGCEのIPアドレスが引けるように設定します。

GCPDNSサービス (CLOUD DNS) を使うと、無料クレジットはあるものの本来有料であることと、AWS Route53で所有ドメインを管理していることがあり、今回はRoute53でAレコードを設定しました。

SSL証明書取得

Let's Encryptで証明書を発行します(無料)。

証明書の有効期間は90日と短めですが、証明書はCertbotと呼ばれるクライアントを使って簡単に取得・更新することができます。

さらにDebianだとCertbotインストール時に証明書更新のCRONジョブを自動で追加してくれるので便利です。

ただし、証明書の更新コマンド certbot renew を実行すると、いくつかのディレクトリでパーミッションエラーになってしまったので、事前にパーミッションを付与して実行できることを確認しておくと良いでしょう。

私はこのあたりでハマりました。。

Nginx設定

NginxにSSL証明書を設定します。 セキュリティのためにNginxでSSLの評価をA+にする手順を参考に、SSLv3の無効化など対応しておくと良いでしょう。

下記は今回の設定例です。Unicornを使うためupstreamディレクティブでソケットファイルを指定しています。

/etc/nginx/conf.d/ssl.conf

upstream linebot {
    server unix:/tmp/linebot.sock;
}

server {
    listen                     443;
    server_name                example.com;
    ssl                        on;
    ssl_certificate            /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key        /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_protocols              TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers  on;
    ssl_ciphers                ECDHE+RSAGCM:ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!aNULL!eNull:!EXPORT:!DES:!3DES:!MD5:!DSS;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    location /linebot/ {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_pass http://linebot;
        proxy_redirect http:// https://;
    }
}

Unicorn & Sinatra

【Ruby】Sinatraで、速攻でWebサイトを公開するための環境構築にわかりやすくまとめられていますので、特に詰まる箇所はないと思います。

LINE Messaging APIの使い方はLINE Bot SDKに言語ごとにまとめられています。そのままで動くようになっているので、ここも詰まる箇所はないと思います。

参考までに、今回作ったLINE Botのコードの抜粋を掲載しておきます。

config.ru

require './app.rb'
run Linebot

app.rb

class Linebot < Sinatra::Base
  def client
    @client ||= Line::Bot::Client.new do |config|
      config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
      config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
    end
  end

  post '/linebot/callback' do
    body = request.body.read

    signature = request.env['HTTP_X_LINE_SIGNATURE']
    unless client.validate_signature(body, signature)
      error 400 do 'Bad Request' end
    end

    events = client.parse_events_from(body)
    events.each do |event|
      case event
      when Line::Bot::Event::Message
        case event.type
        when Line::Bot::Event::MessageType::Text
          reply_text = build_reply_text event.message['text']
          if !reply_text.nil? && reply_text != ""
            client.reply_message(event['replyToken'], type: 'text', text: reply_text)
          end
        when Line::Bot::Event::MessageType::Image, Line::Bot::Event::MessageType::Video
          response = client.get_message_content(event.message['id'])
          tf = Tempfile.open("content")
          tf.write(response.body)
        end
      end
    end

    "OK"
  end
end

猫ちゃん(LINE Bot)導入後の様子

f:id:otoyo0122:20180111183042p:plain

実際にはTodoistというタスク管理アプリとも連携して、「ホイちゃん 今日の晩ごはん」みたいに話しかけるとTodoist REST APIから今日の晩ごはんを取ってきて教えてくれるといった機能も載せています。

そのためリポジトリを公開できないことについては悪しからずご了承ください🙏🙏

おわりに

今回LINE Botを作ってみて、将来的にはLINEを通じて自宅のエアコンや照明を操作できるようにしてみたくなりました。

ドメインの費用以外は無料でLINE Botが運用できるので、皆さんもぜひアイデアを膨らませて作ってみてくださいね。

宣伝

普段の業務ではCRE (Customer Reliability Engineering)という役割のエンジニアとして働いています。CREチームを設立しました!も良ければご覧ください😄

参考文献