まーぽんって誰がつけたの?

iOS→Scala→インフラなおじさん技術メモ

Google Cloud Platformの環境をterraformで作る

そもそもGoogle Cloud Platformとは

Googleが出してるAWS的なやつ。GCPと略す。だいたいの比較表。

dev.classmethod.jp

なんでAWS使わないの?

コンテナでぽんぽんアプリケーションをdeployしたいんだけどそれをAWSでやろうとすると、ECSというサービスを使うことになる。でも、このECSというのがdeployまわりの取り扱いがめんどくさくてちょっといけてない。 で、同じようなコンテナのスケジューリングとかやってくれるソフトウェアでkubernetesというのがあるんだけど、それをAWS上にたてようとするとちょいめんどい。GCPにはGKE(Google Container Engine)というkubernetesのマネージドサービスが最初から用意されてるのでこれを使いたいから。

GCPにおけるprojectという概念

GCPは一つのアカウントに対して、projectという概念を持ってる。たくさんprojectは作ることができる。すごくざっくりだけど、AWSでいうVPCぐらいの単位かも。

GCPにおける地域とゾーン

GCPにもAWSでいうregion的なやつがある。

  • AWSでいうregionはGCPだと地域で、アジアだと日本(asia-northeast1)と台湾(asia-east1)がある
  • AWSでいうazはGCPだとゾーンと言って、日本には1a〜1cまである。

GCPのprovider

ここからterraformの話。とにもかくにもproviderを定義する。 GOOGLE CLOUD PROVIDER | terraform

provider "google" {
  credentials = "${file("../account.json")}"
  project = "elated-bebop-161001"
  region = "asia-northeast1"
}
  • account.jsonというのは、GCPのコンソールから認証情報(秘密鍵が書いてある)ファイルをjson形式で落としてきたもの。
  • projectは上で言及してるもので全GCP上で一意になるもの。Project名ではなくIDが振られるのでそれを書く。
  • regionは地域。ここでは日本を指定する。

terraformの実行🚀

terraformコマンドで直接実行してもいいけど、いろんなprojectを掛け持ちしてるとローカルのversionを揃えるのが大変なので、docker imagesで提供されているものを使う。 参考にしたサイト 実行するときにいろんなことをしたり、長いコマンドうつの面倒なのでRakefileを作ってそれで実行する。

Rakefileの中身とはまったポイント

  • 🙅 terraformのdocを見るとGOOGLE_CREDENTIALSに認証情報のjsonの中身をつめて渡せばそれを使ってくれるとかいてあったが、これをdockerのコマンドに渡すようにするとstdoutに表示されてしまう
  • 😓 出力されないように環境変数jsonの中身をいれようと試行錯誤したが、jsonの末尾の改行を取り除かないといけないのと、private keyが記述されてるのでそこに文字列として\nが入っててそれが環境変数として渡すと評価されてしまって改行扱いになってしまう

docker実行時に、GOOGLE_APPLICATION_CREDENTIALSで認証情報のファイルの場所を渡してあげるようにする💯

@terraform_version = "0.8.8"

@docker = %Q(docker run --rm -v ${PWD}:/work -w /work/terraform -e GOOGLE_APPLICATION_CREDENTIALS=/work/account.json hashicorp/terraform:#{@terraform_version})

namespace :tf do
  task :init do
    sh %Q(#{@docker} remote config \
            -backend=gcs \
            -backend-config="bucket=my-first-project-terraform-state-20170309" \
            -backend-config="path=terraform.tfstate" \
            -backend-config="project=elated-bebop-161001")
  end

  task :plan do
    sh %Q(#{@docker} plan)
  end
end

まとめ

俺はなぜあんな無駄な時間を・・ by 三井 寿

teeコマンドの使いどころ

標準入力を標準出力とファイルに出力する

というコマンドです。

なんか使いどころが分からないなーって思ってたけど、コマンドの結果をファイルに書き出してそれを別のコマンドに渡すってのをcircle ci上でやってて、あー、画面上でもこのファイルの中身見たいなーって思って、あっ!こういうときにteeを使いたくなるのか!!!ってなった。

terraformでif文的なものを使ったユースケース例

usecase

EC2インスタンス、ELB、security_groupあたりがまとまったmoduleがあるんだけど、特定の役割のインスタンスにだけiam_roleにSNSFullAccessをつけたい。

設定内容

  • allow_sns_full_accessっていう変数宣言しとく。
variable "allow_sns_full_access" {
  default = false
}
  • 対象のリソースでtrueならcount = 1、falseならcount = 0にする。
resource "aws_iam_role_policy_attachment" "app_sns_full_access" {
  count = "${var.allow_sns_full_access ? 1 : 0}"
  role = "${aws_iam_role.app.name}"
  policy_arn = "arn:aws:iam::aws:policy/AmazonSNSFullAccess"
}
  • 利用したいやつだけ、trueにする
module "app" {
  source = "../modules/app"

  allow_sns_full_access = true
}

結果

+ module.app.aws_iam_role_policy_attachment.app_sns_full_access
    policy_arn: "arn:aws:iam::aws:policy/AmazonSNSFullAccess"
    role:       "app"

AWSのロードバランサーあたりのセキュリティーグループ制限がさくっと緩和できなかった

http://docs.aws.amazon.com/ja_jp/general/latest/gr/aws_service_limits.html#limits_elastic_load_balancer

ロードバランサーあたりのセキュリティグループ 5

ご担当者様

平素よりお世話になっております。
AWSカスタマーサービスの藁品でございます。

折角ご申請いただきましたのに誠に申し訳ございませんが、「Classic Load Balancer」の
「ロードバランサーあたりのセキュリティグループの上限」を緩和することは致しかねます。
理由といたしましては、「ロードバランサーあたりのセキュリティグループ」は
「ネットワークインターフェースあたりのセキュリティグループ」に基づいている為でございます。

なお、下記サービスの上限値の変更を行うことで「ロードバランサーあたりのセキュリティグループの上限」の
緩和をすることも可能でございますが、この変更を行うことによりネットワークインターフェースを使用している
全リソースに影響を及ぼしますのでご留意くださいませ。

1) セキュリティグループあたりのインバウンド/アウトバウンドルール(デフォルト50)を減らす。
2) ネットワークインターフェースあたりのセキュリティグループを(デフォルト5)増やす。

引き続き緩和をご希望ということであれば、ケースにご返信いただくかたちでお知らせいただければ幸いです。
その他ご不明点、ご要望等ございましたら、ご遠慮なくお問い合わせくださいませ。

何卒よろしくお願いいたします。

terraformでsecurity groupをmodule化するときに気をつけること

IPアドレスを定義した共通のsecurity groupを作りたい

あるプロジェクトで外部のIPアドレスなどをまとめたものをsecurity groupとしてmodule化している。このアイディア自体はいいんだけど、環境ごとにこれを利用しようとした場合に失敗する。

例えば、こんな感じでmodulesに外部IPを書いたようなsecurity_groupをつくる。

terraform
├── development
│   └── main.tf
├── staging
│   └── main.tf
├── production
│   └── main.tf
└── modules
    └── external_ips_sg
        ├── security_group.tf
        └── outputs.tf

で、これらを各環境のmain.tfで利用すると、同一のsgを作ろうとするので、security groupの名前を変える必要がある。

module "external_ips_sg" {
  source = "../modules/external_ips_sg"
}

ここで、security groupのnameを変数化しておかないと同じ名前のsecurity groupを作ろうとして失敗する。

解決策

当たり前の話だけど、変数でnameを変えられるようにしておく。

└── modules
    └── external_ips_sg
        ├── variables.tf
        ├── security_group.tf
        └── outputs.tf
variable "env" {}
variable "vpc_id" {}
module "external_ips_sg" {
  source = "../modules/external_ips_sg"

  env = "dev"
  vpc_id = "vpc-xxxxxxxx"
}
resource "aws_security_group" "a" {
  name = "external-ips-${var.env}"
  vpc_id = "${var.vpc_id}"

ちなみに、Security GroupのDescriptionはForce new Resourceなのであとから変更できないので、何も設定しない方がいいかも。ちょっと文言変えたいなーってときにもう変更できない。何も設定しなければ、 Mangaed By Terraformのデフォルト文言が設定される。何か名前付けをしたい場合は、TagのNameを使おう。 あと、vpc_idを入れるのを忘れがち。vpc_idはなければ自動的にdefautl vpcが設定されるのでうまくいってしまう。

awsのsecurity groupにはルールの上限がある

IPアドレスをたくさん追加しようとしたら:scream:

各拠点のIPアドレスを追加してほしいという依頼で、terraform planで問題なかったので、applyしたらエラーが出た。

* aws_security_group.elb_app: Error authorizing security group ingress rules: 
RulesPerSecurityGroupLimitExceeded: 
The maximum number of rules per security group has been reached.
    status code: 400, request id: 88277351-1fc1-4e48-a005-3fe046a8145b

制限があるのを知らなかった。ドキュメントによると制限は50だった。

http://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/VPC_Appendix_Limits.html#vpc-limits-security-groups

多分手動で追加してれば51個目でエラーになるから気づけるけど、terraformだとapplyしてはじめてエラーになる。なので、エラーになった瞬間、該当のsecurity groupの設定は空っぽになってしまう。

気をつけよう :cry:

とくにsecruty groupの変更は要注意

ingressとか書くときに、cidr_blocksと、security_groupsを指定できるけど、つい間違ってcidr_blocksの方にsecurity_groupのidを指定しまったことがあった。これも、planのときは問題ないけど、applyで指定方法が間違ってるってことでエラーになる。

ingress {
...
  cidr_blocks = [
     "${aws_security_group.hoge.id}"
  ]
}

まとめ

validateしたい。terraformにPRチャンスかもしれない。

aws_security_groupのdescriptionはupdateできない

descriptionを気軽な名前で作ってしまって、あとでちょこっと変更したいなーと思って terraform planするとforce new resourceになってしまう。

ドキュメントにも書いてあった。

AWS: aws_security_group - Terraform by HashiCorp

description - (Optional, Forces new resource) The security group description. Defaults to "Managed by Terraform". Cannot be "". NOTE: This field maps to the AWS GroupDescription attribute, for which there is no Update API. If you'd like to classify your security groups in a way that can be updated, use tags.

aws_security_groupは気軽にdescriptionを設定しないようにしよう!識別したいだけなら、tags.Nameを使えばok

今日覚えたやつメモ 2017/1/27

rubyとかrailsとかRSpecのこと

fluentdのこと

dockerとmacでunix domain socketを共有する

ECSでの動的なネットワークポートマッピングとfluentd

固定ポートだとインスタンスの数以上にコンテナが増やせない

ECS上でfluentdを複数コンテナで動かして集約サーバーとして動かそうとしている。 最初だから試しにautoscaling groupで1つのインスタンスだけ立ち上げて、コンテナを2つ(desired count = 2)なサービスで立ち上げようとした。

でも、2台目のコンテナはportが埋まってますよというエラーで立ち上がってくれずにstoppedになってしまう。 そう言われてみればそうだなと。

ALBなら動的なネットワークポートマッピングが可能だが・・

Amazon ECSのELB構成パターンまとめ(ALB対応) | Developers.IOとか、Amazon ECS と AWS Application Load Balancer の組み合わせを試しているメモ - ようへいの日々精進XPとかを見ると動的にポートマッピングしてるからALBを使えばいけそう。しかし、healthcheckはHTTPかHTTPSでやらないといけない。

fluentdの集約サーバーはforwardプロトコルで24224で待ち受けていて、ELBならTCPでのhealthcheckでOKなので問題なかったが、ALBにするならばHTTPでhealthcheckできるようにしないといけない。 healthcheckに関してはfluentdはin httpも受け付けているのでそれでhealthcheckできるようにすればいける。

ただ、healthcheckはいけたとしても、結局forward Output Pluginはforward protocolでhttpじゃないのでダメだ。。

まとめ

集約サーバー側でforwardを使う限りALBは使えない。

fluent-plugin-s3でなかなかs3にアップロードされない

github.com

time_slice_formatの値をexampleに従って、%Y%m%d-%Hにしたんだけど、なかなかs3にアップされない。 buffered_pathには吐かれてるんだけどなかなかS3には上がってこない。

instanceのpoliciyかなーとかs3のbucketのpoliciyかなーとか色々迷っててうーんってハマってたらいつのまにかアップされてた。 どうやら1時間ぐらいたってた。

で、これはなぜかっていうと、time_slice_formatが時間ごとの値になってるからファイル名が変更になるまではs3にアップされない。s3にアップされて欲しいintervalを設定するのが、flush_intervalだった。 flush_intervalはplugin-s3のものではなく、そもそもbuffered-outputのもの。 flush_interval 60sと書けば1分ごとにs3にアップされた。

terraformのecs_registry.repository_urlにhttpsがついてるのを消す

バグだったようだ。mergeされたのでそのうち修正版がリリースされるはず。それまでは"${replace(aws_ecr_repository.test.repository_url, "https://", "")}"でしのぐ。

github.com

追記

terraform v0.8.5 で取り込まれた。

ECS(Amazon EC2 Container Service)がなんなのかやっと理解できてきた

いざ自分で一から作ってみると・・・

今まで人が作ったECS上でサービスの作成とか更新とか、タスクの更新とかやってきてなんとなく使えてたけど、 いざ自分で一から作ってみるとそれぞれの要素がどうなってるのか何も分かってないことに気づいた。 今まではECSでclusterとserviceを作っていって、clusterとかserviceに対して全体的なネットワークとかインスタンスの数とかの設定をしていくものだと思ってたけどそうじゃなかった。

ECSの役割

ECSがやってるのは主にスケジューラ(どのインスタンスにどのコンテナをいい感じに配置するか)がメインで、コンテナーインスタンスamazon-ecs-agentをおいてecsサービスのAPIを叩かせている。

じゃあ、全体的なネットワークの設定はどうするのかっていうと、ただのAuto Scalingという機能を使っていつも通りインスタンスを立ち上げてるだけ。なんならAuto Scalingを使わずに手動でAMIからインスタンスたちあげて、それをECSにコンテナーインスタンスとして登録したってよい。

GUIのウィザードでECSを作ろうとすると至れり尽せりでいい感じに色々なものができる。で、今やろうとしてるのはterraformで一から作ろうとしてるところだから、必要なものがなんなのか、どんな機能の組み合わせでできてるのかが分からないとterraformを書くことができない。進みは遅いし苦しいけど勉強にはなる。

ecs-agentの起動方法

会社の既存プロジェクトとかterraformのexampleを見てると、launch_configurationでuser_dataで結構がっつりシェルが書いてある。でも、AWS Consoleでウィザード経由で作ると、これだけ。

#!/bin/bash
echo ECS_CLUSTER=hoge >> /etc/ecs/ecs.config

一体この違いはなんなんだ・・ってはまったけどlinuxのdistributionが違ってた。見てたexampleとかはcoreOSとかubuntuとか。一方で、ウィザードだとamazon-linuxのecs-optimizedてやつ。だから色々書かずに済んでたんだ。 amazon-ecs-agentのREADMEにその辺のことが書いてあった。

まとめ

ちょっとすっきりした

terraformで作るときに参考にするもの

社内のプロジェクトのを参考にできる恵まれた環境なのでまずはそれを見る。

他にもterraform公式リポジトリにあるexampleも参考になった。 terraform/examples at master · hashicorp/terraform · GitHub

インフラエンジニアになっていきたいと思った理由

今の思い

ここでいうインフラエンジニアはハードディスクがとかケーブルがとかガチなやつじゃなくて、各種スタックを組み合わせて構築するぐらいのやつ。 プログラミング歴=ほぼ社会人歴で、iOS開発がメインで一番長かった。そのあとScalaでサーバーサイド。で、今はインフラできるようになりたいと思ってる。

iOSエンジニアとしてサーバーサイドへの引け目

iOSは動く画面を作るのが楽しかった。ただ、すぐに太ってしまうUIViewControllerやたくさんのManagerクラスなどクソコードもいっぱい生み出してきてしまった。なので、Clean Architectureとかもっといい設計はないかとかを考えるのが楽しかった。 でも、なんとなくサーバーサイドとかWebのことが分からないことに引け目をずっと感じていたが、プロジェクトの状況で幸か不幸かサーバーサイドが足りないとなり、がっつりサーバーサイドの開発に携わることもできた。 はじめはWebの基本的なこととか効率的なSQL、DB設計とかが分かってなかったりScalaの関数型的な書き方が分からず苦しかったけどそこそこできるようになった。

解決できる領域の広さ

でも、サービスを運営してると障害起きたりしてもインフラ周りだと手も足も出せないのが悔しく、あと、何かXXXという問題を解決したいっていう時に、アプリケーション側で色々苦労して解決できたとしてもインフラ側でそれを何十倍の効果で解決しちゃったりする場面があって、それも悔しかった。なので、出来るようになりたい。

あとアプリもサーバーサイドも保守しやすいとか変更しやすいとかの設計を考えるのは楽しいし、実力もまだまだなんだけど、普通ぐらいのレベルにはなったなという気がしてる。

新しいことを覚える楽しさ

インフラは0だからそれを普通にする方がワクワクする。ほんの1ヶ月前は分からなかったことが分かるようになる感覚がたまらない。 ドラクエ3で言えば転職をしてレベルが1に戻るのを繰り返してる。 最初は簡単なことも分からず進捗も悪くてかなり苦しいんだけど、だんだんできるようになっていくのが好き。マゾなのかもしれない。