Ubuntu18.04 + pyenv + pipenv + Django + Apache2 なデプロイ その1

その0でサーバーの初期設定的な部分の実装は完了しているので，必要なライブラリ類をインストールしていきます．
今後は基本的にrootユーザー(`ubuntu@xxx-xxx-xxxxx`とか`root@xxx-xxx-xxxxx`)でログインすることは無いと思います．設定で禁止しているし．

#必要ライブラリ群のインストール
##いろいろインストール
`curl`とか`wget`とかがあるので，ソースコードハンドリング周りのいろいろなライブラリ群じゃないですかね，知らんけど．

```
ttimes@xxx-xxx-xxxxx:~$ sudo apt install -y gcc make build-essential libssl-dev libffi-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev liblzma-dev
```

##gitのインストール
pyenvはgitからcloneで引っ張ってくるみたいですが，今回の`ttimes`もソースコード管理をgithub上で行っているのでちょうどいいです．

```
ttimes@xxx-xxx-xxxxx:~$ sudo apt install -y git
```

##gitのssh設定
僕はソースコード管理をgithubで行っているので，`git clone`でソースコードを引っ張ってきたり，`git pull`でコードを更新して保守運営していく予定です．

その時に，githubとの間でssh接続の認証が完了していないとめんどくさいということで，楽できるように設定を進めます．

###git

```

ttimes@xxx-xxx-xxxxxx:~$ git config --global user.name branch-git
ttimes@xxx-xxx-xxxxxx:~$ git config --global user.email xx@yy.com
ttimes@xxx-xxx-xxxxxx:~$ cd ~/.ssh
ttimes@xxx-xxx-xxxxxx:~/.ssh$ ssh-keygen -t rsa -C "xx@yy.com"
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ttimes/.ssh/id_rsa): /home/ttimes/.ssh/id_git_rsa
# RSA鍵のペアをどういう名前で出力するかを設定する．念のためデフォルトとは違う名前を設定．
Enter passphrase (empty for no passphrase):                   # パスフレーズを入力．なくていいと思う
Enter same passphrase again:                                  # パスフレーズを再入力．
Your identification has been saved in /home/ttimes/.ssh/id_git_rsa.
Your public key has been saved in /home/ttimes/.ssh/id_git_rsa.pub.
The key fingerprint is:
SHA256: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ xx@yy.com
The key's randomart image is:
+---[RSA 2048]----+
|~~~~~~~~~        |
| ~~~~~~~~~~      |
|  ~~~~~~~~~~     |
|   ~~~~~~~~~~    |
|     ~~~~~~~~~~  |
|      ~~~~~~~~~~ |
|       ~~~~~~~~~~|
|      ~~~~~~~~~~ |
|     ~~~~~~~~~~  |
+----[SHA256]-----+
ttimes@xxx-xxx-xxxxxx:~/.ssh$ cat id_git_rsa.pub
ssh-rsa ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~
~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~
~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~
~~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~ xx@yy.com
```
catしたRSA公開鍵の`ssh-rsa`から`xx@yy.com`のところまでコピーして，githubに公開鍵として登録します．僕は忘れたら[ここ](https://qiita.com/aki4000/items/4c81bc2747bbd5e96d85)を見ています．

####よく分からんエラーをする場合

```
ttimes@xxx-xxx-xxxxxx:~$ ssh -T git@github.com
The authenticity of host 'github.com (52.192.72.89)' can't be established.
RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8.
Are you sure you want to continue connecting (yes/no)? yea
Please type 'yes' or 'no': yes
Warning: Permanently added 'github.com,52.192.72.89' (RSA) to the list of known hosts.
git@github.com: Permission denied (publickey).
```
これも[こっち](https://qiita.com/E-yusuke/items/46b5a5034c39dc45f712)に書いてある通りに，`ssh-add`すればOKです．

```
ttimes@xxx-xxx-xxxxx:~/.ssh$ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-ofp3LmgKOEVN/agent.27372; export SSH_AUTH_SOCK;
SSH_AGENT_PID=27373; export SSH_AGENT_PID;
echo Agent pid 27373;
ttimes@xxx-xxx-xxxxx:~/.ssh$ eval $(ssh-agent -s)
Agent pid 27375                                    # sshを起動できた
ttimes@xxx-xxx-xxxxx:~/.ssh$ ssh -T git@github.com # RSA鍵を認証
Warning: Permanently added the RSA host key for IP address '13.114.40.48' to the list of known hosts.
Hi branch-git! You've successfully authenticated, but GitHub does not provide shell access.
ttimes@xxx-xxx-xxxxx:~/.ssh$ rm id_git_rsa.pub    # githubに公開鍵を，
# known_hostsに秘密鍵を登録できたので，元のファイルは不要．削除してしまいましょう．

```


##pyenvのインストール
`~/.pyenv`なるインストール先は公式が推奨しているらしいです．

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

##pyenvのパスを通す
`~/.bashrc`を編集します．前述の通り，僕は`nano`派なので，`nano`で触りますが，ここは`#set pyenv path`以降を`.bashrc`の一番最後に貼り付けるだけでOKです．
`~/.bash_profile`を編集するように紹介する記事もありますが，基本的にどっちでもいいと思います．詳しい人の解説記事でも読んでみてください～

```
ttimes@xxx-xxx-xxxxx:~$ sudo nano ~/.bashrc

# set pyenv path
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"
```

最後の行の部分は，記事によっては`eval "$(pyenv init -)"`と紹介されていることもありますが，それだと次に設定する`global`コマンドだけでうまく切り替わってくれませんでした．
[pyenvのreadme](https://github.com/pyenv/pyenv#basic-github-checkout)に，うまくいかない場合の対応方法がディストリビューションごとに載っていますので参考にしてみてください．急がば回れ，詰まったときこそ公式リファレンス読むのって大事．

保存できたら，設定内容を`sourceコマンド`で読み込み，設定を有効にします．

```
ttimes@xxx-xxx-xxxxx:~$ source ~/.bashrc
```

##pyenvでPythonをインストール
基本的にubuntuやCentOSにはプリインでPythonが入っていますが，こいつらはOS周りの低階層ファイルをマネージメントするために用意されていることがほとんどなので，あまりガンガンこいつらを触るのは良くないらしいです．
っていうことで，pyenvで適当なバージョンを入れましょう．
僕の場合は，ローカルの開発環境が`python3.8.5`だったので，互換性のある中で一番最新の`3.8.12`を入れてみます．
この`pyenv install`コマンドは，ソースコードからビルドするらしいので，それなりに時間がかかってしまいます．RAM1GBで1分くらい？
特に返り値は帰ってこないので，下記コマンドでpyenv管理下のpythonを全て表示させてみましょう．

```
ttimes@xxx-xxx-xxxxx:~$ env PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install 3.8.12    # 3.8.12をインストール
ttimes@xxx-xxx-xxxxx:~$ pyenv versions                                                      # 選択中のバージョンを確認
*  system
   3.8.12 (set by /home/ttimes/.pyenv/version)
```
無事，systemのプリインpythonに加えて3.8.12が追加され，認識されていることが分かります．
それでは新しく追加された3.8.12を選択し，pyenvが仕事している(3.8.12のPATHが通っている)ことを確認しましょう．
コマンドの前半部分は，pyenvでインストールしたpythonが共有オブジェクトを共有するためのオプションらしいです．これをつけないと，今後訳の分からんところでエラーしまくるので，しっかり設定しましょう．
~~っていうか共有してない共有オブジェクトってあるの？~~

```
ttimes@xxx-xxx-xxxxx:~$ pyenv global 3.8.12             # 3.8.12を選択
ttimes@xxx-xxx-xxxxx:~$ pyenv versions                  # 選択中のバージョンを確認
  system
* 3.8.12 (set by /home/ttimes/.pyenv/version)
ttimes@xxx-xxx-xxxxx:~$ python3 --verison
Python 3.8.12
```


##pipenvのインストール
単純に`pip install pipenv`でもいいんですけど，
①ubuntuに新規ユーザー`ttimes`を追加
②`pyenv`を利用して新しいpythonをインストール
と，わりかし丁寧に来ているので，この流れに乗って丁寧に進めます．

```
ttimes@xxx-xxx-xxxxx:~$ python3 -m pip install pipenv
```
今後も`pip`を使うときは単独で入力せず，`python3 -m pip`とするように気を付けましょう．

:::note warn
pipと-m pipの違い
これって結構なんとなくで進めてきたって人が多い気がします．僕もそうでした．
端的に区別するならこんな感じですね；

* pip 　  ：PATH一覧の中から`pip`という名前のモジュールを起動する
* -m pip ：現在起動中のpythonに紐づいているpipを選択して起動する

要は前者だとシステムにプリインされているpythonに紐づいたpipが起動してしまう可能性がある，というわけです．折角`pyenv`とか使って丁寧に環境分けてきたのに，そんなことになったらオジャンだよね～ってことですね．
ここまでの設定だと，pyenv globalコマンドで指定したpythonがpython3コマンドで呼び出されるので，"現在起動中のpython"となるのです．
:::

:::note
ちなみに，-m pipを「使わなければいけないタイミング」は多々あれど，「使ってはいけないタイミング」はほぼないと思います．
今後も-m pipを呼び出すクセを付けた方がよいでしょう．
:::

#ディレクトリ整備
今回作成している`ttimes`のHOME直下に`/app`を作成し，そこに`git clone`します．
ここで注意すべきは，開発環境において「どこをgit管理下に置いているか」です．考えながらディレクトリ構造を再現しましょう．

```
ttimes@xxx-xxx-xxxxx:~$ mkdir app
ttimes@xxx-xxx-xxxxx:~$ cd app
ttimes@xxx-xxx-xxxxx:~/app$ git clone https://github.com/xxxxx/TTimes.git
Cloning into 'TTimes'...
Username for 'https://github.com': xxxxx
Password for 'https://branch-git@github.com':
remote: Enumerating objects: 1160, done.
remote: Counting objects: 100% (164/164), done.
remote: Compressing objects: 100% (97/97), done.
remote: Total 1160 (delta 98), reused 117 (delta 66), pack-reused 996
Receiving objects: 100% (1160/1160), 1.65 MiB | 8.81 MiB/s, done.
Resolving deltas: 100% (753/753), done.
ttimes@ik1-217-78942:~/app$ ls
TTimes
```
ということで，無事`git clone`に成功し，ソースコードを引っ張ってくることができました．

#`pipenv`で仮想環境構築
ここまでくるとあと一息です．まずはpipenvの設定を済ませてしまいましょう．

##任意の場所にpipenvで仮想環境を構築する
pipenv は初期設定のままだと `~/.local/share/virtualenvs/` の下に仮想環境を作るようになっている．このままではせっかく`git clone`で引っ張ってきた中に含まれている`Pipfile`と`Pipfile.lock`に対して`pipenv install`で環境構築しても，よく分からないところ（`~/.local/share/virtualenvs/`）に環境が立ってDjangoをrunできなくなる．
回避するためには，下記のように`.bashrc`に対して`pyenv`の設定の直後に設定してやればよい．

```
ttimes@xxx-xxx-xxxxx:~/app$ sudo nano ~/.bashrc

# pipenv setting
export PIPENV_VENV_IN_PROJECT=1
```
他にも様々な設定が利用できるようなので，気になる方は[こちら](https://qiita.com/tonluqclml/items/cd0d2a2cb0197cbaee42)を参考にするとよさそう．
さて，`.bashrc`をいじったあとは，忘れずに再読み込みして設定を反映させること！

```
ttimes@xxx-xxx-xxxxx:~/app$ source ~/.bashrc
```

##`Pipfile`，`Pipfile.lock`から環境を再現
詳しくは他の記事に譲るが，`Pipfile`，`Pipfile.lock`と同一ディレクトリにいれば`pipenv install`コマンドで環境の再現が可能です．ということで，いざ．．．！
ちなみに，Djangoプロジェクトをgit管理するときの`git管理する階層`も，`Pipfileの置き場所`も両方悪いのであまり参考になりません．．．
自分的なベストプラクティスとは少し違いますが，[こちら](https://qiita.com/F_clef/items/9d079d0164c2ea9251ab)も参考になると思います．

```
ttimes@xxx-xxx-xxxxx:~/app$ cd TTimes
ttimes@xxx-xxx-xxxxx:~/app?TTimes$ ls
Pipfile       templates        TTimes
manage.py     Pipfile.lock     static      timecardproject
ttimes@xxx-xxx-xxxxx:~/app/TTimes$ python3 -m pipenv install
  ?   ???????????????????????????????? 10/10 ― 00:00:06
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.
ttimes@ik1-217-78942:~/app/TTimes$ python3 -m pipenv shell
Launching subshell in virtual environment...
ttimes@ik1-217-78942:~/app/TTimes$  . /home/ttimes/app/TTimes/.venv/bin/activate
(TTimes) ttimes@ik1-217-78942:~/app/TTimes$ 
```

頭に(TTimes)ってついていますね．これでOKです．
今日はここまで．[次回](https://qiita.com/drafts/7c225cbc277d53b71f0e/)はApache2とMySQL5.7の設定を進めます．

### [その０](https://qiita.com/_branch_/items/e9c22d9e51ed3ed8d0bb) リモートの本番環境にSSHでアクセスする
### [その１](https://qiita.com/_branch_/items/633055f69503aec96156) pythonの環境を整える（pyenv, pipenv）
### [その２](https://qiita.com/_branch_/items/7c225cbc277d53b71f0e) のこり