SHOYAN BLOG

I am a pragmatic programmer.

SinatraのインストールとRspecでテストする

RubyといえばRuby on Railsが有名ですが、DBを使わないシンプルなアプリケーションの場合はSinatraで十分な気がします。
この記事では、SinatraのインストールとRspecでテストする方法を紹介します。

SinatraのInstall

sinatra_sampleというディレクトリを作成してそこにアプリを作成します。

1
2
mkdir sinatra_sample
cd sinatra_sample

Gemfileを作成します。

1
2
3
4
5
# Gemfile
source 'https://rubygems.org'

gem 'rake'
gem 'sinatra'

bundle install でインストールします。

アプリケーションを作成

myapp.rbを作成します。

1
2
3
4
5
6
# my_app.rb
require 'sinatra'

get '/' do
  'Hello world!'
end

以下のコマンドで実行します。

1
ruby myapp.rb

ブラウザで以下にアクセスするとHello world!と表示されます。
http://localhost:4567

あっという間にできましたね。

Rspecでテストをする

RspecでテストするためにRspecをインストールします。

1
2
3
4
5
6
7
8
9
10
11
# Gemfile

source 'https://rubygems.org'

gem 'rake'
gem 'sinatra'

group :test do
  gem 'rspec'
  gem 'rack-test'
end

bundle installでインストールします。

spec/spec_helper.rb を作成します。
spec_helper.rbはrspecの設定を行うためのファイルです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# spec/spec_helper.rb
require 'rack/test'
require 'rspec'

ENV['RACK_ENV'] = 'test'

require File.expand_path '../../myapp.rb', __FILE__

module RSpecMixin
  include Rack::Test::Methods
  def app() Sinatra::Application end
end

RSpec.configure { |c| c.include RSpecMixin }

spec/myapp_spec.rbを作成します。
myapp_spec.rbはアプリケーションをテストするためのファイルです。

1
2
3
4
5
6
7
8
9
# spec/app_spec.rb
require File.expand_path '../spec_helper.rb', __FILE__

describe "My Sinatra Application" do
  it "should allow accessing the home page" do
    get '/'
    expect(last_response).to be_ok
  end
end

テストを実行してみましょう。

1
bundle exec rspec spec
1
2
3
4
5
  bundle exec rspec spec
.

Finished in 0.03119 seconds (files took 0.20975 seconds to load)
1 example, 0 failures

テストが成功しました!

参考文献

資料は以下を参照しました。

  • [英語]http://www.sinatrarb.com/intro.html
  • [日本語]http://www.sinatrarb.com/intro-ja.html
  • [Sinatra Recipes]http://recipes.sinatrarb.com/

Capistrano3-unicornを使う

capistrano3-unicornとは、capistranoでデプロイしたときにunicornのstart/restartをしてくれるgemです。
https://github.com/tablexi/capistrano3-unicorn

Install

Gemfileに以下を追記してbundle installします。

1
2
3
group :development do
  gem 'capistrano3-unicorn'
end

Capfileに以下を追記します。

1
require 'capistrano3/unicorn'

config/deploy.rbに以下を追記します。

1
2
3
4
5
6
after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
  task :restart do
    invoke 'unicorn:restart'
  end
end

これで設定完了です。
cap deployすればunicorn restartが実行されるようになります。

注意点ポイント

設定していて少しわかり辛かった点があります。

unicorn.rbがデフォルトではCURRENT_PATH/config/unicorn/RAILS_ENV.rbに設定されています。
sinatraなどのrails以外のアプリケーションの場合は、RAILS_ENVがセットされていないため、CURRENT_PATH/config/unicorn/.rbのようになってしまいます。
ですので、明示的に設定が必要です。
しかし、設定方法についてドキュメントに明記されてないので少し戸惑いました。

設定はソースを参考にしました。

https://github.com/tablexi/capistrano3-unicorn/blob/master/lib/capistrano3/tasks/unicorn.rake#L4

unicorn_config_pathの設定

以下のようにlambdaを使って設定します。
config/unicorn.rbをunicorn_config_pathとして設定しています。
config/deploy.rb

1
set :unicorn_config_path, -> { File.join(current_path, "config", "unicorn.rb") }

cookbook_fileリソースでCookbookNotFoundが発生した

cookbook_fileでCookbookNotFoundというエラーがでた。
しかし、どこをどうみても合っているようにしか見えず、2時間ほどハマった。

エラーは以下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  * cookbook_file[/etc/nginx/nginx.conf] action create

    ================================================================================
    Error executing action `create` on resource 'cookbook_file[/etc/nginx/nginx.conf]'
    ================================================================================

    Chef::Exceptions::CookbookNotFound
    ----------------------------------
    Cookbook cookbooks not found. If you're loading cookbooks from another cookbook, make sure you configure the dependency in your metadata

    Resource Declaration:
    ---------------------
    # In /var/chef/cache/cookbooks/cookbooks/recipes/default.rb

     25: cookbook_file '/etc/nginx/nginx.conf' do
     26:   source 'nginx.conf'
     27:   owner 'root'
     28:   group 'root'
     29:   mode '0755'
     30: end
     31:

原因はmetadata.rbの名前。
cookbooks/site という構成でcookbookを作成しているのだが、cookbooks/site/metadata.rbのnameが’cookbooks’となっていた。
これによりcookbook_fileリソースがcookbooksというcookbookを参照していたが、そんなものはないのでCookbookNotFoundエラーが発生していた。
nameを’site’と変更してやることでうまくいくようになった。

Dockerでsystemctlでserviceが起動できない

centos7からsystemctlでserviceを起動するようになったが、Dockerで起動すると「Failed to get D-Bus connection: No connection to service manager.」というエラーメッセージがでて起動できないという問題が起こった。

1
2
3
$ docker run -it centos:centos7 /bin/bash
# systemctl
Failed to get D-Bus connection: No connection to service manager.

サービスを起動するためには以下の方法でコンテナを起動すればよい。

1
$ docker run --privileged -d --name httpd centos:centos7 /sbin/init

起動したコンテナでhttpdをinstallして起動する。

1
2
3
4
$ docker exec -it httpd /bin/bash
# yum install httpd -y
# systemctl enable httpd.service
# systemctl start httpd.service

プロセスを確認。起動できている。

1
2
3
4
5
6
7
8
9
ps aux | grep apache

bash-4.2# ps aux | grep apache
apache     168  0.0  0.3 221912  4028 ?        S    05:41   0:00 /usr/sbin/httpd -DFOREGROUND
apache     169  0.0  0.3 221912  4028 ?        S    05:41   0:00 /usr/sbin/httpd -DFOREGROUND
apache     170  0.0  0.3 221912  4028 ?        S    05:41   0:00 /usr/sbin/httpd -DFOREGROUND
apache     171  0.0  0.3 221912  4028 ?        S    05:41   0:00 /usr/sbin/httpd -DFOREGROUND
apache     172  0.0  0.3 221912  4028 ?        S    05:41   0:00 /usr/sbin/httpd -DFOREGROUND
root       180  0.0  0.0   9044   808 ?        S+   05:49   0:00 grep apache

yunanoさんの記事が大変参考になった。

Dockerについて学ぶ

Dockerについてはいくつか書籍が出ているが、プログラマのためのDocker教科書 インフラの基礎知識&コードによる環境構築の自動化が良さそうに思う。
目次を見てみると、インフラの基礎知識からDockerfileを使ったDockerの構築、Docker Composeの使い方、Docker Swarmを使ったマルチホスト環境でのDocker運用まで網羅してある。
また、Dockerの基礎的なことに加え、インフラの基礎とコンテナ仮想化技術についても説明してあるのでDockerを学びつつもインフラについても学べそうだ。

目次

第1章: 抑えておきたいシステム / インフラの知識
第2章: コンテナ仮想化技術とDocker
第3章: Dockerのインストールと基本コマンド
第4章: Dockerfileを使ったコードによるサーバ構築
第5章: Dockerイメージの共有 - Docker Registry
第6章: 複数コンテナの一元管理 - Docker Compose
第7章: マルチホスト環境でのDocker運用 - Docker Machine, Docker Swarm
第8章: クラウドでのDocker運用

Dockerの記事一覧

SHOYAN BLOGではDockerについていくつか記事を書いているので興味があれば見てほしい。

Dockerのサンプルコード

githubでDockerを使ったサンプルコードを公開しているのでこちらも参考にしてほしい。

DockerでRubyアプリケーションをホスティングするサンプルコード

docker-composeを使ってPHPコンテナとMySQLコンテナを連携させるサンプルコード

nginxとrubyをChefを使ってインストールするサンプルコード

Dockerでno Space Left on Deviceが出てbuildできなくなった

Dockerのbuild時に以下のエラーが発生するようになった。

1
2
3
$  docker build -t docker-and-chef .
Sending build context to Docker daemon 131.6 kB
Error response from daemon: mkdir /mnt/sda1/var/lib/docker/tmp/docker-builder670782655: no space left on device

PCを再起動してみても直らず、どうしたものかとググっていたら以下の情報を見つけた。
http://stackoverflow.com/questions/30604846/docker-error-no-space-left-on-device

やることは以下

  • docker ps -aして表示されたコンテナを消す。
  • docker images して表示されたイメージを消す。

コンテナはdocker rm container_idで消すことができる。
イメージはdocker rim image_idで消すことができる。

VMのディスク容量がないときに発生するエラーのようだ。
不要なコンテナがたくさんあったので、それらのコンテナを消すとエラーはでなくなった。