Upgrade to Pro — share decks privately, control downloads, hide ads and more …

runitが便利なので、使い方を紹介した話 /runit

Medley Inc.
October 03, 2017

runitが便利なので、使い方を紹介した話 /runit

メドレー開発本部の社内勉強会「TechLunch」で発表した内容を掲載しました。

今回は、runitというunixのプロセススーパバイザについてお話しました。
runit自体は特に目新しい技術ではなく、大して難しい話題でもありません。ただ、個人的には便利に使っている”手放せないツール”であり、もしスーパバイザというものの存在を知らずに使わずにいる人がいると勿体無いなあという思いから、TechLunchのテーマとして取り上げました。

発表者:nakatani

Medley Inc.

October 03, 2017
Tweet

More Decks by Medley Inc.

Other Decks in Technology

Transcript

  1. εʔύόΠβͬͯԿʁ daemonΛ؂ࢹͯ͠ɺམͪͯͨΒ্ཱͪ͛ͨΓ͢ Δ΋ͷɻ େ఍͸OSʹඪ४Ͱ͍ͭͯ͘Δɻ initɺ upstart(amazon gnu linux, ݹ͍ubuntu, centos),

    systemd(࠷ۙͷgnu linuxσΟετϦϏϡʔγϣϯ), launchd(mac) OSඪ४͡Όͳ͍΍ͭ΋৭ʑ͋Δɻrunitͱ͔ɻ 4 / 38
  2. daemonͱ͸ʁ ੍ޚ୺຤ʹඥ෇͍͍ͯͳ͍ϓϩηεͷ͜ͱͰ͋Δɻ (1) ϋϩʔϫʔϧυϓϩάϥϜ͸୺຤Λ௨ͯ͠ੈքʹ͜ΜʹͪΘͱݴͬͯఀࢭ͢Δ. #!/bin/sh echo Hello world. (2) nginx΍mongod͸େ఍͸osىಈͱͱ΋ʹཱͪͬͺͳ͠ɻ

    ຊ࣭తʹ͸(1)ͱ(2)͸ಉ͡΋ͷͰ͋Δɻ σʔϞϯͱσʔϞϯҎ֎ʹɺͦΕ΄Ͳͷࠩ͸ͳ͍ɻ ࠓޙɺσʔϞϯͰ͸ͳ͍ϓϩηεΛɺϑΥΞάϥ΢ϯυϓϩηεͱݺͿɻ ( nginx΋confʹ daemon off; Λࢦఆͯ͠ϑΥΞάϥ΢ϯυϓϩηεʹͰ͖Δɻ ) 7 / 38
  3. ྫ:hello world #!/bin/sh # shell echo hello world. `date` exec

    sleep 1 runͱ͍͏ϑΝΠϧ໊Ͱ࣮ߦՄೳϑΝΠϧΛͭ͘Δɻ ./run Ͱىಈ͢Δͱɺ୺຤Λ௨ͯ͠ੈքʹ͜ΜʹͪΘͱݴͬͯɺऴྃ͢Δɻ runit ؀ڥʹrunΛ์ΓࠐΉͱɺͦΕ(it)Λrun͠ଓ͚ͯ͘ΕΔɻࢮ׆؂ࢹɻ #!/usr/bin/env ruby # ruby puts("hello from ruby. #{rand(100)}"); sleep(1); #!/usr/bin/env ruby # ruby infinite loop while true puts("hello from ruby. #{rand(100)}"); sleep(1); end ແݶϧʔϓ൛ͷεΫϦϓτ͸ຊ࣭తʹnginxͳͲͷσʔϞϯͱมΘΒͳ͍ɻ 12 / 38
  4. ྫ:railsىಈ #!/bin/sh echo ------------------------------ sleep 1 exec 2>&1 export HOME=/Users/nakatani

    # bundler need this stuff. export MONGO_HOST='localhost:27017' export SPROF_P=1 export SPROF_MODE=cpu export SPROF_DIR=/tmp/sprof # puma's port setting is bonehead. export PORT=3333 exec bundle exec rails server macbookىಈͨ͠Βɺ։ൃ؀ڥ͕ৗʹ্ཱ͕ͪͬͯΔɻ ΋ͪΖΜຊ൪؀ڥͰ࢖ͬͯ΋͍͍ɻ Կ͔ͷഥࢠʹམͪͯ΋ࣗಈతʹ࠶ىಈͯ͘͠ΕΔͷͰɺϝϯςφϯεϑϦʔɻ (஫ҙ) exec͠ͳ͍ͱࢠϓϩηε্ཱ͕͕ͪΓɺ؂ࢹ͔Β࿙ΕΔɻ 13 / 38
  5. ྫ:͜ͷεϥΠυࣗ਎ #!/usr/bin/env ruby require 'webrick'; s = WEBrick::HTTPServer.new(:DocumentRoot => "./",

    :Port => 9999); s.mount_proc '/main' do |req, res| # ࣮͸ෆཁɻlocalhost:9999/a.htmlͰOK html = File.open('a.html').read(); res.body = html; end s.start(); ( runitͱؔ܎ͳ͍͚Ͳɺremarkͱ͍͏markdownΛεϥΠυʹͯ͘͠ΕΔϓϩμ ΫτΛ࢖ͬͯΔɻ ) rubyϫϯϥΠφʔͰwebߏஙͰ͖Δɻ ͦΕΛrunit؀ڥʹͿͬ͜Ί͹ɺϓϩμΫγϣϯ؀ڥ͕Ͱ͖͕͋Δɻ ϫϯϥΠφʔͱdaemonͱͷڥ໨͕ᐆດͰૉఢ 14 / 38
  6. runitߏங on mac for user $ brew install runit $

    mkdir ~/serviceu # any names work. $ sudo cat <<EOF |sudo tee /Library/LaunchDaemons/runitu.plist # nakatani͸ม͑ͯ ! <?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd" > <plist version='1.0'> <dict> <key>Label</key><string>runitu</string> <key>ProgramArguments</key> <array> <string>sh</string><string>-c</string> <string>PATH="/usr/local/sbin:/usr/local/bin:$PATH" exec chpst -u nakatani '/usr/local/bin/runsvdir' '/Users/nakatani/serviceu' </string> <string>;</string> <string>--pid=exec</string> </array> <key>Debug</key><false/><key>Disabled</key><true/><key>KeepAlive</key><true/> </dict> </plist> EOF $ sudo launchctl load -w /Library/LaunchDaemons/runitu.plist $ sudo launchctl list | grep runitu # ֬ೝɻ 16 / 38
  7. ͔ΜͨΜʹղઆɻ homebrew͕͋Ε͹nakataniΛஔ͖׵͑Δ͚ͩͰಋೖՄ (I prefer macports) macOSͷඪ४εʔύόΠβ(launchd)ʹrunsvdirΛىಈ͍ͤͯ͞Δɻ launchctl load -w Ͱplistʹఆٛͨ͠಺༰Λlaunchd഑ԼͷσʔϞϯͱͯ͠ى

    ಈ͢Δ͜ͱ͕Ͱ͖Δɻ runsvdir͸~/serviceuΛ؂ࢹͯ͠daemonΛ্ཱͪ͛ͨΓ͢Δ΍ͭɻ mkdir ~/serviceu/hello/ͱ͢Δͱɺhello഑Լ͕daemon؀ڥʹͳ Δɻhello/supervise/͕ੜ੒͞ΕΔɻ ~/serviceu/hello/run ʹ࣮ߦՄೳͳεΫϦϓτΛஔ͘ͱɺdaemonͱ࣮ͯ͠ߦ ͞ΕΔɻ chpstίϚϯυͰrunsvdirͷΦʔφʔΛnakatani(nakatani)ʹมߋ͍ͯ͠Δɻ ৄ͍͜͠ͱ͸ࣗ෼Ͱௐ΂͍ͯͩ͘͞ɻmanίϚϯυɺweb৘ใɺqiitaɺblogͱ͔ɻ 17 / 38
  8. runitߏங on mac for root $ brew install runit #

    macports feels better for me, but... $ sudo mkdir /service $ sudo cat <<EOF |sudo tee /Library/LaunchDaemons/runit.plist <?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd" > <plist version='1.0'> <dict> <key>Label</key><string>runit</string> <key>ProgramArguments</key> <array> <string>sh</string><string>-c</string> <string>PATH="/usr/local/sbin:/usr/local/bin:$PATH" exec '/usr/local/bin/runsvdir' '/service' </string> <string>;</string> <string>--pid=exec</string> </array> <key>Debug</key><false/><key>Disabled</key><true/><key>KeepAlive</key><true/> </dict> </plist> EOF $ launchctl load -w >/Library/LaunchDaemons/runit.plist $ launchctl list | grep runit 18 / 38
  9. ؀ڥΛύοέʔδԽͰ͖Δɻ ϓϩηεͱ͍͏ͷ͸ɺҰछͷԾ૝ϚγϯͰ͋Δɻ ϓϩηεͱ஥ྑ͘ͳΔͱɺdockerͱ͔jail͕େ͛͞ʹࢥ͑Δ͜ͱ͕͋Δɻ runitͩͱɺҎԼͷΑ͏ʹɺmedley಺෦ʹੈքΛด͡ࠐΊΔ͜ͱ͕΍Γ΍͍͢ɻ /service/medley/run # ϝΠϯσʔϞϯɻrailsͱ͔ɻ /service/medley/supervise # εʔύʔόΠβʔ͕࢖͏৘ใɻී௨͸ؾʹ͠ͳ͍ɻ

    /service/medley/log/run # ϩΨʔ /service/medley/log/current # ϩά /service/medley/log/xxxxxxxx.s # ݹ͍ϩά /service/medley-nginx/ # nginx /service/medley-mongo/ # mongo /service/job-medley/... medley಺෦ʹඞཁͳͳΜ΍͔Μ΍Λߏ੒͢Ε͹ɺ؀ڥΛͻͱ·ͱΊʹͰ͖Δɻ 22 / 38
  10. runitΛߏ੒͢ΔίϚϯυ܈ $ brew list runit /us../bin/runsvdir # σΟϨΫτϦΛ؂ࢹͯ͠daemonͷ௥Ճɾ࡟আͳͲΛ؅ཧ͢Δɻ /us../bin/runsv #

    σΟϨΫτϦ഑Լͷ֤daemonΛ؅ཧ͢Δɻ /us../bin/sv # daemonΛ੍ޚ͢ΔίϚϯυɻ /us../bin/svlogd # daemonͷग़ྗΛϩάʹམͱ͢ɻ /us../bin/chpst # ϓϩηεͷ࣮ߦϢʔβͳͲΛมߋ͢Δπʔϧɻchange process sta tusɻ /us../bin/runit /us../bin/runit-init /us../bin/runsvchdir /us../bin/utmpset /us../share/man/ (9 files) # man svͱ͔ͰϚχϡΞϧݟΕ·͢ɻ 24 / 38
  11. svͰdaemonΛ੍ޚ͢Δɻ $ cd ~/serviceu/ $ mkdir -p hello/log # logΛಉ࣌ʹͭ͘Δͱrunsvdir͕logͷ४උ΋͢Δ

    $ cd hello $ cat <<EOF > run #!/usr/bin/env ruby while true puts("hello ruby #{Time.now.to_i % 100}"); STDOUT.flush(); sleep(1); end EOF $ cat <<EOF > log/run #!/bin/sh exec svlogd -ttt . EOF $ chmod 755 run log/run $ tail -F log/current # ϩά͕ݟΒΕΔɻ $ sv st . # daemonͷঢ়ଶΛ֬ೝ͢Δɻ run: .: (pid 35517) 46s; run: log: (pid 34727) 456s $ sv st /Users/nakatani/serviceu/hello/ # σΟϨΫτϦͷࢦఆํ๏͸ࣗ༝ɻ $ sv t . # TERMγάφϧΛdaemonʹૹΔ $ sv st . run: .: (pid 35589) 1s; run: log: (pid 34727) 470s # ىಈ͕࣌ؒ1sʹͳͬͯΔɻ 25 / 38
  12. svͰdaemonΛ੍ޚ͢Δɻ(2) $ sv x . # runsvΛఀࢭ͢Δɻ $ sv down

    . # daemonΛҰ࣌తʹఀࢭ͢Δɻ $ sv up . # down͔Βupʹɻ $ touch down # downͱ͍͏ϑΝΠϧ͕͋ΔͱϚγϯ࠶ىಈޙɺࣗಈىಈ͠ͳ͍ɻ ৭ʑγάφϧ͓͘ΕΔɻsvͷmanʹৄ͘͠ॻ͍ͯΔɻ runҎ֎ʹfinishͱ͍͏εΫϦϓτΛ༻ҙ͓ͯ͘͠ͱɺrun͕ऴྃ͢ΔλΠϛϯάͰ finishΛ࣮ߦͯ͘͠ΕΔɻ 26 / 38
  13. ྫ:nginx run #!/bin/sh exec nginx -c `pwd`/nginx.conf nginx.conf worker_processes 1;

    daemon off; error_log /dev/stdout info; events { worker_connections 1024; } http { include mime.types; ... ϙʔτɺઃఆม͑ͯෳ਺ىಈͰ͖Δɻ 32 / 38
  14. ྫ:mongod #!/bin/sh sleep 2 exec mongod --profile 2 --slowms 20

    --dbpath ./mongodb --logpath ./log/mongodb.lo g ϙʔτΛࢦఆͯ͠ز্ཱ͔͓͚ͭͪ͛ͯ͹ɺෳ਺؀ڥ४උͰ͖Δɻ 33 / 38
  15. ྫ:σΟϨΫτϦ؂ࢹͯ͠build͢Δ ࣗ෼Ͱ࡞Βͳͯ͘΋jsͩͱ৭ʑ༻ҙ͞Ε͍ͯͨΓ͢Δɻ ͜͜Ͱॏཁͳͷ͸ɺϓϩμΫτʹཔΒͳͯ͘΋ࣗ෼ͰಠࣗͷԿ͔ΛߏஙͰ͖Δ͜ͱ Ͱ͋Δɻ CͰ։ൃ͍ͯ͠Δ৔߹ɺιʔεͷมԽΛݕ஌ͯ͠makeΛ࣮ߦ͢Δͱ͔ɺ #!/usr/bin/env ruby require 'listen'; tgtpath='/Users/nakatani/dev/medley/medley-ghost/frontend';

    listener = Listen.to(tgtpath) do |mod, add, rem| Dir.chdir(tgtpath); puts "npm rebuild start"; res = system('npm run build'); puts "npm rebuild end"; res = system('sv t /Users/nakatani/service/medley-ghost-nginx/'); puts "reboot nginx res:#{res}"; end listener.start; # not blocking sleep; 35 / 38