Skip to content

Commit 2f4695e

Browse files
christopherheinbrendandburns
authored andcommitted
Adding Rubygem for Ruby Applications (#21)
**Why:** * Currently tested to run a `sinatra` application * Uses the same `mp-compiler` to build out the specs * Uses an `alpine` image out of the box to run
1 parent bceb824 commit 2f4695e

27 files changed

+673
-0
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,13 @@ When you run this program via the `java` command or your IDE, rather than simply
3333
packages up the Java code in a container, and runs that container.
3434

3535
## What languages do you support?
36+
3637
Currently:
3738
* [java](java)
3839
* [.NET core](dotnet)
3940
* [javascript](javascript) (NodeJS)
4041
* [go](go)
42+
* [ruby](ruby)
4143

4244
But it's fairly straightforward to add other languages, we would love to see contributions.
4345

@@ -47,6 +49,7 @@ For more details see the more complete walkthroughs for each language:
4749
* [java tutorial](tutorials/java/tutorial.md)
4850
* [.NET Core tutorial](tutorials/dotnet/tutorial.md)
4951
* [javascript tutorial](tutorials/javascript/tutorial.md)
52+
* [Ruby tutorial](tutorials/ruby/tutorial.md)
5053

5154
## Contribute
5255
There are many ways to contribute to Metaparticle

ruby/README.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Metaparticle/Package for Ruby
2+
Metaparticle/Package is a collection of libraries intended to
3+
make building and deploying containers a seamless and idiomatic
4+
experience for developers.
5+
6+
This is the implementation for Ruby.
7+
8+
## Introduction
9+
Metaparticle/Package simplifies and centralizes the task of
10+
building and deploying a container image.
11+
12+
Here is a quick example.
13+
14+
Consider this simple Ruby application:
15+
16+
```ruby
17+
class App < Sinatra::Base
18+
set :bind, '0.0.0.0'
19+
20+
get '/' do
21+
'metaparticle from ruby!'
22+
end
23+
end
24+
```
25+
26+
To containerize this application, you need to use the `metaparticle` gem and
27+
the `Metaparticle::Package` wrapper class like this:
28+
29+
```ruby
30+
require 'metaparticle'
31+
require 'sinatra/base'
32+
33+
Metaparticle::Package.containerize(
34+
{
35+
name: 'sinatra-app',
36+
ports: [4567],
37+
replicas: 3,
38+
runner: 'metaparticle',
39+
repository: 'christopherhein',
40+
publish: true,
41+
public: true
42+
}) do
43+
class App < Sinatra::Base
44+
set :bind, '0.0.0.0'
45+
46+
get '/' do
47+
'metaparticle from ruby!'
48+
end
49+
run!
50+
end
51+
end
52+
```
53+
54+
Then when you run the ruby file it will automatically create a docker image,
55+
push to your registry of choice, and then use `mp-compiler` to push to your k8s
56+
cluster.
57+
58+
## Tutorial
59+
For a more complete exploration of the Metaparticle/Package for Ruby, please see the [in-depth tutorial](../tutorials/ruby/tutorial.md).
60+

ruby/examples/Dockerfile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM ruby:2.4-alpine
2+
3+
RUN mkdir -p /sinatra-app
4+
WORKDIR /sinatra-app
5+
6+
COPY Gemfile /sinatra-app/
7+
COPY Gemfile.lock /sinatra-app/
8+
RUN bundle install
9+
10+
COPY . /sinatra-app/
11+
CMD ruby app.rb

ruby/examples/Gemfile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
source 'https://rubygems.org'
2+
3+
gem 'sinatra'
4+
# gem 'metaparticle', path: './metaparticle'
5+
gem 'metaparticle'

ruby/examples/Gemfile.lock

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
GEM
2+
remote: https://rubygems.org/
3+
specs:
4+
metaparticle (0.0.0.13)
5+
mustermann (1.0.1)
6+
rack (2.0.3)
7+
rack-protection (2.0.0)
8+
rack
9+
sinatra (2.0.0)
10+
mustermann (~> 1.0)
11+
rack (~> 2.0)
12+
rack-protection (= 2.0.0)
13+
tilt (~> 2.0)
14+
tilt (2.0.8)
15+
16+
PLATFORMS
17+
ruby
18+
19+
DEPENDENCIES
20+
metaparticle
21+
sinatra
22+
23+
BUNDLED WITH
24+
1.15.4

ruby/examples/app.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
require 'rubygems'
2+
require 'metaparticle'
3+
require 'sinatra/base'
4+
5+
class App < Sinatra::Base
6+
set :bind, '0.0.0.0'
7+
8+
get '/' do
9+
'metaparticle from ruby!'
10+
end
11+
end
12+
13+
Metaparticle::Package.containerize(
14+
{
15+
name: 'sinatra-app',
16+
ports: [4567],
17+
replicas: 3,
18+
runner: 'metaparticle',
19+
repository: 'christopherhein',
20+
publish: true,
21+
public: true,
22+
# shardSpec: {
23+
# shards: 3,
24+
# "urlPattern": "(.*)"
25+
# },
26+
}) do
27+
App.run!
28+
end

ruby/metaparticle/.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/.bundle/
2+
/.yardoc
3+
/Gemfile.lock
4+
/_yardoc/
5+
/coverage/
6+
/doc/
7+
/pkg/
8+
/spec/reports/
9+
/tmp/
10+
11+
# rspec failure tracking
12+
.rspec_status

ruby/metaparticle/.rspec

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
--format documentation
2+
--color

ruby/metaparticle/.travis.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
sudo: false
2+
language: ruby
3+
rvm:
4+
- 2.4.0
5+
before_install: gem install bundler -v 1.15.4

ruby/metaparticle/Gemfile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
source "https://rubygems.org"
2+
3+
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4+
5+
# Specify your gem's dependencies in metaparticle.gemspec
6+
gemspec

ruby/metaparticle/README.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Metaparticle
2+
3+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/metaparticle`. To experiment with that code, run `bin/console` for an interactive prompt.
4+
5+
TODO: Delete this and the text above, and describe your gem
6+
7+
## Installation
8+
9+
Add this line to your application's Gemfile:
10+
11+
```ruby
12+
gem 'metaparticle'
13+
```
14+
15+
And then execute:
16+
17+
$ bundle
18+
19+
Or install it yourself as:
20+
21+
$ gem install metaparticle
22+
23+
## Usage
24+
25+
require 'metaparticle'
26+
require 'sinatra/base'
27+
28+
class App < Sinatra::Base
29+
set :bind, '0.0.0.0'
30+
31+
get '/' do
32+
'metaparticle from ruby!'
33+
end
34+
end
35+
36+
Metaparticle::Package.containerize(
37+
{
38+
name: 'sinatra-app',
39+
ports: [4567],
40+
replicas: 3,
41+
runner: 'metaparticle',
42+
repository: 'christopherhein',
43+
publish: true,
44+
public: true
45+
}) do
46+
App.run!
47+
end
48+
49+
## Development
50+
51+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
52+
53+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
54+
55+
## Contributing
56+
57+
Bug reports and pull requests are welcome on GitHub at https://github.com/metaparticle/package.
58+
59+
## License
60+
61+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
62+

ruby/metaparticle/Rakefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
require "bundler/gem_tasks"
2+
require "rspec/core/rake_task"
3+
4+
RSpec::Core::RakeTask.new(:spec)
5+
6+
task :default => :spec

ruby/metaparticle/lib/metaparticle.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
require "metaparticle/version"
2+
require 'metaparticle/package'
3+
4+
module Metaparticle
5+
end
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
module Metaparticle
2+
class Docker
3+
def in_docker_container?
4+
if ENV['METAPARTICLE_IN_CONTAINER'] == "true"
5+
return true
6+
end
7+
8+
# Using same hack to work on macOS
9+
begin
10+
info = File.readlines('/proc/1/cgroup')
11+
12+
# horribly ineffient, can do this better
13+
if !info.select {|line| line =~ /docker/}.empty?
14+
return true
15+
end
16+
if !info.select {|line| line =~ /kubepods/}.empty?
17+
return true
18+
end
19+
rescue
20+
return false
21+
end
22+
23+
return false
24+
end
25+
end
26+
end
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module Metaparticle
2+
class DockerBuilder
3+
def initialize(config)
4+
@config = config
5+
end
6+
7+
def build
8+
`docker build -t #{@config.image} .`
9+
end
10+
11+
def push
12+
`docker push #{@config.image}`
13+
end
14+
end
15+
end
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module Metaparticle
2+
class DockerRunner
3+
def initialize(config)
4+
@config = config
5+
end
6+
7+
def run
8+
`docker run -it --name #{@config.name} #{port_string} #{@config.image}`
9+
end
10+
11+
private
12+
def port_string
13+
@port_string = @config.ports.map {|port| "-p #{port}:#{port}" }.join(" ")
14+
end
15+
end
16+
end
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
require 'fileutils'
2+
3+
module Metaparticle
4+
class MetaparticleRunner
5+
def initialize(config)
6+
@config = config
7+
end
8+
9+
def run
10+
options = {
11+
name: @config.name,
12+
guid: 1234567,
13+
services: [
14+
{
15+
name: @config.name,
16+
replicas: @config.replicas,
17+
shardSpec: @config.shardSpec,
18+
containers: [
19+
{
20+
image: @config.image
21+
}
22+
],
23+
ports: @config.ports.map {|p| {number: p}}
24+
}
25+
],
26+
serve: {
27+
name: @config.name
28+
}
29+
}
30+
if @config.public
31+
options[:serve][:public] = true
32+
end
33+
34+
create_directory
35+
36+
File.open(".metaparticle/service.json", "w") do |f|
37+
f.write(options.compact!.to_json)
38+
end
39+
40+
`mp-compiler -f .metaparticle/service.json`
41+
`mp-compiler -f .metaparticle/service.json --deploy=false --attach=true`
42+
end
43+
44+
private
45+
def create_directory
46+
FileUtils::mkdir_p('.metaparticle')
47+
end
48+
end
49+
end

0 commit comments

Comments
 (0)