1.はじめに
lambdaのコードを書くにあたってCloud9を使えるという噂を以前聞いていたので、実際に試してみました。その中でいくつかの 罠 がありましたので紹介したいと思います。
2.前提
Cloud9で環境構築する際に、既存の環境にSSHで接続する方法と専用のEC2を新規に立てる方法がありますが、後者の環境とします。また、OSはAmazonLinux2とします。なお、pythonのバージョンですが、PEP-373とPEP-404で定義されている通り2系は2019年末にはEOL( End Of Life = サポート終了 )となりますので3系を用います。
ある程度pythonとLinuxコマンドを理解していることも前提になります。
3.注意事項
3-1. rootユーザと開発ユーザのpythonコマンドのバージョンが異なっている!?
linux系のOSですので特に珍しいことではないかもしれませんが、rootユーザと開発ユーザのpythonコマンド1のバージョンの設定が違うのです。。。
試しに以下コマンドを実行します。
$ python --version
Python 3.6.8 # 想定通り
$ sudo python --version
Python 2.7.16 # え” !?
さらに、pythonコマンドとpipコマンドのバージョンが違います。。。
$ python --version
Python 3.6.8 # 想定通り
$ pip --version
pip 9.0.3 from /usr/lib/python2.7/dist-packages (python 2.7) # え” !?
標準モジュールを用いるにあたっては特に問題にならないのですが、pipで外部モジュールをinstallする際2に何も手当をしないと、想定通りにinstallがなされません。。。
何が起きているのでしょう。各コマンドの場所を確認してみます。
まず、pythonコマンドから。
$ which python
alias python='python36' # aliasが設定されている
/usr/bin/python36
$ sudo which python
/usr/bin/python
$ ls -la /usr/bin/python
lrwxrwxrwx 1 root root 24 Sep 3 14:51 /usr/bin/python -> /etc/alternatives/python # alternativesが利用されている
開発ユーザはaliasにてpython36を向くようにされており、rootユーザはalternativesが使われていることが分かります。
続いて、pipコマンド。
$ which pip
/usr/bin/pip
$ sudo which pip
/usr/bin/pip
$ ls -la /usr/bin/pip
lrwxrwxrwx 1 root root 21 Sep 3 14:51 /usr/bin/pip -> /etc/alternatives/pip # alternativesが利用されている
環境によっては、rootのpythonのバージョンを変えられないということはありがちなのですが、今更python2は無いでしょうということと、開発用の新しい環境ですし、python3にスイッチすることで悪影響はないと思いますので、alternativesの設定を変えるのが一番シンプルで良いと考えます。
以下手順にて設定を変更します。
$ sudo update-alternatives --config python
There are 2 programs which provide 'python'.
Selection Command
-----------------------------------------------
*+ 1 /usr/bin/python2.7
2 /usr/bin/python3.6
Enter to keep the current selection[+], or type selection number: 2
$ python --version
Python 3.6.8 # 想定通り
$ sudo python --version
Python 3.6.8 # 想定通り
$ pip --version
pip 9.0.3 from /usr/lib/python3.6/dist-packages (python 3.6) # 想定通り
$ sudo pip --version
pip 9.0.3 from /usr/lib/python3.6/dist-packages (python 3.6) # 想定通り
これで、心置きなく外部モジュールを導入できます。
試しにjinaja2をインストールしてみます。
$ sudo python -m pip install jinja2
Collecting jinja2
Using cached https://files.pythonhosted.org/packages/...../Jinja2-2.10.1-py2.py3-none-any.whl
Requirement already satisfied: MarkupSafe>=0.23 in /usr/local/lib64/python3.6/site-packages (from jinja2) (1.1.1)
Installing collected packages: jinja2
Successfully installed jinja2-2.10.1
$ sudo python -m pip freeze
astroid==1.6.6
Django==2.0.2
ikp3db==1.1.4
isort==4.3.21
jedi==0.11.1
Jinja2==2.10.1 # ← インストールされた!
lazy-object-proxy==1.4.2
MarkupSafe==1.1.1
mccabe==0.6.1
parso==0.1.1
pbr==5.4.2
pylint==1.8.1
pylint-django==0.8.0
pylint-flask==0.5
pylint-plugin-utils==0.5
pytz==2019.2
six==1.12.0
stevedore==1.30.1
virtualenv==16.2.0
virtualenv-clone==0.5.3
virtualenvwrapper==4.8.4
wrapt==1.11.2
なお、jinja2以外のモジュールは最初からインストールされているものです。
3-2.pylintが外部モジュールを認識しない!?
さて、これでやっと開発ができると思って、実際にコードを書いてみますと、なんと先ほどインストールした外部モジュールが正しく読み込めていないのか、「no value for argument 'backend' in constructor call」というエラーが発生します。。。
原因ですが、Cloud9の設定の問題でした。。。
左ペインのPython Supportをクリックすると、pythonの設定画面が開きます。
設定内容の中に、"PYTHONPATH"という設定があるのですが、以下の通り記述されています
/usr/local/lib/python2.7/dist-packages:/usr/local/lib/python3.4/dist-packages:/usr/local/lib/python3.5/dist-packages
3系と2系のモジュールを全部読み込んでいるという、雑な設定にも驚きなのですが、そもそも3.4も3.5入ってすらないです。。。この記事を作成している段階で標準導入されているものは3.6ですので以下のように変更します。3
/usr/local/lib64/python3.6/site-packages:/usr/local/lib/python3.6/site-packages
3-3.lambdaにデプロイしたファイルが消せない!?
Cloud9ではlambdaを開発できることがウリなのですがここでも罠が。。。
続いて、適当にファイルを作ります。例としてsample.txtというファイルを作成しました。
lambdaをデプロイします。ボタン一つでデプロイできます!
lambda側の管理画面でsample.txtがアップされていることを確認します。無事上がってます。
ここで、私は混乱しました。Cloud9上では確かに削除しており、実体は残っていないのですが、何度lambdaにデプロイしなおしても削除したファイルは残り続けるのです。いろいろ調べたのですが、 .debug という隠しフォルダがあり、その中に削除したファイルのコピーが置かれていることに気づきました。
隠しフォルダはデフォルトでは非表示になっているので、表示するように設定します。歯車ボタンで表示されるメニューの「Show Hidden Files」にチェックを入れます。
すると、 .debug フォルダが表示され、削除したはずのsample.txtが。。。
.debug フォルダのsample.txtを削除し、改めてデプロイしなおします。
3-4.lambda実行で外部モジュールが見つからない!?
サンプル作成した関数にて外部モジュールをimportします。先にpipでinstallしておけば、pylintでエラーになることは当然ありません。
この状態でlambdaを実行すると、モジュールが見つからないと言われ動きません。
実は、lambdaとして動かすためには、ローカルにもモジュールを入れておく必要があります。
関数の名前がついているフォルダ(の親の方のフォルダ)にて右クリックをして「Open Terminal Here」をクリックしてターミナルを開きます。
ターミナルにてpip installコマンドに「-t .」オプションを付けて実行します。
$ python -m pip install jinja2 -t .
Collecting jinja2
Downloading https://files.pythonhosted.org/packages/1d/e7/fd8b501e7a6dfe492a433deb7b9d833d39ca74916fa8bc63dd1a4947a671/Jinja2-2.10.1-py2.py3-none-any.whl (124kB)
100% |████████████████████████████████| 133kB 3.1MB/s
Collecting MarkupSafe>=0.23 (from jinja2)
Downloading https://files.pythonhosted.org/packages/b2/5f/23e0023be6bb885d00ffbefad2942bc51a620328ee910f64abe5a8d18dd1/MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl
Installing collected packages: MarkupSafe, jinja2
Successfully installed MarkupSafe-1.1.1 jinja2-2.10.1
当然、デプロイしてlambdaの管理画面側でも動きます!
#4. おわりに
IDEもブラウザで完結させることができる世の中になったことは感慨深いです。が、もう少しユーザフレンドリーだとありがたいなと思いました。当記事が、Cloud9利用にあたって躓いている方の一助になれば幸甚です。