2012年12月18日火曜日

Chef Recipeの書き方と運用

Chefがインストールできたので次はRecipeを書いていきます。


Recipeの作成


ChefはRecipeをバージョン管理することができます。ただSVNやGitのような高機能なバージョン管理システムはもっていないので複数人でRecipeを編集する場合は編集点を明確にする上でもSVNやGitを導入した方がよいでしょう。

リポジトリは'knife configure -i'で設定した場所になります。
デフォルトだと'/var/chef/cookbooks/'になります。

knifeコマンドでbaseというRecipeを作成します。

#knife cookbook create base


以下のようなファイルとディレクトリが作成されたと思います。

-attributes/
-CHANGELOG.md
-definitions/
-files/
-libraries/
-metadata.rb
-providers/
-README.md
-recipes/
-resources/
-templates/

普段使わないものもあるので、利用頻度の高そうなものから書きたいとおもいます。

recipes


このディレクトリの中にdefault.rbというファイルがあります。
このファイルにRecipeを書きます。
Rubyが使えます。

'/tmp/work'というディレクトリを作成するには以下のように書きます。

directory "/tmp/work" do
owner "root"
group "root"
mode "0777"
action :create
end


directory部分はResourcesと言われまして、Chef側で予めサポートされているものになります。
標準Resourcesだけで十分Recipeを書くことができます。
Chef Resources一覧

Resourcesを使いこなすことでグンとRecipeを書くスピードが上がりコストも下がるので一度目を通しておくとよいでしょう。

スクリプトを記述することもできます。
ただ、毎回実行されてしまうためこのようにtar展開などをすると毎回上書きされ実行時間が長くなるのであまりオススメできません。
スクリプトはPerl,Ruby,bash,csh,Pythonが対応しています。


script "install_something" do
interpreter "bash"
user "root"
cwd "/tmp"
code <<-EOH
wget http://www.example.com/tarball.tar.gz
tar -zxf tarball.tar.gz
cd tarball
./configure
make
make install
EOH
end


files


クライアントに配布したいファイルをこのディレクトリに置きます。
CHEF-REPO/base/files/default/New_File.tgzと配置したとします。

Recipeでこのように書くと'/tmp/'に配置されます。

cookbook_file "New_File.tgz" do
source "/tmp/New_File.tgz"
end


filesはパッケージや設定ファイルを含めてファイルを配布するには非常に便利ですが設定ファイルはtemplateで配布することを推奨したいです。
そうすることでChefの本来のパワーを自然と発揮できるようになるはずです。

libraries


recipesと殆ど同様の使い方ができます。
RubyとChef既存のResourcesで記述でき独自のクラスを定義することでChefを拡張できます。

moduleを定義することもできますし、defで定義してrecipeで利用することもできます。
your_cookbook/libraries/your_example_library.rb

# define a module to mix into Chef::Recipe
module YourExampleLibrary
def your_function()
# ... do something useful
end
end


your_cookbook/recipes/default.rb


# open the Chef::Recipe class and mix in the library module
class Chef::Recipe
include YourExampleLibrary
end

your_function()


definitions


機能的にはlibrariesと近いですがChefの拡張ではなく既存のResourceを組み合わせて、再帰可能なResourceを定義します。
Rubyが使えます。

apache_siteというdefinitionsを定義します。
apache_site Definition

define :apache_site, :enable => true do
include_recipe "apache2"

if params[:enable]
execute "a2ensite #{params[:name]}" do
command "/usr/sbin/a2ensite #{params[:name]}"
notifies :restart, resources(:service => "apache2")
not_if do
::File.symlink?("#{node[:apache][:dir]}/sites-enabled/#{params[:name]}") or
::File.symlink?("#{node[:apache][:dir]}/sites-enabled/000-#{params[:name]}")
end
only_if do ::File.exists?("#{node[:apache][:dir]}/sites-available/#{params[:name]}") end
end
else
execute "a2dissite #{params[:name]}" do
command "/usr/sbin/a2dissite #{params[:name]}"
notifies :restart, resources(:service => "apache2")
only_if do ::File.symlink?("#{node[:apache][:dir]}/sites-enabled/#{params[:name]}") end
end
end
end


recipeないでapache_siteに対して渡された値はparams[:hoge]で取得できます。



# Enable my_site.conf
apache_site "my_site.conf" do
enable true
end

# Disable my_site.conf
apache_site "my_site.conf" do
enable false
end


definitionsは読み込まれたrecipeないで包括的に利用されるためActionメソッドを渡すことはできません。
Actionメソッドを使いたい場合はResouceを使います。
cookbook {cookbook_name}でcookbookを指定することも可能なのでファイルなどは特定のrecipeにまとめることができます。


templates/attributes


erbが使えます。
設定ファイルはerbを書かなくてもtemplatesで配布すること推奨します。
templateかrecipeにnilの処理を入れておかないとnilがあった際にエラーがでます。
node[:hoge]の部分はattributeから取得できる値に展開されます。

A template (templates/default/sudoers.erb)


#
# /etc/sudoers
#
# Generated by Chef for <%= node[:fqdn] %>
#

Defaults !lecture,tty_tickets,!fqdn

# User privilege specification
root ALL=(ALL) ALL

<% @sudoers_users.each do |user| -%>
<%= user %> ALL=(ALL) <%= "NOPASSWD:" if @passwordless %>ALL
<% end -%>

# Members of the sysadmin group may gain root privileges
%sysadmin ALL=(ALL) <%= "NOPASSWD:" if @passwordless %>ALL

<% @sudoers_groups.each do |group| -%>
# Members of the group '<%= group %>' may gain root privileges
%<%= group %> ALL=(ALL) <%= "NOPASSWD:" if @passwordless %>ALL
<% end -%>


attributeを定義しておくと、プラットフォームやOSが代わっても柔軟に対応させることができます。個々のパラメータなどはattributeに書いておきましょう。

default["authorization"]["sudo"]["groups"] = [ "sysadmin","wheel","admin" ]
default["authorization"]["sudo"]["users"] = [ "jerry","greg"]


A template resource (recipes/default.rb)

template "/etc/sudoers" do
source "sudoers.erb"
mode 0440
owner "root"
group "root"
variables({
:sudoers_groups => node[:authorization][:sudo][:groups],
:sudoers_users => node[:authorization][:sudo][:users]
})
end



recipeの更新


recipeを書き終えるとcookbookの更新を行わければ最新バージョンは適用されません。


//cookbooK_nameのrecipeを更新
#knife cookbook upload {cookbooK_name}

//すべてのrecipeを更新
#knife cookbook upload -a


metadata.rbでバージョンを0.1.1にあげてuploadするとバージョンがあがることがわかります。

Uploading hoge [0.1.1]


バージョンを区切ると前回のバージョンは別で保持されるので、クライアントごとにバージョンを指定したり特定のバージョンに固定化させることもできます。バージョンの運用方法はそれぞれあるので環境に適した方法を選んでください。

オススメは、とにかく編集した後はバージョンを上げるてクライアントにはバージョン指定でrecipeを適用する方法でそうすることでデグレードを最小限に防ぐことができます。

recipeの適応


recipeの適応はクライアント側でchef-clientを実行するのみです。
chef-clientを実行すると即座に適応が開始されるためDryRunを適応前に行いましょう。

chef-client --why-run


knife sshを使いこなせ


数百台レベルのサーバになるとchef-clientの実行自体が容易ではないのでサーバからknifeコマンドでクライアントのrecipeを適用します。

knife sshコマンドはオプションが多数あるので一例です。
hostnameの部分はhostnameを元にマッチしたホストにSSHを実行します。デフォルトはFQDNになります。

interactive オプションをつけることで接続できたクライアントに対してインタラクティブに操作することが可能になります。

-aは接続に利用するattributeを選択でいます。attributeで取得できる値であればなんでも利用可能なのでIPアドレスベースでの接続も可能です。例はhostnameを指定しています。

-x:接続ユーザ
-P:パスワード

knife ssh 'hostname:client-1[0-9]' interactive -x root -P password -a hostname

Opscode Knife

サーバのホスト名を自動で取得し割り当てる方法


※タイトルが不適切だったので変えました(笑)
Chefで構成管理ができると電源ポチでサーバ構築までしてほしいですよね。
ホスト名とIPを動的に結びつけることができれば少なくともDHCPで払い出すIPのレンジ単位でホストの管理でき、うまくいけばIP管理表を捨てれるかもしれません。
今回紹介する仕組みはBINDの拡張機能を利用します。

お気づきかと思いますがタイトルと内容が若干ずれていますがタイトルの内容は十分把握できると思います。

概要
  1. DHCPからIPを割り当てる
  2. 割り当てられたIPから逆引きで名前を引いてくる
  3. ホスト名に割り当てる
DHCP

DHCPは任意のIPを割り当てられる環境がればなんでもよいです。
安物ルータのDHCPでも可。

Linuxのdhcpdを使うのであれば以下のような設定になると思います。

/etc/dhcp/dhcpd.conf
ddns-update-style interim;
ignore client-updates;

subnet 192.168.0.0 netmask 255.255.255.0 {

# --- default gateway
        option routers                  192.168.0.1;
        option subnet-mask              255.255.255.0;

        #option nis-domain              "domain.org";
        #option domain-name             "domain.org";
        #option domain-name-servers      192.168.10.1;

        option time-offset              -18000; # Eastern Standard Time
        #filename "/linux-install/pxelinux.0";
        #next-server                     192.168.1.2;
#       option ntp-servers              192.168.10.1;
#       option netbios-name-servers     192.168.10.1;
# --- Selects point-to-point node (default is hybrid). Don't change this unless
# -- you understand Netbios very well
#       option netbios-node-type 2;

        range dynamic-bootp 192.168.0.100 192.168.0.200;
        default-lease-time 21600;
        max-lease-time 43200;

        # we want the nameserver to appear at a fixed address
#        host ns {
#                next-server marvin.redhat.com;
#                hardware ethernet 12:34:56:78:AB:CD;
#                fixed-address 207.175.42.254;
#        }
}


後はDHCPを受けるクライアントをBOOTPROTO=dhcpにしてネットワークを再起動してください。

BIND

BINDはDHCPによって割り当てられたIPからホスト名を逆引きするために利用します。
BINDにはGENERATEという拡張機能がありゾーンフィアルを簡略化することができます。

これが通常の逆引きのゾーンファイルです。
200     IN      PTR     client-200.
201     IN      PTR     client-201.
202     IN      PTR     client-202.


サーバ台数が増えるとゾーンファイル内が煩雑になるので以下のように書き換えることができます。
$GENERATE 200-202 $.0.168.192.in-addr.arpa. PTR client-$.


前者と後者は同意になります。

複数セグメントがある場合は
$GENERATE 200-202 $.0.168.192.in-addr.arpa. PTR client-168-$.

とかするとユニークなホスト名が生成できます。

$GENERATE 200-210/2 $.0.168.192.in-addr.arpa. PTR client-${-99,3,d}.

200-210/2

/nはステップになります。
192.168.0.200
192.168.0.202
192.168.0.204
192.168.0.206
192.168.0.208
192.168.0.210
に展開されます。

${-99,3,d}

${オフセット,桁数,ベース(o,d,X,x)}
オフセット
ex)192.168.0.200
200-99=101
逆引きのホスト名はclient-101になる。

桁数
client-{桁数}

ベース
d:小数
o:8進数
X or x:16進数

このようにオプションがあり、自由に規則性を持たせることができます。
GENERATEはPTR以外にもCNAME, DNAME, A, AAAA and NSで利用できます。
BIND Master File Extension: the $GENERATE Directive

ホスト名を逆引きから割り当てる

/etc/sysconfig/network
HOSTNAME=
のように空にして逆引きができれば起動時に動的に割り当てられます。

hostname -fで引けるFQDNやホスト名を固定化させたい場合はhostsに追加するしたり、networkに追記するなどの工夫が必要です。
ChefのOhaiが取得するFQDNはhostname -fの値になるので注意してください。

自動でホスト名を割り当てる基準としてDHCPを利用しているため起動のタイミングによってはIPが変わる可能性があります。
そのため一度逆引きすると固定化するようにnetworkファイルを書き換えたほうが無難です。

PXE+Kickstart+Chefを組み合わせれば電源ポチで構築できるようになります。

2012年12月11日火曜日

ChefかPuppetで悩んだお話

前回の記事でChefは動くようになったと思います。
ChefとPuppetの違いはなんだろうと思い使いながら気づいた事をツラツラと書いておきます。

DSL


これらの構成管理ツールはPuppetだとマニフェストでChefだとレシピを統一された言語とフォーマットで記述し誰が見てもわかる状態であることがとても大切だと思っています。

やはり大きな違いは外部DSL(Puppet)か内部DSL(Chef)であることがあげられます。

この点に関しては大きな差は見られないといったところでしょうか。ChefもDSLチックに書くことができRubyを殆ど書かなくてもレシピを書き上げることができます。

前述したましたが構成管理は”統一された言語とフォーマット”であるべきだと思っているので各構成管理ツールの専用の文法のみで書き上げることが望ましいですが、さすがにfor eachぐらいは使わないと辛いのでどうしてもこのへんはRubyになります。ただそれぞれ関数化など包括する仕組みがあるので実際問題それほど煩わしい作業になることはありません。

結論でいうとDSLという面で言えばPuppetでもChefでも同じですよって話でした。

ミドルウェア


PuppetはPupept以外のミドルウェアが必要なくUnicornを使ったりもできますね。
それと比べてChefはメッセージキューやDBが必要になります。

特にDBはCouchDBでそんなもの運用したことないよって思いましたがネット上にゴロゴロと情報があったので運用面では問題になりそうではありませんでした。

インストール自体はyumやGemを利用すればよいので導入コストも殆ど同じでしょう。

Attributes


アトリビュート?で僕はChefを選びました。おそらくChefで一番ウリにしている部分だと思っています。
AttributesはOhaiを使ってクライアンの情報をサーバ側に伝え、サーバ側はそれを記録したものがAttributesです。
Attributesで取得できる情報はディスクのマッピング先、メモリサイズ、インストールされている言語、Uptime、OSの種類、ファイルシステム、ネットワーク、ハイパーバイザーの種類などもっと多くあり追加することも可能です。
これらの情報を動的に取得し、レシピ内ではnode[:os]やnode[:fqdn]と記述することで利用できます。

端的に申しますと、これらの情報はオンプレ環境やマルチクラウドなどに大いに役に立てる事ができます。
例えば、ネットワーク情報を元にG/Wを変更したりOS毎にレシピを分けることなくtemplateを簡単に切り分けることができるためサーバの環境の差を柔軟に吸収することができます。

バージョン管理


Chefは標準でバージョン管理の仕組みを持っています。
metadata.rbをversionを変えることでバージョンを指定できます。
このバージョンもAttributesと同様の使い方ができProduction環境では1.0の利用を強制してDevでは1.0以上のバージョンが利用できるなどオンラインでレシピを変更しても誤ってProductionに影響を与える事がありません。
このバージョン管理はロール単位で行え、バージョンの指定はクライアンごとに行えます。

databags


databagsはJSON形式であらゆるデータを保存し暗号化することができる機能です。
databagsにユーザIDやPasswordを一元管理し保存しレシピから利用できるためレシピ内にPasswordを記述し漏洩するリスクを軽減したり、変更するコストを下げることができます。


# Load the keys of the items in the 'admins' data bag
admins = data_bag('admins')

admins.each do |login|
# This causes a round-trip to the server for each admin in the data bag
admin = data_bag_item('admins', login)
home = "/home/#{login}"

# for each admin in the data bag, make a user resource
# to ensure they exist
user(login) do
uid admin['uid']
gid admin['gid']
shell admin['shell']
comment admin['comment']

home home
supports :manage_home => true
end

end

# Create an "admins" group on the system
# You might use this group in the /etc/sudoers file
# to provide sudo access to the admins
group "admins" do
gid 999
members admins
end


Tags


AWSのタグと同等の機能を持っておりkey valueの形式で記述事ができレシピ内で利用できます。
Attributesでは取得できないMETA情報を持たせるこに利用することが多いです。

まとめ


様々なレンタルサーバーでサーバを構築したりすることが多いので今回はChefを選びました。
キーさえあれば様々な情報をJSONで取り出すことができるので監視の自動がなども容易に行えます。
ハードウェア情報やクライアン情報を元に構築する必要がない場合はPuppetで十分だと思います。

2012年11月12日月曜日

mirror speeds from cached hostfile Error: Cannot retrieve metalink for repository: epel. Please verify its path and try again

なんだこのエラーっと思ってググっても的確な情報がなかったのですが、実は我が家の環境はF/W側でSSLをオフロードしているという特殊な環境でして、まれに対応していない証明書やオレオレ証明をうまくオフロードできずに通信を遮断してしまうのですがそれが原因でした。

具体的な対応策はrepoファイルのmirrorlistの部分をHTTPSからHTTPに変えるだけなんですがHTTPSにしか対応してないレポジトリもあるので要確認です。


mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-6&arch=$basearch





mirrorlist=http://mirrors.fedoraproject.org/metalink?repo=epel-6&arch=$basearch


一応 yum clean allしておくのがいいのかも。

2012年11月9日金曜日

Chef-Serverの設定

最近はPuppetよりもChefが流行りみたいなので「乗るしかない このビッグウェーブに」と思い色々検証を兼ねて入れてみましたメモです。
というより、Chef-Soroから入れている情報が多くてちょっと構成を把握しにくかったのでマニュアルインストールすることにしました。
でもgemで入れるだけで簡単に入るので特に作業はありませんが。

先に言ってしまったのですがChefはサーバ・クライアントモデルのChef-serverとChef-clientからなるモデルとServerなしでスタンドアロンで動作するChef-Soroがあります。

ちなみにこの章ではサーバ・クライアントの構築とWebUIが動くまでですのでレシピの管理とか運用系はまた後で書くのですぐにこのブラウザを閉じてください。

検証環境


OS:CentOS release 6.3
NIC:2
ネットワーク:eth0 10.0.2.0/24, eth1 192.168.56.0/24

Chef-Server環境



引用:Opscode

CouchDB (0.9.1-0.10+)
Java
Ruby
RabbitMQ
Rubygems
上記のミドルウェアはyumで入れます。

その前にEpelのリポジトリを追加しておきましょう。
#wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-7.noarch.rpm
#rpm -ivh epel-release-6-7.noarch.rpm


以下が必須パッケージです
#yum install couch*
#yum install java
#yum install ruby
#yum install ruby-devel
#yum install rabbitmq-server
#yum install gecode-devel
#yum install gecode

Rubyは1.9でも動くことを確認しましたが1.8.7で動かしました。
#wget http://rubyforge.org/frs/download.php/76073/rubygems-1.8.24.tgz
#tar -zxvf rubygems-1.8.24.tgz
#cd rubygems-1.8.24
#ruby setup.rb

これでChef-Serverを構築する環境が整いました。

ではGemから入れていきます。結構時間がかかります。
#gem install --no-rdoc --no-ri chef-server chef-server-api chef-server chef-solr chef-server-webui

インストールが問題なく終わったらミドルウェアの初期化しています。

RabbitMQ


# rabbitmqctl add_vhost /chef
Creating vhost "/chef" ...
...done.
# rabbitmqctl add_user chef testing
Creating user "chef" ...
...done.
# rabbitmqctl set_permissions -p /chef chef ".*" ".*" ".*"
Setting permissions for user "chef" in vhost "/chef" ...
...done.

CouchDB


かうちでぃーびぃーと読むみたいです。
初めて触りましたがMongoDBによく似ていてテーブルレスでNoSQLなDBです。
# /etc/init.d/couchdb start

Solr


# chef-solr-installer

Chef-Serverの設定


# mkdir /etc/chef/
# vi /etc/chef/server.rb

パスワードなどは適宜変更してください。
cookbook_pathはRecipeを配置するためのパスになります。
GithubからCloneしてきたりすることも想定されているので複数指定できます。
/etc/chef/server.rb
log_level          :info
log_location       STDOUT
ssl_verify_mode    :verify_none
chef_server_url    "http://localhost:4000"

signing_ca_path    "/var/chef/ca"
couchdb_database   'chef'

cookbook_path      [ "/var/chef/cookbooks", "/var/chef/site-cookbooks" ]

file_cache_path    "/var/chef/cache"
node_path          "/var/chef/nodes"
openid_store_path  "/var/chef/openid/store"
openid_cstore_path "/var/chef/openid/cstore"
search_index_path  "/var/chef/search_index"
role_path          "/var/chef/roles"

validation_client_name "chef-validator"
validation_key         "/etc/chef/validation.pem"
client_key             "/etc/chef/client.pem"
web_ui_client_name     "chef-webui"
web_ui_key             "/etc/chef/webui.pem"

web_ui_admin_user_name "admin"
web_ui_admin_default_password "1234567890"

supportdir = "/srv/chef/support"
solr_jetty_path File.join(supportdir, "solr", "jetty")
solr_data_path  File.join(supportdir, "solr", "data")
solr_home_path  File.join(supportdir, "solr", "home")
solr_heap_size  "256M"

umask 0022

Mixlib::Log::Formatter.show_time = false

ここまで準備できるともうChefが起動できるので起動してみましょう。
以下のコマンドで実行できますが、単体で動くか確認するためのnohupと&を省いて実行してみてください。
nohup chef-expander -n1 &
nohup chef-solr &
nohup chef-server -N -e production &
nohup chef-server-webui -p 4040 -e production &

証明書の設定


サーバとクライアント間は証明書を通じて認証を行います。
運用後にknife configure -iを実行すると証明書が変更され全クライアントと通信できなくなるので注意してください。
# knife configure -i
WARNING: No knife configuration file found
Where should I put the config file? [/root/.chef/knife.rb]
Please enter the chef server URL: [http://localhost:4000]
Please enter a clientname for the new client: [root]
Please enter the existing admin clientname: [chef-webui]
Please enter the location of the existing admin client's private key: [/etc/chef/webui.pem]
Please enter the validation clientname: [chef-validator]
Please enter the location of the validation key: [/etc/chef/validation.pem]
Please enter the path to a chef repository (or leave blank):
Creating initial API user...
Created client[root]
Configuration file written to /root/.chef/knife.rb

ここからClient側のお話
Client側はシンプルです。
RubyなどはServer側と同じバージョンですので省略します。
Severと同様の手順でGemもインストールしてください。
#yum install ruby
#yum install ruby-devel

Chef-Client


Clientインストール後初期設定をします。
# gem install --no-ri --no-rdoc chef 
# mkdir -p /etc/chef
# cd /etc/chef
# knife configure client ./

/etc/chef/client.rb
log_level        :info
log_location     STDOUT
chef_server_url  'http://chef-server.com:4000'
validation_client_name 'chef-validator'

/etc/chef/validation.pem
Server側にある'/etc/chef/validation.pem'の中身をコピーしてください

コピーするとサーバ側と認証し自身のクライアントキーが動的に登録されます。
#chef-client




ドハマリしたお話


”The file /etc/chef/validation.pem does not contain a correctly formatted private key.”

このエラーはほとんどの場合みかける場合がないと思います。
これは先程サーバ側からvalidation.pemをコピーしたと思いますがこのキーとサーバ側でフォーマットが違うよってエラーなんですが、そんな馬鹿な‥って思ってずっと悩み続けました。

SPCで転送すればいいものの僕はCygwinからコピーして貼りつけたのですが、ここで改行コードがWindowsの改行コードになってしまったんですねー。本当に馬鹿だった。
cat -eで改行コードが見えるのでこのエラーが出たときは確認してみるといいかもしれません。

2012年8月26日日曜日

立石バーガー

これを機にバイクでバーガーめぐり始めようと思います。

住所:東京都葛飾区堀切3丁目17−15‎

立石バーガー食べてきました。
マジで店が暗くて開いているかどうがわからんかった。。。




営業中が出てれば開いている。



入りづらい方は外からでも買えます。インターフォン押すと中からバーガーを出してくれます。



色んな種類あるよ


このガソリンスタンドの向かい側。このガソリンスタンドはタイヤ専門店でガソリンは売ってません。



立石バーガー!100円!


Amebaピグ…

2012年5月26日土曜日

ブログのタイトルが変わりました

もう新卒じゃないし、いつまでも甘えてたらだめですよね。

Network is unreachableはついさっき発生したエラーなのでなんの考えもありません。

質問にも応じません。

2012年4月27日金曜日

回線遅延やパケットロスをシュミレートする方法

回線遅延(帯域)を考慮しない負荷試験なんて意味あるの?って思い使ってみました。
負荷試験はLAN内で行う事が殆どだと思いますが実際はインターネット経由でユーザからのアクセスがあり、それぞれ回線速度もバラバラのはずです。

この回線速度の違いはシステムにどのような影響を与えるかというと1アクセスに対して1プロセスが長時間専有されることでシステムリソースを消費するということです。

これらを考慮せずに安易にKeepAliveを有効にしてWebサーバを高速化しよう!なんてしてしまうと高負荷になり返ってレスポンスが遅くなったという人も多いと思います。

Linux2.6系(だったはず)からiproute2などが組み込まれてネットワーク系が強化されました。
その一部としてtc(Traffic Control)コマンドがあります。


tcコマンドでできること


・回線遅延
・パケットロス
・パケット入れ替え
・パケットの破損
・etc...

このコマンドはそのサーバに対して適応されるので、遅延速度を大きくしすぎるとSSHがタイムアウトすることもあるので注意してください。
複数NICがある環境が望ましいです。

eth0を100ms遅延させる場合

#tc qdisc add dev eth0 root netem delay 100ms
//Delete Command
#tc qdisc del dev eth0 root netem delay 100ms


qdisc=>'queueing discipline'
kernelがNICから送信する必要がある場合、一旦qdiscに格納されkernelはqdiscからNICドライバーへと引き渡そうとします。
その順番はキューに入った順に引き渡され、NICはできるだけ速くキューを送信しようとします。
それを操作して送信を遅延させてやろうというコマンドです。

別の端末からCurlを実行してみます。
通常の速度は9000msぐらいです。

# curl -o /dev/null -w time_total 10.0.60.24
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 9 0 9 0 0 2572 0 --:--:-- --:--:-- --:--:-- 9000



tcコマンドを実行すると。
綺麗に100ms遅延した結果が得られました。

# curl -o /dev/null -w time_total 10.0.60.24
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 9 0 9 0 0 44 0 --:--:-- --:--:-- --:--:-- 90



遅延をランダムにさせることもできます。100ms〜10msの遅延。

# tc qdisc add dev eth0 root netem delay 100ms 10ms



パケットロスはランダムにパケットをロスさせることができる。
このランダムというところが厄介なのでNICが1つしかない場合はSSHのパケットとHTTPのパケットが混ざってしまい正確な値の計測が難しい。
NICが1つの場合はlossの確率を10%程度まで上げても殆ど変化がみられないと思う。
NICが2つあり、殆どパケットがながれていない場合1%以下から検証することを勧める。


# tc qdisc del dev eth0 root netem loss 0.00003%


delayと組み合わせて使うこともできます。


# tc qdisc add dev eth0 root netem delay 100ms 10ms loss 0.00003%


パケットの破損はパケットの1bitを破壊する事ができる。TCPの場合は輻輳の機能があるので観測しづらいのでPingで試すのが吉。

# tc qdisc del dev eth0 root netem corrupt 10%


tcpdumpを実行しながらPingを打つとwrong data byteが発生して一定の確率で破損しているのが伺える。

# tcpdump -n -p icmp &
# ping 10.0.60.24
PING 10.0.60.24 (10.0.60.24) 56(84) bytes of data.
20:59:15.942681 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 1, length 64
20:59:15.943743 IP 10.0.60.24 > 10.0.74.150: ICMP echo reply, id 47365, seq 1, length 64
64 bytes from 10.0.60.24: icmp_seq=1 ttl=64 time=2.05 ms
20:59:16.942993 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 2, length 64
20:59:16.943303 IP 10.0.60.24 > 10.0.74.150: ICMP echo reply, id 47365, seq 2, length 64
64 bytes from 10.0.60.24: icmp_seq=2 ttl=64 time=0.342 ms
20:59:17.943496 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 3, length 64
20:59:17.943813 IP 10.0.60.24 > 10.0.74.150: ICMP echo reply, id 47365, seq 3, length 64
64 bytes from 10.0.60.24: icmp_seq=3 ttl=64 time=0.347 ms
20:59:18.943501 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 4, length 64
20:59:18.943841 IP 10.0.60.24 > 10.0.74.150: ICMP echo reply, id 47365, seq 4, length 64
64 bytes from 10.0.60.24: icmp_seq=4 ttl=64 time=0.372 ms
20:59:19.943514 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 5, length 64
20:59:19.943854 IP 10.0.60.24 > 10.0.74.150: ICMP echo reply, id 47365, seq 5, length 64
64 bytes from 10.0.60.24: icmp_seq=5 ttl=64 time=0.372 ms
20:59:20.943554 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 6, length 64
20:59:20.943952 IP 10.0.60.24 > 10.0.74.150: ICMP echo reply, id 47365, seq 6, length 64
64 bytes from 10.0.60.24: icmp_seq=6 ttl=64 time=0.431 ms
wrong data byte #45 should be 0x2d but was 0xd
#16 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c d 2e 2f
#48 30 31 32 33 34 35 36 37
20:59:21.943526 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 7, length 64

2012年4月18日水曜日

NHKにお金を払うこと。Webコンテンツにお金を払うこと。

就職して一人暮らしを始めてから真面目に?NHKの料金を払い続けてるのですが去年9月の引越しから引き落としがうまく行かず振込用紙で支払っていました。

3ヶ月ぐらい前からでしょうか、色々と忙しくなり支払うのを忘れて毎月NHKの集金係の人に料金を支払っています。

NHKへの支払うんぬんは置いておき、お金を支払うという事はその対価として何かを得るという事は幼い子供でも知っていることだと思います。
殆どの人はその対価として自身が等価またはそれ以上の価値があると思うからお金を支払うと思うんですよね。

NHKの問題点はいくつかあると思いますが、TVを通じて彼らはコンテンツを配信していますがそのコンテンツに対する対価と見合わないから払わない人、お金の使途が気に入らない人、色々いると思います。
おそらくニュースなどで取り上げられる一部の不真面目人を除いて、NHKの中の人はその対価と見合ったコンテンツを配信するために必死になっていると信じているのですが、その努力が少なくとも僕の目には見えないし、成果もでていないんじゃないかと思っています。

僕はNHKと同様にユーザから金を頂いてサービスを展開している企業に勤めています。
インフラでシステムの安定化という事に取り組んでいるので直接ユーザに触れるようなサービスを開発しているわけではないですが、どうやってシングルポイントを無くすのか、いかにしてダウンタイムを短くするかという事を常に考えて行動してます。

実際にピークタイムになるとサーバの負荷が高くなりユーザのアクセスも相当なものになっていることを実感し、その中にはお金を払って使ってくれているユーザもたくさんいます。
Webサイトだとバーチャルな繋がりでしか無いものが目に見えて負荷が高くなったりログがたくさんでてたりとかで人がいるってよく実感するんですよね。
そいうのを想像するとシステムは絶対落とせないし、ユーザに申し訳ないって気持ちが凄く強くなって、そのためにより高度のテクノロジーを使う必要があったり、そして自分自身成長する必要があるって考えると凄くプレッシャーの掛かる仕事なんですが自分自身の成長が実感できるし、なにより何気なく使ってくれてるユーザ人がいると凄く嬉しんですよね。
当たり前のように使えるサービスを作ることは本当に大変な事なんだけど、そのバックグラウンドの努力って中の人じゃないと見えないんですよ。これはエンジニアだけではなくて、僕達を支えてくれている総務だったり人事だったりも同じなんです。

だから、NHKも実はバックグラウンドで凄く努力をしているのかもしれないんですよ。それを僕は信じてお金を払ってます。
ただユーザが僕達を信じてお金を払ってくれているということを絶対忘れてはいけないし、そのための努力惜しんではいけないんですよね。

集金係にお金を払うのは意味があって、自動引き落としやカード決済だとお金を払うっていう重さが伝わりにくいと僕は思っています。
ユーザがお金を払うってどいう気持ちなんだろうかという事を知るために、毎月数千円手渡しで払っています。別にNHKでなくともいいのですが、数百円だと自分にプレッシャーにならないし、少し財布に痛い料金であるNHKをいつも僕は使っています。


信じるは悪いことじゃないので、好きなWebコンテンツに思い切ってお金を払うのはありかもしれません。

2012年1月23日月曜日

ドワンゴを退職しました

はじめに
1月いっぱいで株式会社ドワンゴを退職することになりました。
20日が最終出社日で2月からは新しい職場でお世話になることになりました。

ドワンゴには2010年4月に新卒として入社しサーバインフラエンジニアとして配属されました。

ドワンゴは企画から開発、インフラまで全てを内製している会社です。
そのため高いクオリティかつスピーディにサービスを提供できる環境にあり開発者自身も驚くべきスピードで成長していきます。
そんな環境に憧れて新卒として入社しました。

入社後は研修として短い期間でサービスを作りそのサービスをリリースすることもでき、辛かったですが優秀な仲間たちと一つの物を作り上げ生放送を行いユーザに触っていただくこともできました。


研修終了後は複数のプロジェクトを担当させて頂き、インフラとして困難なプロジェクトもありましたが私のわがままなどもよく受け入れて頂きメンバーの方には迷惑をかけたと思います。
しかし、その困難を乗り越えていく事で自分自身が大きく成長していくのを実感しより高みへと志が移り変わりチャレンジしてきたつもりです。

311
2011年3月11日に関東大震災が起きました。実はこの地震、私は人生で二回目の大きな地震でした。
一度目の被災は小学二年生の時に起きた阪神大震災です。家も潰れ死に物狂いで公園まで逃げました。
その時人生で初めて死というものを身近に感じ、死という目に見えないものに怯えて過ごしてきました。
しかし、人は慣れるものです。
慣れから傲慢になったり怠けたりすることも何度もあり、いつしかこの経験は忘れるほど記憶から薄れていきました。
その中で3月11日の地震は薄れた記憶を再び呼び覚まし死というものを以前より増して意識するようになり今の自分を見直すきっかけとなりました。

NOの日
昨年亡くなったスティーブ・ジョブズがスタンフォード大でのスピーチを思い出しました。


"No" for too many days in a row, I know I need to change something.


このスピーチを聞いたのは大学生の頃ですが、義務教育から大学と決められたカリキュラムと経験者から示される道筋からNoと判断することは殆どなくそれに対して疑問を抱くことも殆どありませんでした。

社会に入りカリキュラムもなく、目標や将来についても全て自らの責任として時間は進んでいきます。
日々業務をする中で自分自身のやっていることについてNoが続いている事に気づきました。

同じような業界で務めている方はよくお分かりかもしれませんが、この業界の技術は進化も早く成熟も非常に早いのです。
新卒で入社した頃は最新の技術であっても一年も経てばより効率的な技術が生み出され、常にアンテナを張り巡らせている企業はいち早く取り入れ実績を上げていきます。

自分自身で勉強したりするものの、組織としてやっているような所と比べるとなかなかついていくのが難しいのが現状です。
そして検証できた頃には成熟し新しい技術が注目され始めてるという事が多くあり、エンジニアとして挑戦できない事も増え変化の早い業界で自分自身の将来への不安が徐々に募り始め又それが、不満であったのは事実です。

これが私の"No"であったと思っています。

今ある枠組み
新卒で入社し1年半程度で退職する事については、多くの方から貴重なご意見をいただきました。
今ある枠組の中で優秀なエンジニアと切羽琢磨しながらシステムを創り上げるは素晴らしいことだと思います。

表面的な価値観だけに囚われていてはだめで本当に自分は何がやりたいのか、それに本当の価値を見出すことが大切なんじゃないかと思っています。厳しい環境で自分自身の技術を磨きインフラとしてだけではなくサービス提供者の一人としてサービスをユーザに送り届けたい。それが自分自身に今できる最大の価値なんじゃないかと思いました。


最後に
1年半という短い期間でしたが、お世話になった方々には本当に感謝しています。
ドワンゴという会社と仲間がいなければここまで自分は成長出来なかったんじゃないかと思っています。

そして、これまで使っていただいたユーザの方もドワンゴは時より寄り道をすることもありますがユーザとしてどんどん意見を発してよいサービスを作るための手助けをしたいただけたらいいなと思います。

まだまだ未熟者ですがこれからも応援していただけば励みになります。

長文となりましたが、以上です。