9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

nginx+circus+go(net/http利用)でwebアプリケーションの動作環境構築

Last updated at Posted at 2018-03-22

概要

goのWebappをOSがUbuntu 16.04 LTSのProduction環境で動かすための環境作りについてまとめています。フロントの処理をnginx,プロセス管理をcircusで行いそれぞれのメリットを享受できるようにしています。既にGOJIで対応されているケース等サンプルがありますが、net/httpのみのケースだと情報が点在していたのと、circusを入れるときにpythonの依存関係の問題ですんなり入らなかったのでそこら辺を参考にしていただければと思います。

Webアプリケーションのサンプル

ファイルディスクリプタをパラメータで渡している他、ない場合はTCPポート8080で起動できるようにもしています。

main.go
package main

import (
    "encoding/json"
    "flag"
    "fmt"
    "log"
    "net"
    "net/http"
    "os"
    "os/signal"
    "syscall"
)

var port = flag.Uint("port", 8080, "port to listen")
var fd = flag.Uint("fd", 0, "File descriptor to listen and serve.")

//初期化処理
func init() {
    flag.Parse()
}

//メイン
func main() {

    sigchan := make(chan os.Signal)
    signal.Notify(sigchan, syscall.SIGTERM)
    signal.Notify(sigchan, syscall.SIGINT)

    var l net.Listener
    var err error

    if *fd == 0 {
        log.Println(fmt.Sprintf("listening on port %d", *port))
        l, err = net.ListenTCP("tcp", &net.TCPAddr{Port: int(*port)})
    } else {
        log.Println("listening on socket")
        l, err = net.FileListener(os.NewFile(uintptr(*fd), ""))
    }

    if err != nil {
        log.Fatal(err)
        panic(err)
    }

    go func() {
        mux := routes()
        log.Println(http.Serve(l, mux))
    }()

    <-sigchan
}

//ルーティング
func routes() (mux *http.ServeMux) {
    mux = http.NewServeMux()

    //実際のアプリでは複数ハンドラーを記載
    mux.HandleFunc("/somepass", SomeHandler)


    return
}

//サンプルJsonを出すための構造体(実際では意味のある構造体を作る方が良いです)
type V map[string]interface{}

//ハンドラーサンプル
func SomeHandler(w http.ResponseWriter, r *http.Request) {

    values := V{"testKey": "testValue"}

    content, err := json.Marshal(values)
    if err != nil {
        w.WriteHeader(http.StatusInternalServerError)
        return
    }

    w.Header().Add("Content-type", "application/json")

    w.WriteHeader(http.StatusOK)
    w.Write(content)
}

nginxの設定

通常の手順通りにnginxをインストール後、UNIXドメインソケットに繋ぐように設定を変更します。

server {

  (中略)

  location / {
    proxy_pass http://backend_goweb;
  }

  (中略)
}

upstream backend_goweb {
    server unix:/var/run/goweb.sock;
}

circusの設定

インストール

apt-get install -y python-pip libzmq-dev libevent-dev python-dev python-virtualenv
pip install circus
pip install circus-web

設定ファイル作成

以下のような設定をcircus.iniとして作成。コマンド名、ログのパスは適宜変更してください。これでUNIXドメインソケットで起動することができる他、標準入力と標準出力がそのままログとして出せるようになります。

circus.ini
[circus]
statsd = 1

[watcher:goweb]
cmd = /pass_to_go_application/application_name -fd $(circus.sockets.web)
stop_signal = SIGINT
numprocesses = 1
use_sockets = True
copy_env = True

stdout_stream.class = FileStream
stdout_stream.filename = /var/log/any_log_pass/stdout.log

stderr_stream.class = FileStream
stderr_stream.filename = /var/log/any_log_pass/stderr.log

[socket:web]
path = /var/run/goweb.sock
family = AF_UNIX

実行

# circusd circus.ini 
2018-03-22 15:46:58 circus[4092] [INFO] Starting master on pid 4092
2018-03-22 15:46:58 circus[4092] [INFO] sockets started
2018-03-22 15:46:58 circus[4092] [ERROR] exception __init__() takes exactly 3 arguments (4 given) caught
  File "/usr/local/lib/python2.7/dist-packages/tornado/gen.py", line 315, in wrapper
    yielded = next(result)
  File "/usr/local/lib/python2.7/dist-packages/circus/arbiter.py", line 529, in start
    self.ctrl.start()
  File "/usr/local/lib/python2.7/dist-packages/circus/controller.py", line 116, in start
    self.check_delay, self.loop)

上記のエラーが出て動きません…。

https://github.com/circus-tent/circus/issues/1059
ライブラリの依存関係で引っかかっているようなので、以下で回避。

# pip install tornado==4.5.3 circus

ソケットを削除して、再度トライ

# rm /var/run/goweb.sock
# circusd circus.ini 
2018-03-22 15:54:23 circus[10462] [INFO] Starting master on pid 10462
2018-03-22 15:54:23 circus[10462] [INFO] sockets started
2018-03-22 15:54:23 circus[10462] [INFO] Arbiter now waiting for commands
2018-03-22 15:54:23 circus[10462] [INFO] goweb started
2018-03-22 15:54:23 circus[10462] [INFO] circusd-stats started
2018-03-22 15:54:23 circus[10467] [INFO] Starting the stats streamer

無事起動しましたので、デーモンとして実行します。

# circusd --daemon circus.ini

再起動出来ることも確認します。

# circusctl restart 
ok

http://(your domain)/somepassで{"testKey":"testValue"}というJSONが返って来れば成功です。

参考

  • 本家。
  • 本家Github。
  • GOJIで対応されているケース。参考にさせていただきました。
  • 同様GOJIで対応されているケース。Circusの使い方等参考になりました。
  • 本番環境を作るという点や、その中でcircusをどう使うかという点で非常に参考になりました。
9
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?