Middleware as Code with mruby

Hiroshi SHIBATA
Hiroshi SHIBATAOSS programmer at GMO Pepabo, Inc.
Middleware as Code with mruby
Details of mruby usage in production
self.introduce
=>
{
name: “SHIBATA Hiroshi”,
nickname: “hsbt”,
title: “Chief engineer at GMO Pepabo, Inc.”,
commit_bits: [“ruby”, “rake”, “rubygems”, “rdoc”, “tdiary”,
“hiki”, “railsgirls”, “railsgirls-jp”, “jenkins”],
sites: [“ruby-lang.org”, “rubyci.com”, “railsgirls.com”,
“railsgirls.jp”],
}
I’m from Tokyo, Japan
Tokyo
Matze
RDRC
I’m from Asakusa.rb
Asakusa.rb is one of the most active meet-ups in Tokyo, Japan.
@a_matsuda (Ruby/Rails committer, RubyKaigi organizer)
@kakutani (RubyKaigi organizer)
@ko1 (Ruby committer)
@takkanm (Ruby/Rails programmer)
@gunjisatoshi (Rubyist Magazine editor)
@hsbt (Me!)
I’m from the Ruby core team
We are working on the next version of Ruby, 2.3.0, now. However,
the main feature is under “TBD” status. Some libraries will be
omitted from stdlib such as rake, net-telnet, etc..
If you have any issue, please submit it to our issue tracker at
http://bugs.ruby-lang.org
We hold the core developer meeting every months, and discuss
various issues and ideas on Ruby. See https://bugs.ruby-lang.org/
projects/ruby/wiki/#Developer-Meetings for details.
Middleware as Code with mruby
Today’s target
• Web engineer(Rails programmer)
• Operation engineer
• QA/test engineer
• mruby committer(Matz)
mruby
What's mruby?
“mruby is the lightweight implementation of the Ruby language
complying to (part of) the ISO standard. Its syntax is Ruby 1.9
compatible.”
https://github.com/mruby/mruby#whats-mruby
Differences between mruby and CRuby
• The mruby runtime and libraries are embedded all into a single
binary.
• By default, mruby provides just a minimum set of standard
libraries such as String, Array, Hash, etc.
• Some of standard libraries in CRuby are NOT bundled in mruby,
for example, IO, Regex, Socket, etc..
• mruby doesn't provide “require”, “sleep”, “p”, etc.
Advantages of mruby against CRuby
• Single binary without pure ruby files.
• Embeddable into middlewares like below:
• apache/nginx
• groonga
• mysql
• Fun!!1 # most important thing
Dive into mruby build
You can declare prerequisite libraries in `build_config.rb`
MRuby::Build.new do |conf|
toolchain :gcc
conf.gembox 'full-core'
conf.gem :github => 'iij/mruby-io'
conf.gem :github => 'iij/mruby-env'
(snip)
conf.gem :github => 'matsumoto-r/mruby-uname'
conf.gem '../mrbgems/ngx_mruby_mrblib'
end
mrbgem
See https://github.com/mruby/mruby/blob/master/doc/mrbgems/
README.md :)
• mrbgem.rake
Endpoint of mrbgem, put MRuby::Gem::Specification
• mrblib/
Sources for pure ruby extension
• src/
Sources for C extension
🐙 Demo 🐱
Middleware meets mruby
mruby has embeddable mechanism for middlewares like http
server, search engine, etc..
Embedded mruby provides ruby runtime and syntax to
middlewares. It’s so powerful programming environment for
Rubyists.
ngx_mruby
Introduction to ngx_mruby
“ngx_mruby is A Fast and Memory-Efficient Web Server Extension
Mechanism Using Scripting Language mruby for nginx.”
https://github.com/matsumoto-r/ngx_mruby#whats-ngx_mruby
location /proxy {
mruby_set_code $backend '
backends = [
"test1.example.com",
"test2.example.com",
"test3.example.com",
]
backends[rand(backends.length)]
';
}
location /hello {
mruby_content_handler /path/to/hello.rb cache;
}
In “nginx.conf”!!!
How to build ngx_mruby (and mruby)
I suggest to try it on OS X or Linux environment. You can change
embedded mgem via “build_config.rb” in ngx_mruby repository.
$ git clone https://github.com/matsumoto-r/ngx_mruby
$ git clone https://github.com/nginx/nginx
$ cd ngx_mruby
$ git submodule init && git submodule update
comment-out mruby-redis and mruby-vedis
$ ./configure —with-ngx-src-root=../nginx
$ make build_mruby
$ make
$ cd ../nginx
$ ./objs/nginx -V
mruby_content_handler
location /hello {
mruby_content_handler /path/to/hello.rb cache;
}
location /hello {
mruby_content_handler_code '
Nginx.rputs "hello"
Nginx.echo "world!"
';
}
It’s basic usage of ngx_mruby. These handlers are invoked at
every requests
mruby_set
location /proxy {
mruby_set $backend /path/to/proxy.rb cache;
}
location /proxy {
mruby_set_code $backend '
backends = [
"test1.example.com",
"test2.example.com",
"test3.example.com",
]
backends[rand(backends.length)]
';
mruby_set sets the return value from mruby code to nginx
variable
mruby_init
http {
mruby_init /path/to/init.rb;
server {
location / {
mruby_content_handler /path/to/handler.rb;
}
}
}
It’s invoked when nginx master process launched.
mruby_init_worker/mruby_exit_worker
http {
mruby_init /path/to/init.rb;
mruby_init_worker /path/to/init_worker.rb;
mruby_exit_worker /path/to/exit_worker.rb;
server {
location / {
mruby_content_handler /path/to/handler.rb;
}
}
}
It’s invoked when nginx “worker” process is launched.
Sample code of ngx_mruby
class ProductionCode
def initialize(r, c)
@r, @c = r, c
end
def allowed_ip_addresses
%w[
128.0.0.1
]
end
def allowed?
if (allowed_ip_addresses &
[@c.remote_ip, @r.headers_in['X-Real-IP'], @r.headers_in['X-Forwarded-For']].compact).size > 0
return true
end
(snip for memcached)
end
return false
end
ProductionCode.new(Nginx::Request.new, Nginx::Connection.new).allowed?
Sample configuration of nginx
location /path {
mruby_set $allowed ‘/etc/nginx/handler/production_code.rb' cache;
if ($allowed = 'true'){
proxy_pass http://upstream;
}
if ($allowed = 'false'){
return 403;
}
}
Use cases of ngx_mruby
• Calculation of digest hash for authentication.
• Data sharing with Rails application.
• To replace ugly complex nginx.conf with clean, simple, and
TESTABLE ruby code.
Middleware
as Code
Our use cases
Data sharing with Rails & Restricted access
We have photo sharing service
named “30days album”
This service concept is private
photo sharing.
We need to have restrict access
mechanism for image files and
share data of Rails to http
middleware.
Before ngx_mruby
Current architecture using ngx_mruby
Data sharing with rails using mruby
allowed = false
memcached = Memcache.new(“127.0.0.1”)
allowed_data = memcached.get(session_id)
You can share data via persisted storage like memcahed/redis
In this case, We
share data using
rails session key via
cookie data.
Issue of connection leak and fd open cost
We tried to connect memcached at each request using
“mruby_handler”
This approach open and close network connection each request.
We faced problem of connection overflow
We discussed the issue with the ngx_mruby author, @matsumoto-
r. He solved this issue in a few days. He provided us new handler
named “mruby_init_worker”.
OSS 💖
Share connection in worker process
userdata = Userdata.new("memcached_#{Process.pid}")
userdata.memcached = Memcached.new(‘128.0.0.1’)
userdata = Userdata.new("memcached_#{Process.pid}")
userdata.memcached.close if userdata.memcached
http {
(snip)
mruby_init_worker /etc/nginx/handler/session_connect.rb cache;
mruby_exit_worker /etc/nginx/handler/session_disconnect.rb cache;
(snip)
}
session_connect.rb
session_disconnect.rb
nginx.conf
Restrict access to image asset
allowed = false
userdata = Userdata.new("memcached_#{Process.pid}")
if allowed_data = userdata.memcached.get(session_id)
if @r.uri =~ //image/#{allowed_data}/
allowed = true
end
end
allowed
Allowing uri string in session is compared accessing uri. If it
matches, ngx_mruby allows this request to access image asset.
Comparison of performanceResptime(sec)
0
0.05
0.1
0.15
0.2
0.25
0.3
nginx + perlbal
ngx_mruby
transferrate(byte/sec)
0
5
10
15
20
25
30
nginx + perlbal
ngx_mruby
🌟 STAR IT 🌟
https://github.com/
matsumoto-r/ngx_mruby
Testing
code of mruby
Someone said
“Test is redundant”
What’s motivation
• We are using ngx_mruby in production.
• We should test every production code.
• Testing mruby code is a cutting edge technical issue.
Prototype concept
• Use CRuby(version independent: 2.0.0, 2.1, 2.2)
• Use test-unit
• Test “ruby code” without real world behavior.
Sample code of ngx_mruby
class ProductionCode
def initialize(r, c)
@r, @c = r, c
end
def allowed_ip_addresses
%w[
128.0.0.1
]
end
def allowed?
if (allowed_ip_addresses &
[@c.remote_ip, @r.headers_in['X-Real-IP'], @r.headers_in['X-Forwarded-For']].compact).size > 0
return true
end
(snip for memcached)
end
return false
end
ProductionCode.new(Nginx::Request.new, Nginx::Connection.new).allowed?
Dummy class of ngx_mruby
class Nginx
class Request
attr_accessor :uri, :headers_in, :args, :method, :hostname
def initialize
@uri = nil
@headers_in = {}
@args = nil
@method = 'GET'
@hostname = nil
end
end
class Connection
attr_accessor :remote_ip
def initialize
@remote_ip = nil
end
end
Dummy class of mgem
Memcached = MemCache
class Memcached
def close
servers.each(&:close)
end
end
class Userdata
def initialize(*args)
end
def memcached
Memcached.new('127.0.0.1:11211')
end
end
Skeleton of test-case
require_relative '../lib/production/code/path/mruby.rb'
class MRubyTest < Test::Unit::TestCase
def setup
@r = Nginx::Request.new
@c = Nginx::Connection.new
end
def test_discard_access
assert !ProductionCode.new(@r, @c).allowed?
end
end
Restrict requests with cookie session
require_relative '../lib/production/code/path/mruby.rb'
class MRubyTest < Test::Unit::TestCase
def setup
@r = Nginx::Request.new
@c = Nginx::Connection.new
end
def test_session_access
MemCache.new('127.0.0.1').set 'a77a2a0cc91b739438dfc9dc47c5dd36'
@r.headers_in['cookie'] = '_session=a77a2a0cc91b739438dfc9dc47c5dd36;'
@r.uri = '/secret/file/path'
assert ProductionCode.new(@r, @c).allowed?
end
end
Run test
% ruby test/production_code_test.rb
Loaded suite test/production_code_test
Started
.........
Finished in 0.031017 seconds.
---------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------
--------------------
9 tests, 15 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed
---------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------
--------------------
290.16 tests/s, 483.61 assertions/s
Test is back!!
Our concerns on CRuby testing
• We can test “ruby code”. But it’s not fulfill testing requirements.
We need to test ngx_mruby behavior.
• We use a lot of mock/stub classes. It’s ruby’s dark-side.
• We need to make easy task runner.
Testing
code of mruby
using mruby
Use mruby directly instead of CRuby
mruby-mtest
class Test4MTest < MTest::Unit::TestCase
def test_assert
assert(true)
assert(true, 'true sample test')
end
end
MTest::Unit.new.run
MRuby::Build.new do |conf|
(snip)
conf.gem :github => 'matsumoto-r/mruby-uname'
# ngx_mruby extended class
conf.gem ‘../mrbgems/ngx_mruby_mrblib'
con.gem :github => ‘iij/mruby-mtest’
(snip)
end
build_config.rb test_4m_test.rb
Inline testing for mruby-mtest
class ProductionCode
(snip)
end
if Object.const_defined?(:MTest)
class Nginx
(snip)
end
class TestProductionCode < MTest::Unit::TestCase
(snip)
end
MTest::Unit.new.run
else
ProductionCode.new(Nginx::Request.new, Nginx::Connection.new).allowed?
end
Build mruby for mruby testing
$ cd ngx_mruby/mruby
$ cp ../build_config.rb .
$ make
$ cp bin/mruby /path/to/test/bin
You need to get mruby binary before embed ngx_mruby.
% ./path/to/test/bin/mruby -v
mruby 1.1.0 (2014-11-19)
^C
Test runner for mruby-mtest
require 'rake'
desc 'Run mruby-mtest'
task :mtest do
target = "modules/path/to/production/code"
mruby_binary = File.expand_path("../#{target}/test_bin/mruby", __FILE__)
mruby_files = FileList["#{target}/**/*.rb"]
mruby_files.each do |f|
absolute_path = File.expand_path("../#{f}", __FILE__)
system "#{mruby_binary} #{absolute_path}"
end
end
Advantage of mruby testing
Rapid!
% rake mtest
# Running tests:
.........
Finished tests in 0.007924s, 1135.7900 tests/s, 1892.9833 assertions/s.
9 tests, 15 assertions, 0 failures, 0 errors, 0 skips
Deployment
Deployment strategy
We need to prepare following things for production use:
• Build target binary ngx_mruby in production environment
• Write manifest file of puppet/chef
• Test binary and mruby code continuously
Deploy!
Build on docker
FROM centos:7
MAINTAINER hsbt
RUN yum -y install --enablerepo=extras epel-release
RUN yum -y groupinstall "Development Tools"
RUN yum -y install git libffi-devel libevent-devel cyrus-sasl-devel openssl-devel pcre-devel tar zlib-
devel rake
(snip)
RUN git clone --depth 1 --branch v1.8.11 --recursive https://github.com/matsumoto-r/ngx_mruby.git /
usr/local/src/ngx_mruby
ADD build_config.rb /usr/local/src/ngx_mruby/build_config.rb
RUN git clone --depth 1 --branch v1.9.0 https://github.com/nginx/nginx.git /usr/local/src/nginx
RUN cd /usr/local/src/ngx_mruby && NGINX_SRC_ENV=/usr/local/src/nginx
NGINX_CONFIG_OPT_ENV="--prefix=/etc/nginx …'" sh build.sh
https://gist.github.com/hsbt/f5a3a83ec2ebf8169f38
Build on docker
$ docker build --tag=nginx_mruby:centos7 --file=Dockerfile.centos7 .
You can modify build_config.rb. After that, You run “docker build”
$ export DIR=`pwd` && docker run --volume="$DIR:/tmp:rw" --user=root "nginx_mruby:centos7" "cp"
"-a" "/usr/local/src/nginx/objs/nginx" "/tmp"
You got ngx_mruby binary for centos7 with “docker run”
official nginx package + ngx_mruby
% rpm -qlp nginx-1.9.0-1.el7.ngx.x86_64.rpm
/etc/logrotate.d/nginx
/etc/nginx
/etc/nginx/conf.d
/etc/nginx/conf.d/default.conf
(snip)
/usr/sbin/nginx
/usr/share/nginx
/usr/share/nginx/html
/usr/share/nginx/html/50x.html
/usr/share/nginx/html/index.html
/var/cache/nginx
/var/log/nginx
Replace ngx_mruby binary from
official package
example of puppet
class ngx_mruby::install {
include ngx_mruby::params
(snip)
file { '/usr/local/src/nginx.tar.gz':
source => "puppet:///modules/ngx_mruby/usr/local/src/nginx-${::platform}.tar.gz",
notify => Exec['cleanup and unzip ngx_mruby'],
}
$install_dir = dirname($ngx_mruby::params::nginx)
exec { 'cleanup and unzip ngx_mruby':
path => ['/bin', '/usr/bin'],
command => "tar xf /usr/local/src/nginx.tar.gz -C ${install_dir}",
require => File['/usr/local/src/nginx.tar.gz'],
refreshonly => true,
}
(snip)
}
Next challenge
• mruby binary can have different library from one in production.
• For continuous integration, we need to prepare cross-compile or
live compile environment.
• Replace nginx.conf with mruby code backed by test code.
cross-compile and CI
mruby supports cross-compile configuration.
We made “https://github.com/matsumoto-r/mruby-cross-
compile-on-mac-osx”
MRuby::Build.new do |conf|
# ... (snip) ...
# the last line of conf.gem
load '/path/to/mruby-cross-compile-on-mac-osx/mrbgem.rake'
end
mruby
in the future
mruby-ipvs
“mruby-ipvs is an interface to the IP Virtual Server(IPVS) for
mruby.”
https://github.com/rrreeeyyy/mruby-ipvs
# Create IPVS::Service instance.
s = IPVS::Service.new({
'addr' => '10.0.0.1:80',
'port' => 80,
'sched_name' => 'wrr'
})
# apply to IPVS.
s.add_service
# Create IPVS::Dest instance.
d = IPVS::Dest.new({
'addr' => '192.168.0.1',
'port' => 80,
'weight' => 1
})
# Add destination to IPVS::Service instance.
s.add_dest(d)
mruby_cgroup
mruby cgroup module using libcgroup
https://github.com/matsumoto-r/mruby-cgroup
rate = Cgroup::CPU.new "test"
core = Cgroup::CPUSET.new "test"
rate.cfs_quota_us = 30000
core.cpus = core.mems = "0"
rate.create
core.create
# CPU core 0 and rate 30%
puts "attach /test group with cpu core 0 and rate 30%"
rate.attach
core.attach
We should use
mruby!
1 of 67

Recommended

How to test code with mruby by
How to test code with mrubyHow to test code with mruby
How to test code with mrubyHiroshi SHIBATA
10.1K views39 slides
Practical ngx_mruby by
Practical ngx_mrubyPractical ngx_mruby
Practical ngx_mrubyHiroshi SHIBATA
5.9K views27 slides
Middleware as Code with mruby by
Middleware as Code with mrubyMiddleware as Code with mruby
Middleware as Code with mrubyHiroshi SHIBATA
5.2K views57 slides
How to Begin Developing Ruby Core by
How to Begin Developing Ruby CoreHow to Begin Developing Ruby Core
How to Begin Developing Ruby CoreHiroshi SHIBATA
1.9K views27 slides
Large-scaled Deploy Over 100 Servers in 3 Minutes by
Large-scaled Deploy Over 100 Servers in 3 MinutesLarge-scaled Deploy Over 100 Servers in 3 Minutes
Large-scaled Deploy Over 100 Servers in 3 MinutesHiroshi SHIBATA
3.8K views89 slides
How to Begin to Develop Ruby Core by
How to Begin to Develop Ruby CoreHow to Begin to Develop Ruby Core
How to Begin to Develop Ruby CoreHiroshi SHIBATA
2.9K views80 slides

More Related Content

What's hot

20141210 rakuten techtalk by
20141210 rakuten techtalk20141210 rakuten techtalk
20141210 rakuten techtalkHiroshi SHIBATA
3.9K views100 slides
Gemification plan of Standard Library on Ruby by
Gemification plan of Standard Library on RubyGemification plan of Standard Library on Ruby
Gemification plan of Standard Library on RubyHiroshi SHIBATA
351 views14 slides
RubyGems 3 & 4 by
RubyGems 3 & 4RubyGems 3 & 4
RubyGems 3 & 4Hiroshi SHIBATA
11.5K views64 slides
Dependency Resolution with Standard Libraries by
Dependency Resolution with Standard LibrariesDependency Resolution with Standard Libraries
Dependency Resolution with Standard LibrariesHiroshi SHIBATA
803 views24 slides
The details of CI/CD environment for Ruby by
The details of CI/CD environment for RubyThe details of CI/CD environment for Ruby
The details of CI/CD environment for RubyHiroshi SHIBATA
1.1K views39 slides
How to develop Jenkins plugin using to ruby and Jenkins.rb by
How to develop Jenkins plugin using to ruby and Jenkins.rbHow to develop Jenkins plugin using to ruby and Jenkins.rb
How to develop Jenkins plugin using to ruby and Jenkins.rbHiroshi SHIBATA
1.1K views76 slides

What's hot(20)

Gemification plan of Standard Library on Ruby by Hiroshi SHIBATA
Gemification plan of Standard Library on RubyGemification plan of Standard Library on Ruby
Gemification plan of Standard Library on Ruby
Hiroshi SHIBATA351 views
Dependency Resolution with Standard Libraries by Hiroshi SHIBATA
Dependency Resolution with Standard LibrariesDependency Resolution with Standard Libraries
Dependency Resolution with Standard Libraries
Hiroshi SHIBATA803 views
The details of CI/CD environment for Ruby by Hiroshi SHIBATA
The details of CI/CD environment for RubyThe details of CI/CD environment for Ruby
The details of CI/CD environment for Ruby
Hiroshi SHIBATA1.1K views
How to develop Jenkins plugin using to ruby and Jenkins.rb by Hiroshi SHIBATA
How to develop Jenkins plugin using to ruby and Jenkins.rbHow to develop Jenkins plugin using to ruby and Jenkins.rb
How to develop Jenkins plugin using to ruby and Jenkins.rb
Hiroshi SHIBATA1.1K views
The Future of library dependency management of Ruby by Hiroshi SHIBATA
 The Future of library dependency management of Ruby The Future of library dependency management of Ruby
The Future of library dependency management of Ruby
Hiroshi SHIBATA644 views
Practical Testing of Ruby Core by Hiroshi SHIBATA
Practical Testing of Ruby CorePractical Testing of Ruby Core
Practical Testing of Ruby Core
Hiroshi SHIBATA16.6K views
The Future of Dependency Management for Ruby by Hiroshi SHIBATA
The Future of Dependency Management for RubyThe Future of Dependency Management for Ruby
The Future of Dependency Management for Ruby
Hiroshi SHIBATA7.4K views
Hijacking Ruby Syntax in Ruby (RubyConf 2018) by SATOSHI TAGOMORI
Hijacking Ruby Syntax in Ruby (RubyConf 2018)Hijacking Ruby Syntax in Ruby (RubyConf 2018)
Hijacking Ruby Syntax in Ruby (RubyConf 2018)
SATOSHI TAGOMORI11.1K views
Leave end-to-end testing to Capybara by Hiroshi SHIBATA
Leave end-to-end testing to CapybaraLeave end-to-end testing to Capybara
Leave end-to-end testing to Capybara
Hiroshi SHIBATA2.3K views
How to distribute Ruby to the world by Hiroshi SHIBATA
How to distribute Ruby to the worldHow to distribute Ruby to the world
How to distribute Ruby to the world
Hiroshi SHIBATA3.8K views
How to distribute Ruby to the world by Hiroshi SHIBATA
How to distribute Ruby to the worldHow to distribute Ruby to the world
How to distribute Ruby to the world
Hiroshi SHIBATA937 views
Gate of Agile Web Development by Koichi ITO
Gate of Agile Web DevelopmentGate of Agile Web Development
Gate of Agile Web Development
Koichi ITO5K views

Viewers also liked

High Performance tDiary by
High Performance tDiaryHigh Performance tDiary
High Performance tDiaryHiroshi SHIBATA
1K views25 slides
GitHub Enterprise with GMO Pepabo by
GitHub Enterprise with GMO PepaboGitHub Enterprise with GMO Pepabo
GitHub Enterprise with GMO PepaboHiroshi SHIBATA
3.9K views26 slides
How DSL works on Ruby by
How DSL works on RubyHow DSL works on Ruby
How DSL works on RubyHiroshi SHIBATA
5.1K views64 slides
成長を加速する minne の技術基盤戦略 by
成長を加速する minne の技術基盤戦略成長を加速する minne の技術基盤戦略
成長を加速する minne の技術基盤戦略Hiroshi SHIBATA
9.4K views40 slides
The story of language development by
The story of language developmentThe story of language development
The story of language developmentHiroshi SHIBATA
11K views45 slides
Advanced technic for OS upgrading in 3 minutes by
Advanced technic for OS upgrading in 3 minutesAdvanced technic for OS upgrading in 3 minutes
Advanced technic for OS upgrading in 3 minutesHiroshi SHIBATA
42K views86 slides

Viewers also liked(8)

GitHub Enterprise with GMO Pepabo by Hiroshi SHIBATA
GitHub Enterprise with GMO PepaboGitHub Enterprise with GMO Pepabo
GitHub Enterprise with GMO Pepabo
Hiroshi SHIBATA3.9K views
成長を加速する minne の技術基盤戦略 by Hiroshi SHIBATA
成長を加速する minne の技術基盤戦略成長を加速する minne の技術基盤戦略
成長を加速する minne の技術基盤戦略
Hiroshi SHIBATA9.4K views
The story of language development by Hiroshi SHIBATA
The story of language developmentThe story of language development
The story of language development
Hiroshi SHIBATA11K views
Advanced technic for OS upgrading in 3 minutes by Hiroshi SHIBATA
Advanced technic for OS upgrading in 3 minutesAdvanced technic for OS upgrading in 3 minutes
Advanced technic for OS upgrading in 3 minutes
Hiroshi SHIBATA42K views
Usecase examples of Packer by Hiroshi SHIBATA
Usecase examples of Packer Usecase examples of Packer
Usecase examples of Packer
Hiroshi SHIBATA14.7K views
技術的負債との付き合い方 by Hiroshi SHIBATA
技術的負債との付き合い方技術的負債との付き合い方
技術的負債との付き合い方
Hiroshi SHIBATA5.1K views

Similar to Middleware as Code with mruby

Toolbox of a Ruby Team by
Toolbox of a Ruby TeamToolbox of a Ruby Team
Toolbox of a Ruby TeamArto Artnik
422 views38 slides
Mongodb by
MongodbMongodb
MongodbScott Motte
4.9K views18 slides
Dragoncraft Architectural Overview by
Dragoncraft Architectural OverviewDragoncraft Architectural Overview
Dragoncraft Architectural Overviewjessesanford
653 views28 slides
Ruby C extensions at the Ruby drink-up of Sophia, April 2012 by
Ruby C extensions at the Ruby drink-up of Sophia, April 2012Ruby C extensions at the Ruby drink-up of Sophia, April 2012
Ruby C extensions at the Ruby drink-up of Sophia, April 2012rivierarb
2.4K views35 slides
Practical Use of MongoDB for Node.js by
Practical Use of MongoDB for Node.jsPractical Use of MongoDB for Node.js
Practical Use of MongoDB for Node.jsasync_io
19.9K views54 slides
Hacking with ruby2ruby by
Hacking with ruby2rubyHacking with ruby2ruby
Hacking with ruby2rubyMarc Chung
1.4K views60 slides

Similar to Middleware as Code with mruby(20)

Toolbox of a Ruby Team by Arto Artnik
Toolbox of a Ruby TeamToolbox of a Ruby Team
Toolbox of a Ruby Team
Arto Artnik422 views
Dragoncraft Architectural Overview by jessesanford
Dragoncraft Architectural OverviewDragoncraft Architectural Overview
Dragoncraft Architectural Overview
jessesanford653 views
Ruby C extensions at the Ruby drink-up of Sophia, April 2012 by rivierarb
Ruby C extensions at the Ruby drink-up of Sophia, April 2012Ruby C extensions at the Ruby drink-up of Sophia, April 2012
Ruby C extensions at the Ruby drink-up of Sophia, April 2012
rivierarb2.4K views
Practical Use of MongoDB for Node.js by async_io
Practical Use of MongoDB for Node.jsPractical Use of MongoDB for Node.js
Practical Use of MongoDB for Node.js
async_io19.9K views
Hacking with ruby2ruby by Marc Chung
Hacking with ruby2rubyHacking with ruby2ruby
Hacking with ruby2ruby
Marc Chung1.4K views
Cloud meets Fog & Puppet A Story of Version Controlled Infrastructure by Habeeb Rahman
Cloud meets Fog & Puppet A Story of Version Controlled InfrastructureCloud meets Fog & Puppet A Story of Version Controlled Infrastructure
Cloud meets Fog & Puppet A Story of Version Controlled Infrastructure
Habeeb Rahman3.3K views
Control your deployments with Capistrano by Ramazan K
Control your deployments with CapistranoControl your deployments with Capistrano
Control your deployments with Capistrano
Ramazan K2.6K views
Rspec and Capybara Intro Tutorial at RailsConf 2013 by Brian Sam-Bodden
Rspec and Capybara Intro Tutorial at RailsConf 2013Rspec and Capybara Intro Tutorial at RailsConf 2013
Rspec and Capybara Intro Tutorial at RailsConf 2013
Brian Sam-Bodden29.7K views
JRuby, Ruby, Rails and You on the Cloud by Hiro Asari
JRuby, Ruby, Rails and You on the CloudJRuby, Ruby, Rails and You on the Cloud
JRuby, Ruby, Rails and You on the Cloud
Hiro Asari1.3K views
Node.js - The New, New Hotness by Daniel Shaw
Node.js - The New, New HotnessNode.js - The New, New Hotness
Node.js - The New, New Hotness
Daniel Shaw984 views
Rails Engine | Modular application by mirrec
Rails Engine | Modular applicationRails Engine | Modular application
Rails Engine | Modular application
mirrec6.3K views
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011 by Nick Sieger
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
Nick Sieger3.6K views
JUDCon 2010 Boston : TorqueBox by marekgoldmann
JUDCon 2010 Boston : TorqueBoxJUDCon 2010 Boston : TorqueBox
JUDCon 2010 Boston : TorqueBox
marekgoldmann556 views
Cloud Foundry Open Tour China (english) by marklucovsky
Cloud Foundry Open Tour China (english)Cloud Foundry Open Tour China (english)
Cloud Foundry Open Tour China (english)
marklucovsky368 views
우리가 모르는 노드로 할 수 있는 몇가지 by Rhio Kim
우리가 모르는 노드로 할 수 있는 몇가지우리가 모르는 노드로 할 수 있는 몇가지
우리가 모르는 노드로 할 수 있는 몇가지
Rhio Kim2K views
Puppet at Opera Sofware - PuppetCamp Oslo 2013 by Cosimo Streppone
Puppet at Opera Sofware - PuppetCamp Oslo 2013Puppet at Opera Sofware - PuppetCamp Oslo 2013
Puppet at Opera Sofware - PuppetCamp Oslo 2013
Cosimo Streppone1.7K views

More from Hiroshi SHIBATA

How resolve Gem dependencies in your code? by
How resolve Gem dependencies in your code?How resolve Gem dependencies in your code?
How resolve Gem dependencies in your code?Hiroshi SHIBATA
44 views50 slides
How resolve Gem dependencies in your code? by
How resolve Gem dependencies in your code?How resolve Gem dependencies in your code?
How resolve Gem dependencies in your code?Hiroshi SHIBATA
15 views54 slides
Ruby コミッターと歩む Ruby を用いたプロダクト開発 by
Ruby コミッターと歩む Ruby を用いたプロダクト開発Ruby コミッターと歩む Ruby を用いたプロダクト開発
Ruby コミッターと歩む Ruby を用いたプロダクト開発Hiroshi SHIBATA
49 views14 slides
Why ANDPAD commit Ruby and RubyKaigi? by
Why ANDPAD commit Ruby and RubyKaigi?Why ANDPAD commit Ruby and RubyKaigi?
Why ANDPAD commit Ruby and RubyKaigi?Hiroshi SHIBATA
222 views17 slides
RailsGirls から始める エンジニアリングはじめの一歩 by
RailsGirls から始める エンジニアリングはじめの一歩RailsGirls から始める エンジニアリングはじめの一歩
RailsGirls から始める エンジニアリングはじめの一歩Hiroshi SHIBATA
846 views16 slides
How to develop the Standard Libraries of Ruby? by
How to develop the Standard Libraries of Ruby?How to develop the Standard Libraries of Ruby?
How to develop the Standard Libraries of Ruby?Hiroshi SHIBATA
3.6K views25 slides

More from Hiroshi SHIBATA(13)

How resolve Gem dependencies in your code? by Hiroshi SHIBATA
How resolve Gem dependencies in your code?How resolve Gem dependencies in your code?
How resolve Gem dependencies in your code?
Hiroshi SHIBATA44 views
How resolve Gem dependencies in your code? by Hiroshi SHIBATA
How resolve Gem dependencies in your code?How resolve Gem dependencies in your code?
How resolve Gem dependencies in your code?
Hiroshi SHIBATA15 views
Ruby コミッターと歩む Ruby を用いたプロダクト開発 by Hiroshi SHIBATA
Ruby コミッターと歩む Ruby を用いたプロダクト開発Ruby コミッターと歩む Ruby を用いたプロダクト開発
Ruby コミッターと歩む Ruby を用いたプロダクト開発
Hiroshi SHIBATA49 views
Why ANDPAD commit Ruby and RubyKaigi? by Hiroshi SHIBATA
Why ANDPAD commit Ruby and RubyKaigi?Why ANDPAD commit Ruby and RubyKaigi?
Why ANDPAD commit Ruby and RubyKaigi?
Hiroshi SHIBATA222 views
RailsGirls から始める エンジニアリングはじめの一歩 by Hiroshi SHIBATA
RailsGirls から始める エンジニアリングはじめの一歩RailsGirls から始める エンジニアリングはじめの一歩
RailsGirls から始める エンジニアリングはじめの一歩
Hiroshi SHIBATA846 views
How to develop the Standard Libraries of Ruby? by Hiroshi SHIBATA
How to develop the Standard Libraries of Ruby?How to develop the Standard Libraries of Ruby?
How to develop the Standard Libraries of Ruby?
Hiroshi SHIBATA3.6K views
Roadmap for RubyGems 4 and Bundler 3 by Hiroshi SHIBATA
Roadmap for RubyGems 4 and Bundler 3Roadmap for RubyGems 4 and Bundler 3
Roadmap for RubyGems 4 and Bundler 3
Hiroshi SHIBATA794 views
The Future of library dependency manageement of Ruby by Hiroshi SHIBATA
The Future of library dependency manageement of RubyThe Future of library dependency manageement of Ruby
The Future of library dependency manageement of Ruby
Hiroshi SHIBATA988 views
The Future of Bundled Bundler by Hiroshi SHIBATA
The Future of Bundled BundlerThe Future of Bundled Bundler
The Future of Bundled Bundler
Hiroshi SHIBATA4.7K views
Productive Organization with Ruby by Hiroshi SHIBATA
Productive Organization with RubyProductive Organization with Ruby
Productive Organization with Ruby
Hiroshi SHIBATA545 views
Gemification for Ruby 2.5/3.0 by Hiroshi SHIBATA
Gemification for Ruby 2.5/3.0Gemification for Ruby 2.5/3.0
Gemification for Ruby 2.5/3.0
Hiroshi SHIBATA1.3K views

Recently uploaded

Updates on the LINSTOR Driver for CloudStack - Rene Peinthor - LINBIT by
Updates on the LINSTOR Driver for CloudStack - Rene Peinthor - LINBITUpdates on the LINSTOR Driver for CloudStack - Rene Peinthor - LINBIT
Updates on the LINSTOR Driver for CloudStack - Rene Peinthor - LINBITShapeBlue
166 views8 slides
Backup and Disaster Recovery with CloudStack and StorPool - Workshop - Venko ... by
Backup and Disaster Recovery with CloudStack and StorPool - Workshop - Venko ...Backup and Disaster Recovery with CloudStack and StorPool - Workshop - Venko ...
Backup and Disaster Recovery with CloudStack and StorPool - Workshop - Venko ...ShapeBlue
144 views12 slides
Uni Systems for Power Platform.pptx by
Uni Systems for Power Platform.pptxUni Systems for Power Platform.pptx
Uni Systems for Power Platform.pptxUni Systems S.M.S.A.
61 views21 slides
Cencora Executive Symposium by
Cencora Executive SymposiumCencora Executive Symposium
Cencora Executive Symposiummarketingcommunicati21
139 views14 slides
Centralized Logging Feature in CloudStack using ELK and Grafana - Kiran Chava... by
Centralized Logging Feature in CloudStack using ELK and Grafana - Kiran Chava...Centralized Logging Feature in CloudStack using ELK and Grafana - Kiran Chava...
Centralized Logging Feature in CloudStack using ELK and Grafana - Kiran Chava...ShapeBlue
101 views17 slides
How to Re-use Old Hardware with CloudStack. Saving Money and the Environment ... by
How to Re-use Old Hardware with CloudStack. Saving Money and the Environment ...How to Re-use Old Hardware with CloudStack. Saving Money and the Environment ...
How to Re-use Old Hardware with CloudStack. Saving Money and the Environment ...ShapeBlue
123 views28 slides

Recently uploaded(20)

Updates on the LINSTOR Driver for CloudStack - Rene Peinthor - LINBIT by ShapeBlue
Updates on the LINSTOR Driver for CloudStack - Rene Peinthor - LINBITUpdates on the LINSTOR Driver for CloudStack - Rene Peinthor - LINBIT
Updates on the LINSTOR Driver for CloudStack - Rene Peinthor - LINBIT
ShapeBlue166 views
Backup and Disaster Recovery with CloudStack and StorPool - Workshop - Venko ... by ShapeBlue
Backup and Disaster Recovery with CloudStack and StorPool - Workshop - Venko ...Backup and Disaster Recovery with CloudStack and StorPool - Workshop - Venko ...
Backup and Disaster Recovery with CloudStack and StorPool - Workshop - Venko ...
ShapeBlue144 views
Centralized Logging Feature in CloudStack using ELK and Grafana - Kiran Chava... by ShapeBlue
Centralized Logging Feature in CloudStack using ELK and Grafana - Kiran Chava...Centralized Logging Feature in CloudStack using ELK and Grafana - Kiran Chava...
Centralized Logging Feature in CloudStack using ELK and Grafana - Kiran Chava...
ShapeBlue101 views
How to Re-use Old Hardware with CloudStack. Saving Money and the Environment ... by ShapeBlue
How to Re-use Old Hardware with CloudStack. Saving Money and the Environment ...How to Re-use Old Hardware with CloudStack. Saving Money and the Environment ...
How to Re-use Old Hardware with CloudStack. Saving Money and the Environment ...
ShapeBlue123 views
CloudStack Object Storage - An Introduction - Vladimir Petrov - ShapeBlue by ShapeBlue
CloudStack Object Storage - An Introduction - Vladimir Petrov - ShapeBlueCloudStack Object Storage - An Introduction - Vladimir Petrov - ShapeBlue
CloudStack Object Storage - An Introduction - Vladimir Petrov - ShapeBlue
ShapeBlue93 views
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas... by Bernd Ruecker
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...
Bernd Ruecker50 views
NTGapps NTG LowCode Platform by Mustafa Kuğu
NTGapps NTG LowCode Platform NTGapps NTG LowCode Platform
NTGapps NTG LowCode Platform
Mustafa Kuğu365 views
VNF Integration and Support in CloudStack - Wei Zhou - ShapeBlue by ShapeBlue
VNF Integration and Support in CloudStack - Wei Zhou - ShapeBlueVNF Integration and Support in CloudStack - Wei Zhou - ShapeBlue
VNF Integration and Support in CloudStack - Wei Zhou - ShapeBlue
ShapeBlue163 views
Hypervisor Agnostic DRS in CloudStack - Brief overview & demo - Vishesh Jinda... by ShapeBlue
Hypervisor Agnostic DRS in CloudStack - Brief overview & demo - Vishesh Jinda...Hypervisor Agnostic DRS in CloudStack - Brief overview & demo - Vishesh Jinda...
Hypervisor Agnostic DRS in CloudStack - Brief overview & demo - Vishesh Jinda...
ShapeBlue120 views
KVM Security Groups Under the Hood - Wido den Hollander - Your.Online by ShapeBlue
KVM Security Groups Under the Hood - Wido den Hollander - Your.OnlineKVM Security Groups Under the Hood - Wido den Hollander - Your.Online
KVM Security Groups Under the Hood - Wido den Hollander - Your.Online
ShapeBlue181 views
Live Demo Showcase: Unveiling Dell PowerFlex’s IaaS Capabilities with Apache ... by ShapeBlue
Live Demo Showcase: Unveiling Dell PowerFlex’s IaaS Capabilities with Apache ...Live Demo Showcase: Unveiling Dell PowerFlex’s IaaS Capabilities with Apache ...
Live Demo Showcase: Unveiling Dell PowerFlex’s IaaS Capabilities with Apache ...
ShapeBlue85 views
State of the Union - Rohit Yadav - Apache CloudStack by ShapeBlue
State of the Union - Rohit Yadav - Apache CloudStackState of the Union - Rohit Yadav - Apache CloudStack
State of the Union - Rohit Yadav - Apache CloudStack
ShapeBlue253 views
CloudStack Managed User Data and Demo - Harikrishna Patnala - ShapeBlue by ShapeBlue
CloudStack Managed User Data and Demo - Harikrishna Patnala - ShapeBlueCloudStack Managed User Data and Demo - Harikrishna Patnala - ShapeBlue
CloudStack Managed User Data and Demo - Harikrishna Patnala - ShapeBlue
ShapeBlue94 views
Digital Personal Data Protection (DPDP) Practical Approach For CISOs by Priyanka Aash
Digital Personal Data Protection (DPDP) Practical Approach For CISOsDigital Personal Data Protection (DPDP) Practical Approach For CISOs
Digital Personal Data Protection (DPDP) Practical Approach For CISOs
Priyanka Aash153 views
"Surviving highload with Node.js", Andrii Shumada by Fwdays
"Surviving highload with Node.js", Andrii Shumada "Surviving highload with Node.js", Andrii Shumada
"Surviving highload with Node.js", Andrii Shumada
Fwdays53 views
2FA and OAuth2 in CloudStack - Andrija Panić - ShapeBlue by ShapeBlue
2FA and OAuth2 in CloudStack - Andrija Panić - ShapeBlue2FA and OAuth2 in CloudStack - Andrija Panić - ShapeBlue
2FA and OAuth2 in CloudStack - Andrija Panić - ShapeBlue
ShapeBlue103 views

Middleware as Code with mruby

  • 1. Middleware as Code with mruby Details of mruby usage in production
  • 2. self.introduce => { name: “SHIBATA Hiroshi”, nickname: “hsbt”, title: “Chief engineer at GMO Pepabo, Inc.”, commit_bits: [“ruby”, “rake”, “rubygems”, “rdoc”, “tdiary”, “hiki”, “railsgirls”, “railsgirls-jp”, “jenkins”], sites: [“ruby-lang.org”, “rubyci.com”, “railsgirls.com”, “railsgirls.jp”], }
  • 3. I’m from Tokyo, Japan Tokyo Matze RDRC
  • 4. I’m from Asakusa.rb Asakusa.rb is one of the most active meet-ups in Tokyo, Japan. @a_matsuda (Ruby/Rails committer, RubyKaigi organizer) @kakutani (RubyKaigi organizer) @ko1 (Ruby committer) @takkanm (Ruby/Rails programmer) @gunjisatoshi (Rubyist Magazine editor) @hsbt (Me!)
  • 5. I’m from the Ruby core team We are working on the next version of Ruby, 2.3.0, now. However, the main feature is under “TBD” status. Some libraries will be omitted from stdlib such as rake, net-telnet, etc.. If you have any issue, please submit it to our issue tracker at http://bugs.ruby-lang.org We hold the core developer meeting every months, and discuss various issues and ideas on Ruby. See https://bugs.ruby-lang.org/ projects/ruby/wiki/#Developer-Meetings for details.
  • 6. Middleware as Code with mruby
  • 7. Today’s target • Web engineer(Rails programmer) • Operation engineer • QA/test engineer • mruby committer(Matz)
  • 9. What's mruby? “mruby is the lightweight implementation of the Ruby language complying to (part of) the ISO standard. Its syntax is Ruby 1.9 compatible.” https://github.com/mruby/mruby#whats-mruby
  • 10. Differences between mruby and CRuby • The mruby runtime and libraries are embedded all into a single binary. • By default, mruby provides just a minimum set of standard libraries such as String, Array, Hash, etc. • Some of standard libraries in CRuby are NOT bundled in mruby, for example, IO, Regex, Socket, etc.. • mruby doesn't provide “require”, “sleep”, “p”, etc.
  • 11. Advantages of mruby against CRuby • Single binary without pure ruby files. • Embeddable into middlewares like below: • apache/nginx • groonga • mysql • Fun!!1 # most important thing
  • 12. Dive into mruby build You can declare prerequisite libraries in `build_config.rb` MRuby::Build.new do |conf| toolchain :gcc conf.gembox 'full-core' conf.gem :github => 'iij/mruby-io' conf.gem :github => 'iij/mruby-env' (snip) conf.gem :github => 'matsumoto-r/mruby-uname' conf.gem '../mrbgems/ngx_mruby_mrblib' end
  • 13. mrbgem See https://github.com/mruby/mruby/blob/master/doc/mrbgems/ README.md :) • mrbgem.rake Endpoint of mrbgem, put MRuby::Gem::Specification • mrblib/ Sources for pure ruby extension • src/ Sources for C extension
  • 15. Middleware meets mruby mruby has embeddable mechanism for middlewares like http server, search engine, etc.. Embedded mruby provides ruby runtime and syntax to middlewares. It’s so powerful programming environment for Rubyists.
  • 17. Introduction to ngx_mruby “ngx_mruby is A Fast and Memory-Efficient Web Server Extension Mechanism Using Scripting Language mruby for nginx.” https://github.com/matsumoto-r/ngx_mruby#whats-ngx_mruby location /proxy { mruby_set_code $backend ' backends = [ "test1.example.com", "test2.example.com", "test3.example.com", ] backends[rand(backends.length)] '; } location /hello { mruby_content_handler /path/to/hello.rb cache; } In “nginx.conf”!!!
  • 18. How to build ngx_mruby (and mruby) I suggest to try it on OS X or Linux environment. You can change embedded mgem via “build_config.rb” in ngx_mruby repository. $ git clone https://github.com/matsumoto-r/ngx_mruby $ git clone https://github.com/nginx/nginx $ cd ngx_mruby $ git submodule init && git submodule update comment-out mruby-redis and mruby-vedis $ ./configure —with-ngx-src-root=../nginx $ make build_mruby $ make $ cd ../nginx $ ./objs/nginx -V
  • 19. mruby_content_handler location /hello { mruby_content_handler /path/to/hello.rb cache; } location /hello { mruby_content_handler_code ' Nginx.rputs "hello" Nginx.echo "world!" '; } It’s basic usage of ngx_mruby. These handlers are invoked at every requests
  • 20. mruby_set location /proxy { mruby_set $backend /path/to/proxy.rb cache; } location /proxy { mruby_set_code $backend ' backends = [ "test1.example.com", "test2.example.com", "test3.example.com", ] backends[rand(backends.length)] '; mruby_set sets the return value from mruby code to nginx variable
  • 21. mruby_init http { mruby_init /path/to/init.rb; server { location / { mruby_content_handler /path/to/handler.rb; } } } It’s invoked when nginx master process launched.
  • 22. mruby_init_worker/mruby_exit_worker http { mruby_init /path/to/init.rb; mruby_init_worker /path/to/init_worker.rb; mruby_exit_worker /path/to/exit_worker.rb; server { location / { mruby_content_handler /path/to/handler.rb; } } } It’s invoked when nginx “worker” process is launched.
  • 23. Sample code of ngx_mruby class ProductionCode def initialize(r, c) @r, @c = r, c end def allowed_ip_addresses %w[ 128.0.0.1 ] end def allowed? if (allowed_ip_addresses & [@c.remote_ip, @r.headers_in['X-Real-IP'], @r.headers_in['X-Forwarded-For']].compact).size > 0 return true end (snip for memcached) end return false end ProductionCode.new(Nginx::Request.new, Nginx::Connection.new).allowed?
  • 24. Sample configuration of nginx location /path { mruby_set $allowed ‘/etc/nginx/handler/production_code.rb' cache; if ($allowed = 'true'){ proxy_pass http://upstream; } if ($allowed = 'false'){ return 403; } }
  • 25. Use cases of ngx_mruby • Calculation of digest hash for authentication. • Data sharing with Rails application. • To replace ugly complex nginx.conf with clean, simple, and TESTABLE ruby code.
  • 28. Data sharing with Rails & Restricted access We have photo sharing service named “30days album” This service concept is private photo sharing. We need to have restrict access mechanism for image files and share data of Rails to http middleware.
  • 31. Data sharing with rails using mruby allowed = false memcached = Memcache.new(“127.0.0.1”) allowed_data = memcached.get(session_id) You can share data via persisted storage like memcahed/redis In this case, We share data using rails session key via cookie data.
  • 32. Issue of connection leak and fd open cost We tried to connect memcached at each request using “mruby_handler” This approach open and close network connection each request. We faced problem of connection overflow We discussed the issue with the ngx_mruby author, @matsumoto- r. He solved this issue in a few days. He provided us new handler named “mruby_init_worker”.
  • 34. Share connection in worker process userdata = Userdata.new("memcached_#{Process.pid}") userdata.memcached = Memcached.new(‘128.0.0.1’) userdata = Userdata.new("memcached_#{Process.pid}") userdata.memcached.close if userdata.memcached http { (snip) mruby_init_worker /etc/nginx/handler/session_connect.rb cache; mruby_exit_worker /etc/nginx/handler/session_disconnect.rb cache; (snip) } session_connect.rb session_disconnect.rb nginx.conf
  • 35. Restrict access to image asset allowed = false userdata = Userdata.new("memcached_#{Process.pid}") if allowed_data = userdata.memcached.get(session_id) if @r.uri =~ //image/#{allowed_data}/ allowed = true end end allowed Allowing uri string in session is compared accessing uri. If it matches, ngx_mruby allows this request to access image asset.
  • 36. Comparison of performanceResptime(sec) 0 0.05 0.1 0.15 0.2 0.25 0.3 nginx + perlbal ngx_mruby transferrate(byte/sec) 0 5 10 15 20 25 30 nginx + perlbal ngx_mruby
  • 37. 🌟 STAR IT 🌟 https://github.com/ matsumoto-r/ngx_mruby
  • 39. Someone said “Test is redundant”
  • 40. What’s motivation • We are using ngx_mruby in production. • We should test every production code. • Testing mruby code is a cutting edge technical issue.
  • 41. Prototype concept • Use CRuby(version independent: 2.0.0, 2.1, 2.2) • Use test-unit • Test “ruby code” without real world behavior.
  • 42. Sample code of ngx_mruby class ProductionCode def initialize(r, c) @r, @c = r, c end def allowed_ip_addresses %w[ 128.0.0.1 ] end def allowed? if (allowed_ip_addresses & [@c.remote_ip, @r.headers_in['X-Real-IP'], @r.headers_in['X-Forwarded-For']].compact).size > 0 return true end (snip for memcached) end return false end ProductionCode.new(Nginx::Request.new, Nginx::Connection.new).allowed?
  • 43. Dummy class of ngx_mruby class Nginx class Request attr_accessor :uri, :headers_in, :args, :method, :hostname def initialize @uri = nil @headers_in = {} @args = nil @method = 'GET' @hostname = nil end end class Connection attr_accessor :remote_ip def initialize @remote_ip = nil end end
  • 44. Dummy class of mgem Memcached = MemCache class Memcached def close servers.each(&:close) end end class Userdata def initialize(*args) end def memcached Memcached.new('127.0.0.1:11211') end end
  • 45. Skeleton of test-case require_relative '../lib/production/code/path/mruby.rb' class MRubyTest < Test::Unit::TestCase def setup @r = Nginx::Request.new @c = Nginx::Connection.new end def test_discard_access assert !ProductionCode.new(@r, @c).allowed? end end
  • 46. Restrict requests with cookie session require_relative '../lib/production/code/path/mruby.rb' class MRubyTest < Test::Unit::TestCase def setup @r = Nginx::Request.new @c = Nginx::Connection.new end def test_session_access MemCache.new('127.0.0.1').set 'a77a2a0cc91b739438dfc9dc47c5dd36' @r.headers_in['cookie'] = '_session=a77a2a0cc91b739438dfc9dc47c5dd36;' @r.uri = '/secret/file/path' assert ProductionCode.new(@r, @c).allowed? end end
  • 47. Run test % ruby test/production_code_test.rb Loaded suite test/production_code_test Started ......... Finished in 0.031017 seconds. --------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------- -------------------- 9 tests, 15 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed --------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------- -------------------- 290.16 tests/s, 483.61 assertions/s
  • 49. Our concerns on CRuby testing • We can test “ruby code”. But it’s not fulfill testing requirements. We need to test ngx_mruby behavior. • We use a lot of mock/stub classes. It’s ruby’s dark-side. • We need to make easy task runner.
  • 51. Use mruby directly instead of CRuby mruby-mtest class Test4MTest < MTest::Unit::TestCase def test_assert assert(true) assert(true, 'true sample test') end end MTest::Unit.new.run MRuby::Build.new do |conf| (snip) conf.gem :github => 'matsumoto-r/mruby-uname' # ngx_mruby extended class conf.gem ‘../mrbgems/ngx_mruby_mrblib' con.gem :github => ‘iij/mruby-mtest’ (snip) end build_config.rb test_4m_test.rb
  • 52. Inline testing for mruby-mtest class ProductionCode (snip) end if Object.const_defined?(:MTest) class Nginx (snip) end class TestProductionCode < MTest::Unit::TestCase (snip) end MTest::Unit.new.run else ProductionCode.new(Nginx::Request.new, Nginx::Connection.new).allowed? end
  • 53. Build mruby for mruby testing $ cd ngx_mruby/mruby $ cp ../build_config.rb . $ make $ cp bin/mruby /path/to/test/bin You need to get mruby binary before embed ngx_mruby. % ./path/to/test/bin/mruby -v mruby 1.1.0 (2014-11-19) ^C
  • 54. Test runner for mruby-mtest require 'rake' desc 'Run mruby-mtest' task :mtest do target = "modules/path/to/production/code" mruby_binary = File.expand_path("../#{target}/test_bin/mruby", __FILE__) mruby_files = FileList["#{target}/**/*.rb"] mruby_files.each do |f| absolute_path = File.expand_path("../#{f}", __FILE__) system "#{mruby_binary} #{absolute_path}" end end
  • 55. Advantage of mruby testing Rapid! % rake mtest # Running tests: ......... Finished tests in 0.007924s, 1135.7900 tests/s, 1892.9833 assertions/s. 9 tests, 15 assertions, 0 failures, 0 errors, 0 skips
  • 57. Deployment strategy We need to prepare following things for production use: • Build target binary ngx_mruby in production environment • Write manifest file of puppet/chef • Test binary and mruby code continuously Deploy!
  • 58. Build on docker FROM centos:7 MAINTAINER hsbt RUN yum -y install --enablerepo=extras epel-release RUN yum -y groupinstall "Development Tools" RUN yum -y install git libffi-devel libevent-devel cyrus-sasl-devel openssl-devel pcre-devel tar zlib- devel rake (snip) RUN git clone --depth 1 --branch v1.8.11 --recursive https://github.com/matsumoto-r/ngx_mruby.git / usr/local/src/ngx_mruby ADD build_config.rb /usr/local/src/ngx_mruby/build_config.rb RUN git clone --depth 1 --branch v1.9.0 https://github.com/nginx/nginx.git /usr/local/src/nginx RUN cd /usr/local/src/ngx_mruby && NGINX_SRC_ENV=/usr/local/src/nginx NGINX_CONFIG_OPT_ENV="--prefix=/etc/nginx …'" sh build.sh https://gist.github.com/hsbt/f5a3a83ec2ebf8169f38
  • 59. Build on docker $ docker build --tag=nginx_mruby:centos7 --file=Dockerfile.centos7 . You can modify build_config.rb. After that, You run “docker build” $ export DIR=`pwd` && docker run --volume="$DIR:/tmp:rw" --user=root "nginx_mruby:centos7" "cp" "-a" "/usr/local/src/nginx/objs/nginx" "/tmp" You got ngx_mruby binary for centos7 with “docker run”
  • 60. official nginx package + ngx_mruby % rpm -qlp nginx-1.9.0-1.el7.ngx.x86_64.rpm /etc/logrotate.d/nginx /etc/nginx /etc/nginx/conf.d /etc/nginx/conf.d/default.conf (snip) /usr/sbin/nginx /usr/share/nginx /usr/share/nginx/html /usr/share/nginx/html/50x.html /usr/share/nginx/html/index.html /var/cache/nginx /var/log/nginx Replace ngx_mruby binary from official package
  • 61. example of puppet class ngx_mruby::install { include ngx_mruby::params (snip) file { '/usr/local/src/nginx.tar.gz': source => "puppet:///modules/ngx_mruby/usr/local/src/nginx-${::platform}.tar.gz", notify => Exec['cleanup and unzip ngx_mruby'], } $install_dir = dirname($ngx_mruby::params::nginx) exec { 'cleanup and unzip ngx_mruby': path => ['/bin', '/usr/bin'], command => "tar xf /usr/local/src/nginx.tar.gz -C ${install_dir}", require => File['/usr/local/src/nginx.tar.gz'], refreshonly => true, } (snip) }
  • 62. Next challenge • mruby binary can have different library from one in production. • For continuous integration, we need to prepare cross-compile or live compile environment. • Replace nginx.conf with mruby code backed by test code.
  • 63. cross-compile and CI mruby supports cross-compile configuration. We made “https://github.com/matsumoto-r/mruby-cross- compile-on-mac-osx” MRuby::Build.new do |conf| # ... (snip) ... # the last line of conf.gem load '/path/to/mruby-cross-compile-on-mac-osx/mrbgem.rake' end
  • 65. mruby-ipvs “mruby-ipvs is an interface to the IP Virtual Server(IPVS) for mruby.” https://github.com/rrreeeyyy/mruby-ipvs # Create IPVS::Service instance. s = IPVS::Service.new({ 'addr' => '10.0.0.1:80', 'port' => 80, 'sched_name' => 'wrr' }) # apply to IPVS. s.add_service # Create IPVS::Dest instance. d = IPVS::Dest.new({ 'addr' => '192.168.0.1', 'port' => 80, 'weight' => 1 }) # Add destination to IPVS::Service instance. s.add_dest(d)
  • 66. mruby_cgroup mruby cgroup module using libcgroup https://github.com/matsumoto-r/mruby-cgroup rate = Cgroup::CPU.new "test" core = Cgroup::CPUSET.new "test" rate.cfs_quota_us = 30000 core.cpus = core.mems = "0" rate.create core.create # CPU core 0 and rate 30% puts "attach /test group with cpu core 0 and rate 30%" rate.attach core.attach