年の瀬に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で作成しています。
このバックアップそのものも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のリストア画面から、リストアするだけです。
リストアしたら、元気なおじーちゃんが生まれました。良かったです。
かなりはしょりましたが、こんな感じで訃報がとんできても悲嘆にくれないようにしています。
ひよっこDevOpsエンジニアで、まだまだPuppetやServerSpecを使いこなせてないです。
そんなひよっこDevOpsエンジニアがいる弊社は絶賛DevOps系エンジニアを募集中です!
明日のアドベントカレンダーは@tadasyさんです。お楽しみに!