SEEDS Creator's Blog

ISUCON7に「ガトリンガー葉の仲間たち」で参加して今年も惨敗しました

毎年恒例のISUCONに参加してまいりました。
毎年今年こそは!と心に闘志を燃やして参加するのですが、今年も予選敗退でした。残念。

ISUCONとは「いい感じにスピードアップコンテスト」の略で
与えられたお題のWEBアプリケーションをできるだけ早くし、ベンチマークの出す点数で競うコンテストです。

isucon.net

今回は社内の方々にお誘い活動を行って捕まえたkawakattsun、luccafortと僕(cs_sonar)の3名で参加しました。
僕はISUCON1から参加していて、kawakattsun、luccafortは今回がISUCON初参加でしたので
裏テーマとして二人がISUCONを本気で楽しんでもらえたら嬉しいなーと思っていたのですが
実際はものごっつい楽しんでもらえたようで結果は惨敗でしたがそういう意味ではとても成功だったと思います。

順位は暫定55位で点数は72,285。言語はPHPです。

そういえばISUCON1は複数台構成だったなぁと思い出しました。

事前準備

業務の忙しさにかまけてあまり事前準備してなかったです。 2ヶ月前くらいにみんなでPixivのISUCON問題をじっくり解きましたので 今回非常構成が似ていたのでそれがよかったです

・とりあえずベンチ回す
・レギュレーションを熟読する
・git
・phpに切り替え
・SSH簡易接続設定
・mysqlのdata dir をコピー
・アクセスログ解析(analog)
・netdataつかってみる?
・app armor注意
・プログラムDBで明らかに重いところを潰す
・インフラ関連のチューニングを行う
・ある程度のチューニングができたら抜本的な構造変更の対策を検討

ボトルネックを常に潰していく
同時に改修は行わない。
なにがよくて何がだめだったかがわからなくなるから

という方針だけ前日10分くらいでざっくり作って共有。

本番での流れ

もうあたふたしてたので詳細は覚えてないですが・・・

  • 9:30 会社に到着。会社にいた方がエナジードリンクを差し入れしてくれた。
  • 10:00 開始が遅れるらしい。 これはこれで非常に有意義な時間だった。お祭り感。
  • 11:30 もう今日はないのでは?と、昼から飲みに行く気に半分くらいなってた
  • 13:00 開始・・・されない。このズコーー!がお祭り感がさらに加速。
  • 13:10 本当開始!とりあえずSSH鍵認証。
  • 13:12 初期ベンチ pythonで6189
  • 13:30 各サーバーどこからでも ssh {web1|web2|db}で接続できるように設定
  • 13:30 DBサーバーのID/PASSをあふあふ探す
  • 13:30 PHPに切り替えてベンチで4157
  • 14:00 DBが重かったので簡単にチューニング。innodb_flush_log_at_trx_commit = 0 くらいですが。6397
  • 14:15 さくっとanalogでアクセス数だけ確認。loginとadd_channelとかが多い
  • 15:00 slow_logから明らかに画像の部分がボトルネックなので静的に書き出し、nginxでiconsから返すように設定。8293
  • 16:00 mysqlのINDEX貼る、N+1改善、php-fpmプロセス数上げる、などなどで12000
  • 17:00 疲れが見え始めた所に社内の方が差し入れでお菓子とジュースをくれる。ありがたい。余ったけど。
  • 17:10 nginx <=> php-fpmをunix domain socketに変更するのに僕が結構はまる。20000
  • 18:00 php-fpm <=> DB をスレッドプールするようにした。mysql-pdoでいうparsistantの設定。点数はメモってなかった
  • 18:30 静的ファイルの接続でエラー出るので帯域でつまってる事にやっと気づく。

じゃぁ3台から返せばいいんじゃね?という事でこの時間で大きな構成変更をした。ベンチ対象は全台に変更。

[app1]    [app2]    [app3]
web        web      web
app        app      db
  • app3への接続は静的ファイルはそのまま返し、それ以外はロードバランス的にapp1/app2 に振り分け。
  • iconsの共有はnfsを使用。app1をnfsサーバーにしてapp2/app3はnfsクライアントとしてmountする形に。
  • 静的ファイルを304で返せるように expire 10d;を追加。 (ここがpublicつけないといけなかったなどの話)
  • これで59000
  • 20:15 SQLのストリクトモード消したりして73160が出た。これが最高得点。
  • 20:30 ここからベンチガチャがあって15000 ~ 70000まで大きく振れまくる・・・304レスポンスの数で変わってたのかな
  • 21:00 再起動テストをする。nfsマウントしてたので起動順によってはマウントされない事態が発覚。autofs入れて対応。
  • 21:10 ベンチ&ベンチ&ベンチ&ベンチで72285が出たのでやめる

僕はプログラムをまったく見ておらずインフラばかり見てました。
php-fpmのsocket化の権限関係でえらいハマってしまい、プログラム見る時間がなかったです・・・
のでプログラム部分はkawakattsun、luccafortがいろいろとやってくれていたのだと思います!

アクシデント

  • gitのリポジトリのdbディレクトリを含めてしまい、復旧用dumpが含まれてしまった為にどえらい重いリポジトリに
  • 画像の静的化の時にDBをやらかしてしまいdumpから復元する事態に
  • php-fpmの設定ファイルのコメントが#ではない事に気づくのがかなり最後の方だった
  • 開始が3時間遅れたので、後に予定のあったluccafortが途中で抜けてしまう

アクシデントを含めてのISUCON!!

感想

開始が遅れるという所で、運営側が本当に大変だったんだな、と改めて感謝です。
毎年こんなにも楽しい時間をくれて頭が上がりません。

今回の問題も本当によく考えられてて本当に楽しかったです!
メモリ1GBしかない所なんてとても素敵でした。

今年はシーズからもう1チーム出てたのですが競技終了後に「あそこどうした?」みたいな反省会は本当に楽しい
問題のリポジトリも公開されましたので、これからも社内で2次会して楽しみたいと思います!

しかし、、、とっても悔しい!くやしーーー!!!
僕はこれからブラウザキャッシュの設定で Cache-Control: public の設定をしない事はないでしょう。

ISUCONは本当に最高です!

社内WindowsサーバーをAWSに移行する話1

経緯

シーズでは、見積書・請求書の発行などに社内にWindowsサーバーを立て弥生販売を使っていました。

複数拠点から複数人が同時に使うためネットワーク版5ライセンスです。

社内にサーバーを置くメリットとして、

*ギガビットLANでの高速アクセス

*社外との通信が発生しないためセキュリティーが高い

*売るほどサーバーラックがあるのでコストはあまり気にならない

といった利点がありましたが サーバー筐体費用、Windowsサーバー、SQLライセンスなどの初期費用(トータル約40万※構築費用は自前のため無料)がかかるうえ 毎年のライセンス更新や筐体保守費用、また毎月の電気代・空調費用も馬鹿になりません。 さらに、場所も取るし、空調にも気を使うし、なにかとメンテも大変なのでクラウドに行きたいと考えておりました。

要件

*AWSで24時間365日稼働(ただし夜間は止めるかも)

*OSはWindowsサーバー2012

*弥生販売ネットワーク版5ライセンスを動かす

*シーズ社内とVPNでセキュアに常時接続

特に最後のVPNで社内とシームレスかつセキュアに接続が一番重要ですね。

これらの要件をAWSでこのように準備しました。

AWS構成

*ec2インスタンス(Windows2012) t2.small $36.60

*EBS45GB $5.40

*VPC VPN接続 $36

合計 約78ドル=約8,424円 (1ドル108円)

f:id:panmizser:20161121214003p:plain

EBSボリューム、転送量、EIP、IOなど少額の従量制がありますが、それらを含んだとして、約8,500円です。

移行してどうだったか

結論としては、最高でした。

まず費用としては

サーバー1台をデータセンターでハウジング(月50,000相当,OSライセンス諸々込)として、それが月8,500円ポッキリになりました。(83%DOWNです!)

また弥生を使わない夜間止めることで更にコストダウンも可能です。

次に、回線速度やアプリの使用感ですが、こちらも全く問題ありません。

インスタンスタイプは最初 large → medium と様子を見ていきましたが最終的にはsmallまで落としても操作感に問題ありませんでした。

(ただし弥生インストール時はlargeでやったほうが効率がいいです)

回線速度は、AWSの提供するVPNサービスを利用することで全くストレスを感じません。 (以前、WindowsインスタンスからPPTPで会社ルーターに繋げたりしたことがありましたが、その場合、一応つながりますが、結構遅かったです。)

次回は、これらAWSの設定、社内VPNルーターの設定を含め詳しく解説していきたいと思います。

AWS 中国(北京)リージョンの利用でハマった所をご紹介します

f:id:cs_sonar:20161118201515p:plain

原口です。

AWS China(Beijing) [中国(北京)リージョン] を触らせていただく機会がありまして触ってみた感じをお伝え致します。

中国リージョンは結構前から追加されていますが、通常のアカウントのリージョン一覧には出てきません。

中国リージョンを利用するには他のリージョンとは異なり、専用のアカウントを作成しなければ利用できません。

基本情報

[リージョン]
cn-north-1

[アベイラビリティゾーン]
cn-north-1a
cn-north-1b

無許可でのポート80 / 443 / 8080 のポートによるページ公開ができない

中国では、ウェブサイトを勝手に公開できないようで、AWS側にて上記のポートは接続できないようになっています。ICPライセンスというものを登録しなければ公開できません。基本的にはAWSアカウントにライセンスが紐づいているようでライセンスが紐づけば公開が可能となるようです。

注意点として、ELBやEC2などでは接続できないときはブラウザくるくるですが、s3の接続できないエラーは401レスポンス(UnauthorizedAccess)を返します。401(UnauthorizedAccess)はs3のgetObjectがない場合でも出すのでICPライセンスが原因である、、、という判別がつきにくいところでハマりやすいので注意です。

ちなみにELBやEC2は待ち受けポートを適当なポートに変えてやれば無理やり公開する事は可能でした。

ARNやドメインネームが変わっているので注意

ドメイン名は ec2.amazonaws.comec2.amazonaws.com.cnと、完全に別のドメインになっていますし、 ARNもarn:awsarn:aws-cn と変わっているので注意が必要です。

cloudformationやterraformのテンプレートなど既存のノウハウを生かそうと流用すると arnを直接指定している部分などではまります。

ないサービスが多い

以下の一覧でも確認できます

リージョン - グローバルインフラストラクチャ | AWS

今回は

  • route53
  • lambda
  • RDS(Aurora)

あたりがなかったので困りました。

既存リージョンからAMIはコピーできない

完全別サービスみたいな感じですので、既存のリージョンで作成していたAMIなどを共有する事ができません。
これはかなりつらかったので・・・以下のようにディスクイメージを作成してコピーする方法を用いました。

インスタンスコピーの手順

AmazonLinux (HVM)を使用した場合。

移行したいAMIのsnapshotからVolumeを作成し、適当なインスタンスにアタッチします。
アタッチしたボリュームをddコマンドでイメージファイル化します。
(/dev/xvdfとしてアタッチした場合)

dd if=/dev/xvdf of=image.img bs=1M

イメージファイルを中国側に作成したインスタンスに転送します

scp -i chn.pem ./image.img ec2-user@***.***.***.***:/home/ec2-user/

中国側インスタンスで空のVolumeを作成し、アタッチします。
この時、空のVolumeサイズはコピー元のVolumeサイズと同じにしてください。

このアタッチした空Volumeにddコマンドでイメージファイルを書き込みます
(/dev/xvdfとしてアタッチした場合)

dd if=./image.img of=/dev/xvdf bs=1M oflag=direct

※独自OSを使っている場合などはこの際にboot関連の項目を書き換えたりしないといけないかもしれないですがAmazonLinuxでは特に修正なくできました。

Volumeをデタッチしてsnapshotを作成します。
そしてsnapshotからAMIを作成。
この際のパラメータはHVM(Hardware-assited VM)に。
カーネルIDなどはデフォルトでOKです。

これで、既存リージョンのAMIを北京リージョンに持ってくる事ができた事になります。

このとき、作成したAMIを北京リージョンで立ち上げるとうまく立ち上がってこない事があります。
マネージメントコンソールからget_systemlogで見ると以下のようなのが出てる場合・・・

http://packages.ap-northeast-1.amazonaws.com/2016.09/main/20160901f6a8/x86_64/repodata/repomd.xml?instance_id=i-******************************&region=ap-northeast-1: [Errno 12]
Timeout on http://packages.ap-northeast-1.amazonaws.com/2016.09/main/20160901f6a8/x86_64/repodata/repomd.xml?instance_id=i-******************************&region=ap-northeast-1: (28, 'Connection timed out after 10000 milliseconds')
Trying other mirror.`

Amazon Linuxはcloud-initでyum update(セキュリティのみのもの)が走るのですがそれが途中で止まっているのが原因です。
止まってしまった場合は再起動すればOKです。
これはたぶん以下の変数が書き換わっていないからではないかと思います。

/etc/yum/vars/awsdomain
/etc/yum/vars/awsregion

同様にRDSのスナップショットも移動できないです。こっちはダンプ持ってく感じになりますね

よく接続切れる、またはめちゃくちゃ遅くなったりする

南北問題と言うらしいです・・・。

(参考) qiita.com

【デーモン化で解決!】WEBrickでRedmineを立ち上げるとpost時に真っ白になる

f:id:seeds-std:20161108200910p:plain
どうも、はらぐちです。

今回は、 「WEBrickでRedmineを立ち上げると、なぜかpostした時だけ真っ白になってしまう」という件について、 解決法をご紹介します。 rails力が足りなくてハマった感じですが……

経緯

シーズではプロジェクト管理ソフトのひとつにRedmineを使用しているのですが、 最近、古いサーバー上のRedmineを、最新OSを搭載した新しいサーバーに移行することになりました。

1.データをそのままごっそり持ってきて、
2.mysqldumpをリストア、
3.rbenvで該当バージョンをそろえて、
4.gemも同じバージョンを入れていったのですが、

どうしても、Passengerだけがうまく使えない……

そこで、WEBrickで起動し、apacheのリバースプロキシ経由で参照するように設定をしてみました。

おおむねこれでうまく動いていたのですが、 なぜかPostした時だけ真っ白なページになる状態に…… (※真っ白なページにはなりますが、更新自体はされている。)

解決法

いろいろ調べてみた結果、 そのままフォアグランドで起動するとうまくいくのにバックグラウンド実行するとうまくいかない事がわかりました。 そこからはWEBrickのドキュメントなどを参照して、-dオプションでデーモン化で立ち上げる事が可能と判明。 以下のような起動方法で問題なく動作しました

/path/to/redmine/script/server -d -e production

デーモン化は知りませんでしたが、バックグラウンド実行だと何故こんな動きになるんでしょうね? ひとまずはデーモン化で解決しました!

AWSとVPN接続を張ったけど転送量はどうなの?

blog_img_4285
先日、CTO原口くんにお願いして、シーズ社内にあったWindowsサーバーをAWSに移行しました。 AWSにWindowsServerOSインスタンスを立てて、シーズからはVPN(IPsec接続)でシームレスかつセキュアに社内ネットワークを拡張したイメージです。 その話はまた別にするとして、その時、「AWSでファイルサーバーをやるのってどうなの?使えるの?」という話になったので検証をちょこっとやってみました。

ファイルサーバー自体は、EC2.linuxでsambaを立てるなり、WindowsServerでファイルサーバーをするなりして簡単に実装できますが、一番のネックは転送スピードということになりますよね。

そこを検証してみました。

環境

社内LAN環境はすべてギガビット回線 =>社内ファイルサーバーにはギガビット転送ができる(1000Mbps=125MB/s)

インターネットともギガビットの専用線を引いている。 インターネット接続はRTX1200を利用している。VPNルーターとしても利用している。 AWS VPC VPN接続にはRTX1200からIPSECで接続している。

社内、社外インターネットともギガビットのため、理論上はすべてギガで通信できる環境です。

社内ファイルサーバーの転送スピード

アップロード
inG

アップロード(パソコンから社内ファイルサーバー)スピードです。 だいたい平均的に32.5MB/s(260Mbps) となっているので、理論値の26%ぐらいしかでていませんが、通常利用ではまったく問題のない速さだと思います。

ダウンロード
outG

ダウンロード(社内ファイルサーバーからパソコン)はさらに早くなりました。 57.2MB/s(457.6Mbps)! これ以上求める必要はないでしょう。というレベルだと思います。

AWS上VPN接続

アップロード
in

アップロード(パソコンからAWS-VPNファイルサーバー)転送スピードは6.82MB/s(54Mbps)です。 スピードはかなり落ちましたが、実用性ではどうでしょうかね。 一昔前の100Mbps環境時代の速度というところでしょうか。 今のギガに慣れているとストレスかもしれませんが、使えなくはなさそうですね。

ダウンロード
out

ダウンロード(AWS-VPNファイルサーバーからパソコン)は逆に遅くなりました。 3.68MB/s(29.44Mbps)で止まっています。 出だしは早かったのですが、なにか制限が入っているのでしょうかね。 とはいえ、まあ実用的に全く使えないわけではなさそうです。

結論

AWS-VPNは100Mbpsで繋がっていた時代の速度ではあるが、使えないことはなさそう。 しかし、転送量でも課金されるので注意が必要。(アップロードは無料) 1000GB = $139.86 100GB = $13.86 10GB = $1.26

Terraformを使ってみました

blog_img_4238
Terraformは、あらかじめインフラ構成を設定ファイルに記述して、 クラウド環境に適用・管理するツールです。 Vagrantなどを開発しているHashiCorpのツールになります。

AWSだけではなく様々なプロバイダに対応していますが、AWSで使用してみました。

インストール

Linuxサーバに入れてみました。 ダウンロードしてきて展開するだけで使えます。

cd /opt
mkdir terraform
cd terraform
wget https://releases.hashicorp.com/terraform/0.6.16/terraform_0.6.16_linux_amd64.zip
unzip terraform_0.6.16_linux_amd64.zip

パスを通すと便利でした。

vi ~/.bashrc

export PATH=/opt/terraform:$PATH

AWS側事前準備

  • AWSアカウント作成
  • terraformで触るリソースをいじれるポリシーを付与したIAMユーザを作成

terraformの動作イメージ

必ず使うコマンドは以下の三つ

terraform plan dry-runです。設定ファイルの記述ミスなどをチェックしてくれます

terraform apply 実行です。設定ファイル通りの構成を実装してくれます

terraform destroy 作成した構成を削除してくれます

terraform初期設定

まずはAWSアクセスキーなどの設定。 terraformは「terraform.tfvars」というファイルがカレントディレクトリにあると そちら中を読んで変数として取り扱ってくれます。 注意点として、このファイルでは配列は設定できないようです。

このようにアクセスキーなどを変数として設定しておく事ができます。

file : terraform.tfvars

#####################################
#Variable Settings
#####################################
#AWS Settings
access_key = "xxxxxxxxxxxxxxxxxxx"
secret_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
region = "ap-northeast-1"

このファイルは.gitignoreとかでリポジトリでは管理しないようにします。

次のこの変数をtfファイル内で使用できるようにvariableで定義します。 上記のterraform.tfvarsの記述内容は環境変数に入るので、それを定義します。

file : variables.tf

#####################################
# Variable Settings
#####################################
#AWS Settings
variable "access_key" {}
variable "secret_key" {}
variable "region" {}

上記で設定した変数を使ってterraformのAWS設定を記述します

file : aws.tf

provider "aws" {
    access_key = "${var.access_key}"
    secret_key = "${var.secret_key}"
    region = "${var.region}"
}

以上で初期設定は終わり。 terraform planやterraform applyをするとカレントにある *.tf ファイルをすべて読み込んでくれます。 また、一度applyを実行すると、terraform.tfstateというファイルが作成されます。 terraform.tfstate は、Terraform が管理しているリソースの状態が保存されているのだと思います。 おそらく次回実行時にこちらのstateファイルとの差分でどのようなAPIを投げるか決定しているのだと思います。

VPCを作成してみる

実際にいろいろ設定をしてみたので紹介です。 以下は

・VPCの作成
・サブネット二つ作成(いずれもパグリックサブネット)
・DHCPオプションの作成
・インターネットゲートウェイ作成
・ルーティングテーブル作成

を行っています。

file aws_vpc.tf

#####################################
# VPC Settings
#####################################
resource "aws_vpc" "vpc_main" {
    cidr_block = "${var.root_segment}"
    enable_dns_support = true
    enable_dns_hostnames = true
    tags {
        Name = "${var.app_name}"
    }
}

#####################################
# DHCP option sets
#####################################
resource "aws_vpc_dhcp_options" "vpc_main-dhcp" {
    domain_name = "${var.dhcp_option_domain_name}"
    domain_name_servers = ["AmazonProvidedDNS"]
    tags {
        Name = "${var.app_name} DHCP"
    }
}
resource "aws_vpc_dhcp_options_association" "vpc_main-dhcp-association" {
    vpc_id = "${aws_vpc.vpc_main.id}"
    dhcp_options_id = "${aws_vpc_dhcp_options.vpc_main-dhcp.id}"
}

#####################################
# Internet Gateway Settings
#####################################
resource "aws_internet_gateway" "vpc_main-igw" {
    vpc_id = "${aws_vpc.vpc_main.id}"
    tags {
        Name = "${var.app_name} igw"
    }
}

#####################################
# Public Subnets Settings
#####################################
resource "aws_subnet" "vpc_main-public-subnet1" {
    vpc_id = "${aws_vpc.vpc_main.id}"
    cidr_block = "${var.public_segment1}"
    availability_zone = "${var.public_segment1_az}"
    tags {
        Name = "${var.app_name} public-subnet1"
    }
}
resource "aws_subnet" "vpc_main-public-subnet2" {
    vpc_id = "${aws_vpc.vpc_main.id}"
    cidr_block = "${var.public_segment2}"
    availability_zone = "${var.public_segment2_az}"
    tags {
        Name = "${var.app_name} public-subnet2"
    }
}

#####################################
# Routes Table Settings
#####################################
resource "aws_route_table" "vpc_main-public-rt" {
    vpc_id = "${aws_vpc.vpc_main.id}"
    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = "${aws_internet_gateway.vpc_main-igw.id}"
    }
    tags {
        Name = "${var.app_name} public-rt"
    }
}

resource "aws_route_table_association" "vpc_main-rta1" {
    subnet_id = "${aws_subnet.vpc_main-public-subnet1.id}"
    route_table_id = "${aws_route_table.vpc_main-public-rt.id}"
}

resource "aws_route_table_association" "vpc_main-rta2" {
    subnet_id = "${aws_subnet.vpc_main-public-subnet2.id}"
    route_table_id = "${aws_route_table.vpc_main-public-rt.id}"
}

この例の通り、作成したリソースのIDなどは他のリソースで読み込む事が可能です。 一番上で作成したVPCのIDは以下のように取得できます。

${aws_vpc.vpc_main.id}

セキュリティグループを作成してみる

特筆するところはないですが、ソース元をセキュリティグループにする例も載せてみました。 ソース元を配列にする事で複数の設定ができます。 terraform.tfvarsに配列が指定できたらいいんですが・・・

resource "aws_security_group" "lb_sg" {
    name = "${var.app_name} Load Balancer"
    vpc_id = "${aws_vpc.vpc_main.id}"
    ingress {
        from_port = 80
        to_port = 80
        protocol = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
    }
    egress {
        from_port = 0
        to_port = 0
        protocol = "-1"
        cidr_blocks = ["0.0.0.0/0"]
    }
    description = "${var.app_name} Load Balancer"
}

resource "aws_security_group" "web_sg" {
    name = "${var.app_name} WEB Server"
    vpc_id = "${aws_vpc.vpc_main.id}"
    ingress {
        from_port = 22
        to_port = 22
        protocol = "tcp"
        cidr_blocks = ["${var.root_segment}"]
    }
    ingress {
        from_port = 80
        to_port = 80
        protocol = "tcp"
        cidr_blocks = ["${var.root_segment}"]
        security_groups = ["${aws_security_group.lb_sg.id}"]
    }
    egress {
        from_port = 0
        to_port = 0
        protocol = "-1"
        cidr_blocks = ["0.0.0.0/0"]
    }
    description = "${var.app_name} WEB Server"
}

RDSの作成

RDS用のサブネットグループを作成する部分が少しはまりました

resource "aws_db_instance" "default" {
  allocated_storage       = 5
  identifier              = "${var.rds_name}"
  engine                  = "${var.rds_engine}"
  engine_version          = "${var.rds_engine_version}"
  instance_class          = "${var.rds_instane_type}"
  name                    = "${var.rds_db_name}"
  username                = "${var.rds_user}"
  password                = "${var.rds_pass}"
  db_subnet_group_name    = "${aws_db_subnet_group.default.id}"
  parameter_group_name    = "${var.rds_parameter_group}"
  vpc_security_group_ids  = ["${aws_security_group.mysql_sg.id}"]
  backup_retention_period = "1"
  backup_window           = "17:08-17:38"
  storage_type            = "gp2"
  maintenance_window      = "Sat:13:38-Sat:14:08"
  multi_az                = false
  apply_immediately       = true
  publicly_accessible     = true
}

resource "aws_db_subnet_group" "default" {
  name = "default-${aws_vpc.vpc_main.id}"
  description = "Our main group of subnets"
  subnet_ids = ["${aws_subnet.vpc_main-public-subnet1.id}","${aws_subnet.vpc_main-public-subnet2.id}"]
}

s3の作成

ポリシーを設定する場合は外部に用意したポリシーのjsonを読み込ませて設定してみました。

resource "aws_s3_bucket" "b" {
    bucket = "${var.s3_bucket_name}"
    acl = "private"
    policy = "${file("s3_bucket_policy.json")}"
}

elbの作成

# Create a new load balancer
resource "aws_elb" "default" {
  name = "${var.elb_name}"
  security_groups = ["${aws_security_group.lb_sg.id}"]
  subnets = ["${aws_subnet.vpc_main-public-subnet1.id}","${aws_subnet.vpc_main-public-subnet2.id}"]

  listener {
    instance_port = 80
    instance_protocol = "http"
    lb_port = 80
    lb_protocol = "http"
  }

  health_check {
    healthy_threshold = 2
    unhealthy_threshold = 2
    timeout = 5
    target = "HTTP:80/index.html"
    interval = 30
  }

}

dynamoDBのテーブル作成

range_keyがソートキーになります

resource "aws_dynamodb_table" "users" {
    name = "${var.dynamodb_prefix_name}.users"
    read_capacity = 1
    write_capacity = 1
    hash_key = "id"
    range_key = "username"
    attribute {
      name = "id"
      type = "N"
    }
    attribute {
      name = "username"
      type = "S"
    }
}

Nが数値、Sが文字列、Bがバイナリです。

elasticacheの作成

redisを作成してみた

resource "aws_elasticache_cluster" "redis" {
    cluster_id = "${var.cache_cluster_name}"
    engine = "redis"
    node_type = "${var.cache_instane_type}"
    port = 6379
    num_cache_nodes = 1
    parameter_group_name = "${var.cache_parameter_group}"
    security_group_ids = ["${aws_security_group.redis_sg.id}"]
    subnet_group_name = "${aws_elasticache_subnet_group.subnet.id}"
}

resource "aws_elasticache_subnet_group" "subnet" {
    name = "${var.cache_cluster_name}"
    description = "${var.cache_cluster_name}"
    subnet_ids = ["${aws_subnet.vpc_main-public-subnet1.id}","${aws_subnet.vpc_main-public-subnet2.id}"]
}

IAMロールの作成

いろいろ躓きました・・・。 IAMロールの作成の場合、

  • ロールの作成
  • 管理ポリシーをアタッチ
  • インラインポリシーをアタッチ

という形なのですが、terraformではポリシーのリソース作成でIMAロールを指定します。 また、IAMロール作成時、「信頼されたエンティティ」のID プロバイダーとして amazonを追加しないと使えないところがはまりました。(普段意識していなかったので・・・)

IAMロールの作成。 信頼されたエンティティにec2.amazonaws.comを設定しています。

resource "aws_iam_role" "sample_role" {
    name = "${var.sample_iam_role_name}"
    assume_role_policy = &lt;&lt;EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF
}

作成したロールに管理ポリシーをアタッチ 管理ポリシーの場合はポリシーarnを直接記述します。

resource "aws_iam_policy_attachment" "dynamodb" {
  name = "AmazonDynamoDBFullAccess"
  roles = ["${aws_iam_role.sample_role.id}"]
  policy_arn = "arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess"
}

作成したロールにインラインポリシーをアタッチ インラインポリシーの場合はpolicyのjsonを直接記述します

resource "aws_iam_role_policy" "sqs_policy" {
  name = "AmazonSQSFullAccess"
  role = "${aws_iam_role.sample_role.id}"
  policy = &lt;&lt;EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "sqs:*"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}
EOF
}

EC2インスタンスの作成

作成したIAMロールを関連付けたインスタンスを作成します。 ついでに固定IPもつけてみました。 インスタンスに関連づける場合は「aws_iam_instance_profile」でまず インスタンスプロフィールを作成する必要があるようです。

こちらのリソースで作成したnameの値をaws_instanceのiam_instance_profileで指定すれば うまくいきました。

resource "aws_iam_instance_profile" "sample_role" {
    name = "sample_role"
    roles = ["${aws_iam_role.sample_role.name}"]
}

resource "aws_instance" "sample" {
    ami = "${var.sample_ami}"
    instance_type = "t2.micro"
    vpc_security_group_ids = ["${aws_security_group.sample_sg.id}"]
    subnet_id = "${aws_subnet.vpc_main-public-subnet1.id}"
    iam_instance_profile = "sample_role"
    associate_public_ip_address = true
    key_name = "${var.key_pair_name}"
    tags {
        Name = "${var.sample_tag_name}"
    }
    root_block_device {
        delete_on_termination = "true"
    }
}

# 固定IPもつけてみる
resource "aws_eip" "lb" {
    instance = "${aws_instance.sample.id}"
    vpc      = true
}

AutoScalingの設定

こちらはあまりうまくいってないので使ってないですが、うまくいかなかったりうまくいったりします。

resource "aws_launch_configuration" "as_conf" {
    name_prefix = "${var.launch_config_name}"
    image_id = "${var.sample_ami}"
    instance_type = "t2.micro"
    iam_instance_profile = "api_role"
    security_groups = ["${aws_security_group.sample_sg.id}"]
    key_name = "${var.key_pair_name}"
    associate_public_ip_address = true

    lifecycle {
        create_before_destroy = true
    }

    root_block_device {
        volume_type = "gp2"
        volume_size = "24"
        delete_on_termination = true
    }
}

resource "aws_autoscaling_group" "sample" {
    name = "${var.auto_scaling_group_name}"
    vpc_zone_identifier = ["${aws_subnet.vpc_main-public-subnet1.id}","${aws_subnet.vpc_main-public-subnet2.id}"]
    launch_configuration = "${aws_launch_configuration.as_conf.name}"
    max_size = 0
    min_size = 0
    desired_capacity = 0
    default_cooldown = 300
    health_check_grace_period = 300
    health_check_type = "EC2"
    load_balancers = ["${aws_elb.default.name}"]
    force_delete = true
    tag {
        key = "Name"
        value = "${var.api_tag_name}"
        propagate_at_launch = true
    }
}

root_block_deviceやelb_block_deviceを使うと以下のようなエラーが出てしまう為、現在はあまり使用していません。

Error refreshing state: 1 error(s) occurred:

* aws_launch_configuration.as_conf: Invalid address to set: []string{"root_block_device", "0", "encrypted"}

こちら、お分かりにな方がいたらご教授頂きたいです・・・

怖いところ

「割と軽微な修正」だと思って修正すると インスタンスが削除されたりする可能性があります。

例えばインスタンスのIAMロールを変更はインスタンスの立ち上げ時にしか変更できないのですが terraformでIAMロールを変更してterraform applyすると、インスタンスは削除されて新規作成される、、 という動作となります。

これはどう考えてもterraformが正しい動作をしているのですが 本番環境などでterraform applyを実行するのは怖すぎるな・・・と思いました。

個人的なTerraformの使いどころ

おなじような機能にAWS公式サービスのCloudFormationがありますが、 構成を管理してしまうところが嫌だと感じていました。

つまり初回構築だけ実行したい、、、という事ができないわけです。 もちろんTerraformにも構成管理をする機能はありますが プロバイダ非依存である為、このあたりは柔軟に対応できます。

あと設定ファイルがjsonではないのでコメントなども書けるのもいいですね。 InteliJにはterraform用のプラグインもありますので 設定ファイル作成もしやすいです。

というわけで個人的には 「初期構築用ツール」、もしくは「開発環境構築ツール」として利用していこうと思います。 destroyでサクッと全部消えるのはとても便利

逆に構成を管理させたい場合は WEB GUIにて変数をフォームで渡して実行、、って事ができるので やはりCloudFormationの方がいいかなぁと感じています。 (AutoScaleはCloudFormationを使う事が多いです)

情報セキュリティマネジメント試験(SG) がはじまります

blog_img_4185
こんにちは。

IPA(情報処理推進機構)の情報処理技術者試験に新しい試験区分が追加されましたね。 その名も、、、

情報セキュリティマネジメント試験(SG) [ Information Security Management Examination ]

じゃじゃーん、、すごく難しそうな試験名(笑)

対象者像は以下のとおりです。

情報システムの利用部門にあって、情報セキュリティリーダとして、部門の業務遂行に必要な情報セキュリティ対策や組織が定めた情報セキュリティ諸規程(情報セキュリティポリシを含む組織内諸規程)の目的・内容を適切に理解し、情報及び情報システムを安全に活用するために、情報セキュリティが確保された状況を実現し、維持・改善する者

 

  • 春期・秋期実施
  • 試験時間・出題形式・出題数(解答数)

内容みてると

ITパスポート <= 情報セキュリティマネジメント試験 < 基本情報処理

みたいな位置づけですかね。最近はこども向けのプログラミング教室があったり、国も施策として考えているみたいですし、試験区分が増えて、IT業界が盛り上がって行くのはいいことですね。これでブラックなイメージが払しょくされればいいのですが(涙)個人的にはLPIC系の国家資格ができればいいのになぁと思う今日この頃です。 今年も何か受験したいと思います。(これは受けないけど(笑))

■参考 https://www.jitec.ipa.go.jp/1_11seido/sg.html https://www.jitec.ipa.go.jp/sg/