ELBにSSL証明書アップロード時のエラー対応方法の備忘録【cloudpack大阪ブログ】

1. エラーが出たらここのopensslコマンドで証明書と秘密鍵のmodule項目が一致しているか調べる。


2. module項目が一致していてもエラーの場合は、これの可能性があるので、CLIでアップロードする。

aws iam upload-server-certificate --server-certificate-name my-server-cert --certificate-body file://my-certificate.pem --private-key file://my-private-key.pem --certificate-chain file://my-certificate-chain.pem

運用でSSHログインをしないための設計ポイント(ログ取得編)【cloudpack大阪ブログ】

こんにちは。村主です。

今回の趣旨

前々回(↓)の「内部の見える化のための、ログ系の情報取得」を実装する。

muranonushi.hatenablog.jp

リソース系の情報をCloudWatch LogsにPutし、ElasticSearchService + Kibanaで可視化してみよう。

僕がお粗末な記事を書くより、非常に優秀な記事があるのでそちらをご紹介します。

2. CloudWatch logsからElasticSearchServiceにストリームする

以下URLの「CloudWatch Logsを連携させる」を参照ください。

[新機能]Amazon Elasticsearch Serviceがリリースされました! | Developers.IO

運用でSSHログインをしないための設計ポイント(リソース取得編)【cloudpack大阪ブログ】

こんにちは。村主です。

前回(↓)の記事の反響が多かったので、少し掘りげて技術的なところを書きます。

muranonushi.hatenablog.jp

今回の趣旨

前回の「内部の見える化のための、リソース系の情報取得」を実装する。

リソース系の情報をCloudWatchにPutしてみよう

1. EC2作成

EC2作成手順はあちこちにあるのでGoogle先生に聞いてください。
注意点は、EC2作成時にIAMロールを付与してください。

2. IAMロール割り当て

EC2作成時に割り当てるIAMロールのポリシーは以下でOKです。

IAMロールを割り当ててないEC2で行う場合は、IAMを発行の上で
アクセスキー・シークレットキーを発行し、ポリシー付与などの対応ください。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1449132764000",
            "Effect": "Allow",
            "Action": [
                "cloudwatch:PutMetricAlarm",
                "cloudwatch:PutMetricData"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}
3. サンプルスクリプトの実行

cloudwatchへ送信するためのサンプルスクリプトを用意しました。
サンプルスクリプトに以下の引数を渡すことで動きます。

このスクリプトcronで5分置きなどで実行すると、
cloudwatchの[カスタムメトリックス]という項目にメトリクスが飛んでいきます。

サンプルスクリプト
#!/bin/sh

# default
INSTANCEID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%S.000Z)
REGION=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's/.$//')

# metrics
while getopts n:m:c: opt
do
   case ${opt} in
    n)
        NAMESPACE=${OPTARG};;
    m)
        METRICNAME=${OPTARG};;
    c)
        COMMAND=$(eval ${OPTARG});;
    *)
  exit 1;;
  esac
done

# put metrics
aws cloudwatch put-metric-data --dimensions InstanceId=$INSTANCEID --timestamp $TIMESTAMP --region $REGION --namespace $NAMESPACE --metric-name $METRICNAME  --value $COMMAND --unit Count
実行例
./metric-put.sh -n process -m process_httpd -c "ps aux|grep [h]ttpd |wc -l"
使い方
オプション 使い方
-n 名前グループを付けてください process
-m メトリックの名前を付けてください process_httpd
-c ここにコマンドを記載ください。数値のみ扱えます。 ps aux | grep [h]ttpd | wc -l
スクリプトの説明
# default awsコマンドを実行するために必要な情報を取得(インスタンスID、タイムスタンプ、リージョン情報)
# option 引数に渡すためのオプション定義
# put metrics awsコマンドでcloudwatchにメトリクス送信

上記はApacheのプロセス数でしたが、もちろん以下のような色々な値を取ることができるので、思いついたものを記載します。
(数値化出来るものはcloudwatchに送信することが可能です。)

その他サンプル
  • sshプロセスの有無
./metric-put.sh -n process -m process_sshd -c "ps aux|grep [s]shd |wc -l"
  • sshログインユーザ数
./metric-put.sh -n sshd -m user_count -c "w -h |wc -l"
  • 特定ファイルの有無(有れば0、無ければ1)
./metric-put.sh -n file -m file_check_index.html -c "test -f /var/www/html/index.html ;echo $?"
  • 特定ディレクトリの容量
./metric-put.sh -n directory -m dir_size_var_www -c "du -s /var/www/ |awk '{print \$1}'"

上記をヒントにシステム毎に必要なメトリクスを取得し、システムの状態を外から見えるようすることで、
SSHログインをしない設計に近づくかと思います。


上記のような内容も、可能な限り汎用性を保ってください。。。
個別要件だけが増えていくのだけは避けるように切に願います。
(汎用性を重点に設計をシンプルにし、システム特有のもののみ変数化するイメージで)


なお、今回はCloudWatchへのメトリクス送信例ですが、システム内部の情報を外出しして見える化出来れば、
muninでもgrafanaでも使いやすいものであれば何でも良いかと思います。


以上、

運用でSSHログインをしなければいけないのは、設計力不足【cloudpack大阪ブログ】

こんなタイトルですが、私もSSHログインしてます。
というか、shell大好きです。

で、何が言いたいかというと、SSHしなくてもいいように設計しましょう。ということ。

運用中にSSHしなければいけない理由

まず、運用中にSSHをしなければいけない理由は以下あたりかと思います。

  1. 設定変更、確認
  2. 障害調査、対応


障害調査の場合は、以下などを行います。

  1. サーバへSSH
  2. リソース状況を確認する
  3. ログを確認する
  4. etc...(システム特有の何か)


上記の作業をする上で最も恐れるべきは「オペミス」です。
そして、調査精度は個人のスキルに依存します。


特にオペミスの場合は、再発防止策とかすごく難しいんですよね。
「経験不足」や「本番と開発環境を間違えていた」とか、「手順を間違えた」とか、、、
どう再発防止しましょうか。。。いっその事ログインしない運用とか。。。

「ログインしなければ問題起きないよね」を考えてみる

という事で「極論、ログインしなければ問題起きないよね」という発想の元、考えてみましょう。というのが今回の趣旨です。
オペミス等の問題も起きずに、素早く且つ確実に情報収集、対応出来たらWin-Winですね。

障害調査

では、障害調査をSSHログインしないで行う方法を考えてみました。
要は、ログインして確認しているものを外出し(見える化)しましょう。ということです。

リソース系 必要な情報をモニタリングツールで収集(cloudwatch/zabbix/Grafana/Graphiteなど)
ログ系 ログ収集基盤 + KVS + 分析ツールでログの見える化
cloudwatch logs + ElasticSearchService (in Kibana)
Fluentd + ElasticSearch + Kibana
etc システム特有のものも上記で収集する


これである程度は外から見えるようになるのでは無いでしょうか。
最近流行りの監視ツール(Mackerel/Datadog)とかでもモニタリング出来ると思います。

ちなみに何でもかんでも取得すると、何を見たらいいか分からなくなり自己満システムになってしまいます。
ポイントは「システムに応じた、必要最小限」です。難しいですが、設計者の腕の見せどころです。

障害対応

次に障害対応ですが、よくあるのは「service httpd stop/start」、、、の前に
「service tomcat stop/start」を打って、、、とか手順や順序を守って作業。などありますよね。
「あ、順番間違えた!」とかは、無いと思いますが、システムが増えてくると手順も増えて資料も増えてレビューして・・・・・・
あれ?資料どこいったっけ?どれが最新?更新漏れてた・・・orz

とかやってられないですよね。


だから、手順はいつも1つ!(コナン風)



インスタンス再起動!!」(しかも、マネジメントコンソール or CLIから!)



OS起動時に順序等を守るように設計・構築しておけば、起動時は正常に立ち上がってくる(はず)

まとめ

上記のように、内部の見える化とともに障害対応手順も簡素化することで、
オペミスや個人スキルへの依存、資料作成・管理等の負荷なども大幅削減出来るのではないでしょうか。


また、上記のような仕組みにしておくことで、場合によっては
「ある障害の場合に、自動的に再起動をかける」などの自動化への一歩にもなるかもしれません。


最終手段としてはSSHすることもあると思いますが、
出来るだけしないように作っておくことが幸せの第一歩と考えてます。


他にこんなアイディアあるよ!という方はコメントくださいー。

PS. 先日リリースされた機能でのアイディア

先日以下の機能がリリースされました。aws.typepad.com

これを使えば、
「cloudwatch => SNS => Lambda => Run command(OS上でshell実行など)」って実行して、
インスタンス再起動」という暴挙に出なくてもよくなるかもしれません。
(run commandで個別要件は取りきれそう)

以上、

ホスト名は付けたら負けなんだぜ?【cloudpack大阪ブログ】

著名な方は言いました。「ホスト名を付けたら負け。SSHしたら負け。」(だったと思う・・)

てことで。今回はホスト名に関することを書きます。


みなさん、ホスト名付けてますかーーーー?!


そう。ホスト名。昔は愛着を込めてよくサーバに名前を付けましたよね。
1台を長く使い続けていたので、ホスト名を付けてました。


時は、クラウド時代。サーバを長く使い続ける事も出来るし、使い捨てる事も出来る。
そんな時代とホスト名はどのように関係があるのか。そんな物語の始まりです。


そもそも、ホスト名はなぜ付けているのでしょう?教えて偉い人。
僕が考えつく理由としては、以下などかな。

  • サーバを識別するため
  • ADなどの制限でユニークにする必要があるため
  • ライセンスの関係でホスト名を固定にする必要があるため


そのホスト名の設定方法は色々あります。

  • SSHして手動でつける
# hostname hogehoge
# vi etc/sysconfig/network

NETWORKING=yes
HOSTNAME=hogehoge
GATEWAY=10.10.10.1
  • Chef / Ansibleでつける
cookbook
playbook
  • cloud init / user dataでつける
#cloud-config
hostname: hogehoge

そして、同じロールで複数構成の場合は、
hogehoge02とか、hogehoge03とかを上記の処理の際にインクリメントするとかしますね。
今のサーバの台数を調べて、最後の数値からインクリメント?
AutoScaleするときは、ホスト名にautoとか入れて1番からインクリメント?
何か少し複雑になってきましたね。


「そのホスト名、本当に必要なの?」


つか、ホスト名って改めて何に使ってるんですかね。

AWSでは、ip-xx-xx-xx-xxというIPアドレスをベースにしたホスト名が自動で割り当てられます。
これでユニーク性は保てます。


サーバの識別は出来ないですが、そもそもSSHしなかったら識別すら必要ないんじゃない?
infrastructure as codeとか推進すると、SSHで手作業することもほぼ無いでしょう。


さらに、今後はコンテナやLambdaが台頭してくると、なおさらSSH不要や、
使い捨て(もはやそう言わないかも)が進みます。
発想の転換が必要ですが、使い捨てベースに考えると色々と考え方や使い方が変わります。


NoSSHについてはまた説明しますが、
AWSのホスト名自動付与にまかせて、ホスト名を明示的に付けなければ
上記のような手順やコードが全くもって不要になります。


全くもって不要になります。


前回IPアドレスの件もそうですが、一つづつ色々なものを引き剥がし、
考え直していくことで、不要な作業の撲滅と共に、シンプルな構成のクラウドネイティブに一歩ずつ近づいていきます。

そして、来たるクラウドネイティブやコンテナ、Lambdaの思想に備えていきましょう。

以上、

AWSでIPアドレスという概念を無くす方法【cloudpack大阪ブログ】

EC2は柔軟だ

EC2は、オンプレミスで作られた設計と同じように構成出来る柔軟性を持っています。
そのため、元々の設計によっては多少の変更は必要ですが、オンプレミス時代の設計でAWS環境を構築することが出来ます。


このようにオンプレミスの設計を持ち込む事でも、AWSへの移行メリットはあるかと思います。
例えば、サーバの調達が早くなる。スペックを柔軟に変えられるので単純に安くなった。夜は止めることでコストダウンが出来た。など。
これらも非常に大きなメリットで、より良いサービス提供が出来るでしょう。



ただ、、、もったいない!!!!!!!!



せっかくクラウドを利用しているので、使いこなさないともったいないです!
使いこなすには発想の転換が必要となりますが、使いこなすことでより低コストでより柔軟な自動化などが図れます。
そろそろ次のステップに移りましょう!!


ということで、今後、もろもろ記載していきたいと思いますが、まずはIPアドレスについて、

IPアドレスなんか無くしちまえ

そう、ミスターマリックのようにハンドパワーで消すことで、よりクラウドっぽく使えるようになります。
なぜIPアドレスを無くしたいかというと、AutoScaleを使ってスケーラブルな構成にしたり、
障害時の復旧などを自動的に行えるようにし、運用負荷を軽減させたいのです。

なので、IPアドレスはアサインするものではなく、
意識しない(DHCPによる自動割当)設計が必要になります。

本題

では、本題に入ります。
以下はよくやる構成かと思います。

よくやる構成

f:id:xwkns157:20151126215711p:plain

これはELB配下になるのでEC2上のApacheはIPベースではなくNameベースのバーチャルホストになっているかと思います。
そのため、以下の感じになります。

Route53 -> ELB A-Alias or CNAME
ELB -> EC2 インスタンスIDで紐付け
EC2 -> RDS DNS Name

上記にはIPアドレスで紐付けられていません。実質的にEC2にはIPアドレスが割り当てられていますが、
IPアドレスで繋げていないので、例えIPアドレスが変わったとしてもサービスは継続されます。
つまり、AutoScaleなどが利用可能になります。


次に、以下のような構成も多いと思います。
これはNothing例です。

Nothing例

f:id:xwkns157:20151126215716p:plain

この状態だと片方のEC2のIPが固定化され、例えば片方のEC2が壊れて復元する場合に、
IPアドレスを引き継ぐ必要があります。

復元時に覚えておいたIPアドレスを手作業で引き継ぐか、手順書に埋め込むか、
コードに埋め込むか。など、まぁやること自体は単純なんですが、

IPアドレスが変わった時など、あちこちの資料を更新しないといけない。とかつらい思いで有りますよね。
言いたいことは「その作業、本当に必要なの?」です。


はじめに設計で何とかしとけば、不要な作業になりえるのです。


では、何とかしてみましょう。done.

オススメ例

f:id:xwkns157:20151126215723p:plain

はい。この構成で、EC2起動時に動的に自分のIPアドレスを調べて
Route53のAレコードを書き換える処理(下記コード)を入れておくだけで
IPアドレスを意識する事無い構成になりました。

費用も100~200円程度で出来ますね。
IPの事考えたり、資料更新したり。。どっちのコストが安いんでしょうね。

また、動的にIPアドレスを取得しますので、
コード内にもIPアドレスが埋め込まれることがなくなりました。

コード例
IP_ADDRESS=`curl -s http://169.254.169.254/latest/meta-data/local-ipv4`
sed -e 's/hogehoge/$IP_ADDRESS/g' /home/ec2-user/template.json > /home/ec2-user/update.json
aws route53 change-resource-record-sets --hosted-zone-id ABCDXYZ --change-batch file:////home/ec2-user/update.json

※template.jsonファイルはレコード内容に応じて別途生成する必要があります。
http://docs.aws.amazon.com/cli/latest/reference/route53/change-resource-record-sets.html


そして、、、、IPアドレスが消えました。


ちっちゃいですが、この辺りに作業がなくなりましたね。

復元時に覚えておいたIPアドレスを手作業で引き継ぐか、手順書に埋め込むか、
コードに埋め込むか。など、まぁやること自体は単純なんですが、

IPアドレスが変わった時など、あちこちの資料を更新しないといけない。とかつらい思いで有りますよね。

このようにして、一つづつ色々なものを引き剥がしていくことで、
不要な作業を撲滅していきましょう。

以上、

【小ネタ】RDS-MySQLのクロスリージョンリードレプリカの昇格時間を計測【cloudpack大阪ブログ】

RDS-MySQLクロスリージョンリードレプリカの昇格時間を計測してみました。

計測方法

  • Masterはバージニア、Replicaはオレゴン
  • MySQLのバージョンは5.6.23
  • 1DB、約6000万レコード
  • 計測開始はオレゴン側で[リードレプリカを昇格]ボタンを押す
  • [SELECT CURTIME()]で時間表示とともに、Insertを発行
  • 昇格前はInsertに失敗するはず
  • 昇格後はInsertに成功するはず
# 昇格前
mysql> SELECT CURTIME();INSERT INTO item () VALUES ();
+-----------+
| CURTIME() |
+-----------+
| 02:50:01  |
+-----------+
1 row in set (0.07 sec)
​
ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement

mysql> SELECT CURTIME();INSERT INTO item () VALUES ();
+-----------+
| CURTIME() |
+-----------+
| 02:51:36  |
+-----------+
1 row in set (0.08 sec)
​
ERROR 2013 (HY000): Lost connection to MySQL server during query

# 昇格のための再起動中
​mysql>
mysql>
mysql> SELECT CURTIME();INSERT INTO item () VALUES ();
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
ERROR 2003 (HY000): Can't connect to MySQL server on 'test-rep3.cuplkakj9btg.us-west-2.rds.amazonaws.com' (111)
ERROR:
Can't connect to the server
​
No connection. Trying to reconnect...
ERROR 2003 (HY000): Can't connect to MySQL server on 'test-rep3.cuplkakj9btg.us-west-2.rds.amazonaws.com' (111)
ERROR:
Can't connect to the server
​
# 昇格後
mysql>
mysql>
mysql> SELECT CURTIME();INSERT INTO item () VALUES ();
No connection. Trying to reconnect...
Connection id:    1
Current database: testdb
​
+-----------+
| CURTIME() |
+-----------+
| 02:51:44  |
+-----------+
1 row in set (0.07 sec)
​
Query OK, 1 row affected (0.09 sec)
​
mysql>
mysql>
mysql> SELECT CURTIME();INSERT INTO item () VALUES ();
+-----------+
| CURTIME() |
+-----------+
| 02:51:47  |
+-----------+
1 row in set (0.08 sec)
​
Query OK, 1 row affected (0.08 sec)
Add Comment

結果

  • 再起動の間、約8秒ほどのサービス断でオレゴンで利用可能となった
  • 1レコードのDBに対しても同じく8秒程度だった
  • データ件数により変わるかもしれないが、大きな違いなさそう?