信頼はずっと、挑戦はもっと。

お問い合わせ
TEL:03-3496-3888

BLOG コアテックの社員ブログ (毎週月曜~金曜更新中)

LIST OF ARTICLES

記事一覧

  • テクログ

    【AWSでの動画配信】HLS 出力には Elastic Transcoder ではなく Elemental MediaConvert を使用するべき

    2020年4月入社の Hary です。今回は動画ライブストリーミング配信の話をさせて頂きます。要点結論だけ知りたい人はここを読めば大体分かります。HLS を使用したVOD形式の動画配信を AWS で行う場合、動画変換には Elastic Transcoder ではなく Elemental MediaConvert を使いましょう。そうしないと iOS で見た時プレイリストファイルを無限にダウンロードし続けます。背景ライブストリーミング配信 コロナの影響でリモートワークの必要性が再認識され、SE カレッジなどでも動画配信コンテンツ提供が多数派となりました。動画配信には様々な形態がありますが、ライブストリーミング配信が一般的です。ビデオオンデマンド (VOD) でもライブ中継でもほぼこれ一択と言っていいでしょう。簡単に言えば、ライブストリーミング配信は動画を時間分割したセグメントに分けて配信します。1時間の動画を1ファイルで扱えばダウンロードだけで時間がかかりますが、10秒毎に区切れば、再生に必要な直近の10秒から順にダウンロードすることでストレスなく視聴できます。これがライブストリーミング配信のキモです。 このライブストリーミング配信の主流は Apple が開発した HTTP Live Streaming (HLS) です。他にも様々な規格がありますが、デファクトスタンダードは HLS と言っていいでしょう。AWS での動画変換 Amazon Web Service (AWS) には動画変換サービスとして Elastic Transcoder と Elemental MediaConvert があります。大雑把に言えばMediaConvert の方が新しく、より多機能MediaConvert の方が基本的に値段が安いです。AWS は基本的に Mediaconvert の使用を推奨しています。Transcoder でなければできない事の方が少ないです。値段についても、一般的な動画であれば MediaConvert の値段は Transcoder の半分と思っていいです。動画の再生時間が短い(2分以下)場合、更に値段の差は開きます。詳しい比較は以下を見てください。ElasticTranscoder VS MediaConvert (Qiita)前提条件今回対象とする HLS は v3出力ファイルは以下の2種類 m3u8 ファイル:プレイリスト ts ファイル:時間分割されたセグメントHLS 変換に MediaConvert を使用するべき理由HLS の設定 EXT-X-PLAYLIST-TYPE を VOD に指定できないとライブ扱いされてプレイリストをずっと再読み込みするからです。MediaConvert が出力する m3u8 ファイルEXT-X-PLAYLIST-TYPE があります。値は VOD になっています。これにより、ビデオオンデマンド方式(プレイリストの更新はありえない)として解釈されます。#EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:3 #EXT-X-MEDIA-SEQUENCE:1 #EXT-X-PLAYLIST-TYPE:VOD #EXTINF:3, movie3-sdk-hls_00001.ts #EXTINF:3, movie3-sdk-hls_00002.ts #EXTINF:3, movie3-sdk-hls_00003.ts . . . (省略) . . . #EXTINF:3, movie3-sdk-hls_00017.ts #EXTINF:3, movie3-sdk-hls_00018.ts #EXTINF:3, movie3-sdk-hls_00019.ts #EXT-X-ENDLIST Transcoder が出力する m3u8 ファイル変換元ファイルは違いますが、同じファイルから変換しても結果は同じです。EXT-X-PLAYLIST-TYPE がありません。これにより、ライブ方式(プレイリストの更新がされる;例:ライブ中継など)として解釈されます(参考元)。#EXTM3U #EXT-X-VERSION:3 #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-ALLOW-CACHE:YES #EXT-X-TARGETDURATION:7 #EXTINF:6.064000, movie2-hls-vod-check00000.ts #EXTINF:6.000000, movie2-hls-vod-check00001.ts #EXTINF:3.000000, movie2-hls-vod-check00002.ts #EXTINF:6.000000, movie2-hls-vod-check00003.ts #EXTINF:6.000000, movie2-hls-vod-check00004.ts #EXTINF:3.000000, movie2-hls-vod-check00005.ts #EXTINF:6.000000, movie2-hls-vod-check00006.ts #EXTINF:1.266667, movie2-hls-vod-check00007.ts #EXT-X-ENDLIST この場合、プレイリストの更新を想定して HLS プレイヤーは一定間隔でプレイリストファイル(*.m3u8)をダウンロードしようとします。PC などではキャッシュが働くようで特に問題は起きませんが、 iOS の Web ブラウザで見る場合、プレイリストのダウンロードを延々と繰り返します。まとめTranscoder で変換した HLS は VOD 扱いされないMediaConvert で変換した HLS は VOD 扱いされるVOD 扱いされない HLS だとプレイリストを延々とダウンロードし続ける上の例のような小さなファイルであれば大したファイルサイズではありませんが、それが延々とダウンロードされ続ければ話は別です。そうならないためにも、VOD 方式の動画配信を行いたい場合は MediaConvert を使用しましょう。
  • テクログ

    Lambdaを試してみました

    お久しぶりです。在宅勤務になり、時間に余裕ができたのでAWSを色々試していました。今回はLambdaについて紹介したいと思います。処理の内容はS3のimagesにjpgの画像をアップすると、別のバケットにリサイズされた画像がアップされ、画像のアップロードパスと登録日時がdynamoDBに登録されます。まず、Lambda上でPillowを使えるようにするために、EC2で下記を実行しました。sudo yum -y install gcc openssl-devel bzip2-devel libffi-devel wget https://www.python.org/ftp/python/3.8.1/Python-3.8.1.tgz tar xzf Python-3.8.1.tgz cd Python-3.8.1 sudo ./configure --enable-optimizations sudo make altinstall pip3.8 install pillow -t . 上記で作成されたPILとPillow.libsとPillow-7.1.2.dist-infoとlambda_function.pyをzipで固めてアップロードします。次にLambdaのトリガーの設定ですが、S3を選択し、下記内容を入力し、追加をクリックします。バケット sample イベントタイプ すべてのオブジェクト作成イベント プレフィックス-オプション images/ サフィックス-オプション .jpg トリガーの有効化 チェック 次にdynamoDBで画像管理テーブルとautoincrementがないためidを管理するテーブルを作成します。テーブルを作成後、idsテーブルにtable_nameがs3_images、idが0を登録します。・s3_images id 主キー   数値型 upload_path 文字列型 created_at  文字列型 ・ids table_name 主キー 文字列型 id                数値型 次にS3で下記の二つのバケットを作成します。sample sample-resize 最後にlambda_function.pyは下記の内容です。import boto3 import os import sys import uuid from urllib.parse import unquote_plus from PIL import Image import PIL.Image import datetime s3_client = boto3.client('s3') dynamodb = boto3.resource('dynamodb') def resize_image(image_path, resized_path):   with Image.open(image_path) as image:     image.thumbnail(tuple(x / 2 for x in image.size))     image.save(resized_path) def get_id(table_name):   table = dynamodb.Table('ids')   data = table.update_item(     Key = {       'table_name': table_name     },     UpdateExpression = 'ADD id :id_val',     ExpressionAttributeValues = {       ':id_val': 1     },     ReturnValues = "UPDATED_NEW"   )       res = table.get_item(     Key = {       'table_name': table_name     }   )   return res['Item']['id'] def insert_dynamodb(id, upload_path):   table= dynamodb.Table('s3_images')   now = datetime.datetime.now()   table.put_item(     Item = {       'id': id,       'upload_path': upload_path,       'created_at': now.strftime("%Y-%m-%d %H:%M:%S")     }   ) def lambda_handler(event, context):   for record in event['Records']:     bucket = record['s3']['bucket']['name']     key = unquote_plus(record['s3']['object']['key'])     tmpkey = key.replace('/', '')     download_path = '/tmp/{}{}'.format(uuid.uuid4(), tmpkey)     upload_path = '/tmp/resized-{}'.format(tmpkey)     s3_client.download_file(bucket, key, download_path)     resize_image(download_path, upload_path)     s3_client.upload_file(upload_path, '{}-resized'.format(bucket), key)           id = get_id('s3_images')     insert_dynamodb(id, upload_path) これでS3のsampleバケットのimagesにjpgの画像をアップすると、sample-resizeバケットにリサイズされた画像がアップされます。Lambdaの設定は一部割愛しましたが、以上となります。
  • テクログ

    git clone 時に出た 「the remote end hung up unexpectedly」に辛勝した話

    どうも!エンジニア歴2年目に突入したわいです。連投になって申し訳ないんですけど、先日ハマった沼から抜け出すために苦悩したことを備忘録として書き留めます。ウダウダ書いていますが、結果だけ知りたい方はまとめまで読み飛ばしてください。何が起きたか開発環境を CodeCommit から git clone したときに、下記のエラーに阻まれた。(いろいろあって開発環境を消してしまった…)FATAL ERROR: Remote side unexpectedly closed network connection fatal: the remote end hung up unexpectedly fatal: early EOF fatal: index-pack failed 1行目のエラーメッセージはなぜかコロコロ変わったりした。開発環境がないので、このままだと仕事ができないとかなり焦り、先輩に相談。>どうやら、リポジトリの容量がでかすぎるらしい試しに、先輩にもcloneし直してもらうと、、成功したあわよくばと思ったが、自力で解決するしかなくなった、、正直、Git Extensions のぬるま湯に1年間浸かりつづけていたので、Git が全くわかっていない。とりあえず、ガンガン試していく作戦に出た。何を試したかこれらの記事を参考にさせていただきました。ありがとうございます。https://stackoverflow.com/questions/6842687/the-remote-end-hung-up-unexpectedly-while-git-cloninghttps://cithukyaw.wordpress.com/2014/09/08/fix-for-the-fatal-error-early-eof-on-git-clone/https://qiita.com/cacahuatl/items/4d763e98f3934e3569ca① 「http.postBuffer」の設定を変更するgit config --global http.postBuffer 524288000 >結果は変わらなかったさらに2倍にしてみるgit config --global http.postBuffer 1048576000 >結果は変わらなかった② 「core.compression」を設定するhttps://git-scm.com/docs/git-configgit config --global core.compression 0 >結果は変わらなかった>設定値を -1, 9 と変えてみたが、結果は変わらなかった③  ssh接続のタイムアウトを設定する「Remote side unexpectedly closed network connection」で検索すると、sshのタイムアウトっぽいことが出てきたので試してみた~/.ssh/configServerAliveInterval 60 ServerAliveCountMax 3 >結果は変わらなかった④  一度にcloneする量を減らす(shallow clone)git clone --depth 1 <my_repo_URI> >結果は変わらなかったいくら調べても他の解決法が出てこないので、この時点でかなり詰んだと思った⑤  有線接続に変える在宅になってから、家の Wi-Fi で仕事をしていたことに先輩の一言で気づいたclone中の「MiB/s」が2倍近く増えたが、、>結果は変わらなかった>①~④のどれも結果は変わらなかった絶望の淵に立たされていたときに、一筋の光が差し込んだ⑥  masterブランチよりも軽いブランチをcloneするgit clone -b <smaller_branch> <my_repo_URI> >結果は変わらなかった一度にcloneする量を減らす(shallow clone)git clone -b <smaller_branch> --depth 1 <my_repo_URI> >clone成功!!現在、<smaller_branch>の最新のコミットだけ取得している状態なので、<smaller_branch>の全履歴を取得git fetch --unshallow >またもや、同様のエラーコミット数を制限して少しずつ履歴を取得git fetch --depth 8 # コミット数:8は任意 >fetch成功!!残りの履歴を取得git fetch --unshallow >fetch成功!!⑦  masterブランチを含め、他のブランチ情報を取得する.git/config の<smaller_branch>を * に変更する[remote "origin"]     url = <my_repo_URI>     fetch = +refs/heads/*:refs/remotes/origin/* git fetch >fetch成功!!これですべての履歴が取得できた>やっとの思いで、開発環境が復活!!まとめ結局、必要だったコマンド。git config --global http.postBuffer 524288000 git clone -b <smaller_branch> --depth 1 <my_repo_URI> git fetch --depth 8 git fetch --unshallow .git/config[remote "origin"]     url = <my_repo_URI>     fetch = +refs/heads/*:refs/remotes/origin/* git fetch 有線接続では以上のコマンドでcloneできた。Wi-Fi の場合、最後の git fetch だけがうまくいかなかった。>いきなり、* で fetch するのではなくて、別のブランチを一度 fetch して、再度 * で fetch したらいけたうーん、Gitムズイ、、そもそも、alpineでDocker環境を作ってたら、こんなことには、、他にいい方法があれば教えてください!以上、わいでした。健闘を祈る!!
  • テクログ

    【AWS】ELBのログをS3に保存して、Athenaで検索しよう!

    こんにちは皆さんAWS使ってますか?LB、使ってます??AWSのLBもいくつか種類がありますねhttps://docs.aws.amazon.com/elasticloadbalancing/index.html弊社も大変お世話になっていますそんなこんなでLBのアクセスログをS3に保存するととてもいいことがあります。https://tech.basicinc.jp/articles/46詳しいやり方はこちらのサイト様を参考にして頂いて・・・S3に保存するとAthenaでSQLを使って検索が出来るようになるので非常に便利です。よく使うクエリはこんな感じです。○該当IPがアクセスしているURLを検索するselect  request_ip, url from  ELBログの保存先 where  elb_name = ‘たくさんあると絞ってあげたほうがわかりやすいです’   AND  (regexp_like(request_ip, ‘111.111.111.111’)) limit 1000; こんな感じで○該当URLにアクセスしているIPを割り出す○該当URLにアクセスしているIPのカウント数○該当日時にアクセスしてきたIPやURLを割り出すなどが検索可能です。更に応用としてはUAでGoogleBotがクローリングしているURLを割り出したり(もちろんUAは偽装できてしまうので正確とは言えないですが・・・参考までに)日毎のGoogleBotの件数を見てみたり(↓)SELECT substr(request_timestamp,      1,     10) AS ymd,      count(*) AS cnt FROM ELBログの保存先 WHERE elb_name = ‘たくさんあると絞ってあげたほうがわかりやすいです’     AND user_agent LIKE '%Googlebot%' GROUP BY substr(request_timestamp, 1,10) ORDER BY ymd; あとはprocessing_time(何種類かあります)でorder by descすれば処理が重いページもわかったりします。便利ですね!!皆さんもELBのログをS3に保存して素晴らしいAthenaライフをお送りください!!
  • テクログ

    AWS CLI等でEC2に紐づいているパブリックIPアドレスがEIPか否かを見分ける

    नमस्ते! आप कैसे(कैसी) हैं?ナマステー!こんにちは。インフラ担当のまつやです。前日までに新たに起動したEC2があり、それが監視が必要なものであるならば自動でZabbixに登録するスクリプトを毎日動かしています。aws cli等でインスタンスの情報を取得して以下の情報を抜き出します。Reservations[].Instances[].NetworkInterfaces[].Association[].PublicIp これでパブリックIPの付与されたインスタンスをピックアップし、別条件でZabbixのホストに登録するか否かを判定し、Zabbixに登録がなければ登録しています。しかし最近、自動でZabbixにホスト登録されたはずのEC2が見つからないという事象が発生しました。上記で抜き出したパブリックIPが見つからない・・・どのEC2にも紐づいていないし、EIPを検索しても見つかりません。色々調べた結果、どうやらAuto ScalingグループのEC2インスタンスがスケールアウトしてローンチする際、予約しておいたEIPに紐づけされる前に、動的に割り当てられるパブリックIPアドレスを検知してZabbixのホストとして登録してしまっていることが分かりました。その後予約してあったEIPが紐づけられたために、一時的に割り当てられていたパブリックIPは解放されたのでどこを探しても見つからないわけです。ということは、動的に割り当てられるパブリックIPと、EIPを区別することができればZabbixに登録するか否かを判定することができそうです。aws ec2 describe-instancesでインスタンスリストを取得して探していると、それらしいものがありました。Reservations[].Instances[].NetworkInterfaces[].Association[].IpOwnerId {   "Reservations": [     {       "Groups": [],       "Instances": [         {    中略               "NetworkInterfaces": [                          {                                 "Association": {                                        "IpOwnerId": "XXXXXXXXXXXX",                                        "PublicDnsName": "ec2-XXX-XXX-XX-XXXX.ap-northeast-1.compute.amazonaws.com",                                        "PublicIp": "XXX.XXX.XXX.XXX"                                 }, IPの所有者のIDですね。この値がAWSアカウントのIDになっていればEIP,amazonになっていれば動的に割り当てられるパブリックIPということになります。これによって、IpOwnerIdがamazonである場合はZabbixホストに登録しないという処理をスクリプトに入れることができました。それではまた!फिर मिलेंगे!
  • テクログ

    Cloudwatch eventsでcronを使って 日か、曜日を指定するとき

    ひなっちです。Cloudwatch eventsでcronなんですが、地味に忘れて、ハマるんです。なぜか?普段、Linuxのcronタブに書いてる書き方とすこしちがうからです。Parameter ScheduleExpression is not valid. ↑これcron的には書き方正しいはずなのになーと今回、自分が少しはまったのが毎週金曜日、10時(JST)で処理を動かす場合でした。これを、そのまま素直にcronで書くと0 1 * * FRI * こうです。が、正解は0 1 ? * FRI * こうです。これ、ちゃんとマニュアルにも書いてあるんです。cron 式の日フィールドと曜日フィールドを同時に指定することはできません。一方のフィールドに値 (または *) を指定する場合、もう一方のフィールドで ? (疑問符) を使用する必要があります。https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/events/ScheduledEvents.html#CronExpressionsほんと地味ーーーにはまるし、普段cronタブに慣れ親しんでいるとマニュアル読むほどのものじゃない気もして、辿りつくまでに時間がかかりました。。。。では!