インフラ屋のAWSはじめた日記─GUIを捨てよ

第5回そろそろサーバを弄りたい

過去の日記を読み返していて、あることに気づいた。

今日までに、俺がAWSでやってきたこと。

オンプレ時代であれば、サーバをラッキングして、電源を入れ、ネットワーク機器をケーブルでつないだ事くらいしかやっていない。サーバに至っては、電源を入れて、SSHで接続して、pingを打っただけ。

クラウドという環境に初めて触れて、すごいことをしている気分だったのに、改めて考えてみると、すごく単純作業しかしていないことに気づいてしまった。でも、今までであれば、必ずデータセンターに行って作業していた事が、手元ですぐに完結するというのはすごい。それは俺がすごいんじゃなくて、AWSがすごい。

とはいえ、俺も何もしていないわけではなくて、ネットワークを作ったり、サーバを立ち上げたりするのをいかに早くできるかというのを反復練習していたわけで、今となってはネットワークを構築して、サーバを起動するくらいなら30分もあれば余裕でできる。

そんな俺が次にやるのは、クラウドっぽいWEB-DB構成を作ること。前回作ったVPCにDBサーバを設置して行くことにする。

ちなみに前回作ったネットワークはこれ

画像

RDSって便利

サーバを起動してDBサーバをつくろうと思ったけれど、AWSにはデータベースのマネージドサービスがあるらしい。

勝手にバックアップをとってくれるわ、レプリケーションをしてくれるわと、インフラエンジニアにとってお仕事を奪われかねないぐらいの機能があるな。でもそれはポジティブに考えると、これを使いこなすことができれば、俺、楽できる、ということだ。

というわけでRDSというサービスを触ってみて、使いこなせるように頑張ってみることにした。

DB Subnetってなに?

さっそくプライベート側のネットワーク(Subnet-2)にRDSを設置しようと思う。

とりあえず、何が必須項目か知るために、なんのオプションも付けずにコマンド投入。

$ aws rds create-db-instance
usage: aws [options] <command> <subcommand> [parameters]
aws: error: argument --db-instance-identifier is required

--db-instance-identifierをつけろと。dentifierと入っているなら、何かしら一意になるようなものをつければよいんだろうな。とりあえず、test-dbとしておく。

$ aws rds create-db-instance  --db-instance-identifier test-db
usage: aws [options] <command> <subcommand> [parameters]
aws: error: argument --allocated-storage is required

まだ足りないパラメータがあるらしい。こんなやりとりを繰り返すこと数回。

$ aws rds create-db-instance  --db-instance-identifier test-db \
--allocated-storage 5 --db-instance-class db.t2.micro \
--engine mysql --master-username root --master-user-password password

結局これだけの必須項目があった。ちなみに--master-user-password はちゃんとしたパスワードにしよう。

起動したようだけれど…、俺は気づいた。どこに起動しているんだこれ??VPCのプライベートなサブネットじゃないぞきっと。とりあえず、消す。

$ aws rds delete-db-instance --db-instance-identifier test-db

まさかこんなにすぐに-db-instance-identifierを使うことになるとは。

A client error (InvalidDBInstanceState) occurred when calling the DeleteDBInstance operation: Instance test-db is currently creating - a final snapshot cannot be taken.

すぐに削除しようとしたせいか、上記のエラーがでたので、Snapshotを取るかどうかみたいな事を言われてしまったので、--skip-final-snapshotをつけてもう1回

$ aws rds delete-db-instance --db-instance-identifier test-db --skip-final-snapshot

今度はうまくいった。

気を取り直してもう1回作る。

$ aws rds create-db-instance  --db-instance-identifier test-db --vpc[TAB]

これできっとVPCのなんかいい感じのパラメータが出てくることだろう。

--vpc-security-group-ids…。違う。違くないけど、違う。そうじゃない。どこのサブネットにつながるのかを指定したいというのに…、諦めて、全部のオプションを見てみることにする。 たぶんそれっぽいのは--db-subnet-group-name これ。けど、db-subnet-groupって何だ。

調べてみると、DB-SubnetGroupというのはデータベースを設置する用のサブネットをグルーピングする方法らしい。なぜSubnetGroupとして複数のSubnetを使うのかというと、RDSのMultiAZという複数のAvailability Zoneにまたがってレプリケーションを作る機能があるので、1つのSubnetを指定してというわけにはいかないんだと思う。

複数のAvailability Zoneを含んだSubnetを束ねて、RDSを起動するときに指定するとMultiAZという機能によって自動的に冗長化させることができる。MultiAZについては後ほど深追いするつもり。

というわけでこのDB Subnet Groupというのを作ってみる。create-db-subnet-groupというコマンドで、既存のSubnetを指定することで作れるようだ。

$ aws rds create-db-subnet-group[TAB]

オプションを見てみると、--subnet-idsというのがある。ここにsubnet-idを指定すれば良さそう。

$ aws ec2 describe-subnets 

で今回対象のsubnetIdを調べておく。プライベートなサブネットを二つ作ったので、その二つをしていけばよいだろう。

AWSとオンプレでの違いは、いろいろあるけれど、このAvailability Zoneが一番の大きな違いなんじゃないかと思う。Availability Zoneの概念がわかれば、だいぶいろいろと便利な機能が使えるようになるから。

$ aws rds create-db-subnet-group --subnet-id subnet-ea00d79d subnet-db06ee82  --

他にも、必須項目があるらしい。--db-subnet-group-nameと--db-subnet-group-descriptionが必須のようなので、それぞれに名前と説明的なものを入れて実行する。

$ aws rds create-db-subnet-group --subnet-ids subnet-ea00d79d subnet-db06ee82  --db-subnet-group-name test-db-subnet --db-subnet-group-description "test db subnet group"
{
    "DBSubnetGroup": {
        "Subnets": [
            {
                "SubnetStatus": "Active",
                "SubnetIdentifier": "subnet-db06ee82",
                "SubnetAvailabilityZone": {
                    "Name": "ap-northeast-1c"
                }
            },
            {
                "SubnetStatus": "Active",
                "SubnetIdentifier": "subnet-ea00d79d",
                "SubnetAvailabilityZone": {
                    "Name": "ap-northeast-1a"
                }
            }
        ],
        "DBSubnetGroupName": "test-db-subnet",
        "VpcId": "vpc-6ac1020f",
        "DBSubnetGroupDescription": "test db subnet group",
        "SubnetGroupStatus": "Complete"
    }
}

なんとか無事にできたらしい。RDSを起動するときにはこのdb-subnet-groupを指定することになるんだろう。

改めてRDSを起動する

DBSubnetGroupを作った所で、改めてRDSを起動する。さっき打ったコマンドに、

$ aws rds create-db-instance  --db-instance-identifier test-db \
--allocated-storage 5 --db-instance-class db.t2.micro \
--engine mysql --master-username root --master-user-password password \
--db-subnet-group-name test-db-subnet

--db-subnet-group-nameオプションを追加して、起動する。今度こそ、想定していた場所にRDSが起動されているはずだ。

$ aws rds describe-db-instances
-略-
"DBSubnetGroup": {
                "Subnets": [
                    {
                        "SubnetStatus": "Active",
                        "SubnetIdentifier": "subnet-db06ee82",
                        "SubnetAvailabilityZone": {
                            "Name": "ap-northeast-1c"
                        }
                    },
                    {
                        "SubnetStatus": "Active",
                        "SubnetIdentifier": "subnet-ea00d79d",
                        "SubnetAvailabilityZone": {
                            "Name": "ap-northeast-1a"
                        }
                    }
                ],
                "DBSubnetGroupName": "test-db-subnet",
                "VpcId": "vpc-6ac1020f",
                "DBSubnetGroupDescription": "test db subnet group",
                "SubnetGroupStatus": "Complete"
            },
-略-
           "AvailabilityZone": "ap-northeast-1a",
-略-

RDSのインスタンスを見てみると、確かにDBSubnetGroupというところに自分が作ったSubnetが書かれていてほっと一安心。

今の状態はこんな感じだろう。

画像

MultiAZってなんだ

MutliAZのAZはAvailability Zoneの事で、RDSを地理的に離れた場所に設置して、冗長化しようという仕組みらしい。Endpointはひとつで、Masterに障害が発生すれば、Slave側に自動的に切り替わり、今度はそっちがMasterになる。冗長化以外の恩恵も結構大きくて、パッチ当てのようなものも、無停止でやってくれる。

他にもいろいろありそうで、RDSの便利さをフルに活用したいのであれば、MultiAZを選択する方が良さそうだ。

踏み台

RDSを起動したのは良いけれど、接続できないのは困ったものだ。

外から接続できないようにしたのはいいのだけれど、一時的にでも接続できないのは辛い。接続するためには、外からアクセスできるようにするのか、踏み台を介してつなぐようにするのかの二択だろう。今回は踏み台のEC2を起動してDBにアクセスするようにする。

踏み台起動

EC2の起動はpublic側のサブネットにして、まずそこにSSHで接続できることを確認する。

画像

ここまでできたら、EC2からRDSに対して接続できるのかを確認してみる。

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|
$ sudo yum install mysql 
$ mysql -h test-db.xxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com -u root -p

つながらない。パスワードが間違っているとかそういった感じではなく、なんかネットワーク的につながっていないような気がする。

また出てきたよSecurity Group

この何故か接続できないというのは、ここでもハマった。たぶんSecurity Groupだろう。そういえば、さっきRDSを起動するときに--vpc-security-group-idsというのを見かけていた。どのVPCに起動するかっていうときに--vpcでタブを連打したら出てきていた。わかってしまえば簡単で、Security Groupを作って設定すればよい。

と思った所で、ひとつ疑問が湧いた。Security Groupってアクセス元に自Security Groupを指定できる。こんな時に、どうするべきなのか悩む。こんな事で悩んでも仕方の無いことなのかもしれないけど、自分のポリシーは決めておきたい。Security Groupはタグのようにインスタンスに付けられる。そこで、Security Groupはどのようにつけるべきなのかを考えてみる。

画像

1つめは上の図のような感じで、データベースにはデータベースのSecurity Group,WebサーバにはWebサーバのSecurity Groupをつけ、DBにはDBのSecurity Groupをつける。その上で、DBのSecurity GroupにはWebサーバからのアクセスをつけるという方法。

画像

もう1つは通信の内容でSecurity Groupを作る方法。MySQLの通信をしたいのであれば、同一Security GroupからのみTCPの3306を通すようにして、EC2とRDSの両方につけるという方法。

どちらの考えかたでも、やりたいことは実現できるかもしれないけれど、それぞれメリット・デメリットがありそうで、どちらが良いとは言いがたい。

前者では、同じ機能を持つインスタンスには同じSecurity Groupが付き、Security Groupを見ればどんなインスタンスなのかがわかるという利点がある。

しかし、新たな通信を許可したい場合は既存のSecurity Groupを編集することになる。いろいろな所で使いまわしていたりしたら、余計な通信を許可することにもなりかねない。

逆に後者では、新たな通信を許可したい場合にはその通信専用にSecurity Groupを作り、インスタンスに設定すればよい。通信の種類が増える毎にSecurity Groupを作るため、インスタンスに設定できるSecurity Groupの上限に達しやすいという問題も存在する。

こちらのURLで上限数を確認してみると、インターフェースあたりのSecurity Groupの数、Security Groupあたりのルール数をかけたものが、250を超えないように上限緩和を行えるみたいだから、どちらの使い方でも可能なんだろう。

“セキュリティグループの設定方法に応じて、ネットワークパフォーマンスが影響を受ける場合があります。⁠⁠ との記述もある。どちらの方法が良いパフォーマンスなのか、管理しやすいのかというのは正直まだわからない。この日記を読んでくれた人がはてブのコメントとかTwitterで考え方を教えてくれたらいいなとか図々しいことも思っていたりもする。

RDSのSnapshotを作る

MySQLに無事に接続できるようになったら、次にはデータを入れるなどをしてみたい。

とはいえ踏み台となるEC2から接続できる事が確認できたら、あとはAWSとは関係の無い、今まで慣れ親しんだ方法で操作が可能になる。

SSHのport forwardingを使って手元からつないでも良いし、EC2上で作業してもよい。特に目新しさは無いけれど、俺は.ssh/configに書くのが好きで、

Host vpc-test-db
   HostName     ec2-****-conpute.amazonaws.com
   User          ec2-user
   Identityfile  ~/.ssh/id_rsa
   GatewayPorts  yes
   LocalForward  13306 test-db.*************.rds.amazonaws.com:3306

と書いておいて、

$ ssh vpc-test-db

とすればCtrl+Cで終わらせるまで、forwardingさせ続けるというやり方を良くする。こうしておけば、

$ mysql -P 13306 -u hoge -p

で接続できるから楽だ。

こんな感じでデータベースの操作をしたら、今度は運用面でRDSを触ってみたい。

Snapshotを作る

RDSの機能の1つに、バックアップがすごく楽になるというのがある。バックアップがすごく楽になるというのがどんなものなのか試してみたい。

$ aws rds create-db-snapshot --db-instance-identifier test-db  \
--db-snapshot-identifier test-db-snapshot-001
{
    "DBSnapshot": {
        "Engine": "mysql",
        "Status": "creating",
        "AvailabilityZone": "ap-northeast-1a",
        "PercentProgress": 0,
        "MasterUsername": "root",
        "Encrypted": false,
        "LicenseModel": "general-public-license",
        "StorageType": "standard",
        "VpcId": "vpc-6ac1020f",
        "DBSnapshotIdentifier": "test-db-snapshot-001",
        "InstanceCreateTime": "2015-02-03T23:03:14.906Z",
        "OptionGroupName": "default:mysql-5-6",
        "AllocatedStorage": 5,
        "EngineVersion": "5.6.19a",
        "SnapshotType": "manual",
        "Port": 3306,
        "DBInstanceIdentifier": "test-db"
    }
}

恐ろしく簡単にsnapshotができたような気がする。

Snapshotが作れたら、次はこのSnapshotからrestoreするということをやってみる。

aws rds restore-db-instance-from-db-snapshot --db-snapshot-identifier test-db-snapshot-001-略-

snapshotからrestoreするのもものすごく簡単だった。

ただひとつ問題なのが、また新たに--db-instance-identifierを指定するって事。それはすなわちrdsのエンドポイントが別で、全く新しくDBサーバが立ち上がったということだ。ここが実は俺の中では面白いところで、クラウドってこういう考え方をするんだなって実感した。

もしたとえばこれが実運用の際にはデータベースが破損しているなどの理由でサービスは停止してしまっているような状況が想像できる。言い換えれば、無停止でデータベースの切り替えを行う必要はない状況だ。であれば、なんとかして新しい方のデータベースに接続できるようにすれば、問題は解決する。壊れたサーバは捨ててしまえというなんとも漢らしい考え方だ。

実際にどうやるかというと

$ aws rds modify-db-instance --db-instance-identifier test-db \
--new-db-instance-identifier test-db-broken --apply-immediately

このコマンドで実行してみる。ただちに変更したい場合は--apply-immediately というオプションを付けないといけないことに気づくまでに少しかかってしまった。

このコマンドを実行すると、

             "PendingModifiedValues": {
                 "DBInstanceIdentifier": "test-db-broken"
             },

こんな感じでPendingModifiedValuesという項目で表示される。

しばらく経つと(Statusがrebootingとなっていたので、たぶん再起動??⁠⁠、db-identifierが変更されている。

こうなれば、新しくSnapshotから作った方も同様に、DBInstanceIdentifierを変更し、もともと動いていたDBInstanceIdentifierにしてあげる事でエンドポイントが新しい方のデータベースを指すことになり、アプリケーションをいじることなく故障したDBサーバから新しいDBサーバに切り替える事ができる。

あれ、でもこれMultiAZ使えば、自動的にやってくれるんじゃないか?と一瞬思ったけど、MultiAZはハードウェア障害では良いかもしれないけれど、データの破損に関してはカバーできなそうだ。そういった時にはこの方法が役に立ちそうだ。

結局今日もRDSの使い方の辺りははわかってきたけど、まだミドルウェアをインストールして、設定してという作業を行っていない。この辺りはやはりなんとかやってみたい。

まあでも最初に比べて、俺はもうAWSを使いこなせばインフラの設計に全力を注げるのではないんじゃないかとも、なんとなく思い始めてきている。だからこそ、ここからの楽しみ度も高い気がする、なんというか、期待大だ。


ついに、GUIなしでサーバ構築まで辿り着いた、とあるインフラエンジニア。これはいよいよ本格的にクラウドエンジニアへの道をつかみ始めている…かも。次回、最終回です、ご期待ください。

AWSの仕事ができるようになる、トレーニングプログラム

http://tr.pasonatech.co.jp/wpaws01

おすすめ記事

記事・ニュース一覧