Raccoon Tech Blog [株式会社ラクーン 技術戦略部ブログ]

株式会社ラクーン 技術戦略部より、tipsやノウハウなど技術的な話題を発信いたします。

ラクーンのCI/CDへの取組みの現状とこれから(1)

こんにちは。技術戦略部で今度から部門長をやることになったたむらです。
 
「お前も技術部なんだからブログの一本や二本は書け!」との鬼編集長からのプレッシャー(?)があり、頑張ってブログを書いてみます。よろしくお願いします!

今回は「ラクーンのCI/CDへの取組みの現状とこれから」と題して2回に分けて書いてみたいと思います。
アジャイル開発の界隈で良く取り上げられ、昨今メジャーな話題となっているCI(継続的インテグレーション)CD(継続的デリバリ)という用語ですが、これらで謳われている方法論はラクーンでも採り入れるべき多くのメリットを持っています。
ただ、ラクーンのメインビジネスとなっている「スーパーデリバリー」は10年以上続いている大きなシステムであり、既存のシステムにCI/CDのポリシーを適用していくのは大きなコストと時間が掛かります。そんな意味で、今回のテーマである取組みの実際の内容の他に、ラクーンがどの様にシステムに対して改善のアプローチを図っているかという一例が紹介できればいいなと考えています。

ということで、第1回は Capistrano によるデプロイの効率向上のお話です。


デプロイって面倒くさい ~「Capistrano」登場~

まず、弊社のサービスである「スーパーデリバリー」や「Paid」は以下の様なシステム構成となっています。
 
WS000005


1系サーバグループと2系サーバグループはそれぞれ複数台のサーバから構成されていて、すべてのサーバは同じ構成になっています。そして、1系と2系のグループが正副の関係となっていて、リリース毎に稼動系サーバが切り替わるという様な運用を行なっています。
さて、この様な構成のサーバ群に対してリリースする際、1年半程前迄はリリース手順書を用意してそれに沿って手動でデプロイを行なっていました。リリースの手順は以下の様なものです。

(リリースの手順の概要) 
1. リリース物の準備/バックアップ
2. ロードバランサーの振分け状況チェック(ここで1系/2系どちらが稼動系かを確認する)
3. 稼動系サーバ群でのファイル同期チェックジョブの停止
4. ファイル共有サーバへのリリース物のアップロード
5. 待機系Webサーバ群でのリリースファイルの同期
6. 待機系Webサーバ群でのプロセスの再起動
7. 待機系Webサーバそれぞれのログ確認とプロセス稼働確認
8. ロードバランサーの切替(待機系を稼働系に)
9. 旧稼動系サーバ群でのファイル同期チェックジョブの再開
 
当然、これらのオペレーションのすべてをマニュアルで行っているとミスが発生することもあり、本番サービスがダウンすることも過去に何度か発生していました。


またデプロイには以下の様な問題が絡んで、オペレーションは属人化する傾向にありました。
(デプロイに関する問題)
a. 操作対象サーバが多く作業負荷が高い
b. プロセスの再起動等のオペレーションにより、リリースユーザ権限がほぼ管理者権限になってしまう
c. ロードバランサーの操作が別物になっており、作業負荷・リスクが高い
d. リリース手順自体が複雑

そこで採用したのがCapistranoです。Capistrano はオープンソースのソフトウェアデプロイメントツールで、デプロイツールの中では非常にメジャーなものです。複数サーバへの作業の効率化・自動化が簡単に行えます。デフォルトで一通りのデプロイタスクのひな形が用意されているのですが、ラクーンでは上記のリリース手順に沿ったものにする必要があったため独自のタスクを用意して実装することにしました。


では上記で挙げたデプロイに関する問題に対してそれぞれどんなアプローチをしたのかを説明していきましょう。
 
まず、「a. 操作対象サーバが多く作業負荷が高い」についてです。
これはCapistrano の基本的な機能を使えばそれだけで解決できます。

独自タスクはrakeタスクを書く要領で簡単に実装できます。例えばこんな感じです。
(rubyやrakeタスクについての説明はここでは省略します) 
■tomcatプロセスの再起動の例(上記「手順6」の一部)■
~ deploy.rb の抜粋 ~
set :application, "deploy"
set :user, "deployuser"

if togroup == "group1"
 # 1系統のサーバーグループを定義
  role :web, "XXX.XXX.XXX.XX1"
  role :web, "XXX.XXX.XXX.XX2"
  role :web, "XXX.XXX.XXX.XX3"
elsif togroup == "group2"
 # 2系統のサーバーグループを定義
  role :web, "YYY.YYY.YYY.YY1"
  role :web, "YYY.YYY.YYY.YY2"
  role :web, "YYY.YYY.YYY.YY3"
end

desc "cap -f deploy.rb tomcat_action -S togroup=[group1|group2] -s repos=[serviceA|serviceB]"
task :tomcat_action, :roles => [:web] do
  # パラメタで指定されたサービスの停止
  run "sudo \/etc\/init.d\/#{repos} stop"
  run "sleep 10"
  # プロセス停止を確認後・・・
  run "test `ps -ef | grep \"#{repos}\" | grep -v \"grep\" | wc -l` -eq 0"
  # 起動
  run "sudo \/etc\/init.d\/#{repos} start"
  run "sleep 15"
  # 起動ログを出力し確認
  run "tail -n 10 \/var\/log\/#{repos}.log"
  # プロセス状況を出力し確認
  run "ps -ef | grep \"#{repos}\" | grep -v \"grep\""
end

Capistrano では、リモートサーバにsshで接続しコマンドを実行します。その為、事前に Capistrano を実行するマシンとリモート実行する対象のサーバではsshで接続できる設定をしておく必要があります。

上記で定義したtomcatプロセス再起動タスク(tomcat_action)を実行する際は以下の様にコマンドラインから実行します。
$ cap -f deploy.rb tomcat_action -S togroup=group1 -s repos=serviceA
パラメタは"-S"または"-s"の後にname=valueの形で指定します。オプションの"-S"と"-s"の違いは、前者は初期化時から使用したい場合、後者はタスク内でのみ使用する場合に利用します。その為、サーバーグループの選択を行う"togroup"は"-S"、タスク内のみの"repos"は"-s"と使い分けています。
 
この様にCapistrano ではパラメタにより複数サーバグループを切替えつつ、同一の操作を実行することが簡単に実装できます。


次に、「b. プロセスの再起動等のオペレーションにより、リリースユーザ権限がほぼ管理者権限になってしまう」についてです。
これは、Capistrano 経由でデプロイのコマンドを発行するユーザを新規に作成し、そのユーザに対してsudoers のコマンドエイリアスを定義することで解消させました。

■/etc/sudoersの記載例■
Cmnd_Alias PROCCMD=/etc/init.d/serviceA,/etc/init.d/serviceB
deployuser ALL=NOPASSWD:PROCCMD
この様にすることで、管理者権限が必要な特定のコマンドのみをリリース用アカウントにノーパスワードにて実行させることができます。
直接的には Capistrano とは関わりませんが、Capistrano 実行環境の構築に合わせて環境周りも整備した結果選択できた対処となります。


続いて「c. ロードバランサーの操作が別物になっており、作業負荷・リスクが高い」についてです。
これは、利用しているロードバランサーのプロダクト「BigIP」がI/Fとして提供している bigpipe shell をCapistranoから実行することにより作業を一本化&タスク化することができました。
BigIPはGUIとCUIそれぞれI/Fを持っているのですが、CUIである bigpipe shell はその名の通りLinuxのシェルと変わらない作りの為、問題なく Capistrano から実行することができます。

■ロードバランサーの切替タスクの例(上記「手順8」の一部)■
set :application, "deploy"
set :user, "deployuser"

role :lb, "ZZZ.ZZZ.ZZZ.ZZZ"

desc "cap -f deploy_lb.rb exchange_balancing -S togroup=[group1|group2]"
task :exchange_balancing, :roles => [:lb] do
  grp = togroup == "group1" ? 1 : 2
  # 指定したプール(1系/2系に分けたサーバグループ)に本番アクセスを切替
  run "bigpipe profile httpclass httpclass_serviceA pool pool_serviceA_#{grp}"
  # 切替えられたプールを表示
  run "bigpipe profile httpclass_serviceA list | grep pool"
  # ロードバランサの待機系に設定変更を反映
  run "bigpipe config sync all"
end

尚、BigIPはv10.0.0からCUIとして bigpipe shell の他に tmsh というCisco風なシェルがサポートされています。当初ラクーンではBigIPのデフォルトシェルを tmsh にしていたのですが、Capistrano はデフォルトだと tmsh 形式のコマンド実行ができません。そこでBigIP側のデフォルトシェルを bigpipe shell に切り替えて対応することにしました。これにより、「c.」の問題も解消させることができました。


最後に、「d. リリース手順自体が複雑」についてです。
そもそも、何故リリース手順が複雑になるかというと、スーパーデリバリーではコンテンツの更新などで開発案件以外でもサイト更新が頻繁に行われている為、その運用を壊さずにリリースする必要がある事が1つの大きな理由となっています。
手順自体の簡略化はプログラム化することで概ね解消します。しかし、別のマニュアルリリース作業が一部残存してしまうことから、上で挙げたリリース手順「7」の最終的なサイト確認などは現時点では自動化するより目視により行う方が適切だという判断に至りました。
そこで、最終的にはCapistrano のタスクをシェルでラップしてCUIの対話形式ツールとし、適宜確認を行えるところ迄を一つの到達点としました。

■シェルでラップしたデプロイツールのイメージ■
WS000006


以上の様にラクーンの持っていたデプロイの問題に対して、Capistrano という強力なツールを軸にデプロイの改善を進めたのでした。
色々と不完全な部分もあり完全自動化迄は至っていませんが、これによりオペレーションミスの抑制や作業の省力化はかなり進めることができました。

今回はここ迄になります。
次回は Selenium を用いた自動テストと Capistrano や Selenium 等のツールを統合してくれる Jenkins の話題に続きます。

rake+sequelで組み立てる実践的データベースタスク

開発を担当している松尾です。
花粉飛び回るこの時期に集中力を掻き乱される度合いが年々ひどくなっている気がしてしょうがない昨今ですが、頑張って書いてみます。

イレギュラーなデータベースタスク

弊社では企業間向けサービスを提供しているという性質上、多岐にわたるバックオフィス業務からの要請としてイレギュラーな業務パターンが日々発生します。
全てのイレギュラーパターンに合わせて律儀にシステムを改修していくというのは費用も時間も掛かり過ぎるため、必然的に「過渡的」だったり「小規模」なものについては最小のコストで解決する手法が必要になります。
とはいえ、「人力でメールの大量送信」や「人力でSQLを使ったDB操作」は考えるまでもなく危険極まりないものです。
ここでは私の担当範囲で起こりがちな「システム化するには時間がかかるからすぐには無理」とはいえ「すぐに実施したい」ビジネス要件について、最小のコストと適度な安全性を担保しつつ「ちょっとだけ作って解決する」ことを目指した実践例の解説をしてみます。

rake

rakeとはrubyのビルドツールとして構築されたツールおよびライブラリのことです。

もともとはmakeに代わる高機能なビルドツールとして設計されたという経緯があり、シンプルに依存関係のあるタスクを記述できる使い勝手の良い枠組みが提供されています。

ruby-1.9.1より標準添付されるようになったため、比較的最近のrubyがインストールされている環境であればrakeコマンドが実行できます。

$ rake --version

rake, version 10.0.3

rakeは実行されるとカレントディレクトリ内のRakefileという名称のファイルを読み込みます。
意図的に別のファイル名を指定することも可能ではあるのですが、そんな酔狂な設定を喜ぶ人はいないのでやめておきましょう。

rakeで定義するタスク群を全てRakefile内に記述した場合はrakeタスク定義はひとつのファイルに完結します。
$ cat > Rakefile
task :hello do
puts "Hello"
end
$ rake hello
Hello
上記は"hello"という名前のタスクを定義して, rakeにタスクを指定して実行させるという最小の実行例になります。

Sequel

SequelはJeremy Evans氏によって開発されているrubyのためのデータベースツールキットです。
簡潔かつ多機能なDSLを備えており多くの種類のデータベースに対応しています。
また、SQLを抽象化するためのデータアクセス層とORM層が明解にモジュールで分離されているところが特徴的です。
$ gem install sequel
上記のようにgemを使ってインストールします。
sequel自身はデータベースのドライバを含まないため、rubyからデータベースへ接続するための各ドライバ(MySQLであればmysql2、Postgresqlであればpg、Oracleであればruby-oci8など)は別途インストールされている必要があります。

今回は私が現実に相手をする機会が多いからということと、MySQLやPostgresqlといったオープンソースのデータベースとはひと味ちがう商用データベースで使いこなすという目的から操作対象がOracleデータベースであるという前提になっています。

sequelの機能は多岐に渡るため、あえてここでその機能についての詳細は割愛します。
Cheat Sheetというドキュメントを眺めて貰えればひと通りの感触は掴んでもらえるのではないかと思います。

ファイル構成

データベースのタスクを定義するためのファイルは下記のような構成にしています。
また、参考例は架空のサービス「piyo」を運用するためのタスク定義であると仮定の上で作成しています。
  • config.yml
  • Rakefile
  • logs/
    • xxxxxx.log
    • ...
  • tasks/
    • piyo/
      • task1.rake
      • task2.rake
      • ...

config.yml

YAMLで記述された設定ファイルです。
log:
dir: /path/to/logs
databases:
piyo_db:
user: piyo
password: xxxxxxxx
database: //xxx.xxx.xxx.xxx:xxxx/piyo.oracle.local
例としてログの出力ディレクトリとデータベースへの接続情報をYAML形式で記述しています。
運用とともに複数データベースへの接続や他の設定値が必要になった場合は適宜この設定ファイルに追記していきます。

Rakefile

rakeコマンドが実行されると読み込まれるファイルです。
仕組みとして全てのタスクをこのRakefile内に記述することもできるのですが、内容が増大するにつれて間違いなくメンテナンスに苦労するハメになるのでタスク定義は別ファイルに分割してRakefileそのものはシンプルにしておきます。
# -*- coding: utf-8 -*-
# requires
%w(fileutils logger yaml time date csv sequel).each {|lib| require lib }
# tasks
Dir['tasks/**/*.rake'].each {|path| load path }
3行目ではタスクで頻繁に利用するであろうライブラリをまとめて読み込んでいます。
少々乱暴な気もしないでは無いですが、いちいち指定するのも煩わしいのでここで読み込みます。
5行目でtasksディレクトリ以下に配置されたタスク定義を読み込んでいます。
タスク定義のためのrubyスクリプトは、他のファイルとの区別がつくように*.rakeのような形式が良いでしょう。

logs

名前の通りログファイルの出力用ディレクトリで中身は空になっています。
rakeタスクで実行した全てのデータベース操作の内容がログとして出力されるように構成します。

tasks

このディレクトリ以下にタスク定義を配置していきます。
後々のタスクの分類や整理に困らないように、もう1階層グループ名のようなディレクトリを配置してrakeのnamespace機能と整合させるために、ここではtasks/piyo/*.rakeのように配置することにします。

基本タスク

tasks/piyo/configuration.rake

namespace :piyo do
  task :configuration do
    # YAML設定ファイルの読み込み
    CONTEXT = YAML.load_file('config.yml')
  end
end
まずは、設定ファイルを読み込むタスクを定義します。
YAML形式で記述されたファイルを読み込むだけの単純極まりない内容です。
他のタスクから簡便に参照できるようにCONTEXTという名前の定数に放り込んでいます。

またtaskの定義自体をnamespaceで囲っていますが、rakeではnamespace機能を利用してネストしたタスクを定義することができます。
ネストしたタスクは階層化された名前を「:」で区切った文字列がタスク名となります。
上記の例でいえば「piyo:configuration」がタスク名となります。

tasks/piyo/logging.rake

namespace :piyo do
task :logging => :configuration do
raked_at = Time.now.strftime('%Y-%m-%d_%H%M%S')
log_dir = CONTEXT['log']['dir']

# ログ出力ディレクトリが存在しなければ作成しておく
FileUtils.mkdir_p(log_dir) unless FileTest.directory?(log_dir)

# CONTEXTへlogger生成メソッドを追加する
CONTEXT.instance_eval do
self.class.send :define_method, :logger do |name, level=Logger::INFO|
logger = Logger.new(File.join(log_dir,
[raked_at, name, 'log'].join('.')))
logger.level = level
logger
end
end
end end
次はloggingのためのタスク定義です。
task :logging => :configuration do
rubyの文法としてはHashリテラルに該当する上記の書き方でタスクの依存関係を定義します。
上記の場合は「configuration」タスクに依存した「logging」タスクの定義、という意味になります。
ちなみに依存するタスクが複数存在する場合は下記のように複数記述することもできます。
task :new_task => [:dependent1, :dependent2, dependent3] do
タスク内で実行されたデータベース操作を記録したログを集約しやすくするために、「configuration」タスクで定義したCONTEXTオブジェクト(単なるHashのインスタンスですが)にlogger生成用の特異メソッドを定義しています。
rubyの特異メソッド定義は下記のように、
s = "string"
class << s
def hoge
"hoge"
end
end
puts s.hoge
# => "hoge"
classキーワードを利用して簡潔に書く方が簡潔なのですが、タスク内のローカル変数であるraked_atとlog_dirを特異メソッド内にバインディングしたかったという事情から、少々黒魔術っぽくなっています。

tasks/piyo/connect_piyo.rake

namespace :piyo do
task :connect_piyo => :logging do
PIYO_DB = Sequel.oracle(CONTEXT['databases']['piyo_db'])
PIYO_DB.loggers << CONTEXT.logger('piyo')

class << PIYO_DB
def literal(s)
Sequel::LiteralString.new(s.to_s)
end
end
end
end
さて、本丸に近いデータベースへの接続タスクです。
ここでは設定ファイルと同様に定数PIYO_DBに、設定ファイル内の接続情報から作成したSequel::Oracle::Databaseオブジェクトを保存しています。
また、sequelのDatabaseオブジェクトは複数のLoggerを保持できるようになっているのですが、ここに「logging」タスクで定義したCONTEXT#loggerメソッド経由で作成したLoggerを放り込んでおきます。
これでsequelによって発行されるSQLなどの情報は全てログに出力されるようになります。

さらに、このタスクではPIYO_DBにliteralという特異メソッドを定義しています。
与えられたStringオブジェクトをSequel::LiteralStringにラップしているだけの単純な内容ですが、これはデータベース特有のSQLリテラルを簡便に使用したいという欲求から定義しています。

仮に接続先データベースがMySQLであれば、
PIYO_DB[:users].select(:name, Sequel.function(:now))
#=> SELECT name, now() FROM users
上記のようにSequel.functionを利用してMySQLの関数呼び出しを自然に組み込むことができるのですが、リテラルやFunctionの呼び出し記法に独特なところを持つOracleデータベースの場合は上手く動作しないことがあります。
(引数ゼロの関数やプロシージャ呼び出しに空カッコが書けない、などなど)

Sequel::LiteralStringを使用することで、
PIYO_DB[:users].select(:name, PIYO_DB.literal(:sysdate))
#=> SELECT name, sysdate FROM users
上記のようにデータベース特有のリテラル表現を含んだSQLの生成に役立ちます。
特に大きな使い所としては、INSERT文を実行する場合にOracleのSequenceを利用して連番のプライマリキーを発行する下記のようなパターンでしょうか。
PIYO_DB[:users].insert(:id => PIYO_DB.literal('users_seq.nextval'), :name => 'Matsuo')
#=> INSERT INTO users (id, name) VALUES (users_seq.nextval, 'Matsuo')

tasks/piyo/available_users.rake

さて、データベースへ接続するタスク定義まで準備が整ったので、あとはsequelの機能を駆使して様々なタスクを定義していくだけです。
下記のコードはPIYO_DBよりavailable=1であるレコーをSELECTして各レコードをカンマ区切りで出力するだけの簡単なサンプルです。

namespace :piyo do
desc 'ログイン可能であるユーザの一覧を出力する'
task :available_users => :connect_piyo do
# SELECT * FROM users WHERE available = 1
PIYO_DB[:users].where(:available => 1).each do |row|
puts row.values_at(:id, :name, :email).join(',')
end
end
end
実行すると下記のような出力が得られるイメージです。
$ rake piyo:available_users
(in /home/piyo/tasks)
1,Taro Yamada,yamada@example.com
2,Hanako Tanaka,tanaka@example.com
3,Mitsu Dan,dan@example.com
...
ログファイルの出力イメージは下記の通り。
# Logfile created on 2013-03-26 16:44:33 +0900 by logger.rb/31641
I, [2013-03-26T16:44:33.887404 #3899] INFO -- : (0.002629s) SELECT * FROM "USERS" WHERE ("AVAILABLE" = 1)
発行されたSQLの内容と実行にかかった時間が記録されていることが確認できます。

このタスクで初めてdescというメソッドが登場して来ましたが、ここにはタスクの説明を付加することができます。
descを付加することで何が嬉しいかというと、
$ rake -T
(in /home/piyo/tasks)
rake piyo:available_users # ログイン可能であるユーザの一覧を出力する
このようにrakeコマンドに-Tオプションを付加することで定義済みのタスクの一覧を説明付きで出力できるようになります。
内部的な共通タスクにはdescをつけず、実際に目的をもって実行するタスクについてはdescを付加して公開タスクとするというルールがオススメです。

単純なSELECT文にとどまらず、トランザクション制御+CRUDといった局面も例示してみたいのは山々ながら、長くなるので割愛しちゃいますが、特にトランザクションの取扱いについてはrubyの柔軟性を活かして非常にシンプルな記述ができる、とだけ叫んでおきます。

適用範囲の拡張のために

さて、ここまでの準備でデータベースタスク定義の枠組みは最低限揃いました。
あとは必要に応じたタスクを追加していくことで日々の業務に役立てていけると思います。

最後に細かいtipsをいくつか提示したいと思います。

HighLineによるパスワードの隠匿

今回の例では設定ファイル内にデータベース接続のためのパスワードを直書きしていますが、こういったパスワードを設定ファイルに持たずに実行時に入力させたいといった状況も十分に考えられます。
こういう場合にはHighLineがピッタリです。
$ gem install highline
sequelと同様にgemでインストール出来ます。
ask("Enter your password:  ") { |q| q.echo = false }
ask("Enter your password:  ") { |q| q.echo = "x" }
一般にパスワード入力中の内容は画面上に表示しないことが望ましいため、上記のどちらかのパターンを使ってタスク中の任意のタイミングでパスワード入力を求めることができます。

Net::SSHを利用したサーバタスク

ruby上でsshセッションを気軽に扱えるNet::SSHNet::SCPといったgemを導入すると、サーバリソースの操作も含めたタスクの作成に役立ちます。
Net::SSHを利用すればサーバにログインしてコンソールから実行できることの大部分が自動化できます。

JRuby+JDBCを利用する

sequelを使う利点のひとつがJRubyとJDBCへの対応です。
DB = Sequel.connect(:adapter => 'jdbc',
:url => 'jdbc:mysql://localhost/test',
:user => 'piyo',
:password => 'xxxxxxxx')
adapterにjdbcを指定することで簡単にJRuby環境からJDBCデータソースを利用することができます。
(ちなみにJDBCドライバの配置場所は$JRUBY_HOME/lib直下になります。)

JRuby+sequelの構成が素晴らしいのは「真のマルチスレッドが実現できる」ところにあります。
いわゆるCRuby(MRI)では外部ライブラリも含む環境全体でThread-safeが保証できないという前提からGIL(Global Interpreter Lock)機構によってプロセス内で同時に実行されるスレッド数が1つに制限されます。
JVMを基盤にしたJRubyにおいてはこの制限が無いため、CPUのコア数を活かした並列処理が容易に実現可能です。
つまるところ、Thread-safeに設計されているsequelと組み合わせることでデータベースへの並列処理を組み立てることが可能になります。

おわりに

たまたまrubyと知り合って10年以上愛用していますが、railsのようなフレームワークの材料として使うよりも、こういった小さなタスクを簡潔にこなすために利用する局面の方が、なんとなくrubyらしいと感じてしまうのは私だけでしょうか?
DRYでもなければRESTFULでもなく、ちょっと泥臭い(けれども現実にはありふれた)課題をスクリプト言語の足回りを活かして手早く解決していく、rubyをスーパーカブのように乗りこなすスタイルも悪く無いと思う昨今です。


仕事内容のご紹介 ~デザイン制作部編

こんにちは。
11月に新設されましたデザイン制作部(旧:技術戦略部 WEBマスターチーム)のみながわです。

これまでTECH BLOGでは、技術戦略部のメンバーがエンジニアならではの情報を発信してきましたが、
今回はテクニカルな内容から少し離れ、デザイン制作部の仕事内容を紹介させていただきます。


◆デザイン制作部とは?
 
目的に応じて、何を、どこに、どのように配置するべきかを考え、ページデザインと
HTML/CSSコーディングを行う部門です。

・わかりやすさ、使いやすさ(ユーザビリティー、アクセシビリティ)の追求
・ページから与えられる印象の形成
・サイト内のデザイン統一
・コーディング品質の向上

を担っています。


◆作業フロー
 
1.要望があがる
  要望箱という社内掲示板に、他の部署や同じ部署のメンバーから実現したいことが書かれます。
  具体的な実現手段が指定されているケースもあれば、大雑把に目的だけが示されている場合も
  あります。

写真1(要望)

2.実現手段をすり合わせる
  社内会議やメール、要望箱掲示板などを通して、どのような画面が必要なのかを依頼者と、
  制作担当者とですり合わせます。

3.実施判断
  依頼内容に応じて、ドメイン責任者による承認ステップを踏みます。
  また法務に抵触する内容がないか、法務担当への確認も、このタイミングで行います。

4.制作
  印刷物のデザインやバナー、新規ページ、メールフォームなど対応内容は様々。
  コーディングはHTMLファイルで行うこともあれば、JSPファイルで行うこともあります。
  メールフォームを作る際は、社内に用意されている、汎用的に使えるメールフォームの
  システムを使い、複雑な仕様でなければ、開発者なしで制作できるようになっています。
  【使用するソフト】
  IllustratorCS5、PhotoshopCS5、Dreamweaver、Eclipse、サクラエディタ、WinMerge など
  
5.最終チェック
  デザインはそれぞれの好みに左右されることが多いため、
  サイト全体から見たそのページの印象、統一感などを含め、第三者目線での判断を入れます。
  これは各ドメインの最終チェック者が担当します。
  
6.依頼者確認
  できあがったものを依頼者に確認してもらいます。
  
7.QA
  部内で品質をチェックをします。
  QA担当者は、制作物に問題がないかを専用のチェックシートに沿って確認します。
  【確認ポイント】
  ・ページ内容
  ・フォーム等の挙動
  ・ブラウザ互換
  ・HTMLバリデーション
  ・JavaScriptの動作
                                  など
  メンバーごとに固有のローカルIPでページを確認できるようになっており、Hostsファイルを
  書き換えて確認しています。
  システムが絡む案件の場合は、技術戦略部と協力し、品質を担保することもあります。
  
8.本番アップ~反映確認


◆活用しているツールなど
 
部内Wiki
   作業の引継ぎや共有がスムーズに行えるよう、作業マニュアルをWikiで管理しています。

UIガイドライン
  デザイン統一化のためにドメインごとにUIガイドラインを用意しています。
  HTMLファイルで作成しており、ソースのコピペができるようになっているため、作業の効率化
  にも役立っています。

写真2(ガイドライン)
  
 Windows Virtual PC
  ブラウザ互換のチェックをするために利用しています。

Google Analytics
  制作したページの効果を検証したり、改善提案を行う際の調査に活用しています。

Firefox各種アドオン
  「FireBug」・・・Webデバッグツール
  「Html Validator」・・・表示中のページにHTMLのエラーがないかを検証する
  「SwitchHosts」・・・hostsの切り替えを行う
  「Popup ALT Attributes」・・・Firefox上からaltの内容を確認する
  「ColorZilla」・・・表示しているページ内から色情報を取得する
  「Firesizer」・・・ウィンドウの表示サイズの切り替えを行う

※スペースの都合上、詳細は割愛させていただきました。
   「活用しているツールなど」については、後日また改めてご紹介いたします!


◆まとめ

ラクーンでは企画~リリースまでにいくつものチェックがあります。
そのために、案件の対応に時間がかかってしまうこともありますが、
「品質を最優先して案件に臨める環境」が整っていると感じています。

以上、「デザイン制作部の仕事内容について」でした。

写真3(デザイン制作部)
 新しい仲間を募集中です☆

格安サーバで作る ESXi+NFS(ZFS) の仮想マシン環境(3)

インフラエンジニアのETOです。  

弊社は間もなく本社を移転するため、準備に追われていて忙しい日々です。
なにかと人手不足なので、一緒に働いてくれる方を募集中です!


前回の「格安サーバで作る ESXi+NFS(ZFS) の仮想マシン環境(2)」に引き続き、今回はいよいよ「仮想マシンホストサーバ」を構築し、仮想マシンを作ってベンチマークをとりたいと思います。
3回目になりますこのお題も、今回で最後です。張り切っていきましょう!

・今回使うもの
 ・仮想マシンホストサーバ
  ハード: HP ML110G7 
      メモリ 16GB
      USBメモリ起動 8GB
      HDD ナシ ZEROスピンドル!
 
 OS: ESXi5.0 Update 1 
      "VMware-VMvisor-Installer-5.0.0.update01-623860.x86_64.iso"を焼いた起動メディア一枚。
       ※ESXi5.0用のライセンスキーもisoダウンロードの際に控えておいてください。


・構成図
今回は左側の「vmhost01」をセットアップします。
kousei




・前準備
ML110G7の内部USBポートに起動用のUSBメモリをさします。

前面スロットからHDDを抜きます。
抜いたHDDの転用先がないという方はそのままでも結構です。

ネットワークを結線します。
前回作ったNFSサーバも結線して起動しておいてください。 

BIOSの設定を調整します。
ML110G7とESXi5.0は標準設定のままだと、紫色(?)のエラー画面が出て起動しません。
これを回避するにはBIOSの以下の項目を調整する必要があります。
HP Power Regulator: OS Control Mode
HP Power Profile: Custom
Advanced Power Management Options Minimum Processor Idle Power State: C6 States
参考:vSphere 5.0 on HP ML110 G7 

↓このあたりです
ML110G7_BIOS_2

 
 

・セットアップ手順 
ESXi5.0 Update 1 をインストールします。
BIOSの設定が正しく行われていれば詰まるような箇所はないと思います。

注意が必要なところのみ抜粋します。
Select a Disk to Installation or Upgrade
※インストール先にUSBメモリを選択。
※HDDを搭載したままの人はインストール先に注意。

Please select a keyboard layout
※Japaneseを選択。
あとは画面の指示に従ってインストールしてください。


インストールが終了して、再起動後にやるべきことは、
  1. ESXiサーバの管理用ip設定
  2. VMware vShpere Clientのインストール
  3. ESXiサーバの構成設定(ライセンス、NTP、ネットワーク、ストレージ)
になります。


1. ESXiサーバの管理用ip設定
再起動して黄色いESXiの画面になったらF2を押してログインし、
[Configure Management Network]→[IP Configuration]
を選択。
構成図の通りにipを設定していきます。必要な方はご自分の環境に合わせて変更してください。
IP Address [192.168.0.1]
Subnet Mask [255.255.255.0] 
Default Gateway [192.168.0.254]
 0U1_01

SSHでESXiに直接ログインしたい方は
[Troubleshooting Options]→[Enable SSH]
もやっておきましょう。色々と便利です。


2. VMware vShpere Clientのインストール
設定したipにブラウザでアクセスするとクライアントをダウンロードできるページが表示されます。便利ですね!
ダウンロードしてインストールしてください。

ちなみに既に旧バージョンのクライアントがインストールしてある場合は、クライアントでアクセスするとバージョンアップファイルが自動的にダウンロードされます。
 

3. ESXiサーバの構成設定(ライセンス、NTP、ネットワーク、ストレージ)
クライアントでESXiサーバにアクセスして構成設定をしていきます。
 0U1_02

・ライセンス設定
isoダウンロードの際に控えておいたライセンスキーを入力してください。

・ NTP設定
適当なNTPサーバを設定してください。nictmfeedあたりでよいでしょう。
設定後に、起動ポリシーを[ホストに連動して開始および停止]にしてサービスコマンドから[開始]しておいてください。
仮想マシンは時計がずれやすいので、ホストサーバ側の時計を正確に保っておくのは意外と重要なことです。

・ネットワーク設定
管理用に登録したip側のネットワークは既に構成されていると思いますので、NFS用のネットワークを追加します。
ネットワークの追加画面から[接続タイプ]で[VMkernel]を選択してNFSネットワーク用のip(10.255.255.1)を設定します。必要な方はご自分の環境に合わせて変更してください。

↓成功すればこのような感じになります。
0U1_03
・ストレージ設定
ストレージの追加画面から[ネットワークファイルシステム]を選び、NFSサーバの情報を入れていきます。ご自分の環境に合わせた方は適宜読み替えてください。 
サーバ: 10.255.255.100
フォルダ: /datapool/nfs01
データストア名: nfs01 
ネットワークの設定と、前回作ったNFSサーバの設定がうまくいっていればここで詰まることはないはずです。



これで「仮想マシンホストサーバ」の作成は完了です!



仮想マシンでベンチマーク
早速Linux(CentOS5)の仮想マシンを1台作ってベンチマークを取ってみましょう。
[ファイル]→[新規]→[仮想マシン]から仮想マシン作成を行います。

各パラメータは以下のとおりです。
名前 linuxtest
データストア nfs01
ゲスト OS CentOS 4/5/6(64ビット)
CPU 2
メモリ 4096MB
NIC 1
NIC1ネットワーク: VM Network
NIC 1タイプ E1000
ディスクプロビジョニング: シン プロビジョニング
仮想ディスクサイズ: 30GB
 
 仮想マシンが追加されたら、
[インベントリ]→[仮想マシン]→[コンソールを開く]
で仮想マシンのコンソール画面を開き、今回はCentOS5.8をインストールします。

↓コンソール画面からインストール用のisoイメージを直接マウントすることができます。
0U1_04

 
CentOSのインストール部分は割愛させていただきます。 


さて、無事にインストールができたでしょうか。
次はbonnie++でベンチマークタイムです。ドキドキです。 
[root@centos5~]# bonnie++ -d / -n 128  -u 0
~中略~
Version  1.03       ------Sequential Output------ --Sequential Input- --Random-
                    -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks--
Machine        Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP  /sec %CP
centos5                4G 42153  71 96249  17 39526   8 53224  85 101409   7 14859  18
                    ------Sequential Create------ --------Random Create--------
                    -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete--
              files  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP
                128 65598  70 +++++ +++ 126228 100 94847  99 +++++ +++ 120353  99
NFS越しですが、シーケンシャルでread/write共に100MB/s近く出ています。
今回は1000BASE-Tでネットワークを組んでいますので、理論値の限界は125MB/s。
そう考えるとなかなかいい数字が出ているのがお分かりいただけると思います。



おわりに
今回はひとまず基本をおさえていただきたいということで、あえて安い機材構成を使いましたが、
UPSや冗長化電源、RAIDカード、LANカードを追加していただくことで、さらに可用性の高いシステムを
手軽に構築することが可能だと、実感いただけたかと思います。

全3回になりましたが、このお題も今回で終了です。長々とお付き合いいただきありがとうございました!

格安サーバで作る ESXi+NFS(ZFS) の仮想マシン環境(2)

インフラエンジニアのETOです。  

暑い日が続きますが皆様いかがお過ごしでしょうか。
最近、週に2回ほど熱いお風呂につかるようにしたのですが、寝付きがとても良くなりました。
肩こりも取れますので、オフィスの冷房で肩こりが酷い方にもお勧めです!


さて、早速ですが前回の「格安サーバで作る ESXi+NFS(ZFS) の仮想マシン環境(1)」の続きです。今回は実際の構築に入っていきましょう。
まずは「NFS外部ストレージサーバ」からセットアップしていきます。

・今回使うもの
  ・NFS外部ストレージサーバ
 ハード: HP ML110G7
     メモリ 8GB
     USBメモリ 8GB
     HDD 2TB*4
 
 OS: OpenIndiana 151a (for servers)
      "oi-dev-151a-text-x86.iso"を焼いた起動メディア一枚。
※今回はZFSを使うのでOpenSolaris系OSの正統後継である「OpenIndiana」をインストールしたいと思います。最近ではFreeBSDやLinuxでもZFSを使えますが、やはり安定性を考えると実装元であるSolaris系OSで使うべきだと思います。

・構成図
今回は右側の「fsrv01」をセットアップします。
kousei



・前準備
ML110G7の内部USBポートに起動用のUSBメモリをさします。
この機種では内部SDカードスロットも付いたので、そちらでチャレンジしてみても面白いかもしれません。

前面の4つのスロットにHDDを搭載します。
今回使うノンホットプラグモデルのML110G7に4つ並んだSATAスロットのうち、左側の2つは6.0Gbpsですが右側の2つは3.0Gbpsです。SSDを搭載する場合はボトルネックにならないよう左側に搭載しましょう。
※余談ですが、2.5インチのSSDをこのスロットにきれいに収めるには2.5→3.5変換ケースのSilverStone「SST-SDP09」が大変おすすめです。余計なチップは搭載されておらず、延長コネクタのような構造のため相性問題など出ません。

BIOSの設定を調整します。
起動時に、F9でBIOS設定画面へ。
 [Advanced Options]→[SATA Controller Options]→[Embedded SATA Configuration]
  "Enable SATA AHCI Support"へ変更
 [Advanced Options]→[SATA Controller Options]→[Drive Write Cache]
  "Enable"へ変更 (信頼性優先ならDisableで)
↓このあたりです
ML110G7_BIOS





・セットアップ手順
OpenIndiana 151a (for servers) をインストールしていきます。
サーバ用として配布されている「oi-dev-151a-text-x86.iso」でCDかDVDを作成して起動しましょう。

以降注意が必要なところのみ抜粋します。 
TO select the Keyboard layout, enter a number [default 47]: 23
※23番日本語キーボードを選択。

TO select the language you wish to use, enter a number [default is 7]: 7
※ここはそのまま7で。テキスト版なので日本語は出ません。

Disks
※内部に挿したUSBを選択。

Fdisk Partitions: ~
※「Use the whole disk」を選択。

Network
※[Computer Name:]に「fsrv01」を入力。
※カーソルを下段の「None」にあわせる。
あとは画面の指示に従ってインストールしてください。


インストール終了後、再起動後にやるべきことは、
  1. rpool(システム領域)のatimeをoffにする
  2. ipとネットワークの設定
  3. ストレージプールの作成とNFS設定
  4. swap領域をrpoolからdatapoolに移す 
になります。
どんどんいきましょう。


1. rpool(システム領域)のatimeをoffにする
まずシステム領域のatime(access time)を無効化しましょう。
atimeの無効化には賛否両論ありますが、利用目的がNFSオンリーであることとUSBメモリだと細かいディスクI/Oが気になるので、思い切ってoffにします。

root@fsrv01:~# zfs set atime=off rpool


2. ipとネットワークの設定
構成図の通りに設定していきます。必要な方はご自分の環境に合わせて変更してください。
今回は必要最低限の設定しかしませんので、詳しく勉強したい方はORACLE社のドキュメント「ネットワークスタックの概要」をご覧ください。
root@fsrv01:~# echo '192.168.0.254' > /etc/defaultrouter
root@fsrv01:~# ipadm create-addr -T static -a 192.168.0.100/24 e1000g0/v4
root@fsrv01:~# ipadm create-addr -T static -a 10.255.255.100/24 e1000g1/v4  
上から、デフォルトゲートウェイの設定、表ネットワークのip設定、 NFSネットワークのip設定、になります。
ここで設定反映のため一度再起動してください。


3. ストレージプールの作成とNFS設定
zpoolコマンドを使ってzfsストレージプールを作成していきます。
まず、formatコマンドを使ってHDDの認識状況を確認しましょう。
root@fsrv01:~# format
Searching for disks...done


AVAILABLE DISK SELECTIONS:
       0. c4t0d0
          /pci@0,0/pci103c,330d@1f,2/disk@0,0
       1. c4t1d0
          /pci@0,0/pci103c,330d@1f,2/disk@1,0
       2. c4t2d0
          /pci@0,0/pci103c,330d@1f,2/disk@2,0
       3. c4t3d0
          /pci@0,0/pci103c,330d@1f,2/disk@3,0
Specify disk (enter its number): ^D

しっかり認識されていますね。CTRL+Dで抜けて、続けて以下のコマンドを実行します。

root@fsrv01:~# zpool create datapool mirror c4t0d0 c4t1d0 mirror c4t2d0 c4t3d0

これで、「datapool」という名前のストレージプールが、raid10で作成されます。なんとお手軽なのでしょう。
zpool statusコマンドで確認してみましょう。
root@fsrv01:~# zpool status datapool
  pool: datapool
 state: ONLINE
  scan: none requested
config:

        NAME        STATE     READ WRITE CKSUM
        datapool   ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            c4t0d0  ONLINE       0     0     0
            c4t1d0  ONLINE       0     0     0
          mirror-1  ONLINE       0     0     0
            c4t2d0  ONLINE       0     0     0
            c4t3d0  ONLINE       0     0     0
mirror-0とmirror-1がそれぞれRAID1、それをストライプしてdatapoolが構成されているのがわかります。
また作成時に自動的に/datapoolとしてマウントされていますので、今回はこのまま使います。 


続けてNFS用のデータセットの作成と、NFSエクスポートを一気にやってしまいます。

root@fsrv01:~# zfs create datapool/nfs01
root@fsrv01:~# zfs set sharenfs=rw,root=@10.255.255.0/24 datapool/nfs01

たった2行です。上がデータセットの作成、下がNFSのエクスポートの設定になります。
エクスポート設定について補足すると、"root="はLinuxでいうところの"no_root_squash"、"@10.255.255.0/24"はこのネットワークに対して許可を出すという意味合いです。


4. swap領域をrpoolからdatapoolに移す
USBメモリにインストールしたので、swap領域もUSBメモリ上の「rpool/swap」にできてしまっています。
立派なストレージプール「datapool」ができましたのでこちらに移してしまいましょう。
root@fsrv01:~# zfs create -V 8G -b 4k datapool/swap
root@fsrv01:~# swap -a /dev/zvol/dsk/datapool/swap

root@fsrv01:~# swap -lh
swapfile             dev    swaplo   blocks     free
/dev/zvol/dsk/rpool/swap 179,2         8  2.0G  2.0G
/dev/zvol/dsk/datapool/swap 179,3         8  8.0G  8.0G    ←追加された方
rpoolのswap領域をswapから外して消します。
root@fsrv01:~# swap -d /dev/zvol/dsk/rpool/swap
root@fsrv01:~# zfs destroy rpool/swap

root@fsrv01:~# swap -lh
swapfile             dev    swaplo   blocks     free
/dev/zvol/dsk/datapool/swap 179,3         8  8.0G  8.0G


おまけ
せっかくなのでbonnie++でベンチ取ってみました。
root@fsrv01:~# bonnie++ -d /datapool/ -n 128  -u 0
~中略~
Version 1.03c       ------Sequential Output------ --Sequential Input- --Random-
                    -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks--
Machine        Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP  /sec %CP
fsrv01           8G 92723  98 197266  21 115933  20 100931  99 327860  20  1439   3
                    ------Sequential Create------ --------Random Create--------
                    -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete--
              files  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP
                128 20072  93 182108  99 26543  96 22806  98 206876  84 24443  97
シーケンシャルでwrite 200MB/s, read 300MB/s程度出ているので、NFSで利用することを考えると十分な性能ですね。


どうでしょうか、非常に簡単にNFSサーバが構築できたかと思います。
NFS以外にもSMB共有の設定なども簡単にできますので、興味のある方はORACLE社のドキュメント「ZFSファイルシステム」を御覧ください。


さて、次回はESXiのストレージとしてNFSを登録、その上に仮想マシンをつくってみます。
「格安サーバで作る ESXi+NFS(ZFS) の仮想マシン環境(3)」へ続きます。
言語を検出 » Japanese

記事検索