# Fargate OneDay # 基本情報 ## 日時場所 日付:2019/12/27 12:00-18:30 場所:樋渡パレス@石神井公園 講師:樋渡俊介大先生 塾生:梅澤 ## 道具箱 - [リポジトリ(BitBucket)](https://bitbucket.org/serverlesslab/sgg/src/develop/) (そもそも明細項目とかのっけちゃってるけど、こーいうのリポジトリにのっけて公開していいのかな?) ### 作業EC2 - IP:3.114.133.159 - 秘密鍵:oneday.pem - user:oneday - ソースの在処:/home/ec2-user/ # 当日の工程 ## 全体像 3ステップでクラウドネイティブ(サーバーレス)なしくみへとブラッシュアップしていく。今は梅澤がアブダクションできる範囲でやらないとならなそうな事柄を列挙している。 ![](https://i.imgur.com/ykTjM4G.jpg) 1. EC2上で動くアプリケーションをDocker化する。参考資料[Docker上のCentOSにPython3と、関連ライブラリpip, virtualenvとフレームワークDjango, bottle, Flaskのインストール!これらをまとめたDockerfile付き!](https://qiita.com/RyosukeKamei/items/eca9687162b7fe122094) - [EC2にDockerインストール](https://qiita.com/ymasaoka/items/b6c3ffea060bcd237478) - [Container-Selinuxインスコ](https://qiita.com/fake-deli-ca/items/cf098cf35d0bfa0185ed) - [その2](https://qiita.com/nohhoso/items/28f76604a637791c9deb) - [アプリケーションをDocker化](https://qiita.com/yumatsud/items/33bc22f7d8f640a286f4) - 【アドバンス】アプリイメージをDockerHubにアップ - Q.EC2 or Dockerコンテナを選択するときの基準って、どんなメリデメに着目すればいいの? - - A.個人的な意見としては基本的にコンテナにすべきだと思う。 InfraAdCodeのメリットは大きい。 参考: 2つの条件を満たせばコンテナにすべきという意見もある。下記参照。 https://dev.classmethod.jp/cloud/aws/cmdevio2019-container/ 2. DockerコンテナをFargateに搭載する - Fargate操作方法把握 - Fargateインスタンス作成 - 起動停止自動化処理作成(後述)▶梅澤案の妥当性チェックも - Q.現在の梅澤の実装形態だと、オートスケーリングしたときにスケールメリットは得られる?(=多くの人がこのサービスに大量アクセスした場合オートスケーリングで対応できるのか) - ▶︎今回は1プロセス=1コンテナ=1処理に対応させる方法と、一つの大きなコンテナに複数のアクセスを同時に集中させる方法の二つがある。前者がおすすめ。わかりやすいし。後者はプログラム内で並列処理する必要がある。オートスケーリングするならば、FlaskのようなライブラリでWebAPIを待ち構えておく必要がある。振り分けが必要だからね。 3. CloudFormation化して、全体をコマンド一発で作成できるようにする。 - Q.リソースが作られていく順番ってどう指定するの? - - A.yamlを分割するか否かで変わる **分割しない場合:** 基本的に考慮する必要はない。AWSのポリシーに則って自動判断される。 例えば、VPCは必ずEC2より先に構築される。 ただし明示的に依存関係を指定することも可能。 **分割する場合(分からないので調べた):** 各yamlの依存関係を明示的に指定する必要がある。 yamlの中の依存関係は分割しない場合の通り。 - Q.yamlファイルはどういう単位で分割したほうがいい? - - A.公式ベストプラクティスでは、ライフサイクルと所有権を考慮しろとのこと(分からないので調べた) **ライフサイクル:** 変更or削除タイミングが同一のリソースを一つのyamlにまとめる これによってオペミスやコンフリクトで誤った変更や削除を避ける **所有権:** 「誰がそのリソースの変更を担当するのか?」、すなわち変更担当チーム単位で分割する これによって他チームのリソースに影響を与えることを防ぐ **今回でいうと:前提をどう置くかで変わる** ライフサイクル・所有者が同一⇒一つのyamlでいい VPCは他システムでも使う(ライフサイクルが違う)⇒VPCとそれ以外でyamlを分ける などなど・・・ - [公式CloudFormationパラメータ【Lambda】](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html) 4. 【すげぇ余裕があったら】CodeCommitと連携させて、CI/CDが回る体制を組む - Q.稼働中のFargateコンテナに自動デプロイをした場合サービスは止まるの?内部的にどのような処理をするの? - ▶︎止まらない。ALBをFargateにつけておくことで回避できる。自動デプロイが走ったときに以下の手順に従って切り替えが起きる。 1.新コンテナ作成 2.ALBが新コンテナをヘルスチェックする。 3.ヘルスチェックOKだったらユーザーからの通信情報を待機させる 4.新コンテナに切り替え 5.ユーザーの信号を流すのを再開する。 ## 起動停止自動化処理フロー図 ![](https://i.imgur.com/5t5GFpt.jpg) Q.Fargateでメイン処理部分を作成した場合、以下のようなフローでも制御部分は作成可能? 1. S3に新規ファイル到着をキャッチ 2. イベント発動。SNS経由でLambdaがキックされ、当該ファイル名が引数で渡される。 3. Fargateを起動 ※この「起動」でCMDが発動するならば、ファイル名を引数として渡してキックすれば、コンテナ作成->本処理->コンテナ消滅まで全て自動で終わる? ▶︎この理解であっている。CMDでプロセスが動くとき、そのプロセスが死んだらコンテナも死ぬ。Djangoを走らせる場合はプロセス自体はずっと行きている性質のものなのでコンテナも半永久的に行きている。 ## その他質問 ### Q.コンテナを使ったサービスの開発はどんな順序でやるべき? 今回のOneDayでは、もともとEC2上で環境構築もアプリ開発も完了しているサービスをDocker移行するという形で開発を行っている。 これは完成形を先に作ってから、Dockerナイズする順序である。 最初からコンテナで本番稼働させることが決定しているサービスは、Dockerで最初から作り込むのがよいのか、それともEC2上で作ってからDocker移行したほうがいいのか。もし最初から作り込むなら具体的にどのように作っていくのか. ▶︎最初からドッカーの中で作業したほうがいい。コンテナの中で作業しながら、手順はメモしつつDockerfileに移していく。慣れるとこっちのほうが試行錯誤がしやすくスピードも早い。 # 事前準備 以下は梅澤向けメモ。 ## 作業編 - [x] EC2ベースでメイン機能(=S3に給与明細と賞与明細を入れて、テーブルが作成される)開発完了 - [x] 今回のOneDay用にアクセス用ユーザーをEC2に新規作成。秘密鍵を当日USBメモリ等で渡す。 - [x] 樋渡さん用AWSユーザー作成。 - [x] Note初記事投稿 ## 持ち物編 - [ ] Mac - [x] 電源アダプタ - [x] アダプタ用ケーブル - [x] USB to iPhoneケーブル - [x] プロジェクタ用D-Subコネクタ - [x] iPad - [x] iPad用充電器 - [x] USBメモリ - [x] おいしいお菓子 - [ ] 飲料 # 当日の記録 ## rpm ``` rpm -qa ``` - rpm=パッケージ管理マネージャ。 - -qa=このマシンに入っているパッケージ一覧を出す。 - yum はインターネットからダウンロードする部分、rpmはローカル内の整備をする部分 ``` /etc/yum.repo.d/ ``` ここに、yumで取ってくるダウンロード先の設定ファイルがある。 Ec2の場合は、AWSが用意しているサーバーがさし先になっている。 そこにはrpmが置いてある。 rpmにはパッケージ本体とインストーラが両方入っている。 これをyumでダウンロードしてくる。 ちなみにこれら設定ファイルはただのテキストファイルだが、「リポジトリ」という名前がついている。 ## Docker基本文法講座 CMDとEXPOSEは性質が異なるコマンド。 ### コマンド編 #### FROM 誰かのDockerイメージをpullするためのもの #### ENV 環境変数を設定する #### RUN コマンド実行 Dockerイメージを作るために打つコマンド。 ちなみに、RUNは一つのDOckerファイルに一つだけの方がいい。 データ量が少なく済むから。 ただし、分けると可読性が上がるから、書き分けの程度はある程度のお好みで。 #### WORKDIR cdコマンドのこと #### ADD Dockerfileと同一階層にあるファイルを、DockerImageの中にコピーするためのコマンド #### EXPOSE ポートを開けるためのコマンド。 #### CMD コマンド実行 作られたDockerイメージ内で起動するコマンドを打つ。 ### Dockerそのもの編 ![](https://i.imgur.com/fUofSvf.jpg) - ADDやRUNなどのグループは、DockerファイルからDockerイメージを作成するためのもの。 - DockerImageはバイナリファイル - DockerImageをdocker runコマンドで叩くと、コンテナが出来上がる。 - コンテナの中で走らせるコマンドがCMD - シェルを複数業にまたがって書く場合は「&& \」を行末尾にいれましょう。「&&」はその行のシェルが成功したら次のシェルを叩いて良いという司令。 - 最初からルートユーザーでコマンドは実施される - Dockerイメージを作成するときに叩かれるシェルはボーンシェル。すなわちsh。bashではない。だからbashで使えてshで使えないコマンドは使える。 ### Fargate編 * Clusterはなにも設定せずともできあがる。ガワだけの存在。 * Task:コンテナのこと。TaskDefinitionでどのECRを使用するかを決定する。 * Service:コンテナ群が働くルールの束。 * 一つのServiceに複数のTaskDefinitionを仕込むことができる(基本的には一つだけどね)。一つのClusterに複数のServiceを仕込むこともできる。 * 複数のTask定義が登場するのはWebAPのコンテナの隣にFluentedlyのコンテナをサブ的に登場させて一つのサービスに入れ込むなんて使い方がメジャー。 ![](https://i.imgur.com/oBi17DV.png) * つまりFargateのコンソールにはTaskDefinitionとServiceの2レイヤーの操作ボタンが羅列されている。 * ClusterとTask定義は登録しているだけだったら無料。 * サービスにタスク定義を紐づけるので、先にTask定義を作成する必要がある。 * task定義は同名で繰り返しやると勝手にバージョン管理される。なのでタスク定義名ー3みたいな名前になる。そのバージョン管理されているリビジョンをクリックして、「新しいリビジョンの作成」を押せば、その状態をこぴーして新しいのを作れる。ちょっとずつメモリを増やしたりする使い方ができる。 #### コンテナの追加メニューについて * FargateでTaskと言っているのはほぼコンテナに≒。タスクサイズといわれたらコンテナのスペックだと思えばいい。 * メモリ制限は、一つのタスク定義に複数のコンテナを登録する場合、それぞれのコンテナがどれだけメモリを使っていいのかを指定する。だから一つのタスク定義に一つのコンテナイメージだけがあるときには設定しなくていい。 * ポートマッピングはどのInboundのポートを開けておくのか。Webサーバーコンテナだったら80を開けましょう。今回はアプリを動かすだけなのでいらない。 ## 文字コードの謎 ### 現象 - ファイル名のバリデーションでエラーになって落ちる。 - しかし与えているファイル名は正しいフォーマットになっている。 - pythonのソースファイル自体はutf-8で保存されているものの、vimで開くと日本語部分が文字化けしている ### 原因 **日本語ロケールがDockerのCentOS7イメージに定義されていなかった** Linuxはユニバーサルに使えるように、国際標準化がされている。これを自分の使う環境地域に合わせることを**ロケール**という。 日本語の文字コードは「ja_JP.UTF-8」となる。 DockerのCentOSイメージには日本語ロケールが定義されていない(ロケール候補の一覧を見ても入っていない)のである。イメージサイズを小さくする意図かららしい。 ゆえにこれを #### 参考記事 - [【Linux入門】ローカライゼーションのためのロケール情報設定方法](https://eng-entrance.com/linux-localization-locale) - [CentOS 7 コンテナに消えない日本語ロケールを追加する](https://qiita.com/teruo-oshida/items/08cb84efc2b581b0a439) ### 修正 Dockerfileに以下の記述を差し入れる。 ``` RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8 ENV LANG="ja_JP.UTF-8" \ LANGUAGE="ja_JP:ja" \ LC_ALL="ja_JP.UTF-8" ``` なお、yum update等をやる前にこれを入れると、リセットされるらしい。注意。 この記事が正解。 [Dockerfileで日本語ロケールを設定する方法。およびロケールエラーの回避方法。](https://qiita.com/YuukiMiyoshi/items/f389ea366060537b5cd9) ## データの保持方法変更について ### 現象 給与明細は項目を見ると、ある時点で突然列項目が増加したり順番が変更になったりすることが判明。 | 変更時点 | 内容 | | -------- | -------- | | 2017-11 | 「支給」ブロック 総支給額の手前に「P給与」と「P通勤費」の項目追加 | | 2019-05 | 「支給」ブロック 「課税支給」項目追加 「通勤費」と「現物支給」が左にずれて、空いたマスに「課税支給」が配置 | ### 対応 - いつどのような変更があっても、吸収できるような形にしたい - ほとんどの項目は空。値が入っている項目は基本的に変わらない。 - 列も前後するので、順番は保証されていない。 - ほぼ9割以上の列項目は変わらない。変わったとしても1~2個の項目が増減する。 - 保持されたデータに対しては、insertとshowが必要な処理であり、複雑なJOINなどは不要 以上のような特性から、Document storeを採用する。 DynamoDBでデータ保持する仕様変更を行った。 ## Fargateエラー ### 現象 以下のエラー分がでてきて、Fargateでサービスを作成してもコンテナが誕生してくれなかった ``` CannotPullContainerError: Error response from daemon: Get <Repository URL>: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers) ``` ### 解決策 インターネット公開する。 ECR内のイメージをFargateはインターネット経由で取得しにいく。 だから外にでられるように、Publicサブネットにコンテナを配置し、グローバルIPをつけてあげる。 ### 参考文献 [Fargateでタスク定義実行時,ECRからイメージの取得に失敗 ](http://takahiro0914.hatenablog.com/entry/2019/03/30/143320) ### 参考文献 - [【Qiita】aws cli で DynamoDB を使う](https://qiita.com/ekzemplaro/items/93c0aef433a2b633ab4a) - [【公式ドキュメント】 CLIを使用する](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Tools.CLI.html) - [【公式ドキュメント】dynamodb create-table](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/create-table.html) - [【Developpers io】DynamoDB全くわからない、から、ちょっとわかるようになるまでの道しるべ](https://dev.classmethod.jp/cloud/aws/dynamodb-chottowakaru/) - [【Developpers io】コンセプトから学ぶAmazon DynamoDB【ハッシュキーテーブル篇】](https://dev.classmethod.jp/cloud/aws/conceptual-learning-about-dynamodb-hash-key/) ## pdf->csv変換の複雑性 「pdfをただcsvのような行列テキストデータにさえ変換できればいい」と思っていたが、pdf->csv変換のライブラリを複数試してみるもどれも環境構築でかなり手こずってしまった。 今回は実験の末うまくいったcamelotライブラリを使用することにしたが、pipで関連するライブラリを調べてみると、pandas, numpy, pdfminer, PyPDF2, chardet, openpyxl, OpenCVなど単体でも複雑なライブラリがずらりと並んでいることがよくわかる。camelotライブラリ自体は、これらをうまく組み合わせてコマンド一発でpdf->csvをお手軽にできるようにしてくれるライブラリと捉えた方が良さそうである。 するとpipで管理できるライブラリだけで済むわけでなく、OSそのもののライブラリ管理システム(CentOSであればyum)においても必要なライブラリを探して取り揃える必要があり、その搜索に一人日を費やすこととなった。 結果AWS Lambdaで一発変換かける簡単なシステムになると思われたが、実際はDockerを使って構築する必要があると判断した。 ## Lambdaの果てしなき可能性に気づく yum installがLamdba上でできないと思ったので(Linux共通依存ライブラリを使用する必要があることがわかったので)Fargate活用をする必要が ### 参考文献 * [【公式】Python 用の AWS Lambda デプロイパッケージを作成するには、どうすればよいですか?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/build-python-lambda-deployment-package/) * [【Qiita】AWS Lambda で、動作環境にない Linux 共有ライブラリに依存するコードを動かす](https://qiita.com/yaiwase/items/e64db2c0c06a88a52038) ## 場所を特定してyum installをする方法 ``` $ yum --installroot=/yum-dir --releasever=2 install git ``` --installrootオプションを使うことによって、狙った位置に依存ライブラリを全て落とすことができる。 するとこの配下のファイル全てをZIP化することで、Lambdaへデプロイしたりすることができる。 ただし--releaseverオプションをつけずにやると、以下のようなエラーがでる。 ``` Loaded plugins: extras_suggestions, langpacks, priorities, update-motd Could not retrieve mirrorlist http://amazonlinux.$awsregion.$awsdomain/$releasever/$product/$target/x86_64/mirror.list error was 14: curl#6 - "Could not resolve host: amazonlinux.$awsregion.$awsdomain" One of the configured repositories failed (Unknown), and yum doesn't have enough cached data to continue. At this point the only safe thing yum can do is fail. There are a few ways to work "fix" this: 1. Contact the upstream for the repository and get them to fix the problem. 2. Reconfigure the baseurl/etc. for the repository, to point to a working upstream. This is most often useful if you are using a newer distribution release than is supported by the repository (and the packages for the previous distribution release still work). ... ``` これは--installrootオプションがyum configで指定しているパラメータを一部読み込まなくなる仕様が働いているから。 そのパラメータがリリースバージョンなので、明示してあげる必要があった。 ちなみにAmazonLinux2の場合、リリースバージョンはどのyumリポジトリも2なので、2を一度指定するだけでよい。 もともと--installrootはchrootでルートディレクトリを偽装したいシチュエーションでつかうべきオプションなのである。 ▶︎悲報:Lambdaに重すぎと怒られる zipをアップロードしようとしたら、以下の文章が出て怒られる。 ``` Unzipped size must be smaller than 262144000 bytes ``` サイズが大きすぎたのだ。 Layerで分割して継承しようとしても、Layerの合計がこのサイズを超過するとアウトらしい。(公式より) なんだよイベントドリブンだめじゃん・・・。 似たような現象にぶち当たっている人は結構いるのだが、だいたい「サイズを小さくする」とか「ライブラリを使わない実装方法にする」とか根本的なところで回避してしまっている。Fargateに逆戻りしたほうがいいのか???? 例:[AWS Lambdaと深層学習を組み合わせて、予測APIを作ってみて感じた事](https://qiita.com/RyujiKawazoe/items/348cebdc8e2af4132df1) キャッシュ等を除き、不要なファイルはないはずであるが、ここでひわたし先生一言。 > 今はyumで入れるべきものを全て作業用ディレクトリに入れている。しかしこの方法だとAmazon linux 2に標準搭載されているファイルをも必要と判断して取り入れている。標準搭載のものと必要なものを峻別し、差分のみをインストールできればサイズは減るかもしれない。 そんなことできるんですか??? > yumdownloader という呪文を使えば、差分のみのrpmを取得できる。そのrpmを狙った場所に展開できればやりたいことはできる。 ### 細かいつまづき事象 1. camelotライブラリを削除しても(camelot-pyとCamelot両方)、なぜかimport camelotができてしまい、同じエラーになる。 A.真新しい仮想環境をvenvで新設して、camelot-pyを再導入。クリア 2. インポートエラー「ModuleNotFoundError: No module named 'cv2'」 A.OpenCVが不足しているの意。OpenCVにもいろいろ種類があり、裏で動いているC言語のコンパイルの関係上pythonで動かすには本当はいろいろな設定が必要みたい。今回はpipで全てが管理できるopencv-pythonをpip installした。そもそも、「pip install camelot-py[cv]」という形でインストールすると、両方手に入る。 3. 「RuntimeError: Please make sure that Ghostscript is installed」 A.裏でghostscript等が必要になってくる。yumで落とす。「 yum install tcl-tk ghostscript」 4. パラメータをFargateに与えたい場合、タスク定義をいじるひつようがある。ここの環境変数に値を与えればよいのだ。タスク定義はバージョン管理されているから、処理をするたびにたくさんできることになる。 ### 参考文献 - [【公式Doc】Camelot: PDF Table Extraction for Humans](https://camelot-py.readthedocs.io/en/master/) ## FireLens 一つのコンテナは、CloudWatchLogsにログを吐き出すことができる。ここが生命線。しかしCWLは料金が高い。だからみんなFluentedlyなどを使ってS3に直接ログデータを吐くような処理をかましている。 この機能をFireLensというAWS側のマネージドサービスとしてリリースした。 eval : 変数に入っている文字列がシェルコマンドだったら、それを実行してくれるコマンド。 eval $login_cmd # 根本的な方針おさらい そもそもデータ分析基盤の本質は以下のような図で表現することができる。 ![](https://i.imgur.com/F7BqTur.png) 1. 「Raw」生データ。なにかしらのローデータとなるデータソース。ここにあるデータがマシーンだったらIoTになるし、売り上げデータであればBIシステムとなる。 2. 「Process」データ抽出処理。生の現実をデジタルデータへ変換する仕事や取得できたデータからノイズを取り除くクレンジング処理などがある。大半の「ビッグデータ・ハンドリング技術」と呼ばれているものはここに該当する。 3. 「DataBase」データを蓄積しておく場所。一時的な置き方、半永続的な置き方などに特化したツールなどを使い分けることが大切になる。あるいはデータの持ち方を考えるのも大事。「みんな処理にばかり目がいっているんだ。大切なのは処理よりもデータの構造そのものがどうなっているかを見る目を養うことなんだ」by Linus Torvalds 4. 「Visualize」可視化。今流行りのBIツールはこれを実現させるもの。私のイメージではここまでがデータエンジニアリングの世界。そしてこの可視化されたグラフや値の羅列から意味を読み取っていく作業が「Analyze」分析 すなわちこれらの四要素がスムーズに接続できるように、かつコスト等の要件に合致するようにアーキテクチャを組めばどんなデータ分析基盤でも完成させることができる。上記を踏まえて基盤選定を考えて見る。 ### 実装アーキテクチャ候補 1. LambdaにZIPを込めて送る->ライブラリのサイズがでかすぎる。むりぽ。camelotライブラリを諦めたらできるかもしれない。イベント駆動で実現したいならばこれがベストプラクティス。 2. Fargateにしてイベント駆動させる->タスク定義とサービスを毎回書き換える必要がある。それはFargateの設計思想とあっているのかちょっと疑問。本来はDjangoなど半永久的に動かし続けるサービスを稼働させるホスティングだから。すなわちFargateはイベント駆動にはあまり向いていない?(定期のバッチ処理だったら向いている記述は結構あった。ただし引数で値を渡して都度操作対象が変わるようなイベント駆動は向いていないっぽい) 3. AWS Batchを使う->謎 4. EC2で動かし続ける->DASAI★ 1頑張って調べて実装。だめだったら4で諦めろ!▶︎2020/01/11の結論。 参考文献:[AWS Batch, Lambda, ECS Task 比較:バッチやジョブにはどれを使う?](https://techblog.timers-inc.com/entry/2019/08/06/aws-batch-lambda-ecs-comparison) ## Lambdaを諦めないパターン ### pdfをcsvにライブラリ検討 * tabula-py:メジャーなライブラリ。numpyを使用するものの、83Mと小さい!しかしJava8がないと動かないので実際サイズは大きくなる。 * 実装してみてもLambdaの中身がどうなっているのか、どんなライブラリが搭載されているのかが謎なので、LambdaのDockerイメージを取って来て開発し、そのままデプロイでぶち込むとう方法があるかもしれない。▶実際やってみた。 * ほかに「Python csv pdf」などで検索するとPyPDFなるライブラリがでてくるが、これはPDFのページ統合等の操作をするためのライブラリであり中身の数値をとってくるようなものではない。 * ### Lambda用コンテナを利用した開発を実験してみた件 Lambda環境内にはEC2と異なって元からいろいろなツールが入っている場合がある。(boto3はEC2の中には無いがLambdaの中には標準装備してある) ゆえに環境差によって動いたり動かなかったりすることがあったり、搭載しなくていい余分なツールをZIPで固めてアップロードして容量オーバーでLambdaが動かなかったりすることもある。 したがってローカルとLambdaとの環境差をなくすため、Dockerを使って開発をしてみる。 利用するのがこちら [ lambci / docker-lambda ](https://github.com/lambci/docker-lambda) 使い方はかんたんで、このイメージを取ってくればLambdaの中に入りながらいじるようなことができる。 ただしイメージに複数種類があり、それぞれ違うので注意が必要。 1. lambci/lambda:python3.6 2. lambci/lambda:build-python3.6 **1.lambci/lambda:python3.6** これは本当にLambdaを再現しているコンテナ。lambdaテスト用なのでdocker runでlambda_function.lambda_handlerとjsonしか指定できない。/bin/bashは無い。だからコンテナの中に入って自由にコマンドを打つことはできない。 **2.lambci/lambda:build-python3.6** 名前にもある通り、ビルド用なので色々なコマンドが使える。この中には1のイメージよりも多くのツールが初めから入っている。ビルドはビルド用イメージの中で行ってもよいが、実際のLambdaの中にはビルド用イメージにはあったものがなかったりするため、ここで実験的に動かしてうまく行ったとしても、実際にアップロードするとツールが不足して動かなかったりもする。 実際tabula-pyを動かしたときにこれでハマる。tabula-pyは裏でJava8が必要になる。ビルド用のイメージの中にはJava8が入っていてtabula-pyをpip installするだけで動かすことができるが、LambdaへDeployするとJavaが無いから動かないということになる。(参考までに、以下のメッセージではJavaが無いからtabula-pyが動かせないことが書かれている) これは推測だが、「ビルド用イメージ」ということはPandasなどの「どの環境でpip installしたかによってビルドされた結果が異なり同じ環境内でないと動けない」ツールをビルドしてあげるためのコンテナ環境として使うことが想定されているのではないか。つまりツールを落としてきてビルドすることが目的であり、「Lambdaを完全再現してその中でいじくりまわしながらソースを作成する」といった使い方は想定されていないのではないか。 以上のような特性を鑑みて実験してみた結果、**「tabula-pyはJava8を一緒にZIPにしてアップロードしないとLambdaでは動かせない」**ということが判明した。 1. tabula-py:Java8がないので動かない 2. camelot:yumに起因するライブラリが必要であり、全てをアップロードすると重量オーバーになる。 3. PyPDF2:狙い撃ちで文字を取得することができない。 以上のとおり、Lambdaで帳票をCSV化するのは諦めなければならない模様。悲しい。 せっかくなのでdocker-lambdaを使ったをメモしておく。以下の手順を踏めば、環境差に煩わされずビルドができるようになる。 自分の知らないpythonライブラリは裏で何がビルドされているのか(C++だったりJavaだったり)わからないので、基本はこの方法でZIP化+Deployするのが安全のように思われる。 ``` #作業用ディレクトリ作成 mkdir sgg_lambda && cd sgg_lambda #必要なライブラリ一式リスト作成 echo "requests" > requirements.txt ``` 次にDockerfileを作成 ``` FROM lambci/lambda:build-python3.6 ENV AWS_DEFAULT_REGION ap-northeast-1 +ADD . . CMD pip3 install -r requirements.txt -t /var/task && \ zip -9 deploy_package.zip lambda_function.py && \ zip -r9 deploy_package.zip * ``` メインのLambdaを作成 ```lambda_function.py import requests def lambda_handler(event, context): res = requests.get('https://www.google.com/') return res ``` ビルド実施 ``` # イメージ作成 docker -t sgg-lambda . # ビルドを走らせる。これでdeploy_package.zipというファイルが作成される。これがアップロード対象となるもの。 docker run -v "$PWD":/var/task sgg-lambda # デプロイ方法はいろいろあるが、ここではS3にファイルをうpしてLambdaにコンソール画面でリンクを指定する方法をとっている。 aws s3 cp deploy_package.zip s3://salary-gg/src/deploy_package.zip ``` # CloudFormation覚書 ## 大枠について [公式サイト](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/template-anatomy.html) ↑これを見れば大項目の意味がわかる。基本的にこの大項目を埋めていけばいい。 yamlをファイル分割するときも、必須と書かれたものを書くこと。 ## 記号説明 ### !Sub yamlファイル内の値を変数として扱いたいときに使える記号。CloudFormationに組み込まれている関数Fn::Subの短縮記載方法である。 [参考記事](https://dev.classmethod.jp/etc/cfn-yaml-variable_on_strings/) 「${AWS::Region}」や「${AccountID}」などは組み込み関数になっていて、特に指定せずとも文字通りの情報をCloudFormationが自動でとってきてくれる。疑似パラメータというらしい。 [公式の一覧](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/pseudo-parameter-reference.html) 自分で独自に指定する場合は、Parameters:(9行目)というところで書いているように指定する。(多分Defaultのところが値の本体) ``` Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: AWS Account Parameters: - AWSAccountID Parameters: AWSAccountID: ConstraintDescription: AWS ID is Only Number with 12digit Default: 123456789012 MinLength: 12 MaxLength: 12 AllowedPattern: "[0-9]*" Description: Please enter Gambit System AWS ID! Type: String Resources: TestPolicy: Properties: PolicyDocument: Statement: - Action: lambda:InvokeFunction Effect: Allow Resource: !Sub arn:aws:lambda:${AWS::Region}:${AWSAccountID}:function:hogehoge Version: '2012-10-17' PolicyName: AWSLambdaTestPolicy Roles: - test-hogehoge-role Type: AWS::IAM::Policy ``` ### !Ref ### !ImportValue [【参考】CloudFormationテンプレート間で値を渡す3つの方法](https://qiita.com/tiibun/items/67aa74cdc17bc0b9812c) 値を渡すテンプレート(vpc.yaml)ではOutputsにExport属性付きで値を出力し、 受け取るテンプレート(subnet.yaml)は!ImportValueで取得します。 ``` AWSTemplateFormatVersion: '2010-09-09' Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: 10.250.251.0/24 Outputs: VpcId: Value: !Ref VPC Export: # 渡す値をExportで出力する Name: VpcId ``` ``` AWSTemplateFormatVersion: '2010-09-09' Resources: Subnet: Type: AWS::EC2::Subnet Properties: VpcId: !ImportValue VpcId CidrBlock: 10.250.251.0/28 ``` ## エラーについて ### No default VPC found for this user デフォルトVPCがないとこのように怒られてEC2をCFnで立ち上げることができない。 [参考資料](https://aws.amazon.com/jp/premiumsupport/knowledge-center/cloudformation-cloudformer-default-vpc/) なお、以下のコマンド一発でデフォルトVPCが作成できる ``` $ aws ec2 create-default-vpc ``` # ブログ投稿用フレーズゾーン > サーバーとは言うなれば言うなれば可能性の塊です。そこに特定のミドルウェアを入れることで、DBにもWebサーバーにも、ETL処理用サーバーにもストレージにも化けさせることができます。そう、いうなれば進化の可能性をあまたゆうしている無垢な目をしたイーブイですね。 > 今までのエンジニアは自分でサーバー(イーブイ)を調達して、自分でチューニングや設定(お世話)をする方法でしかDBやストレージサービスを実現させる方法はありませんでした。しかしマネージドサービスというものをクラウド業者が作ったことで、最初からサンダースやブラッキーやニンフィアをエンジニアは使えるようになったのです。 > 確かにマネージドサービスは業者が作ったものですから、細かいチューニング(個体値はもっと素早さが馬鹿高いやつがいい!等)は諦めなければならない部分もあります。しかしクラウドベンダー(大手はAmazon、Google、Microsoft)の優秀な中のエンジニアたちがチューニングした結果を使えるので、大抵は満足なスペックを発揮してくれることが多いです。「俺が考えた最強のリーフィアを作りたい!」と思うエンジニアもまだまだ多いですが、生き馬の目を抜く変化の激しいビジネス業界(ポケモンリーグ)で勝ち抜いていくためには、こうしたマネージドサービスを使うことがとても有効であると私は思っています。 > こうしたマネージドサービスを使うことをサーバーレス、なんてよぶんですね。自分で世話するサーバーがないわけだから。このサーバーレスに私は個人的にすごい可能性を感じていたのでございます。だからEC2=DASAIと言っていた背景はこんな感じなのです。 > 1. マネージドサービスは便利で、Lambdaはイベントドリブンなシステムを作るのにもっとも適したサービスである。 > 2. しかしLambdaに搭載できるPythonライブラリ以外にも必要なライブラリがある。 > 3. Pythonの外のライブラリを環境ごとパッケージ化して運用できるような手段が必要になってくる > 4. コンテナであれば「環境ごとパッケージ化し運用する」作戦にとてもマッチしている。 > 5. Fargateがマッチしている