apache で X-Forwarded-For をログに記録する
記事としてよくありますが、ちょっとハマったので記録として。
<VirtualHost *:80> ServerName hoge.com DocumentRoot "/var/www/html" LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined_x CustomLog "/var/log/httpd/access_hoge.com.log" combined_x ErrorLog "/var/log/httpd/error_hoge.com.log" </VirtualHost>
ELB 配下で使っているため、 %h
は除去しました。
また、 combind_x
としているのは /etc/httpd/httpd.conf
にある LogFormat のデフォルト設定に上書きされてしまうことを回避するためです。
218 # 219 # Load config files from the config directory "/etc/httpd/conf.d". 220 # 221 Include conf.d/*.conf 493 # 494 # The following directives define some format nicknames for use with 495 # a CustomLog directive (see below). 496 # 497 LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
ログは以下のようになります。
52.68.214.11 - - [10/Feb/2016:15:58:36 +0900] "GET /index.html HTTP/1.1" 200 47 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.103 Safari/537.36"
以上です。
ssh で rake spec する時に sudo password が渡せない
追記
serverspec の実行時や、ローカルPCの環境変数に sudo_password を設定すればデフォルトのままで問題ありませんでした。
Sudo password support
If you log into servers as non-root user, Serverspec add "sudo" in front of the command. You can specify sudo password like this.
$ SUDO_PASSWORD=xxxxxxxx rake spec
Or display prompt for sudo password if you run Serverspec like this.
$ ASK_SUDO_PASSWORD=1 rake spec
tutorial を先に読まないとこういうことになりますね。猛省します。
追記ここまで
.ssh/config や /etc/hosts をごにょごにょして、
デフォルトの spec_helper.rb を使って鍵認証でもパスワード認証でも ssh ログインまでできたのですが、sudo できずにエラーで終了してしまいます。
$ rake spec (in /home/vagrant/serverspec) /home/vagrant/.rbenv/versions/2.2.3/bin/ruby -I/home/vagrant/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rspec-support-3.4.0/lib:/home/vagrant/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rspec-core-3.4.1/lib /home/vagrant/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rspec-core-3.4.1/exe/rspec --pattern spec/test-001/\*_spec.rb Package "postgresql-9.3" hoge@test-001's password: Wrong sudo password! Please confirm your password on test-001. Finished in 6.7 seconds (files took 0.37223 seconds to load) 1 example, 0 failures /home/vagrant/.rbenv/versions/2.2.3/bin/ruby -I/home/vagrant/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rspec-support-3.4.0/lib:/home/vagrant/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rspec-core-3.4.1/lib /home/vagrant/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rspec-core-3.4.1/exe/rspec --pattern spec/test-001/\*_spec.rb failed
必要な環境変数が null
なことが原因のようです。
if ENV['ASK_SUDO_PASSWORD'] begin require 'highline/import' rescue LoadError fail "highline is not available. Try Installing it." end set :sudo_password, ask("Enter sudo password:") { |q| q.echo = failse } else set :sudo_password, ENV['SUDO_PASSWORD'] end
対象は ASK_SUDO_PASSWORD
と SUDO_PASSWORD
の両方の様で、
上記 if 文の後に puts ENV['ASK_SUDO_PASSWORD']
と、 puts ENV['SUDO_PASSWORD']
したら結果は null 。
なので、highline
がインストールされているかどうかのチェックもできず落ちていた模様。
(highline が未インストールだったのでパスワード認証の時に、標準入力にパスワード丸見えになってしまった・・)
なので if 文を削って強制的に sudo password を入力させることにしました。
(環境変数を追加するのはちょっと抵抗あるので)
また、ssh が成功した時に set :request_pty, true
と書くように怒られたので、追記しています。
require 'serverspec' require 'net/ssh' set :backend, :ssh set :request_pty, true begin require 'highline/import' rescue LoadError fail "highline is not available. Try installing it." end set :sudo_password, ask("Enter sudo password: ") { |q| q.echo = false } host = ENV['TARGET_HOST'] options = Net::SSH::Config.for(host) options[:user] ||= Etc.getlogin set :host, options[:host_name] || host set :ssh_options, options
これでパスワードでも鍵認証でも実行できました。が、本当にこれでいいんだろうか。。。
apache で elb からのヘルチェックをログに記録しない
apache のバージョン
# httpd -V Server version: Apache/2.2.15 (Unix) Server built: Aug 13 2013 17:29:28 Server's Module Magic Number: 20051115:25 Server loaded: APR 1.3.9, APR-Util 1.3.9 Compiled using: APR 1.3.9, APR-Util 1.3.9 Architecture: 64-bit Server MPM: Prefork threaded: no forked: yes (variable process count) Server compiled with.... -D APACHE_MPM_DIR="server/mpm/prefork" -D APR_HAS_SENDFILE -D APR_HAS_MMAP -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled) -D APR_USE_SYSVSEM_SERIALIZE -D APR_USE_PTHREAD_SERIALIZE -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT -D APR_HAS_OTHER_CHILD -D AP_HAVE_RELIABLE_PIPED_LOGS -D DYNAMIC_MODULE_LIMIT=128 -D HTTPD_ROOT="/etc/httpd" -D SUEXEC_BIN="/usr/sbin/suexec" -D DEFAULT_PIDLOG="run/httpd.pid" -D DEFAULT_SCOREBOARD="logs/apache_runtime_status" -D DEFAULT_LOCKFILE="logs/accept.lock" -D DEFAULT_ERRORLOG="logs/error_log" -D AP_TYPES_CONFIG_FILE="conf/mime.types" -D SERVER_CONFIG_FILE="conf/httpd.conf"
ELB-HealthChecker/1.0 からのアクセスログ
***.***.***.*** - - [11/Dec/2015:14:36:42 +0900] "GET /check.html HTTP/1.1" 200 20 "-" "ELB-HealthChecker/1.0" 373 ***.***.***.***
これをログに記録させないようにします。
config
<VirtualHost *:80> DocumentRoot /var/www/html ServerName hoge.com SetEnvIf Request_URI "^/check.html$" dontlog CustomLog /var/log/httpd/vhost-access.log combined_customized env=!dontlog ErrorLog /var/log/httpd/vhost-error.log </VirtualHost>
CustomLog
に env=!dontlog
が肝ですね。
反映は reload で OK です。
PostgreSQL で UPDATE REPLACE する時にちょっと怖かった
こんな感じのテーブルがあるとします。
select count(*) from table ; count ------ 1000
a
が含まれているレコードが 10 あるとします。
select count(*) from table where column like '%a%'; count ------ 10
replace してみます。
BEGIN; UPDATE table SET column = REPLACE(column, 'a', 'b'); UPDATE 1000
a
にマッチするのは 10 件のはずなのに、全件 UPDATE しています。
select count(*) from table where column like '%a%'; count ------ 0
目的は果たせているようですが、他に影響でていたらいやなので慌てて rollback します。
select count(*) from table where column like '%a%'; count ------ 10
結論としては普通に WHERE 句を指定していないから全件走査するようでした。(そりゃそうか)
BEGIN; UPDATE table SET column = REPLACE(column, 'a', 'b') WHERE column like '%a%'; UPDATE 10
WHERE句なしの時は全カラム走査して、検索条件にマッチすれば更新するという挙動のようです。
UPDATE 1000 と表示されても実際に影響があったのは a
が含まれている行のみでした。
Serverspec のセットアップ (rbenv / bundler)
Serverspec を使うために ruby の環境をセットアップします。 環境は CentOS 7 です。 O'REILLY を参考に進めていきます。
rbenv のインストール
rbenv は ruby のバージョン切替ができるツールです。 以下の手順でセットアップします。
$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv $ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile $ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile $ source ~/.bash_profile $ rbenv --version rbenv 0.4.0-192-g825de5d
インストールできる ruby のバージョン確認
$ rbenv install --list
ruby のインストール
今回は 2.2.3 をインストールします。
$ rbenv install 2.2.3 Downloading ruby-2.2.3.tar.gz... -> https://dqw8nmjcqpjn7.cloudfront.net/df795f2f99860745a416092a4004b016ccf77e8b82dec956b120f18bdc71edce Installing ruby-2.2.3... BUILD FAILED (CentOS Linux 7 using ruby-build 20151028-11-gbd22205) Inspect or clean up the working tree at /tmp/ruby-build.20151119040352.4827 Results logged to /tmp/ruby-build.20151119040352.4827.log Last 10 log lines: The Ruby openssl extension was not compiled. The Ruby readline extension was not compiled. The Ruby zlib extension was not compiled. ERROR: Ruby install aborted due to missing extensions Try running `yum install -y openssl-devel readline-devel zlib-devel` to fetch missing dependencies. Configure options used: --prefix=/home/vagrant/.rbenv/versions/2.2.3 LDFLAGS=-L/home/vagrant/.rbenv/versions/2.2.3/lib CPPFLAGS=-I/home/vagrant/.rbenv/versions/2.2.3/include
エラーになってしまいました。パッケージが足りないようです。
$ sudo yum install -y openssl-devel readline-devel zlib-devel
もう一度インストールします。
$ rbenv install 2.2.3 Downloading ruby-2.2.3.tar.gz... -> https://dqw8nmjcqpjn7.cloudfront.net/df795f2f99860745a416092a4004b016ccf77e8b82dec956b120f18bdc71edce Installing ruby-2.2.3... Installed ruby-2.2.3 to /home/vagrant/.rbenv/versions/2.2.3
できました!
インストールした ruby を local 環境に設定します。
$ rbenv local 2.2.3 $ rbenv local 2.2.3 $ ruby --version ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-linux]
bundler のインストール
Gemfile に記載したパッケージをインストールしてくれる bundler をインストールします。
$ gem install bundler
bundler を使って Serverspec をインストール
serverspec ディレクトリを作成して作業ディレクトリとします。 また、Gemfile を用意します。
$ pwd /home/vagrant/serverspec $ cat Gemfile source 'https://rubygems.org' gem 'serverspec'
インストールします。
$ bundle install Fetching gem metadata from https://rubygems.org/....... Fetching version metadata from https://rubygems.org/.. Resolving dependencies... Installing diff-lcs 1.2.5 Installing multi_json 1.11.2 Installing net-ssh 2.9.2 Installing net-scp 1.2.1 Installing net-telnet 0.1.1 Installing rspec-support 3.4.0 Installing rspec-core 3.4.1 Installing rspec-expectations 3.4.0 Installing rspec-mocks 3.4.0 Installing rspec 3.4.0 Installing rspec-its 1.2.0 Installing sfl 2.2 Installing specinfra 2.44.2 Installing serverspec 2.24.3 Using bundler 1.10.6 Bundle complete! 1 Gemfile dependency, 15 gems now installed. Use `bundle show [gemname]` to see where a bundled gem is installed.
インストールできました。
サンプルの生成
postgresql の構築テストを行いたいので、target host name を test-db としてみます。
$ serverspec-init Select OS type: 1) UN*X 2) Windows Select number: 1 Select a backend type: 1) SSH 2) Exec (local) Select number: 1 Vagrant instance y/n: n Input target host name: test-db + spec/ + spec/test-db/ + spec/test-db/sample_spec.rb + spec/spec_helper.rb + Rakefile + .rspec
spec
の配下にホストごとのディレクトリが生成され、それぞれにテストコードがあるようです。
ホストごとでは大規模になったときに大変とどこかに書いてあった気がします。。
とりあえずはこれで進めてみようと思います。
一旦ここまで。
bash でよく使うやつ
桁指定で表示する
-bash ~$ i=1 -bash ~$ printf "%02d" $i 01-bash ~$
改行させるなら
-bash ~$ printf "%02d\n" $i 01
整数の加算
expr とさらばできる
-bash ~$ i=0 -bash ~$ ((i++)) -bash ~$ echo $i 1
C 言語っぽい for 文がかける
$ for (( i=0; i<3; i++)) do echo $i; done 0 1 2
正規表現でマッチングできる
in 句のように使える
-bash ~$ a=abc -bash ~$ [[ $a =~ c ]] && echo "matched" matched -bash ~$ [[ $a =~ d ]] && echo "matched" -bash ~$
リスト
# リストの作成 -bash ~$ i=("a" "b" "c") # リストの展開 -bash ~$ echo ${i[0]} a -bash ~$ echo ${i[1]} b -bash ~$ echo ${i[2]} c -bash ~$ echo ${i[@]} a b c -bash ~$ echo ${i[*]} a b c # 要素の数 -bash ~$ echo ${#i[@]} 3 # 要素の追加 -bash ~$ i+=("d") -bash ~$ echo ${i[@]} a b c d -bash ~$ echo ${#i[@]} 4
引数を順番に処理する
$ cat shift_test.sh #!/bin/bash echo $1 echo $# shift echo $1 echo $# $ sh shift_test.sh 1 2 1 2 2 1
引数がなくなるまでループする
$ cat shift_test.sh #!/bin/bash for (( i=0; $#>0; )) do echo $1 shift done echo "exit" && exit 0 $ sh shift_test.sh 1 2 3 4 5 1 2 3 4 5 exit
i=0
がないと shift_test.sh: line 3: syntax error: arithmetic expression required
と怒られる
ユーザからの入力があるまでスクリプト実行を待機する
$ cat shift_test.sh #!/bin/bash for (( i=0; $#>0; )) do echo $1 shift if [ $# = 1 ]; then read -p "this is last loop. hit enter key to continue." fi done echo "exit" && exit 0 $ sh shift_test.sh 1 2 3 4 5 1 2 3 4 this is last loop. hit enter key to continue. 5 exit
中断するときは ctrl + c
関数名を表示する
$ cat func_test.sh #!/bin/bash function mytest() { echo ${FUNCNAME} } mytest $ sh func_test.sh mytest
printf で文字列を置換する
$ a=test $ printf '%s\n' $a test
ファイルの行番号を表示する
以下の様な txt を用意して、
$ cat raw.txt nikko nikko ni- anata no heart ni niko niko ni- egao todokeru yazawa niko niko- nikoni- tte yonde love niko
while ループでまわす
$ cat raw.txt | while read line; do printf '%2d %s\n' ${lineno} "${line}"; (( lineno++ )) ; done 1 nikko nikko ni- 2 anata no heart ni 3 niko niko ni- 4 egao todokeru 5 yazawa niko niko- 6 nikoni- tte yonde 7 love niko
実行中のファイルの行番号を表示する
$ cat raw.sh #!/bin/bash echo ${LINENO} echo ${LINENO} echo ${LINENO} echo ${LINENO} function mytest() { echo ${FUNCNAME} ${LINENO} } echo ${LINENO} echo ${LINENO} mytest echo ${LINENO} echo ${LINENO} $ sh raw.sh 3 4 5 6 13 14 mytest 10 18 19
PostgreSQL を暖気する
postgresql は linux においてファイルキャッシュを信用するので、
データファイルを cat
してあげると自然とデータがメモリに乗ります。
メモリ大容量時代が到来していますので、このようなニーズもあるのかなと。
postgresql の再起動後などに以下のようなコマンドを実行することで、全てのデータファイルをメモリに乗せることができます。
find "${PG_DATA}" -name "*" -exec cat {} \;
また、特定のテーブルを除いて暖気したい要求がありましたのでスクリプトを書いてみました。
#!/bin/bash # warming_up_database.sh set -e PG_HOST="host" PG_USER="user" PG_PORT="5432" PG_DATABASE="user_table" PG_DATA="db_cluster_dir" PG_CONN="-U ${PG_USER} -H ${PG_HOST} -p ${PG_PORT} -d ${PG_DATABASE}" warming_up_database_with_exclude_file() { # generate exclude string for (( i=1; $#>0; )) do target=$1 # need to do without password, using .pgpass or pg_hba.conf data_file_name=$(/usr/pgsql-9.3/bin/oid2name ${PG_CONN} -t ${target} -q | awk {'print $1'}) if [ -z "${data_file_name}" ]; then read -p "no datafile -> $1 . if you want continue, hit Enter key." break fi if [ $i = 1 ]; then exclude=("-name ${data_file_name}") else exclude+=(" -o -name ${data_file_name}") fi shift done # warming up ! [ -n "${exclude[*]}" ] && time find ${PG_DATA} ${exclude[@]} -prune -o -print -exec cat {} \; > /dev/null 2>&1 \ || echo "${FUNCNAME} failed." && exit 1 } warming_up_database_all() { time find "${PG_DATA}" -name "*" -exec cat {} \; > /dev/null 2>&1 \ || echo "${FUNCNAME} failed." && exit 1 } print_usage() { echo "Usage:" echo "do all warming up => $0 --all" echo "do warming up with exclude file => $0 --exclude exclude_table_name" exit 1 } case $1 in --help|*) print_usage ;; --exclude) if [ $# -lt 2 ]; then print_usage exit 1 fi shift warming_up_database_with_exclude_file $@ exit 0 ;; --all) warming_up_database_all exit 0 ;; esac