Docker 㮠Remote API + serverspec 㧠CI
æ¨æ¥ http://d.hatena.ne.jp/naoya/20130620/1371729625 ã§æ¸ããããã« Docker ã使ãã°ã欲ãã VM ã "ä»»æã®ç¶æ " ã§ç°¡åã«ãã¤" "ç¬æã«" ã³ãã¼ãã¦ä½ãåºããã¨ãã§ããã
- ãä»»æã®ç¶æ ãã¨ããã®ã¯ãä¾ãã°ãOS 㯠CentOS ã§ãRuby 㨠Chef ãå ¥ã£ã¦ãããã¿ãã㪠VM ã®ãã¨
- ãç¬æã«ãã¨ããã®ã¯æ¬å½ã«ç¬æãVM ã®èµ·åæéãå¾ ã£ãããRuby ã Chef ãå ¥ããæéãå¾ ã¤å¿ è¦ã¯ãªã
serverspec ã§ãã¹ããããå ´åãçã£æ°ãª VM ãç¨æãã¦ããã«ãããã¸ã§ãã³ã°ãè¡ã£ã¦ããã®å¾ã«ç ´æ£ããã¿ãããªãã¨ãè¯ãããããã®ã¨ããçã£æ°ãªVMããç«ã¡ä¸ããã®ã«ãVagrant ãªã©ã使ããããVagrant ã ã¨ãã¹ãã®åº¦ã« VM ãä¸ããä½ãç´ã・・・ã¤ã¾ã vagrant up ããªããã°ãããªããããã§çµæ§ãªå¾ ã¡æé & ãªã½ã¼ã¹æ¶è²»ãããã
Docker ã使ãã¨ãDocker ã LXC 㨠AUFS ãçµã¿åããã¦ãããã¨ã«ããããã®å¾ ã¡æéãªãã§ä»»æã®ç¶æ ã® VM ããã²ãªå½¢ã®ã³ãã¼ã§ç°¡åã«æã«å ¥ãããã¨ãã§ãããã¨ããããã§ããã¾ãã
Docker + serverspec ã§ãã¹ããä¸æ°éé¢ã§
ã¨ãããã㧠sshd enabled 㪠VM ã Docker ã§ä½ã£ã¦ serverspec ã§ãã® VM ã®ä¸èº«ããã¹ããããã¨ãããã¨ãããããæ¨æ¥ã®ã¨ã³ããªã§ã¯ãã® sshd enabled 㪠VM ãä½ãã¾ã§ãã§ãããDockerfile ãä½ã£ã¦ãã£ã¦ããã«ãããã ãã
ã¨ããã§èªå㯠Docker ã Vagrant ã§ç«ã¡ä¸ãã VirtualBox ã® VM å ã§ä½¿ã£ã¦ãããserverspec 㯠Vagrant VM ã«ã¨ã£ã¦ã®ãã¹ãOS ã§ãã OSX å´ã§æ¸ãã¦å®è¡ããããã¤ã¾ã
ã¨ãªã£ã¦ãOSX ãããã¹ãã®å¯¾è±¡ã«ããã Docker VM ã¨ã®éã« Vagrant VM ãæã¾ããã¨ã«ãªã£ã¦ç´ ã®ç¶æ ã§ã¯ç´ãOSX å´ããç´æ¥ Docker VM ãä½ã£ããç ´æ£ããããããã㯠ssh ãéãããã¨ãã£ããã¨ãã§ããªãã
éã«ããããã§ããã° serverspec ã§ãã¹ãã®åæå㧠VM ããã³ã£ã¨ä½ã£ã¦ãã£ã¦ããã¹ããæµãã¦ãçµãã£ãã VM ãç ´æ£ããã¨ããä¸é£ã®æµããå ¨é¨èªååã§ããã
ssh ãéã
OSX ããç´æ¥ Docker VM ã¸ã® ssh ãéãã®ã¯ç°¡åã§ãDocker ã®æä¾ãã port forwarding ã®æ©è½ã使ãã°è¯ããããã使ãã¨ãDocker ããè¦ããã¹ãOSã®ãã¼ããã Docker ã®ä»»æã®ãã¼ãã¸ã® port forwarding ãã§ããããã®è¾ºã®è¨å®ã¯æ¨æ¥ã®ã¨ã³ããªã® Dockefile ã®ä¸ã«æ¢ã«å ¥ã£ã¦ããã
Docker ã® Remote API ã使ã
Docker ã«ã¯ "Remote API" ã¨ããåè¿°ã®ãããªã¦ã¼ã¹ã±ã¼ã¹ã«å©ç¨ã§ãã HTTP 㪠API ãç¨æããã¦ããã
ãã® API 㯠Docker ãåããã¦ãããã¹ãOSãã¤ã¾ãä»åã®ä¾ã§ã¯ Vagrant VM ä¸ã® OS ã§åãã¦ãã¦ãããã©ã«ãã§ã¯ 4243 ãã¼ãã«ãã¤ã³ããã¦ããããã®ãã¼ãã« HTTP ãªã¯ã¨ã¹ããé£ã°ãã¦ãã㨠API 㧠Docker ã³ã³ããã®æä½ãã§ããã
ããã使ãã°ãªãã¨ããªãããã ã
Remote API ãå¤ããå©ããããã«ãã
ãã ããã® Remote API ã¯ããã©ã«ãã§ã¯ã»ãã¥ãªãã£ã®çºããã¹ãOS ã®ã«ã¼ãããã¯ã¢ãã¬ã¹ã«ãããã¤ã³ããã¦ããªãã/etc/init/docker.conf ãæ¸ãæãã¦
script /usr/bin/docker -d -H=tcp://0.0.0.0:4243/ end script
ã¨ãèµ·åæã®ãªãã·ã§ã³ã§ãã¤ã³ãã¢ãã¬ã¹ãæå®ãã¦ãã£ã¦ sudo restart docker
ããã
次㫠OSX 㨠Vagrant VM ã®éä¿¡ãã©ãããããå®ã¯ãã¹ãOS ã® 4243 ãã²ã¹ãOS ã® 4243 ã« port forwarding ãããããªè¨å®ããVagrantfile ã«ã¯å ¥ã£ã¦ããã®ã ãã©ã©ãããããä¸æãåããªãã£ãã®ã§ãVagrant å´ã§ hostonly ãããã¯ã¼ã¯ãä½ã£ã¦éä¿¡ããããã«ããã
Vagrant::Config.run do |config| # Setup virtual machine box. This VM configuration code is always executed. config.vm.box = BOX_NAME config.vm.box_url = BOX_URI config.vm.forward_port 4243, 4243 config.vm.network :hostonly, '192.168.50.5' # ãã
ãã㧠OSX ãã http://192.168.50.5:4243/ ã«ãªã¯ã¨ã¹ããããã¨ã§ãOSX å´ãã Docker ã®æä½ãã§ããã
docker-client
API ã¯ç´æ¥å©ãã®ã¯é¢åãªã®ã§ãgithub ã§å ¬éããã¦ãã ruby ã®ã©ããã©ã¤ãã©ãªã使ãã
ããã使ãã¨
require 'docker' docker = Docker::API.new(base_url: 'http://192.168.50.5:4243') containers = docker.containers result = containers.create(nil, 'naoya/sshd') container_id = result['Id'] containers.start(container_id) p containers.show(container_id)
ãããªæã㧠Docker ã ruby ã¹ã¯ãªããã®ä¸ããããã°ã©ããã«ã«æä½ã§ããããã«ãªãã
serverspec ã§ãã¹ã
ããã§æºåã¯ã§ããã
serverspec ã rake spec æã«å®è¡ãã spec/spec_helper.rb ãæ¸ãæãã¦ããã¹ãã®å®è¡åå¾ã§ Docker 㧠VM ãä½ã£ããåé¤ãããããããã«å¤æ´ããã
OSX ããè¦ãå ´åãssh ã®è»¢éãã¼ãã¯æ¯åã©ã³ãã ã«å¤æ´ã«ãªãã®ã§ API ããã³ã³ããã®æ å ±ãåå¾ãã¦ããã®ãã¼ãçªå·ã¯åçã«åå¾ãããã¨ã«ããã
require 'serverspec' require 'pathname' require 'net/ssh' require 'docker' require 'awesome_print' include Serverspec::Helper::Ssh include Serverspec::Helper::DetectOS RSpec.configure do |c| if ENV['ASK_SUDO_PASSWORD'] require 'highline/import' c.sudo_password = ask("Enter sudo password: ") { |q| q.echo = false } else c.sudo_password = ENV['SUDO_PASSWORD'] end ## Initialize docker API docker = Docker::API.new(base_url: 'http://192.168.50.5:4243') containers = docker.containers container_id = nil c.before :all do ## Start VM and retrieve port number of sshd res = containers.create(nil, 'naoya/sshd') container_id = res['Id'] containers.start(container_id) sleep 1 container = containers.show(container_id) port = container["NetworkSettings"]["PortMapping"]["22"].to_i block = self.class.metadata[:example_group_block] if RUBY_VERSION.start_with?('1.8') file = block.to_s.match(/.*@(.*):[0-9]+>/)[1] else file = block.source_location.first end host = File.basename(Pathname.new(file).dirname) # if c.host != host c.ssh.close if c.ssh c.host = host options = Net::SSH::Config.for(c.host) user = options[:user] || Etc.getlogin options[:port] = port c.ssh = Net::SSH.start(c.host, user, options) # end end c.after(:all) do ## Stop and remove VM containers.stop(container_id) containers.remove(container_id) end end
rake spec ãã㨠Docker API çµç±ã§ sshd enabled 㪠VM ãç«ã¡ä¸ãã£ã¦ãserverspec ãããã« ssh ãã¦ãã¹ããå®è¡ãã¦çµæãè¿ãã¦ããããå¾ ã¡æéã¯ã»ã¨ãã©ãªããã¯ã³ããã«ã
ä»ã®ã¨ããè¥å¹²ããããã¦ãã¦ããã£ã¦ãdocker.start ããç´å¾ã«ãã¹ããéå§ãã㨠ssh port ãã¾ã æºåã§ãã¦ããªããã¨ããã£ã¦ãã¹ããè½ã¡ãã®ã§ sleep 1 ãå ¥ãã¦ãããã¡ããã¨ããã«ã¯ãTCP polling ãä½ãã§ãã§ãã¯ãããªã©ããã»ããè¯ãããããã¨ã¯ããã¼ãçªå·ãæ¯åå¤ããã®ã§ Net::SSH ã®ã¤ã³ã¹ã¿ã³ã¹ãæ¯åä½ãããã«ã¡ãã£ã¨å¤æ´ãã¦ããã¨ãã
å®éç¨ããããã¨ããã¨ããå°ããªãã¡ã¤ã³ãå¿ è¦ã ãã©ãä»åã®ç®çã¯ã¨ãããã OSX å´ãã Docker ãæä½ãã¦ãã¹ãã¨çµ±åãããã¨ããã¨ãããªã®ã§ã²ã¨ã¾ãããã¨ãããããã Jenkins ã§åãããªã©ãã¦ãCI ãããã¨æãã°ã§ãããã¨ã¯åãã£ãã
Docker ã¯ã¾ã ã¾ã API ãã®ä»ä»æ§å¤æ´ãæ¿ããã®ã§ãã·ã³ãã«ãª CI ã®å®æ¦æå ¥ã«ã¯å æ¥ç´¹ä»ãã Vagrant ã使ãæ¹æ³ http://d.hatena.ne.jp/naoya/20130520/1369054828 ã®æ¹ãå®å®ãã¦ãã¦è¯ãã¨ã¯æãããDocker ã®ç¹å¾´ãæ´»ããã¦ãä¾ãã° Travis CI ã®ããã« perl ã ruby ãå®è¡ã§ããç°å¢ãç¨æãã¦ããã®ä¸ã§åããã¢ããªã±ã¼ã·ã§ã³ã¯å¾ããåçã«æ³¨å ¥ããã¿ãããªããããããã¹ããã©ãããã©ã¼ã ãä½ãããã¨ãã«ãã® Retmote API ã§ã®é£æºãå½¹ã«ç«ã¤ã¨æãã