Rのつく財団入り口

ITエンジニア関連の様々な話題を書いているはずのブログです。

【AWS】オンラインでハッカソンイベントに参加して実績解除してきました

ハッカソン

 しばらく前に会社で社内のハッカソンイベントに参加してきました。ほとんど遊びもとい、普段の業務とは一味違う空気を味わえた貴重な経験だったので、記録に残しておこうと思います。

f:id:iwasiman:20210312191004p:plain
ハッカソン (写真はイメージですw)

ハッカソンとは?

 ググるといろいろ出てきますが、語源がハック(hack)ラソン(marathon)ハッカソン(hackathon)だというのは実は最近知りました。ソンはsonじゃなくてthonなんですね。

ja.wikipedia.org

参加の経緯

 へーしゃでも資格取得を奨励したり各種教育や社内の認定制度などなど、人材育成は色々やっています。高度なエンジニアリングの領域でクラウドも分かるスペシャリスト……的な認定の候補者に僕も以前からなっていました。2019年からAWS認定突破作戦をやっていたのはこのためです。
 認定突破に必要な資格としてAWS認定が1つ必要なところは余裕で3つ合格済み。あとは実際のプロジェクトで実践すれば……というところでなかなか機会がなくて止まっていたのですが、そこで参加すればプロジェクト実践と同じ扱いになるこの社内ハッカソンが開催されることに。
 これぞ千載一遇の好機ということで、掛け持ちでいろいろやってる他の仕事を調整しながらジョインすることにしました。

 参加資格は特になくて社内なら誰でも可、2人以上のチーム必須、AWSを用いて好きなテーマで開催2日間の中で何かを作り、最後に発表というものです。以前は物理で集まってやっていたのですが、2021年の今回はオンラインで開催されました。

やったこと(前日編)

 こうしたイベントに自発的に参加するような人ならスキルやモチベーションもまず問題ないので、広い社内で知らない人とやる……というのも楽しそうではあるのですが、すべてがオンラインなこのコロナのご時世。初めて会う人だとコミュニケーションコスト掛かりそうだよなあということで、幸い同じ部署の同僚を誘えたので僕がリーダーの2人チームで参加しました。
 新人ならともかく、両名とも掛け持ちでいろいろ仕事を抱えている関係で当日割り込みが起こらないとも限りません(というか案の定あったw)。またAWSの実務経験が圧倒的に不足しているので余裕を持っておく必要も感じました。仕事の合間にできる限り準備は事前にやっておくようにしました。

  • 部内で試験的に動かしているシステムのWeb部分をAWSのサーバーレス構成に移行してみるというアイデアは僕の中にあったので、テーマはこれで確定。
  • 事前に作戦会議をして分担決め。もう一人のメンバーは仕事のウェイトが大きい状況だったので分量は僕が多めに。
  • 各サービスごとにやることを整理、できることは事前にやったり手順を確認したり。エスアイヤ~伝統の必殺のExcelでまとめていました(笑
  • 社内のTeamsのチャネルでハッカソン情報が流れて人が集まってくるので定期的に注視、いいね!をどんどんつけて気持ちを高めたり。
  • 定常的に続けている技術書の読書で、勝手にサーバーレス強化月間を開始!

 読書では昨年末から少しづつ読んでいたかなり分厚い『マイクロサービスパターン』をやっと読了したところでした。マイクロサービスやクラウド、サーバーレスの文脈がある程度分かってきた(気がする)ので、次はサーバーレスに注目。
 『AWS Lambda実践ガイド』『Amazon Web Servicesを使ったサーバーレスアプリケーション開発ガイド』『AWSによるサーバーレスアーキテクチャ』の3冊を読みました。これから実際に自分が行う作業と本のここが繋がっている……という意識があって読むと、理解度がより深まります。
 前からサーバーレス関係は深掘りしようと思っていたのでちょうど良かったです。PythonでLambda完全に理解した……という気持ちに自分をもっていきました。(※フラグ)

 既に一部上げていますが、これらの本は読書記録&感想のエントリも順次このブログに上げていきまする。

iwasiman.hatenablog.com

iwasiman.hatenablog.com

やったこと(当日編)

コミュニケーション手段

 各チームはZoomのブレイクアウトルームで部屋を用意してそこでやりとり。事務局の人が時々覗きに来たり。実況などはTeamsのチャネルへの投稿という形でした。ハッカソンで初めて顔合わせという剛の者のチームもあれば2日間の期間中でサービスのアイデア出しから始めるチームもあり。オンラインでホワイトボードで相談したり、Cloud9を使ってモブプログラミングをするチームもあり様々です。
 僕のとこはやることは決まっているのでブレイクアウトルームはほぼ空、必要な時はTeamsのチャットでやりとりしながらもくもく作業、というスタイルでした。

 作ったのはアーキテクチャ的には S3静的ホスティング -> API Gateway -> Lambda -> DynamoDB でいろいろやるというサーバーレスの基本構成です。個々の動作を確認して学びにするために、AWS SAMSeverless Frameworkは使わずにやりました。
 やったことはごく普通なんですが、けっこうハマったので作業ログから失敗経験含めメモしておきます。

S3static site hosting

 作るアプリの移行元はサーバーサイドメインのWebアプリケーションだったので、HTTPレスポンスの部分を抜き出して静的HTML+JavaScriptのVue.jsで動く状態のフロントエンドのリソースのブツ一式を作っておきました。

  • パブリックアクセスのブロックはオフに。
  • フォルダに移動して諸々を > aws s3 sync . s3://{バケット名}
    で一気にアップ。AWS CLIでやるこれは便利ですね。
  • こんな簡単にホスティングできちゃうのか……! と密かに感動してブラウザからアクセスしたら Access Denied 403。本や紹介記事によく出てくるバケットポリシー設定で s3:GetObject を許可するのを忘れてました。
  • 後からCORS設定が必要なのを思い出してバケットのアクセス許可を変えたり。
  • 他にも、設定が正しいのにブラウザから見えない→よーく見たら長いバケット名自体が1文字typoしてた、などのアホなミスを経ています。
API GatewayAPI新規作成

 こちらも理屈は分かっているんですが、初見だと管理コンソールのUIがけっこう独特で最初は戸惑いました。

  • こんな簡単にAPI作れちゃうのか……!と初心者な感想を持ちながらとりあえずブラウザからURLを叩いたら {"message":"Forbidden"} 。まあそりゃそうか。
  • OSにMacを使った作業例でよくcurlコマンドを叩いて動作を確認していますが、WindowsもWindows10からは最初からcurl.exeが入っているんですね。
  • さっそく叩いてみると今度は 403 Forbidden。レスポンスを覗いてみると
    x-amzn-ErrorType: ForbiddenException。レスポンスヘッダ内はamazonじゃなくてamznなのか……!とか地味に感動したり。
  • 試していくと「無効な API キー識別子が指定されました」で、APIキーの設定が必要でした。そりゃそうか。
  • 管理コンソールでAPIキーを新規作成して乱数が生成。
  • リソースでAPIをデプロイすると反映されると分かったけどデプロイできない……
  • →まずはステージを新規作成してステージと紐付てからデプロイでした。
  • こうして出来たつもりでURLを叩くと {"message":"Missing Authentication Token"} で認証トークンが効いていない。あり?
  • →まずはなんでもいいから「使用量プラン」を作ってAPIキーをこれに追加してからデプロイでした。
  • サンプル通りダミーの値を返すリソースを作るとcurlで叩いたらレスポンスが Go Ahead。よし前進した……!
  • その後Web画面のJavaScriptを通してアクセスすると今度は CORS(Cross Origin Resource Sharing) でエラー。これもよく出てくるやつで、API Gatewayのリソースを選択してからメニューの[アクション] - [CORSの有効化]で適用されてくのが正解でした。
Lambda FunctionPythonでロジックを書く

 Lamba開発時の言語で一番シェアがあるのはPython、ネット上のリソースや書籍でもPythonが一番多いので、言語はPythonに事前確定。移行前の素のアプリケーションではサーバーサイドJavaで動いていたロジックをPythonで書き直し、動く(はず)のコードを事前にある程度準備し、管理コンソールに貼りつけてデプロイする方式でやっていきました。

  • API Gatewayと連動して作れるので、一緒に作ってみたらAPIのリソース名が getSomeList みたいに動詞スタートのイケてない形になってしまい試行錯誤したり。
  • getSomeList?param1=xx&param2=yy みたいにしてテストしたらちゃんと200が返ってきてOK。
  • しかしAPI Gatewayを介したアクセスでコマンドラインからcurl.exeで叩くと 502 BadGatewayamzn-ErrorType: InternalServerErrorException 。なんでサーバー側の内部エラー……?
  • ここもしばらくハマッたのですが、コマンドをたまたまPowerShellコンソールから打っていたためでした。URLに含まれる&があると認識してしまうようです。URLを""で囲って以下のように叩くのが正解でした。PowerShellはほんと独特な所が多い……

> curl.exe "https://{APIのID}.execute-api.{リージョン}.amazonaws.com/dev/{リソース}?param1=xx&param2=yy" --header "x-api-key: {APIキー}" -i

  • こうしてダミーが動くはずになってWeb画面→API Gateway→Lambdaと繋げると、対応したはずのCORSでエラー。
  • Chromeの開発者ツールで見ると、Lambda関数のPython内の戻り値で定義しているはずの Access-Control-Allow-Origin がレスポンスヘッダに入っていません。なんぞ……?
  • curlから叩いても同じでレスポンスに x-amzn-ErrorType: InternalServerErrorException でまたも内部エラー。Lambda関数実行時に吐き出されるログをよくよく見ると……
  • Pythonコードの最初の方の凡ミスでコケてそこでエラー終了していました。(アホ) HTTPレスポンス生成まで処理が進んでいないので、Access-Control-Allow-Originが作られないままAPI Gatewayに戻っていたわけですね。

 そんなこんなでダミーの関数作りにしばらく試行錯誤した後、本物の関数を作ろうとしたわけですが……

  • なんかあっという間に終わってしまう→タイムアウトが3秒のままだったので最長の15分に。
  • 管理コンソールでテスト用イベントを作って流すとちゃんと動かない→ハンドラの引数の event の中身は本物と同じように作らないと動かない。例えばURLパラメーターに値が渡ってくる前提なら……
{
    "queryStringParameters": {
        "param1": "xx",
        "param2": "yy"
    }
}
  • 今度は関数に実行権限がない→忘れてたので LambdaFullAccessAmazonDynamoDBFullAccess の権限のあるロールをアタッチ。
DynamoDB からデータ取得

 元のアプリではRDBに収めていたレコードを元にダミーデータを作り、アイテムとしてDynamoDBに保存しておきました。ここからLambdaを通してデータを取得したりして、RDBを使った版とまったく同じ機能を実現できるようにしていきます。
 さてRDB全般に比べると検索周りが弱いと言われるNoSQL。テーブル設計が重要という点は我々も認識しており(キリッ)、求めるqueryが実現できるようにインデックスを貼って準備万端のはずだったのですが……

  • Pythonコードから動かない!?→今回のケースではqueryの実行時に引数で IndexName='sample-index' のようにインデックス名の指定も必要だった。
  • 動いた……が、Web画面から検索して見ると項目(DynamoDB的には属性)が全然足りていない!→インデックスは単に作るとquery実行時、パーティションキーとその属性しか取れない。この時はテーブルの全属性を指定したインデックスを再度作って解決。

もしかしてDynamoDBの仕様だと今回やりたい要件が実現できない……!?と一瞬焦ったりしましたが解決。うーんエンタープライズな開発に従事しているとまだまだ頭がRDBだなあと思ったり。
我々はオンプレの重力に魂を縛られている……早くクラウドとサーバーレスの無重力の世界に羽ばたきニュータイプとして覚醒しなくては……

 そして全部サービス群が繋がる本番のものを作り直したのですが、ここでまた問題発生。

  • curl.exe "https://{新しいAPIのID}.execute-api.{リージョン}.amazonaws.com/dev/{リソース}?param1=xx&param2=yy" --header "x-api-key: {APIキー}" -i で正しい指定で叩いても、MissingAuthenticationTokenExceptionが発生してしまう。設定は再確認するとみな正しいように見える。
  • あれこれ試すと、URLが https://{新しいAPIのID}.execute-api.{リージョン}.amazonaws.com/dev?param1=xx&param2=yy だとなぜか正常に動く。なんぞ????
  • APIを新しく作り直した時、リソース"/"のみでそもそも目的のリソースを作り忘れていた……(アホ)

などのマチガイを経てようやく動くようになりました。うーんAPI Gatewayに向けてHTTPリクエストを送るURLが間違っている時も MissingAuthenticationTokenException が起こったりするんですねえ。
ググった時に見たQiitaの記事でAWSが返してくるエラーの種類は実際と違う時がある」というような話があったのですが、確かにそうでした。AWSからしたら機械的に正しい反応をしているだけでも、開発者から見るとそう見えないケースがある訳ですね。

 まあでもプログラム言語や技術を問わず、こういう失敗経験は身に刻まれて記憶にも残って学びになります。こうやって試行錯誤したりググりながら少しづつ進んでいくのがけっこう楽しいというのもありますが、あれこれ試す機会があってよかったです。

最後にプレゼン会!

準備

 2日目の最後にはZoomウェビナーを使い、各チーム3分で成果を発表する発表会があります。
僕のチームは同僚メンバーは他の予定が割り込んでしまったので僕が単独でプレゼン。正攻法でPowerPoint資料と実際の動くWeb画面と喋りでいきました。
 資料は事前にある程度作っておきました。社内のテンプレートを使うと色遣いが地味であまり好きでないので、今回は仕事と関係ないイベントなので色調を明るめに。AmazonのロゴのAmazon Orangeと言われるオレンジ色(カラーコード#FF9900)を多めに使ってフォントも大きく、インパクト重視にしました。

https://amazon-press.jp/dam/jcr:0e4e9bd6-61e8-42dd-a60b-d16606a5bf3a/Amazon%20Logo_Brand%20Guidelines.pdf

www.appsious.com

公式アイコンセットを使って構成図も書いたのですが、ちゃんとやるとAWSっぽさが高まって見栄えも良くなって気分が高まりますね。AWSの英文資料はフォントがArialと決まっているのもここでへえーとなりました。

aws.amazon.com

 比較的予定通り事が運んで余った時間は、ひたすら3分間プレゼンの練習をしていました(笑

発表

 各チームのどのサービスが良かったかも、このオンラインの成果発表会に参加した人がその場で投票した結果を集計して決めます。このウェビナーに参加したのが確か100名ぐらい、成果発表会は録画して後日社内に配信。全国合計社員数ウン桁の弊社、おっよく考えたらワイもオンラインイベントでの発表は初めてだぞ……?

  • さすがにいくらか緊張します。ディスプレイの前で手が震えるなど。(物理出社してる時はこういうことないんだけどなあ)
  • でも他のチームの発表にチャット実況カキコをする余裕はあった。
  • 10回以上練習しているので自分のチームの分は予定通り滞りなく終了。司会からのひとことフィードバックのコーナーで、おまけのメンバー紹介にも反応があったりして良かったです。
  • 終わった後はもうこっちのもんだぜ~と他のチームの発表を楽しんだり実況カキコをしたり。他の人もゆるい感じで気軽に実況をしています。おっこの雰囲気、社外の勉強会のTwitter実況のノリとほぼ同じじゃないか……!と気づく。
  • 自分のポジティブコメントが相手に喜ばれるのが嬉しい。エラい人に遠慮したりのないフラットな空気が楽しい。ゆるい雰囲気でネタに反応しあったりするのが楽しい。
    誰も否定せずみな相手を尊重する気持ちを持っているのが楽しい。みな楽しんで好きなものをワイワイ作って発表しているのが楽しい。
    そうだよこの雰囲気だよ!お堅い弊社が変革を進めてこれからの時代に生き残ってやっていくにはこのエモさがいるんだよ!と思う。

  • 10チーム以上あるとプレゼン手法も様々でバラエティに富んでいます。一発ネタで勝負したり最後まで劇になっていたり新サービスのCM風になっていたり、人間は喋らずAWSが喋ったり。こういうところも面白い。

  • 作ったものもバラエティ豊かです。LINEと連携したりチャット形式で応答してきたりゲーム形式になっていたり構想は大きく今回はモックまでだったり。翻訳や音声読み上げ、果ては深層学習など先進的なサービスを使ったチームもあり、刺激をビンビンに受けます。2日間だと入り口止まりのサービスもありますが、おおおここまでできちゃうのか……!と感動します。
  • うち含め資料に構成図を載せているチームも幾つかありましたが、EC2は見当たらずほぼサーバーレス構成でサービス間をLambdaで繋げる形が多かったです。やはり短い時間で少人数で圧倒的に開発していくにはサーバーレスなのだなあと。
  • 役職が上の人からの談話もあったりするのですが、アジャイルウォーターフォールの違いやゴールデンサークル、少数精鋭高速でのサービス開発へのマインド転換、サービスの本質……などなど普段とは一味違う話が聴けて、あーやっぱりこういうイベントに集まってくる人たちは分かってるんだなと思いました。

 投票はサービスの独創性などを観点にしているので、移行という堅実なテーマでやったうちのチームは入賞を逃したのですが、まあここは予想通り。サーバーレスというテクノロジーを使って考えていたものを予定通り完成させられたのでよしとしましょう。

終わりに

 最後はZoomで参加者一同が集まった所を約束の記念写真に収めたりしながら、ハッカソンイベントは終わりました。いやはや普段と一味違うイベントで楽しかった。社外の勉強会イベントに行った時のあの刺激と空気に似たモノを久々にバーチャルで受け取りました。

 社外の勉強会イベントと同じような空気を分かち合える人たちが広い社内にもちゃんといる...というのを頭では知っていたけど今回改めて実際に見て分かったのが嬉しいですね。
社員数ウン桁、グループ全社だとさらに+1桁の弊社もここ数年で急速に変化を進めて未来に適合していこうとしていますが、こういうのはどんどんやって欲しいですね。次はうちの部門の若手にもけしかけてもとい参加を勧めてみよう。

f:id:iwasiman:20210312191004p:plain
ハッカソン (写真はイメージですw)

実績解除したぞい

 こうしてサーバーレスで実際に動くアプリケーションを作る実績解除。そしてもうひとつ...厳密には仕事じゃないけど仕事でPythonを使うという実績を解除することができました。(今更か!)
 機械学習ブームで勢いに乗った2017年、このブログを再起動した頃に基礎は学んだので、いったい何年掛かりだって感じですね……w
 とゆことで、Twitterのプロフィールで技術ワードを並べてドヤっているところにこっそりPythonを追加して満足するのでした。まる。
 そういえば最近フォロワーが1700人を突破しました。皆様ありがとうございます!

twitter.com