さくらインターネットのレンタルサーバーでGOで書いたCGIを動かした(苦労)話
作っているCGIは一言で言えば、データベースから利用者の指定した条件で引っ張ってきたデータを表やグラフにして提供する、というようなものです。
自分でサーバーを立てて、みたいなことをやる機材も気力もないのでレンタルサーバーを使うことにします。
・GOのコンパイラーが使えて
・GOで書いたCGIを動作させてることができる(許されている)
レンタルサーバーということになるのですが、今契約しているさくらインターネットのレンタルサーバーがこれに該当します。
ただ残念なことに私が契約しているサーバーはOSが「FreeBSD 9.1-RELEASE-p24 #0: Thu Feb 5 10:03:29 JST 2015」ということで、これにはGOのコンパイラーは入っていません。何年か前からOSは徐々に新しいバージョンへ移行しているようですが、私のサーバーのOSの更新がいつになるのかよくわかりません。そこで新しいサーバーを借りてみました。こちらは「FreeBSD 11.2-RELEASE-p14 #0: Mon Aug 19 22:38:50 UTC 2019」とGOが使えるやつでした(お試し期間があるので、その間にチェックが可能です)
GOは「go version go1.15.5 freebsd/amd64」でした。
レンタルサーバーはMySQLとSSHが使える中でいちばんお安いスタンダードプランで月524円でした。
ところでFreeBSD 9.1の方にGOのコンパイラーを入れてはどうかとも考えるのですが、これはやめた方がよさそうです。
FreeBSD 9.1ではコンパイラのバイナリは古いバージョンのものしか動かないのですが、ググると「Go 1.4.3 バイナリで Go 1.7.4 ソースをビルドする 」みたいな話がありました。実際1.4.3のコンパイラは動くのを確かめたのですが...
・MySQLのアクセスのために"github.com/go-sql-driver/mysql"を使っていて
・このSQL Driverは「Go 1.10 or higher. We aim to support the 3 latest versions of Go.」
・一方「Go 1.10 now requires FreeBSD 10.3 or later」
ということでFreeBSD 9.1でどうにかしようというのはムリみたいです。11.2で作ったモジュールを9.1に持っていっても動かないのは確認済みですし w
--------------
GOコンパイラーが使える環境は整ったのでCGIのコーディングなのですが、今回は次のようなパッケージを使用しました。
1. "net/http"
2. "html/template"
3. "github.com/PuerkitoBio/goquery"
4. "database/sql"
5. "github.com/go-sql-driver/mysql"
6. "github.com/ajstarks/svgo/float"
7. "github.com/dustin/go-humanize"
--------------
3.、4.、5.はMySQLのアクセス用です。
これについてはいろんな記事があるのでそういうのを参照すればいいのですが、次の問題には手間取りました。
「技術向上 - MySQL - invalid memory address or nil pointer dereference【Go】」
私と同じところではまる人もいそうな気がするので紹介しておきます。
--------------
6.はグラフを作るのに使っています。まあ、グラフができさえすればいいということであれば、それなりのパッケージがあるのですが、(SVG大好き人間なので)自前で作っています。これからSVGの特色を生かしていければと思っています。
なお"github.com/ajstarks/svgo/"というのもあり、これだと座標をint型で与えることになるのでグラフを作るというような目的であればfloatのついた方(座標はfloat64で与えます)がいいでしょう。intの方で作って拡大・縮小の機能を利用したほうがいのかもとも思いますが。
これについても一点だけ書いておくと、SVGを書き出すファイルはClose()する前にFlush()する必要があります。これをしないとSVGが途中でぶった切れてしまいます。
--------------
7.は表に数値を表示するとき3桁ごとにカンマを入れるという目的で使っています。
--------------
ド素人で、最初は簡単なCGIなのでstdoutにhtmlを出力すればいいんだろうくらいに考えていたのですが、あさはかな考えでちゃんと1.とか2.を使うべきです。
"net/http"はおもしろくて、CGIとして作ったプログラムがソースを一行書き換えるだけでWebサーバーのように動きます。
if OS == "windows" {
// Webサーバーとして起動
http.ListenAndServe(":8080", nil)
} else { // "freebsd"
// CGIとして起動
cgi.Serve(nil)
}
このおかげで
・Windowsでプログラムを作り、Windows10上でテストする。
・テストが完了したらレンタルサーバーにftpで上げてコンパイルする。
というときWindowsでWebサーバーを用意する必要がありません。もっともWindowsとFreeBSDでまったく同じソースが動くわけでもないです。パスがからむところは注意した方がいいようです(要するにWebサーバーから見える景色とCGIから見える景色は異なる)
一例を上げると
if OS == "windows" { // SVGファイルの置き場所
http.Handle("/", http.FileServer(http.Dir("public")))
}
rootPath := ""
if OS == "freebsd" {
rootPath = os.Getenv("SCRIPT_NAME")
}
http.HandleFunc(rootPath+"/top", HandlerTopForm)
.
.
上の方はSVGファイルを表示させるhtmlを
<img src="/TEST/public/46.svg" alt="" width="100%">
のようにして、表示できるようにするためです。
下の方はURLがWindowsの場合
http://localhost/top
になるのに対しレンタルサーバーでは
http://xxx.sakura.ne.jp/CGI.cgi/top
みたいになることへの対応です。
以上、コーディングはWindowsだったら/FreeBSDだったらとなっていますが、意味的にはWebサーバーだったら/CGIだったらということです。これらはもっと簡単な対策があるのかもしれませんが...
--------------
ところで、実際のところソースをレンタルサーバーに持っていってコンパイルすると頻繁に強制終了が発生してコンパイルできないことがあります。このとき動いているプロセスをkillするとコンパイルできるので、どうやら何かのリソースの制限みたいなのにひっかかっているようです(同じような現象として「go get」を行ったときの強制終了というのもあります)
この対策は簡単で、Windowsでテストが終わったら、そのままクロスコンパイルしてロードモジュールを作りこれをアップロードすればOKです。
書き忘れましたが Windows側は
go version go1.15.5 windows/amd64
です。IDEはliteideを使っています。
--------------
"html/template"は、面倒くさそうだなあと思って使い始めたのですが、こんなに便利なものはないです。コーディング量が画期的に減るということもあるのですが、ちょっとした変更がソースではなくテンプレートの方で済ませられるのでらくちんです。
ちょっと複雑なhtmlになると最初どうしたらいいかよくわからなかったのですが、
1. htmlを複数に分割して、それぞれにデータを与える。
2. htmlの構造に合わせた構造体を作る(構造体を作るときどのようなhtmlで使うかを意識しておく)
のどちらかで(あるいは両方を組み合わせれば)対応できるようです。2.の方がすっきりしているようですが、実際はかなり泥臭い構造体になってしまうので、まあどっちもどっちみたいな気がします。
1.の方はこんな感じです。
tpl := template.Must(template.ParseFiles(
"templates/top1.gtpl",
"templates/top2.gtpl",
))...
...
if err := tpl.ExecuteTemplate(w, "top1.gtpl", eventlist); err != nil {
...
...
}
......
if err := tpl.ExecuteTemplate(w, "top2.gtpl", eventinf); err != nil {
...
...
}
それからHTML5だとinputをformとは別に書いたり、formの中に(formactionを使って)複数のsubmitをおいたりできるので、このあたりを利用するとレイアウトの自由度が格段に大きくなります。
以上、雑然としていますが、私がつまずいたポイントを思い出しながら書いてみました。
他にもviでUTF-8が表示できないとか、Windows側のMySQLでUTF-8が使えない、と言ったこともあったのですが、これはCGIに限ったことではないので省略します。
ここまで来るのにずいぶんググったのですが、なかなか自分が必要とする情報に行き着きませんでした。そういうとき少しは参考になるのではと思います。
最近のコメント