【AWS】CentOS6.xをEC2へ持っていってしんどかった話

はじめに

どうも皆さんおはこんばんクリスマス。
アイスタイルで爆弾処理インフラまわりを担当しております sugimotorです。

弊社では主にサーバOSとしてCentOS 6~7を多く利用していますが、
今回はやんごとなき事情によりAWS EC2へオンプレのCentOS6.x環境をマイグレーションを行いドツボにはまったお話(主にCodedeployAgent,ElasticFileSystem)をします。

CodeDeploy agentが動かない

今回はEC2へアプリケーションのデプロイにAWS CodeDeployを導入しました。
この際にCentOS6.X環境だとruby 1.8系がOSデフォのrubyバージョンなので、
CodeDeployAgentがサポートしているrubyバージョンが2以上を使うため、rbenvを用いて起動させることにしたのですが、
OS再起動後にCodeDeploy agentが起動されないという事象がありました。
これが立ち上がらないと、AutoScaleのインスタンス起動時にコードがデプロイされず。
ひたすら失敗ループを繰り返すという事になります。

・原因其1
まず、手動でrbenv経由でのCodeDeploy Agent起動を試してみると、下記のエラーが出ました。

[root@hogehoge~]# bash /root/.rbenv/libexec/rbenv-exec ruby /opt/codedeploy-agent/bin/codedeploy-agent start
/root/.rbenv/libexec/rbenv-exec: line 24: rbenv-version-name: コマンドが見つかりません

・回避方法
エラー内容を見てみると、どうやらrbenv-version-nameのコマンド形式がどうやらまずいというのは分かったので、
rbenv-execの内容を修正し無事起動が行えました。

[root@hogehoge ~]# diff -u /root/.rbenv/libexec/rbenv-exec.bkup /root/.rbenv/libexec/rbenv-exec
--- /root/.rbenv/libexec/rbenv-exec.bkup      2018-10-20 18:41:36.804054472 +0900
+++ /root/.rbenv/libexec/rbenv-exec     2018-10-20 18:41:57.414082893 +0900
@@ -21,7 +21,7 @@
   exec rbenv-shims --short
 fi

-RBENV_VERSION="$(rbenv-version-name)"
+RBENV_VERSION="$(rbenv version-name)"
 RBENV_COMMAND="$1"

 if [ -z "$RBENV_COMMAND" ]; then
@@ -30,11 +30,11 @@
 fi

 export RBENV_VERSION
-RBENV_COMMAND_PATH="$(rbenv-which "$RBENV_COMMAND")"
+RBENV_COMMAND_PATH="$(rbenv which "$RBENV_COMMAND")"
 RBENV_BIN_PATH="${RBENV_COMMAND_PATH%/*}"

 OLDIFS="$IFS"
-IFS=$'\n' scripts=(`rbenv-hooks exec`)
+IFS=$'\n' scripts=(`rbenv hooks exec`)
 IFS="$OLDIFS"
 for script in "${scripts[@]}"; do
   source "$script"

・原因其2
codedeploy-agentの起動時にCodeDeployユーザを指定していたのですが、
このユーザ指定を行っている場合にOS起動時にCodeDeploy Agentが起動されない事があります。

[root@hogehoge ~]# cat /etc/init.d/codedeploy-agent
#!/bin/bash

# Init file for codedeploy-agent
#
# chkconfig: 2345 98 02
# description: codedeploy-agent processes the deployments created by AWS CodeDeploy and installs \
# the deployment artifacts on to this instance.

### BEGIN INIT INFO
# Provides:          codedeploy-agent
# Required-Start:    $all
# Required-Stop:     $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: AWS CodeDeploy Host Agent
# Description:       codedeploy-agent processes the deployments created by AWS CodeDeploy and installs
#                    the deployment artifacts on to this instance.
### END INIT INFO

COMMAND=$1
RETVAL=0
[ -f /etc/profile ] && [ "`stat --format '%U %G' /etc/profile`" == "root root" ] && source /etc/profile

prog="codedeploy-agent"
# Modify the following CODEDEPLOY_USER variable to run the codedeploy process as a non-root user
# Note: You also need to chown /opt/codedeploy /var/log/aws
CODEDEPLOY_USER="hogehoge"  ←この部分

OS起動後CodeDeployagentのエラー

sudo: sudo を実行するには tty がなければいけません。

これは単純にsudoへ起動ユーザのrequirettyを無視させる事で回避しました。

[root@hogehoge ~]# visudo 
Defaults:hogehoge    !requiretty

EFSマウントヘルパーが入らない。

今回、マイグレーションを行ったCentOS6.x系サーバにてEFSを利用し画像ファイルを置く構成をとりました。
EFSをマウントする手段として
1、AWSのEFSマウントヘルパーを使う。
2、通常のNFSマウントを使う

という選択肢があります。
今回はまずパフォーマンス重視の1でやろうとしたときに、Amazone推奨の方法で入れてみたのですが、

[root@hogehoge efs-utils]# sudo yum -y install ./build/amazon-efs-utils*rpm
読み込んだプラグイン:fastestmirror, refresh-packagekit
インストール処理の設定をしています
./build/amazon-efs-utils-1.4-1.el6.noarch.rpm を調べています: amazon-efs-utils-1.4-1.el6.noarch
./build/amazon-efs-utils-1.4-1.el6.noarch.rpm をインストール済みとして設定しています
Loading mirror speeds from cached hostfile
 * base: ftp.riken.jp
 * extras: ftp.riken.jp
 * updates: ftp.riken.jp
依存性の解決をしています
--> トランザクションの確認を実行しています。
---> Package amazon-efs-utils.noarch 0:1.4-1.el6 will be インストール
--> 依存性の処理をしています: stunnel >= 4.56 のパッケージ: amazon-efs-utils-1.4-1.el6.noarch
--> 依存性解決を終了しました。
エラー: パッケージ: amazon-efs-utils-1.4-1.el6.noarch (/amazon-efs-utils-1.4-1.el6.noarch)
             要求: stunnel >= 4.56
            利用可能: stunnel-4.29-7.el6.x86_64 (base)
                stunnel = 4.29-7.el6
 問題を回避するために --skip-broken を用いることができません
 これらを試行できます: rpm -Va --nofiles --nodigest

このように関連パッケージとして、stunnelのバージョンが4.56以上ではないと入らない且つ、
amazon-efs-utilsがrpmパッケージのみしか配布されておらず、手動でstunnelをビルドしてもrpm側で認識してくれない感じです。また、EFSマウントヘルパーの説明ページを見ると、

とあるようにどうやらCentOS6.x 系では使えなさそうだという事が判明したので、
しぶしぶ通常のNFSマウントで利用を行いました。

EFSのパフォーマンスが出ない。

EFSマウントヘルパーが使えない都合上のNFSマウントでEFSをEC2(CentOS6系)へマウントしたのですが、
rsync経由でEFSへの大量のファイル同期を行うとロードアベレージが急上昇してしまいKernel Blockingが発生してしまうという事象が発生しました。

・topコマンドで確認した際のOS状況

top - 13:54:12 up 21:50,  5 users,  load average: 23.99, 23.42, 17.78

・/var/log/messagesに吐かれたdump

Oct 19 13:37:58 localhost kernel: INFO: task rsync:9814 blocked for more than 120 seconds.
Oct 19 13:37:58 localhost kernel:      Not tainted 2.6.32-504.12.2.el6.x86_64 #1
Oct 19 13:37:58 localhost kernel: "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
Oct 19 13:37:58 localhost kernel: rsync         D 0000000000000000     0  9814   9807 0x00000080
Oct 19 13:37:58 localhost kernel: ffff8800c00d1c78 0000000000000082 ffff8800c00d1bc8 ffffffffa01aa36e
Oct 19 13:37:58 localhost kernel: ffff8800c00d1bf8 ffffffffa01aac10 ffff8800c16bd800 ffff8800c00d1c28
Oct 19 13:37:58 localhost kernel: ffff8800c16bd8b0 ffff88006e16b660 ffff88008e5e9098 ffff8800c00d1fd8
Oct 19 13:37:58 localhost kernel: Call Trace:

更に調べていくと今回マイグレーションを行ったOSのバージョンは2.6.32-504系Kernel(CentOS6 .6)を利用しており、この場合NFSのBugを踏んでいる可能性があるとの情報がありました。
https://forums.aws.amazon.com/thread.jspa?threadID=252851

というわけで

[root@hogehoge ~]# yum update -y

OSアップデートを行った後はOS側は安定して動くようになりました。

結論

どちらの事象も紐解いていくと、CentOS6.x系のSysVinitの問題であったり、
2.6系Kernelの問題が起因していることでした。根本対策としてはsystemdを利用していたり、
Kernelが3以上のCentOS7.x系やAmazone Linux2での利用を推奨かとは思うのですが、
今回の様なやんごとなき事情によるCentOS6環境下で移行をしなければならないシチュエーションでの参考にしていただけると幸いです。(最低限OSのマイナーアップデートはやっておいたほうが良い)

爆弾処理係 自ら爆弾を落とすこともしばしば