serverspecで複数のdocker containerに対してテストしたい
前回の記事でdocker containerに対してserverspecでテストができるようになりました。
dockerを扱う以上、containerは複数立てるのが普通です。
今回は複数のcontainerを立てた時にそれぞれのcontainerに対してテストする方法について書いていきます。
やりたいこと
docker-composeで管理している複数のdocker containerに対してテストしたい
docker-composeで複数のcontainerを管理する
前回のrubyを動かすcontainerに加えて今回はnginxのcontainerを動かしていきます。
まずは、ruby用のDockerfileと実行するrubyスクリプトを配置します。
# Dockerfile FROM ruby:2.3.1-alpine ADD app.rb .
# app.rb puts 'Hello, world!'
そして、以下のようなdocker-compose.yml
を配置します。
# docker-compose.yml app: build: . command: [ruby, app.rb]
この時点で$ docker-compose up
すると、Hello, world
と表示されるはずです。
次に、上記のrubyを実行するcontainerとは全く関係ありませんが、nginx containerを別で追加します。
nginxというディレクトリを切り、nginx用のDockerfileと表示するための適当なindex.html
を作ります。
# nginx/Dockerfile FROM nginx:stable-alpine COPY index.html /usr/share/nginx/html
<!-- nginx/index.html --> <strong>Hello, world!</strong>
そうしたら、docker-compose.yml
にnginx serviceの記述も追加しましょう。
私の環境では80をすでに使っていたため、nginxのportは8080にforwardしておきます。
app: build: . command: [ruby, app.rb] web: build: nginx/ ports: - "8080:80"
appとwebのcontainerを立ち上げます。
$ docker-compose up --build Building web Step 1 : FROM nginx:stable-alpine ---> c6b7a3ab1800 Step 2 : COPY index.html /usr/share/nginx/html ---> Using cache ---> 4a0b194d5d82 Successfully built 4a0b194d5d82 Building app Step 1 : FROM ruby:2.3.1-alpine ---> c872d09a2f2e Step 2 : ADD app.rb . ---> Using cache ---> 8eb82eb96cf9 Successfully built 8eb82eb96cf9 Starting dockerforblogpost20160625_web_1 Starting dockerforblogpost20160625_app_1 Attaching to dockerforblogpost20160625_app_1, dockerforblogpost20160625_web_1 app_1 | Hello, world! dockerforblogpost20160625_app_1 exited with code 0
これで、app containerが立ち上がり、rubyのスクリプトを実行し、nginx containerも同時に立ち上がりました。
http://localhost:8080
にアクセスしてnginxが立ち上がっているか確認しておきます。
複数のdocker containerに対してテストする
それでは、本題の複数のdocker containerに対してserverspecでテストを実行できる環境を作りましょう。
まずはGemfileを追加します。 今回は複数のdocker containerに対してserverspecを実行するためにrakeも使います。
# Gemfile # frozen_string_literal: true source "https://rubygems.org" gem 'serverspec' gem 'docker-api' gem 'rake'
specディレクトリは以下のように作成します。
spec/roles
以下に各container毎のテストを書いていきます。
$ tree spec/ spec/ ├── roles │ ├── app_spec.rb │ └── web_spec.rb └── spec_helper.rb 1 directory, 3 files
# spec/roles/app_spec.rb require 'spec_helper' describe 'app' do describe command 'ruby -v' do let(:disable_sudo) { true } its(:stdout) { should match /ruby 2.3.1/ } end end
# spec/roles/web_spec.rb require 'spec_helper' describe 'web' do describe file('/usr/share/nginx/html/index.html') do it { should exist } end end
また、spec_helper.rb
は以下のように書きます。
docker_imageに指定するimageは環境変数を指定するようにします。 これで、rakeタスクから動的にserverspecを実行するdocker containerを切り替えることができます。
# spec/spec_helper.rb require 'serverspec' require 'docker' set :backend, :docker set :docker_image, ENV['DOCKER_IMAGE_NAME']
さて、最後にRakefileを作成します。 hostsの中にdocker containerを定義することで、それぞれのcontainerに対してserverspecを実行できます。
nameにはdocker-composeで作成されたimage名、short_nameはrake taskで使う名前、roleはspec/roles
以下に配置するファイル名を指定します。
serverspec実行時のENVにそれぞれのimage名を渡してあげます。
# Rakefile require 'rake' require 'rspec/core/rake_task' hosts = [ { name: 'dockersandbox_app', short_name: 'app', roles: 'app', }, { name: 'dockersandbox_web', short_name: 'web', roles: 'web', } ] class ServerspecTask < RSpec::Core::RakeTask attr_accessor :target def spec_command cmd = super "env DOCKER_IMAGE_NAME=#{target} #{cmd}" end end task default: :spec desc 'Run serverspec to all hosts' task spec: hosts.map { |h| "spec:#{h[:short_name]}" } namespace :spec do hosts.each do |host| desc "Run serverspec to #{host[:name]}" ServerspecTask.new(host[:short_name].to_sym) do |t| t.target = host[:name] t.pattern = "spec/roles/#{host[:roles]}_spec.rb" end end end
これで、spec/roles
以下に置かれたファイルごとにserverspecが実行されます。
$ bundle exec rake spec app Command "ruby -v" stdout should match /ruby 2.3.1/ Finished in 3.29 seconds (files took 0.83075 seconds to load) 1 example, 0 failures web File "/usr/share/nginx/html/index.html" should exist Finished in 3.18 seconds (files took 0.64689 seconds to load) 1 example, 0 failures