terraformでS3バケットのACLに権限を付与する

CloudFrontのアクセスログをS3に保存させる事はごくごく普通にあると思いますが、terraformで環境を構築しているとS3作成時に特殊なACLは設定できず、CloudFront作成時にログ出力指定をしていると権限不足で落ちてしまいます。

参考: アクセスログ – Amazon CloudFront

terraformだけで解決できれば一番良いのですが、2017年6月現在ではissueが出ているものの反映されるのはまだ先になりそうな感じです。

GUIからぽちぽちしてると勝手にACLを作ってくれるので、手で作った後にterraformに記載するとかいう意味のない作業をしていたのですが、そんな作業やりたくなかったので無理やり気味ではありますがterraform applyを実行するだけでS3にACLを付与し、CloudFrontの構築まで一気通貫で行えるようにちょっとした工夫を加えてみました。

準備するもの

linux/mac前提です。windowsの場合はbash on windowsであれば動作可能です。

必須

  • terraform
  • AWS CLI

推奨

  • direnv

準備するスクリプト

bin/AssignAwsdatafeedsAcl
#!/bin/sh

# 自身のディレクトリパスを取得
CURRENT_DIR=$(cd $(dirname $0);pwd)/

# 引数のチェックを行う
if [ $# -ne 1 ]; then
    exit 1
fi

# バケット名を引数から取得
BUCKET_NAME=$1

TEMP_FILE=$(mktemp)

# S3待ち(waitが無い場合にエラーが発生)
sleep 2

# 現在のバケットACL情報を取得する
aws s3api get-bucket-acl --bucket ${BUCKET_NAME} > ${TEMP_FILE}
if [ $? -ne 0 ]; then
    # テンポラリファイルを削除する
    rm -f ${TEMP_FILE}
    exit 1
fi

# ACLにawsdatafeeds権限が含まれていない場合は追加する
grep awsdatafeeds ${TEMP_FILE}
if [ $? -eq 1 ]; then
    # 追記する文字列を取得
    INPUT_LINES=$(perl -p -e 's/n/\n/' ${CURRENT_DIR}acl.txt)
    if [ $? -ne 0 ]; then
        # テンポラリファイルを削除する
        rm -f ${TEMP_FILE}
        exit 1
    fi

    # 権限情報を追記
    sed -i -e "s/("Grants": *[)/1n${INPUT_LINES}/" ${TEMP_FILE}
    if [ $? -ne 0 ]; then
        # テンポラリファイルを削除する
        rm -f ${TEMP_FILE}
        exit 1
    fi

    # 権限情報をS3バケットに反映
    aws s3api put-bucket-acl --bucket ${BUCKET_NAME} --access-control-policy "$(cat ${TEMP_FILE})"
    if [ $? -ne 0 ]; then
        # テンポラリファイルを削除する
        rm -f ${TEMP_FILE}
        exit 1
    fi
fi

# テンポラリファイルを削除する
rm -f ${TEMP_FILE}

exit 0
bin/acl.txt
        {
            "Permission": "FULL_CONTROL",
            "Grantee": {
                "DisplayName": "awsdatafeeds",
                "ID": "c4c1ede66af53448b93c283ce9448c4ba468c9432aa01d700d3878632f77d2d0",
                "Type": "CanonicalUser"
            }
        },

上記2ファイルをパスが通ったところに配置しておきます。
シェルスクリプトの方にはちゃんと実行権限を付与しましょう。

ちなみにdirenvを使って、terraform実行パスなどでPATHを追加するのが推奨です。

.envrc
export AWS_DEFAULT_PROFILE=[AWSプロファイル名]
export AWS_DEFAULT_REGION=[デフォルトとするリージョン]

export AWS_PROFILE=$AWS_DEFAULT_PROFILE
export AWS_REGION=$AWS_DEFAULT_REGION

PATH_add `pwd`/bin

terraformの記述

s3.tf
resource "aws_s3_bucket" "sample" {
    bucket = "sample-cfn-logs"
    acl    = "private"
    tags {
         Name = "sample-cfn-logs"
    }

    provisioner "local-exec" {
         command = "AssignAwsdatafeedsAcl ${aws_s3_bucket.test.bucket}"
    }
}

概要

terraformのprovisionerにlocal-execという、実行マシンでのコマンド実行機能があります。

これはリソースが作成されたのちに実行されるので、S3リソースが作成された後にシェルスクリプトを実行し、AWS CLIを利用してS3バケットにACLを付与しています。

上記スクリプトでは下記の様な処理を行っています。

  1. aws cli: S3バケットの設定済みACLを取得
  2. shell: 取得したACLにawsdatafeedsの権限が付与されているかチェックする
  3. shell: 権限がない場合、権限の内容を取得したACLに追記する
  4. aws cli: 改変したACL情報をS3バケットに反映する

S3バケットが構築されてからAPIで叩けるまでに微妙なタイムラグがあるらしく、sleepが入っていないとAPIを叩いた時にバケットが存在しないと怒られてしまいます。

ちゃんとするならば、APIのレスポンスを見て待つ処理を入れるのが良いのですが、terraformがMulti ACLに対応するまでの暫定的な対応なのでsleepで濁しています。

配置したスクリプトにパスが通っていないとlocal-execの指定時にわざわざパスを書いてあげる必要があるので、direnv使ってパス通しちゃいましょう。

相対パスがどこからになるのか知らない。

ちなみにacl.txtの内容を変えると好きな権限を入れれます。でもあまり使わないですし変更検知もされないので推奨はしません。

どうしてもという場合はaws_s3_bucketリソースの代わりにnull_resourceリソースを使って毎回スクリプトをキックするようにした上で、前回実行のACLと反映するACLに差分がある時に実行するなど工夫をしてみてください。

結論

はよterraform自体で対応して。

続きを読む

Mac から AWS CodeCommit を使ってみる

0.はじめに

AWS CodeCommit が東京リージョンでも使えるようになったみたいなので、使ってみました。

1.AWS CodeCommit のリポジトリの作成

  1. AWS CodeCommit のコンソールへアクセス。

  2. ダッシュボードの「リポジトリの作成」ボタンを押下。
    • FireShot Capture 053 - AWS CodeCommit Management Console_ - https___ap-northeast-1.console.aws.png

  3. 「リポジトリの作成」画面が表示されるので、以下の事項を入力し、「リポジトリの作成」ボタンを押下。
    • リポジトリ名
    • 説明
    • ※「リポジトリ名」「説明」共に、後で変更が可能。
    • FireShot Capture 054 - AWS CodeCommit Management Console_ - https___ap-northeast-1.console.aws.png

  4. リポジトリが作成され、「リポジトリに接続」画面が横から飛び出てきますので、次に接続の手順へ。

2.AWS CodeCommit のリポジトリへの接続

  1. 今回は、HTTPS で接続。

    • FireShot Capture 055 - AWS CodeCommit Management Console_ - https___ap-northeast-1.console.aws.png

  2. 前提条件を一つずつ確認します。Mac に Git がインストールされていたので、続いて IAM の設定を行います。
  3. IAM のコンソールへアクセス。
  4. 左側ペインの「ユーザー」をクリック。
    • FireShot Capture 057 - IAM Management Console - https___console.aws.amazon.com_iam_home#_home.png

  5. ユーザーの一覧から、接続するユーザーの「ユーザー名」のリンクをクリック。
    • FireShot Capture 058 - IAM Management Console - https___console.aws.amazon.com_iam_home#_users.png

  6. ユーザーの情報が表示されるので、「アクセス権限」タブを選択し、以下のポリシーをアタッチ。
    • IAMSelfManageServiceSpecificCredentials
    • IAMReadOnlyAccess
    • AWSCodeCommitFullAccess
    • FireShot Capture 061 - IAM Management Con_ - https___console.aws.amazon.com_iam_home#_users_y.uekama.png

  7. 「認証情報」タブの「AWS CodeCommit の HTTPS Git 認証情報」の「生成」ボタンを押下。
    • FireShot Capture 063 - IAM Management Con_ - https___console.aws.amazon.com_iam_home#_users_y.uekama.png

  8. 「生成された Git 認証情報」ダイアログが表示されるので、「証明書のダウンロード」ボタンを押下し、「リポジトリのクローンを作成するステップ」の 1 の記載の通りに、コンピュータ上の安全な場所に保存。
    • FireShot Capture 067 - IAM Management Con_ - https___console.aws.amazon.com_iam_home#_users_y.uekama.png

  9. 「リポジトリのクローンを作成するステップ」の 2 の記載にしたがって、以下のコマンドを実行。
    • git clone https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/Test

      • ※ユーザー名とパスワードを求められたら、保存した Git 認証情報を対応するフィールドに入力。

99.ハマりポイント

  • これは、AWS CodeCommit とは関係なくて、Git のことをよく知らない私のせいなんですが…、iOS アプリの Swift のコードを git add したんですが、全然追加されなくて悩んでいたら、追加したディレクトリの中に .git ディレクトリがあったせいでした…。登録する時は、余計なディレクトリやファイルは削除しておかないといけないですよね…。

XX.まとめ

と言う訳で、簡単に使うことができました。

AWS CodeCommit は、料金もほぼ無料みたいなので、AWS を利用している方はガシガシ使った方がメリットあるんじゃ無いかと思います。

続きを読む

CloudFrontでモバイル端末を判別する

サーバー側で User-Agent を見て端末を判別するとキャッシュ効率が落ちるので、代わりに下記の4つのHTTPヘッダをWhitelistに入れると、判別済みの情報が送られてきます。

  • CloudFront-Is-Desktop-Viewer
  • CloudFront-Is-Mobile-Viewer
  • CloudFront-Is-SmartTV-Viewer
  • CloudFront-Is-Tablet-Viewer

これらの動作を調べてみました。

iOSスマートフォン (iPhone)

User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 9_3_2 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13F69 Safari/601.1

Desktop Mobile SmartTV Tablet
false true false false

iOSタブレット (iPad)

User-Agent: Mozilla/5.0 (iPad; CPU OS 9_3_2 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13F69 Safari/601.1

Desktop Mobile SmartTV Tablet
false true false true

MobileとTablet両方trueになる

Mac (Firefox)

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:54.0) Gecko/20100101 Firefox/54.0

Desktop Mobile SmartTV Tablet
true false false false

Androidスマートフォン (Nexus 5X)

User-Agent: Mozilla/5.0 (Linux; Android 7.1.1; Nexus 5X Build/N4F26I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36

Desktop Mobile SmartTV Tablet
false true false false

Androidタブレット (Nexus 7)

User-Agent: Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MMB29O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Safari/537.36

Desktop Mobile SmartTV Tablet
false true false true

ちゃんとスマートフォンとタブレット判別できてる!

Fire TV

User-Agent: Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; AFTB Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30

Desktop Mobile SmartTV Tablet
false false true false

検証に用いたソースコード

PHPで殴り書きしました。

<?php
echo($_SERVER['HTTP_CLOUDFRONT_IS_DESKTOP_VIEWER']);
echo($_SERVER['HTTP_CLOUDFRONT_IS_MOBILE_VIEWER']);
echo($_SERVER['HTTP_CLOUDFRONT_IS_SMARTTV_VIEWER']);
echo($_SERVER['HTTP_CLOUDFRONT_IS_TABLET_VIEWER']);

参考文献

続きを読む

Node.jsでslackのbotを作ってEC2上でデーモン化するまで

Web開発用にチームでSlackを使うことになった。
今後はChatOps的な使い方をしてデプロイや監視との連携なんかをしていきたいんだけども
まず始めは bot を使い倒してチーム内のコミュニケーションをうまくできないかなぁと思って始めてみた。

botの準備

Slack Botsを設定する

SlackのApps&integrationsメニューから、Manageを選択
スクリーンショット 2017-06-03 17.26.31.png

Custom Integrationsの項目を開くとBotsがあるので選択

スクリーンショット 2017-06-03 17.29.01.png

Add Configurationを選択し、Botの名前(@username)を入力して Add bot integration

スクリーンショット 2017-06-03 17.29.38.png

スクリーンショット 2017-06-03 17.30.24.png

ここでは @username=satomiとしました。
次のページで出てくるAPIトークンは後で使用するので覚えておきましょう。
Botsのアイコンは画像をアップロードしてもいいし、絵文字を使用することもできるようです。
とりあえずここまでできればBotsの準備はOK

EC2とNode.jsの準備

最初は自前のmacにnode.jsを入れて動かしてたんだけど
macがスリープモードになったり、シャットダウンしたら当然botは動かなくなるので
しかたなくサーバを立てようかなと思っていたってのと、

AWSの無料枠があると聞いていたので使ってみようかなと思って
EC2インスタンス上にnode.jsを入れてbotが常駐できる環境を作ることにした。

EC2インスタンスにSSHで接続

EC2インスタンスをどうやって立てるの?ってのは省略します。
ローカルPCからこんな感じで接続することになります。

ssh -i "XXXXXX.pem" ec2-user@XXXXXXXX.compute-1.amazonaws.com

最新のNode.jsの準備

nvm (Node Version Manager)を入れて、最新のNode.jsを使えるようにしましょう。

1. nvmのインストール

$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.29.0/install.sh | bash

2. Node.jsの最新バージョンをインストール

$ nvm install v5.1

3. インストールしたNode.jsの設定

インストールしたNode.jsはデフォルトver.として5.1を使うことにしておきましょう

$ nvm use 5.1
$ nvm alias default 5.1

foreverの準備

Node.jsをバックグラウンドで動かしておくためのパッケージforeverをインストールする。

nodejsはコマンドアプリケーションのため、コンソール閉じるとアプリが終了してしまうらしい。そのため、永続的に起動するには、コンソールからnodejsを切り離す。

foreverはハンドルされていない例外が発生してプログラムが停止した場合自動で再起動やってくれる。なのでプログラムがエラーで勝手に止まっちゃう心配は無い。

これがないとSSH接続が切れた際にNode.jsも一緒に切断されてしまってbotが落ちてしまった。少しハマった。

$ sudo npm install -g forever

これでOK。

ちなみにforeverの使い方を簡単に書いておくとこんな感じ

// 書式
forever [options] [action] SCRIPT [script-options]

// プログラムを実行
forever start SCRIPT

// 実行中のプロセスを確認. ここで表示されるログファイルなどチェック
forever list

// プログラムを停止. プロセス番号はforever listで確認
forever stop プロセス番号

// プログラムを再起動. プロセス番号はforever listで確認
forever restart プロセス番号

Node.jsでbot用のスクリプトを書いていく

ここまで準備ができたらいよいよbotを作ります。

botの作成

botを作成しましょう。まずはnpmで初期化します。

$ npm init

usernameとか聞かれますのでいい感じに答えていってください。

botkitを使ってbotを作っていきます。
公式サイト: https://www.botkit.ai/

$ npm install --save botkit

これによってnode_modulesというディレクトリができ、そのなかにbotkitディレクトリができます。
–saveオプションをつけてインストールすることで、package.jsonのdependenciesにもbotkitを追加してくれるようです。

botの中身を書いていきます。

$ vi index.js
index.js
var Botkit = require('botkit');
var controller = Botkit.slackbot();
var bot = controller.spawn({
  token: '初めに作ったbotのAPIトークン'
}).startRTM(function(err,bot,payload) {
  // 初期処理
  if (err) {
    throw new Error('Could not connect to Slack');
  }
});
controller.hears(["hello"],["direct_message","direct_mention","mention"],function(bot,message) {
  // キーワードに反応した処理
  bot.reply(message, 'hello! I am bot!!');
});<img width="238" alt="スクリーンショット 2017-06-03 18.18.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/163591/49a475d1-d60b-9b84-2a14-83e76837483c.png">

botの起動

$ forever start -l app.log -a index.js

このようにしておくとapp.logにログを吐いてくれるので便利ですね。
念のためforever listで確認しておきましょう。

$ forever list
info:    Forever processes running
data:        uid  command                                           script   forever pid   id logfile                         uptime       
data:    [0] Kpda /home/ec2-user/.nvm/versions/node/v5.1.1/bin/node index.js 27318   27323    /home/ec2-user/.forever/app.log 0:1:3:57.891 

正常にrunnningしているようです。
やっと完成。あとはbotに話しかけてみましょう。

スクリーンショット 2017-06-03 18.18.32.png

上手くできてますね。

続きを読む

Mac OS Sierra でamazon awsのインスタンスにsshす

うまくできなくてめっちゃ詰まったので自分用として作成

前提(と用意するもの)

  • ES2のインスタンス
  • sshしたいインスタンスのキーペアと秘密鍵 hogehoge.pem

やり方

  • キーペアの秘密鍵 hogehoge.pem を ~/.ssh 以下に置く
  • ~/.ssh のパーミッションを700に、~/.ssh/* または hogehoge.pem のパーミッションを600に変更する
sudo chmod 700 ~/.ssh
sudo chmod 600 ~/.ssh/*
  • sudo vim ~/.ssh/configでコンフィグファイルを開いて、PubkeyAcceptedKeyTypes=+ssh-dssを追記

  • ssh接続する

    ssh -i /Users/username/.ssh/hogehoge.pem ec2-user@パブリックDNS

何が原因だったのか

  • Sierraにアップデータした時にsshのバージョンが上がって鍵がうまく使えなかったっぽい
  • 秘密鍵のある場所は700にしないといけないけど、秘密鍵自体は600じゃないと動かないっぽい(400がいいとか644がいいとか諸説ありだけど、私の環境では600じゃなきゃダメだった)

続きを読む

MacのiTunesライブラリをAWS S3にバックアップする

あらまし

長いこと使っている MBA(Late 2013, SSD128GB) のiTunesのライブラリ*を、どこかしらにバックアップしようと考えた。けれど、

  • 手元に空いた外付けディスクがない
  • iTunesライブラリが60GBぐらいあるので、ディスク容量が足りず圧縮できない
    • →DropboxとかGoogle Driveとか、オンラインストレージにzipファイルを投げるのはアウト
    • そもそも定期的にzip作ってアップロードして、って面倒すぎない?
      スクリーンショット 2017-05-28 20.48.18.png

などなどの状態で困っていたけれど、最終的に「S3でいいんじゃない?」ってとこに辿り着いた。
実際にやってみたので、その手順をメモしておく。

*本記事では /Users/${username}/Music/iTunes 以下を想定しています。それ以外にバックアップしておくべき箇所があるなら教えてほしい。

手順

  1. ターミナルでAWS CLIが利用できるようにする
  2. CLI経由でS3にアクセスできるIAMロールを作成する
  3. 2.のIAMロールをCLI側で設定する
  4. ターミナルでaws syncコマンドを実行する

1. AWS CLIコマンドのインストール

ターミナルからpipでインストールする。

$ pip install --upgrade --user awscli

ダウンロードできたら aws --version を叩いてみる。
こんな感じで返ってきたらOK。

$ aws --version
aws-cli/1.11.93 Python/2.7.10 Darwin/16.6.0 botocore/1.5.56

command not found な場合は、パスを通してから再度実行する。

$ export PATH=$PATH:/Users/${username}/Library/Python/2.7/bin

2. IAMユーザーの作成

S3にアクセスするためのIAMユーザーを作成する。

メニュー > IAM > [ユーザーを追加]

1. 詳細

ユーザー名: ex.) s3-uploader
アクセスの種類: プログラムによるアクセス を選択

2. アクセス権限

ユーザーをグループに追加 > グループの作成
グループ名: ex.) s3-uploader
ポリシー: AmazonS3FullAccessを選択

以降、3.確認 > 4.完了と進み、credentials.csv をダウンロードしておく。

3. IAMユーザーのID・PWを設定する

2.で作成したIAMユーザーでAWS CLIコマンドを実行するための設定をする。

$ aws configure

ダウンロードしたcredentials.csvの情報を入力する。

AWS Access Key ID: (記載されているAccess Key ID)
AWS Secret Access Key: (記載されているSecret Access Key)
Default region name: us-east-1
Default format: json
スクリーンショット 2017-05-26 21.48.54.png

4. AWS CLIコマンド実行

$ aws s3 sync /Users/${username}/Music/iTunes s3://${s3bucketname}/iTunes

sync で、指定したディレクトリ以下を再帰的に同期してくれる。

結構時間がかかった。(諸事情で出先でやっていたので、だいたい7~8時間)
が、GUIで操作して……だと何百年経っても終わらないだろうことを考えると、目覚ましい。便利です。

参考

http://www.task-notes.com/entry/20150904/1441335600
https://aws.amazon.com/jp/getting-started/tutorials/backup-to-s3-cli/
http://docs.aws.amazon.com/cli/latest/userguide/installing.html#install-bundle-other-os

続きを読む

Amazon Pollyを使って耳で本の推敲をする

自分のブログ「Real World HTTPが出版されます」で紹介したAmazon Pollyを使って本の推敲をする、というやつを軽く紹介します。

ささっと2-3日で作ったSphinx拡張を使っています。本エントリーではツールの使い方も紹介はしますが、Sphinx以外のツール向けに似たような変換機能を作りたい人の参考のために、ツールが何をしているかも紹介します。今まで使う機会もなかったので実は初AWSでした。

リポジトリはこれです。BSDライセンスです。

SSMLというのは、Amazon Pollyの入力に使う音声合成用のデータフォーマットのことです。W3Cの規格になっており、PanasonicとかTOSHIBAの人も規格制定に加わっています。Amazon Pollyはこのうちのいくつかのサブセットに対応しています。

できあがりはこんな感じです。

インストール

Sphinxがインストールされているとして次のコマンドでインストールします。

$ pip install sphinxcontrib-ssmlbuilder

AWSアクセスのライブラリのboto3と、AWSを使うコマンドラインツールのawscliもインストールされていなければ入ります。あと、ffmpegを使うのでインストールしておきます。

# MacPortsの場合
$ sudo port install ffmpeg

AWSのコンソールのIAMでPollyを使う用のアカウントを作ります。僕はpollyという名前にしました。Amazon Pollyが使えるリージョンを選んで(僕はUS-West-Oregon)、Amazon Pollyのアクセス権(Read Onlyでよい)を付けます。ここでいう書き込みというのはオリジナルの発音設定などをアップロードするためのものですが、日本語はサポートしていないようですし、読み込みで十分です。

スクリーンショット 2017-05-25 23.57.04.png

できたら、aws congiureコマンドで、このアカウントのアクセストークン的なものをローカルに作っておきます。このときの名前をSphinxで使います。

sphinx-quickstartコマンドでドキュメントのプロジェクトフォルダを作ったら設定ファイル(conf.py)に次のssmlbuilder用の設定を追加します。

extensions = ['sphinxcontrib.ssmlbuilder']
# you should register the following user name
# via aws configure.
ssml_polly_aws_profile = "polly"      # AWSのプロファイル
ssml_polly_apply_docnames = "*"       # どのソースファイルを変換するか

# for Japanese
ssml_language = 'ja-JP'               # 言語
ssml_polly_aws_voiceid = 'Mizuki'     # 使いたい音声(現在日本語はMizukiのみ)

どのソースファイルを変換するかはここでは全部を指定していますが、実際にはMakefileの中で、書き上がったファイルをオプションで渡せるようにしていました。

TARGET        = ""

.PHONY: ssml
ssml:
    $(SPHINXBUILD) -b ssml $(ALLSPHINXOPTS) $(BUILDDIR)/ssml -D ssml_polly_apply_docnames=$(TARGET)
    @echo
    @echo "Build finished. The SSML files are in $(BUILDDIR)/ssml."

こんな感じで実行します。

$ make ssml TARGET=preface
sphinx-build -b ssml -d _build/doctrees   . _build/ssml -D ssml_polly_apply_docnames=preface
Running Sphinx v1.6
loading translations [ja]... done
loading pickled environment... done
building [mo]: targets for 0 po files that are out of date
building [ssml]: targets for 0 source files that are out of date
updating environment: 0 added, 0 changed, 0 removed
looking for now-outdated files... none found
no targets are out of date.
build succeeded.
ssml_polly_aws_profile:  polly
ssml_polly_apply_docnames:  preface
audio output folder:  polly
ssml_polly_aws_voiceid:  Mizuki
Found credentials in shared credentials file: ~/.aws/credentials
polly.synthesize_speech for preface-1.ssml (1/18)
polly.synthesize_speech for preface.1-1.ssml (2/18)
polly.synthesize_speech for preface.4-1.ssml (3/18)
polly.synthesize_speech for preface.3-1.ssml (4/18)
:
polly.synthesize_speech for preface.5-1.ssml (18/18)
concatinating MP3 fragments: preface.mp3 (1/1)
:
Build finished. The SSML files are in _build/ssml.

推敲の成果

Mac上でも、Android上でも、再生速度が細かく設定できるVLCを使って聞きました。どちらも、間違いを見つけたら一時停止しつつGoogle Keepにメモするようにしてコメントを同期していました。通勤は歩く距離が長く、かつ、歩道が整備されているので、歩きながら聞いたりもしました。自転車に乗りながらはダメですよ。

ブログにも書きましたが、細かい助詞の違いとかは目で見るよりも、耳で聞くほうが間違いが分かりやすいです。それ以外にも、同じ内容を繰り返していたりとか、定義を紹介せずに説明を始めてしまっているところ、何を言いたいのかよくわからない場所とかもよくわかります。

ただし、速度を上げると、時間が節約できる代わりに間違いに気づきにくくなります。速聴の練習をしているのであれば、多少速めても問題はないでしょう。僕は聞くだけなら3.5倍ぐらいで聞く練習をしたのですが、推敲する場合はゆっくり目でないと役に立ちません。僕の場合は次のような感じでした。

  • 1.2倍: 助詞の違いにも気づける。中身の間違いにも気づける
  • 1.5倍: 中身の違いには気付けるが、助詞の違いは気づけ無い
  • 2倍: 間違いに気づけない。

章の内容が書き上がったら、耳で聞きながら推敲するのを2回ぐらい回してからレビューに投げる感じでした。見直しをするときは、少し時間を置いてからとか「新鮮な視点で」やることが大事だとよく言われますが、耳でレビューはまったく別のヒューマンインタフェースを使うので、そういう「ちょっと置いて」とかもあまり考えずにガンガンやって大丈夫です。

あとは、強制的に進むので、時間の見通しが付けやすいのと、集中力がきれて別のことを調べ始めたりとかそういうことが起きにくい点も良かったです。ルールファイルを作ったりとかそういうのも必要ないですしね。

内部の仕組み

処理のフロー

Pollyの入力では1500文字(SSMLの制御文字を除く)しか受け取れませんので、分割してこの分量で出すようにして個別に音声化して最後にマージします。

初使用から一年間は無料枠がかなりあり、本を何度もエクスポートしても無料枠で収まってしまいましたが、そのうち無料枠がなくなることを考えればサーバーアクセスは最低限にしたいところですよね。もちろん、金額だけじゃなくて、余計な仕事を投げなければ実行時間も節約できます。個人的には上坂すみれオプションがあれば1万円ぐらい払うのもやぶさかでないのですが、残念ながら提供されていません。

本だと、段落を入れ替えたり、新しい段落を追加・削除するのは日常的に起こります。そのため、段落ごとに分割(ついでに1000文字超えても分割)し、本文のコンテンツのハッシュをキーとして、同じキーを持つmp3がある時はサーバーアクセスをスキップするようにしました。あと、読み上げてもしょうがないコメント、テーブル、ソースコードとかもスキップしています。

必要なMP3ファイルがそろったら、それをffmpegを使って1つのMP3に変換します。

テキスト抽出部分

よくあるビジターパターンです。Sphinxのビルダーを作ったことがある人ならお馴染み。まあ、長いし楽ではないです。参考となるビルダーをコピーしていじる感じです。装飾となるような情報はほぼすっ飛ばしてテキスト、セクションタイトルぐらいをピックアップするぐらいです。

変換部分

一応次のような感じで詳細な設定もできるようにしていましたが、デフォルトのまま使いました。

    ssml_skip_block = {'comment': True, 'table': True, 'codeblock': True}
    ssml_break_around_section_title = [2000, 1600, 1000, 1000, 1000, 1000]
    ssml_break_after_paragraph = 1000
    ssml_emphasis_section_title = ['none', 'none', 'none', 'none', 'none', 'none']
    ssml_paragraph_speed = 'default'

SSMLを使うと、再生速度や強調などを設定できます。しかし、実験してみるとどちらも不自然さが目立ってしまったので、声色に関しては何も設定しないようにしました。普通の人が本を音読する時は、表題とか段落の後は空白の溜めだけで区切っているだけで、章、節などのタイトルで強さを変えているわけではありませんからね。セクションタイトルはそれぞれ深くなるにつれて、2秒、1.6秒、1秒と停止時間を減らすようにしています。あと、段落の後にも1秒追加しています。工夫としてはこれだけです。というか、いろいろ実験したけど削った結果がこれです。

AWSのAPIを叩く部分は連続で叩きすぎないように、少し待つようにしています。Goのtime.TickerのAPIを参考に。

あとはffmpegで段落ごとのMP3を結合しておしまいです。管理しやすいようにSphinxの書籍名、著者名、ファイルのタイトル、通し番号のメタデータを付与します。これでVLCでもきちんと整理できます。

続きを読む

Node.js + Express をAWS Elastic Beanstalkで動かす

以前と設定の仕方が変わったようで、
npm startを設定しないとExpressが起動されなかったので手順をまとめました。
クライアントはMacです。

IAMユーザーの作成

マネジメントコンソールから必要な権限を持ったIAMユーザーを作成し、認証情報を取得。

awscliのインストール

sudo pip install awscli
aws --version
-------
aws-cli/1.11.74 Python/2.7.13 Darwin/16.6.0 botocore/1.5.55
-------

aws configure
------
AWS Access Key ID [None]: ********
AWS Secret Access Key [None]:  ********
Default region name [None]: ap-northeast-1
Default output format [None]: 
------

ebコマンドのインストール

pip install --upgrade --user awsebcli
vi .bash_profile
-----
export PATH=~/Library/Python/2.7/bin:$PATH
-----

eb --version
------
EB CLI 3.10.1 (Python 2.7.1)
------

Express環境の設定

sudo npm install -g express
sudo npm install -g express-generator

Expressプロジェクトの作成

express test-nodejs
cd test-nodejs/
npm install

git初期設定

git init

cat > .gitignore <<EOT 
node_modules/
.gitignore
.elasticbeanstalk/
EOT

Elastic Beanstalkの初期設定/アプリ作成


eb init --platform node.js --region ap-northeast-1
eb create --sample test-nodejs

eb status
------
Environment details for: test-nodejs
  Application name: test-nodejs
  Region: ap-northeast-1
  Deployed Version: app-e465-170525_182949
  Environment ID: e-v7aa4cmhbi
  Platform: arn:aws:elasticbeanstalk:ap-northeast-1::platform/Node.js running on 64bit Amazon Linux/4.1.0
  Tier: WebServer-Standard
  CNAME: test-nodejs.xxxxxxxxx.ap-northeast-1.elasticbeanstalk.com
  Updated: 2017-05-25 09:31:52.871000+00:00
  Status: Ready
  Health: Green

これでElastic Beanstalk側の環境が完了です。

eb open

スクリーンショット 2017-05-25 20.58.26.png

ここからExpressアプリをデプロイしていきます。

elasticbeanstalkでExpressを動かす設定


mkdir .ebextensions

vi .ebextensions/nodecommand.config
------
option_settings:
  aws:elasticbeanstalk:container:nodejs:
    NodeCommand: "npm start"
-------

ちなみに、これをやらないで進めると、Expressが起動せずに502エラーになってしまう。

スクリーンショット 2017-05-25 18.28.22.png

アプリのデプロイ

vi views/index.jade
-----
extends layout

block content
  h1= title
  p Welcome to AWS
------

git add .
git commit -m "First express app"    
eb deploy

eb open

無事expressアプリが表示されました

スクリーンショット 2017-05-25 18.32.15.png

参考

http://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/create_deploy_nodejs_express.html

続きを読む