Share
Embed
The introduction of mRuby on Container /mruby-on-container
@ RubyKaigi 2016, Kyoto
2016/09/08
#container #linux
KONDO Uchio
September 08, 2016
Transcript
89 slides
-
6DIJP,POEP !VE[VSB *TBOZP3VCZJTU POFPG 'VLVPLBSCDPPSEJOBUPST 3BJMT(JSMT'VLVPLB0SHBOJ[FST BOEBTZTUFNQSPHSBNNJOHOPWJDF 0OFPGUIFBVUIPSTPG l5IF1FSGFDU3VCZz
l5IF1FSGFDU3VCZPO3BJMTz #PUIJO+BQBOFTF -
FH*TTVF 8IFOUSZJOH%PDLFSJO%PDLFS VTFGVM GPS*OGSB$* TPNFQBDLBHFTNBEFUSPVCMFJO JOTUBMMJOH FTQFDJBMMZIUUQE BOE TZTUFNE
5IJTJTCFDBVTFPMEFSWFSTJPOTPGBVGT CVJMEEPFTO`UTVQQPSUpMFDBQBCJMJUJFT #VU*DPVMEOPUEFTDSJCFUIFCVHJO EFUBJMBUUIBUUJNF -
0QFSBUJPOT PQFSBUJPOT w &WFSZEBZIBSEEJTLDMFBOVQPQFSBUJPOʜʜ • docker ps -a | \
grep Exited | \ awk '{ print $1 }' | \ xargs docker rm -f w *ODSFBTJOH-" $16VTBHF NFNPSZʜʜ w *XBTMFTTGBNJMJBSBOEIBEMFTTLOPXIPXTBCPVU%PDLFSPSDPOUBJOFST JOUFSOBM TP*IBETPNFUSPVCMFT -
-9$JO4RBMF w -9$MPPLFENPSFMJHIUXFJHIUBOEVOEFSTUBOEBCMFUPNFUIBOEPDLFS w FH w $BOVTFCJOENPVOUSBUIFSUIBOBVGT PSBMJLF w
$BODIPPTFOPOFUXPSLJTPMBUJPO QMBZJOHJTPMBUJPOJOTJEFUIFDPOUBJOFS TPVOEFSTUBOEBCMFBOEDPOUSPMMBCMFGPSNFBUUIBUUJNF -
#VUʜʜ w *NFUTPNFEJTDPOUFOUBHBJOJOPQFSBUJPO w FHSFTPVSDFSFBMMPDBUJPO w DQVTFUSFBMMPDBUJPOJTEPOFCZSFHFOFSBUJOHDPOpHXJUIDIFGJO4RBMF w 0UIFSSFTPVSDFSFBMMPDBUJPOTBSFEPOFCZIBOE FHNFNPSZMJNJU
w "OE*IBEBDPOqJDUJOVQHSBEJOH-9$JUTFMG w #FDBVTFXFXFSFVTJOHWFSZFBSMZ-9$ -
$PODMVTJPO w *IBEUPTUVEZIBSEFSBCPVUDPOUBJOFSTʜʜ w *XJTIFEUPIBWFBCSBOEOFXDPOUBJOFSFOHJOFXIJDIFOBCMFVT w UPDPNCJOFDPOUBJOFSTZTUFNBUUSJCVUFTJOBDDPSEBODFXJUIPVSDIPJDF w UPDIBOHFUIFTFTZTUFNBUUSJCVUFTCZEZOBNJDQSPHSBNNJOH w
4P*IBWFDSFBUFEIBDPOJXB )BDPOJXBTJHOJpFTBNJOJBUVSFHBSEFOJO+BQBOFTF BOE$JOWPMWFT$0/UBJOFS -
*OTUBMMBUJPO w 1BDLBHFTBSFBWBJMBCMFJOQBDLBHFDMPVE IUUQTQBDLBHFDMPVEJPVE[VSBIBDPOJXBJOTUBMM # example for deb-ish distro curl
-s https://packagecloud.io/install/repositories/udzura/ haconiwa/script.deb.sh | sudo bash apt-get update apt-get install haconiwa apt-get install lxc lxc-templates # Required to bootstrap fs -
'JSTU DSFBUFUIFDPOpHpMFGSPNCPJMFSQMBUF $ haconiwa new test.haco assign new haconiwa name
= haconiwa-0491a405 assign rootfs location = /var/lib/haconiwa/0491a405 create test.haco -
*OTUBMMTTIE DIBOHFTTIEDPOpH Haconiwa.define do |config| #... config.provision do |p| p.run_shell
<<-SHELL apk add --update openssh sed -i 's/#Port.*/Port 2222/' /etc/ssh/sshd_config # NOTE: insecure but an example below sed -i 's/#PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config sed -i 's/#PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config echo root:r00t | chpasswd ssh-keygen -t rsa -P "" -f /etc/ssh/ssh_host_rsa_key SHELL end #... end -
$IBOHFlJOJUzDPNNBOEUPTTIE UIFOJOWPLFlSVOz Haconiwa.define do |config| # The container name and
container's hostname: config.name = "haconiwa-0491a405" # The first process when invoking haconiwa run: # config.init_command = "/bin/bash" # To: config.init_command = %w(/usr/sbin/sshd -D) # And uncomment: config.daemonize! #... end $ haconiwa run test.haco -
.PSFBCPVU%4- w :PVDBODPOpHVSFOBNFTQBDF DHSPVQ DBQBCJMJUZ NPVOUQPJOU MJNJU TFUVJE TFUHJEʜʜWJBIBDPpMF JGOFDFTTBSZ
TFFDPNNFOUT w #PJMFSQMBUF`TEFGBVMU w *UVOTIBSFTOBNFTQBDFTVUTJQDQJENOUCVUOFUVTFS w *USFNPVOUTTPNFNPVOUQPJOUTJOBOFXOBNFTQBDF FHQSPD TZT -
$PODMVTJPOPGUIJTTFDUJPO w )BDPOJXBDBOCFJOTUBMMFEBTQBDLBHFT $FOU04%FCJBOKFTTJF6CVOUVUSVTUZBOEYFOJBM w )BDPOJXBTVQQPSUTUIFTFDPOUBJOFSPQFSBUJPOT w OFXDSFBUFSVOBUUBDILJMM w
:PVDBODPNCJOFDPOUBJOFSGVODUJPOBMJUJFTVTJOHIBDPpMF`T%4- 4FFDPNNFOUTPOHFOFSBUFEPOF -
8IBUXFDBMM -JOVY DPOUBJOFS w *TDPNQPTFEXJUITPNF-JOVYGFBUVSFT w -JOVY/BNFTQBDF w DISPPUCJOENPVOU w
DHSPVQT w -JOVYDBQBCJMJUJFT w SFTPVSDFMJNJUT TFUVJETFUHJEʜʜ -
-JOVYOBNFTQBDF w -JOVYOBNFTQBDFQSPWJEFTUIFQBSUJUJPOTJO04SFTPVSDFT w FH w 654/BNFTQBDF4FQBSBUFTIPTUOBNFGSPNIPTUNBDIJOF w 1*%/BNFTQBDF$PVOUTVQ1SPDFTT*%TBHBJO w
.PVOU/BNFTQBDF4FQBSBUFTNPVOUQPJOUJOGPSNBUJPOGSPNIPTU w 0UIFST*1$ /FUXPSL 6TFS $(SPVQ -
/BNFTQBDFVOTIBSFUPTFF654OBNFTQBDF puts "Before unshare:" RunCmd.new("sample1").run "uname -a" # This puts
“localhost” # Then unsure the UTS namespace Namespace.unshare Namespace::CLONE_NEWUTS Procutil.sethostname "rubykaigi.example.org" puts "After new namespace:" RunCmd.new("sample1").run "uname -a" # This puts “rubykaigi.example.org” and parent remains unchanged -
DISPPUBOECJOENPVOU w DISPPU DISPPU w $IBOHFTUIFSPPUEJSFDUPSZPGUIFDBMMJOHQSPDFTT w
CJOENPVOU w *TVTFGVMUPVTFTPNFEJSFDUPSJFTPSpMFTGSPNBOPUIFSMPDBUJPO w 0SUPBEETPNFTVCEJSFDUPSJFTFYUSBBUUSJCVUFT FHSFBEPOMZ -
/BNFTQBDF DISPPUTNBMMFTUDPOUBJOFS # The smallest container with mruby: Namespace.unshare(Namespace::CLONE_NEWNS|Namespace::CLONE_NEWPID) m
= Mount.new m.make_private "/" root = "/var/lib/haconiwa/125f23ef" m.bind_mount root, root, readonly: true # To make readonly Dir.chroot root Dir.chdir "/" c = Process.fork { m.mount "proc", "/proc", :type => "proc" Exec.exec "/bin/sh" } puts "Container exited: #{Process.waitpid2(c).inspect}" -
DHSPVQT $POUSPM(SPVQT w 5IFGFBUVSFPG-JOVYLFSOFM w 5IJTlQSPWJEFTGPSHSPVQJOHPGUBTLTBOESFTPVSDFUSBDLJOHBOEMJNJUBUJPOTGPS UIPTFHSPVQTz GSPNNBODHSPVQT
w 5IJTGFBUVSFGPSIBOEMJOHSFTPVSDFTCZHSPVQTPGUBTLTJTVTFGVMUPNBLF lBDPOUBJOFS JOEFFEBHSPVQPGQSPDFTTFT zMPPLTMJLFBOJOEJWJEVBM04 -
FHDQVTFUMJNJUBUJPOCZDHSPVQ cpuset = Cgroup::CPUSET.new "rubykaigi001" cpuset.cpus = "0-1"; cpuset.mems =
"0" cpuset.create # Comment out to use full-core cpuset.attach def fib(n); n < 2 ? 1 : fib(n-2) + fib(n-1); end procs = (1..4).to_a.map do Process.fork do loop { fib(rand(1000)) } end end procs.each {|pid| Process.waitpid pid } -
FHESPQQJOHUJNFDPOUSPMQSJWJMFHFGSPNlSPPUz # Will be dropped after the process invoke execve(2)
Capability.drop_bound Capability.from_name("cap_sys_time") exec "/bin/bash" # Then to be new program... root@localhost:~# hacorb mruby/caps.rb # new process below root@localhost:~# date -s 'Thu, 21 Dec 95 14:44:05 JST' date: cannot set date: Operation not permitted # even a root Wed Dec 20 21:44:05 PST 1995 root@localhost:~# date Thu Aug 25 20:40:59 PDT 2016 # unchanged -
$PODMVTJPOUIFDPOUBJOFSXFDBMMJT *TPMBUJPOT -JOVYOBNFTQBDF DISPPU CJOENPVOU ʜ -JNJUBUJPOT DHSPVQT DBQBCJMJUJFT SFTPVSDFMJNJU
ʜ 8JUIUIFTF UIFlQSPDFTTzDBOCFUSFBUFEBTBOl04zCZEFWFMPQFST "OEUIFTFDBOCFDPOUSPMMFECZIBDPOJXB`T3VCZ%4- -
':*0$*TQFDJpDBUJPOT w *UEFpOFTXIBUGFBUVSFTUPCFTVQQPSUFECZ0$*DPOUBJOFS FH/BNFTQBDFT $POUSPMHSPVQT 1SPDFTTDPOpHVSBUJPO TVDIBTDBQBCJMJUJFT 6TFS OBNFTQBDFNBQQJOHT TFDDPNQʜʜ
w IUUQTHJUIVCDPNPQFODPOUBJOFSTSVOUJNFTQFDCMPCNBTUFSDPOpHNE w IUUQTHJUIVCDPNPQFODPOUBJOFSTSVOUJNFTQFDCMPCNBTUFSDPOpHMJOVYNE w #58 0$*TQFDSFGFSTUPMJOVYBOETPMBSJTTQFDJpDDPOpH w *UJTMJLFMZUIBU)BDPOJXBDBOQSPWJEFUIFBCTUSBDUMBZFSGPSSFTPVSDF MJNJUBUJPO OBNFTQBDF pMFTZTUFN CFUXFFOLFSOFMT w *UXJMMCFSFMFBTFEGBSJOUIFGVUVSF NBZCF -
'JSTUJNQMFNFOUBUJPOPG)BDPOJXB w *O$3VCZ w /BNFTQBDFIBOEMJOHCZ,FSOFMTZTDBMM w %JSDISPPUNPVOU DBMMCZ,FSOFMTZTUFN w
%PJOHBpMFPQFSBUJPO PQFOSFBEXSJUF GPSDHSPVQ w 6TJOH''*GPSDBQBCJMJUJFT EFQFOEFOUPOMJCDBQ w "OE1SPDFTTGPSL,FSOFMFYFDUIFHPMEFOUXJO -
&TQFDJBMMZ TPNFSFTUSJDUJPOTJOTZTUFNDBMMT w $3VCZJTJOWPLFEJONVMUJUISFBEFENPEF 5IJTJTCFDBVTFPGBUJNFSUISFBEXIJDIJTVTFGVMUPBMNPTUBMMPGMBOHVBHFVTF DBTFT#VUʜʜ [vagrant@udzura ~]$ ruby -e
'loop { sleep 1 }' & [1] 7560 [vagrant@udzura ~]$ ls -l /proc/7560/task/ total 0 dr-xr-xr-x 6 vagrant vagrant 0 8݄ 25 11:38 7560 dr-xr-xr-x 6 vagrant vagrant 0 8݄ 25 11:38 7561 -
*OTQFDUJOHNBOBCPVUOBNFTQBDFTZTDBMMT w NBOQBHFPGVOTIBSF w $-0/&@/&81*% TJODF-JOVY ʜʜ $-0/&@/&81*%BVUPNBUJDBMMZJNQMJFT$-0/&@5)3&"%BTXFMMʜʜ
&33034 &*/7"-$-0/&@5)3&"% $-0/&@4*()"/% PS$-0/&@7.XBTTQFDJpFE JOqBHT BOEUIFDBMMFSJTNVMUJUISFBEFE w IUUQNBOPSHMJOVYNBOQBHFTNBOVOTIBSFIUNM -
*OTQFDUJOHNBOBCPVUOBNFTQBDFTZTDBMMT w NBOQBHFPGTFUOT w "QSPDFTTNBZOPUCFSFBTTPDJBUFEXJUIBOFXNPVOUOBNFTQBDFJGJUJT NVMUJUISFBEFE
w "NVMUJUISFBEFEQSPDFTTNBZOPUDIBOHFVTFSOBNFTQBDFXJUITFUOT w ʜʜ w IUUQNBOPSHMJOVYNBOQBHFTNBOTFUOTIUNM -
4P3VCZJNQMFNFOUBUJPODIPTF w 5PDSFBUFVOTIBSFEQSPDFTT w DSFBUFTBUFNQPSBSZTIFMMpMFBOEUIFOQBTTJUUPVOTIBSF w 5PBUUBDIFYJTUJOHOBNFTQBDF w
JUMBSHFMZEFQFOETPOOTFOUFS w 5IFTFBSFʜʜ5IFTFBSFVOEFTJSBCMFTUSBUFHZ VHMZQSPDFTTMBZPVU -
(SFBUFYJTUJOHNSCHFNT w MJCDHSPVQNSVCZXSBQQFSCZNBUTVNPUPSZ w MJCDBQNSVCZXSBQQFSCZNBUTVNPUPSZ w TNBMMVOTIBSF XSBQQFSCZIJSPLBXB OPU*%IBDPOJXB
w **+`THSFBUNSCHFNT FTQFDJBMMZNSVCZEJSBOENSVCZQSPDFTT -
&YBNQMFNSVCZMJOVYOBNFTQBDF w 8SJUFBTNBMMGVODUJPOXJUIBOBJWFVTFPGTFUOT w 5IFOBUUBDIUPBNPEVMF static mrb_value mrb_namespace_setns_by_fd(mrb_state
*mrb, mrb_value self) { mrb_int fileno, nstype; int ret; mrb_get_args(mrb, "ii", &fileno, &nstype); ret = setns((int)fileno, (int)nstype); if (ret < 0) { mrb_sys_fail(mrb, "setns failed"); } return mrb_fixnum_value(ret); } /* ... */ void mrb_mruby_namespace_gem_init(mrb_state *mrb) { struct RClass *namespace; namespace = mrb_define_class(mrb, "Namespace", mrb->object_class); mrb_define_class_method(mrb, namespace, "setns_by_fd", mrb_namespace_setns_by_fd, MRB_ARGS_REQ(2)); } -
'PS3VCZJTI"1*MPPLT KVTUEPXSJUF w *IBWFJNQMFNFOUFEVTFSGSJFOEMZQBSBNFUFSBSHVNFOUTJOUIFSVCZMBZFS class Namespace def self.setns(flag, options) fd
= options[:fd] pid = options[:pid] if fd setns_by_fd(fd, flag) elsif pid setns_by_pid(pid, flag) else raise ArgumentError, "Options :fd or :pid must be specified" end end end -
NSVCZBTBl$zGSBNFXPSL w NSVCZQSPWJEFTNBOZGVODUJPOBMJUJFTUIBUBSFVTFGVMJOXSJUJOH$ w ($ SFTPVSDFMJGFDZDMFNBOBHFNFOU w TUSJOHBSSBZIBTIUBCMFPCKFDUBOEGVODUJPOTGSJFOEMZUPIBOEMF w 6TFSJOQVU
BTBSVCZDPEF $XPSMENBQQFS NSC@HFU@BSHTNSC@ @WBMVF -
FHSFTPVSDFMJGFDZDMFNBOBHFNFOU w NSVCZIBT($ w :PVKVTUDBO w CJOEZPVS$PCKFDUUP 3VCZPCKFDUXIFODSFBUFE w SFHJTUFSUIFGSFFJOHGVODUJPO
GPS$PCKFDU XIFO3VCZPCKFDUJT($`FE static void mrb_cap_context_free(mrb_state *mrb, void *p) { mrb_cap_context *ctx = (mrb_cap_context *)p; cap_free(ctx->cap); mrb_free(mrb, ctx); } static const struct mrb_data_type mrb_cap_context_type = { "mrb_cap_context", mrb_cap_context_free, }; mrb_value mrb_cap_init(mrb_state *mrb, mrb_value self) { mrb_cap_context *cap_ctx; //... DATA_TYPE(self) = &mrb_cap_context_type; DATA_PTR(self) = cap_ctx; //... } &YBNQMFBUNSVCZDBQBCJMJUZ -
FHl4USJOHzIBOEMJOHBOETPPO w )VNBOTXBOUFEUPBWPJEEJSFDUMZIBOEMJOHPGDIBS<>`T w NSVCZ`T4USJOHDMBTTQSPWJEFT w 3FTPVSDFIBOEMJOHJO3VCZMBZFS w 4USJOHNPEJpDBUJPOUPPMDIBJOT w
:PVDBODBMM3VCZ`TQPXFSGVMBOE qFYJCMF4USJOHNFUIPETFWFOJO $XPSME w 'PSBSSBZIBTIBOEPUIFSPCKFDUT TBNFBTBCPWF mrb_value member; mrb_get_config_value(mrb, "member", "o", &member); mrb_value mnum = mrb_funcall(mrb, member, "size", 0); int i; int seki_num = mrb_fixnum(mnum); for (i = 0; i < seki_num; i++) { mnum = mrb_funcall(mrb, member, "size", 0); mrb_value seki = mrb_funcall(mrb, mrb_top_self(mrb), "rand", 1, mnum); mrb_p(mrb, mrb_funcall(mrb, member, "[]", 1, seki)); mrb_funcall(mrb, member, "delete_at", 1, seki); } 5IFlTFLJHBFNSVCZzDPEF IUUQTHJUIVCDPNNBUTVNPUPSNSVCZDPOpHCMPCNBTUFSFYBNQMFTFLJHBFTFLJHBFD -
NSVCZDMJGPSDPNNBOEMJOFUPPM w 7FSZIFMQGVMGPSJNQMFNFOUJOHBDPNNBOE BOEJU`TCJOBSZ w haconiwaCJOBSZJTDSFBUFEVOEFSUIFNSVCZDMJEJSFDUPSZMBZPVU UIBOLT w *IBWFBEEFETPNFDVTUPNJ[BUJPOTUP3BLFpMF
w FH w NSVCZWFSTJPOMPDLFSDIFDLTPVUTQFDJpDWFSTJPOPGNSVCZGSPNHJUIVCXIFOCVJMEJOH w NSVCZNSCHFNWFSTJPOEFUFDUPS w POCVJMEJOH HFOFSBUFTBpMFXIJDIIBTBMMPGNSCHFNBOENSVCZWFSTJPOIBTIFT JTQPTTJCMF BOEUIFO FNCFETUIJTUPBDPNNBOE w "OE*IBWFDSFBUFENSVCZBSHUBCMFGPSQBSTJOHBSHVNFOUT w IUUQTHJUIVCDPNVE[VSBNSVCZBSHUBCMF -
':*UIFDPOUBJOFSNSCHFNT*VTFPSDSFBUF GFBUVSFT DPVOUFSQBSUNSVCZHFN -JOVYOBNFTQBDF mruby-linux-namespace DISPPUBOECJOENPVOU mruby-dir mruby-mount(*) DHSPVQT mruby-cgroup
-JOVYDBQBCJMJUJFT mruby-capability 3FTPVSDFMJNJUT mruby-resources 0UIFST GPSLFYFDXBJU mruby-process mruby-exec(*) w "DUVBMMZ UIFTFBSFBMSFBEZVTFECZUIFIBDPSCFYBNQMF OPUQVCMJTIFEUPNHFNMJTU -
#VUXIBUXFXBOUJOSFBMPQTXPSMEJT w 5IFXBZUPDPOUSPM w )PXUPEFQMPZNVMUJQMFDPOUBJOFST w )PXUPJODSFBTFPSEFDSFBTFDPOUBJOFST w )PXUPMJOLNVMUJQMFDPOUBJOFSTJONVMUJQMFSPMFT w
ʜʜJOFBTZBOEqVFOUNBOOFS w BLB5IFMBZFSPG0SDIFTUSBUJPO -
1SFQBSFDPOUBJOFSCBTFBT Haconiwa.define do |config| suffix = UUID.secure_uuid("%4x%4x") config.name = "haconiwa-#{suffix}"
config.init_command = ["/bin/sleep", UUID.secure_random(30..60).to_s] config.daemonize! root = Pathname.new("/var/lib/haconiwa/common") config.chroot_to root #... end -
1SFQBSFXBUDIFS%4-BT Haconiwa.watch do |config| config.watch :cluster do |event| if event.cluster.count
< 5 # Should be spawned 1 by 1 Haconiwa.spawn "/etc/haconiwa/haco.d/sleeper.haco" end end end -
*OUIFGVUVSF CFESFBNJFSBOENPSFBNCJUJPVT w &WFOU%4-DBOCFSFHJTUFSFEUPFUDE PSTPNFXIFSFHPPETUPSBHF w &BDIDPOUBJOFSTVQFSWJTPSNJHIUCFMJOLFEJOBXFBLSFMBUJPOTIJQ BOEUIFOFMFDUUIFMFBEFS
UIFOUIFMFBEFSDBOXBUDIUIFDMVTUFSBOEpSFUIFSFHJTUFSFEFWFOUT w 5IJTMPPLTMJLFBLFSOFMMFTT 410'MFTTBSDIJUFDUVSFUIBUNBZCFXPSLT w #VUOPJNQMFNFOUBUJPOZFUʜ w *IBWFGPVOENSVCZ$JNQMFNFOUBUJPOPGSBGU TP*`MMUSZOFBSGVUVSF -
4VQFSWJTPS 5IF$POUBJOFS 1SPDFTT FUDE FUDE FUDE 0WFSMBZ/FUXPSLT 4VQFSWJTPS 5IF$POUBJOFS 1SPDFTT
4VQFSWJTPS 5IF$POUBJOFS 1SPDFTT 47TBSF$MVTUFSECZ3BGU 5IF)PTU "1*BDDFTT -
3FGFSFODFT w 3FGFSFODFT BMMJO+BQBOFTF w 4RBMFTUBMLPGNJOF w IUUQTTQFBLFSEFDLDPNVE[VSBQIQQBBTTRBMFXP[IJFSVKJTIV w
$POUBJOFSUVUPSJBMT w IUUQTTQFBLFSEFDLDPNIBZBKPUVLVUVUFYVFCVMJOVYLPOUFOBGBMTFMJDF CZ!IBZBKP w IUUQTTQFBLFSEFDLDPNUFOGPSXBSEPTDLZPUP CZ!UFOGPSXBSE w IUUQTTQFBLFSEFDLDPNVE[VSBUIFTLFMUPOPGXIBMFT