読者です 読者をやめる 読者になる 読者になる

きょこみのーと

元六本木でGo書いてました。今はVRでGo書いてます。

Arukasを使って無料でGo製のslackbotを運用する

docker golang Go Arukas wercker

はじめに

SlackbotをHerokuで一日中動かすと課金が発生するので色々ハックが必要となったりするので、なんとかしたくArukasに出会いました。

今回は、自分が作ったgo製のslackbotを元につくったbotgithubにpushしてWercker経由でdockerImageを作ってArukasへのDeployを行う方法を紹介します。

github.com

今回のコードとか設定をexampleとして公開してますので、よろしければ参考にしていただければと。

Arukasとは?

いまのところ無料でDockerをホスティングできるサービスです。

arukas.io

一応CLIツールも公開されていて、結構便利です。

github.com

※注意点としては、CMDで起動したプロセス監視とかは無いので自分でとかgo-server-starterとかを入れてプロセス死んだときに再起動する仕組みを入れる必要があるところです。

流れ

  • 以前作ったgo製のslackbotのdockerImageをWerckerで作成する kyokomi.hatenablog.com kyokomi.hatenablog.com
  • Arukasのコンソールでアプリケーションを作成し、dockerImageを指定する
  • WerckerのworkflowでArukasのrestartを設定する

slackbotのコード自体はDockerとか意識しない形になっているので、wercker.ymlとかを見ていただければと。

example-go-slackbot/wercker.yml at master · kyokomi/example-go-slackbot · GitHub

Werckerの設定

f:id:kyokomi:20170101221031p:plain

README.md に書いてある通り6つの環境変数の登録が必要です。

ポイントはdocker-pushのworkflowで github.com/lestrrat/go-server-starter/cmd/start_serverをinstallしてます。 まあ別にバイナリをdonwloadでもいいんですが面倒だったので...

docker-push:
  box: golang
  steps:
    - glide-install
    - setup-go-workspace
    - script:
        name: install deamontools
        code: |
          go get github.com/lestrrat/go-server-starter/cmd/start_server
    - script:
        name: install application
        code: |
          go install
    - internal/docker-push:
        username:   $DOCKER_HUB_USERNAME
        password:   $DOCKER_HUB_PASSWORD
        tag:        latest
        repository: $DOCKER_HUB_REPOSITORY
        registry:   https://registry.hub.docker.com

arukas-deployのworkflowでは、 arukasのバイナリをdownloadして適当にPATHを通してstop -> startしてます。 sleep 10 を挟んでいるのは、stopする前にstartするとエラーになるので仕方なくです。

arukas-deploy:
  box: golang
  steps:
    - script:
        name: install tools
        code: |
          sudo apt-get update
          sudo apt-get -f install
          sudo apt-get install -y wget unzip curl tree
    - script:
        name: arukas install
        code: |
          mkdir -p $HOME/lib
          export PATH=$PATH:$HOME/lib
          cd $HOME/lib
          wget https://github.com/arukasio/cli/releases/download/v0.1.2/arukas_v0.1.2_linux_amd64.zip
          unzip arukas_v0.1.2_linux_amd64.zip
          rm arukas_v0.1.2_linux_amd64.zip
    - script:
        name: arukas restart
        code: |
          arukas stop ${ARUKAS_CONTAINER_ID}
          sleep 10
          arukas start ${ARUKAS_CONTAINER_ID}

Arukasの設定

f:id:kyokomi:20170102005223p:plain

おまけ

ちゃんとプロセス死んで再起動するかの動作確認ですが、昔ネタでいれたcommandを実行させるプラグインが役に立ちました。(危険)

f:id:kyokomi:20170102010051p:plain

何度でも蘇る。

2016年振り返り

2016年 日記

主にTwitterの全ツイート履歴を見て振り返る。

振り返り

半分くらいは業務コードと思われる.

f:id:kyokomi:20170101122503p:plain

開発合宿とかPC持っていく旅行

結構同じメンバー何回も開発合宿行ってて、会社が別になっても気軽に集まれる関係なのがいいなと思いました。 来年も行きましょう!!!

各月のサマリー

2〜7月: ひたすらAndroidして退職

  • Droidkaigiに行った
  • 業務でAndroidエンジニアが居なくて困っていたので、Androidエンジニアにコンバートした
  • ひたすらAndroid書いてた。とにかく仕様バグとかクラッシュを削りながらな日々
  • twitter.com
  • 去っていた人のコードを当時いた人の気持ちになってリーディングするサイコメトリーをマスターする
  • twitter.com
  • twitter.com
  • Androidそこそこできるようになったので、Androidエンジニアの採用を頑張っていた
  • 制約と誓約を意識して、Goを書かないで全ステータスをAndroidに振っていた
  • 7月一杯でGunosyを退職

8月〜9月

10月〜12月

その他

麻雀

2016年は10回くらい打った気がする。役満は1回。 メンツは結構バラバラだったけど、トータル勝ち越した気がする。

twitter.com

関係者各位また定期的にやりましょう!!!

個人開発

  • GAE/Goでちょっとしたキュレーションシステム
  • Androidアプリ2つ(キュレーションのクライアントと、Twitterの画像をひたすら表示するやつ)
  • 放置ゲーのAPIサーバーをGAE/Go -> ECSに移行
  • 放置ゲーのクライアントをUnityでプロトタイプ作成

相変わらずエターなってるけど、作ったものを自分では使っているのでそこそこ満足している。

まとめ

  • 2016年は発表とかブログとかアウトプット少なめで本を読んだり技術検証したりでインプット多めだった気がする
  • 温泉行って開発合宿すると疲労を回復しながら、開発が捗るので2017年もやっていきたい
  • 2017年はリリースもあるので、Tipsとか開発フローとかについてとか発表したり、ブログでの情報発信とかもしっかりやっていくぞ

werckerでprivate repositoryを含むglide installする方法

Go Wercker glide github

手順

  1. glide.ymlでsshのURLを指定する
  2. wercker上でApplication Environmentか Organization settings Environmentで + Generate SSH Keys してssh keyを環境変数に登録する
  3. 「2.」で登録したssh keyをgithub上の Settingsの SSH keys で登録する
  4. wercker.ymlに add-ssh-keyadd-to-known_hosts を記載する

glide.ymlとwercker.yml

gist.github.com

fingerprintはこちらを参考に入力しましょう。

What are GitHub's SSH key fingerprints? - User Documentation

wercker Generate SSH Keys

Application Environment

f:id:kyokomi:20161218150924p:plain

Organization settings Environment

こっちで指定すると全部のアプリケーションで使いまわせます。

f:id:kyokomi:20161218150826p:plain

Webラジオのm3u8をdownloadしてffmpegでmp3に変換するツールをGoで書いた

Go tool ffmpeg アニメ ラジオ

2016/12/15 23:06 追記:

ちなみにffmpegでm3u8 -> mp3変換はできますが、実行時間が20分以上かかって待ってられなかったのでBulkDownloadが含まれてます。

あとm3u8のURLが推測難しく、いちいちブラウザ開いてplaylistをダウンロードして中身のmedia playlistのm3u8のURLを確認して〜がだるかったのでScrapingしてます。

Webラジオのm3u8をScrapingしてtsファイルをBulkDownloadしてffmpegでmp3に変換するツールをGoで書いた が正確なタイトルですかね。


今期は、ガーリッシュナンバーが結構お気に入りです。

www.tbs.co.jp

(ちーさまのダメ可愛さがなかなか癖になります)

f:id:kyokomi:20161215205231p:plain

(そして目玉焼きの服というセンス...圧倒的か...)

なんでこんな話から始まったかと言うと、面白いなーと思った作品のアニメのWebラジオとか結構聴くんですが、なんか専用のアプリがあって使いにくかったり、Webブラウザでしか再生できなかったりと中々不便なので結局ダウンロードすることにしてツールを作りました。

(たとえば、途中まで再生してブラウザ閉じたときに、続きから聴けない...とか)

sp.animatetimes.com


ここから本編

今回作ったツール

github.com

github.com

github.com

1つのツールにしても良かったんですが、用途考えると別々のほうが使いやすいかなと思って3つに分けました。

はじめに

今回必要なダウンロードの流れは以下になります。

流れ

  1. 指定したURLのWebページのCrawl
  2. CrawlしたHTMLから対象のURLをScrapingして抽出
  3. m3u8のPlaylistのURLを元にtsファイルをBulkDownload
  4. tsファイルをffmpegでつなぎ合わせてaacを作成
  5. aacffmpegを使ってmp3に変換

3〜5のあたり github.com/yyoshiki41/radigo こちらを参考にさせていただきました。

前提条件・事前準備

  • Macでしか試してません
  • 対象のWebページのURLを用意してださい
  • 対象のxpathを適当に調べておく(ChromeDeveloperToolとかで)
  • ffmpegをインストールしておく
  • Go環境用意しておく

インストールの仕方・それぞれの役割説明

インストール

go get github.com/kyokomi/xcrawl
go get github.com/kyokomi/m3u8go
go get github.com/kyokomi/ffmpego

役割

使い方

xcrawlのオプションで使えるconfig

スマートフォンサイトをCrawlしたいとかのときに使います。

headers:
  User-Agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Mobile Safari/537.36

実行例

xargsでつなぐと一発で実行できて便利です。

$ xcrawl -c <configファイルのパス> \
         -i '<ラジオ再生ボタンがあるWebページのURL>' \
         -x '<master playlistのURLが抽出できるxpath>' \
         | xargs m3u8go -i \
         | xargs ffmpego -o <出力するファイル名> -i

デモ

冒頭にもリンク貼りましたが最近ハマっている、ガーリッシュナンバーの「クズらじ」で試してみます。

www.animatetimes.com

$ xcrawl -c config.yaml \
            -i 'http://sp.animatetimes.com/radio/details.php?id=gn&a=10&m=a' \ 
            -x '//*[@id="main-contents"]/ul[1]/li[3]/div/div[1]/div/a[1]/@href' \
            | xargs m3u8go -i \
            | xargs ffmpego -o kuzu3.mp3 -i

f:id:kyokomi:20161215203950p:plain

これでひとまず満足... ^q^

かなり雑に実装したので、もし自分以外に使う方がいましたら、バグとかあればお気軽に〜(対応するかはわからないが...)

Amazon Lambdaにデフォルトでインストールされているライブラリを最新にして使う方法の1つ

Go Amazo ImageMagick ghostscript Lambda

業務でAmazonLambda上でPDFを画像に分割処理を実装したのですが、その時ghostscriptのVersionが古くて、 特定のPDF変換でエラーになるという現象でハマったのでその時調べたことと、 対応策を紹介したいと思います。

前提

  • Apex (Go)で動かしてます
  • ImageMagickがghostscriptを呼び出している
  • ghostscriptが古くてエラー

Apexについては前に書いた記事をご覧ください。

kyokomi.hatenablog.com

Lambdaのamiについて

Amazon Linux AMI 2014.09 Packages

ghostscript-8.70
ghostscript-fonts-5.50

フォーラムでの質問

https://forums.aws.amazon.com/message.jspa?messageID=611159

AWS Lambda doesn't provide a way for functions to update the Amazon Linux AMI. 
As has been suggested, you can include alternative versions of libraries, executables, 
and language runtimes in your function's ZIP file if the default ones available don't address your needs.

We'll also be looking at ways to make that process easier in the future through simplified deployment options. 
Until then, apologies for the inconvenience of having to copy this in with your code.
  • AWS LambdaではAMIをupdateする術を提供してない
  • もしversionを更新したいならzipに含んで頑張ってくれ

と解釈。/(^o^)\

解決策

functionの構成

pdf2images
├── bin
│   └── gs            // 上記のdownloadしたバイナリ
└── main.go

コード抜粋

func main() {
    apex.HandleFunc(func(event json.RawMessage, ctx *apex.Context) (interface{}, error) {
        os.Setenv("PATH", os.Getenv("LAMBDA_TASK_ROOT")+"/bin"+":"+os.Getenv("PATH"))
 
        // TODO: 〜 色々省略 〜

        outputLog, err := exec.Command("convert", "/tmp/input/hoge.pdf", "/tmp/output/hoge.png").CombinedOutput()
        if err != nil {
            return nil, err
        }
        log.Println(string(outputLog))

        return nil, nil
    })
}

Lambda x Apexで、Goで書いたラムダ関数を楽に動かす

Go Lambda Amazon Apex

業務でAmazonLambdaを使う機会があり、Apex(Go)を試していい感じだったのでその紹介とハマりポイントを幾つか紹介しようかと。

github.com

導入

すごく簡単で、 https://github.com/apex/apex#installation に書いてある通りインストールして apex init で対話式でプロジェクト名とか入力するだけです。

ExampleのGo実装をそのままコピって apex deploy すれば速攻でdeployも出来ます。

exampleはこちら -> https://github.com/apex/apex/tree/master/_examples/go

package main

import (
    "encoding/json"

    "github.com/apex/go-apex"
)

type message struct {
    Hello string `json:"hello"`
}

func main() {
    apex.HandleFunc(func(event json.RawMessage, ctx *apex.Context) (interface{}, error) {
        var m message

        if err := json.Unmarshal(event, &m); err != nil {
            return nil, err
        }

        return m, nil
    })
}

かなりシンプルに書けて楽です。

概要・Tips

  • functions下がラムダ関数と1対1になります
    • 下記の例だと pdf2imagesresizeImage になります
  • GOPATH下にプロジェクトを置けば共通の実装とかをパッケージ化して使いまわせるので便利
    • 下記の例だと resize パッケージと aws パッケージ
  • glide使ってライブラリ固定もできます
  • ちゃんと調べてないんですが、 os.stdoutを呼び出すとNode.js側でエラーになるので fmt.Print ではなく log.Print を使いましょう
  • 外部ライブラリも exec.Commnad で呼び出せます
  • 環境変数の変更は os.Setenv() を使うと exex.Commandで呼び出すときにも反映されます
  • /tmp 下が書き込み可能になっているので、一時ファイル系の処理で積極的に使っていきましょう

プロジェクト構成例

example_lambda
├── functions
│   ├── pdf2images // PDFを画像に変換するラムダ関数
│   │   ├── main.go
│   └── resizeImage // 画像を元にサムネイルを作成するラムダ関数
│       └── main.go
├── glide.lock
├── glide.yaml
├── project.json
├── resize        // resizeする共通処理
│   └── resize.go
├── aws          // aws-sdk-go周りの共通処理
│   ├── aws.go
│   └── message.go
└── vendor   // vendoring

ISUCON6本戦初出場で敗退しました @ご注文はpoyoですか?

isucon 感想

ISUCON参加は今年で3回目。毎年運営の方々はお疲れ様です。 今年は初の本戦出場が出来て本当に楽しかったです。

仕事とかでバタバタしてて、ブログ書くのが遅くなってしまった...

チームメンバーと役割

過去2年はk02というチームで出ていたのですが、メンバーの一人がセブ島にいるという体たらくで雑に集まったメンバーで参加しました。

実際、雑に集まった突貫チームだけど、前職で一緒に仕事してたこともあり、それぞれの得意分野とか性格とか把握してたので事前準備とか打ち合わせ無しでも特に問題がありませんでした。

f:id:kyokomi:20161103140723p:plain

※窓側の席でした

当日の準備

  • 無事に起床
  • 本戦参加者だけが貰えるネームカードをGETしてテンションが上がる
  • GitHubのRepositoryを作ってコラボレーターに招待
  • sshのPrivateKeyを共有したり
  • インスタンスで使うgithubアカウントの用意など

ちゃんと会社の宣伝してきました ^^

※右の写真のひきこもりTシャツ

地味に弊社を知っている人が居て驚きましたね。

今回のお題

  • フロントエンドサーバーとしてReact.jsを使ったnode.js
  • そこからリバースプロキシされる形でアプリが存在し、それには各言語の実装(Goを選択)
  • DBは、MySQL
  • すべて docker になっていて、 docker-compose で動いている
  • 5台あるけど1台で全部のdockerが動いてる状況

反省点

  • Dockerを捨てるかどうかの判断が遅かった(午前中くらい)
    • nginxをdocker-composeに混ぜるのでハマった
    • そもそもなんで docker-compose...頑張ってるんだ... ってなるまでに時間かかった
  • 5台インスタンスを使い切る前に時間切れ(時間配分)
    • ある程度チューニングしたら横に並べるつもりだったが時間配分ミス
  • Reactのフロントエンドサーバーは飾りだと思って、軽視してた
    • 一応、チラっと見たけど先にセオリー通りまずはサーバーを〜って優先度を雑に決めてしまった
  • 絵チャット掲示板的なやつという前情報でなんとなくわかったつもりになってしまった
    • あまりサービスそのものを触る時間を取らなかった
    • 触ってると、ここはAPI通信必要そうだな〜とかここは最適化できそうみたいなのが湧いてきて、本戦終了して改めて触ってると「なるほど、こうなってたのか〜」という感じだった

所感

本戦は初出場なんですが、予選と違って裁量がかなり多くてやることも多いけど一番効果的なものをやろうという感じで、今までの経験と頭をフルにつかって取り組む感じがめっちゃ楽しかったです。

結果は11位という形でやり残しもたくさんありますが、来年も開催されるだろうと思い腕を磨いて行きたいと思います。 来年も本戦出るぞ。来年こそ優勝だ !!!