massの日記

日々の薪

年の瀬にJenkinsの訃報が届いても、悲嘆にくれないために #vgadvent2013

この記事はVOYAGE GROUP エンジニアブログ : Advent Calendar 2013 の11日目の記事になります。

adingoでDevOpsやっている@_zooです。
今年から、弊社が提供しているSSPサービスのFluctでは、AWSを利用した広告配信を開始しました。

AWSは手軽に構築できる分、いつインスタスの訃報が飛んできてもいいように準備をしておく必要があります。

今回は普段元気なJenkinsおじいちゃんが年の瀬にお亡くなりになった場合に、悲嘆にくれないためのお話です。

まずは、おじいちゃんの訃報に備えての対策

急な訃報で普段きないスーツやら、黒い靴やら、年末でぐでーと酒のんでいる時に探したくはないです。

  • Puppetによる構成管理
  • ServerSpecによるサーバの状態テスト
  • Jenkinsのジョブbackupをs3に定期的に同期

以下、JenkinsのPuppetとServerSpecのコードを抜粋します。

# Puppet

class jenkins::install {
  file {
    "/ebs1/jenkins":
      owner   => "jenkins",
      group   => "contentsuser",
      mode    => 755,
      ensure  => directory;

    "/ebs1/jenkins_backup":
      owner   => "jenkins",
      group   => "contentsuser",
      mode    => 755,
      ensure  => directory;
  }

  package {
    "jenkins":
      ensure  => installed,
      require => File["/var/lib/jenkins"];

    "java-1.6.0-openjdk":
      ensure => installed;

    "rubygem-bundler":
      ensure => installed;
  }
}

class jenkins::prepare( $jenkins_https_port = 8443,
                        $jenkins_cert_file,
                        $jenkins_key_file,
                        $jenkins_java_options ) {

  file {
      "/etc/pki/tls/certs/jenkins.ec2.crt":
        owner   => "jenkins",
        group   => "contentsuser",
        mode    => 440,
        source  => "puppet:///jenkins/etc/pki/tls/certs/dev.fluct.ec2.crt";

      "/etc/pki/tls/certs/jenkins.ec2.key":
        owner   => "jenkins",
        group   => "contentsuser",
        mode    => 400,
        source  => "puppet:///jenkins/etc/pki/tls/certs/dev.fluct.ec2.key";
    }
  }

  file {
    "/etc/sysconfig/jenkins":
      owner   => "root",
      group   => "root",
      mode    => 644,
      content => template("jenkins/etc/sysconfig/jenkins.erb");
  }
}

class jenkins( $jenkins_https_port   = 8443,
               $jenkins_cert_file    = "/etc/pki/tls/certs/jenkins.ec2.crt",
               $jenkins_key_file     = "/etc/pki/tls/certs/jenkins.ec2.key",
               $jenkins_java_options = "-Djava.awt.headless=true" ) {

  Class["jenkins::install"]
  -> Class["jenkins::prepare"]
  -> Class["jenkins"]

  include "jenkins::install"
  class {
    "jenkins::prepare":
      jenkins_https_port   => $jenkins_https_port,
      jenkins_cert_file    => $jenkins_cert_file,
      jenkins_key_file     => $jenkins_key_file,
      jenkins_java_options => $jenkins_java_options;
  }

  service {
    "jenkins":
      ensure  => running,
      enable  => true;
  }
}

# ServerSpec

require 'spec_helper'

describe package('jenkins') do
  it { should be_installed }
end

describe package('java-1.6.0-openjdk') do
  it { should be_installed }
end

describe package('rubygem-bundler') do
  it { should be_installed }
end

describe package('dejavu-sans-fonts') do
  it { should be_installed }
end

describe service('jenkins') do
  it { should be_enabled   }
  it { should be_running   }
end

describe port(8443) do
  it { should be_listening }
end

describe file('/etc/sysconfig/jenkins') do
  it { should be_file }
  it { should be_mode 644 }
  it { should be_owned_by 'root' }
  it { should be_grouped_into 'root' }
end

おじいちゃんは自分の健康状態を維持するため、このServerSpecを30分おきに実行しています。

さて、そんな日々の健康管理があっても急な病にかかることもあります。

そんな時に備えて、おじいちゃんは自分の設定ファイルをS3に置いておきます。
これでいつ倒れても、次のおじいちゃんが引き継げます。

JenkinsのバックアップはPluginで提供されているthinBackupで作成しています。
f:id:johnsmith0707:20131210224758p:plain

このバックアップそのものもJenkinsのジョブで取っています。
とはいっても、ワンライナーです。ぶっちゃけ、s3cmdのsync一行です。

s3cmd -c s3cfg sync /ebs1/jenkins_backup s3://jenkins-backup/

次に、おじいちゃんを殺してみます

やはりAWSとはいえ殺すというのは怖いですね、手が震えます。
インスタンスはCloudFormationで作成しているので、Stackを消せば終了です。

いざっ!

aws cloudformation delete-stack --stack-name JENKINS

やってしまいました。
ついカッとなって、やってしまった。怖いですね、これが人間というものです。

最後に、次のおじいちゃんを作ります

先ほど同様、CloudFormationを利用します。

aws cloudformation create-stack --stack-name JENKINS --template-body file://template_jenkins.json

次にできあがったインスタンスsshでログインしてPuppetをあてます。

sudo /etc/init.d/puppet start

次にデータをリストアします。

s3cmd -c s3cfg sync s3://jenkins-backup/ /ebs1/jenkins_backup

後はthinBackupのリストア画面から、リストアするだけです。
f:id:johnsmith0707:20131210224802p:plain

リストアしたら、元気なおじーちゃんが生まれました。良かったです。

かなりはしょりましたが、こんな感じで訃報がとんできても悲嘆にくれないようにしています。
ひよっこDevOpsエンジニアで、まだまだPuppetやServerSpecを使いこなせてないです。
そんなひよっこDevOpsエンジニアがいる弊社は絶賛DevOps系エンジニアを募集中です!

明日のアドベントカレンダー@tadasyさんです。お楽しみに!