Rails開発者が片手間にインフラ業務こなして得た知見

## はじめに

[Co-Edoでエンジニア・webデザイナー飲み会『泡の出る飲み物とケンタッキーを楽しむ日』](https://coedo-dev.doorkeeper.jp/events/51340)のLT資料です

- 前提として
  - 俗にいうスタートアップな会社（社員数は数十名という感じ）でエンジニアは自分以外に2名おり、共にインフラ詳しくないということでその部分を補う感じで業務委託メンバーとして参画
  - お手伝いを始めたのは2016年6月〜


-----------

## この3ヶ月ほどやったことを振り返る

とにかくブラックボックス化していたものを可視化

- 本番環境の構成を知らべつつAnsibleで設定ファイルの可視化＆コード化
  - なぜその変更を行った・行うのかというのを将来の自分（他人）のために残す
- ログ分析基盤構築
  - fluentd+Embulk+BigQueryでログ集約化
  - （管理機能を除いた）RailsのControllerのログ
  - 集約したログは、Re:dashで好きなように分析
- インフラ部分もRSpec!
  - serverspec
  - nginxの設定がちょっと複雑＆今後変更予定の作業があるので振る舞いをRSpec＋RestClientでコード化
- AWSベースのシステムだったので構成図を作る
  - 外部連携する箇所多いからそこも図

-----------

### 可視化した結果の成果物

Re:dash | AWSの構成図
-----|----------
![ 2016-09-09.png](https://qiita-image-store.s3.amazonaws.com/0/10187/fd7ce1ec-cde5-cb56-584d-db38c68bd9db.png)| ![ 2016-09-08 18.34.16.png](https://qiita-image-store.s3.amazonaws.com/0/10187/8f938367-0b6d-492a-2f29-4b326a5434f4.png)



-----------

### インフラ部分もRSpec!

折角なのでRSpec+RestClientのサンプルを！

```rb

require 'rest-client'
require 'pry'

describe 'Web site' do
  let(:base_site_urls) do
    [
      'https://production.oursite',
      'https://stage.oursite'
    ]
  end
  it "HTTPステータス200を返す" do
    base_site_urls.each do |base_site_url|
      response = RestClient.get "#{base_site_url}/home"
      expect(response.code).to eq 200
    end
  end
  context '管理ページの場合' do
    it "HTTPステータス401を返す" do
      base_site_urls.each do |base_site_url|
        begin
          response = RestClient.get "#{base_site_url}/admin"
        rescue => e
          response = e.response
        end
        expect(response.code).to eq 401
      end
    end
  end
  context 'Amazon S3 から配信されてる特集ページの場合' do
    let(:sp_contents) do
      ['s3 HostingのサイトのURL']      ]
    end
    it "S3固有のヘッダ情報が確認できる" do
      sp_contents.each do |sp_content|
        response = RestClient.get sp_content
        expect(response.headers[:x_amz_id_2].empty?).to eq false
      end
    end
  end
  context 'WordPressが利用されてる場合' do
    context '/xxxxx/の場合' do
      it 'response.headersにPHP情報が含まれる' do
        base_site_urls.each do |base_site_url|
          response = RestClient.get "#{base_site_url}/blog/"
          expect(response.headers[:x_powered_by].include?('PHP')).to eq true
        end
      end
    end
  end
end
```

---------

### Rails部分の仕事

- ちょっとした機能追加開発
- （あるあるネタだけど）テストがほとんどなくRuby/Railsのアップグレードやりづらい状態なのでちょっとづつテストを書いていく
- フロントがカオスだったのでちょっとづつ整備
  - ひとまずデザインリニューアル控えてることもあり既存のCSSは一旦無視してSMACSSなガイドライン作って新規に作成

-----------


## 本題の片手間にインフラ業務こなして得た知見

以下3つ説明します

- メール関連のトラブル
- もうすぐできるけどRe:dashベースでトラブルシューティング
- ステージング環境は使う時だけ起動

-----------

### メール関連のトラブル

メール送信にからむトラブル対応難しい・・・　でも頑張って対応したのでだいぶ把握理解進んできた

- メール送信がたまにうまくいってないという報告を受ける
  - 具体的にはRails＋ActionMailer+AmazonEC2＋Postfix→ Amazon SESという構成の箇所
  - 報告受けて、初めてこの辺りの設定の不備に気づく
  - AWS EC2 Eメール上限緩和 / 逆引き(rDNS)設定 申請手順で解決
- Zendeskのパブリック返信時にメールが届いてないっぽいと言われた
  - SPFレコード設定の不備
- バッチ処理でリマインドメール送って届いてないケースがあるっぽいので調査頼まれる
  - 過去に会員登録したメールアドレスが今も存在してるとは限らない＆何らかの理由でメール受信が一時的に出来なくなってる
  - SMTPのRCPT TOコマンド的な処理を入れる処理を作った（これは2016年9月9日実装）

-----------

#### 折角なのでメールアドレスの確認をどうやったか記載

[Ruby で メールアドレスの有効性チェックしてみた](http://qiita.com/yutackall/items/ce9285ecdf2f03db0404)をほぼ流用してこんな感じの処理を入れるようにした

```rb

class EmailExistValidator
  def self.validate(email)
    domain = email.split("@").last
    records = Resolv::DNS.open do |dns|
      dns.getresources(domain, Resolv::DNS::Resource::IN::MX)
    end
    unless records.empty?
      begin
        Net::SMTP.start(records.first.exchange.to_s, 25, 'ourdomanname.xxx.xxx')do |smtp|
          smtp.mailfrom("my mail address")
          res = smtp.rcptto(email)
          { email: email, result: true, domain: true, status: res.string.chomp }
        end      
      rescue
        { email: email, result: false, domain: true, status: $!.message.chomp }
      end
    else
      { email: email, result: false, domain: false, status: "domain not exists" }
    end
  end
end
```

-----------

### Re:dashベースでトラブルシューティング

もうすぐ出来る仕組みだけど

- これまで
  - 何かトラブル発生
  - サーバーにSSHしてトラブル発生時の時間を頼りに、production.logをgrep
- これから
  - ユーザさんの一連操作を識別できるように、ログフォーマットを工夫
  - サーバーにSSHしなくてもRe:dash上でクエリーを投げて調査
    - 理論上は非エンジニアの人でもトラブルの原因調査は出来るかも 


-----------


### ステージング環境は使う時だけ起動

AWS Data Pipelineを活用！

- バッチ処理とかのジョブスケジューリング的な活用がData Pipelineの使い方が割りとよくある使い方っぽい
- AWS CLIで出来る操作はAWS Data Pipelineからは簡単にできることに気づき、インスタンスのシャットダウン＆起動をスケジューリング

#### AWS CLIのシャットダウンコマンド

```sh
aws ec2 stop-instances --instance-ids i-xxxx1 i-xxxxx2 --region ap-northeast-1
```

#### 起動

```sh
aws ec2 start-instances --instance-ids i-xxxx1 i-xxxxx2 --region ap-northeast-1
```

-----------

## 最後に感想を

- 全部の作業をこなすのは無理。
  - 可視化して全体像を関係者間で共有出来るのが大事
- 気持ち悪い所はたくさんあるけど **サービスの成長とかビジネスの売上につながらないのならそこはひとまずスルーする力** が大事