1
0
hugo/content/blog/2018-08-21-heroku.md

347 lines
13 KiB
Markdown
Raw Normal View History

2024-04-23 13:21:26 +00:00
+++
date = "2018-08-21"
tags = ["heroku"]
title = "herokuでsnsやらchatやらを立ててみた時の話"
slug = "heroku"
+++
## 導入
この前、chat立てたい、みたいな話を耳にしたので、1,2時間ほどでherokuのほうに立ててみました。ちょっと調べたりした。
そういえば、この場合、立てた、建てた、どっちだろう。まあ、どっちでもいいか。
## phx-chat
さて、chatというと、elixirのphx(phoenix)が便利です。これは、作る場合という話ですが、exampleでも機能はないけど、シンプルなものができます。
herokuの場合、なかなか面倒ですけど、[dwyl/phoenix-chat-example](https://github.com/dwyl/phoenix-chat-example)を使えば、割と簡単にできます。
```sh
$ git clone https://github.com/dwyl/phoenix-chat-example
$ cd !$:t
$ heroku create $APP_NAME
$ rm -rf .git
$ heroku git:remote -a $APP_NAME
$ echo "erlang_version=20.1
elixir_version=1.6.0
always_rebuild=false
runtime_path=/app
" >> elixir_buildpack.config
$ echo "web: MIX_ENV=prod POOL_SIZE=2 mix ecto.migrate && mix phx.server" >> Procfile
$ vim config/prod.exs
config :chat, ChatWeb.Endpoint,
load_from_system_env: true,
url: [scheme: "https", host: "syui-chat.herokuapp.com", port: 443],
force_ssl: [rewrite_on: [:x_forwarded_proto]],
cache_static_manifest: "priv/static/cache_manifest.json",
secret_key_base: Map.fetch!(System.get_env(), "SECRET_KEY_BASE")
$ mix deps.get
$ mix phx.gen.secret
XXX
$ heroku config:set SECRET_KEY_BASE="XXX" -a $APP_NAME
$ heroku addons:create heroku-postgresql:hobby-dev -a $APP_NAME
$ heroku buildpacks:set https://github.com/HashNuke/heroku-buildpack-elixir.git -a $APP_NAME
$ heroku buildpacks:add --index 2 https://github.com/gjaldon/heroku-buildpack-phoenix-static.git -a $APP_NAME
$ echo mix.lock >> .gitignore
$ git add .
$ git commit -m "first"
$ git push heroku master
```
多分、こんな感じですね。
https://github.com/dwyl/learn-heroku/blob/master/elixir-phoenix-app-deployment.md
https://hexdocs.pm/phoenix/heroku.html#making-our-project-ready-for-heroku
## pleroma
[pleroma](https://git.pleroma.social/pleroma/pleroma)もphxで書かれています。ただし、phx exampleであるようなディレクトリ構造とは少し違うので、heroku buildpacksも違ってきます。
具体的には、`https://github.com/gjaldon/heroku-buildpack-phoenix-static.git`は、`assets/package.json`を`npm i`するのですが、pleromaは、heroku deployする際に、npm(node)が必要ありません。`package.json`ないですし。ということで、buildpacksは`elixir`のやつだけでOKです。
大抵、srcを読めばわかりますが、`config/prod.exs`はこんな感じになってます。
> config/prod.exs
```sh
use Mix.Config
config :pleroma, Pleroma.Web.Endpoint,
http: [port: {:system, "PORT"}],
url: [scheme: "https", host: "pleroma.syui.cf", port: 443],
force_ssl: [rewrite_on: [:x_forwarded_proto]],
#cache_static_manifest: "priv/static/manifest.json",
secret_key_base: System.get_env("SECRET_KEY_BASE")
config :logger, level: :info
config :logger, :console, format: "[$level] $message\n"
config :phoenix, :stacktrace_depth, 20
config :pleroma, Pleroma.Repo,
adapter: Ecto.Adapters.Postgres,
url: System.get_env("DATABASE_URL"),
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
ssl: true
config :pleroma, :media_proxy,
enabled: true,
redirect_on_failure: true,
base_url: "https://syui.gitlab.io/img/pleroma"
```
pleromaもそうですが、imgをuploadするserverが必要で、通常はhostingしているserverにuploadするんですけど、herokuは再起動と同時に、upload(write)されたものを消します。なので、この際にuploadしたavatarも消えます。
ということで、`media_proxy`を設定してみてどうにかならないかなってことでやってみましたが、どうにもなりませんでした。
これに関しては、srcの`lib/pleroma/upload.ex`をいじって対応しています。けど、やりたいこと事自体は単純なので上記の設定でなんとなく分かると思います(それ自体は有効ではないけど)。
heroku webは、アクセスがないとM30ごとに落ちます。多分そんな感じ。立ち上がるまで結構時間がかかるので、`scheduler`を設定してみたわけですが、`heroku logs`みてみると、`Stopping all processes with SIGTERM`したことがありました。なのでやめといたほうがいいですね。特に`process-scheduler`です。herokuに負担がかかりすぎるみたい。
```sh
$ heroku addons:add process-scheduler -a $APP_NAME
$ heroku addons:create scheduler:standard -a $APP_NAME
$ heroku addons:open process-scheduler -a $APP_NAME
$ heroku addons:open scheduler -a $APP_NAME
```
こちらは、pleromaの初期コマンド等です。
```sh
# sing up
# example : $ heroku run "mix register_user syui syui user@github.com . password123" -a pleroma
$ heroku run "mix register_user <name> <username> <email> <bio> <password>" -a $APP_NAME
# admin user
$ heroku run "mix set_moderator $USER" -a $APP_NAME
# single user mode
$ vim config/config.exs
+ config :pleroma, :instance, registrations_open: false,
+ config :pleroma, :chat, enabled: false
```
https://git.pleroma.social/pleroma/pleroma/wikis/Pleroma%E3%81%AE%E5%85%A5%E3%82%8C%E6%96%B9
https://git.pleroma.social/pleroma/pleroma/wikis/Admin%20tasks
pleromaにもchatありますね。chatは、web, mobileが必要ないならirc server立てればいいだけなんですけどね。
## gnu-social
[gnu-social](https://git.gnu.io/gnu/gnu-social)はphpで書かれていて、しかもcomposerすらないので、つらい感じでした。
ということで、composerを用意してるrepo(branch)から持ってくることにしました。それをカスタマイズしてheroku deployという感じですね。
なお、composer.lockもcommitする必要があります。
```sh
$ git clone https://git.gnu.io/dansup/gnu-social
$ cd !$:t
$ git checkout composer-autoloading
$ php -v
7.2
$ composer update
error
# これでいけました
$ vim composer.json
{
"require": {
"ext-pgsql": "*",
"ext-gd": "*",
"ext-intl": "*",
"php": "^7.2.0",
"illuminate/contracts": "*",
"illuminate/support": "*",
"ramsey/uuid": "^3.0",
"ezyang/htmlpurifier": "^4.10",
"psy/psysh": "^0.8.17"
},
"scripts": {
"post-install-cmd": [
"chmod 644 config.php"
],
"post-update-cmd": [
"chmod 644 config.php"
]
}
}
$ composer update
$ heroku buildpacks:add https://github.com/heroku/heroku-buildpack-php -a $APP_NAME
$ heroku addons:add cleardb:ignite -a $APP_NAME
# trueとかの部分はいらない
$ heroku config -a $APP_NAME | grep CLEARDB_DATABASE_URL
mysql://username:password@hostname/database
$ rm -rf .git
$ heroku git:remote -a $APP_NAME
$ git add .
$ git commit -m "first"
$ git push heroku master
$ open -a Google\ Chrome $APP_NAME.herokuapp.com/install.php
```
gnu-socialの仕組みは単純で、基本的に`install.php`が`config.php`を書き込む処理を行います。ただし、deploy後は、heroku resetの関係でそこで作った`config.php`は、一時的にしか有効ではありません。もちろん、DBに保存されるユーザー情報は別ですが。
ということで、srcにconfig.phpを用意して、deployする必要があるわけなんですけど(.gitignoreに注意)、config.phpの内容がわからないんですよね。そもそも`heroku run bash -a $APP_NAME`してもconfig.phpが見つからないし、権限を考慮してもやっぱり見当たらないので、herokuの仕組み的なものなんだと思いますが、私は、dockerでpreviewして、そのときに作成したconfig.phpをdocker cpして持ってくることを考えました。
install.phpのINSTALLDIRで設定されているはずなんですが、`lib/installer.php`の`chmod 644`を書き直したり、INSTALLDIRを`/app`にしたりしたのですが、heroku runでは見つけられなかった。
ということで、dockerを使って簡潔に行きましょー。こんな感じで持ってきます。一応、CONFIGUREを読んでもいいんですけど、これ読んでやってるほうが時間かかると思う。
```sh
$ sudo docker run -p 8000:80 rudism/gnu-social /root/start
$ open -a Google\ Chrome http://localhost:8000/install.php
$ sudo docker ps -q
$ sudo docker cp xxx:/var/www/gnu-social/config.php .
or
$ sudo docker exec xxx /bin/bash
cat /var/www/gnu-social/config.php
$ sudo docker cp xxx:/var/www/gnu-social/config.php .
or
$ sudo docker commit xxx rudism/gnu-social
$ sudo docker run -it rudism/gnu-social /bin/bash
cat /var/www/gnu-social/config.php
$ sudo docker ps -q
$ sudo docker cp xxx:/var/www/gnu-social/config.php .
```
上記コマンドを見れば、やりたいことはだいたい分かると思います。いろいろな方法があります。この他にも色々ありますね。
しかし、要点は、heroku dbの情報を入力して作成されたconfig.phpを持ってくることが重要だと思います。下記はexampleです。
> config.php
```sh
<?php
if (!defined('GNUSOCIAL')) { exit(1); }
$config['site']['name'] = 'gnusocial';
$config['site']['server'] = 'app.herokuapp.com';
$config['site']['path'] = false;
$config['site']['ssl'] = 'never';
$config['db']['database'] = 'mysql://username:password@hostname/database';
$config['db']['type'] = 'mysql';
// Uncomment below for better performance. Just remember you must run
// php scripts/checkschema.php whenever your enabled plugins change!
//$config['db']['schemacheck'] = 'script';
```
gnu-socialをdocker等で試行錯誤した結果、`ssl`と`pgsql`はどうやっても機能しませんでした。特に、`pgsql`はバグってると思います。`lib/installer.php`みたいなファイルから書き直したんですが、docker上でもheroku上でもまともに動きませんでした。正直、よくわからない。
https://suriyadeepan.gitbooks.io/mesh-guide/content/gnu_social.html
あと、config.phpを置いたのはいいんですが、本来は、644でchmodされるファイルですから、そのパーミッションで行きたいんですけど、なぜか`heroku run bash`, `ls -l config.php`で確かめてみると、意図した権限じゃないんですよね。危険ですよ。composerでscript実行してるはずなんですけどね。(これはherokuの問題だと思う)
その他、gnu-socialはqvitterというpluginがあるのですが、qvitter+pleroma-feでdual bootできるっぽいので、今度試してみようかなーと思っています。(herokuでどこまでできるかわからないけど。directory構造とかnginx設定とかが来ると、ちょっと面倒なことになりそうですね...)
https://git.pleroma.social/pleroma/pleroma-fe/wikis/dual-boot-with-qvitter
### 追記
[qvitter](https://git.gnu.io/h2p/Qvitter)+[pleroma-fe](https://git.pleroma.social/pleroma/pleroma-fe)できた。
ちょっとハマったところとかを解説。
qvitterは、urlに/index.phpを付けずにapiを呼び出すため、fancy urlsをenableにしていない場合、url間違いでapiを呼び出せない。そのためエラーを出すのだけど、herokuなどのPaaSは、nginxなどを直接操作できないため、なかなか面倒でした。
具体的には、`nginx_app.conf`を作って、Procfileのオプションで指定してやればOKでした。
> nginx_app.conf
```sh
location @rewriteapp {
# rewrite all to index.php
rewrite ^(.*)$ /index.php/$1 last;
}
```
> Procfile
```sh
web: vendor/bin/heroku-php-nginx -C nginx_app.conf
```
メモ
```sh
fancy urls = index.php
ex : /index.php/api/user -> /api/user
https://github.com/hannesmannerheim/qvitter/issues/256
> nginx_app.conf
location @rewriteapp {
# rewrite all to index.php
rewrite ^(.*)$ /index.php/$1 last;
}
> Procfile
-C nginx_app.conf
https://devcenter.heroku.com/articles/custom-php-settings
```
あと、ちょっと変な現象に遭遇して、config.phpのsite nameにqvitterを入れてると、plugins/Qvitterを呼び出せなかった気がする。多分、plugins/Qvitterのcodeか何かバッティングしたのかも。なので、サイト名変えました。
## site
そういえば、今回、適当にsnsとか立ててみたわけですが、ついでに自分のメインサイトの方にも追記しておきました。
ですが、そんな立てても使いませんよね。ということで、cssのほうもちょっと作ってみました。使わないやつは赤で表示します。
<span class="blue"></span> [https://mstdn.syui.cf](https://mstdn.syui.cf)
<span class="red"></span> [https://pleroma.syui.cf](https://pleroma.syui.cf)
<span class="red"></span> [http://qvitter.herokuapp.com](http://qvitter.herokuapp.com)
<span class="red"></span> [http://syui-chat.herokuapp.com](http://syui-chat.herokuapp.com)
```html
<span class="blue"></span>
span.blue {
display: inline-block;
width: 10px;
height: 10px;
border-radius: 50%;
background: #61bdcc;
margin: 0px 5px;
box-shadow: 0px 0px 10px #61bdcc;
}
<span class="red"></span>
span.red {
display: inline-block;
width: 10px;
height: 10px;
border-radius: 50%;
background: #f41b16b0;
margin: 0px 5px;
box-shadow: 0px 0px 10px #f41b16;
}
```
これ、他にも使えそうだなー。