AWS S3
今回はS3。
AWSの複数あるストレージサービスの一つです。
S3はファイルをアップロード、ダウンロードできるWebサービスです。
Webサーバとしても動作します。
特徴は、
容量制限がなく(5GB/file)、
非常に高い耐久性(99.999999999%)、
低価格です。
AWSは他に以下の様なストレージサービスを提供しています。
- EBS
- Glacier
- Storage Gateway
- EFS
EBSはEC2のディスクとしてアタッチするサービス。
Glacierはアーカイブストレージサービス。
Storage Gatewayはオンプレミスのストレージに接続するサービス。
EFSはNASサービス。
といったようにそれぞれ機能が違うので目的に応じたサービスをチョイスしましょう。
EC2でWebAP構築
↓
RDSでWebAP-DB構築
↓
AMIでEC2のイメージ化、複製
↓
ELBで冗長化
↓
ElastiCacheでセッション管理
↓
S3にアクセスログ保存 (今回はここ)
↓
(できれば)SQSでWebAP連携
S3は汎用的なストレージサービスであるため、本当に様々な用途があります。
今回はログの集約用途に利用します。
Webサーバやアプリケーションサーバを冗長化するとその分ログが各OSのファイルシステムに分散されてしまい、いざログを調査したい時に手間です。
またトラブル対応の調査する時にこのメッセージって過去にもあるんだろうか、など過去のログから比較をしたいけどそこまで古いログないや、ってことも多々あります。
ログの置き場所や保持世代数って運用設計でよく悩みます。
そんな時はS3に飛ばすことで、ログデータの集約、蓄積を実現できます。
今回はWebサーバのhttpdのアクセスログをFluentdでS3へ飛ばします。
それではいってみよう。
Simple Storage Service
- S3画面へ遷移
AWSのメニューからS3を選択します。
- バケットの作成
ファイル保存先のトップディレクトリ(FQDN)となるバケットを作成します。
[バケットの作成]ボタンを押下します。
- バケット名とリージョンの選択
各項目を入力して、[作成]ボタンを押下します。
バケット名:任意の名前を入力します。FQDNに含まれます。
リージョン:バケットを作成するリージョンを選択します。
- フォルダ作成
作成されたバケットが一覧に表示されます。
バケットのリンクを選択します。
バケットの中に入りました。
作成直後は何もデータが無いため、[バケット「<バケット名>」は空です。]と表示されます。とりあえず今回はアクセスログを置くので、
置き場となるフォルダを作成します。
[フォルダの作成]ボタンを押下します。
名前を入力します。
- Fluentd設定
Fluentdのインストールは以下の記事を参考にしてください。sfujimoto.hatenablog.com設定は以下になります。
input pluginはtailでaccess_logを監視します。
output pluginはs3で対象となるAWSのキー情報とバケット名、パスを指定します。以下、サンプル
# cat /etc/td-agent/td-agent.conf <source> type tail format apache path /var/log/httpd/access_log tag td.apache.access </source> <match td.apache.access> type s3 aws_key_id ************** aws_sec_key *********************** s3_bucket <bucket name> s3_region ap-northeast-1 path <folder name>/ buffer_path /var/log/td-agent/buffer # デバッグ用(デフォルトは1h) flush_interval 1s </match>
今回は試験用でflush_intervalを1秒毎にしています。
デフォルト設定では1時間単位にまとまったgzファイルが生成されます。
# ファイル容量が8MBにならない限りは。
- 動作確認
とりあえず、httpdにアクセスして、access_logに書き込みます。S3のManagementConsoleから作成したフォルダの中を確認します。
httpdにアクセスした数だけgzファイルが存在することでしょう。中を覗いてみましょう。
アップロードしたファイルのデフォルトアクセス権はAWSアカウントにしかないため、
アクセス権の設定を行います。
被付与者に「全員」を選択し、「開く/ダウンロード」を選択して、
「保存」ボタンを押下します。オブジェクトの「リンク」からURLを確認します。
gzファイルの中を確認してみると、
アクセスログの情報がJSON形式に変換されて格納されています。# curl -s https://s3-ap-northeast-1.amazonaws.com/<bucket name>/<folder name>/2015062113_3.gz |gunzip 2015-06-21T13:46:34Z td.apache.access {"host":"127.0.0.1","user":"-","method":"GET","path":"/","code":"200","size":"16","referer":"-","agent":"curl/7.40.0"}
これで集約を実現できました。
ただこの方法では単純な読み出しや解析が不便なので、
ログ集約が目的ならばElasticSearch+Kibanaで可視化する方が有用です笑次回はちょっと逸れてCloudFormationを試してみたいと思います。
AWS ElasticCache
先日、クリエーションラインさんが開催したHashiCorp社プロダクトの勉強会に参加しました。
Vagrantが有名で、その他プロダクトも注目されていることは、
色々な媒体で知っていましたが、
なかなか時間を確保出来ず、触ることができませんでした。
勉強会を通して何がいいな、って、
初めて社外の勉強会に参加しましたが、
個人で一から調べれば一週間かかるような知識を2時間という短時間で得ることができます。
今まで引きこもって勉強してきましたが、
これからはもっと外の世界に目を向けて勉強していきたい。
connpassやDoorkeeper等、今は手を伸ばせばこういう機会を得ることができます。
さて、本題。
前回はAMIを利用してELBを利用して、
複数のEC2インスタンスへのバランシングを利用することができました。
ロードバランサーのバランシングルールにRoundRobinやLeastConnectionを採用するに直面する課題があります。
セッション維持です。
アプリケーションサーバでクライアントのキャッシュ情報を保持することで、
クライアントはそのアプリケーションサーバのみアクセスするようにしないといけないこととなります。
この対策として有名な実装方式として、以下があります。
- ロードバランサーでセッション維持機能を利用
- アプリケーションサーバでキャッシュ情報をそれぞれがアクセスできる場所に外出しする
前者はL4LBではソースIPによる振り分けやL7LBではクッキーパーシステンスによる振り分けを利用することで実装可能です。
L4では振り分けが均等にならない、L7は高価だし、負荷が気になります。
ということで、今回はElasticCacheを利用した後者を実装します。
EC2でWebAP構築
↓
RDSでWebAP-DB構築
↓
AMIでEC2のイメージ化、複製
↓
ELBで冗長化
↓
ElastiCacheでセッション管理 (今回はここ)
↓
S3にアクセスログ保存
↓
(できれば)SQSでWebAP連携
今回はElasticCacheを起動して、
どちらのWebサーバにアクセスしてもセッション情報を返すような構成を組みます。
ElasticCacheでやることは少ないです。。
ElasticCahceは実装方式として、Memcached、Redisがあります。
両方共、オンメモリタイプのKVSです。
私のイメージは安定的なMemcached、高機能なRedisです。
Memcachedはメモリにデータの参照、追加/追記/変更/削除、加減算しかできないが、シンプルな分、安定動作が期待できる。
Redisはパターン一致やList,Hash型の取り扱いや永続化等の機能を実装している。
今回はセッション情報の扱いたいだけなのでMemcachedを利用します。
環境はずっと利用しているDjangoを利用したWebアプリケーション構成を引き続き利用します。
実はDjangoは初期設定でセッション情報をデータベースに出力するようになっています。
つまり、既にセッション管理不要な状況です笑
で、でもパフォーマンス面を考えれば、ElasticCacheの方がよいよね。そうだよね。
それではいってみよう。
Elastic Cache
- Elastic Cache画面へ遷移
AWSのメニューからElastic Cacheを選択します。
- Cache Subnet Group作成
Elastic Cacheを作成する前にElastic Cache用にSubnet Groupを作成する必要があります。覚えている方もいると思いますが、RDS作成時にもSubnet Groupを作成しました。
考え方は同じです。
Elastic CacheはCluster構成とすることが一般的です。
またCluster構成はAvailabilityZone(AZ)を跨いだ分散配置が可能です。APサーバがAZを跨いでいるのでそれぞれのAPサーバは同じAZのElastic Cacheを参照したいです。
その願い叶えましょう、AWSが。
Elastic Cache作成前は確認できないですが、作成済みだと思ってください。AP#1(AZ#1)で作成されたElastic CacheのEndpointホスト名を名前解決してください。
[root@ip-192-168-0-54 ~]# dig test-cache.g0y8q8.cfg.apne1.cache.amazonaws.com ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.30.rc1.36.amzn1 <<>> test-cache.g0y8q8.cfg.apne1.cache.amazonaws.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33761 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;test-cache.g0y8q8.cfg.apne1.cache.amazonaws.com. IN A ;; ANSWER SECTION: test-cache.g0y8q8.cfg.apne1.cache.amazonaws.com. 60 IN A 192.168.1.13 ;; Query time: 84 msec ;; SERVER: 192.168.0.2#53(192.168.0.2) ;; WHEN: Sun May 31 03:05:35 2015 ;; MSG SIZE rcvd: 81
次はAP#2(AZ#2)。
[root@ip-192-168-100-35 ~]# dig test-cache.g0y8q8.cfg.apne1.cache.amazonaws.com ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.30.rc1.36.amzn1 <<>> test-cache.g0y8q8.cfg.apne1.cache.amazonaws.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 17159 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;test-cache.g0y8q8.cfg.apne1.cache.amazonaws.com. IN A ;; ANSWER SECTION: test-cache.g0y8q8.cfg.apne1.cache.amazonaws.com. 60 IN A 192.168.101.230 ;; Query time: 2 msec ;; SERVER: 192.168.0.2#53(192.168.0.2) ;; WHEN: Sun May 31 03:05:46 2015 ;; MSG SIZE rcvd: 81
結果が違います。
ちな、192.168.1.0/24はAZ#1のPrivateSubnet、192.168.101.0/24はAZ#2のPrivateSubnet。
それぞれCache Subnet Groupに割り当てています。
つまり、そういうことです。順を追って一応説明します。
AP#1/AP#2は同じIPアドレス(192.168.0.2)のDNSサーバを参照しています。
なのに、返ってきたIPアドレスが違います。
ということは同じIPアドレスですが、それぞれ違うDNSサーバを参照していることが想像できます。これによってそれぞれのAPサーバは通信範囲を自身が配置されたAZ内だけとすることができます。
設定に戻ります。
左メニューからCache Subent Groupsを選択し、[Create Cache Subnet Group]ボタンを押します。
-
-
- -
-
Name: 任意の名前
Description: 任意の説明
VPC ID: Elastic Cacheを設置するVPC
Availability Zone: 追加するSubnetが存在するAZ
Subnet ID: 追加するSubnet-
-
- -
-
Subnet IDを選択して[Add]ボタンを押すことで追加されます。
追加したいSubnetの数だけAvailability Zone、Subnet IDを選択、[Add]を繰り返します。Subnet IDがIDというところがイケてないです。
プログラミングする上では一意となるIDが嬉しいですが、GUIでIDって言われても覚えていません。
一度[Add]しないとそれらの情報は表示されません。
任意で入力できる名前やCIDR Blockをプルダウン内に表示してほしいところです。
-
- Elastic Cache用Security Group作成
Security Groupを作成します。
Memcachedを利用する場合、デフォルト接続ポートは11211です。
ルールはInboundでAPサーバのセキュリティグループからの通信に対して11211のみを開放します。ちな、Redisのデフォルト接続ポートは6379です。
- Elastic Cache Cluster作成
Elastic Cacheを作成します。
左メニューからElastic Cache Clustersを選択し、[Get Started]ボタンを押します。
- Select Engine
実装方式を選択します。
先の説明にあったように今回はMemcachedを選択します。
- Specify Cluster Details
Memcachedの一般設定情報を入力します。Engine Version: 利用可能なバージョンからプルダウンで選択可能
Port: デフォルトは11211
Parameter Group: 詳細設定のパラメータを選択可能
事前にParameter Groupで詳細設定情報を定義しておくことでMemcachedに設定を投入できます。
Cluster Name: 任意の名前。
Endpointにも利用されます。
Node Type: スペックを選択可能
Number of Nodes: Clusterのノード数(MultiAZ構成とする場合、最低2つ)
- Configure Advanced Settings
Cache Subnet Group: 2で作成したSubnet Groupを選択
Availability Zone(s): どういうAZ構成にするか選択可能
[No Preference]、[Spread Nodes Cross Zones]、[Specify Zones]から選択可能
分散配置したい場合、[Spread Nodes Cross Zones]を選択
VPC Security Group(s): 3で作成したSecurity Groupを選択
Maintenance Window: 自動メンテナンス(パッチ適用)とするか、する場合、可能な日にち、曜日、時間等で指定可能。
[Select Window]、[No Preference]から選択可能
Topic for SNS Notification: 自動メンテナンス時の通知先(SNSのARNで指定)
- 作成
確認画面で設定内容を確認し、作成を開始します。
5分ほどで出来ます。
- AP側の準備
LoginURLにユーザ名、パスワードを渡すと、RDSのUserテーブルからユーザ名を元にデータを取得し、パスワードを照合できると、ログイン成功とします。
セッションにユーザ名を登録します。
HelloURLにアクセスすると、セッション情報からユーザ名を取得し、Hello, ユーザ名、を返します。
セッション情報からユーザ名を取得できなければ、ログインしろよ、を返します。またそれぞれアクセス先がわかるようにレスポンスにAPサーバのホスト名も含めます。
それではササッと作ります。
あー、時間かかった。
無駄にロギング、エラーハンドリング入れすぎた。AWS関係ないのでメモ程度
Elastic Cache設定追加、CSRF対策解除
vi /var/lib/project/project/settings.py ----- CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': 'test-cache.g0y8q8.cfg.apne1.cache.amazonaws.com:11211', } } # 'django.middleware.csrf.CsrfViewMiddleware',
Login、Hello URL追加
vi /var/lib/project/project/urls.py ----- url(r'^login/', views.login, name='login'), url(r'^hello/', views.hello, name='hello'),
model設定追加
vi /var/lib/project/app/models.py ----- class User(models.Model): name = models.CharField(max_length=32) password = models.CharField(max_length=32, null=True) created = models.DateField()
※ 今回、passwordカラムだけを追加したのですが、
dbmigrations、migrateでテーブルにカラムが追加されます。
既にデータがある場合、not null成約を外さないとエラーとなります。views設定追加(エラー処理削除)
vi /var/lib/project/app/views.py ----- def login(request): res = {"server": gethostname(), "message":""} body = request.body user_dict = json.loads(body) users = User.objects.filter(name=user_dict["user"]) user = users[0] request.session["user"] = user.name res["message"] = "ok" return HttpResponse(json.dumps(res)) def hello(request): res = {"server": gethostname(), "message":""} username = request.session.get("user") if not username: res["message"] = "You are not logined" return HttpResponse(json.dumps(res)) res["message"] = "Hello, " + username return HttpResponse(json.dumps(res))
- 動作確認
ELBをエンドポイントにアカウント情報を引き連れて、LoginURLへアクセスします。$ curl -d '{"user":"shinji","pass":"password"}' -X POST http://lb-*********.ap-northeast-1.elb.amazonaws.com/app/login/ {"message": "ok", "server": "ip-192-168-100-35"}
AP#2からレスポンスが返ってきました。
もう一回。
$ curl -d '{"user":"shinji","pass":"password"}' -X POST http://lb-*********.ap-northeast-1.elb.amazonaws.com/app/login/ {"message": "ok", "server": "ip-192-168-0-54"}
AP#1からレスポンスが返ってきました。
次にHelloURLへCookieを渡さずアクセスします。
$ curl http://lb-*********.ap-northeast-1.elb.amazonaws.com/app/hello/ {"message": "You are not logined", "server": "ip-192-168-100-35"}
ログインしてませんよー、よしよし。
次はCookieを取得して、Cookieを渡してHelloを受け取ります。
$ curl -c cookie.txt -d '{"user":"shinji","pass":"password"}' -X POST http://lb-*********.ap-northeast-1.elb.amazonaws.com/app/login/ {"message": "ok", "server": "ip-192-168-100-35"} $ curl -b cookie.txt http://lb-***********.ap-northeast-1.elb.amazonaws.com/app/hello/ {"message": "Hello, shinji", "server": "ip-192-168-0-54"}
AP#2にログインして、AP#1からHelloを受け取れました。
いかがでしたでしょうか?
これである程度の可用性、スケーラビリティを確保したWebアプリケーションシステムを組むことが出来ました。
クラウドIaaSを利用すると、なんといってもお手軽です。
私が入社した時は検証環境なんて一つの検証サーバをOSレベル、アプリケーションレベルで何人か共有していたり、本番環境はOSが分かれているところ同居させていたりが当たり前で、検証環境なのに気を使ったり、本番環境と違う構成だから本番環境にデプロイすると想定外のエラーがあったりと本当に苦労しました。(ブツブツ
次回は運用面です。
AWS ELB
4ヶ月ぶりにダーツ部が活動しました。
ぜんっぜんダメでした。
3時間投げても、4ヶ月前の投げ方がわかりませんでした。
1年ぐらい前に三ヶ月間ほど週二で通って身につけてフォームもブランク空くと分からなくなるもんです。
ブログはそうならないように頑張ります。
さて、本題。
前回はAMIを利用してEC2インスタンスを複製し、
同一構成のEC2インスタンスを2つのAZに分けて配置しました。
ただし、これだけでは2つのWebサーバがあるだけで、
負荷分散も冗長化も構成されていません。
入口となるグローバルIPアドレス、DNSがバラバラだからです。
一般的な負荷分散方式としてDNSラウンドロビンを使ったDNSによる負荷分散、
ロードバランサーを入口に置くことで振り分けてもらうことによる負荷分散があります。
前者は負荷分散としては意味がありますが、冗長化の観点では役に立たないため、あまり採用されません。
ロードバランサーの過負荷となる場合にロードバランサーを複数並べてDNSラウンドロビンして負荷分散することは可能です。
ただし、この場合も各ロードバランサーを冗長化しないと、意味を成し得ません。
またGSLBのようにDNSによって死活監視を行うことでDNSレコードをダイナミックに切り替えるシステムを使うことでロードバランサーの負荷も、そもそもロードバランサーを置く必要がなくなる仕組みもあります。
AWSのRoute53を使えば簡単に組むことができます。
、、、今調べたらELBは負荷に応じてスケーリングするようです。
AWSさん、さすがです。
今回はELBを起動して、
2つのWebサーバを負荷分散、冗長化できる構成を組みます。
EC2でWebAP構築
↓
RDSでWebAP-DB構築
↓
AMIでEC2のイメージ化、複製
↓
ELB (Elastic Load Balancing)
ELBはロードバランサーです。
通信を振り分けてくれることにより負荷分散してくれたり、
負荷分散対象を監視し、ダウンした対象を切り離すことで冗長化構成としてくれます。
ELB作成
- EC2画面へ遷移
AWSのメニューからEC2を選択します。
ELBはEC2画面より作成します。AWSのポータルが日本語対応しました。
アマゾンジャパンの方、本当にありがとうございます。
- ELB作成
左のメニューからロードバランサーを選択します。
「ロードバランサーの作成」ボタンを押下します。
- ロードバランサーの定義
基本情報を入力します。
ロードバランサー名
: 名前です。DNS名にも利用されます。
今回はlbとします。
内部向け LB の作成
: 作成する対象のVPCを指定します。
内部向けロードバランサーの作成
: インターネットに開放せず、内部からのアクセスのみの場合、
こちらをチェックしてください。
ロードバランサーのプロトコル/ロードバランサーのポート
: アクセス元が指定するプロトコル/ポート番号です。
今回は80番ポート(http)を利用します。
インスタンスのプロトコル/インスタンスのポート
: ロードバランサーがインスタンスにアクセスするプロトコル/ポート番号です。
今回は80番ポート(http)を利用します。
サブネットの選択
: バランシン対象が存在するサブネットを選択します。
今回は2つのazにあるpublic networkを選択します。
EC2インスタンスに設定したサブネットです。
- セキュリティグループの割り当て
80番ポートが空いていればいいのでEC2インスタンスに割り当てたセキュリティグループを選択します。
- セキュリティ設定の構成
httpだと注意されます。。
- ヘルスチェックの設定
ELBがEC2インスタンスを監視する方式を指定します。pingプロトコル
: HTTP、HTTPS、SSL、TCPから選択します。
今回はHTTPを利用します。
pingポート
: そのポート番号です。
今回は80番ポートを利用します。
pingパス
: ヘルスチェック先パスを指定します。デフォルト値は「/index.html」です。
SSL、TCPの場合、指定不要です。
応答タイムアウト(秒)
: ヘルスチェックの応答待ち時間を指定します。デフォルト値は「5」です。
ここで指定した時間以内に応答がない場合、NGと判断します。
ヘルスチェック間隔(秒)
: ヘルスチェックを行う間隔を指定します。デフォルト値は「30」です。
非正常のしきい値
: EC2インスタンスがダウンしたと判断するヘルスチェックNG連続回数を指定します。
デフォルト値は「2」です。
正常のしきい値
: EC2インスタンスがアップしたと判断するヘルスチェックOK連続回数を指定します。
デフォルト値は「10」です。デフォルト設定の場合、30秒ごとに監視対象サーバに向けて、
http://<対象サーバ>/index.html
のリクエストを発行し、5秒間応答がない、を2連続検知すると、
監視対象サーバがダウンしたと判断します。
- EC2 インスタンスの追加
振り分け対象のサーバを指定します。
今回は作成したWebサーバ2台を選択します。クロスゾーン負荷分散の有効化
: LBが存在するEC2インスタンスにしか振り分けない場合、こちらのチェックを外してください。
Connection Drainingの有効化
: LBがEC2インスタンスを強制的に切り離す時間を設定します。
ファイルダウンロード等長時間のリクエスト処理があった場合、
切り離してもここで指定した秒数は待つ、という設定です。
メンテナンス等で片系切り離して設定変更などする時に大変有用な機能です。
- タグの追加
- 確認
LBが作成されます。
- 作成状況確認
一覧画面へ遷移します。作成されたELBを選択して、概要タブを選択します。
ステータスが「2 個のうち 2 個のインスタンスが実行中です」となっていれば準備完了です。
DNS名はメモってください。インスタンスタブを選択します。
インスタンスの各ステータスが「InService」となっていることも確認します。
- 動作確認
それでは接続しましょう。
その前に、、、
接続先がわかるように各Webサーバのindex.htmlをホスト名等分かり易いように編集してください。$ curl http://lb-*********.ap-northeast-1.elb.amazonaws.com/index.html ip-192-168-100-35
Web#2(複製先)へアクセスされました。
それではもう一回。$ curl http://lb-*********.ap-northeast-1.elb.amazonaws.com/index.html ip-192-168-0-54
Web#1(複製元)へアクセスされました。
はい、ちゃんとバランシングされていますね。次に片系を落としてみて切り離されることを確認しましょう。
今回はWeb#2を落とします。
[root@ip-192-168-100-35 ~]# /etc/init.d/httpd stop Stopping httpd: [ OK ]
15秒ぐらいでWeb#2のステータスがOutOfServiceとなりました。
それでは接続$ curl http://lb-*********.ap-northeast-1.elb.amazonaws.com/index.html ip-192-168-0-54
Web#1にアクセスされました。
10回ほどアクセスしても全てWeb#1へアクセスされました。Web#2を起動します。
[root@ip-192-168-100-35 ~]# /etc/init.d/httpd start Starting httpd: httpd: apr_sockaddr_info_get() failed for ip-192-168-100-35 httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName [ OK ] >|| 10分ほどでWeb#2のステータスはInServiceとなりました。 >|| $ curl http://lb-*********.ap-northeast-1.elb.amazonaws.com/index.html ip-192-168-0-54 $ curl http://lb-*********.ap-northeast-1.elb.amazonaws.com/index.html ip-192-168-100-35
またWeb#2へ振り分けられるようになりました。
以前、ELBは切り離されたインスタンスはアップしても自動復旧しない(ELBに組み込まれない)という情報を得たのですが、改善したようです。
いかがでしたでしょうか?
AWSを使えば負荷分散、冗長構成のWebAPシステムを簡単に構成することが出来ます。
メンテナンスも考慮されたシステムとなっており、インフラ担当の悩みをどんどんAWSが吸収してくれます。
インフラ担当の運用・保守をAWSに任せることができるので、
その分、楽しい楽しい開発業務に専念することができます。
次回はElastic Cacheを利用してステートレスのWebAP構成を作りましょう。
「Amazon Web Services徹底活用ガイド」を読みました
Amazon Web Services 徹底活用ガイド (日経BPムック)
- 作者: 日経SYSTEMS,日経NETWORK,ITpro
- 出版社/メーカー: 日経BP社
- 発売日: 2014/12/13
- メディア: 単行本
- この商品を含むブログ (1件) を見る
AWSのノウハウ、Tipsを学びたく読んでみました。
AWSを触ったことがない人にはオススメの一冊だと思います。
AWSの機能紹介はいらなかった。
もっと多くの事例紹介が欲しかったです。
とにかく感じたことはオンプレから移行するなら方式設計、運用設計は大きく見直す必要がある。
郷に入っては郷に従え!に尽きます。
脱vSphereClient (Apple信者向け)
最近、自宅マシンにESXiをインストールしました。
プライベートの端末がOSXということもあり、vSphereClientの利用がサポートされません(*)。
VirtualBox上のWindowsマシンにインストールして操作する、という利用方法もありますが、
vSphereClientを利用するのに、VirtualBoxを起動して、Windowsを起動して、vSphereClientを起動。
んで、GUI操作ぽちぽち。
めんどい!
実はある程度のことはESXiにSSH接続してコマンドラインで出来るんです!
今回はVM作成を実施してみます。
ESXiのインストールやストレージ、ネットワークは準備済みとします。
ほとんどはvim-cmdコマンドを利用します。
vim-cmd
サブコマンドを実施し、色々なことを実現できます。
[root@localhost:~] vim-cmd Commands available under /: hbrsvc/ internalsvc/ solo/ vmsvc/ hostsvc/ proxysvc/ vimsvc/ help [root@localhost:~] vim-cmd hostsvc Commands available under hostsvc/: advopt/ enable_ssh refresh_firewall autostartmanager/ firewall_disable_ruleset refresh_services datastore/ firewall_enable_ruleset reset_service datastorebrowser/ get_service_status runtimeinfo firmware/ hostconfig set_hostid net/ hosthardware standby_mode_enter rsrc/ hostsummary standby_mode_exit storage/ login start_esx_shell summary/ logout start_service vmotion/ maintenance_mode_enter start_ssh connect maintenance_mode_exit stop_esx_shell cpuinfo pci_add stop_service disable_esx_shell pci_remove stop_ssh disable_ssh queryconnectioninfo task_list enable_esx_shell querydisabledmethods updateSSLThumbprintsInfo
例えば、
vim-cmd hostsvc/enable_sshを実行すると、ESXiホストでssh接続が有効となります。
vim-cmd maintenance_mode_enterを実行すると、ESXiホストをメンテナンスモードにします。
とかです。
それではいってみよう。
今回はCentos6のVMを作成します。
- VM作成
ブランクVMを作成します。
[root@localhost:~] vim-cmd vmsvc/createdummyvm centos6-1 /vmfs/volumes/local_ssd 4
戻り値はVMのIDです。
[root@localhost:~] ls -l /vmfs/volumes/local_ssd/centos6-1_3/ total 1024 -rw------- 1 root root 1048576 May 10 10:42 centos6-1_3-flat.vmdk -rw------- 1 root root 465 May 10 10:42 centos6-1_3.vmdk -rw-r--r-- 1 root root 0 May 10 10:42 centos6-1_3.vmsd -rwxr-xr-x 1 root root 977 May 10 10:42 centos6-1_3.vmx [root@localhost:~] cat /vmfs/volumes/local_ssd/centos6-1_3/centos6-1_3.vmx .encoding = "UTF-8" config.version = "8" virtualHW.version = "11" nvram = "centos6-1_3.nvram" pciBridge0.present = "TRUE" virtualHW.version = "11" nvram = "centos6-1_3.nvram" pciBridge0.present = "TRUE" svga.present = "TRUE" pciBridge4.present = "TRUE" pciBridge4.virtualDev = "pcieRootPort" pciBridge4.functions = "8" pciBridge5.present = "TRUE" pciBridge5.virtualDev = "pcieRootPort" pciBridge5.functions = "8" pciBridge6.present = "TRUE" pciBridge6.virtualDev = "pcieRootPort" pciBridge6.functions = "8" pciBridge7.present = "TRUE" pciBridge7.virtualDev = "pcieRootPort" pciBridge7.functions = "8" vmci0.present = "TRUE" hpet0.present = "TRUE" floppy0.present = "FALSE" scsi0.virtualDev = "lsilogic" scsi0.present = "TRUE" scsi0:0.deviceType = "scsi-hardDisk" scsi0:0.fileName = "centos6-1_3.vmdk" scsi0:0.present = "TRUE" displayName = "centos6-1" guestOS = "other" uuid.bios = "56 4d fd a6 54 0c 8e 22-a5 d9 9a 10 df 9d be ae" uuid.location = "56 4d fd a6 54 0c 8e 22-a5 d9 9a 10 df 9d be ae" vc.uuid = "52 79 a6 30 04 b7 91 37-35 5d ad 4c 42 08 59 a4"
vmxファイル、vmdkファイル等おなじみのファイルが作成されています。
勝手に付加された「_3」はどこから来たのでしょう。
- ISOファイルアップロード
scpコマンドでCentOS6のisoファイルをdatastoreにアップロードします。
- VMリソース設定
最低限必要な箇所のみ設定します。
まずは以下を設定。
- CPU数 -> 2core
- メモリ値 -> 2GB
- ネットワーク -> 1つ
- CDROMデバイス
- ゲストOS種別
- VNC
[root@localhost:~] vi /vmfs/volumes/local_ssd/centos6-1_3/centos6-1_3.vmx 以下、編集 guestOS = "other" ↓ guestOS = "rhel6-64" 以下、追記 numvcpus = "2" memSize = "2048" ide1:0.startConnected = "TRUE" ide1:0.deviceType = "cdrom-image" ide1:0.fileName = "/vmfs/volumes/local_ssd/CentOS-6.6-x86_64-minimal.iso" ide1:0.present = "TRUE" ethernet0.virtualDev = "vmxnet3" ethernet0.networkName = "VM Network" ethernet0.addressType = "generated" ethernet0.present = "TRUE" RemoteDisplay.vnc.enabled="true" RemoteDisplay.vnc.port="5901" RemoteDisplay.vnc.password="password" RemoteDisplay.vnc.keyMap="jp"
ide1:0.fileNameはアップロードしたisoファイルのパス指定
ethernet0.networkNameはポートグループ名
RemoteDisplay.vnc.portはVNC接続するポート番号
後述しますがVNC接続する用のポートをESXiで開放する必要があります。
RemoteDisplay.vnc.passwordはVNC接続時のパスワード
次はディスクサイズを設定。
- ディスクサイズ -> 16GB
[root@localhost:~] vmkfstools -c 10g -d thin /vmfs/volumes/local_ssd/centos6-1_3/centos6-1_3-1.vmdk [root@localhost:~] vi /vmfs/volumes/local_ssd/centos6-1_3/centos6-1_3.vmx 以下、編集 scsi0:0.fileName = "centos6-1_3.vmdk" ↓ scsi0:0.fileName = "centos6-1_3-1.vmdk" [root@localhost:~] vmkfstools -U /vmfs/volumes/local_ssd/centos6-1_3/centos6-1_3.vmdk
元のvmdkファイルは削除して構いません。
- VM起動
[root@localhost:~] vim-cmd vmsvc/power.on 3 Powering on VM:
- コンソール接続
OSXの場合、デフォルトでVNCクライアントが備わっています。
Finderのメニューから[移動] - [サーバへ接続]を選択
vnc://
:<設定したポート番号>
vmxファイルに設定したパスワードを入力
コンソールの画面が表示されます。
セキュリティプロファイル定義
[root@localhost:~] cp /etc/vmware/firewall/service.xml /etc/vmware/firewall/service.xml.bak [root@localhost:~] chmod u+w /etc/vmware/firewall/service.xml [root@localhost:~] chmod +t /etc/vmware/firewall/service.xml 以下を<ConfigRoot>タグ内に追記 <service id='0140'> <id>vnc</id> <rule id='0000'> <direction>inbound</direction> <protocol>tcp</protocol> <port type='dst'>5901</port> </rule> <enabled>false</enabled> <required>false</required> </service> [root@localhost:~] chmod 444 /etc/vmware/firewall/service.xml
ポート開放
[root@localhost:~] esxcli network firewall refresh [root@localhost:~] esxcli network firewall ruleset list vnc false [root@localhost:~] esxcli network firewall ruleset set -r vnc -e true [root@localhost:~] esxcli network firewall ruleset set -r vnc -a true Already allowed all ip
このようにコマンドとVNC接続により、VMを構築できました。
細やかな設定は難しいところもありますが、
多くの機能を扱うことができます。
私は省エネのため、利用しない時はESXiを落としています。
そのため、VMを全てシャットダウンして、シャットダウンが完了したらESXiをシャットダウンするスクリプトと、
ESXiを起動したらtxtファイルに登録したVMを自動で起動するスクリプトを作成しています。
またESXiはpythonを標準搭載しているのでpythonistaには助かります。
(*) Wineでほとんどの機能を利用可。
AWS AMI
最近、MAC用のSSHクライアントを探しています。
iTerm2でやっていますが、
WindowsのSSHクライアントはログの設定保存でホスト名でログファイルを作成できますが、
iTerm2は元々SSHクライアントツールじゃないところもあり、
ログは都度Startさせなきゃ開始してくれないし、
ファイル名も都度指定しなきゃいけないし、で正直めんどい。
はい、本題です。
前回はRDSを使ってWeb-AP-DB構成を作りました。
本日はWebAPサーバ(EC2インスタンス)をAMIのImage化し、
異なるEC2インスタンスとして生成します。
EC2でWebAP構築
↓
RDSでWebAP-DB構築
↓
AMI (Amazon Machine Image)
AMIはテンプレートです。
EBSディスクのコピーです。
AMIは単体では何もできず、
AMIからEC2インスタンスを作成して複製したり、
AMIを他リージョンにコピーしてDR構成を取ることが可能です。
AMIは不変なデータであるため、
バックアップとしても利用可能です。
それでは作成します。
- EC2画面へ遷移
AWSのメニューからEC2を選択
- AMI作成
対象となるEC2インスタンスを選択して、
[Actions] -> [Image] -> [Create Image]を選択します。
- 設定値入力
Image name -> イメージ名
Image description -> 説明[Create Image]ボタンを押せば、作成が開始されます。
AMI一覧ページを表示するとpenddingステータスのAMIを確認することができます。
次は作成したAMIからEC2インスタンスを作成します。
- AMI画面へ遷移
AWSのメニューからEC2を選択
左のメニューからAMIsを選択
- EC2インスタンス作成
作成したAMIを選択して、
[Actions] -> [Launch]を選択します。
それ以降はEC2インスタンス作成と同じです。EC2インスタンス一覧を確認すると、
作成したAMIのIDと同じAMI IDのEC2インスタンスが作成されていることを確認できます。
それでは確認です。
# curl http://<EC2 Instance Public DNS>/django/list/ Hello, fuji
アクセスできました。
今回はボリューム少な目でしたね。。
次回はELBを作成してアクセスが分散されることを確認します。
AWS RDS
早いもので更新が2週間空いてしまった。
AWSスクリプトを書くことが楽しくなっちゃってアウトプットをサボりました。
botoというPython製のAWSライブラリがあって、
これがまた利用者に優しくAPIリファレンスさえ読めば、
PythonもAWSも理解が乏しい私が簡単にAWSの環境構築スクリプトを組めちゃいました。
さて、本題。
前回はEC2インスタンスを作成して、Webサーバを立ち上げました。
今回はRDSインスタンスを立ち上げて、Webサーバと連携します。
EC2でWebAP構築
↓
RDSでWebAP-DB構築 (今回はここ)
↓
AMIでEC2のイメージ化、複製
↓
ELBで冗長化
↓
ElastiCacheでセッション管理
↓
S3にアクセスログ保存
↓
(できれば)SQSでWebAP連携
では早速RDSを作成しましょう。
(キャプチャは後日こっそりつけときます)
あれ?
2週間の間にEC2インスタンスのOSがRHEL7になってる。。。
- RDS画面へ遷移
AWSのメニューからRDSを選択
- RDS作成開始
[Get Started Now]ボタンやら[Launch DB Instance]ボタンやらをクリック
- DBエンジン選択
DBエンジンは4種類が選べます。(ブログ執筆現在:2015/04/18)
Auroraはまだ東京リージョンでは登場していません。- MySQL
- PostgreSQL
- Oracle Database
- Standard Edition One
- Standard Edition
- Enterprise Edition
- Microsoft SQL Server
- Express
- Web Edition
- Standard Edition
- Enterprise Edition
今回はMySQLを利用します。
- MultiAZ
MultiAZかどうかを選択します。
MultiAZはDBの配置方式として複数のAZに配置するかどうかです。
MultiAZを選択すると、稼働率99.95%以上を保証されます。
99.95%を下回る場合、AWSから返金があります。
※注意:MultiAZは無償枠外です!
私のような無償プレイヤーは要注意です。
でも、本番運用するような場合は必須だと思う。
- 基本設定
- インスタンス設定
- Engineバージョン
- Instanceタイプ
t1.micro以外は無償枠外
-
- ストレージタイプ
-
- ストレージサイズ
- DB設定
DNS等に利用され、データベースでは持たないっぽ
-
- DBユーザ名
- パスワード
- インスタンス設定
- 詳細設定
- ネットワーク設定
- VPC
- SubnetGroup
VPCのSubnetとは別で、複数のSubnetをまとめたもの
-
- Availability Zone
- SecurityGroup
EC2作成時とは別でDBポート番号のみを許可した紐づけるのが望ましい
- DB詳細設定
- DB名
作成する空のデータベース
-
- ポート番号
最初からデフォルト値が入っている
以上の設定で作成されます。
- ネットワーク設定
- 作成中
けっこう時間かかります。。。
- APサーバ作成
DB作成中にDBを利用可能なAPサーバを構築しましょう。
APサーバはDjangoでちょちょいと。。。
ん?
あれ?こうかな。
ダメだな。
あー、これか。
はぁ。。。
あーーーー
ですよねー
だいたいこういう時ってSELINUXですよねー
ちょちょいと、3時間(内、SELINUXに2時間半)で出来ました。
さて、そろそろRDS立ち上がったかな。簡単にやったことを備忘録
# yum install -y gcc python-devel mysql mysql-devel # pip install django mysql-python # django-admin startproject project # cd project # vi project/settings.py databaseの設定追記 # ./manage.py startapp app # vi project/settings.py appを追加 # vi app/models.py Userクラス追加 # ./manage.py makemigrations # ./manage.py makemigrate # vi app/views.py list関数定義 UserテーブルからSelectしたデータにHelloを付けて返す # vi project/urls.py list/とapp.views.listを紐付け # vi /etc/httpd/conf.module.d/10-wsgi.conf 魔法の言葉を追加 # systemctl # setenforce 0 こ、こいつまで遠かった。。。
- DB接続確認
試験用にDBを設定します。# mysql -h <RDS Public DNS> -u <username> -p Password: > show databases; +--------------------+ | Database | +--------------------+ | information_schema | | innodb | | mysql | | newdb | | performance_schema | +--------------------+
newdbがRDS作成時に指定したDB名です。
> use newdb; Database changed > show tables; +----------------------------+ | Tables_in_newdb | +----------------------------+ | app_user | | auth_group | | auth_group_permissions | | auth_permission | | auth_user | | auth_user_groups | | auth_user_user_permissions | | django_admin_log | | django_content_type | | django_migrations | | django_session | +----------------------------+ > desc app_user; +-------------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(32) | NO | | NULL | | | create_date | date | NO | | NULL | | +-------------+-------------+------+-----+---------+----------------+
Djangoが勝手に色々作ってます。
app_userテーブルにデータを登録して取得します。> insert into app_user values(1, 'fuji', '2015-04-18'); Query OK, 1 row affected (0.00 sec) > select * from app_user; +----+------+-------------+ | id | name | create_date | +----+------+-------------+ | 1 | fuji | 2015-04-18 | +----+------+-------------+ 1 row in set (0.00 sec)
おk
- 接続確認
早速繋いでみましょう。# curl http://<EC2 Instance Public DNS>/django/list/ Hello, fuji
おー、うまくいきました。
今回は
クライアント -> Internet -> Web -> AP -> RDS
というあるある構成をAWS上に作ることができました。次回は今回作ったAPサーバをAMIにイメージ化して複製します。