herokuにルート権限はあるのか?
4月からはもっぱらherokuにつきっきりです。
ようやくherokuの全貌をつかめてきた感覚があり、前は読んでもわからなかった記事も少しづつではありますが、理解できるようになってきたところです。
今までローカルで動かしていたプログラムを自動プログラムに書き換えて、Webアプリで提供するという夢があと一歩のところまで来ました。
長かったです。
4月に入社して飲み会ラッシュの中、同期にはちょっとづつ飲み会苦手キャラを浸透させつつ、飲み会を断りやすい雰囲気を作って、5時に帰れる日は直帰してプログラムを書いて...
苦労に苦労を重ね、そして、大きな問題が発生しました。
まずはじめにroot権限とは?
ubuntuユーザはpip install ライブラリ を行う際、たいていsudoをつけます。
sudoというのはルート権限であることの宣言であり、sudoをつけることでファイルの書き込み・変更等を許可することになります。
ライブラリによってはファイルの書き換えを行う必要があるので、sudoをつけなければ、ファイルの書き込みができません的なエラーを発生させる要因になります。
たしか、windowsでは、コマンドプロンプト自体を起動する際にroot権限で起動するか否かを選択したはずです。
ここらへんの違いは設計思想の違いなんですかね。
herokuにroot権限はあるのか?
herokuはIaas系のサービスで、のせるOSは自由に選べます。(toolbeltという形で選択が可能です)
私はherokuにはUbuntuの環境を構築したのですが、なぜかheroku上でsudoコマンドが使用できません。
これが何を意味するかというと、ファイルを書き換えるライブラリがインストールできない、ということです。
これは詰みです。
本来、herokuからインストールできないライブラリ等はbuildpacksによってソースから直接インストールすれば良いのですが(私の解釈が間違ってなければ)、
今回はインストールできないわけではなくて、heroku上で動かすにはファイルを書き換える必要がある、ということなのでbuildpacksでは解決できません。
3日かけて(貴重な土日と5時帰りの月曜の夜)色々とgoogleで解決方法を探しまわったのですが、無理でした。
普通に考えてIaasでroot権限がないって考えにくいなぁと思いつつ、ただ自分では解決できないので諦めることにしました。
ただ一つ、良いことがあるとすれば、このエラーを餌に同期の中からプログラミング好きな人をたくさん見つけれたことです。
「プログラミング得意!?このエラーでてるねんけど、わかる?教えて!」みたいなノリで声をかけまくりました。
herokuのタイムゾーンを変更したらAPSchedulerが動いた話
APSchedulerがピクリともしない問題発生
APSchedulerをcron式タイムスケジュールで0:20に命令を実行したいのですが、なぜか0:20になってもピクリともしませんでした。
from apscheduler.schedulers.blocking import BlockingScheduler sched = BlockingScheduler() #0:20 @sched.scheduled_job('cron', hour=0, minute=20) def scheduled_job(): print('This job is run every weekday at 0:20.') sched.start()
時間設定の仕方はhour=0、minute=20で0:20を指すはずだが...
APChedulerをcron形式で動かすドキュメントを読んだので、きっと間違いはないはず。
apscheduler.triggers.cron — APScheduler 3.3.1.post4 documentation
だが、動かぬ。
herokuのタイムゾーンをJSTに変更
まず、herokuの現在のタイムゾーンを念の為確認。
#heroku上でbashを起動してから。 heroku run bash #タイムゾーンを確認 date
heroku config:add TZ=Asia/Tokyo
無事解決しました
最近は株価の分析には時間が割けてなくて、heroku上でシステムを動かすことにばかり時間を費やしています。
あまり楽しくはありませんが、これから自分一人でシステムを作っていこうと思うと避けて通れない道だと思っています。
なので、焦らず地道にドキュメントを読みながら作業を進めています。
herokuでのスケジュール管理にAPSchedulerを使ってみる
目次
- herokuで定期的にファイルを実行したいとき何を使っていますか?
- cron...?
- heroku scheduler...?
- cronよりもheroku schedulerよりAPSchedulerが良い
- heroku上でAPSchedulerを使ってみる
- 用意するもの
- まとめ
- 参考
herokuで定期的にファイルを実行したいとき何を使っていますか?
cron?
heroku scheduler?
APScheduler?
cron...?
DBの更新、データの取得、バックアップの保存などのスケジュールの管理はモダンなWebアプリには必須機能です。
ubuntuのデフォルトでインストールされているcronはあらゆるスケジューリングが可能で、上記のほとんどのことはcronによって達成することが出来ます。
ですが、cronはサーバー上で動作することもあり、Webアプリのテストをローカル環境で行うことを考えると、もっと高いレイヤーのアプリケーションのインスタンスで動作するほうが勝手がいいです。
heroku scheduler...?
herokuにはスケジュール管理のためのファンタスティックなアドオンが用意されています。
このheroku schedulerはシンプルなタスクを10分、1時間、一日、複数の間隔での実行が可能です。
しかし、5分や37分など中途半端な時間での実行は難しいです。
cronよりもheroku schedulerよりAPSchedulerが良い
アプリケーションのインスタンスで動作し、かつ、中途半端な時間でも簡単にスケジュールの管理が可能なのが、APSchedulerです。
これはPython製のライブラリなので、私のようにwebアプリを全てpythonで完結させたい人たちにはもってこいです。
heroku上でAPSchedulerを使ってみる
ということで、1分おきに現在時刻をDBにインサートするプログラムを書いてみます。
最終的な出力はこうなります。
herokuのログを見ると、1分おきにDBを更新していることがわかります。
用意するもの
herokuでアプリを運用するために必要なファイルは以下です。
#適当に用意してください runtime.txt requirements.txt #以下は今から作成します Procfile gettime.py time.db timeclock.py
スタート。
#screamtimeという名前のアプリを作ります heroku create screamtime
次に、gettime.pyを作成します。
import sqlite3 import pandas as pd import datetime #現在時刻を取得する now = datetime.datetime.today() hour = now.hour minute = now.minute #DataFrame形式にぶち込む #普通はSQL文書いてインサートすると思いますが、 #私がDataFrame形式に慣れているので、こちらを使用していますが、各自なれた方法でお願いします time_df = pd.DataFrame({"Hour" : [hour], "Minute" : [minute]}) #db作成 dbname = "time.db" #dbコネクト conn = sqlite3.connect(dbname) c = conn.cursor() #dbのnameをtime_dfとし、読み込んだcsvファイルをsqlに書き込む #if_existsでもしすでにtime_dfが存在していても、置き換えるように指示 time_df.to_sql("times", conn, if_exists="replace") #作成したdbを見てみる select_sql = 'select * from times' for row in c.execute(select_sql): print(row) conn.close()
これをgettime.pyという名前で保存します。
次は、今作成したgettime.pyをAPSchedulerで定期的に実行させるコードを書きます。
from apscheduler.schedulers.blocking import BlockingScheduler import os sched = BlockingScheduler() #間隔は1分ごとにしています #minutesではなくてhourに変更したら、時間での指定も可能です @sched.scheduled_job('interval', minutes=1) def timed_job(): print("Let's start") os.system("python gettime.py") sched.start()
これをtimeclock.pyという名前で保存します。
最後にProcfileを作成します。
clock: python timeclock.py
これで、herokuにclockのファイルであるということを宣言します。
ファイルが全て揃ったので、あとはherokuに上げるだけです。
念の為、herokuに上げるまでのgitでの手順を載せておきます。
git init git add . git commit -m "first commit" git push heroku master
エラーなく行けば、これでherokuには「1分おきに現在時刻をDBにインサートするプログラム」がアップロードされました。
以下でherokuにclockをスケールします。
heroku ps:scale clock=1
上手くスケールされたことを確認して。
heroku ps |< 数分待ってからherokuのログを見てみます。 >|| heroku logs
以上で「1分おきに現在時刻をDBにインサートするプログラム」が完成しました。
まとめ
APSchedulerはとても簡単にスケジュールの管理が行うことができます。
コードもpythonで書くことができるので、使い勝手がとても良いです。
cronよりもheroku schedulerよりもAPSchedulerが良いんじゃあないでしょうか!?
herokuのworker dynoとweb dynoの違いって何?
目次
dyno?
herokuでは、プロセスの処理はdynoによって行われます。
プロセスの処理とはHTTPのリクエストやレスポンス、バックグラウンド処理などです。
dynoは3種類あり、処理をするプロセスの種類によって使い分けられます。
- web dyno
- worker dyno
- one-off dyno
herokuを勉強していて、dynoはheroku内の独特の単位で一番はじめにつまづいたのでまとめておきます。
web dyno
HTTPのリクエスト・レスポンスを処理します。
ユーザーからのリクエストはweb dynoが処理するので、webアプリが行う処理の大半はweb dynoによって行われています。
worker dyno
バックグラウンド処理を行います。(ほぼweb dyno以外の処理)
バックグラウンド処理とは、例えばAPIsからのデータ取得やRSSフィードの読み込み、画像のリサイズ、S3へのデータ送信などが当てはまります。
one-off dyno
一時的な処理を行うためのdyno。
heroku run
などのherokuコマンドを実行したときに使用されるdynoです。
ログ
これらdynoの動作状況はログを見ることによって確認できます。
#ログの確認 heroku logs -t #見たい行数を指定する(最大1500行まで) heroku logs -n 200
Control+Cでログの出力を中止できます。
ログは直近の1500行のみしか表示されず、ログの保存を行う場合はアドオンを追加します。
使用中のdynoを確認する
heroku ps
このコマンドで現在、使用しているdynoを確認することができます。
まとめ
worker dynoとweb dynoの違いは、まとめると処理するプロセスの違い、ということになります。
Webアプリによって必要な処理は違ってくるので、アクセス数がひたすら多いWebアプリはweb dynoを増やしたり(=スケーリング)、バックグラウンドでの処理が多いならworker dynoを増やしたりと適宜変更しながら運用していきたいですね。
cronで定期的にフォルダを作成してみる(Ubuntu 16.04)
色々とcronについて勉強したので、今回はcronで一分毎にTestという名のフォルダを作成するまでやってみようと思います。
cronとは
設定したファイルを定期的に実行させるためのツール
crontabに登録されているcronを確認
crontab -e
編集等はvimで行うことになります。
もし、まだcronがひとつも登録されていなければ、no crontab for <ユーザー名> が表示されます。
crontabは /etc の中にあるのですが、私はvimの使い方がわからなかったので、sublimetext(テキストエディタ)に移してから編集していましたが、これではうまくいきませんでした。(編集しても内容が反映されない)
おそらく、編集・実行の権限が与えられていなかったからだと思います。
諦めてvimの使い方をドットインストールで学んできて、ようやく編集することができました。
(vimは癖が強すぎるが、慣れれば最高に使いやすいツールになることの片鱗をつかめた!)
そもそもcronが動作しているのかをチェック
sudo service cron status
active(running)が表示されていれば正常に動作しています。
また、cronの動作ログもこれで確認可能です。
基本的にcronの動作ログは /var/log のsyslogファイルに書かれています。
なので。
cd /var/log cat syslog
で、確認可能ですが、いちいちsyslogを見に行くのも面倒なので、sudo service cron status で確認したほうが楽です。
定期的に実行させるファイルを作成
/home にtest.shというファイルを作成します。
#!/bin/shはシェルスクリプトであるということを明示するためのものです。
mkdir Test にしているので、cronが上手く実行されれば/home にTestという名のフォルダが作成されるはずです。
(mkdirでもなくても大丈夫です、今回はcronが動作しているかどうかを確認したいため、適当にmkdirにしました)
#!/bin/sh mkdir Test
crontabからcronを設定
crontab -e
* * * * * /bin/sh /home/ubuntu/test.sh > /dev/null 2>&1
時間は1毎分に設定しています。
エラーが発生していた場合、すぐに確認できるので。
また、cronによって実行するファイルがシェルスクリプトであることを明示するために /bin/sh を記述しています。
cronでの時間設定の書式は以下のサイトがわかりやすかったです。
これでcronの設定は終わったので、ログを見てみます。
3月 30 23:09:01 tk CRON[4148]: (ubuntu) CMD (/bin/sh /home/test.sh)
CMDとはcronが実行したコードを示しています。
ログを見る限り、cronは正常に実行されています。
ディレクトリを見てみると...
これが...
テンプレート ピクチャ test.sh デスクトップ ミュージック ドキュメント 公開 ダウンロード ビデオ
1分後...
Testフォルダが作成されたので、無事にcronが動作したようです。
Test ダウンロード ビデオ テンプレート ピクチャ test.sh デスクトップ ミュージック ドキュメント 公開
MTAというエラーが出た場合
cronはエラーが出た際、メールで通知しようとするのですが、メールの設定を行っていない場合にMTAというエラーが出ます。
postfixなどでメールの設定を行うことでこのエラーは解決できます。
以下のサイトがわかりやすかったです。
bootの容量がいっぱいなのに、古いカーネルが消せない問題(ubuntu 16.04)
bootの容量がいっぱいすぎて、新しいカーネルに更新できず、まわりまわって他のソフトウェアもアップデートできないという問題が発生しました。
試しにbootの容量を確認してみると...
df /boot
Filesystem 1K-blocks Used Available Use% Mounted on /dev/sda7 236876 224404 0 100% /boot
見事に100%!!
100%って何か気持ち良いですね!元気がでました。
だがしかしだけれども、何とかbootの容量を空けないと身動きができないので、古いカーネルを消そうとしました。
とりあえず、現在使用中のカーネルは...
uname -r
4.4.0-63-generic
そして、boot内にあるカーネルは...
dpkg --get-selections | grep linux-
linux-base install linux-firmware install linux-generic install linux-headers-4.4.0-57 install linux-headers-4.4.0-57-generic install linux-headers-4.4.0-59 install linux-headers-4.4.0-59-generic install linux-headers-4.4.0-62 install linux-headers-4.4.0-62-generic install linux-headers-4.4.0-63 install linux-headers-4.4.0-63-generic install linux-headers-4.4.0-64 install linux-headers-4.4.0-64-generic install linux-headers-4.4.0-66 install linux-headers-4.4.0-66-generic install linux-headers-4.4.0-70 install linux-headers-4.4.0-70-generic install linux-headers-generic install linux-image-4.4.0-21-generic deinstall linux-image-4.4.0-53-generic deinstall linux-image-4.4.0-57-generic install linux-image-4.4.0-59-generic install linux-image-4.4.0-62-generic install linux-image-4.4.0-63-generic install linux-image-4.4.0-64-generic install linux-image-4.4.0-66-generic install linux-image-4.4.0-70-generic install linux-image-extra-4.4.0-21-generic deinstall linux-image-extra-4.4.0-53-generic deinstall linux-image-extra-4.4.0-57-generic install linux-image-extra-4.4.0-59-generic install linux-image-extra-4.4.0-62-generic install linux-image-extra-4.4.0-63-generic install linux-image-extra-4.4.0-64-generic install linux-image-extra-4.4.0-66-generic install linux-image-extra-4.4.0-70-generic install linux-image-generic install linux-libc-dev:amd64 install linux-sound-base install syslinux-common install syslinux-legacy install
放置っぷりが明らかに...
古いカーネルはたくさんあるし、最新のカーネルにアップデートもしてないし...
現在使用しているのが、4.4.0-63なので、それ以前のカーネルは削除しようと思います。
sudo apt-get autoremove --purge linux-image-4.4.0-57-generic
すると未解決の依存関係があるようで、削除できません。
パッケージリストを読み込んでいます... 完了 依存関係ツリーを作成しています 状態情報を読み取っています... 完了 以下の問題を解決するために 'apt-get -f install' を実行する必要があるかもしれません: 以下のパッケージには満たせない依存関係があります: linux-image-extra-4.4.0-57-generic : 依存: linux-image-4.4.0-57-generic しかし、インストールされようとしていません linux-image-extra-4.4.0-70-generic : 依存: linux-image-4.4.0-70-generic しかし、インストールされようとしていません linux-image-generic : 依存: linux-image-4.4.0-70-generic しかし、インストールされようとしていません E: 未解決の依存関係です。'apt-get -f install' を実行してみてください (または解法を明示してください)
'apt-get -f install'を実行したとしても、bootの容量がいっぱいなのでどのみちインストールはできません。
sudo apt-get -f install linux-image-4.4.0-70-generic
けっこうな詰みです。
古いカーネルを消そうとしても、未解決の依存関係が原因で消せない、にもかかわらず、その未解決の依存関係を修復するために最新のカーネルをインストールしようとしてもbootの容量がいっぱい...
ということで最終手段、依存関係を無視して古いカーネルを消すことにしました。
cd /boot ls boot
一番古い57系のものを色々と削除。
sudo rm linux-image-4.4.0-57-generic
ここでもう一度容量を確認。
df /boot Filesystem 1K-blocks Used Available Use% Mounted on /dev/sda7 236876 184731 35608 84% /boot
無事にbootを整理できました。
以上終わり!
SQLite3をPandasから操作する
SQL文の操作を覚えるのが面倒...
select * from tbl_nameまでが覚えれる限界でした。
データの検索・変更などのwhere文等を覚えるのが面倒かつ、逃げ道を見つけてしまったので、逃げ道のほうに行くほかない。
ということで、SQLite3のデータをPandasのDataFrame型に出力してから、DataFrame型でデータを加工するという技を身につけたので、ここにメモとして保存します。
これだと、Pandasでデータをいじくり回して、最後にSQLite3に保存するだけなので、楽ちん。
Pandasの万能さを実感し、かつ、SQL文を覚える機会をまたまた失ったわけであります。
#SQLite3をインポート import sqlite3 import pandas as pd #db dbname = "code.db" #dbコネクト conn = sqlite3.connect(dbname) c = conn.cursor() #dbを見てみる pd.read_sql_query("select * from code_7776", conn) #dbをpandasのDataFrame型で読み込む df = pd.read_sql("select * from code_7776", conn) #dfの中身はすでにDataFrame形式 #データの変更等はPandasでのデータいじりの操作方法でいける df["Altering"] = None print(df) #データをいじり終わったら、SQLite3のdbに書き込む df.to_sql("code_7776", conn, if_exists="replace")
【参考】