Amazon Linuxでgunicorn+supervisorをした際のメモ
今更感がありますが、ずっとアプリケーションサーバーは、主にuwsgiを使用していて gunicornを触ってこなかったので、良い機会なので使ってみたのと、supervisourを使って デーモン化してみたのでメモです。
環境
- Amazon Linux
- Python 3.5.2 (DjangoのWSGIアプリケーションで使用済) (supervisourは、現状3系未対応のため Amazon LinuxのデフォでインストールされているPython2.7を使用します)
supervisorのインストール
$ sudo /usr/bin/pip install supervisor Traceback (most recent call last): File "/usr/bin/pip", line 5, in <module> from pkg_resources import load_entry_point File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 3020, in <module> working_set = WorkingSet._build_master() File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 616, in _build_master return cls._build_from_requirements(__requires__) File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 629, in _build_from_requirements dists = ws.resolve(reqs, Environment()) File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 807, in resolve raise DistributionNotFound(req) pkg_resources.DistributionNotFound: pip==6.1.1
pipが古いようなのでrootになって更新
$ sudo su - # /usr/bin/easy_install --upgrade pip $ exit
再度トライ
$ sudo /usr/bin/pip install supervisor Requirement already satisfied: supervisor in /usr/local/lib/python2.7/site-packages Requirement already satisfied: meld3>=0.6.5 in /usr/local/lib/python2.7/site-packages (from supervisor)
pipの更新時に既にインストールされたらしい・・
$ /usr/bin/pip freeze ・・略 supervisor==3.3.3
supervisorのconfファイル
$ sudo su - root -c "echo_supervisord_conf > /etc/supervisord.conf" $ sudo mkdir /etc/supervisord.d
ログ設定の変更
ログのパスを変更
$ sudo vi /etc/supervisord.conf [supervisord] ;logfile=/tmp/supervisord.log ; main log file; default $CWD/supervisord.log logfile=/var/log/supervisor/supervisord.log ; main log file; default $CWD/supervisord.log
ログローテーションの設定
$ cd /etc/supervisord.d $ sudo sh -c "echo '/var/log/supervisor/*.log { missingok weekly notifempty nocompress }' > /etc/logrotate.d/supervisor"
pid, includeの設定
$ sudo vi /etc/supervisord.conf [supervisord] # pidファイル(/var/run配下にpidを生成するように変更) pidfile=/var/run/supervisord.pid # includeセクションのコメントを外す + 拡張子を変更 [include] files = /etc/supervisord.d/*.conf
supervisordをサービス登録
Amazon Linuxは、systemdが無いためinitスクリプトを作成する必要があります。 素で書くのは厳しいため、以下を使います。
initscripts/redhat-init-equeffelec at master · Supervisor/initscripts · GitHub
$ sudo curl -o /etc/rc.d/init.d/supervisord https://raw.githubusercontent.com/Supervisor/initscripts/master/redhat-init-equeffelec $ sudo chmod 755 /etc/rc.d/init.d/supervisord $ sudo chkconfig --add supervisord
起動確認
$ sudo service supervisor start Starting supervisord: /bin/bash: /usr/bin/supervisord: No such file or directory [FAILED]
となりエラーとなったので、シンボリックリンクを貼ります。
# シンボリックリンクを貼る $ sudo ln -s /usr/local/bin/supervisord /usr/bin/ $ sudo ln -s /usr/local/bin/supervisorctl /usr/bin/ # 再度、起動 $ sudo service supervisord start Starting supervisord: # プロセス確認 root 3765 1 0 22:09 ? 00:00:00 /usr/bin/python2.7 /usr/bin/supervisord -c /etc/supervisord.conf ec2-user 3771 3375 0 22:09 pts/0 00:00:00 grep --color=auto supervisord
gunicorn用のconfig設定
今回は、/etc/supervisord.d/django_app.confを作成
[program:django_app] directory=[アプリケーションパス:Djangoのproject_rootを指定] command=/home/ec2-user/.pyenv/versions/3.5.2/bin/python3.5 /home/ec2-user/.pyenv/versions/3.5.2/bin/gunicorn jsl_attendance.wsgi --bind=0.0.0.0:8001 numprocs=1 autostart=true autorestart=true user=ec2-user redirect_stderr=true environment=DJANGO_SETTINGS_MODULE="xxxx.settings.production" # settings.pyを分けているのでproduction用に設定
configの読み込みと、gunicornの起動
configを読み込みます。
$ sudo service supervisord reload
起動は、supervisorctlで実行します。
$ sudo supervisorctl start django_app django_app: started
まとめ
pipのバージョンが古かったりで、少々ハマってしまいましたがなんとか出来ました。 本来は、 グローバルのPython(2.x)に直接pipインストールはせずに仮想環境を作成した方が良かったです。 とは言うものの、2系と3系で仮想環境を作るのが手間なので、早くsupervisorが3系対応してくれればなと 思いました。
参考サイト/ブログ等
http://supervisord.org/installing.html
EC2にNginx + Gunicorn + SupervisorでDjangoアプリケーションをデプロイする - Qiita
PyCon JP 2017に参加してきた。
9月8日〜9日に今年もPyCon JPのトークイベントに参加してきました。
今年は、弊社(日本システム技研)もシルバースポンサーで ご協力させて頂き、かつブースを初出展しました。
2014年からの参加で今年で4回になりますがブースを出展しているということも あり、常時バタバタしていたように思いますが、感想をまとめました。
1日目
「ベンリに使おう変数アノテーション - typing.pyとの楽しいお付き合い」
スライドはこちらにありました。
変数アノテーションの歴史的なから、ジェネリック型の話しが中心でした。 なかなか導入することは出来てないですが、普段PyCharmを使ってる立場からすると有用なことも 多いと思うので、小さな個人プロジェクトなんかに使ってみるところから初めてみようかなと思います。
Djangoフレームワークのユーザーモデルと認証」
スライドは、こちらにありました。
Djangoの「認証」に関する話しでした。HTTPのCookieとセッションの仕組みからDjangoのAuthに関する 説明をされていました。 認証バックエンドのカスタマイズの勘所も説明されていたので、今後自前で認証コードを書く際の参考になるかと 思いました。
「len()関数がオブジェクトの長さを手にいれる仕組み」
スライドは、こちらにありました。
毎年、@shimizukawaさんのトークは人気でブースをギリギリまで対応して参加したら立ち見になってしまいました・・。ですが、楽しい内容のトークで立ち見でも苦痛ではなかったです。
Pythonのlen()はAdapter Patternで、オブジェクトのアンスコアンスコlenが呼ばれているとうお話しで処理系の理解が深まりました。また、現在ぎーらぼで開催中の読書会で、「オブジェクト指向設計実践ガイド」を読んでいて、GoFの話題になることも多いので、その際のネタ話も出来るかなと思いました。
「プロダクト開発して分かったDjangoの深~いパーミッション管理の話」
スライドは、こちらにありました。
こちらも毎年、楽しみにしている@hirokikyさんのトークです。内容は、Djangoの認可についてでした。
認可で、if文のお化けになっちゃう話しは自分も経験していたので非常に興味深く、お話しを聞かせて頂きました。
パーミッションを作るためのライブラリとして「django-rules」や「django-gardian」があるよとのこと。
それぞれの特徴として「django-rules」はパーミッションがDB管理され、「django-gardian」はDB管理せずに利用出来るとのこと。
最終的には、所望な動作が期待できなかったため、「django-keeper」を作られたというお話しでした。
苦労された点も含め、認可設計時の参考にしたい内容でした。
1日目まとめ
Pythonの実装系の話しとDjangoの認証/認可のトークを中心に聞いたように思えます。 今年は、毎年楽しみにしていた@aodagさんの「パッケージングの話し」を聞けなかったので後で、動画で見させて頂こうと思います。
2日目
「基調講演」
Pandasのコミッターの堀越 真映さんのお話しでした。
Pandasのコミュニティでコミッターとして認められるために1年間の活動が必要とのことで なかなか敷居の高さも感じましたが、まずがOSSに貢献するために、まずが業務で使用している お気にい入りのライブラリなんかのIssueを読んで見たり、軽微なバグのプルリクを上げて みるところから始めてみようと思いました。
「Reactive Programming on AWS Lambda in Python」
はじめて英語のトークを聞いてみました。普段Lambdaに関わっていることもあって 技術的にある程度、理解しているものをチョイスしてみました。
こちらのライブラリを使用するとデプロイが楽だよという 感じの内容だったかと思うのですが、如何せん英語力の無さを痛感する内容だったので、動画を見て 復習します・・。
「The theory of Serverless development by Python (理論から学ぶPythonによるサーバレス開発)」
スライドは、こちらにありました。
業務でサーバーレスを扱うことが多くなってきたので、今回一番聞きたいトークだったのですが、途中ブースの関係で断片的になってしまったので、再度スライドと動画を見て、まとめたいと思います(@marcy-teruiさん、ごめんなさい)。
途中お聞きした際には、Faasの向いてるもの、向かないもののお話しがあったかと思うので要チェックです!
「ジョブフェア」
今年の自分のテーマで「英語力」を上げるあるので、各社さんの取り組みは非常に刺激になる内容でした。
「Pythonをとりまく並行/非同期の話」
スライドは、こちらにありました。
過去にthreading.Threadを使用して、ツライ目にあった(実装を理解していなかったため・・) 経験もあったので、興味深い内容でした。
並行/並列処理の解説では、CPUバウンドか、I/Oバウンドかで使用するケースやGILについての 説明も分かりやすく今後、弊社のエンジニアに教える際に良いスライドだなと思いました。
非同期I/Oについては、なかなか触れるケースがなく理解が乏しいのですが、これを機に勉強して みようかと思える内容でした。
2日目まとめ
英語のセッションとLambda系のトークを中心に聞きました。 深い内容のものが多かったのですが、ブースの関係でSlackが気になって途中断片的になってしまったので あったので、再度スライドや動画で要復習な感じです。
その他
ポスターセッションの際に、Python BootCampの各地のメンバの方と集合写真撮らせて頂きました。 今後も長野でPythonを盛り上げていく活動を進めていきたいと思います。
まとめ
今年は、ブースを初出展ということもあり、スタッフとSlackでやりとりをすることが あったので、トークに集中できなかったことが多々あったのですが、youtubeで動画配信 されているので、こちらは再度復習がてら見ようと思います。
また、ささやかな目標であった英語のトークを聞いてみるという試みで、まだまだリスニングのスパーリング が足りないことに気づいたので、引き続き頑張ります。 2日目のパーティーで海外スピーカーのRizky Ariestiyansyahさんとお話しできたのは、良い経験になりました。
最後に、スピーカーとしての参加は、2014年から出来ていないので来年はプロポーザル提出してみようと思います。
以上
【自由研究③】react-reduxのconnectについて調査してみた話
Reduxで実装する場合にReact部とRedux部の繋ぎ込みに react-redux が有効ということは、分かったのですがどうもconnect() に渡している引数や、戻り値として何が生成されるのか分からず 結果として、なんでconnect()使うと幸せになれるのか分からなかったため 調査してみました。
なぜ分からないのか?
なぜ分からないのか考えてみました。
- チュートリアル等で、手を動かしただけでドキュメントの読み込みが足りない
- そもそもReduxの理解が不足している
ドキュメントを再度読んでみる。
Usage with React · Redux を読んでまずは まとめてみることにしました。
Presentational / Container componentについて
再利用性を考慮して、Presentational(プレゼンテーショナル) / Container(コンテナ) component の2つに分離されるようです。 2つのコンポーネントの役割を簡単にまとめてみましたが、ざっくりいうと
- 見た目(表示)担当のPresentational component
- ロジック担当のContainer component
って感じのようです。
また、調べていたら良い記事を既に書いていらっしゃる方がいたので参考にさせて 頂きました。
Presentational Componentsとは
- 役割:見た目の実装
- データ取得時:propsより取得
- データ更新時:propsのcallback関数
- コンポーネントの作成:自分で作る
実際のイメージとしては、こんな感じです(こちらからの抜粋です)。
import React from 'react' export default React.createClass({ render() { const { text, onButtonClick, } = this.props return ( <div> <p>{text}</p> <button onClick={onButtonClick}>Click!</button> </div> ) } })
- {text}の表示は、props経由
- ボタンクリック時の{onButtonClick}の実装もprops経由
Container Componentsとは
- 役割:データフェッチやStateの更新
- データ取得時:reduxのstateにより取得
- データ更新時:reduxのactionにより更新
- コンポーネントの作成:react-reduxが生成
実際のイメージとしては、こんな感じです(こちらからの抜粋です)。
import { connect } from 'react-redux' import SomePresentationalComponent from 'some-presentational-compnent' const mapStateToProps = (state, ownProps) => { return { // blah blah blah } } const mapDispatchToProps = dispatch => { return { // blah blah blah } } export default connect( mapStateToProps, mapDispatchToProps )(SomePresentationalComponent)
はい、出てきましたー。connect() この辺りから、分からなくなってきます・・・。
こちらに以下のようなコメントが ありました。
mapStateToProps(state, ownProps)は,store.getState()の結果を第一引数に,このContainer component へ渡されたpropsを第二引数にして呼び出される関数で,これらのstateとpropsを使って子のPresentational componentにpropsとして渡す値を生成します. mapDispatchToProps(dispatch)は,store.dispatchを第一引数にして呼び出される関数で, 子のPresentational componentにpropsとして渡す値(というか,コールバック関数)を生成します. 通常,このコールバック関数では,引数として渡されているdispatchを呼び出し,子のPresentational Componentが StoreへActionを送信できるようにしておきます. ボタン押下時に呼ばれる処理などもコールバック関数として書いてPresentational componentにpropsとして 渡すと言いましたが,このコールバック関数を作るためのものと思っておけばいいと思います.
すごく丁寧な解説をして頂いているのですが、そもそも以下が良く分かっていないことが判明しました。 その結果として、connect()の引数から何が生成されるのかが分かっていないのだという結論に至りました。
- Store.getState()
- Store.dispatch()
以下のドキュメントで各メソッドの仕様を調査しました http://redux.js.org/docs/api/Store.html
getState()
- 要訳すると、現状のStoreが持つ最新のState郡を返す。
dispatch()
- 要訳すると、dispatchは、唯一Stateを変更する手段。
- 引数として、actionを渡す。actionとは、UIイベント、 networkのcallback等を指す。 actionのfieldには、"type"が必要
これを踏まえて
上記を踏まえて、connect()の解説を読むとより理解が深まりました。 要は、Presentational componentに対して、propsとして、stateと stateを更新するためのCallback関数として渡してるだけのようです。
変に、connect()の第1引数と、第2引数がなにかしらの対応づけがされているのでは と推察していたことがそもそもの間違いでした・・
ちゃんとドキュメント読めよと・・
以前作成した、以下のコードを「React Developer Tools」で確認(スクショ参照)すると、それが良く分かりました。CalculatorContainerコンテナ(Presentational component)に対して、propsとして引数に渡していることが 分かります。
import * as actions from '../actions'; const mapState = (state, ownProps) => ({ calculator: state.calculator, }); function mapDispatch(dispatch) { return { actions: bindActionCreators(actions, dispatch) } } export default connect(mapState, mapDispatch)(CalculatorContainer);
(上記のスクショが見えづらかったため、Reactコードを転記しました。)
<Provider store={dispatch: dispatch() subscribe: subscribe() getState: getState() replaceReducer: replaceReducer()}> <Connect(CalculatorContainer)> <CalculatorContainer calculator={inputValue: 0, resultValue: 0,showingResult: false} actions={onNumClick:fn(), onPlusClickfn():, onMinusClick:fn()}/> </Connect(CalculatorContainer)> </Provider>
そして再びconnet()へ
ここまでで、connet()の挙動に関しては、理解できました。 最後に謎なのが・・。
export default connect(mapState, mapDispatch)(CalculatorContainer);
という呼び出し時の記述です。connect(mapState, mapDispatch)の戻り値になんらかの関数が 戻ってきて、それに対してコンテナ(Presentational component)に引数に渡して、Class生成している ことが予想されます。
connect()の戻り値をドキュメントで確認すると
Returns
A higher-order React component class that passes state and action creators into your component derived from the supplied arguments. This is created by connectAdvanced, and details of this higher-order component are covered there.
とありますが、higher-order React component classというなんとも説明しづらい記述があったため 実際にreact-reduxの実装を見てみることにしました。
connect.jsを読む
src/connect/connect.jsが対象です。 ソース内のconnectHOC(selectorFactory)が ポイントのようです!。 connectAdvanced()の実装を確認します。
connectAdvanced.jsを読む
src/components/connectAdvanced.jsが対象です。 ソース を確認すると、Connectコンポーネントを作成し、それの子コンポーネントとして引数のコンテナ(Presentational component) を使用しているようです。
なので、connect()の戻りは、
「higher-order React component class」 == 「Connectコンポーネント」
ということになります。
まとめ
長々と調査してきましたが、自分なりの結論としては以下に至りました。
connect()とは
- 引数には、stateとstateを更新するCallback関数を渡す(引数のPresentational componentはpropsでのみ扱える)。
- Connectコンポーネントを返す(引数のPresentational componentを子コンポーネントして持つ)。
connect()のへの疑問から様々な箇所まで波及しましたが、そもそもReduxの理解不足という一言につきました・・。 ライブラリの内部実装を確認することは、いつも時間の無さにかまけて出来てなかったのですが 今回のconnect()の実装が腑に落ちなく、別のエンジニアに説明する材料が乏しかったため今回の確認作業を実施しました。
中々、ヘビーな作業でしたが、ライブラリのメリデメの理解は断然高まりますので、まとまった時間がある際に再度トライ してみたいです。
最後に
これを読まれている方で、ちょっと認識違うんじゃないかとか、この辺が分かりづらいというご意見ありましたら 是非、コメント頂ければと思います!
【自由研究②:react native】ExpoでDebug環境を整える
前回に引き続き、夏休み自由研究の第2段です! 今回は、前回導入したExpoのDebug環境を整えます。 (環境は、macを対象としています)
目次:
- シミュレータ/エミュレータを使用したDebug
- react-native-debuggerのインストール
- react-native-debugger-open のインストール
- react-native-debuggerの起動
- まとめ
シミュレータ/エミュレータを使用したDebug
まずは、シミュレータ/エミュレータを使用したDebug環境 を試してみました。
Expoの公式サイトのままやっています。 docs.expo.io
Android (Genymotionを使用した場合)
※Genymotionの導入については、別途まとめます。
Either press “Menu” button in Genymotion’s toolbar, or just hit Cmd-m. とあるので、エミュレータ上で、Cmd + mをします。
メニュー表示されるので、「Debug JS Remotely」を選択します。
Chromeが起動して以下のメッセージが表示されるので、それに従います。
こんな感じで、developer toolsが使用できるようになり、Debug出来るように なり、ログDebug等が可能になりましたが、JS記述のためやはり、ReactのDebug 環境としてはまだ厳しい感じです。
iOS
iOSシミュレータは、試せていませんが以下で可能なようです。
Hit Ctrl-Cmd-Z on a Mac in the emulator to simulate the shake gesture, or press Cmd+D.
react-native-debuggerのインストール
react-native-debuggerを使用すると、ReactのDebugが可能なようなので 導入してみます。また、reducerに手を加えることによってReduxのDebugも可能なようです。
$ brew update && brew cask install react-native-debugger
react-native-debugger-open のインストール
ドキュメントを確認すると、react-native-debugger-open も必要なようなので、インストールします。
https://github.com/jhen0409/react-native-debugger/tree/master/npm-package
インストール
$ npm i --save-dev react-native-debugger-open
package.jsonに追記
"scripts": { "postinstall": "rndebugger-open" }
npm run postinstall を実行し、getDevToolsMiddleware.js をreplaceする
$ npm run postinstall
react-native-debuggerの起動
前述しました、Androidエミュレータ場合、Cmd + m後に「Debug JS Remotely」 を選択すると、react-native-debuggerが起動します。
まとめ
react-native-debuggerは使用すると、react NativeのDebugが捗りそうです。 ただ、Androidエミュレータは「Genymotion」を使用することが推奨な感じです。 (SDK版では試していませんが、公式ドキュメントに記述がありませんでした) ReduxのDebugをする場合は、redux-devtools-extensionが別途必要そうですが こちらは、次回以降で検証したいと思います。
【自由研究①:react native】Expoを使って、react native環境を作ってみる
夏休み中ですが、休暇明けに「react native」 +「redux」の案件に携わるので 自由研究な感じで諸々やってみたメモをまとめてみようと思います。 今日は、Expoを触ってみた感想をまとめました。
目次:
- Expo.io
- create-react-native-appのインストール
- プロジェクト作成
- XDEのインストール
- Expoアプリのインストール
- XDEでプロジェクトを読み込み
- QRコードをExpoアプリでスキャンする
- まとめ
Expo.io
ちょっと前までは、「react native」はreact-native-cliを使用してアプリ構築する手段 しななかったようですが、xcodeやAndroid Stdioでビルドする必要があったりして、結構手間なようです。 また、実機テストが通常のネイティブアプリ開発のようにUSB接続が必要があります。
今回、Expo.ioというサービスを使用すると幸せになれるらしいということが分かったので こちらを使用してみることにします。react nativeの公式ページを見てもこれ使うサンプルが あるのでこちらを使用する方向になりそうです。
create-react-native-appのインストール
Expoを使用するために、create-react-native-appを使用してreact-nativeプロジェクトを 作成する必要があります。
npm install -g create-react-native-app
プロジェクト作成
プロジェクトを作成します。
create-react-native-app hogefuga
XDEのインストール
Desktop Development Tool: XDEをインストールします。
以下を参照しました。 Installation | Expo v15.0.0 documentation
Expoアプリのインストール
各デバイス向けのExpoアプリをGoogle Play/App Storeよりインストールします。 自分はとりあえず、Androidアプリをインストールしました。
以下を参照しました。 Installation | Expo v15.0.0 documentation
XDEでプロジェクトを読み込み
「Project」-「Open Project」でプロジェクトを読み込みます。
「Share」でQRコードを表示します。
QRコードをExpoアプリでスキャンする
Expoアプリ(今回は、Android)を起動して、「Scan QR Code」を選択し QRコードを読み込みます。
しばらくすると、作成したサンプルプロジェクトが起動します。
まとめ
Expoを使用したreact native環境は、非常にお手軽に実機テストまで出来て良い感じでした。 ビルド待ちが少し気になりましたが・・。
がっつりネイティブ依存の機能を作り込む場合は、「react-native-cli」+「各IDE」を使用して開発するのかもしれ ませんが現状は「Expo」+「create-react-native-app」で充分に思いました。
今日はここまで。
いまどきのJSプログラマーのための Node.jsとReactアプリケーション開発テクニック
- 作者: クジラ飛行机
- 出版社/メーカー: ソシム
- 発売日: 2017/07/26
- メディア: 単行本
- この商品を含むブログを見る
JavaScriptエンジニアが手っ取り早くReactの基礎を理解するための「超」入門書
- 作者: 天田士郎
- 発売日: 2017/02/05
- メディア: Kindle版
- この商品を含むブログを見る
Reactビギナーズガイド ―コンポーネントベースのフロントエンド開発入門
- 作者: Stoyan Stefanov,牧野聡
- 出版社/メーカー: オライリージャパン
- 発売日: 2017/03/11
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
入門 React ―コンポーネントベースのWebフロントエンド開発
- 作者: Frankie Bagnardi,Jonathan Beebe,Richard Feldman,Tom Hallett,Simon HØjberg,Karl Mikkelsen,宮崎空
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/04/03
- メディア: 大型本
- この商品を含むブログ (2件) を見る
WebデベロッパーのためのReact開発入門 JavaScript UIライブラリの基本と活用
- 作者: 柴田文彦
- 出版社/メーカー: インプレス
- 発売日: 2016/11/25
- メディア: Kindle版
- この商品を含むブログを見る
zappaが想定しないAWSアカウントにデプロイされて焦った話し
世間は、最近サーバレスが盛んで業務でlambdaを使用するメンバも増えてきましたが自分は なかなか使う機会がなかったのですが、PyConJPで弊社ブースを出すに当たってなにか展示物を作る 必要があったので、Zappa(GitHub - Miserlou/Zappa: Serverless Python Web Services)を使ってみようと思いました。
Zappaとは
Python/flaskベースのAWSの Serverless frameworkでAPI Gateway + lambda + S3を使用するようです。
テストアプリを作ってみた
zappa で hello world するまで - Qiitaを参考にさせてもらいながら もりもり作成して、デプロイしたわけです。
こんな感じで設定ファイルを書いて
{ "dev": { "app_function": "test.app", "aws_region": "ap-northeast-1", "profile_name": "default", "s3_bucket": "zappa-xyzxyzxyzxyz" } }
そしてデプロイしたわけです。
$ zappa deploy dev Calling deploy for stage dev.. Creating demo-zappa-dev-ZappaLambdaExecutionRole IAM Role.. Creating zappa-permissions policy on demo-zappa-dev-ZappaLambdaExecutionRole IAM Role. Warning! Your project and virtualenv have the same name! You may want to re-create your venv with a new name, or explicitly define a 'project_name', as this may cause errors. Downloading and installing dependencies.. Packaging project as zip.. Uploading demo-zappa-dev-1498726098.zip (7.6MiB).. 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 7.94M/7.94M [00:01<00:00, 4.31MB/s] Scheduling.. Scheduled demo-zappa-dev-zappa-keep-warm-handler.keep_warm_callback with expression rate(4 minutes)! Uploading demo-zappa-dev-template-1498726129.json (1.6KiB).. 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1.64K/1.64K [00:00<00:00, 5.09KB/s] Waiting for stack demo-zappa-dev to create (this can take a bit).. 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 4/4 [00:15<00:00, 5.71s/res] Deploying API Gateway.. Deployment complete!: https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev
すげーデプロイできた!!。そして、実行。
$ curl -l https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev hello from Flask!
おお、楽すぎるーと感動しつつ・・。さて、マネージメントコンソールでどんな感じなのかなと 見てみました・・・。
何故か、該当するFunctionが見当たらない・・。
profileを確認してみる。
zappa_settings.jsonでは、defaultをしていました。
$ cat ~/.aws/config [default] region = ap-northeast-1 [profile xxxxxx] output = json region = ap-northeast-1 [profile yyyyyy] region = ap-northeast-1 output = json # @@@@は伏せ字 $ cat ~/.aws/credentials [xxxxxx] aws_access_key_id = @@@@ aws_secret_access_key = @@@@ [yyyyyy] aws_access_key_id = @@@@ aws_secret_access_key = @@@@
???。defaultのaccess_keyとsecret_access_key が定義されていないのに、なぜかデプロイされちゃってます・・・。
調査する。
$ aws lambda list-functions { "Functions": [ { "FunctionName": "demo-zappa-dev", "FunctionArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXX:function:demo-zappa-dev", "Runtime": "python3.6", "Role": "arn:aws:iam::[デプロイ先のAWSアカウント]:role/demo-zappa-dev-ZappaLambdaExecutionRole", "Handler": "handler.lambda_handler", "CodeSize": 7939825, "Description": "Zappa Deployment", "Timeout": 30, "MemorySize": 512, "LastModified": "2017-06-29T09:17:27.435+0000", "CodeSha256": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "Version": "$LATEST" } ] }
デプロイされたlambda functionのAWSアカウントが分かりました。 しかし、いまいち覚えがないアカウント・・・。
$ aws sts get-caller-identity { "UserId": [デプロイ先のAWSアカウント], "Account": [デプロイ先のAWSアカウント], "Arn": "arn:aws:iam::[デプロイ先のAWSアカウント]:root" }
うーん、これも同じ。~/.aws/configは使用していない模様。
$ aws configure list Name Value Type Location ---- ----- ---- -------- profile <not set> None None access_key ****************XXXX boto-config secret_key ****************4YT1 boto-config region ap-northeast-1 config-file ~/.aws/config
configの一覧が確認できるようなので、試すとboto-config というキーワードがあります。それで思い出しました。以前、botoを使用するために /etc/boto.cfgを作成したことを・・
試しにboto.cfgを削除して、デプロイすると見事にエラーとなりました。
$ zappa deploy dev Calling deploy for stage dev.. Oh no! An error occurred! :( ============== Traceback (most recent call last): ・・・ ============== Need help? Found a bug? Let us know! :D File bug reports on GitHub here: https://github.com/Miserlou/Zappa And join our Slack channel here: https://slack.zappa.io Love!, ~ Team Zappa!
まとめ
とりあえず、原因は分かりましたが、zappaのデプロイ時にzappa_settings.json に該当するprofileが無かった場合はせめてエラーメッセージ出力してデプロイしないで欲しいなあとも思ったのですが botoの挙動なのかもしれないので、ドキュメントを確認しました。
これ見る限り、 botoの仕様ぽいですね。良い勉強になりました。
The mechanism in which boto3 looks for credentials is to search through a list of possible locations and stop as soon as it finds credentials. The order in which Boto3 searches for credentials is: Passing credentials as parameters in the boto.client() method Passing credentials as parameters when creating a Session object Environment variables Shared credential file (~/.aws/credentials) AWS config file (~/.aws/config) Assume Role provider Boto2 config file (/etc/boto.cfg and ~/.boto) Instance metadata service on an Amazon EC2 instance that has an IAM role configured.
実践AWS Lambda ~「サーバレス」を実現する新しいアプリケーションのプラットフォーム~
- 作者: 西谷圭介
- 出版社/メーカー: マイナビ出版
- 発売日: 2017/06/09
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
サーバーレスシングルページアプリケーション ―S3、AWS Lambda、API Gateway、DynamoDB、Cognitoで構築するスケーラブルなWebサービス
- 作者: Ben Rady,吉田真吾,笹井崇司
- 出版社/メーカー: オライリージャパン
- 発売日: 2017/06/23
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
AWS Lambda: A Guide to Serverless Microservices (English Edition)
- 作者: Matthew Fuller
- 発売日: 2016/01/11
- メディア: Kindle版
- この商品を含むブログを見る
Amazon Web Services クラウドネイティブ・アプリケーション開発技法 一番大切な知識と技術が身につく
- 作者: 佐々木拓郎,佐藤瞬,石川修,高柳怜士,佐藤雄也,岸本勇貴
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2016/04/20
- メディア: Kindle版
- この商品を含むブログを見る
docker for mac + nginxのログをrsyslogコンテナで出力してみた
docker for mac + nginx + オレオレ証明書でローカルSSL環境を作ったメモ - katekichiのゆるブログ
前回の続きで、ログの集中管理する的なことをやってみたかったので rsyslogコンテナに吐き出してみることにしました。
ログの集中管理というと、「fluentd」(http://www.fluentd.org/)が主流だと思いますが 今回は、基本的なところを抑えたかったのでrsyslogにしました。
rsyslogサーバーを立てる
http://d.hatena.ne.jp/tmatsuu/20140603/1401811893 の記事を参考に立てました。
Dockerfile作成
FROM centos:latest RUN yum install -y rsyslog ADD remote.conf /etc/rsyslog.d/ EXPOSE 514 CMD ["/sbin/rsyslogd", "-n"]
remote.conf作成(rsyslog.conf)
$ModLoad imudp $UDPServerRun 514 $AllowedSender UDP, 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 local1.* /var/log/nginx_access_log local2.* /var/log/nginx_error_log
イメージビルド
$ docker build --tag simple-rsyslog .
コンテナ起動
$ docker run -d -p 514:514/udp -h "logserver" simple-rsyslog
テストしてみる
loggerコマンドを使用して、以前構築したnginxコンテナからログを送信してみます。
rsyslogコンテナのIPは、以下で調べました。
$ docker inspect -format="{{ .NetworkSettings.IPAddress }}" コンテナID
nginxコンテナからログ送信
$ docker exec -it [nginxのコンテナID] /bin/bash # コンテナに入る # logger -n[コンテナのIP] -p local1.info testtesttest # logger -n[コンテナのIP] -p local2.error errorerrorerrorerror
rsyslogコンテナでログの確認
$ docker exec -it [rsyslogのコンテナID] /bin/bash # コンテナに入る # tail -f /var/log/nginx_access_log Jun 27 10:07:16 172.17.0.3 <someone>: testtesttest # tail -f /var/log/nginx_error_log Jun 27 10:12:01 172.17.0.3 <someone>: errorerror12345678
ログフォーマット等の調整は必要そうですが、出力することはできました。
nginxイメージの修正
nginx.confのログ設定を変更します。
access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; ↓ access_log syslog:server=logserver,facility=local1 main; error_log syslog:server=logserver,facility=local2 notice;
イメージビルドと起動(--add-host
で「logserver」を指定)
$ docker build --tag webapp-syslog . $ docker run -d --name webapp-syslogp -p 443:443 -p 80:80 --add-host logserver:[rsyslogのIP] webapp-syslog
rsyslogコンテナでログ確認
$ docker exec -it [rsyslogのコンテナID] /bin/bash # コンテナに入る # tail -f /var/log/nginx_access_log Jun 27 11:08:12 f4809369ff7e nginx: 172.17.0.1 - - [27/Jun/2017:11:08:12 +0000] "GET / HTTP/1.1" 200 132 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" "-" Jun 27 11:08:22 f4809369ff7e nginx: 172.17.0.1 - - [27/Jun/2017:11:08:22 +0000] "GET / HTTP/1.1" 200 132 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" "-" Jun 27 11:08:24 f4809369ff7e nginx: 172.17.0.1 - - [27/Jun/2017:11:08:24 +0000] "GET / HTTP/1.1" 200 132 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" "-"
まとめ
思いつきでやってみましたが、rsyslogの知見がそもそも無いのに、Docker上で構築するってのが 少し敷居が高かったです(そもそもDockerのオペレーションも怪しい・・)。
何事もステップ・バイ・ステップですね。良い勉強になりました。
記事読まれている方で、この辺り詳しい方、是非アドバイス頂けると嬉しいです。
- 作者: 鶴長鎮一
- 出版社/メーカー: 技術評論社
- 発売日: 2011/04/22
- メディア: 大型本
- 購入: 2人 クリック: 27回
- この商品を含むブログ (1件) を見る