akiyoko blog

akiyoko の IT技術系ブログです

「EdTech Night!! これからのプログラミング教育とは?」に参加しました

会場

東京都渋谷区桜丘町21−4 渋谷桜丘町ビル3F
Branding Engineerオフィス




EdTech ✕ プログラミング教育の勉強会に参加してきました。
貴重な話をいろいろ聞くことができました。


 

「EdTechとは」「子供向けプログラミング教育のあり方」

渡辺 のぼる 氏

  • 教育版レゴ Mindstorms による人材育成
  • World Robot Olympiad
  • 他にもプログラミング教育というと、Scratch, Minecraft とか?
  • モノを使う学び
    • 動いた時の喜び
    • コンストラクショニズム

コンストラクショニズム理論とは、レゴ・シリアスプレイ®の根底を支えている理論です。
マサチューセッツ工科大学メディア研究所のシーモア・パパート教授によって提唱されました。

手と頭は連携を取り、相互に信号のやり取りをしながら、新しい知識を構築していくという理論です。単に、頭だけで考えていても、新しい知識は構築できない、「何かをつくることで学ぶ」という考え方で、世界中のIT教育や科学分野の研究などに採り入れられています

人は、「モノを使って考える」あるいは「手を動かして考える」ときに、創造的なエネルギー、創造的な思考、モノの見方が引き出されるという理論です。

レゴ・シリアスプレイでは、このコンストラクショニズム理論をベースに構成されています。


コンストラクショニズムとは|レゴ・シリアスプレイ® | コラム | Block Party|レゴブロックを活用したユニークな研修」より引用


 

「プログラミング教育の活動をする理由」

具志堅 雅 氏 (@g08m11)

  • オススメの映画は「マイ・インターン」

【Amazon.co.jp限定】マイ・インターン ブルーレイ&DVDセット(初回仕様/2枚組/デジタルコピー付)(B2ポスター付) [Blu-ray]

【Amazon.co.jp限定】マイ・インターン ブルーレイ&DVDセット(初回仕様/2枚組/デジタルコピー付)(B2ポスター付) [Blu-ray]

  • Swift/Rails
  • morei(モアイ)
    • ちょうどのプログラミング学習をより安く
    • ブート型プログラミング教育が乱立している。けど、高すぎる!
  • Sweet Swift
    • 女性限定のWeb系講座
    • 講座内にスイーツタイムがある、ゆるふわ系
  • なぜプログラミング教育?
    • 他の分野よりも応用が効くから

 

パネルトーク「EdTechトレンド」「プログラミング教育で得られる成果」

EdTechの定義は、教育の抱える課題を技術的に解決すること。

プログラミング教育

  • プログラミング教育で得られる成果(6票)
    • プログラミングは面白そうだ、という素敵な勘違いをしてもらいたい(渡辺)
    • 成果として、職種の垣根がなくなる(具志堅)
  • プログラミング教育とEdTech(11票)
    • 教育以外にも、学校に入れる教具としての電子機器のためのプログラミングもあるので、ビジネスとして包含?している(渡辺)
    • プログラミング教育にTVなどのマスメディアができる役割は?
    • プログラミングは、職業に直結する技術

他にも、

  • プログラミング教育は義務教育化すべきか(5票)
  • プログラミング教育の未来(大人の教育含む)(2票)

EdTech一般

  • ビジネスとしてのEdTech(9票)
    • schooとかは職業と直結しないので、ビジネスとしてはイケてない。ビズリーチみたいに、採用まで持って行ってお金をもらうのがよい。(具志堅)
    • プログラミング教育の周辺事業として(具志堅)
    • 講師を常時付けるなどしないと、離脱率が落ちちゃう。(具志堅)
    • 質問しやすさは、絶対的にリアルのほうがよい。もしするなら、apear.in みたいに教えてあげないと。(具志堅)
    • レゴとかキャッチーなのは私立だと鶴の一声で入れてもらえることもあるが、公立の学校だと、マインド・ITリテラシーが低すぎて導入が難しい。(渡辺)
    • 自治体の方がやりやすいところもある?
  • EdTechのトレンド(盛んな分野)(5票)
    • 世界で盛り上がっているEdTechは?
    • 動画で学べるschooとかはトレンドだと思う。(渡辺)
    • レゴは、ストーリーを作ってみんなに共感を伝えることができる「ストーリースターター」がグローバルにウケる(渡辺)
    • 無料動画の限界が見えてきている。だからこそのリアルな触れ合いが大事。(渡辺)
    • gaccoは、登録したのに、実際に授業が始まるまでに期間が空いてしまうので、その頃にはモチベーションが落ちてしまっている(具志堅)
    • 意識高いヒエラルキーの頂点の人しかリーチ出来ない(具志堅)
    • アプリにして動画をいつでも見えるようにするとか、プッシュ通知するとか工夫しないと厳しい。いいことしてるのにもったいない。(具志堅)
    • 大抵の人はいろんなアプリを入れてて、通知がたくさん来てるので、Webサイトを見に行くという動機がどうしても二番手三番手になってしまう。(具志堅)

他にも、

  • EdTechと人工知能(5票)
  • 5年後10年後のEdTech(4票)

「【AWS 初心者向け Webinar Dec】 利用者が実施する AWS 上でのセキュリティ対策」に参加しました

12/17 に AWS Webinar があったので、聴講してみました。


aws.typepad.com

主催: アマゾン ウェブ サービス ジャパン株式会社
対象: 技術者向け
セミナー概要:
Amazon Web Services(AWS)は、お客様が資産とデータを安全に管理、運用して いくための様々なサービスや機能を提供しています。 お客様は AWS の基盤上にシステムを構築しますので、セキュリティ上の責任は 分担されることになります。基盤となるインフラストラクチャのセキュリティは AWS が確保していますが、そのインフラストラクチャにお客様が構築・接続する もののセキュリティは、お客様が保護する必要があります。 本 Webinar では AWS が提供するセキュリティに関する機能を紹介し、その典型的な 使い方やベストプラクティスについて紹介いたします。AWS 上でお客様が行う セキュリティ対策にご興味のある方は、是非ご参加ください。




いつものように、気になったことをメモ。

  • AWSのポリシーは、シェアード・レスポンシビリティ・モデル(責任共有モデル)
    • Webサイト/アプリケーションはお客様・SIでセキュリティ確保、インフラのセキュリティはAWSが提供
  • データ等は、全世界で11リージョンで配置される。AWS側からは勝手に移さない
    • それぞれのリージョンで個人情報保護のポリシーが違う
    • データセンターの場所は秘匿している(テロ・セキュリティ事故対策)
  • DDoS、中間者攻撃、IPなりすましにも対策をしている
  • AWSセキュリティセンター
  • AWSコンプライアンス
  • ネットワークセキュリティ
    • VPC内部にプライベートなサブネットを作る
    • セキュリティグループによるアクセスコントロール
    • ネットワークACLによるアクセスコントロール(サブネット単位のフィルタ)
  • 論理サクセス管理
    • IAM
      • ユーザー、グループ管理
      • セキュリティクレデンシャル(認証情報)
        • アクセスキー
        • ログイン・パスワード
        • 多要素認証(MFA)
    • AWSルートアカウントは極力使用しない
    • AWSルートアカウントやIAMユーザーアカウントにはMFAを利用する
    • 強度の高いパスワードポリシーを設定する(ただし、このポリシーはAWSルートアカウントには適用されない)
    • EC2インスタンスにはIAM Roleを利用する(クレデンシャルを静的に書かないようにする)
    • IAMベストプラクティス
  • データの保護
    • 暗号化
    • 鍵の保管、鍵の管理をAWSですることが可能
      • Key Management Service (KMS) や CloudHSM を使う
    • AWSのサーバサイド暗号化(SSE)
      • S3 だとボタン一発
  • ログ・監視
    • CloudWatch/API/SDK, Alarm
    • CloudWatch では各AWSサービスのメトリクス監視が可能
      • 各メトリクスに対してアラームを設定可能
    • CloudTrail(監査)を全リージョンで有効化することを推奨
      • まだ対応していないサービス(S3等)もある

「VIDEOTECH:元TV局プロデューサーが語る、これからのオンライン動画戦略」に参加しました

会場

東京都新宿区新宿6-27-30 新宿イーストサイドスクエア13階
NHN テコラス株式会社



 

オフラインからオンライン動画へ!Cchannelが描く未来のメディアの理想像

登壇者:三枝 孝臣氏(Cchannel)

  • 前職日本テレビ
    • Huluの立ち上げにも関わる
  • テレビは年齢層が上の人たちが見ている
  • この2年は、ファーストウィンドウがスマホ、セカンドがテレビになってきている
    • もうTVをだらだら見る時代じゃない。細切れにしよう!
  • アメリカ、テイストメイドのアプローチ
    • 食動画
    • 動画配信専門の製作会社
  • アメリカでは、オリジナルコンテンツを動画配信プラットフォームに向けて作る製作会社の動向が重要に
  • ソーシャルプラットフォームを使った新しいアプローチ
    • Now This!
    • 脱プラットフォームメディア
      • 一つのコンテンツをそれぞれのメディア向けにバラす
  • Share is all!
  • これからの動画ビジネスの主役はモバイルに!?
    • タブレットが日本で伸びないのは、通勤状況が原因ではないか??


C Channelの取り組み

  • 映像業界の課題
    • 遅い、コストがかかる
  • 高品質でスピードを早く、大量に
  • 1分動画
  • 今話題の縦動画。世界は縦動画へ
    • YouTube、Instagram も縦画面OKに
  • 動画を作ったら、テキストデータを一緒にアップできるのが C Channelアプリの特徴
  • 何がコミュニケーションを生み出すコンテンツなのかが問われる時代


秦基博のオリジナルPVとかも発信してるっぽいです。
www.cchan.tv





 

狩猟社が2015年にやった動画実験!海外でも100万再生される動画を作るまでのプロセス

登壇者:イセオサム氏(狩猟社)

  • 日本テレビでズーミンに入ってた!
  • 株式会社ハロの共同経営。bokete のスマホアプリを運営
  • バイラルメディア VIRATES を運営
  • 現在は、狩猟社とオモロキ
  • 今年は 150本の動画を作り、YouTube上で再生回数320万回
  • VIRATES✕動画で、メディアパワーを使ってスケールを狙う
    • HOW TOモノを、動画でおもしろく
    • 一瞬でTシャツをたたむ方法
    • 記事PV38,000回で再生25,000回
    • 課題は、記事と比較すると圧倒的に制作費が高い
  • 内製チーム+外注テレビマンチームで大量製作することに!
    • 内製チームは3ヶ月で100本出して実験してみた
    • 外注チームは50本制作するも、スピード感・コスト感が合わず、途中で断念
  • 動画を作った後に、どうやって事業にするか?が課題
  • バイラルにフォーカス!
  • でも、どうやって事業化するの?
  • バイラルしない理由
    • 企画が面白くないから?(インターネット的に)
    • 質が低いから?
    • プロモーションしてないから?
  • 7つのコツ
    • 1. 面白い企画を考える。「インターネット的に面白い」が大事
    • 2. シェアされる理由を考える
      • なぜシェアするのか?→人間の感情がある一線を超えたときに自分以外の誰かに言いたくなる(度を超えているもの)
    • 3. ファンとのコミュニケーション
      • どこが震源になっているか?などを調べて、手動でフォロー
    • 4. メディアともコミュニケーションする
      • 国内外ともに、魅力あるニュースとして動画を伝える
    • 5. プラットフォーム戦略を考える
      • 見せたい人はどこにいるのか?
      • ニコニコ生放送、Facebook、Youkuも利用
    • 6. トラフィック構造を考える
      • 瞬発力(バイラル)⇔じわじわ力(検索、ファン)
      • HHH戦略ベースで考える
    • 7. ローカライズする(海外を狙う場合)
      • サイト多言語化、YouTube字幕、YouTubeコメント、PF対応(中国ではYouku)
  • HHH戦略
    • コンテンツを3種類に分ける
    • Hero(バイラル), Hub(ブランドのファンに対して定期的に配信するファン向け動画), Hygiene(コアターゲット向け)= Help
      • メディア+HOW TO動画=Help
      • ファン向け動画大量生産=Hub
      • バイラル動画=Hero
  • 狩猟者の動画制作パッケージ
  • 2015年は動画元年だった?
    • 動画広告、10代向け YouTuber は認知を得た
    • コンテンツがまだ来てない?? Netflix, Hulu, ...
  • テンガマン2 12/24公開!
  • 自分の経験から、尺は短いほどよいとも限らない、というのも分かった
  • 一方でコミュニケーションのネタであれば、短ければ短い方がよい?とかはあるかも

 

オンライン動画最前線(仮)

登壇者:山田 雄介氏(メタップス)

  • グローバル ✕ 動画を科学する
  • アプリ数が急増して、レッドオーシャン化している
  • 上位ランクインしているのは、ほとんどIPタイトル
  • 上位100アプリ中、TVCMをしているものが75タイトル
  • オリジナルタイトルでは想定月商2億円、IPタイトルでは1億円でTVCMを実施する傾向
  • TVCMを打った後に、成功(売上上昇もしくはセールス上位ランキング)しているのは 6割程度??


 

パネルディスカッション

Q. 動画は何のために活用されている?

  • 映像と音とでインパクトを与えられる。表現の手法として(イセ)
  • 情報量が多いから。(三枝)
  • 使ってる人からすると、動画を撮ってみようというのがだんだん普通になってきている。(三枝)


Q. 動画の効果検証は?

  • 再生数と時間を定量的に、TwitterとかFacebookのシェアの文言を定性的に分析。バズフィード(イセ)
  • 連鎖の間に何が起こったのかは知りたい。(イセ)


Q. 再生数を伸ばすコツは?

  • サビから入る(サビ頭)。(三枝)
  • 最初の5秒で下落率がある。引っ張って引っ張ってがなかなかできない。YouTuberは固定ファンがあるからそれができる(イセ)


Q. 動画はタレントなの?クリエイティブなの?

  • タレント性がある人はやっぱり強い。(イセ)
  • 2017年くらいまでは「人」が続くかも? YouTuberも作るのは大変。(三枝)
  • クリエイティブはチーム戦。人の場合はそれができないので、いつまでもつか。クリエイティブサイドに今後は移っていくのでは。(三枝)


Q. TV動画とWeb動画の違いは?

  • 場所。後ろにいる人がぜんぜん違う。(イセ)
  • 視聴環境が違う。TVは「付いてる」という感覚で視聴されている。ながら視聴されている。邪魔にならなさ加減がTVに向いている?(三枝)
  • せっかちな人はTV見れない。(イセ)
  • 編成をされたものを見るというのが無くなる。見たいものを見る、という流れに。そうなると、不可逆的に戻ってこない。(三枝)


Q. 注目している動画関連のサービスは?

  • 人の感覚をデータ化・可視化していくサービス(イセ)
  • Now this!みたいなサービス。オマケで動画が付いてくる Amazon Primeはすごいなと思う。(三枝)
  • 動画で検索流量ができると一気にブレイクする(三枝)


Q. 今後のユーザーの方向性は?

  • 人間は面倒くさがり。テキストが面倒くさくなった人たちが写真をInstagramを使って、それが動画になってきた。


Q. 日本独自の動画産業の動向は?

  • アメリカの方が2〜3年早いと言われているが、ツボが浅い。日本はコンテキスト重視でよっぽど刺さらないと流行らない。(イセ)
  • アメリカは動画産業がハリウッド。多民族というのもある。(三枝)
  • アメリカ人は軽いノリでシェアしてくれるカルチャーがあるが、日本人は見え方を気にする。(三枝)
  • 中華圏のマーケットはこれから必ず大きくなる。(三枝)

「【AWS 初心者向け Webinar】AWSでBig Data活用」に参加しました

12/10 のランチタイムに AWS Webinar があったので、聴講してみました。


aws.typepad.com


なぜ今 Big Data なのか?なぜ AWS なのか?について、Big Data on AWS の事例と関連サービスを紹介するということでした。



いつものように、気になったことをメモ。

  • Big Dataとは?
    • サンプリングせず(異常値も含めて)全データを扱う(定義)
    • 因果関係より相関関係
    • 個にフィードバック
    • 規模が大きいから Big Data ではない
  • ダベンポートによる分析の分類
  • なぜ Big Data?
    • 属人性を排除して組織をスケール
    • 新しい発見から、ビジネスチャンスを作る
  • なぜ AWS?
    • ちょっと試してみたい。数クリックで利用開始でき、初期コスト不要
    • スケール可能
  • 事例
    • データ収集と保存
      • S3, Amazon Kinesis Stream(大量でかつ連続したデータを信頼性格納し、低レイテンシーでデータ処理に伝送が可能), DynamoDB, RDS
      • Amazon Redshift(フルマネージドのデータウェアハウスサービス。インタフェースはSQL検索)
      • Amazon Kinesis Firehose(大量ストリームデータをS3とRedshiftへ)
      • Amazon Kinesis Analytics(ただしアナウンスのみ)
      • S3 + Lamdba + SQS + EC2 でログ分析をしていたものを、Kinesis でリプレースした事例も
    • イベント処理
      • AWS Lambda(イベントをトリガーに処理を実行)
      • Amazon Kinesis Streamで受け取ったデータをLambdaで処理させる
    • データ処理
      • Amazon Elastic MapReduce(EMR)
      • S3 と連携させれば便利。HDFS(Hadoop上のオブジェクトストレージ)からS3へ。S3をDBのレコード(永続的データストア)のように扱うことができる
      • EMRだと、使いたいときだけにクラスタを起動し、その他の時間はクラスタを落としておくことができる、などの利点が
    • 保存
  • アドバンスド
    • クエリに最適化するために、カラムナーフォーマット?に変換して保存している
    • スポットインスタンスでEMRクラスタを起動すると、通常価格の半額から90%引きのコストまで削減することも
    • Workflow tools from re:Invent 2015
      • Dataduct (AWS Data Pipeline)
        • Coursera が使っている
      • Luigi
  • SQL on Big Data
    • 簡単かつ高速に全件検索可能
    • Redshift or EMR に JDBC/ODBC で接続
      • Redshift は Compute Node にデータを一旦置いておく必要がある。その後、COPY/UNLOAD
      • JDBCは、Zeppelin などを使う
  • Spark streaming でリアルタイムログ収集
    • ZeppelinとかでSQLでクエリ検索できる

PostgreSQL を Ansible Galaxy でさくっと3分でインストール

はじめに

PostgreSQL 初心者です。
最近ちらほらと PostgreSQL を使うようになったのですが、いちいち手でインストールするのは面倒なので、さっくりと自動化したいと考えていました。


そこで 前回 紹介した、Ansible Galaxy です。
ローカルに Ansible がインストールされていれば、わずか 3分で PostgreSQL をサーバにインストール することができます。


<過去記事>
akiyoko.hatenablog.jp



なお、今回利用した Role は、
https://galaxy.ansible.com/detail#/role/512
で、Ubuntuサーバに PostgreSQL をインストールするための Role です。
利用できる変数などの詳細については、こちら を参照してください。


f:id:akiyoko:20151212190455j:plain


環境

<クライアント>

  • Mac OS X 10.10.5
  • ansible 1.9.3


<サーバ>

  • Ubuntu 14.04 LTS (on Vagrant)
    • IPアドレス : 192.168.33.10

 

PostgreSQL インストール

以下のコマンドを、クライアント上(私の場合は Mac)で実行します。

$ mkdir -p ~/dev/ansible-postgresql && cd $_

### ANXS.postgresql を Ansible Galaxy からインストール
$ ansible-galaxy install ANXS.postgresql -p roles

### Inventoryファイル(hosts)を作成
$ cat << EOF > hosts
[db-servers]
192.168.33.10
EOF

### Playbookファイル(site.yml)を作成
$ cat << EOF > site.yml
- hosts: db-servers
  user: vagrant
  vars_files:
    - vars/database.yml
  roles:
    - { role: ANXS.postgresql }
EOF

### Variablesファイル(vars/database.yml)を作成
$ mkdir vars
$ cat << EOF > vars/database.yml
postgresql_databases:
  - name: myproject
postgresql_users:
  - name: myprojectuser
    pass: myprojectuserpass
postgresql_user_privileges:
  - name: myprojectuser
    db: myproject
    priv: "ALL"
EOF

### Playbookを実行
$ ansible-playbook -i hosts site.yml --sudo -k -vv


上記のサンプルでは、PostgreSQL をインストールするのに合わせて、以下のデータベースとユーザを作成しています。

項目 設定内容
データベース名 myproject
データベースユーザ myprojectuser
データベースユーザパスワード myprojectuserpass

 
なお、サーバのIPアドレスを変更したい場合は hosts、データベース名やデータベースユーザ名・パスワードを変更したい場合は vars/database.yml を適宜編集してから実行してください。




もしインストールの途中で失敗してしまう場合は、サーバから PostgreSQL を削除すれば、何度でも Playbook の実行をやり直すことができます。

$ sudo apt-get --purge -y autoremove postgresql*

<参考>
apt - Uninstall an specific version of PostgreSQL - Ask Ubuntu





上記のサンプルを、私の GitHub のリポジトリにアップしているので、それを使えば、たった数行のコマンドでインストールすることができます。要 git です。

$ mkdir -p ~/dev && cd $_
$ git clone https://github.com/akiyoko/ansible-postgresql.git
$ cd ansible-postgresql/
$ ansible-playbook -i hosts site.yml --sudo -k -vv

<参考>
github.com




 

おまけ

psql コマンドの使い方

$ psql -U postgres
or
$ sudo su postgres
$ psql
### データベース一覧(MySQL では show databases)
postgres=# \l
   Name    |  Owner   | Encoding |   Collate   |    Ctype    |     Access privileges
-----------+----------+----------+-------------+-------------+----------------------------
 myproject | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =Tc/postgres              +
           |          |          |             |             | postgres=CTc/postgres     +
           |          |          |             |             | myprojectuser=CTc/postgres
 postgres  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 |
 template0 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres               +
           |          |          |             |             | postgres=CTc/postgres
 template1 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres               +
           |          |          |             |             | postgres=CTc/postgres
(4 rows)


### ユーザ一覧(MySQLでは select * from mysql.user;)
postgres=# \du
                               List of roles
   Role name   |                   Attributes                   | Member of
---------------+------------------------------------------------+-----------
 myprojectuser |                                                | {}
 postgres      | Superuser, Create role, Create DB, Replication | {}

  or

postgres=# select * from pg_shadow;
    usename    | usesysid | usecreatedb | usesuper | usecatupd | userepl |      passwd       | valuntil | useconfig
---------------+----------+-------------+----------+-----------+---------+-------------------+----------+-----------
 postgres      |       10 | t           | t        | t         | t       |                   |          |
 myprojectuser |    16384 | f           | f        | f         | f       | myprojectuserpass |          |
(2 rows)


### データベース接続(MySQL では use myproject)
postgres=# \c myproject


### テーブル一覧(MySQL では show tables)
postgres=# \d


 

Mac で使える PostgreSQLクライアント

pgAdmin III

http://www.pgadmin.org/

brew cask install pgadmin3

動作が少しもっさりしてて、見た目もイケてないが、とりあえずこれで。
何かいいのがあれば乗り換えたい。。

Postico

https://eggerapps.at/postico/

brew cask install postico

フリーでも十分使えるが、操作感がちょっと独特かも。

PSequel

http://www.psequel.com/

brew cask install psequel

SSH Tunnel 利用時に、パスワード認証が使えなかった。。


他にもいろいろ。
https://wiki.postgresql.org/wiki/Community_Guide_to_PostgreSQL_GUI_Tools

Ansible 初心者なら、まずは Ansible Galaxy から始めてみよう

この投稿は 「Ansible Advent Calendar 2015 - Qiita」 の 6日目の記事です。

はじめに

もしあなたが Ansible 初心者で、ゆくゆくは Ansible をサーバ構築などの実戦で使ってみたいと思っているのであれば、「Ansible とは何か?」という記事から始めるのではなく、いきなり Ansible Galaxy から始めてみてはどうでしょうか?

加えて、小難しいことはいいから手っ取り早く使えるようになりたい!という人にも、Ansible Galaxy は非常に有用だと思います。


http://www.flickr.com/photos/8269775@N05/3918373246
photo by write_adam



まずはじめに、Ansible のことを少し説明すると、Ansible には、

  • ansible
  • ansible-playbook

の 2つのコマンドがあり、実戦では通常、複数のタスクをまとめて実行する仕組みを持った ansible-playbook コマンド(Ansible Playbook)が使われます。


次に、Ansible Playbook を利用するには、

  • Inventory
  • Playbook

の 2つのファイルが最低限必要です。簡単に説明すると、

Inventory は、制御するサーバ情報を INI形式で記述した設定ファイル
Playbook は、実行するタスクを YAML形式で記述したファイル

ということになります。

f:id:akiyoko:20151206111518p:plain


実行するタスクを 1つの Playbookファイルに書くと、どうしても可読性が悪くなってしまいがちなので、

  tasks:
    - include: tasks/main.yml

として別の Playbookファイルを include してファイルを分割する方法もあるのですが、Ansible のベストプラクティスとして、メインとなる実行ファイルを 1つ用意し、そこから、

  roles:
     - mysql

という形式で Role(task や handler、template などを纏めて再利用できるようにしたもの)を参照したり、

  vars_files:
    - vars/database.yml

という形式で Variables(変数の値を設定したファイル)を参照したりすることが多いです。



つまり、Ansible Playbook を効率的に使うには、

  • Inventory(ホスト情報)
  • Playbook(実行タスクを記述したメインのファイル)
  • Role(必要なだけいくつでも)
  • Variables(変数定義用のファイル)

を揃えればよいということになります。


f:id:akiyoko:20151206111528p:plain



ここで、Role の作成にはノウハウや試行錯誤が必要で、一から作ろうとすると非常に手間がかかります。実戦で使えるようになるまでには、タスクの書き方をあれこれと参考にしながら覚えていく必要がありますし、ベストプラクティスにもある程度従うことも必要でしょう。たとえ時間をかけて作り上げたとしても、すでにベストプラクティスが世の中に存在していて、車輪の再発明をしてしまったということにもなりかねません。


そこで、Ansible Galaxy の登場です!


Ansible Galaxy には、世界中の Ansible厨 *1 から寄せられた自信作の Role が GitHub のようにアップされていて、それをパクる再利用することが、なるべく手早く Ansible を実戦投入するための近道となっているのです。



Ansible Galaxy については、以下の記事が分かりやすいと思います。
<参考>
Ansible Galaxyを使ってRoleをダウンロードする | Developers.IO


Ansible公式のディレクトリ構成のベストプラクティスもあります。
Best Practices — Ansible Documentation




では実際に、Ansible Galaxy を使ってみましょう。

環境

<クライアント>

  • Mac OS X 10.10.5
  • ansible 1.9.3


<サーバ>

  • Ubuntu 14.04 LTS (on Vagrant)
    • IPアドレス : 192.168.33.10


 

今回利用した Role

今回利用したのは、
https://galaxy.ansible.com/detail#/role/509
で、Ubuntuサーバに MySQL をインストールするための Role です。

利用できる変数などの詳細については、README を参照してください。



 

1. ANXS.mysql を Ansible Galaxy からインストール

Ansible Galaxy インストールの基本コマンドは、

ansible-galaxy install <username>.<role> -p <path_to_role>

です。


Ansible Galaxy から、ANXS.mysql の role をインストールします。

$ cd ~/dev/
$ mkdir -p ansible-mysql
$ ansible-galaxy install ANXS.mysql -p ansible-mysql/roles

$ cd ansible-mysql/


 

2. 文字化け対策

Ansible Galaxy を使うという本筋からは外れてしまいますが、ここで、日本語の文字化け対策のために、my.cnf のテンプレートを修正しておきます。*2

$ vi roles/ANXS.mysql/templates/etc_mysql_my.cnf.j2

<変更前>
---
# ssl-key=/etc/mysql/server-key.pem

character_set_server = {{ mysql_character_set_server }}
collation_server = {{ mysql_collation_server }}

[mysqldump]
---

<変更後>
---
# ssl-key=/etc/mysql/server-key.pem

character-set-server = {{ mysql_character_set_server }}
collation-server = {{ mysql_collation_server }}

[mysqldump]
---

<参考>
MariaDB で日本語を扱う場合の文字コードの設定 | 雪猫ノート



 

3. Inventoryファイルを作成

INI形式でホストの情報を列挙します。今回は、サーバを 1つだけ定義しておきます。

hosts

[db-servers]
192.168.33.10

 

4. Playbookファイルを作成

メインとなる Playbookファイルを 1つ作成します。
「user:」でタスクを実行するユーザを指定し、「hosts:」で Inventory のセクション名、「roles:」で実行する Role、「vars_files:」で Variables ファイルのパスを指定してあげます。Playbook ファイルはたったこれだけで OK です。


site.yml

- hosts: db-servers
  user: vagrant
  vars_files:
    - vars/database.yml
  roles:
    - { role: ANXS.mysql }

 

5. Variablesファイルを作成

こちらの Variablesファイルは、作成しなくても構いません。
作成しなければ、ANXS.mysql で規定されているデフォルト値(こちら を参照)が使われることになります。


vars/database.yml

mysql_current_root_password: ''
mysql_root_password: rootpass
mysql_databases:
  - name: myproject
mysql_users:
  - name: myprojectuser
    pass: myprojectuserpass
    priv: "myproject.*:ALL"


例えば、上記のように変数設定を行うと、MySQLをインストールするのに合わせて、rootユーザのパスワードを「rootpass」に変更し、以下のデータベースとユーザを作成することができます。

項目 設定内容
データベース名 myproject
データベースユーザ myprojectuser
データベースユーザパスワード myprojectuserpass





ちなみに、ディレクトリ構成は以下のようになります。

ansible-mysql
├── hosts
├── roles
│   └── ANXS.mysql
│       ├── LICENSE
│       ├── README.md
│       ├── Vagrantfile
│       ├── defaults
│       │   └── main.yml
│       ├── handlers
│       │   └── main.yml
│       ├── meta
│       │   └── main.yml
│       ├── tasks
│       │   ├── configure.yml
│       │   ├── databases.yml
│       │   ├── install.yml
│       │   ├── main.yml
│       │   ├── monit.yml
│       │   ├── secure.yml
│       │   └── users.yml
│       ├── templates
│       │   ├── etc_monit_conf.d_mysql.j2
│       │   ├── etc_mysql_my.cnf.j2
│       │   └── root_dot_my.cnf.j2
│       ├── test.yml
│       ├── vagrant-inventory
│       └── vars
│           └── debian.yml
├── site.yml
└── vars
    └── database.yml


 

6. Playbook を実行

Vagrant インスタンスに SSHアクセスできるか、確認しておきます。

$ ssh vagrant@192.168.33.10


Inventoryファイルと Playbookファイルを指定して、Playbook を実行します。

$ ansible-playbook -i hosts site.yml --sudo -k -vv



ちなみに、使用したオプションには以下のような意味があります。

オプション 意味
--sudo sudo で実行
-k パスワード認証でサーバにアクセスする場合にSSHパスワードを入力できるようにする
-vv デバッグログを詳細に出す


 

7. 確認

Playbook の実行が完了したら、サーバ側で MySQL のセットアップ内容を確認します。

mysql -u root -p
mysql> show variables like 'char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

mysql> select * from mysql.user;
+--------------------------+------------------+-------------------------------------------+-------------+-------------+-------------+-------------+-------------+-----------+-------------+---------------+--------------+-----------+------------+-----------------+------------+------------+--------------+------------+-----------------------+------------------+--------------+-----------------+------------------+------------------+----------------+---------------------+--------------------+------------------+------------+--------------+------------------------+----------+------------+-------------+--------------+---------------+-------------+-----------------+----------------------+--------+-----------------------+
| Host                     | User             | Password                                  | Select_priv | Insert_priv | Update_priv | Delete_priv | Create_priv | Drop_priv | Reload_priv | Shutdown_priv | Process_priv | File_priv | Grant_priv | References_priv | Index_priv | Alter_priv | Show_db_priv | Super_priv | Create_tmp_table_priv | Lock_tables_priv | Execute_priv | Repl_slave_priv | Repl_client_priv | Create_view_priv | Show_view_priv | Create_routine_priv | Alter_routine_priv | Create_user_priv | Event_priv | Trigger_priv | Create_tablespace_priv | ssl_type | ssl_cipher | x509_issuer | x509_subject | max_questions | max_updates | max_connections | max_user_connections | plugin | authentication_string |
+--------------------------+------------------+-------------------------------------------+-------------+-------------+-------------+-------------+-------------+-----------+-------------+---------------+--------------+-----------+------------+-----------------+------------+------------+--------------+------------+-----------------------+------------------+--------------+-----------------+------------------+------------------+----------------+---------------------+--------------------+------------------+------------+--------------+------------------------+----------+------------+-------------+--------------+---------------+-------------+-----------------+----------------------+--------+-----------------------+
| localhost                | root             | *3800D13EE735ED411CBC3F23B2A2E19C63CE0BEC | Y           | Y           | Y           | Y           | Y           | Y         | Y           | Y             | Y            | Y         | Y          | Y               | Y          | Y          | Y            | Y          | Y                     | Y                | Y            | Y               | Y                | Y                | Y              | Y                   | Y                  | Y                | Y          | Y            | Y                      |          |            |             |              |             0 |           0 |               0 |                    0 |        |                       |
| vagrant-ubuntu-trusty-64 | root             | *3800D13EE735ED411CBC3F23B2A2E19C63CE0BEC | Y           | Y           | Y           | Y           | Y           | Y         | Y           | Y             | Y            | Y         | Y          | Y               | Y          | Y          | Y            | Y          | Y                     | Y                | Y            | Y               | Y                | Y                | Y              | Y                   | Y                  | Y                | Y          | Y            | Y                      |          |            |             |              |             0 |           0 |               0 |                    0 |        |                       |
| 127.0.0.1                | root             | *3800D13EE735ED411CBC3F23B2A2E19C63CE0BEC | Y           | Y           | Y           | Y           | Y           | Y         | Y           | Y             | Y            | Y         | Y          | Y               | Y          | Y          | Y            | Y          | Y                     | Y                | Y            | Y               | Y                | Y                | Y              | Y                   | Y                  | Y                | Y          | Y            | Y                      |          |            |             |              |             0 |           0 |               0 |                    0 |        |                       |
| ::1                      | root             | *3800D13EE735ED411CBC3F23B2A2E19C63CE0BEC | Y           | Y           | Y           | Y           | Y           | Y         | Y           | Y             | Y            | Y         | Y          | Y               | Y          | Y          | Y            | Y          | Y                     | Y                | Y            | Y               | Y                | Y                | Y              | Y                   | Y                  | Y                | Y          | Y            | Y                      |          |            |             |              |             0 |           0 |               0 |                    0 |        |                       |
| localhost                | debian-sys-maint | *1A50E3F67F834184F18493CB9FDC7B91D746FA38 | Y           | Y           | Y           | Y           | Y           | Y         | Y           | Y             | Y            | Y         | Y          | Y               | Y          | Y          | Y            | Y          | Y                     | Y                | Y            | Y               | Y                | Y                | Y              | Y                   | Y                  | Y                | Y          | Y            | Y                      |          |            |             |              |             0 |           0 |               0 |                    0 |        | NULL                  |
| localhost                | myprojectuser    | *B18A090DBF78EF9F2C5F71986EF462287B0C995D | N           | N           | N           | N           | N           | N         | N           | N             | N            | N         | N          | N               | N          | N          | N            | N          | N                     | N                | N            | N               | N                | N                | N              | N                   | N                  | N                | N          | N            | N                      |          |            |             |              |             0 |           0 |               0 |                    0 |        | NULL                  |
+--------------------------+------------------+-------------------------------------------+-------------+-------------+-------------+-------------+-------------+-----------+-------------+---------------+--------------+-----------+------------+-----------------+------------+------------+--------------+------------+-----------------------+------------------+--------------+-----------------+------------------+------------------+----------------+---------------------+--------------------+------------------+------------+--------------+------------------------+----------+------------+-------------+--------------+---------------+-------------+-----------------+----------------------+--------+-----------------------+
6 rows in set (0.00 sec)


バッチリです。


ちなみに、MySQL をサーバからアンインストールするには、

$ sudo apt-get --purge -y autoremove mysql*

とすれば OK です。これで、失敗しても何度もやり直せますね。

<参考>
software installation - How do I uninstall Mysql? - Ask Ubuntu



 

まとめ

一から Playbook や Role を作って育てていくのは結構大変です。
そこで、Ansible Galaxy を使って、完成度の高い Role を再利用してしまえば、あとは、Inventoryファイルとメインとなる Playbookファイルを用意し、オプションで Variablesファイルを調整すれば、すぐにでも Ansible を実戦投入できるようになります。

Ansible Galaxy の Role をサンプルにして、Playbook や Role の書き方を覚えていくというのも、Ansible 初心者の学習方法としてよいのではないかと思った次第です。


ところで、久々に Ansible の記事を書いたのですが、@r_rudi(しろう)さんのサイト
ansibleを使ってみる — そこはかとなく書くよん。
には今回も大変お世話になりました。昔から何度も読ませていただいています。
Ansible 本も出版されているようです。Ansible 初心者でしっかり基礎からやりたいという人にはピッタリな内容の本ですね。

入門Ansible

入門Ansible



明日は、yaegashi さんの 7日目の記事です。よろしくお願いします。

*1: もちろんいい意味です!

*2: バグ?なのか、このままではうまく文字化け対策ができないので、このような修正を行いました。

mp4動画ファイルのトランスコードを Python for Lambda で自動化

この投稿は 「今年もやるよ!AWS Lambda縛り Advent Calendar 2015 - Qiita」 の 3日目の記事です。


f:id:akiyoko:20151203083001j:plain

1、2、3、ラムダーーーーーーー!!


12/3 の記事ということではしゃいでしまいました。
とっとと始めます。。

はじめに

これまで、「Boto3 で Elastic Transcoder を操作する方法」「Boto3 で Amazon SNS を操作する方法」「Python for Lambda (Python Functions) の基本操作」を試してきました。

<過去記事>
akiyoko.hatenablog.jp

akiyoko.hatenablog.jp

akiyoko.hatenablog.jp





今回は、その総まとめとして、S3 への mp4ファイルのアップロードイベントを AWS Lambda で自動検知し、 Amazon Elastic Transcoder を起動して mp4ファイルを HLS形式の動画ファイルにトランスコードする、という仕組みを自動化してみます。

 

やりたいこと

S3 に mp4ファイルがアップロードされたことを AWS Lambda で検知し、Amazon Elastic Transcoder を起動して mp4ファイルを HLS形式の動画ファイルにトランスコードする



概要図を描こうかと思ったのですが、 AWSのスライドにそのままの図がありました。


 

利用手順

今回の手順の概要は、以下の通りです。


 

1. IAM で Role を作成

まずは、IAM で Lambda を実行するための Role を作成していきます。

IAM の Management Console から「Create New Role」をクリックします。
f:id:akiyoko:20151107203504p:plain


「lambda_auto_transcoder_role」という名前で Role を作成します(名前は任意)。
f:id:akiyoko:20151107203709p:plain

Role Type に、「AWS Lambda」を選択します。
ここで、「AWS Lambda」を選択しておかないと、Lambda 側の Role のプルダウンメニューにここで作成した Role が出てこなくなるので要注意です。
f:id:akiyoko:20151107204035p:plain


Managed Policy は付与せず、Inline Policy を直接付与したいので、ここでは何もせず次に進みます。
f:id:akiyoko:20151107204117p:plain

f:id:akiyoko:20151107204157p:plain


Inline Policy を付与します。
先に作成した「lambda_auto_transcoder_role」を選択します。
f:id:akiyoko:20151107204320p:plain

「Inline Policies」の「click here」をクリックします。
f:id:akiyoko:20151107204359p:plain

Custom Policy を選択します。
f:id:akiyoko:20151107204438p:plain

Inline Policy を「lambda_auto_transcoder_role_policy」という名前(任意)で、以下のように設定します。

なお、以下のポリシーは、AWS Lambda(というか CloudWatch)、S3、Amazon Elastic Transcoder、および Amazon SNS への、今回使う機能でなるべく最小限のアクセスを許可したものになります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "iam:GetRole",
                "iam:PassRole"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:Put*",
                "s3:Get*",
                "s3:*MultipartUpload*"
            ],
            "Resource": "arn:aws:s3:::*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "elastictranscoder:*"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "sns:CreateTopic",
                "sns:Publish"
            ],
            "Resource": "*"
        }
    ]
}

f:id:akiyoko:20151107204525p:plain



ここで罠(?)が。
これまでの設定だけだと、AWS Lambda から Amazon Elastic Transcoder を呼び出して実行しようとしたときに、

arn:aws:iam::xxxxxxxxxxxx:role/lambda_auto_transcoder_role either does not exist or has not granted Amazon Elastic Transcoder the sts:AssumeRole permission.

といったエラーが出てしまいます。

AWS Security Token Service(AWS STS)の AssumeRole で Amazon Elastic Transcoder を認可する必要があるということなのですが、簡単に言うと、Role の信頼ポリシーに Amazon Elastic Transcoder を追加する必要があるのです。

<参考>
IAMロール徹底理解 〜 AssumeRoleの正体 | Developers.IO


を参考に、IAM Role の [Trust Relationships] タブから、信頼ポリシーを編集していきます。


「Edit Trust Relationship」をクリックします。
f:id:akiyoko:20151107205325p:plain


以下のように「elastictranscoder.amazonaws.com」を追加します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "lambda.amazonaws.com",
          "elastictranscoder.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

f:id:akiyoko:20151107205359p:plain


最終的に、「lambda_auto_transcoder_role」はこのようになります。
f:id:akiyoko:20151107205445p:plain
f:id:akiyoko:20151107205510p:plain



 

2. S3 Bucket を用意する

Amazon Elastic Transcoder の入力バケット・出力バケットをそれぞれ用意しておきます。

入力バケット

入力バケットは「lambda-transcoder-in」とします。

Bucket Policy は以下のように設定します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::xxxxxxxxxxxx:role/lambda_auto_transcoder_role"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::lambda-transcoder-in/*"
        }
    ]
}

(AWS Account ID は、「xxxxxxxxxxxx」と表記しています。)

f:id:akiyoko:20151107205745p:plain

出力バケット

出力バケットは「lambda-transcoder-out」とします。

Bucket Policy は以下のように設定します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::xxxxxxxxxxxx:role/lambda_auto_transcoder_role"
            },
            "Action": [
                "s3:Put*",
                "s3:*MultipartUpload*"
            ],
            "Resource": "arn:aws:s3:::lambda-transcoder-out/*"
        }
    ]
}

f:id:akiyoko:20151107205813p:plain


 

3. Lambda Function を作成

Python Function を作成していきます。

f:id:akiyoko:20151107205849p:plain

Blueprint(テンプレート)は(後で Event を変更できるので)何でもよいのですが、「s3-get-object-python」を選択しておきます。
f:id:akiyoko:20151107205911p:plain

Event source を以下のように設定します。

項目 設定例
Event source type S3
Bucket lambda-transcoder-in
Event type Object Created (All)
Prefix -
Suffix mp4

f:id:akiyoko:20151107205949p:plain


Function Nameは「autoTranscoder」、Description(説明)は無しで設定します。
f:id:akiyoko:20151107210411p:plain


Role には、1. で作成した「lambda_auto_transcoder_role」を選択します。

また、実際の処理には 2200ms ほど必要なので、念のため、Advanced settingsで、Timeout を 3秒から 10秒に変更しておきます。
f:id:akiyoko:20151107210729p:plain


Python Function は以下をコピペします。

import boto3
from botocore.client import ClientError
import json
import urllib

REGION_NAME = 'ap-northeast-1'
TRANSCODER_ROLE_NAME = 'lambda_auto_transcoder_role'
PIPELINE_NAME = 'HLS Transcoder'
OUT_BUCKET_NAME = 'lambda-transcoder-out'
COMPLETE_TOPIC_NAME = 'test-complete'

print('Loading function')

s3 = boto3.resource('s3')
iam = boto3.resource('iam')
sns = boto3.resource('sns', REGION_NAME)
transcoder = boto3.client('elastictranscoder', REGION_NAME)


def lambda_handler(event, context):
    #print("Received event: " + json.dumps(event, indent=2))

    # Get ARN
    complete_topic_arn = sns.create_topic(Name=COMPLETE_TOPIC_NAME).arn
    transcoder_role_arn = iam.Role(TRANSCODER_ROLE_NAME).arn

    # Get the object from the event
    bucket = event['Records'][0]['s3']['bucket']['name']
    key = urllib.unquote_plus(event['Records'][0]['s3']['object']['key']).decode('utf8')
    print("bucket={}, key={}".format(bucket, key))
    try:
        obj = s3.Object(bucket, key)
    except Exception as e:
        print(e)
        print("Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.".format(key, bucket))
        # Publish a message
        sns.Topic(complete_topic_arn).publish(
            Subject="Error!",
            Message="Failed to get object from S3. bucket={}, key={}, {}".format(bucket, key, e),
        )
        raise e

    # Delete inactive pipelines
    pipeline_ids = [pipeline['Id'] for pipeline in transcoder.list_pipelines()['Pipelines'] if pipeline['Name'] == PIPELINE_NAME]
    for pipeline_id in pipeline_ids:
        try:
            response = transcoder.delete_pipeline(Id=pipeline_id)
            print("Delete a transcoder pipeline. pipeline_id={}".format(pipeline_id))
            print("response={}".format(response))
        except Exception as e:
            # Raise nothing
            print("Failed to delete a transcoder pipeline. pipeline_id={}".format(pipeline_id))
            print(e)

    # Create a pipeline
    try:
        response = transcoder.create_pipeline(
            Name=PIPELINE_NAME,
            InputBucket=bucket,
            OutputBucket=OUT_BUCKET_NAME,
            Role=transcoder_role_arn,
            Notifications={
                'Progressing': '',
                'Completed': complete_topic_arn,
                'Warning': '',
                'Error': ''
            },
        )
        pipeline_id = response['Pipeline']['Id']
        print("Create a transcoder pipeline. pipeline_id={}".format(pipeline_id))
        print("response={}".format(response))
    except Exception as e:
        print("Failed to create a transcoder pipeline.")
        print(e)
        # Publish a message
        sns.Topic(complete_topic_arn).publish(
            Subject="Error!",
            Message="Failed to create a transcoder pipeline. bucket={}, key={}, {}".format(bucket, key, e),
        )
        raise e

    # Create a job
    try:
        job = transcoder.create_job(
            PipelineId=pipeline_id,
            Input={
                'Key': key,
                'FrameRate': 'auto',
                'Resolution': 'auto',
                'AspectRatio': 'auto',
                'Interlaced': 'auto',
                'Container': 'auto',
            },
            Outputs=[
                {
                    'Key': 'HLS/1M/{}'.format('.'.join(key.split('.')[:-1])),
                    'PresetId': '1351620000001-200030',  # System preset: HLS 1M
                    'SegmentDuration': '10',
                },
            ],
        )
        job_id = job['Job']['Id']
        print("Create a transcoder job. job_id={}".format(job_id))
        print("job={}".format(job))
    except Exception as e:
        print("Failed to create a transcoder job. pipeline_id={}".format(pipeline_id))
        print(e)
        # Publish a message
        sns.Topic(complete_topic_arn).publish(
            Subject="Error!",
            Message="Failed to create transcoder job. pipeline_id={}, {}".format(pipeline_id, e),
        )
        raise e

    return "Success"


Pipeline は、デフォルトで合計4つまでしか保持できないので、アクティブになっていない Pipeline は事前に削除しておくことにしました。

ちなみに、以下の Boto3 の API を使用しました。



Event source に「Enable now」を選択し、「Create Function」をクリックすると、Lamdba Function の作成は完了です。
f:id:akiyoko:20151107211304p:plain

f:id:akiyoko:20151107211335p:plain



テストしてみます。
f:id:akiyoko:20151107211551p:plain

f:id:akiyoko:20151107211612p:plain


ここで少しハマりました。。
テストを実行すると、以下のようなエラーが出ることが何度かありました。

Log output
START RequestId: 66b929e2-8510-11e5-b2c3-99a74c2c1765 Version: $LATEST
An error occurred (InvalidClientTokenId) when calling the CreateTopic operation: The security token included in the request is invalid.: ClientError
Traceback (most recent call last):
  File "/var/task/lambda_function.py", line 24, in lambda_handler
    complete_topic_arn = sns.create_topic(Name=COMPLETE_TOPIC_NAME).arn
  File "/var/runtime/boto3/resources/factory.py", line 394, in do_action
    response = action(self, *args, **kwargs)
  File "/var/runtime/boto3/resources/action.py", line 77, in __call__
    response = getattr(parent.meta.client, operation_name)(**params)
  File "/var/runtime/botocore/client.py", line 310, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/var/runtime/botocore/client.py", line 395, in _make_api_call
    raise ClientError(parsed_response, operation_name)
ClientError: An error occurred (InvalidClientTokenId) when calling the CreateTopic operation: The security token included in the request is invalid.


原因は、Role の設定が AWS内に浸透していなかったということらしく、少し前に「lambda_auto_transcoder_role」という名前で IAM Role を作っていたのですが、それを削除して同じ名前で Role を作り直して Lambda Function を実行したので、このようなエラーが出たのだと推測されます。

私の場合は、5時間ほどでエラーが出なくなりました。

<参考>
InvalidClientTokenId => The security token included in the request is invalid · Issue #21 · fog/fog-aws · GitHub





 

4. 実環境で試す

S3 の入力バケットに mp4ファイルをアップロードしてみます。
f:id:akiyoko:20151107212149p:plain



しばらくすると、SNS からメールが通知が来ました。
state が「COMPLETE」になっています。

<メール>

Amazon Elastic Transcoder has finished transcoding job 1446894541726-3waslu.
{
  "state" : "COMPLETED",
  "version" : "2012-09-25",
  "jobId" : "1446894541726-3waslu",
  "pipelineId" : "1446894541305-zo2lwm",
  "input" : {
    "key" : "D0002022073_00000/sample.mp4",
    "frameRate" : "auto",
    "resolution" : "auto",
    "aspectRatio" : "auto",
    "interlaced" : "auto",
    "container" : "auto"
  },
  "outputs" : [ {
    "id" : "1",
    "presetId" : "1351620000001-200030",
    "key" : "HLS/1M/D0002022073_00000/sample",
    "segmentDuration" : 10.0,
    "status" : "Complete",
    "statusDetail" : "Some individual segment files for this output have a higher bit rate than the average bit rate of the transcoded media. Playlists including this output will record a higher bit rate than the rate specified by the preset.",
    "duration" : 40,
    "width" : 640,
    "height" : 360
  } ]
}




S3 の出力バケットにも、トランスコードされた HLSファイルが配置されています。

<S3 出力バケット>
f:id:akiyoko:20151107212410p:plain



CloudWatch にもログが出力されていました。

<CloudWatch ログ>

Loading function 
START RequestId: f09505b7-853f-11e5-9a79-e33dc551d93f Version: $LATEST 
bucket=lambda-transcoder-in, key=D0002022073_00000/sample.mp4 
Delete a transcoder pipeline. pipeline_id=1446890654281-yttx9x 
response={'ResponseMetadata': {'HTTPStatusCode': 202, 'RequestId': 'f2ff00f2-853f-11e5-8fdf-67ed42920387'}} 
Create a transcoder pipeline. pipeline_id=1446894541305-zo2lwm 
response={u'Pipeline': {u'Status': u'Active', u'ContentConfig': {u'Bucket': u'lambda-transcoder-out', u'Permissions': []}, u'Name': u'HLS Transcoder', u'ThumbnailConfig': {u'Bucket': u'lambda-transcoder-out', u'Permissions': []}, u'Notifications': {u'Completed': u'arn:aws:sns:ap-northeast-1:xxxxxxxxxxxx:test-complete', u'Warning': u'', u'Progressing': u'', u'Error': u''}, u'Role': u'arn:aws:iam::xxxxxxxxxxxx:role/lambda_auto_transcoder_role', u'InputBucket': u'lambda-transcoder-in', u'OutputBucket': u'lambda-transcoder-out', u'Id': u'1446894541305-zo2lwm', u'Arn': u'arn:aws:elastictranscoder:ap-northeast-1:xxxxxxxxxxxx:pipeline/1446894541305-zo2lwm'}, 'ResponseMetadata': {'HTTPStatusCode': 201, 'RequestId': 'f31d5e2d-853f-11e5-a4f1-c5fc4d6a4741'}} 
Create a transcoder job. job_id=1446894541726-3waslu 
job={u'Job': {u'Status': u'Submitted', u'Playlists': [], u'Outputs': [{u'Status': u'Submitted', u'PresetId': u'1351620000001-200030', u'Watermarks': [], u'SegmentDuration': u'10.0', u'Key': u'HLS/1M/D0002022073_00000/sample', u'Id': u'1'}], u'PipelineId': u'1446894541305-zo2lwm', u'Output': {u'Status': u'Submitted', u'PresetId': u'1351620000001-200030', u'Watermarks': [], u'SegmentDuration': u'10.0', u'Key': u'HLS/1M/D0002022073_00000/sample', u'Id': u'1'}, u'Timing': {u'SubmitTimeMillis': 1446894541789}, u'Input': {u'Container': u'auto', u'FrameRate': u'auto', u'Key': u'D0002022073_00000/sample.mp4', u'AspectRatio': u'auto', u'Resolution': u'auto', u'Interlaced': u'auto'}, u'Id': u'1446894541726-3waslu', u'Arn': u'arn:aws:elastictranscoder:ap-northeast-1:xxxxxxxxxxxx:job/1446894541726-3waslu'}, 'ResponseMetadata': {'HTTPStatusCode': 201, 'RequestId': 'f35f4936-853f-11e5-8c93-9d0b85e88cf1'}} 
END RequestId: f09505b7-853f-11e5-9a79-e33dc551d93f 
REPORT RequestId: f09505b7-853f-11e5-9a79-e33dc551d93f  Duration: 2188.52 ms    Billed Duration: 2200 ms Memory Size: 128 MB    Max Memory Used: 58 MB  



 

まとめ

ここまで AWS Lambda を使ってみての感想ですが、やはり IAM 絡みの設定が少しややこしいな、という印象があります(そもそも IAM に対する根本的な理解が足りていないということなのかもしれません)。それさえクリアできれば、AWS Lambda が強力な武器になることは間違いないでしょう。



明日は、crifff さんの 4日目の記事です。よろしくお願いします。