【V2V】dd コマンドでデータを丸ごと吸い出して GCP にサーバを移設してみる

こんにちは。
dd コマンドでディスクのデータを丸ごと吸い出して、GCP にサーバ移設を行う方法について検証してみたので備忘録を残しておきます。

前提として、AWS に構築した WEB / DB の仮想サーバ( EC2 )を、GCP に移設してみます。

1. 移設元

事前にデータを吸い出すディスクよりも大きなボリュームを EC2 にアタッチ / マウントしておきます。
あとは dd コマンドで吸い出すだけで OK です。
吸い出したデータは tar.gz で固めておきます。
※ デバイスファイル名は適宜変更してください。

fdisk /dev/xvdf
mkfs -t xfs /dev/xvdf1
mkdir -p /tmp/mnt
mount -t xfs /dev/xvdf1 /tmp/mnt
dd if=/dev/xvda of=/tmp/mnt/disk.raw bs=4M conv=sparse
cd /tmp/mnt
tar --format=oldgnu -Sczf /tmp/mnt/sanuki-source-wd01-compressed-image.tar.gz disk.raw

固めたデータは GCS ( Cloud Storage )にアップロードします。
方法はなんでも大丈夫ですが、gsutil を使うのが一番手っ取り早いかと考えます。
※ バケット名は適宜変更してください。

cd ~
curl https://sdk.cloud.google.com > install.sh
bash install.sh --disable-prompts
./google-cloud-sdk/bin/gcloud init
./google-cloud-sdk/bin/gsutil mb gs://sanuki-v2v-test-bucket01
./google-cloud-sdk/bin/gsutil ls
./google-cloud-sdk/bin/gsutil cp /tmp/mnt/sanuki-source-wd01-compressed-image.tar.gz gs://sanuki-v2v-test-bucket01/

2. 移設先

・Cloud Storage にアップロードしたファイルを元にイメージを作成しておきます。

イメージ > イメージを作成 > ソース : Cloud Storage ファイル > 作成

・作成したイメージから VM を起動します。
※ VM は sanuki-dest-wd01 という名称にしておきます。

VM インスタンス > インスタンスの作成 > ブートディスク : カスタムイメージ から 作成したイメージを選択 > 作成

…が、VM は正常に起動しません。

シリアルコンソールから VM に接続するとレスキューモードになっており、ログを漁ったところ、どうも File System が壊れているようです。

Feb 15 08:41:23 localhost kernel: XFS (sda1): Unmount and run xfs_repair
Feb 15 08:41:23 localhost kernel: XFS (sda1): First 64 bytes of corrupted metada
Feb 15 08:41:23 localhost kernel: ffff96cdf565fe00: 58 41 47 46 00 00 00 01 00 0
Feb 15 08:41:23 localhost kernel: ffff96cdf565fe10: 00 00 00 01 00 00 00 02 00 0
Feb 15 08:41:23 localhost kernel: ffff96cdf565fe20: 00 00 00 01 00 00 00 00 00 0
Feb 15 08:41:23 localhost kernel: ffff96cdf565fe30: 00 00 00 04 00 07 bf 6b 00 0
Feb 15 08:41:23 localhost kernel: XFS (sda1): metadata I/O error: block 0x1bff20
Feb 15 08:41:23 localhost mount[343]: mount: mount /dev/sda1 on /sysroot failed:
Feb 15 08:41:23 localhost systemd[1]: sysroot.mount mount process exited, code=e
Feb 15 08:41:23 localhost systemd[1]: Failed to mount /sysroot.
Feb 15 08:41:23 localhost systemd[1]: Dependency failed for Initrd Root File Sys
Feb 15 08:41:23 localhost systemd[1]: Dependency failed for Reload Configuration
Feb 15 08:41:23 localhost systemd[1]: Job initrd-parse-etc.service/start failed 
Feb 15 08:41:23 localhost systemd[1]: Triggering OnFailure= dependencies of init
Feb 15 08:41:23 localhost systemd[1]: Job initrd-root-fs.target/start failed wit
Feb 15 08:41:23 localhost systemd[1]: Triggering OnFailure= dependencies of init
Feb 15 08:41:23 localhost systemd[1]: Unit sysroot.mount entered failed state

3. 復旧

復旧用 VM を用意して、壊れたブートディスクをセカンダリとしてアタッチしリペアを試みます。

・ディスクだけ残し VM を削除します。

VM インスタンス > sanuki-dest-wd01 > 編集 > ブートディスク : 削除ルール : ディスクを維持 > 保存 > 削除

・リカバリ用の VM を作成して、壊れたディスクをアタッチします。
※ VM は sanuki-recover01 という名称にしておきます。

VM インスタンス > インスタンスの作成 > ブートディスク : 公開イメージ : CentOS7 > 作成

VM インスタンス > sanuki-recover01 > 編集 > 追加ディスク : 既存のディスクを接続 > sanuki-dest-wd01 : 保存 > 保存

・リカバリ用の VM に接続し、File System のリペアを試みます。
先に復旧対象のデバイスファイルを確認しておきます。
今回は /dev/sdb1 が対象になります。

[root@sanuki-recover01 ~]# lsblk
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda      8:0    0   20G  0 disk
tqsda1   8:1    0  200M  0 part /boot/efi
mqsda2   8:2    0 19.8G  0 part /
sdb      8:16   0   30G  0 disk
mqsdb1   8:17   0   30G  0 part
[root@sanuki-recover01 ~]# ls -l /dev/disk/by-id/ | grep "sanuki-dest-wd01"
lrwxrwxrwx. 1 root root  9 Feb 15 11:40 google-sanuki-dest-wd01 -> ../../sdb
lrwxrwxrwx. 1 root root 10 Feb 15 11:40 google-sanuki-dest-wd01-part1 -> ../../sdb1
lrwxrwxrwx. 1 root root  9 Feb 15 11:40 scsi-0Google_PersistentDisk_sanuki-dest-wd01 -> ../../sdb
lrwxrwxrwx. 1 root root 10 Feb 15 11:40 scsi-0Google_PersistentDisk_sanuki-dest-wd01-part1 -> ../../sdb1

いきなり xfs_repair を行うと怒られました。
一度 マウント / アンマウント する必要があるようです。

[root@sanuki-recover01 ~]# xfs_repair /dev/sdb1
Phase 1 - find and verify superblock...
        - reporting progress in intervals of 15 minutes
Phase 2 - using internal log
        - zero log...
ERROR: The filesystem has valuable metadata changes in a log which needs to
be replayed.  Mount the filesystem to replay the log, and unmount it before
re-running xfs_repair.  If you are unable to mount the filesystem, then use
the -L option to destroy the log and attempt a repair.
Note that destroying the log may cause corruption -- please attempt a mount
of the filesystem before doing this.

適当にディレクトリを切ってから マウント → アンマウント → xfs_repair を行います。

mkdir /tmp/mnt
mount /dev/sdb1 /tmp/mnt
umount /dev/sdb1
xfs_repair /dev/sdb1

…正常にリペアできました。

[root@sanuki-recover01 ~]# xfs_repair /dev/sdb1
Phase 1 - find and verify superblock...
        - reporting progress in intervals of 15 minutes
Phase 2 - using internal log
        - zero log...
        - scan filesystem freespace and inode maps...
agi unlinked bucket 29 is 23389 in ag 13 (inode=54549341)
        - 11:45:46: scanning filesystem freespace - 16 of 16 allocation groups done
        - found root inode chunk
Phase 3 - for each AG...
        - scan and clear agi unlinked lists...
        - 11:45:46: scanning agi unlinked lists - 16 of 16 allocation groups done
        - process known inodes and perform inode discovery...
        - agno = 15
        - agno = 0
        - agno = 1
        - agno = 2
        - agno = 3
        - agno = 4
        - agno = 5
        - agno = 6
        - agno = 7
        - agno = 8
        - agno = 9
        - agno = 10
        - agno = 11
        - agno = 12
data fork in ino 50509395 claims free block 6314488
data fork in ino 50509395 claims free block 6314489
        - agno = 13
data fork in ino 54549341 claims free block 6818903
data fork in ino 54549341 claims free block 6818904
data fork in ino 54549341 claims free block 6818937
data fork in ino 54549341 claims free block 6818938
        - agno = 14
        - 11:45:47: process known inodes and inode discovery - 103104 of 103104 inodes done
        - process newly discovered inodes...
        - 11:45:47: process newly discovered inodes - 16 of 16 allocation groups done
Phase 4 - check for duplicate blocks...
        - setting up duplicate extent list...
        - 11:45:47: setting up duplicate extent list - 16 of 16 allocation groups done
        - check for inodes claiming duplicate blocks...
        - agno = 0
        - agno = 1
        - agno = 2
        - agno = 3
        - agno = 4
        - agno = 5
        - agno = 6
        - agno = 7
        - agno = 8
        - agno = 9
        - agno = 10
        - agno = 11
        - agno = 12
        - agno = 13
        - agno = 14
        - agno = 15
        - 11:45:47: check for inodes claiming duplicate blocks - 103104 of 103104 inodes done
Phase 5 - rebuild AG headers and trees...
        - 11:45:47: rebuild AG headers and trees - 16 of 16 allocation groups done
        - reset superblock...
Phase 6 - check inode connectivity...
        - resetting contents of realtime bitmap and summary inodes
        - traversing filesystem ...
        - traversal finished ...
        - moving disconnected inodes to lost+found ...
disconnected inode 54549341, moving to lost+found
Phase 7 - verify and correct link counts...
        - 11:45:47: verify and correct link counts - 16 of 16 allocation groups done
done

・リカバリ用 VM からディスクをデタッチします。

VM インスタンス > sanuki-recover01 > 編集 > 追加ディスク : 既存のディスク > sanuki-dest-wd01 : デタッチ > 保存

・リペアしたディスクからもう一度 VM を起動します。

VM インスタンス > インスタンスの作成 > ブートディスク : 既存のディスク : sanuki-dest-wd01 : 選択 > 作成

コンソールに接続します。
…接続できました。

serialport: Connected to fleet-acumen-286514.asia-northeast1-b.sanuki-dest-wd01 
port 1 (session ID: 99e0fefe92785865dd201bdc6865a89ae461aa77, active connections
: 1).
[   31.822303] APL|18307:18410:transport.c:1112:transport_device_release| INFO: 
detaching interceptors
[   31.838278] APL|18307:18410:tracepoints.c:99:tracepoints_detach| INFO: tracep
oints detached
[   31.847363] APL|18307:18410:syscall_common.c:149:detach_hooks| INFO: detachin
g syscall hooks...
[   31.856628] APL|18307:18410:syscall_common.c:186:detach_hooks| INFO: syscall 
hooks detached
[   31.865252] APL|18307:18410:syscall_common.c:213:syscall_hooks_detach| INFO: 
module_refcount()=1
[   31.874511] APL|18307:18410:transport.c:1117:transport_device_release| INFO: 
interceptors detached
[   32.305021] snapapi_init(modprobe,18440): Snapapi(v.0.8.8) init OK. Session s
ize 13784. Em size 990. Ctl major 245
[   32.351295] device-mapper: uevent: version 1.0.3
[   32.356843] device-mapper: ioctl: 4.37.1-ioctl (2018-04-03) initialised: dm-d
evel@redhat.com
[   32.390383] BIOS EDD facility v0.16 2004-Jun-25, 1 devices found
CentOS Linux 7 (Core)
Kernel 3.10.0-1062.12.1.el7.x86_64 on an x86_64

sanuki-dest-wd01 login: root
Password: 
Last login: Tue Feb 15 07:57:24 on pts/0
[root@sanuki-dest-wd01 ~]#

4. 終わりに

色々と躓きましたが、サーバの移設自体は可能なようです。
移設元が稼働していてデータの差分等が発生するのであれば、適宜 rsync 等でデータを同期してあげればよいですね。
一から移設先のサーバを作ってデータを同期するよりもお手軽かもしれません。

【jq】AWS WAF で Block されたリクエストの一覧を CSV に整形して出力してみる

こんにちは。
AWS WAF により Block されたリクエストの一覧を月一でリスト化する必要がございました。
最初は API を叩いて Sample request を取得し、その後にログ解析を行おうと思ったのですが、どうも、この API には 5000req/3h の制限があるようで断念…。
調べてみると Kinesis Firehose を経由して S3 に JSON 形式で WAF のログを出力できるようです。
ついては出力された S3 のログを引っ張って jq でリスト化すればいいや、となりました。

シェルスクリプト

cron で月末にスクリプトが実行されるよう設定しておけば、あとは放置で OK ですね。

#!/bin/bash

WORK_DIR=""
THIS_YEAR=`date "+%Y"`
THIS_MONTH=`date "+%m"`
S3_BUCKET=""
PROFILE=""
OUTPUTDIR=""
OUTPUT=${OUTPUTDIR}block_requests-`date +'%FT%R'`.csv

# 作業ディレクトリの作成
mkdir -p ${WORK_DIR}/${THIS_YEAR}/${THIS_MONTH}

# S3 からログのダウンロード
aws s3 cp s3://${S3_BUCKET}/${THIS_YEAR}/${THIS_MONTH}/ ${WORK_DIR}/${THIS_YEAR}/${THIS_MONTH} --recursive --profile=${PROFILE}

# csv のフィールド名を出力
echo "Request.ClientIP,TerminatingRuleId,Request.Country,Request.URI,Request.httpVersion,Request.Method,Other" >> ${OUTPUT}

# ログの一覧を取得
SERCH_FILES=`find ${WORK_DIR}/${THIS_YEAR}/${THIS_MONTH} -type f -name aws-waf-logs*`

for SERCH_FILE in ${SERCH_FILES}
do
    # json -> csv の変換 / パース / 出力
    cat ${SERCH_FILE} | jq -r ' select( .action == "BLOCK") | [.httpRequest.clientIp, .terminatingRuleId, .httpRequest.country, .httpRequest.uri, .httpRequest.httpVersion, .httpRequest.httpMethod, "#HeadersName", .httpRequest.headers[].name, "#HeadersValue",.httpRequest.headers[].value, "#RuleGroup", .ruleGroupList[].ruleGroupId, "#RuleMatch", .ruleGroupList[].terminatingRule.ruleId, "#RuleAction", .ruleGroupList[].terminatingRule.action] |@csv' \
    >> ${OUTPUT}
done

jq って便利ですね。

【PHP】Cookie を保存/送信して認証が必要なページをスクレイピングしてみる【curl】

こんにちは。
先日、CakePHP で作られた外部システムからデータを引っ張ってくる必要がありました。
ただ、データ取得用の API 等が用意されているわけでもなかったため、curl で叩いてデータを引っ張ってくることにします。

最初のログインページの認証後に Cookie を維持する必要があったので、その処理を PHP で実装してみます。

コード

PHPには cURL 関数が用意されているのでありがたく使わせて頂きます。

<?php

class PHPCurl {
    
    private $getCookieUrl;
    private $targetUrl;
    private $username;
    private $password;
    private $saveCookieFile;

    /**
     * コンストラクタ
     * 
     * @param string $getCookieUrl Cookie取得用のURL
     * @param string $targetUrl    CurlのターゲットURL
     * @param string $username     ログイン情報(ユーザ名)
     * @param string $password     ログイン情報(パスワード)
     */
    public function __construct($getCookieUrl, $targetUrl, $username, $password){
        $this->getCookieUrl = $getCookieUrl;
        $this->targetUrl = $targetUrl;
        $this->username = $username;
        $this->password = $password;
        $this->saveCookieFile = stream_get_meta_data($fp = tmpfile());
    }

    /**
     * Cookie取得用のメソッド
     */
    public function getCookie(){
        $data = array(
            'data[User][username]' => $this->username,
            'data[User][password]' => $this->password,
        );

        $curl = curl_init($this->getCookieUrl);
        curl_setopt($curl, CURLOPT_POST, TRUE);
        curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data));

        curl_setopt($curl, CURLOPT_COOKIEJAR, $this->saveCookieFile['uri']);
        curl_setopt($curl, CURLOPT_COOKIEFILE, $this->saveCookieFile['uri']);
        curl_exec($curl);
        curl_close($curl);
    }

    /**
     * コンテンツ取得用のメソッド
     * 
     * @return string HTMLコンテンツ
     */
    public function getContent(){
        $curl = curl_init($this->targetUrl);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_COOKIEFILE, $this->saveCookieFile['uri']);
        $result = curl_exec($curl);
        curl_close($curl);

        return $result;
    }
}

$curlInfo = new PHPCurl('https://xxxxxx.xxx/login', 'https://xxxxxx.xxx/target', 'finger', 'ease');

$curlInfo->getCookie();
$content = $curlInfo->getContent();

echo $content;

※ POST の bodyデータ は適宜置き換えてくださいね。
あとは必要なデータをパースするだけです。

おまけ

curl だったら下記 2 行だけなんですよね。

curl -c ./cookie.txt -d "data[User][username]=finger" -d "data[User][password]=ease" "https://xxxxxx.xxx/login"
curl -b ./cookie.txt "https://xxxxxx.xxx/target"

awk で特定の行の値を取得して計算してみる(Linux のモニタリングツールを作る)

Linux のモニタリングツールといえば、dstat、sarなんかが有名だと思いますが、環境によってはツールが入っていないこともしばしば。
というわけで、linux にプリインストールされているコマンドで必要最低限のモニタリングツールを用意してみます。

ログ調査とかテキストの整形とかでお世話になる awk ですが、実は計算が出来るんですよね。
例えば、 cat /proc/meminfo の出力結果から実メモリの使用率を計算してみようと思います。

/proc/meminfo

ちなみに meminfo の内容はこちら。
MemTotal、MemFree、MemAvailable の値を取得できれば、メモリ使用率を求めることができそうですね。
※ 今回はawkの挙動を確認したいので、あえて MemTotal と MemAvailable を取得してみます。

[root@verienv01 ~]# cat /proc/meminfo | head
MemTotal:         498672 kB
MemFree:           77104 kB
MemAvailable:     363416 kB
Buffers:               0 kB
Cached:           261200 kB
SwapCached:            4 kB
Active:           147176 kB
Inactive:         150668 kB
Active(anon):        492 kB
Inactive(anon):    43400 kB

awkでメモリ使用率を求める

awk で行を指定したい場合は「NR」を使えばよくて、1行目と3行目で且つ、スペースで区切った左から2列目の値を取得したいのでこうですね。

[root@verienv01 ~]# cat /proc/meminfo | awk 'NR==3 {print $2} NR==1 {print $2}'
498672
363332

取得した値をワンライナーで変数ava(MemAvailable)と変数total(MemTotal)に入れて、計算まで行う場合はこうです!
[root@verienv01 ~]# cat /proc/meminfo | awk 'NR==3 {ava=$2} NR==1 {total=$2} {per = ava / total}END{print 100 - per * 100}'
27.1136

小数点以下は切り捨てます。
これでバッファキャッシュも考慮したメモリ使用率を出力できましたね。
[root@verienv01 ~]# cat /proc/meminfo | awk 'NR==3 {ava=$2} NR==1 {total=$2} {per = ava / total}END{print 100 - per * 100}' | sed s/\.[0-9,]*$//g
27

モニタリングツール

というわけで、CPU使用率、メモリ使用率、ロードアベレージ、タイムスタンプを出力するシェルスクリプトを用意します。

#!/bin/bash

MEMORY=$(cat /proc/meminfo | awk 'NR==3 {ava=$2} NR==1 {total=$2} {per = ava / total}END{print 100 - per * 100}' | sed s/\.[0-9,]*$//g)
CPU=$(vmstat | awk 'NR==3 {print $13,$14}')
LA=$(uptime | awk '{print $8,$9,$10}')
TIME=$(vmstat -t | awk 'NR==3 {print $18,$19}')

echo "--cpu-- --mem--  --------la--------  --------time--------"
echo " " $CPU "    " $MEMORY "   " $LA " " $TIME

いろいろとツッコミ処があると思いますが、、まぁいいでしょう。
[root@verienv01 ~]# ./monitor.sh
--cpu-- --mem--  --------la--------  --------time--------
  0 0      27     0.00, 0.01, 0.01   2020-12-05 23:56:43

whileでループすれば、モニタリングツールの出来上がり(小並感)
[root@verienv01 ~]# while true; do ./monitor.sh ; sleep 1; done
--cpu-- --mem--  --------la--------  --------time--------
  0 0      27     0.00, 0.01, 0.01   2020-12-06 00:02:42
--cpu-- --mem--  --------la--------  --------time--------
  0 0      27     0.00, 0.01, 0.01   2020-12-06 00:02:43
--cpu-- --mem--  --------la--------  --------time--------
  0 0      27     0.00, 0.01, 0.01   2020-12-06 00:02:44
--cpu-- --mem--  --------la--------  --------time--------
  0 0      27     0.00, 0.01, 0.01   2020-12-06 00:02:45
--cpu-- --mem--  --------la--------  --------time--------
  0 0      27     0.00, 0.01, 0.01   2020-12-06 00:02:46
--cpu-- --mem--  --------la--------  --------time--------
  0 0      27     0.00, 0.01, 0.01   2020-12-06 00:02:48
--cpu-- --mem--  --------la--------  --------time--------
  0 0      27     0.00, 0.01, 0.01   2020-12-06 00:02:49

終わりに

正直 dstat と sar と vmstat でいいですね。

【サーバレス】Lambda + API Gateway + Flask で Web ツールを作ってみる【AWS】

こんにちは。
仕事でサーバレス環境を扱うことがありまして、勉強がてら少し触ってみようと思ったんですね。
先日に SSL/TLS 証明書の整合性チェックツールを Flask で作ったんで、こちらをサーバレス環境で動かしてみます。
https://github.com/keisukesanuki/certificate_verify_flask_lambda

zappa

コードのデプロイ用に zappa というツールがあるそうです。。
下記手順で簡単に Lambda + API Gateway の環境構築とアプリケーションのデプロイが完了するようです。

# 必要なパッケージの導入
yum groupinstall "Development tools" -y
yum install zlib-devel openssl-devel sqlite-devel -y

# pyenvの導入
git clone https://github.com/pyenv/pyenv.git ~/.pyenv
echo 'export PATH="$HOME/.pyenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
source ~/.bash_profile

# pyenv-virtualenvの導入
git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bash_profile
exec $SHELL -l

# 3.6系のpythonを導入
pyenv install 3.6.5
pyenv global 3.6.5

# awscliの導入/設定
pip install -U pip
pip install awscli
aws configure

# ソースの取得
pyenv virtualenv 3.6.5 lambda
git clone https://github.com/keisukesanuki/certificate_verify_flask_lambda.git 
cd certificate_verify_flask_lambda
pyenv local lambda

# モジュールの導入
pip install -U pip
pip install flask
pip install zappa

# lambdaにデプロイ
zappa init
===========================================================================
What do you want to call this environment (default 'dev'): certificateCheck
===========================================================================
zappa deploy

リストファイルを分割して複数のサーバに配布するスクリプト

JMeter での負荷試験時に slave の個数分だけ CSVファイルを分割して、それぞれの slave サーバに scp で転送したかったのです。
そんな背景で取り急ぎ作成したよくわからない何かです。

スクリプトみたいな何か

#!/bin/bash

############################################
# 第一引数に配布先マシンのIPアドレス(9つまで)
# 第二引数に分割して配布するリストファイル
############################################

# ファイルの転送先ディレクトリ
DIR=/var/tmp/dlist.txt
# 接続ユーザ
USER=vagrant
# 接続に使用する秘密鍵
SECRET_KEY=/home/vagrant/.ssh/id_rsa

# 引数の数をチェック
if [ $# != 2 ]; then
    echo "引数の数が不正です"
    exit 1
fi

# 配布先マシンの数量を取得
TARGET_COLUMN=`cat $1 | wc -l`
# リストファイルの行数を取得
LIST_COLUMN=`cat $2 | wc -l`
# 1ターゲット辺りのリスト数を取得
ONE_TARGET_NUM=$[LIST_COLUMN / TARGET_COLUMN]

# 配布先マシンのIPアドレスが9つ以上あるかチェック
if [ $TARGET_COLUMN -gt 9 ]; then
    echo "配布先IPアドレスは9つまでしか設定できません"
    exit 1
fi

# 配布先マシンの数量分だけファイルを分割する
split -l $ONE_TARGET_NUM -a 1 --numeric-suffixes=1 $2 list.

# 分割したファイルを転送する
while read VAL;
do
  NUM=$((NUM+1))
  scp -i $SECRET_KEY ./list.$NUM $USER@$VAL:$DIR

  if [ $? -ne 0 ]; then
    echo "scp コマンドが正常に終了しませんでした"
    exit 1
  fi

  # 分割したファイルを削除
  rm -f ./list.$NUM
done < $1

スクリプトの第一引数に下記のような形で転送先サーバの IP アドレスを記載したファイルを渡せば OK です。
※ 第二引数に分割したいリストファイルを指定してください。
192.168.33.11
192.168.33.12
192.168.33.13
192.168.33.14
192.168.33.15
192.168.33.16

【シェルスクリプト】だいたいのサーバ情報を取得する便利スクリプト【サーバ移設】

取り敢えずこのスクリプトを実行すれば、ある程度のサーバ情報を取得できるよ、ってだけのスクリプトです。

#!/bin/sh

# 情報取得関数
function addinfo(){

	# 情報を出力するファイル名を定義
	OUTPUT=serverinfo-`hostname`.txt
	# 情報内容を出力
	echo "####### $1 #########" >> $OUTPUT
	# コマンド結果を出力
	$2 >> $OUTPUT
	
	return 0
}

# ホストネーム
addinfo hostname "hostname"
# プロセス一覧
addinfo process-list "ps auxwwf"
# Listenポート一覧
addinfo listen-port "sudo netstat -lntp"
# ルートテーブル
addinfo route-table "sudo netstat -rn"
# rpmパッケージ
addinfo rpm-package "sudo rpm -qa | sort"
# 自動起動リスト
addinfo chkconfig "sudo chkconfig --list"
# OSバージョン
addinfo os-version "cat /etc/redhat-release"
# CPU
addinfo cpu-info "cat /proc/cpuinfo"
# メモリ
addinfo memory-info "free -m"
# ディスク
addinfo disk-info "df -hT"
# fstab
addinfo fstab "cat /etc/fstab"
# iptables
addinfo iptables "sudo service iptables status"
# ifconfig
addinfo ifconfig "ifconfig"

【proxy】踏み台経由でデータを同期する【rsync】

こんにちは。
踏み台を経由して rsync でデータ同期する方法を、自分用の備忘録として残しておきます。

↓ 前提として同期先、及び、踏み台に root ユーザで接続できる必要があります。

【AWS】EC2 に root ユーザで接続する【サーバ移設】


# SSH 接続設定
vi ~/.ssh/config
============================================================
# 踏み台サーバ
Host mng-bastion01
    # IP アドレス ( 踏み台サーバ )
    HostName      111.111.111.111
    # 接続ユーザ ( 踏み台サーバ )
    User          root
    # 秘密鍵 ( 踏み台サーバ )
    IdentityFile  ~/.ssh/root_secretkey

# ステージングサーバ
Host stg-web01
    ProxyCommand  ssh -W %h:%p mng-bastion01
    # IP アドレス ( ステージングサーバ )
    HostName      222.222.222.222
    # 接続ユーザ ( ステージングサーバ )
    User          root
    # 秘密鍵 ( ステージングサーバ )
    IdentityFile  ~/.ssh/root_secretkey

# 本番サーバ
Host prod-web01
    ProxyCommand  ssh -W %h:%p mng-bastion01
    # IP アドレス ( 本番サーバ )
    HostName      333.333.333.333
    # 接続ユーザ ( 本番サーバ )
    User          root
    # 秘密鍵 ( 本番サーバ )
    IdentityFile  ~/.ssh/root_secretkey
============================================================
    
# パーミッションを調整
chmod 600 ~/.ssh/config

# 接続確認
ssh mng-bastion01
ssh stg-web01
ssh prod-web01

# /path/to/sync_dir を同期先の /path/to/ 配下に同期 ( ドライラン )
rsync -avzn --bwlimit=6400 -e 'ssh -i ~/.ssh/root_secretkey' /path/to/sync_dir stg-web01:/path/to/
rsync -avzn --bwlimit=6400 -e 'ssh -i ~/.ssh/root_secretkey' /path/to/sync_dir prod-web01:/path/to/

# /path/to/sync_dir を同期先の /path/to/ 配下に同期
rsync -avz --bwlimit=6400 -e 'ssh -i ~/.ssh/root_secretkey' /path/to/sync_dir stg-web01:/path/to/
rsync -avz --bwlimit=6400 -e 'ssh -i ~/.ssh/root_secretkey' /path/to/sync_dir prod-web01:/path/to/


# 同期元の /path/to/sync_dir を /path/to/ 配下に同期 ( ドライラン )
rsync -avzn --bwlimit=6400 -e 'ssh -i ~/.ssh/root_secretkey' stg-web01:/path/to/sync_dir /path/to/
rsync -avzn --bwlimit=6400 -e 'ssh -i ~/.ssh/root_secretkey' prod-web01:/path/to/sync_dir /path/to/

# 同期元の /path/to/sync_dir を/path/to/ 配下に同期
rsync -avz --bwlimit=6400 -e 'ssh -i ~/.ssh/root_secretkey' stg-web01:/path/to/sync_dir /path/to/
rsync -avz --bwlimit=6400 -e 'ssh -i ~/.ssh/root_secretkey' prod-web01:/path/to/sync_dir /path/to/

【AWS】EC2 に root ユーザで接続する【サーバ移設】

こんにちは。
rsync でデータ同期を行う際、一般ユーザを用いてしまうと owner と group が適切に設定されないケースがあるようです。
AWS EC2 ( AmazonLinux ) のデフォルト設定では root ユーザでの接続ができないので、後述のように設定を調整します。

# 設定ファイルをバックアップ
cp -p /etc/ssh/sshd_config /etc/ssh/sshd_config.org
diff /etc/ssh/sshd_config /etc/ssh/sshd_config.org

# sshd 設定ファイルの調整
vi /etc/ssh/sshd_config
======================================
#PermitRootLogin forced-commands-only
PermitRootLogin without-password
======================================
# sshd 設定ファイルの syntax チェック
sshd -t

# sshd 再読み込み
/etc/init.d/sshd reload

# sshd の起動を確認
netstat -lntp | grep sshd

# root ユーザの公開鍵追記
vi /root/.ssh/authorized_keys
=======================================
ssh-rsa xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
=======================================

※ 秘密鍵、公開鍵のキーペアは下記コマンドで作成できます。
ssh-keygen -b 2048 -t rsa -f ./key_name

【bash】アクセスログ集計【チラ裏】

完全にチラ裏ですね。よく忘れるので…

# アクセスの多いIPアドレスの上位10件を表示
tail -n 10000 fingerease.work_access.log | awk '{print $1}' | cut -f2 | cut -d: -f2 | sort -n | uniq -c | sort -rn | head

# 分単位のアクセス数を表示
tail -n 10000 fingerease.work_access.log | awk '{print $4}' | awk -F":" '{print $1" "$2":"$3}' | sort | uniq -c