ローカルマシンで開発したPython3 on pyenv with pipenvな常駐プログラムのGitリポジトリを、Bitbucketのプライベートリポジトリにリモートマスターを作成してプッシュして、ConoHaのサーバーにgit clone して動かすまで

長ったらしいタイトルだけど、何の記事か後から振り返った時に思い出せるようにw

ということで、2か月くらいローカルのMacbookでビットコインのトレードを自動化するボットを開発していて、そろそろ24時間365日動かし続けてみようということで、あまり活用していないConoHaサーバーにデプロイして動かそうとしている最中のメモ

(今、環境設定の作業自体は7割くらい終わっちゃっているけど、忘れないうちに作業内容を書き出しておく)

#Bitbucketのセットアップとローカルリポジトリとの連携

https://bitbucket.org/ にアクセスして、プライベートなリポジトリを新規作成

ローカルのリポジトリからプッシュできるように自分のプロフィールにsshの公開鍵を登録しておく

リポジトリを作成するとローカルにクローンするか、既存のリポジトリのリモートリポジトリとして登録するかどうかの案内のメッセージが表示されるので、それに従い、すでに作成済みのローカルリポジトリで以下のコマンドを実行する

```
cd /path/to/repository/
git remote add origin git@bitbucket.org:user_account/new_repository.git
```

で、すでにソースコードがあり、上記ディレクトリ内でバージョン管理されているのでBitbucketに作成したリモート オリジンのリポジトリに `push` しちゃう

```
git push -u origin master
```

途中、ssh鍵のパスフレーズ聞かれるけど、それは、前段でBitbucketの新規リポジトリにプッシュできるように公開鍵を登録しておいたので、そのパスフレーズを入力する感じ

以下のようなメッセージが表示されれば、無事、Bitbucketのリモートリポジトリにプッシュできたことになる

```
To bitbucket.org:user_account/new_repository.git
 * [new branch]      master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
```

#BitbucketのリポジトリからConoHa上にクローン

Bitbucketのリポジトリから `git clone` するため、適当なディレクトリを用意する

Bitbucketのリポジトリはプライベートなため、あらかじめローカルの鍵の公開鍵をBitbucketのリポジトリ側に登録しておく

そのため、ConoHa上で `git clone` するユーザーのSSHの鍵を作成
むろん、パスフレーズも登録しておく

```
ssh-keygen -t rsa -b 4096
```

生成した鍵は、 `/home/user/.ssh/id_rsa.pub` とかで出力されているので、`cat`や`view`でファイルを開いて中身をコピーするか、`cat ~/.ssh/id_rsa.pub | pbcopy`でクリップボードに保存しておき、Bitbucketのリポジトリの設定より、アクセスキーとして登録

ここまで準備ができれば、あとは、クローンするディレクトリに移動して、`git clone`するだけ

```
cd /path/to/git_clone_directory
git clone git@bitbucket.org:user_account/new_repository.git
```

#Python環境のセットアップ

ConoHaで標準で入っているPythonはバージョンが2.7で、ローカルで開発したのは、3.7だったので、それで動くようにしたい

Pythonの環境は、pipenvを利用するので、`pip` で `pipenv` をまずはインストール

```
# pip install pipenv
```

`git clone`してきたソースには、`Pipfile`が含まれているので対象のディレクトリに移動して、`pipenv install`すれば良いかなぁ... と思い、やってみたけど、以下のようなエラーが発生

```
$ cd /path/to/git_clone_directory
$ pipenv install
Warning: Python 3.7 was not found on your system...
You can specify specific versions of Python with:
  $ pipenv --python path/to/python
```

##情報収集

以下のあたりを、ザーーッと読んで理解を深める

* [Pipenvの進んだ使い方 ... Pythonの自動インストール — pipenv 2018.11.27.dev0 ドキュメント ](https://pipenv-ja.readthedocs.io/ja/translate-ja/advanced.html#automatic-python-installation)
* [複数のバージョンのPythonで使えるPipfileの書き方 - Qiita](https://qiita.com/TomoyukiAota/items/87017a4f57b8246b894c)
* [pyenv と pipenv による python 環境 - Qiita](https://qiita.com/euxn23/items/fdd79bad28ccc0476a36)
* [環境構築 - pipenv で Python 環境の構築方法 (2018年11月版) - Pynote](http://pynote.hatenablog.com/entry/python_ubuntu_pipenv)
* [Pythonのパッケージ周りのベストプラクティスを理解する - エムスリーテックブログ](https://www.m3tech.blog/entry/python-packaging)
* [Mac上のPython仮想環境をpipenv+pyenvへ移行してみた ｜ DevelopersIO](https://dev.classmethod.jp/etc/environment_to_pipenv-pyenv/)
* [pipenvで環境構築 - こたつむりの備忘録](https://justice-vsbr.hatenablog.com/entry/2018/11/13/034906)

要は、pipenvだけインストールしてあってもダメで、裏で動く pyenv もないと自動で Python のバージョンまで揃えてくれない、ということかな

前段で `pip install pipenv` したけれど、 `pyenv` を入れて、そちらの Python で `pipenv` するのが良さそう

## pyenvのインストール

インストール先は、 `~/.pyenv` にしている例が多いけど、個別のアカウントのホームディレクトリ配下に入れるのは、なんか好きじゃないので `/opt/pyenv` にする

```
# git clone https://github.com/pyenv/pyenv.git /opt/pyenv
```

環境変数周りをイジって `pyenv` コマンドが適切に機能するように設定する

```
$ echo 'export PYENV_ROOT="/opt/pyenv"' >> ~/.bash_profile
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
$ exec $SHELL -l
mkdir: ディレクトリ `/opt/pyenv/shims' を作成できません: 許可がありません
mkdir: ディレクトリ `/opt/pyenv/versions' を作成できません: 許可がありません
```

`exec $SHELL -l` でエラーが出てしまった、どうやら `/opt/pyenv/`配下を操作するようなので... 他の例のように `~/.pyenv` に配置する方が良さそう

ということで、やり直し

```
$ git clone https://github.com/pyenv/pyenv.git ~/.pyenv
```

環境変数も周りをイジって `pyenv` コマンドが適切に機能するように設定する

```
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
$ exec $SHELL -l
```

話は変わるが... 設定ファイルが `.bash_profile` と `.bashrc` どっち？という話もあるみたいだけど...

* [本当に正しい .bashrc と .bash_profile の使ひ分け - Qiita](https://qiita.com/magicant/items/d3bb7ea1192e63fba850)

以下でバージョンが適切に表示されればOK

```
$ pyenv -v
pyenv 1.2.13
```

##pyenvでPython3.7をインストール

リビジョン番号を指定せずに、マイナーまでの 3.7 でインストールしてみる

```
$ pyenv install 3.7
pyenv: no such command `install'
$ pyenv global 3.7
```

`install`コマンドが見つからないので... 検索して、同様のトラブルが発生している人を発見

* [pyenvでインストールを実行しようとしたら"no such command `install' "となる - Qiita](https://qiita.com/Soh1121/items/68f231d759a76de8c471)

要は、完全な一般ユーザーで `pipenv` w/ `pyenv` な環境構築って難しいのかもと思いつつ

```
$ .pyenv/plugins/python-build/install.sh
mkdir: ディレクトリ `/usr/local/share/python-build' を作成できません: 許可がありません
```

と、やはりエラーになったので、公式ページも見つつ

> https://github.com/pyenv/pyenv/tree/master/plugins/python-build
> This will install python-build into /usr/local. If you do not have write permission to /usr/local, you will need to run sudo ./install.sh instead. You can install to a different prefix by setting the PREFIX environment variable.


公式も `sudo` でやれということなので、やってみる

```
$ sudo ~/.pyenv/plugins/python-build/install.sh

あなたはシステム管理者から通常の講習を受けたはずです。
これは通常、以下の3点に要約されます:

    #1) 他人のプライバシーを尊重すること。
    #2) タイプする前に考えること。
    #3) 大いなる力には大いなる責任が伴うこと。

[sudo] user_name のパスワード:
```

って、そりゃそうだw `sudo` できるようにセットアップしてねーしw

公式サイトの以下が気になったので...

> You can install to a different prefix by setting the PREFIX environment variable.

`.pyenv/plugins/python-build/install.sh` を覗いて見た

```
# Usage: PREFIX=/usr/local ./install.sh
#
# Installs python-build under $PREFIX.
```

あぁー、なるほど、ということで

```
$ PREFIX=~/.local ~/.pyenv/plugins/python-build/install.sh
```

上手くいったっぽいので、再度、`pyenv install 3.7`を実行したが...

```
$ pyenv install 3.7
python-build: definition not found: 3.7

The following versions contain `3.7' in the name:
  2.3.7
  3.3.7
  3.7.0
  3.7-dev
  3.7.1
  3.7.2
  3.7.3
  3.7.4
  miniconda-3.7.0
  miniconda3-3.7.0
  stackless-3.3.7

See all available versions with `pyenv install --list'.

If the version you need is missing, try upgrading pyenv.

$ pyenv install 3.7.4
Downloading Python-3.7.4.tar.xz...
-> https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tar.xz
Installing Python-3.7.4...
WARNING: The Python bz2 extension was not compiled. Missing the bzip2 lib?
WARNING: The Python readline extension was not compiled. Missing the GNU readline lib?
WARNING: The Python sqlite3 extension was not compiled. Missing the SQLite3 lib?
Installed Python-3.7.4 to /home/user/.local/bin/~/.pyenv/versions/3.7.4
```

`3.7.4` とリビジョン番号まで指定して、インストールが完了はしたけれど...
依存系で足りないものがったようなので、以下を実行して

```
# yum install gcc zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel tk-devel libffi-devel
```

`pyenv install 3.7.4` でインストールし直したところ、WARNING なしでインストール完了したので、以下も実行

```
$ pyenv global 3.7.4
```

問題なさそうなので、次に pipenv のインストールし直し(し直しというか、pyenv の環境下でインストール)

##pyenv環境にpipenvをインストール

`pip` だけで、`pyenv global 3.7.4` の Python の pip を使うことになるのかな？ `pyenv global 3.7.4`したから、`3.7.4` の `pip` が認識されるのだろう

```
$ pip install pipenv
```

上記を実行したいわけだけど、ユーザー環境で完結させるためには、実行コマンドの例として、`pip install --user pipenv` とユーザーディレクトリ配下にインストールする方法を取るのが良さそう

`--user` のオプションの有る無しの違いについては、以下のページが詳しく分かり易かった

* [Python：pip における管理者権限と user install - pyてょん日記](https://pyteyon.hatenablog.com/entry/2019/05/24/003924)

```
$ pip install --user pipenv
DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7. More details about Python 2 support in pip, can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support
Requirement already satisfied: pipenv in /usr/lib/python2.7/site-packages (2018.11.26)
Requirement already satisfied: setuptools>=36.2.1 in /usr/lib/python2.7/site-packages (from pipenv) (41.0.1)
Requirement already satisfied: virtualenv in /usr/lib/python2.7/site-packages (from pipenv) (15.1.0)
Requirement already satisfied: enum34; python_version < "3" in /usr/lib/python2.7/site-packages (from pipenv) (1.1.6)
Requirement already satisfied: pip>=9.0.1 in /usr/lib/python2.7/site-packages (from pipenv) (19.2.1)
Requirement already satisfied: typing; python_version < "3.5" in /usr/lib/python2.7/site-packages (from pipenv) (3.7.4)
Requirement already satisfied: certifi in /usr/lib/python2.7/site-packages (from pipenv) (2019.6.16)
Requirement already satisfied: virtualenv-clone>=0.2.5 in /usr/lib/python2.7/site-packages (from pipenv) (0.5.3)
WARNING: You are using pip version 19.2.1, however version 19.2.2 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
```

ん？ `Python 2.7` って、想定と違う...

```
$ pyenv global 3.7.4
$ python --version
Python 2.7.5
$ pip --version
pip 19.2.1 from /usr/lib/python2.7/site-packages/pip (python 2.7)
```

`pyenv global` が機能していない... orz

原因は、`.bash_profile` の設定だったので編集して再設定して、読み込み直した上で、`pyenv` の `git clone` からやり直し


##改めて、pyenvなpipenvでセットアップ

前項までの内容が上手くいっていれば、以下のコマンドも上手くいくはず！

```
$ cd /path/to/git_clone_directory
$ pipenv install
Creating a virtualenv for this project...
Pipfile: /opt/user/Pipfile
Using /home/user/.pyenv/versions/3.7.4/bin/python3.7m (3.7.4) to create virtualenv...
⠦ Creating virtual environment...Using base prefix '/home/user/.pyenv/versions/3.7.4'
New python executable in /home/user/.local/share/virtualenvs/script-UDmdRvaW/bin/python3.7m
Also creating executable in /home/user/.local/share/virtualenvs/script-UDmdRvaW/bin/python
Installing setuptools, pip, wheel...done.
Running virtualenv with interpreter /home/user/.pyenv/versions/3.7.4/bin/python3.7m

✔ Successfully created virtual environment! 
Virtualenv location: /home/user/.local/share/virtualenvs/script-UDmdRvaW
Installing dependencies from Pipfile.lock (6aaddf)...
An error occurred while installing pubnub==4.1.4 --hash=sha256:98b02b1fb3c08f95d50b05cd4ee58bb1ba2d3b858c355256d6c232fe4d3dad7c! Will try again.
An error occurred while installing graphql-relay==2.0.0 --hash=sha256:0e94201af4089e1f81f07d7bd8f84799768e39d70fa1ea16d1df505b46cc6335 --hash=sha256:75aa0758971e252964cb94068a4decd472d2a8295229f02189e3cbca1f10dbb5 --hash=sha256:7fa74661246e826ef939ee92e768f698df167a7617361ab399901eaebf80dce6! Will try again.
An error occurred while installing apistar==0.7.2 --hash=sha256:8da0d3f15748c8ed6e68914ba5b8f6dd5dff5afbe137950d07103575df0bce73! Will try again.
An error occurred while installing jinja2==2.10.1 --hash=sha256:065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013 --hash=sha256:14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b! Will try again.
An error occurred while installing graphql-server-core==1.1.1 --hash=sha256:e5f82add4b3d5580aa1f1e7d9f00e944ad3abe1b65eb337e611d6a77cc20f231! Will try again.
An error occurred while installing responder==1.3.1 --hash=sha256:717ad3d85999007066aac62ff822913452940f9679a8ae6b77597e2e7c841ec4 --hash=sha256:a8936a250620f99aa8f88813963d433f32c82acba81f1b45ae23f3dd84a3a219! Will try again.
An error occurred while installing uvicorn==0.8.4 --hash=sha256:5320b48629564fa914fe8120542608c91f98fcd2278e8454bda9db08467519d1! Will try again.
  🐍   ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 41/41 — 00:00:20
An error occurred while installing requests==2.22.0 --hash=sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4 --hash=sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31! Will try again.
Installing initially failed dependencies...
  ☤  ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 8/8 — 00:00:10
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.
```

`An error occurred while installing ... Will try again.` と出ているのでエラーかと思いきや... スクリプトは実行できたので問題なさそう...

環境は、コレでOK

#スクリプトの実行

ローカルPCでパラメーターの調整のためファイルを編集して、コミットして、リモートのマスターに`push`

```
$ git push -u origin master
Warning: Permanently added the RSA host key for IP address '1234:abcd:1234::abcd:123' to the list of known hosts.
Enter passphrase for key '/Users/user_name/.ssh/id_rsa': 
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 354 bytes | 354.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0)
To bitbucket.org:account/repos.git
   d7862b3..28cff50  master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
```

スクリプトを動かすサーバー側では、最新のデータを取得

```
$ git pull origin master
Warning: Permanently added the RSA host key for IP address '1234:abcd:1234::abcd:1234' to the list of known hosts.
Enter passphrase for key '/home/user_name/.ssh/id_rsa': 
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From bitbucket.org:account/repos
 * branch            master     -> FETCH_HEAD
Updating d7862b3..28cff50
Fast-forward
 v.py | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
```

スクリプトを実行したら、`logs`ディレクトリがないと怒られたw

```
$ pipenv run python ./script.py
Traceback (most recent call last):
  File "./script.py", line 452, in <module>
    filename="./logs/script_debug.log",
  File "/home/user/.pyenv/versions/3.7.4/lib/python3.7/logging/__init__.py", line 1895, in basicConfig
    h = FileHandler(filename, mode)
  File "/home/user/.pyenv/versions/3.7.4/lib/python3.7/logging/__init__.py", line 1087, in __init__
    StreamHandler.__init__(self, self._open())
  File "/home/user/.pyenv/versions/3.7.4/lib/python3.7/logging/__init__.py", line 1116, in _open
    return open(self.baseFilename, self.mode, encoding=self.encoding)
FileNotFoundError: [Errno 2] No such file or directory: '/opt/user/logs/script_debug.log'
```

ディレクトリを作成

```
$ mkdir /path/to/logs/
```

スクリプトは、バックグラウンドで実行

```
$ nohup pipenv run python ./script.py &
```

初回 `nohup` をつけ忘れたので以下の手順でスクリプトを一時停止させてからバックグラウンド処理に変更

```
$ pipenv run python ./script.py
^Z
[1]+  停止                  pipenv run python ./script.py

$ jobs
[1]+  停止                  pipenv run python ./script.py

$ bg 1
[1]+ pipenv run python ./script.py &

$ jobs
[1]+  実行中               pipenv run python ./script.py &

$ disown %1

$ jobs
$ ps -Af
```

上手く動いている様子