vague memory

うろ覚えを無くしていこうともがき苦しむ人の備忘録

Datadog MonitorからSNS経由でLambda起動

Datadog から SNS(Amazon Simple Notification Service) への通知ができるということで、 Datadog → SNS → Lambda → Slack で通知情報に+αで情報付与をしてみます。

f:id:htnosm:20170218155648p:plain

題材

Lambda で実行可能な物でしたら何でも良いのですが、常々不便を感じていた CloudFront のエラー通知で試してみました。

CloudFront で ErrorRate 上昇時に Datadog から Slack へ通知します。 これは Datadog の通常の機能(Metric Monitor)で実現できます。ですが、CloudFront の Tag は取得していないようで通知メッセージには DistributionId しか出力されません。

f:id:htnosm:20170218155640p:plain

DistributionId で判別するのは中々敷居が高いので CNAME と OriginName を後追いで付与します。

1) Monitor 通知先の作成

通知先として使用する Slack と SNS の設定です。
Datadog の Integration ページの Configuration 記載内容に沿って各種設定を行います。

1-1) Slack

Incoming WebHook を作成します。

Datadog 側への設定に Webhook URL が必要になりますので、Slack の Configure Apps に追加します。

f:id:htnosm:20170218155641p:plain f:id:htnosm:20170218155642p:plain

1-2) SNS

使用する SNS Topic を作成します。

例では dd-alert という名前で作成しました。

f:id:htnosm:20170218155643p:plain

通知先設定の確認

正常に登録できていれば Datadog の Monitor 作成画面で選択可能になります。

f:id:htnosm:20170218155644p:plain

2) Datadog Monitor の作成

Lambdaの関数を起動するトリガーとする Monitor を作成します。
例では 5xx Error Rate のメトリクスを使用しました。 尚、5xx Error Rate 等の未発生のメトリクスは Edit で選択できないので、初回は直接 Source に書く必要があるかもしれません。

通知先として作成した Slack Incoming WebHook と SNS topic の2つを指定します。

f:id:htnosm:20170218155645p:plain

avg(last_15m):max:aws.cloudfront.5xx_error_rate{*} by {distributionid} > 10
5xx Error Rate over {{#is_alert}}{{threshold}}%{{/is_alert}}{{#is_warning}}{{warn_threshold}}%{{/is_warning}}
{{^is_recovery}} @slack-notice @sns-dd-alert {{/is_recovery}}

3) Lamdba Function の作成

アラート通知が発生した際に実行したい関数を作成します。 Slack通知がメインとなるため cloudwatch-alarm-to-slack-python をベースに作成しました。 IAM role へは CloudFrontReadOnlyAccess を付与しています。

f:id:htnosm:20170218155646p:plain

Environment variables に作成した Slack Incoming WebHook と SNS topic を設定します。

f:id:htnosm:20170218155647p:plain

例ではSNSを受け取り、通知された DistributionId を基に CNAME と OriginDomainName を取得します。

実行例

アラート発生した場合に通知される内容の例です。 タイミングにより通知される順序は前後します。

f:id:htnosm:20170218165648p:plain

f:id:htnosm:20170218165647p:plain


今回題材にした CloudFront の名称取得はその内 Datadog 側で対応してくれそうですが、
アラート受けてから別に確認していた情報を付与、実行していた処理を自動実行させる等、 色々と応用が効きそうです。

RDS for PostgreSQLへ CF/ELB/ALB/S3のアクセスログをそのままインポート(したかった)

f:id:htnosm:20170201001606p:plain

S3に出力された CloudFront/ELB/ALB/S3 アクセスログを特に加工せずにRDS PostgreSQLへインポート。。。したかったのですができませんでした。 (極力簡単にインポートし、整形・集計はDB側に任せようと思いました。)

PostgreSQL ベースである Redshift と RDS(PostgreSQL) の違いを確認しました。

\copy コマンドでインポート

\copy コマンドを使用して PostgreSQL DB インスタンス上のテーブルにデータをインポートする

ローカルの実行環境にtsvファイル(未圧縮・要変換)を置いた状態で、psqlから “\copy” を実行します。

# CloudFront
\copy cf_log FROM '〜.tsv'
# ELB
\copy elb_log FROM '〜.tsv'
# ALB
\copy alb_log FROM '〜.tsv'
# S3
\copy s3_log FROM '〜.tsv'
# シェル上から実行する場合
psql -h <host> -p <port> -U <user> -d <db> -c "\copy ..."

Redshift での \copy

syntax errorとなり実行できませんでした。

# \copy cf_log from '〜.tsv'
ERROR:  syntax error at or near "STDIN"
行 1: COPY  cf_log FROM STDIN

Redshift で S3以外からの COPY

マニフェストファイル作成等の事前準備をした上で、S3以外のファイルを対象に COPY が行えるようです。

COPYコマンド

COPYコマンドでS3からのインポートは不可です。そもそもCOPYコマンド自体実行できません。 (\copy を使いなさいとヒントをくれます)

ERROR:  must be superuser to COPY to or from a file
HINT:  Anyone can COPY to stdout or from stdin. psql's \copy command also works for anyone.

COPYはサーバ側、\copyはクライアント側依存になるので RDS では使えないということですね。


Redshift の COPY コマンドはAWS向けに拡張されていますが、RDSでも同様に使えるようになると混乱せずに済むのかなと思いました。

Redshiftへ ELB/ALB/S3のアクセスログをそのままインポート(したかった)

f:id:htnosm:20170201001605p:plain

S3に出力された ELB/ALB/S3 アクセスログを特に加工せずにRedshiftへインポート。。。したかったのですができませんでした。 (極力簡単にインポートし、整形・集計はDB側に任せようと思いました。)

スペース区切りで且つクォートが必要最低限しか付いていないという、Apacheアクセスログに似た形式のため加工が必要でした。 それぞれ書式が微妙に異なりますが、tsv等ログ内で使用されていない区切り文字に変換してしまえばインポート可能です。

アクセスログ形式

ELB

スペース区切り、未圧縮ファイル、ヘッダ無しです。 Request、UserAgent等はダブルクォートで囲まれた状態になります。

ALB

スペース区切り、圧縮(gzip)、ヘッダ無しです。 Request、UserAgent等はダブルクォートで囲まれた状態になります。

S3

スペース区切り、未圧縮ファイル、ヘッダ無しです。 Request、UserAgent等はダブルクォートで囲まれた状態になります。 また、タイムスタンプ部分は角括弧([])で囲まれています。

テーブル作成

各カラムは記号と予約語回避のため _ を使用しています。

ELB

CREATE TABLE elb_log (
 timestamp_    VARCHAR(4096)
,elb_    VARCHAR(4096)
,client_port_    VARCHAR(4096)
,backend_port_    VARCHAR(4096)
,request_processing_time_    VARCHAR(4096)
,backend_processing_time_    VARCHAR(4096)
,response_processing_time_    VARCHAR(4096)
,elb_status_code_    VARCHAR(4096)
,backend_status_code_    VARCHAR(4096)
,received_bytes_    VARCHAR(4096)
,sent_bytes_    VARCHAR(4096)
,request_    VARCHAR(4096)
,user_agent_    VARCHAR(4096)
,ssl_cipher_    VARCHAR(4096)
,ssl_protocol_    VARCHAR(4096)
);

ALB

CREATE TABLE alb_log (
 type_    VARCHAR(4096)
,timestamp_    VARCHAR(4096)
,elb_    VARCHAR(4096)
,client_port_    VARCHAR(4096)
,target_port_    VARCHAR(4096)
,request_processing_time_    VARCHAR(4096)
,target_processing_time_    VARCHAR(4096)
,response_processing_time_    VARCHAR(4096)
,elb_status_code_    VARCHAR(4096)
,target_status_code_    VARCHAR(4096)
,received_bytes_    VARCHAR(4096)
,sent_bytes_    VARCHAR(4096)
,request_    VARCHAR(4096)
,user_agent_    VARCHAR(4096)
,ssl_cipher_    VARCHAR(4096)
,ssl_protocol_    VARCHAR(4096)
,target_group_arn_    VARCHAR(4096)
,trace_id_    VARCHAR(4096)
);

S3

CREATE TABLE s3_log (
 bucket_owner_    VARCHAR(4096)
,bucket_    VARCHAR(4096)
,time_    VARCHAR(4096)
,remote_ip_    VARCHAR(4096)
,requester_    VARCHAR(4096)
,request_id_    VARCHAR(4096)
,operation_    VARCHAR(4096)
,key_    VARCHAR(4096)
,request_uri_    VARCHAR(4096)
,http_status_    VARCHAR(4096)
,error_code_    VARCHAR(4096)
,bytes_sent_    VARCHAR(4096)
,object_size_    VARCHAR(4096)
,total_time_    VARCHAR(4096)
,turn_around_time_    VARCHAR(4096)
,referrer_    VARCHAR(4096)
,user_agent_    VARCHAR(4096)
,version_id_    VARCHAR(4096)
);

インポート

スペース区切りをTAB区切りへ変換したファイルをgzip圧縮し、S3へ格納後にCOPYコマンドで取り込みます。

COPY { elb_log | alb_log | s3_log }
FROM 's3://bucket/key/〜.tsv.gz'
CREDENTIALS 'aws-auth-args'
GZIP
FORMAT CSV
DELIMITER '\t'

変換は様々な言語でツール化されていたりしますが、 今回は gawk で行いました。

Redshiftへ CloudFrontのアクセスログをそのままインポート

f:id:htnosm:20170201001604p:plain

S3に出力されたCloudFrontアクセスログを特に加工せずにRedshiftへインポートします。 (極力簡単にインポートし、整形・集計はDB側に任せようと思いました。)

S3->RedshiftへCOPYコマンドで実現可能です。

ログ形式

CloudFront が Amazon S3 バケットに保存する各ログファイルの名前には、次のファイル名形式が使用されます。

bucket-name.s3.amazonaws.com/optional-prefix/distribution-ID.YYYY-MM-DD-HH.unique-ID.gz

圧縮(gzip)されたtsvファイルで、ヘッダが2行存在します。

  • ヘッダ
#Version: 1.0
#Fields: date time x-edge-location sc-bytes c-ip cs-method cs(Host) cs-uri-stem sc-status cs(Referer) cs(User-Agent) cs-uri-query cs(Cookie) x-edge-result-type x-edge-request-id x-host-header cs-protocol cs-bytes time-taken x-forwarded-for ssl-protocol ssl-cipher x-edge-response-result-type cs-protocol-version

テーブル作成

各カラムは記号と予約語回避のため _ を使用しています。

CREATE TABLE cf_log (
 date_    VARCHAR(4096)
,time_    VARCHAR(4096)
,x_edge_location_    VARCHAR(4096)
,sc_bytes_    VARCHAR(4096)
,c_ip_    VARCHAR(4096)
,cs_method_    VARCHAR(4096)
,cs_Host_    VARCHAR(4096)
,cs_uri_stem_    VARCHAR(4096)
,sc_status_    VARCHAR(4096)
,cs_Referer_    VARCHAR(4096)
,cs_User_Agent_    VARCHAR(4096)
,cs_uri_query_    VARCHAR(4096)
,cs_Cookie_    VARCHAR(4096)
,x_edge_result_type_    VARCHAR(4096)
,x_edge_request_id_    VARCHAR(4096)
,x_host_header_    VARCHAR(4096)
,cs_protocol_    VARCHAR(4096)
,cs_bytes_    VARCHAR(4096)
,time_taken_    VARCHAR(4096)
,x_forwarded_for_    VARCHAR(4096)
,ssl_protocol_    VARCHAR(4096)
,ssl_cipher_    VARCHAR(4096)
,x_edge_response_result_type_    VARCHAR(4096)
,cs_protocol_version_    VARCHAR(4096)
);

インポート(COPY)

gzip、TAB区切り、ヘッダ2行を指定して実行します。

COPY cf_log
FROM 's3://bucket-name.s3.amazonaws.com/optional-prefix/distribution-ID.YYYY-MM-DD-HH.unique-ID.gz'
CREDENTIALS 'aws-auth-args'
DELIMITER '\t'
GZIP
IGNOREHEADER 2

aws-auth-args’ はIAMロールやアクセスキーを指定します。

認証情報 - Amazon Redshift

ロールベースのアクセスコントロールを指定するには、次の形式で aws-auth-args 文字列を指定します。
aws_iam_role=arn:aws:iam::<aws-account-id>:role/<role-name>’
キーに基づくアクセスコントロールを指定するには、次の形式で aws-auth-args を指定します。
aws_access_key_id=<access-key-id>;aws_secret_access_key=<secret-access-key>’

Mackerel事始め check-plugin ログ監視 仕様変更の影響

2017/02/24 追記

再度仕様変更が入ったようなので追記します。
以下の通り修正されたようです。そのため本記事の内容は一時的な変更となりました。

2017-01-27の告知ブログでお知らせしました通り、アラートの通知先が Slack やメールのときに、その件名が一定以上の長さになる場合は128文字で切り詰める対応を実施していました。 こちらの対象をメール通知の件名のみに変更し、 Slack などは元の仕様どおり、すべて表示されるように変更しています。

追記終わり。


通知メッセージの省略

実際はログ監視そのものではなく通知の仕様変更です。
元々ある程度(1,000 bytes位?)で文字数制限はあったようですが、 128文字制限 となりました。

通知の件名が一定以上の長さになる場合、省略するようにしました

Slack への通知メインで使用していたので、個人的にこの変更は少々悲しい結果となってます。

びふぉー

f:id:htnosm:20170129053050p:plain

あふたー

f:id:htnosm:20170129053051p:plain

変更前は通知内容(Slack)で内容を把握できたのですが、詳細を確認するため LINK を踏むという一手間が増えてしまいました。

メール通知

メール通知は使用していなかったので通知してみると、returnオプションで返されるログ部分も含めて件名に設定されています。

f:id:htnosm:20170129053052p:plain

この仕様ですと確かに省略したくなりますね。 メール件名のみログ本文内容を削るという変更だと良かったのですが。。。残念です。

Amazon Inspector CVEルールを試してみる

AWSのセキュリティ評価サービス Amazon Inspector に触れる機会があったので記録しておこうと思います。
CVE(共通脆弱性識別子)ルールパッケージでの実行結果です。

何をどう検査しているのかという細かな情報は公開されていないようでしたので、パッケージ導入状態と実行時間により評価結果が変わるかを調べました。 (結果謎な部分は謎なままです)

評価テンプレートの時間が長いほど、Amazon Inspector は、より詳細かつ包括的なテレメトリーのセットを収集して分析します。 つまり、分析時間が長くなることで、Amazon Inspector は評価ターゲットの動作を細部にわたって確認し、より詳細な結果を提示できるようになります。

評価検証

  • AmazonLinux に対して Common Vulnerabilities and Exposures-1.1 で評価を実行
  • Duration 15min/1h/8h/12h/24h の結果を比較

結果

今回の検証結果は以下のとおりです。

  • コンパイルした置き換えバイナリと同様に標準以外のリポジトリからの導入パッケージは検査されない
    • パッケージの changelog のみで評価を行っているわけではない
  • 今回の検証では実行時間による評価結果の変動は無かった
  • サポートされるOSでも AWSエージェントのインストールは行えてしまう、コンソール上も特にエラー・警告は無い

実行時間が長くなる事により外部パッケージでの導入状態も検査するようになってくれるかなという期待があったのですが、 変動はありませんでした。 せめて誤検知(ソースからの導入等)用に除外条件設定ができるようになると使い勝手が良くなるのではと思いました。



評価実施OS

CentOSも検証しようと思いましたが、AMI立ち上げ時点で検出結果0だったため、パターン検証からは除外しています。 (Findings としては Informational で No potential security issues found の出力となりました)

OS(Amazon Linux)状態パターン

  • a) 初期状態
    • AMIから起動しただけで他に何も手を入れていない状態
  • b) yum upgrade 実施
    • AMIから起動後に yum upgrade でパッケージ最新化
    • yum で Nginx、MySQL5.6 を導入
  • c) 外部リポジトリからパッケージ導入
    • Nginx、MySQL5.7 を公式 rpm から導入
  • d) 外部リポジトリからパッケージ導入 + changelog書き換え
    • Nginx を公式 rpm から導入し、changelog に CVE No を追記

Findings(検出結果)

Duration(実行時間)で選択可能な時間全てで実施しています。

  • Duration別検出数
Duration a b c d
15min 3 (2pkg) 0 9 (1pkg) 9 (1pkg)
1h 3 (2pkg) 0 9 (1pkg) 9 (1pkg)
8h 3 (2pkg) 0 9 (1pkg) 9 (1pkg)
12h 3 (2pkg) 0 9 (1pkg) 9 (1pkg)
24h 3 (2pkg) 0 9 (1pkg) 9 (1pkg)

パターン a 検出結果

f:id:htnosm:20161127172220p:plain

Severity が High で3つの CVE(2つのパッケージ) が検出されました。
opensslとkernelのバージョンを上げなさいという結果です。

パターン b 検出結果

yum でのパッケージ最新化を行った状態では検出結果 0 となりました。
導入しているパッケージが少なく、且つ、最新状態なので当然の結果です。

パターン c 検出結果

f:id:htnosm:20161127172225p:plain

Severity = High で 8つ、 Medium が1つ検出されました。 パッケージは全て nginx です。
通常だと外部リポジトリのパッケージについては検査してくれないようです。

パターン d 検出結果

changelog の CVE No を見て判断しているのかもしれないと思い、試してみました。
Nginx 公式のパッケージの changelog に CVE No を追記しています。 結果、changelog 書き換えで検知結果が変わる事はありませんでした。(パターン c と同じ結果でした)

CVE No が含まれています。

[ec2-user@ip-172-30-0-95 ~]$ rpm -qa | grep nginx
nginx-1.10.1-1.28.amzn1.x86_64
[ec2-user@ip-172-30-0-95 ~]$ rpm -q --changelog nginx | grep CVE
- CVE-2016-0747: Insufficient limits of CNAME resolution in resolver
- CVE-2016-0746: Use-after-free during CNAME response processing in resolver
- CVE-2016-0742: Invalid pointer dereference in resolver
- CVE-2014-3616 nginx: virtual host confusion (#1142573)
- (#1126891) CVE-2014-3556: SMTP STARTTLS plaintext injection flaw
- add patch for CVE-2013-4547
  CVE-2013-2028 stack-based buffer overflow when handling certain chunked
- Add security patch to fix CVE-2011-4315
  • Nginx 公式から導入

CVE No が含まれていません。

[ec2-user@ip-172-30-0-7 ~]$ rpm -qa | grep nginx
nginx-1.11.6-1.el6.ngx.x86_64
[ec2-user@ip-172-30-0-7 ~]$ rpm -q --changelog nginx | head
* 火 11月 15 2016 Konstantin Pavlov <thresh@nginx.com>
- 1.11.6

* 月 10月 10 2016 Andrei Belov <defan@nginx.com>
- 1.11.5

* 火  9月 13 2016 Konstantin Pavlov <thresh@nginx.com>
- 1.11.4.
- njs updated to 0.1.2.
[ec2-user@ip-172-30-0-7 ~]$ rpm -q --changelog nginx | grep -c CVE
0
  • Nginx 公式からソースパッケージを取得し、changelogに CVE No を追加して rebuild

無理矢理 CVE No を追加してみました。この状態で Inspector での検査を行いました。

[ec2-user@ip-172-30-0-248 ~]$ rpm -qa | grep nginx
nginx-1.11.6-1.amzn1.ngx.x86_64
[ec2-user@ip-172-30-0-248 ~]$ rpm -q --changelog nginx | head
* 火  1月 26 2016 Jamie Nguyen <jamielinux@fedoraproject.org> - 1:1.8.1-1
- update to upstream release 1.8.1
- CVE-2016-0747: Insufficient limits of CNAME resolution in resolver
- CVE-2016-0746: Use-after-free during CNAME response processing in resolver
- CVE-2016-0742: Invalid pointer dereference in resolver

* 水  9月 17 2014 Jamie Nguyen <jamielinux@fedoraproject.org> - 1:1.6.2-1
- update to upstream release 1.6.2
- CVE-2014-3616 nginx: virtual host confusion (#1142573)

EC2 EBS縮小 (というより CentOS ディスク縮小) の流れ

AWS EC2(Linux) のディスクサイズ縮小を行う機会があったので、備忘として整理します。 復旧や作り直しと同意になるので極力行いたくない作業です。

流れは以下のようになります。
各 Volume、Snapshot には判別しやすい名称を付けておくと混乱しないと思います。

01. 縮小対象 EC2 インスタンスの Volume(vol-A) から Snapshot(snap-A) を作成
02. Snapshot から Volume(vol-B) を作成
03. 縮小後のサイズを指定して、空の Volume(vol-C) を作成
04. 作業用 EC2 インスタンスを起動
05. 作業用 EC2 インスタンスに Volume(vol-B、vol-C) をアタッチ
06. データコピー
07. 作業用 EC2 インスタンスから Volume(vol-C) をデタッチ
08. Volume(vol-C) から Snapshot(snap-C) を作成
09. Snapshot(snap-C) から AMI を作成
    - マネジメントコンソールでの操作はデフォルトで Virtualization type  が PV 指定になるようなので、 HVM の場合は注意
10. AMI から縮小後サイズの EC2 インスタンスを起動





肝は 05 のデータコピー部分になるかと思いますので、以下、05部分の手順(一例)です。
ファイルシステムによりコマンドが多少違いますし、環境によっても異なるのであくまで例です。
起動に失敗する場合は大抵 fstab と grub の設定部分誤りなので、その辺りに目星を付けて修正すると起動できると思います。

また、SELINUX は無効にしておいた方がトラブルは少ないと思います。(ssh接続不可等が発生する可能性があります)

$ grep '^SELINUX' /etc/selinux/config
SELINUX=disabled
SELINUXTYPE=targeted

環境

ext4 と xfs で 30GB -> 10GB への縮小を行います。
作業用インスタンスのOSは、コマンド有無があるので対象OSと合わせると良いかと思います。 また、Marketplace のAMIだと stop しないと attach/detach が行えないようなので、 Amazon Linux 等の公式AMIを使用するのが良いのかもしれません。

vol-xxxxxxxx : Unable to detach volume 'vol-xxxxxxxx' with Marketplace codes from instance 'i-xxxxxxxx' as the instance is not in the 'stopped' state.

今回は AWS Marketplace にある CentOS 標準の AMI を対象に実施しました。

縮小元インスタンス情報

Apacheは起動後の確認に使用しただけですが、一応載せてます。

ext4

[root@ip-172-30-0-241 /]# cat /etc/redhat-release
CentOS release 6.8 (Final)
[root@ip-172-30-0-241 /]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1       30G  1.1G   27G   4% /
tmpfs           498M     0  498M   0% /dev/shm
[root@ip-172-30-0-241 /]# httpd -v
Server version: Apache/2.2.15 (Unix)
Server built:   Jul 18 2016 15:24:00

xfs

[root@ip-172-30-0-149 /]# cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)
[root@ip-172-30-0-149 /]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1       30G  1.4G   29G   5% /
devtmpfs        478M     0  478M   0% /dev
tmpfs           496M     0  496M   0% /dev/shm
tmpfs           496M   13M  484M   3% /run
tmpfs           496M     0  496M   0% /sys/fs/cgroup
tmpfs           100M     0  100M   0% /run/user/1000
[root@ip-172-30-0-149 /]# httpd -v
Server version: Apache/2.4.6 (CentOS)
Server built:   Jul 18 2016 15:30:14

データコピー手順

ほぼ同様の流れなので特記しない限りは ext4 の実行結果を載せます。

1) アタッチ状態確認

Volume(vol-B、vol-C) がアタッチされている事を確認します。 vol-Bを xvdf、vol-C(空ボリューム)を xvdg としています。

[root@ip-172-30-0-241 /]# lsblk
NAME    MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
xvda    202:0    0  30G  0 disk
└─xvda1 202:1    0  30G  0 part
xvdf    202:80   0  30G  0 disk
└─xvdf1 202:81   0  30G  0 part /
xvdg    202:96   0  10G  0 disk

2) パーティション設定

縮小前(xvdf)の設定に合わせて縮小後(xvdg)のパーティション設定を行います。

[root@ip-172-30-0-241 /]# fdisk /dev/xvdg
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0x714a83d2.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
         switch off the mode (command 'c') and change display units to
         sectors (command 'u').

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-1305, default 1):
Using default value 1
Last cylinder, +cylinders or +size{K,M,G} (1-1305, default 1305):
Using default value 1305

Command (m for help): a
Partition number (1-4): 1

Command (m for help): p

Disk /dev/xvdg: 10.7 GB, 10737418240 bytes
255 heads, 63 sectors/track, 1305 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x714a83d2

    Device Boot      Start         End      Blocks   Id  System
/dev/xvdg1   *           1        1305    10482381   83  Linux

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

縮小前後(xvdf/xvdg)で同様の設定になっている事を確認します。

[root@ip-172-30-0-241 /]# fdisk -l

Disk /dev/xvda: 32.2 GB, 32212254720 bytes
255 heads, 63 sectors/track, 3916 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00057cbb

    Device Boot      Start         End      Blocks   Id  System
/dev/xvda1   *           1        3916    31454246   83  Linux

Disk /dev/xvdf: 32.2 GB, 32212254720 bytes
255 heads, 63 sectors/track, 3916 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00057cbb

    Device Boot      Start         End      Blocks   Id  System
/dev/xvdf1   *           1        3916    31454246   83  Linux

Disk /dev/xvdg: 10.7 GB, 10737418240 bytes
255 heads, 63 sectors/track, 1305 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x714a83d2

    Device Boot      Start         End      Blocks   Id  System
/dev/xvdg1   *           1        1305    10482381   83  Linux

3) マウント

ファイルシステムを作成後、マウントします。

[root@ip-172-30-0-241 /]# mkfs.ext4 /dev/xvdg1
mke2fs 1.41.12 (17-May-2010)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
655360 inodes, 2620595 blocks
131029 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=2684354560
80 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
    32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632

Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 21 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.
[root@ip-172-30-0-241 /]# mkdir -p /mnt/old /mnt/new/boot
[root@ip-172-30-0-241 /]# mount -t ext4 /dev/xvdf1 /mnt/old
[root@ip-172-30-0-241 /]# mount -t ext4 /dev/xvdg1 /mnt/new
[root@ip-172-30-0-241 /]# mount -l
/dev/xvdf1 on / type ext4 (rw)
proc on /proc type proc (rw)
sysfs on /sys type sysfs (rw)
devpts on /dev/pts type devpts (rw,gid=5,mode=620)
tmpfs on /dev/shm type tmpfs (rw,rootcontext="system_u:object_r:tmpfs_t:s0")
none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw)
/dev/xvdf1 on /mnt/old type ext4 (rw)
/dev/xvdg1 on /mnt/new type ext4 (rw)
  • xfs

xfs を扱うためのパッケージをインストールしておきます。

yum install xfsprogs xfsdump
[root@ip-172-30-0-149 /]# mkfs.xfs /dev/xvdg1
meta-data=/dev/xvdg1             isize=256    agcount=4, agsize=655296 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=0        finobt=0
data     =                       bsize=4096   blocks=2621184, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=0
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
[root@ip-172-30-0-149 /]# mkdir -p /mnt/old /mnt/new/boot
[root@ip-172-30-0-149 /]# mount -t xfs /dev/xvdf1 /mnt/old
[root@ip-172-30-0-149 /]# mount -t xfs /dev/xvdg1 /mnt/new
[root@ip-172-30-0-149 /]# mount -l
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime,seclabel)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
devtmpfs on /dev type devtmpfs (rw,nosuid,seclabel,size=489108k,nr_inodes=122277,mode=755)
securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,seclabel)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,seclabel,gid=5,mode=620,ptmxmode=000)
tmpfs on /run type tmpfs (rw,nosuid,nodev,seclabel,mode=755)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,seclabel,mode=755)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
pstore on /sys/fs/pstore type pstore (rw,nosuid,nodev,noexec,relatime)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/net_cls type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct,cpu)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
configfs on /sys/kernel/config type configfs (rw,relatime)
/dev/xvdf1 on / type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
rpc_pipefs on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw,relatime)
selinuxfs on /sys/fs/selinux type selinuxfs (rw,relatime)
systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=27,pgrp=1,timeout=300,minproto=5,maxproto=5,direct)
debugfs on /sys/kernel/debug type debugfs (rw,relatime)
hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime,seclabel)
mqueue on /dev/mqueue type mqueue (rw,relatime,seclabel)
nfsd on /proc/fs/nfsd type nfsd (rw,relatime)
tmpfs on /run/user/1000 type tmpfs (rw,nosuid,nodev,relatime,seclabel,size=101536k,mode=700,uid=1000,gid=1000)
/dev/xvdf1 on /mnt/old type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
/dev/xvdg1 on /mnt/new type xfs (rw,relatime,seclabel,attr2,inode64,noquota)

その他にラベル付与やスワップ領域作成等が必要な場合は実施しておきます。

### ext4
# ラベル
e2label /dev/xvdg1 /
blkid
# スワップ
mkswap /dev/xvdg2

### xfs
# ラベル
xfs_admin -L "/boot" /dev/xvdg1
xfs_admin -L "/" /dev/xvdg3
blkid
# スワップ
mkswap /dev/xvdg2

4) ファイルコピー

容量により時間が掛かるのでバックグラウンド実行しておきます。複数パーティションが対象となる場合は、それぞれ実行します。

cd /mnt/old/
( LANG=C date; nohup rsync -avxH \
  --exclude ""proc/*"" \
  --exclude ""sys/*"" \
  --exclude ""dev/*"" \
  /mnt/old/ /mnt/new/; date \
) > /tmp/disk-sync.log 2>&1 < /dev/null &
  • xfs
cd /mnt/old/
( LANG=C date; nohup xfsdump -J - /mnt/old \
  | xfsrestore -J -p 60 - /mnt/new ; date \
) > /tmp/disk-sync.log 2>&1 < /dev/null &

5) grubインストール

chroot

OS起動時に作成されるディレクトリ群をマウントした後、 /mnt/new/ に対して chroot します。 (chroot した事を確認するためにログファイルコピーを行っていますが、必須ではありません。)

cp -ip /tmp/disk-sync.log /mnt/new/var/log/
gzip /mnt/new/var/log/disk-sync.log
ls -l /mnt/new/var/log/disk-sync.log*

mount -t proc /proc /mnt/new/proc
mount -t sysfs /sys /mnt/new/sys
mount --bind /dev /mnt/new/dev
chroot /mnt/new/
ls -l /var/log/disk-sync.log.gz

grub

[root@ip-172-30-0-241 /]# grub
Probing devices to guess BIOS drives. This may take a long time.


    GNU GRUB  version 0.97  (640K lower / 3072K upper memory)

 [ Minimal BASH-like line editing is supported.  For the first word, TAB
   lists possible command completions.  Anywhere else TAB lists the possible
   completions of a device/filename.]
grub> device (hd0) /dev/xvdg
device (hd0) /dev/xvdg
grub> root (hd0,0)
root (hd0,0)
 Filesystem type is ext2fs, partition type 0x83
grub> setup (hd0)
setup (hd0)
 Checking if "/boot/grub/stage1" exists... yes
 Checking if "/boot/grub/stage2" exists... yes
 Checking if "/boot/grub/e2fs_stage1_5" exists... yes
 Running "embed /boot/grub/e2fs_stage1_5 (hd0)"...  27 sectors are embedded.
succeeded
 Running "install /boot/grub/stage1 (hd0) (hd0)1+27 p (hd0,0)/boot/grub/stage2 /boot/grub/grub.conf"... succeeded
Done.
grub> quit
quit
  • xfs
[root@ip-172-30-0-149 /]# grub2-mkconfig -o /boot/grub2/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-3.10.0-327.36.3.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-327.36.3.el7.x86_64.img
Found linux image: /boot/vmlinuz-3.10.0-327.10.1.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-327.10.1.el7.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-f32e0af35637b5dfcbedcb0a1de8dca1
Found initrd image: /boot/initramfs-0-rescue-f32e0af35637b5dfcbedcb0a1de8dca1.img
done
[root@ip-172-30-0-149 /]# grub2-install /dev/xvdg
Installing for i386-pc platform.
Installation finished. No error reported.

6) fstab/grub.conf 書き換え

fstab 、grub.conf に UUID 指定がある場合は、書き換えを行います。 (CentOS6 には grub-mkconfig が無いようなので grub.conf は直接書き換えています。)

[root@ip-172-30-0-241 /]# blkid
/dev/xvda1: UUID="cdbab22a-45d6-4cce-95a3-681f42187a46" TYPE="ext4"
/dev/xvdg1: UUID="67a96f57-8e2a-4d6f-b47d-2128b558cc58" TYPE="ext4"
[root@ip-172-30-0-241 /]# cp -ip /etc/fstab /etc/fstab.org
[root@ip-172-30-0-241 /]# vi /etc/fstab
[root@ip-172-30-0-241 /]# diff /etc/fstab.org /etc/fstab
9c9
< UUID=cdbab22a-45d6-4cce-95a3-681f42187a46 /                       xfs     defaults        0 0
---
> UUID=67a96f57-8e2a-4d6f-b47d-2128b558cc58 /                       xfs     defaults        0 0
[root@ip-172-30-0-241 /]# cp -ip /boot/grub/grub.conf /boot/grub/grub.conf.org
[root@ip-172-30-0-241 /]# vi /boot/grub/grub.conf
[root@ip-172-30-0-241 /]# diff /boot/grub/grub.conf.org /boot/grub/grub.conf
17c17
<    kernel /boot/vmlinuz-2.6.32-573.18.1.el6.x86_64 ro root=UUID=cdbab22a-45d6-4cce-95a3-681f42187a46 rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD console=ttyS0,115200 crashkernel=auto SYSFONT=latarcyrheb-sun16  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM
---
>    kernel /boot/vmlinuz-2.6.32-573.18.1.el6.x86_64 ro root=UUID=67a96f57-8e2a-4d6f-b47d-2128b558cc58 rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD console=ttyS0,115200 crashkernel=auto SYSFONT=latarcyrheb-sun16  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM
  • xfs

UUID指定部分を書き換えます。 CentOS7 では grub2 が導入済みのようなので /etc/grub/ ではなく、 /etc/grub2/ が使用されます。

[root@ip-172-30-0-149 /]# blkid | grep xvdg
/dev/xvdg1: UUID="5a413a36-b3cd-4902-b18f-3887282d32b7" TYPE="xfs"
[root@ip-172-30-0-149 /]# cp -ip /etc/fstab /etc/fstab.org
[root@ip-172-30-0-149 /]# vi /etc/fstab
[root@ip-172-30-0-149 /]# diff /etc/fstab.org /etc/fstab
9c9
< UUID=ef6ba050-6cdc-416a-9380-c14304d0d206 /                       xfs     defaults        0 0
---
> UUID=5a413a36-b3cd-4902-b18f-3887282d32b7 /                       xfs     defaults        0 0

7) アンマウント

# chrootを終了
[root@ip-172-30-0-241 /]# exit
exit
# アンマウント
[root@ip-172-30-0-241 old]# cd /
[root@ip-172-30-0-241 /]# umount /mnt/old/
[root@ip-172-30-0-241 /]# umount /mnt/new/proc /mnt/new/sys /mnt/new/dev
[root@ip-172-30-0-241 /]# umount /mnt/new/
[root@ip-172-30-0-241 /]# mount -l | grep "old\|new"

ディスク内容の移行が完了したら、 作業用インスタンスから Volume をデタッチして後続作業を行います。