Home
Slides
Blog
slide.seike460.com
Home
Slides
Blog
Home
Slides
Fukuoka.go #13 + Roppongi.go
Fukuoka.go #13 + Roppongi.go
Fukuoka.go #13 + Roppongi.go
2019年9月13日
Go
Go
Golang
Microservices
Keyboard Shortcuts
←
→
Navigate slides
Space
Next slide
F
Fullscreen
ESC
Exit fullscreen
Home
First slide
End
Last slide
B
.
Pause
S
Speaker notes
?
Reveal.js help
Close
## Goにおけるデーモン化 fukuoka.go #13 清家史郎(@seike460)
###### Who? Fusic Co., Ltd.  清家史郎  @seike460 [](https://twitter.com/seike460) [](https://www.facebook.com/seike460) [](https://github.com/seike460)
### tech - Program Language - PHP - Go - infrastructure - Server - AWS - infrastructure as code - Network - Other - Serverless - Vue.js - React
### OSS products - s3ry (s3 prompt cli) - https://github.com/seike460/s3ry - utakata (Serverless Slack Notificatier) - https://github.com/seike460/utakata ### Organizer - Serverless Meetup Fukuoka
#### Agenda - 何がしたいの? - どうやってやるの? - 纏め
### 何がしたいの? - サーバーの情報を集めるエージェントを作りたい - デーモン化したい - なぜGoなのか? - 様々な情報を並行して取得する為gorutineを使いたい
### デーモン化したい!どうやってやるの? - Goで頑張る - Goで頑張らない
### Goで頑張る - デーモン実装 - 最低条件 - TTYと切り離してバックグラウンド実行 - 実行プロセスのPIDを保持して停止時にsignalを送信出来るようにする - 付加価値 - カレントワーキングディレクトリをシステムルート("/")にする - 標準入力、標準出力、標準エラー出力を/dev/nullにリダイレクトする
- TTYと切り離してバックグラウンド実行 os.ArgsよりTTYが起動したプロセスと プログラムが起動したプロセスを判別して処理を分ける ``` if len(os.Args) == 1 { // TTY起動時はバックグラウンド用のプロセス起動 cmd := exec.Command(os.Args[0], "--child") cmd.Start() } else { for { // ここに実際の処置を書く } } ```
- 実行プロセスのPIDを取得して保持する os.GetpidによりPIDを取得後PIDファイルに保存する ``` // PIDを取得 pid := os.Getpid() // ファイル作成 file, err := os.OpenFile("hoge.pid", os.O_WRONLY|os.O_APPEND, 0666) if err != nil { // エラー処理 } defer file.Close() // 書き込み(手抜き fmt.Fprintln(file, pid) ```
- 停止時はPIDファイルからPIDを特定してsignalを送信する ファイルからPID取得してsyscall.Kill実行 ``` PIDから値取得してsyscall.SIGTERMを送信 // バイト型スライスの作成 buf := make([]byte, 16) for { n, err := f.Read(buf) if n == 0 { break } if err != nil { // エラー処理 } killID := binary.BigEndian.Uint64(buf[:n]) // SIGTERM送信 syscall.Kill(int(killID), syscall.SIGTERM) } ```
- シグナル送信時にハンドリング出来るにする signal.Notifyを利用 ``` // 実行したい処理を gorutine go hoge.Fuga() // signal 用 channelを用意 signalCh := make(chan os.Signal) signal.Notify(signalCh, syscall.SIGHUP, syscall.SIGTERM, os.Interrupt) // selectで channelを待ち受け select { case ch := <-signalCh: catchSig(ch) } func catchSig(sig os.Signal) { // 各種signal用の処理を記述 switch sig { case syscall.SIGHUP: fmt.Println("SIGHUP Happend! stop", sig) case syscall.SIGTERM: fmt.Println("SIGTERM Happend! stop", sig) case os.Interrupt: fmt.Println("os.Interrupt Happend! stop", sig) default: fmt.Println("singal Happend! stop", sig) } } ```
Goで一つ一つ実装することでデーモン化は行えそう -> ほぼ第二次ゆとり世代の自分としては楽したい Library [takama/daemon](https://github.com/takama/daemon) [sevlyar/go-daemon](https://github.com/sevlyar/go-daemon) Goで頑張らない [supervisor](http://supervisord.org/)
### supervisord プロセス管理/デーモン化のツール PID管理やstart stop等の機能を提供してくれる 意図しないプロセス停止時に自動でプロセスの再起動までしてくれる #### yum ``` yum install epel-release yum install --enablerepo=epel supervisor ``` #### pip ``` sudo pip install supervisor ```
#### 設定ファイル [supervisord/configuration](http://supervisord.org/configuration.html) ``` [program:hoge] directory=/var/hoge ; 実行ディレクトリ command=/usr/local/bin/hoge ; 起動コマンド user=hoge ; 起動ユーザ autostart=true ; 自動起動 autorestart=true ; プロセス終了時の自動再起動 redirect_stderr=true ; エラー出力を標準出力にリダイレクト exitcodes=0 startretries=10 redirect_stderr=true stdout_logfile=/var/log/supervisor/jobs/hoge-supervisord.log ; 標準出力ログ stdout_logfile_maxbytes=10MB ; ログローテート stdout_logfile_backups=10 ; 世代数 stopwaitsecs=90 stopasgroup=true killasgroup=true ```
### 纏め - Goでのデーモン化は一般的なデーモン化のプロセスを踏めば可能 - 気軽に使って欲しい場合などに有用 - Libraryを使う事で簡単に実装可能 - supervisordを使う事でコマンドを作るだけでデーモン化することも可能 - 強力な機能を使って安定化させたい、メンテナンスコスト下げたい
Thank you! Fusicは技術が大好きなエンジニアを募集しています  https://fusic.github.io
Swipe to navigate
Previous
Next
Related Slides
Goでパイプライン
2023/1/1
View
Fukuoka.go #14 + Umeda.go #2
2019/11/15
View
Fukuoka.go #12 + Tokyo.go
2019/7/12
View