VMWare EsxiとJenkinsとGradleでインフラのコード化&CI
要件は
- 作業のログは永遠に残す必要がある
- いつ、誰が、どういった理由でインフラを変更したかわかるようにする
ひとつ、落とすと
- インフラをコードで書けるようにする
- 開発、本番共にVMWareで構成された基盤なのでVMWareの仮想マシンが作れるコードを書く
- インフラコードをバージョン管理し、変更毎に構築できるかテストする
- コードで構築されたインフラでアプリケーションの全てのテストが通るか確認する(インフラの要件は設定ファイルがあるかどうかではなく、アプリケーションが動作するかどうか)
- テストは既に動作しているCIがあるので、それを使い回す
- ログの保持もJenkinsにしてもらおう
やること
- Jenkinsから仮想マシン作成、OSのインストール
- Jenkinsのノードに作成された仮想マシンを追加
- 追加されたノードでOSインストール後の設定やミドルウェアのインストール
- 環境の整ったノードに対してアプリのデプロイとテスト
インフラ定義Gradleファイル
applyEx { plugins 'java_ext', 'sh', 'tomcat_ext', 'vm', 'mkdir', 'proxy_auth' files 'common/yum_update.gradle', 'common/set_ntp.gradle', 'common/install_httpd.gradle', 'common/install_ssh.gradle', 'common/set_secretkey.gradle' } vCenter { url = 'http://xxx.xxx.xxx.xxx/sdk' user = 'root' passwd 'JM*rtTS**MfJgDt**CXXZ*4gNiyB***jssVS' } vm { description = 'テスト用アプリケーションサーバ' name = 'testap' registry { center = 'vCenter' datastore = 'test' host = 'test_cluster' } cpu { core = 4 socket = 1 } memory { sizeGB = 8 } hdd { sizeGB = 128 type = 'thin' } iso { file = 'iso/CentOS-6.4-x86_64-netinstall.iso' datastore = 'test' } network { name = 'VM Network' ip = '192.168.**.**' openPorts = ['http', '5900:tcp', '8080:tcp', '8081:tcp'] gateway = '192.168.**.**' } passwd 'JM*rtTS**MfJgDt**CXXZ*4gNiyB***jssVS' } dir { root { var { log { testApp(perm:755) } } } } java { version = '7u21' } tomcat { version = '7.0.40' option = ['-Dfile.encoding=UTF-8', '-Dcatalina.logbase=/var/log/tomcat', '-Dnet.sf.ehcache.skipUpdateCheck=true', '-XX:-UseSplitVerifier', '-XX:+DoEscapeAnalysis', '-XX:+CMSClassUnloadingEnabled', '-XX:+UseParNewGC', '-XX:+UseConcMarkSweepGC', '-XX:PermSize=128m -XX:MaxPermSize=256m', '-Xms256m -Xmx512m', '-server'] } システムの設定 << { os.insert('/etc/sysctl.conf'.asType(File), 'vm.swappiness = 30') os.execute('sysctl -p') } //固有設定を追加 Httpdのインストール << { '/etc/httpd/conf/httpd.conf'.asType(File).with { write text.replaceAll('#ServerName www.example.com:80',"ServerName ${vm.name}:80") write text.replaceAll('Options Indexes FollowSymLinks','Options FollowSymLinks') println path println text } '/etc/httpd/conf.modules.d/01-mpm.conf'.asType(File).with { write '''# event MPM |# StartServers: initial number of server processes to start |# MinSpareThreads: minimum number of worker threads which are kept spare |# MaxSpareThreads: maximum number of worker threads which are kept spare |# ThreadsPerChild: constant number of worker threads in each server process |# MaxRequestWorkers: maximum number of worker threads |# MaxConnectionsPerChild: maximum number of connections a server process serves |# before terminating |<IfModule mpm_event_module> | StartServers 2 | MinSpareThreads 25 | MaxSpareThreads 75 | ThreadsPerChild 25 | MaxRequestWorkers 150 | MaxConnectionsPerChild 0 |</IfModule>'''.stripMargin() println path println text } } task installModJk << { os.installRPM('http://repo/repos/CentOS/6/x86_64/', 'mod_jk-1.2.37-1.x86_64.rpm') new File('/etc/httpd/conf.modules.d/00-mod_jk.conf').with { new File('/etc/httpd/conf.modules.d/workers.properties').with { write '''worker.list=ajp13 |worker.ajp13.port=8009 |worker.ajp13.host=localhost |worker.ajp13.type=ajp13'''.stripMargin() } def conf = '/etc/httpd/conf.modules.d/00-proxy.conf'.asType(File) conf.write(conf.text.replaceAll('^LoadModule proxy_ajp_module','#LoadModule proxy_ajp_module')) } 秘密鍵の設定 { host = 'serverA' user = 'root' password = '1to*oCY*et06axq*9TahD***QvRxu**/n8e' } defaultTasks ( 'システムの更新', 'VMWareToolsのインストール', 'VMWareToolsの更新', 'mkdir', 'Javaの設定', 'Ntpの設定', 'Httpdのインストール', 'Tomcatのインストール', 'modJkのインストール', 'システムの設定', '秘密鍵の設定', '再起動' )
このコードを実行すると仮想マシンが作成されるので、
その後、Jenkins上のスクリプトでノードに追加し、ミドルウェアの設定を実行するジョブを後続として流す。
ミドルの変更前にスナップショットが取られるので、テストがうまくいったら削除する(ここはまだ自動化してない)。
見えてない部分のコードでは泥臭くyum installとかwgetとかやっていて、VMの作成はvijavaを使用している。
ミドルウェアの設定ジョブが終わったら、テストジョブを後続として流して、インフラのCI環境の完成。
次にやりたいのは設定や、ミドルウェアをマトリクスで一斉にパフォーマンステストして・・・みたいなことをやりたい。