Netlify

Podcast 配信環境あれこれ

はじめに

この記事は Podcast を配信する環境を色々試行錯誤した際のメモの集合です

あらすじ

  1. ポッドキャスト、最初は WordPress にプラグインを入れた奴で配信していました
  2. yattecast + GitHub Pages での配信に切り替えました
  3. 最終的に yattecast + Netlify + Google Cloud Storage で配信することにしました

Podcast 配信をはじめよう

最初の選択

2018 年の年始に「なんか、安価に手軽に Podcast を配信したいな」と思って辺りを見渡してみたら、"「ロリポップ!」誰でも簡単にクラウドホスティングを活用できる「マネージドクラウド」プランのオープンβ版を本日11/30(木)より提供開始"というのを見かけて、面白そうだし、当面無料だし、WordPress 程度だったらサクっとセットアップ出来そうだし、試してみるか、という感じでやってみました

マネージドクラウドへの WordPress のセットアップ

まず、"ロリポップ!マネージドクラウドで技術BLOGをオープンしてみた"にあるように、アカウントを作って、ログインして、プロジェクトを作成するときに「WordPress」を選択するだけで、数分でセットアップが完了しました。便利

Podcast 配信に便利な WordPress プラグイン

Seriously Simple Podcasting というのがあります
このプラグインをインストールして、それっぽい設定を埋めるだけで Podcast 配信の準備が完了します
あとは配信したい音声ファイルをアップロードするだけで、ファイルのメタデータを読み取って、1エピソードにすることができてしまいます
これの便利なところは「WordPress の Blog Post と同じように予約投稿が出来る」ところと「アップロードしたファイルからファイルサイズや再生時間などを読み取ってフィードに反映してくれる」ところでした

iTunes 向けのフィードの作成

Apple の Podcast プロバイダというサイトで、iTunes Music Store 向けのエンドポイントを作る事ができます
ここにログインして、Seriously Simple Podcasting で生成した RSS フィードの URL を登録して、必要な項目を埋めてやれば、フィードを読み取って iTunes Music Store のページとミラー URL を作って貰えます

WordPress で、よかったこと

めちゃくちゃ簡単にセットアップできて、あんまり何も考えずに運用できてしまったので良かったです
よし始めよう、と思ったときに、すぐ始められるというメリットはかなり大きいと思います

運用上の問題

マネージドクラウドの HTTP リクエストサイズの制限

ロリポップ!マネージドクラウドでは HTTP リクエストのサイズが 20MB を越えるとエラーになる制限がありました
Seriously Simple Podcasting は WordPress のプラグインなので、音声ファイルを管理画面からアップロードして、それを使ってエピソードを作ります。ちょっと長目のエピソード(15分越えくらい)を作ると、ファイルサイズが 20MB を越えてしまい、管理画面からアップロードできないという事態になってしまいました。だからといってビットレートを落としたりしてファイルサイズの調整をするのは面倒なので、まず管理画面からダミーの小さい音声ファイルをアップロードしておき、マネクラの SSH 機能を利用して、scp コマンドでコンテナのボリュームに大きい音声ファイルをダミーファイルに上書きすることで配信ファイルにしていました。めっちゃ面倒くさい

WordPress のメンテナンス

WordPress のメンテナンスと言っても、WordPress 自体のバージョンアップとプラグインのバージョンアップを管理画面からこまめにやっていれば済むので、そんなに大変じゃないですよね
そう思っていた時期がわしにもありました。でも、まぁ、そんな些細なオペレーションも、ずっとやってると面倒になってくるんですよね...... 辛い......
バージョンアップするときに「DB のバックアップをしてから行って下さい」みたいな事を言われて、最初の何度かは言われたとおりにするんですけど、段々とやらなくなりましたよね。はい......

無料期間の終了

ロリポップ!マネージドクラウドの無料期間が2018年6月30日で終了し、月額980円からという感じの料金体系になりました
マネージドクラウド自体は、オートスケーリング機能などの面白い機能が付いていたり、良いサービスなんですが、今の使い方だと大して負荷もかからないし、まぁ、ちょっと勿体ないなと思い、代わりの環境へ移ることを検討することにしました

新しい環境へ

課題

まず、新しい環境を検討するにあたって、考えないといけない課題の軸が2つありました

サーバーの移転

サーバー環境で是正したい点を整理します

  1. HTTP リクエストのサイズ制限により運用が面倒くさくなっていた
  2. やっていることに対して性能が高すぎて、有料化に伴ってコストが見合わなくなってしまった

というわけで、つぎのサーバー環境は

  1. 音声ファイルのアップロードで悩まない環境
  2. 身の丈に合った、0 〜 500 円/月くらいのコストの環境

という感じになります

配信アプリケーションの変更

配信アプリケーションの課題を整理します

  1. WordPress のメンテナンスするの面倒くさい
  2. そもそも静的なコンテンツを配信するのに WordPress を使うのは大げさなのでは

というわけで

  1. アプリケーションのメンテナンスフリー
  2. 必要最低限の小さいシステム

が求められます

次の選択

サーバー

つまるところ、Podcast 配信って、静的ファイル配信さえ出来れば良いんだから、GitHub Pages とかで配信すればいいのでは?という発想になりました
最初からリポジトリに全部突っ込んでおけば、音声ファイルを POST で渡したりする必要も無いし、無料だし、課題はクリア出来そうです

配信アプリケーション

GitHub Pages に Podcast をリリースするテンプレートとして yattecast というのがあります
これが、すごく良くて、https://github.com/r7kamura/yattecast を fork して nantyara.github.io みたいなリポジトリ名にすれば、あとは設定を適宜書き換えて、音声ファイルと _posts/ 以下にエピソードのマークダウンファイルを push していくだけで配信できてしまいます

運用上の問題

というわけで、試しに yattecast + GitHub Pages 環境を作ってみました
やってみてから気づく問題というのは結構あるもので、いくつかの問題が発生しました

GitHub のリポジトリには何 MB くらいまで push して良いのか

GitHub のリポジトリには「これ以上入れたら動かなくなる」というような明示的なサイズリミットは無いようです。とは言え指針はあります。これによれば、1 ファイル 100MB は越えて欲しくないし、リポジトリ自体のサイズも 1GB くらいまでを目安にして欲しいようです。この指針に沿わずに使っている場合には「お願いですからシュリンクしてください」というようなメールが来るかもしれないそうです
そうなると、既に 20MB の音声ファイルが 50 個近くあり、リポジトリのサイズが 1GB を越えてしまう現状は望ましくありません
音声ファイルの配信だけでも、別のサーバーに移した方が良さそうです

予約投稿が実現しづらい

GitHub Pages は新しいコミットが push されると、Jekyll の build タスクが行われ、静的なサイトが生成されます。このビルドは push 時に 1 度行われるのみで、その後、改めてビルドし直すような機能は有していません。また、ビルド時のオプションとして --future が指定されているようで、このオプションを指定すると _posts の中に書いておいた date がビルド時よりも未来の日付であっても生成してしまうので、予約投稿のつもりで date を指定しても効いてきません。
これをなんとかしようと思ったら、エピソードの publishedfalse にした状態で push しておき、公開したい時刻に true にするコミットを push するような仕組みを作るしかありません。大変すぎる......

GitHub Pages では独自ドメインを使った際に HTTPS に出来ない

GitHub Pages は nantyara.github.io のような github.io のサブドメインとして公開されます。また、自分の管理下にあるドメインの CNAME に nantyara.github.io (nantyara部分は適宜読み替え) を指定する事で独自ドメインを使ってアクセス出来るようになります。
github.io のサブドメインのままであれば、自動的に HTTPS に対応してくれるので楽ですが、独自ドメインからは HTTPS でアクセスしても github.io サブドメイン向けの証明書しかないので、警告が出てしまいます

(追記)なんか、今年の頭くらいから、GitHub pages では独自ドメインであっても自動的に HTTPS の証明書を付けてくれるようになっていたようです

安住の地を求めて

課題

音声ファイルをどこから配信するか

GitHub のリポジトリに突っ込んでおくのは無理があるということが分かっている

予約投稿をしたい

yattecast をそのまま使うとして、--future オプション無しで、定期的にビルドし直せる環境なら問題が無くなるハズ

独自ドメインで HTTPS が使いたい

なんか自動的に Let's Encrypt とかで証明書をくっつけてくれる環境がないもんか......

最終的な選択

音声ファイルの配信

とりあえず、Google Cloud Storage に置いて、allUsers にバケット閲覧者の権限を与えて公開してしまえばいい
この方法は転送料金が 1GB あたり 0.12 ドルかかるけど、月 3 ドルを超えたあたりから VPS へ逃がすことを検討すれば良さそう

フィードと WEB ページのサーバー

Netlify というサービスがあって、それを使う事にしました
Netlify、なんかすごくて、どこがすごいかというと、下記の通り

  • カスタムドメインが使えて、自動的に HTTPS になる
  • Build hooks という機能で、ビルドを開始するトリガーになる URL を生成出来る
  • GitHub のリポジトリを指定するだけで、PULL してビルドしてくれる
  • なんか無料

おあつらえ向き過ぎる。

運用上の問題

MP3 ファイルからメタデータを読み込む仕組みのことを忘れていた

忘れてたけど、WordPress でやってたときに、メディアをアップロードするだけでメタデータを読み込んでくれるの便利だったんだった。代わりの機能が欲しいですね
というわけで、それは、雑にスクリプトを書いて運用することにしました

create_post.rb
require 'mp3info'
require 'pathname'
require 'time'

file_path, publish_date = ARGV
filename = Pathname.new(file_path).basename
publish_datetime = Time.parse("#{publish_date} 22:55:00 JST").rfc2822

File.open(file_path) do |f|
  Mp3Info.open(f) do |mp3|
    title, album, artist =  mp3.tag.values_at('title', 'album', 'artist')
    length = mp3.length
    desc = mp3.tag2.fetch('TT3')
    num = filename.basename('.mp3')

    File.open("./_posts/#{publish_date}-#{num}.md", 'w') do |output_file|
      output_file.puts <<~TXT
        ---
        id: #{num}
        actor_ids:
          - mami
          - aoharu
        audio_file_path: https://storage.googleapis.com/files.nantyara.com/#{filename}
        audio_file_size: #{f.size}
        date: #{publish_datetime}
        description: #{desc}
        duration: #{length}
        layout: article
        title: #{title}
        ---
        ## 概要
        #{desc.each_line.map { |line| "#{line}" }.join}
        ## 関連リンク
        * none
      TXT
    end
  end
end

このスクリプトを ruby create_post.rb path/to/episode.mp3 2018-11-30 みたいな感じで叩くと、MP3 ファイルからメタデータを読み込んで、その内容を反映した新しいエピソード用のマークダウンファイルを所定の場所に書き込んでくれます。あとは適宜ファイルを編集して微調整して commit, push すればよい

定期的にビルドするための CRON が欲しい

せっかくここまでサーバー無しの環境を作ったのに、最後に CRON 用サーバーを用意するんじゃ、あんまりですよね
なので「貧者の CRON」として名高い Google Apps Scriptを使う事にしました

kick_build.js
function kickBuild() {
  const options = {
    'method': 'post',
    'payload': {}
  };

  UrlFetchApp.fetch('https://api.netlify.com/build_hooks/<生成したURL>', options);
}

こういう感じのスクリプトを登録して「編集」->「すべてのトリガー」->「新しいトリガーを追加」から kickBuild を「時間主導型」「分タイマー」「5分ごと」で登録しておけば5分ごとにビルド用のエンドポイントをキックしてくれるようになります

追記(2018/11/08)

なんか、Google Cloud Scheduler がリリースされたので、URL を叩くだけの当 cron は Cloud Scheduler に移行しました。GAS でも簡単だったけど、Cloud Scheduler はコードを使ってリクエストする必要がないので、より楽です

気になること

Netlify のビルド設定はコマンドを直接指定出来るので、もしかしたら、ビルドする度に Google Cloud Storage から全エピソード分の音声ファイルをダウンロードさせて、全部 Netlify で配信することができてしまうのではないかという予感があります。でも、それをやると5分に1回、1GB くらいダウンロードされることになってしまって、1時間に 12GB、1日 288GB、1ヶ月 8,928GB も転送されてしまい、Google Cloud Storage の転送量破産しそうなので、やっぱり気のせいだったようです。ただ、ログを見てると、Ruby の Gem とか、npm の module はキャッシュされたりしてるみたいなので、明示的にキャッシュさせるような設定が書けるならワンチャンありそうなので、今度調べてみます。Netlify、単なる配信ホストではなく、かなり奥が深そう

追記

Large files or sites によれば、10MB オーバーのファイルをアップロードしようとしても通らないっぽいですね。そらそうっすよね。世の中そんなに甘くない

まとめ

  • yattecast 便利
    • 大したことをしなくても良い感じの Poscast 配信が実現出来る
  • Netlify、神では?
  • SoundCloud にお金払って配信するのが一番いいのでは......
    • SoundCloud Pro Unlimited Pro
    • 最近、予約投稿も出来るようになった -> "Scheduled releases"
    • ただ、年間 17,000 円くらいはかかってしまう -> "$16/month or $144/year (save $48)"
  • なんちゃらアイドルのなんちゃラジオ、毎週金曜日 23:00 に更新しています。聴いてみてね