使用Nginx、Circus和Goji来搭建Golang Web应用的运行环境
我使用golang来构建web应用程序的运行环境,并将其转化为ansible playbook。适用于Debian 8(jessie)。
-
- 構築用playbook+Vagrantfile
- gojiベースのサンプルWebアプリケーションコード
参考环境是指Mac操作系统下的设定。
我已经将在vagrant上构建的playbook上传到了GitHub。※没有包含HTTPS(TLS)配置。
必需品
-
- virtualbox(公式からdmg)
-
- vagrant(公式からdmg)
- ansible(homebrewにてbrew install ansible)
# cloneしてきて中に移動
git clone https://github.com/reiki4040/playbooks
cd playbooks
# 仮想マシン立ち上げ。(192.168.20.11で起動するので、かぶるとかの場合はVagrantfileいじってください)
# jessieのイメージを指定していて、大きめサイズが落ちてくるのでモバイル環境では注意
vagrant up
# 仮想マシンへのsshの設定追加
vagrant ssh-config >> ~/.ssh/config
# ansibleで自動構築
ansible-playbook -i local/inventory goweb.yml
# apt-get/pip/nginx-buildあたりがしばらくかかります。
# 仮想マシンに入る
vagrant ssh
# ローカルからcurlで確認
curl http://localhost/api/hello
# hello I'm goji! が返ってきます
提供几个要点
-
- nginx側でhttpsを受け取って、goji側へはhttpで接続(playbook構築分にはhttpsは入っていません)
-
- nginx – goji間はunix domain socketを使ってオーバーヘッドを低減
-
- goji+circusを使って、graceful restartを実現
-
- nginx, circusはsystemdで管理(debian jessie向け)
- これらをansibleを用いて自動構築
简单的请求流程和流程管理图像
积分详情
nginx的配置
在上游中指定Unix域套接字文件路径,并通过location指令使用proxy_pass将其发送到goji。Unix域套接字的创建在后面的circus中进行。
upstream goweb_upst {
server unix:/var/run/goweb.sock;
}
# 中略
location ~^/api/.*$ {
proxy_pass http://goweb_upst;
proxy_set_header X-Forwarded-Host $host;
}
使用UNIX域套接字以减少开销。
在将Nginx和Goji连接时,通过使用Unix域套接字,可以减少通信的开销。然而,Nginx和Goji必须在同一台服务器上共存才能实现。
根据情况,有时可以稍微牺牲性能,将nginx和goji服务器分开,采用不同比例的配置,比如nginx N台 + goji M台也是可行的。
为什么要使用Nginx?
不与Go语言直接交互的原因是将前端处理交由nginx进行,以避免特意在Go语言中重复劳动。仅仅接收HTTPS请求就足够了,但是nginx拥有丰富的功能,如简易访问控制、静态分发、反向代理等。一旦nginx可以完成的任务,就交由nginx去做。只有在需要处理细节的时候再使用Go语言来实现。
枸杞 + 马戏团
Goji具有优雅关闭功能,在与cirucs的套接字结合使用时,可以实现优雅重启。
我希望您可以参考这个链接,因为它提供了详细的信息。简单来说,这里提供了一些解释。
-
- golangでsocketを作ると、どうしてもプロセスを再起動する際には閉じてしまう。
-
- circusがsocketを作り、渡すことで、golangプロセスの再起動時にもsocketが維持できる。
- なおかつcircusが新しいgolangプロセスを起動してから、古いプロセスを殺すので、途切れない(らしい)
请注意枸杞的服务方式。
Graceful shutdown的注意事项是,必须使用goji的Serve()、ServeTLS()或ServeListener()来完成。
即使使用了Goji,但如果使用了Golang标准的http.ListenAndServe()等方法启动服务器,服务器本身可以启动且可用,但无法优雅地关闭,会在处理过程中被断开连接。
在Circus上运行golang应用程序的配置(circus.ini)
[circus]
statsd = 1
[watcher:goweb]
cmd = /opt/goweb/goweb -fd $(circus.sockets.web)
stop_signal = SIGINT
numprocesses = 1
use_sockets = True
stdout_stream.class = FileStream
stdout_stream.filename = /var/log/goweb/stdout.log
stdout_stream.refresh_time = 0.3
stdout_stream.max_bytes = 1073741824
stdout_stream.backup_count = 2
stderr_stream.class = FileStream
stderr_stream.filename = /var/log/goweb/stderr.log
stderr_stream.refresh_time = 0.3
stderr_stream.max_bytes = 1073741824
stderr_stream.backup_count = 2
[socket:web]
path = /var/run/goweb.sock
family = AF_UNIX
[watcher:goweb]のgowebは、circus上で動かすプログラムの名称です。circusctl reload gowebなどで使います。
gojiのgraceful shutdownはSIGINTなので、stop_signal = SIGINTを指定しています。(circusデフォルトは、SIGTERM)
通信用のsocketは[socket:web]で宣言して、cmdの-fd $(circus.sockets.web)で渡しています。
stdoutとstderrをファイルに出力しています。今回のサンプルだと、gojiのデフォルトの動作ログがstderrに出力されます。stdoutには私が適当に出したリクエスト時のmiddlewareのログが出ます。
nginx和circus都是使用systemd进行管理的。
Debian从8(jessie)开始转向systemd。虽然将脚本放置在init.d文件夹下仍然可以正常运行start/stop/restart等命令,但我们会将其定义为systemd的服务单元。由于内容遵循官方指南,因此还想查询其他选项等。
-
- circusのservice unit
nginxのservice unit
将它们放置在/etc/systemd/system/目录下,然后可以像执行systemctl start circus命令的方式来使用。在debian 7(wheezy)中,类似于/etc/init.d/和service命令之间的关系。
更新 unit 文件后,运行 systemctl daemon-reload。
如果更新了systemd的unit文件,则需要调用”systemctl daemon-reload”才能成功。最初仅仅调用了”systemctl reload circus”,但失败了。
Warning: Unit file of circus.service changed on disk, 'systemctl daemon-reload' recommended.
Job for circus.service failed. See 'systemctl status circus.service' and 'journalctl -xn' for details.
自动化运维
可以对任务进行标记,并将其分为在构建时全部执行或者在更新配置文件等情况下执行的任务。
ansible-playbook -i local/inventory goweb.yml
根据需要,我们会为每个个体打上标签,若需要重新加载/重新启动,则会添加通知并调用处理器。
ansible-playbook -i local/inventory goweb.yml -t update-nginx-conf
- name: nginx | put nginx.conf
tags:
- nginx
- update-nginx-conf
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf owner=root group=root mode=644
notify:
- reload nginx
- name: reload nginx
service: name=nginx state=reloaded
如果单独放置,需要的标签。
在开发过程中,如果需要多次执行某个操作,建议使用别名或包装脚本来简化操作。
总结
使用nginx + circus + goji可以运行golang的Web应用程序。一旦建立了基本的运行环境,就可以继续开发应用程序。
顺便提一句,如果不考虑优雅重启,直接使用systemd在nginx和golang之间运行也是一种简单的方法。
使用Ansible进行配置,可以提高效率,因为它可以在每次部署或变更时使用。虽然创建playbook可能需要一些成本,但即使忘记做了什么,也无妨,而且相对较容易地交接给其他人。
请你引用以下的内容
仅需要一个选项
-
- Goで書いたWebサーバを本番(VPS)で動かす
-
- Goji のアプリケーションサーバーを Circus で管理する
-
- Go で書いたサーバーを管理するには circus が便利
-
- Golang_ads_deliver // Speaker DeckGolang_ads_deliver // Speaker Deck
-
- Circus Deployment
-
- Systemd入門(4) – serviceタイプUnitの設定ファイル
- nginx systemd service file