【レポート】「実践SERVERLESS」に参加しました。

はじめに

AWS Lambdaが出てからだいぶ経ちますが、プロダクションとしての実績も
チラホラ聞こえるようになり何かしら勉強会ないかな?と思っていたところに
調度良い勉強会があったため、参加しました。

classmethod.connpass.com

最初は補欠でしたが、当日になり繰り上げ当選となったのは
ほんと運が良かったと思います。

後日、スライドが上がると思いますが、取り急ぎメモした内容を書きます。

セッション

Introducing Serverless Computing

Serverlessが使えるところや事例を聴くことができました。

活用するシステム一例

  • リアルタイムファイルプロセッシング

    • イメージ変換(サムネイル作成)
    • ドキュメントのメタデータのインデックス化
    • ログの処理
    • メディア・コンテンツのバリデーション
  • リアルタイムストリームプロセッシング

    • ストリーム分析
    • メトリクス作成
    • インデクシング

Serverless Web and Mobile Application

下記のものを使うのが定番となっている。

新しいエコシステム

AlexaアプリとSlackを使い、ServerlessでのBotを実現できる。

AWS CloudTrailでログ管理

APIの呼び出しログを管理する「CloudTrail」と連携してログ監視を行える。

事例

海外
  • VidRoll
  • PlayOn! Sports
  • easy ten
国内

Lambda と API Gateway の管理

サーバーレスの役割

  • どこをサーバーレスにするか?
    • いろんなところでできる。
  • フロントエンド
    • 通信データ取得や登録を行うところ
  • バックエンド
  • その他

管理方法の選定

管理ツールはたくさんある。 →ツールごとに観点が違う。

Lambda管理ツールを選ぶ4つのポイント

ツールの特徴
  • API Gatewayの併用
  • 対象は、API Gateway + Lambda、Lambdaのみの2パターン
  • セットはフロントエンドを対象としているツールが多い
  • Lambdaのみを対象としているツールは、汎用的に導入しやすい
他のリソース管理

観点は以下のとおり

  • システムの規模の大きさによって変わってくる。
  • 大きくなったら、分割するほうが良い。
  • 小さい場合は、まとめた方が良い。
ロールバック

リリース時などに障害が起き、前の状態に戻したい場合がある。
その際に管理ツールでできるかどうか。

  • 対応しているツールとしていないツールがある。
  • 対応しているのは手早くロールバックできる。
使い回し

一度、作ったものはある程度汎用的の方が良い。
ただし、考えて作らないといけない。

  • そのアーキテクトは他で使いまわせるか?
  • 汎用性にする必要はあるか?
  • 設定値は実行時パラメータを使うか?
  • 環境変数は必要か?

管理ツール6種

今回は6種ですが、他にもたくさんあるとのこと。

  • AWS Cloud Formation
    • AWSのプロダクトで管理できる
    • JSONでFunctionを管理
  • Serverless
    • フロントエンドとして管理
    • API Gateway, Lambdaを管理、デプロイできる
    • このツールで動作確認もできる
  • Apex
    • Lambdaに特化
    • Terraformと連携できる
  • Gulp (node-aws-lambda)
    • node-aws-lambda以外にもライブラリがある
    • ZIPで固めてデプロイする
    • 動作確認する場合は、AWSコンソールでやる必要がある
  • Swagger hub
    • Swaggerのクラウドサービス
    • IAMのポリシーも作ってくれるので便利
  • Chalice (Beta)
  • Flourish
    • Serverless Confで発表されたもので、そろそろ出てくる?

まとめ

  • 何を重要視するか?(フロントエンド全部か一部だけか)
  • プロジェクトにあった、最適なものを選択すること
  • まずは、触ってみてとのこと

実際に使う Cognito UserPools

すでに資料は公開されています。

cognito-userpools-in-production // Speaker Deck

Serverlessというと確かにLambdaだが、Cognito UserPoolsを使って
Serverlessのシステムを作成することができる。

デモで使用したサンプルは、以下のもの

github.com

※この辺は、自分にとって難しく「便利そう!」というぐらいしかわかりませんでした・・・

まとめ

事例や管理ツールについて詳しく聞けたのが良かったです。
欲を言うと運用方法(監視など)も聞ければ良かったなぁと思っています。
実際に運用されているシステムってどうやっているのでしょうか?気になります。

「Serverless Web and Mobile Application」であれば、比較的手軽に試せそうなので
いろいろ試して、ノウハウを蓄積していこうと思います。

【振り返り】業務で0からシステム構築をしてWebサービスをリリースした話

はじめに

つい最近の話になりますが、小さいWebサービスをリリースしました。
ほんとに小さなもので「これ、作ったんだぜ!」と大きな声で言えないため
細々と嬉しさを噛み締めつつ、1人振り返りしてツラツラ書きます。

これから何かしらリリースする人、リリースしたい人にとって
少しでも有益な情報となり、参考になってもらえればと思います。

チーム

若手が多かったので、それぞれアドバイザーがいましたが、
ディレクター、デザイナー、プログラマ、インフラ含めて
メインは7人ほどで対応していました。

自分はプログラマ側のリーダー的な立場でした。

インフラ

小さいサイトであり、かつ複雑なサイトではないため
「こんな感じでいいよね」という感じでスムーズに進みました。

サーバのランニングコストにもよりますが、最低限、冗長化をして
予期せぬアクセス増加を見据えた方が良いと思います。
なにより運用した際の安心感が違います。

また、同時にSTG環境の用意をしました。
テスト環境なので、そんなに高スペックでなくても良いですが
本番環境でいきなり試すこともできないので、なるべく本番環境と
同等のシステムを構築した方が良いです。

ミドルウェア

新卒から数年間、Javaをやっていましたが、恥ずかしながら
Apacheのメンテ経験は0に近く、実戦経験もなかったので
WebサーバはNginxとしてました。

DBはMySQLにしてレプリケーションを行い 障害に対しての対策を行いました。

アプリ

「小さいサイトなので、効率よく開発できるものを選ぼう」という
考えはあったものの「使いたい言語で開発をしよう!」という
考えもあったので、Ruby (Ruby on Rails)を選択しました。

インフラ(ミドルウェア)構築

過去の案件でAnsibleを使った、構築手順があったので
それを流用させてもらい、今回のシステムにあった形に
書き直しました。

過去に自分で勉強して内容を理解できるところまで
やっておいてよかったと実感した瞬間でした。

コーディング

フロントエンド

デザインが上がってくるまで時間があったため
機能的なところ(バリデーション、テーブル登録)を先に実装していきました。

Railsと便利なGemの数々を使い、レールから外れないようにして
実装をしてもらい、問題なく実装することができました。

後にデザインが上がってきて、デザインの取り込みをしていましたが
やはりリッチな動きとなるとJavascriptやちょっとしたデザイン崩れが発生します。 予期していたことなので、慌てずデザイナーの人に自分の席にきてもらい
対面で一緒に考えてもらいながら対応をしました。 そのおかげで、意思疎通もスムーズに行なえ対応できました。

バックエンド

フロントエンドで登録がある場合、必ずバックエンド(管理画面)が必要となります。
ただし、フルスクラッチで作っている余裕はなく、どうすれば良いか?と
考えていたのですが、2年ぐらい前から勉強がてら作っていたものを流用することにしました。

すでにVPSのサーバで動いているので、自分の中で実績は十分あったので
バックエンドの要件定義の話になった際、サンプルとして画面を見せて
すぐに合意を得ることができました。

ただ、バックエンドもやりたいことはたくさんありますが
期間が期間のた「め本当に必要な機能のみ実装する」ということを
ちゃんと合意を取った上で開発しました。

テスト

残念ながら、Rspecの経験がなく逆にコストが
かかりそうだったため、自動テストはなしとしました。

手で動かしても問題ない規模であったため、どうにかなりました。

リリース

新規サービスということもあり、本番環境は事前に構築しておき
IP制限を行い、社内からしか見れないようにしていました。

そのため、事前に構築→IP制限外して公開ということができたので
安心してリリースを行うことができました。

リリース後

リリースしてみて、気づくこともあり、またバグもあったので
リリース後対応として対応をしています。

ただ、致命的なバグというのはない(と思っている)はずなので
ホッとしています。

反省点

リリース延期ということがなくリリースできましたが
なんやかんやで残業が多かったのが残念なところでした。
ただ、自分が使ってみたい技術をすべて使えたので
100%悪い意味での残業ではなかったです。

次に「限られた期間内でこの規模なら大丈夫だろう」という
思いがあり、軽く見積りしただけで開始してしまいました。
間に合わなければ意味がなく、残業なんてしない方が良いはずで
「定業時間内でできる範囲を考える」というのを意識すれば
良かったと思いました。
上記の弊害として、当初、他の案件も見なければならなかったため
自分がこの案件に100%コミットする感じではありませんでした。

ただ、インフラ構築、バックエンドのコーディングもやらないと
いけなかったため、他のメンバーに迷惑をかけてしまいましたが
この案件に100%コミットすることになりました。
両立できるかな?と考えましたが、甘かったです。

良かった点

自分で勉強してきたことをフルに発揮できる内容であり ある程度、実装イメージがついた状態で実装することが出来ました。
日々の勉強の賜物だなぁとつくづく思いました。

なお、勉強する内容も小難しいものではなく、単純に Railsの基本的な開発方法、サーバへのデプロイをやってみたり
機能として、ユーザー登録、管理画面の作成をやっておいた方が良いです。

チームに関しては「チーム一丸となってやる!」ということを信念を持ち
ディレクター、デザイナー、インフラの方たちと接しました。
ベストなコミュニケーションだったかと言われると難しいところですが
結果的には予定通りリリースできたので、問題なかったと思います。

まとめ

今回初めて、自分1人でインフラ、ミドルウェア、アプリを構築したので
業務を通じて、とてもためになった内容でした。

また、短期間でここまでできたのは、日々の勉強の成果もあり
少しずつですが絶えず続けてきたことが実った業務でした。

まだ、大きなシステム構築する力がありませんが
小さいことを1つずつやっていき、かつ勉強も絶えず続けて
大きなことを成し遂げていければと考えています。

【Rails】【Capistrano】USR2だと環境変数(ENV["XXX"])を再読み込みしない

前にこんな記事を書きました。

fujiyasu.hatenablog.com

対応期限も迫り切羽詰っている状況で
原因や解決方法がわかったのでメモ。

調査

Capistranoでデプロイ後、capistrano3-unicronを使って再起動をしていました。

github.com

再起動前後で、ENV["XXX"]を記述したところが動かず
明示的にunicornをstop, startすると問題なく動きました。

「ENV["XXX"]」に何か原因があるとわかり、探っていると
実際の値は、アプリの実行ユーザーの環境変数「.bash_profile」に
記述していました。

# ~/.bash_profile
export SAMPLE="hogepiyo"

なお、ENV["XXX"]をハードコーディングに置き換えると
動くというところまでわかりました。

原因

同じような原因で困っている人がいるはず!と思って調べていたところ
以下の記事がドンピシャリでした。

qiita.com

capistrano3-unicronを使っていたので、unicorn:restartのソースを見てみます。

https://github.com/tablexi/capistrano3-unicorn/blob/master/lib/capistrano3/tasks/unicorn.rake#L64

# 該当箇所を抜粋
  desc "Restart Unicorn (USR2); use this when preload_app: true"
  task :restart do
    invoke "unicorn:start"
    on roles(fetch(:unicorn_roles)) do
      within current_path do
        info "unicorn restarting..."
        execute :kill, "-s USR2", pid
      end
    end
  end

そして、自分が書いたdeploy.rbはこんな感じです。

# config/deploy.rb
namespace :deploy do
  # ...中略...

  task :restart do
    invoke 'unicorn:restart'
  end

  before :starting, :upload
end

まさしく、unicorn:restartを実行していて、さらにUSR2でkillされていることがわかりました。
これで、環境変数が新しく読み込まれず、エラーになってしまいます。

解決方法

手動でunicornをstop, startするのもイケてないですし、USR2を使って安全にkillをしたい。
なので、unicorn側でよしなに設定するのが良さそうです。

qiita.com

また、stop, startを明示的にdeploy.rbに記述のも手かもしれません。
試していない手がまだあるので、いろいろ試してみます。

まとめ

紹介記事ばかりになってしまいましたが、アプリだけ作成しても
Webサービスを作ったとは言えないということが痛感した内容でした。

【Rails】【Capistrano】database.ymlの<%= ENV['XXX'] >について

はじめに

Railsでアプリを作成していて、Staging, Production環境に
Capistranoでデプロイする際にハマった点をメモ。

ただし、解決策が見つからないため週末いろいろイジってみます。

環境

前提条件

Capistranoで「rake db:migrate」が動作する手前まで
デプロイ環境ができていること。

詳細

例えば、database.ymlのProducitonを確認したところ
デフォルトでは以下のとおりとなっています。

# config/database.yml
production:
  <<: *default
  database: sample_produciton
  username: sample
  password: <%= ENV['SAMPLE_DATABASE_PASSWORD'] %>

通常「cap deploy」をする場合、最新のソースコードを取得して
そのままデプロイ作業に移ってもらいたいと考えます。
そして、ENV['XXX']ということなので、考えられる置き換えの仕方は以下のとおり。

しかし、疑問に思ったのだが
「ymlファイルに上記の設定が有効になるかどうか?」
ということです。

今回、環境変数にもたせて実行してみたのですが、以下の様なエラーが発生してしまいます。

00:31 deploy:migrate
      [deploy:migrate] Run `rake db:migrate`
00:31 deploy:migrating
      01 $HOME/.rbenv/bin/rbenv exec bundle exec rake db:migrate
      01 rake aborted!
      01 Mysql2::Error: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111)

database.ymlに直接、database名とパスワードを書けば実行できるという
よくわからない状態となっています。

なお、実際に動作するディレクトリで <%= ENV['XXX'] %> を書いてあっても
ちゃんと環境変数から値を取得しているようで、問題アプリは動いています。

いろいろ、調べてみましたが有効になるような記事はたくさんあり
自分もその認識でしたが、ある環境ではうまくいかず、半日以上悩ます
案件になっています。

解決策はまだ見出していないですが、わかったらまた記事にしたいと思います。

【Nginx】httpからhttpsに自動でリダイレクトする方法

はじめに

最近、アプリエンジニアからインフラエンジニアに片足突っ込みがちなことを
やっており、件名の通りのことをやったのでメモ。

環境

  • Nginx 1.10.1で動作確認しています。
  • アプリ単位でconfファイルが作成されていること。
  • Nginx + unicorn + Ruby on Railsでアプリを作成しています。

前提条件

  • SSLオレオレ証明書発行済で、とりあえずTOPページが表示できること。
  • confファイルは「sample.conf」とします。
  • nginx.confからsample.confを呼び出せること。

解決策

まず、nginx.confからsample.confを使えるようにします。

# /etc/nginx/nginx.conf
user nginx;
worker_processes 1;

error_log /var/log/nginx/error.log;
pid       /var/run/nginx.pid;

events {
  worker_connections 1024;
}

http {
  include /etc/nginx/mime.types;
  default_type application/octet-stream;

  log_format ltsv 'domain:$host\t'
                  'host:$remote_addr\t'
                  'user:$remote_user\t'
                  'time:$time_local\t'
                  'method:$request_method\t'
                  'path:$request_uri\t'
                  'protocol:$server_protocol\t'
                  'status:$status\t'
                  'size:$body_bytes_sent\t'
                  'referer:$http_referer\t'
                  'agent:$http_user_agent\t'
                  'response_time:$request_time\t'
                  'cookie:$http_cookie\t'
                  'set_cookie:$sent_http_set_cookie\t'
                  'upstream_addr:$upstream_addr\t'
                  'upstream_cache_status:$upstream_cache_status\t'
                  'upstream_response_time:$upstream_response_time';

  access_log /var/log/nginx/access.log ltsv;
  sendfile on;
  keepalive_timeout 65;

  upstream sample_app {
    # Ruby on Railsでunicornを使う場合の設定
    server unix:/var/www/sample_app/current/tmp/sockets/unicorn.sock
    fail_timeout=0;
  }

  include /etc/nginx/conf.d/*.conf;
}

ログフォーマット以外はほぼ初期設定のままです。

次にsample.confです。

# /etc/nginx/conf.d/sample.conf
server {
  listen 80;
  server_name sample_app;
  # ここがポイント
  return 301 https://$host$request_uri;
}

server {
  listen 443;
  server_name sample_app;

  ssl                  on;
  ssl_certificate      /etc/nginx/ssl/server.crt;
  ssl_certificate_key  /etc/nginx/ssl/server.key;

  ssl_session_timeout  5m;

  ssl_protocols  SSLv2 SSLv3 TLSv1;
  ssl_ciphers  HIGH:!aNULL:!MD5;
  ssl_prefer_server_ciphers   on;

  root /var/www/sample_app/current/public;

  location ~ ^/assets/ {
    include /etc/nginx/mime.types;
    root    /var/www/sample_app/current/public;
  }

  location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Proto https;
    proxy_redirect off;
    proxy_connect_timeout   300;
    proxy_send_timeout      300;
    proxy_read_timeout      300;

    if (!-f $request_filename) {
      proxy_pass http://sample_app;
      break;
    }
  }
}

ポイントとしては、80ポートで受付した際に301でリダイレクトするところです。
こうすればhttpでアクセスされても、httpsにリダイレクトされて処理されます。

インフラ周りは素人ですが、なんとか設定することができました。
Javaのアプリエンジニアばかりやっていので、Apache周りの設定はわかりませんが
Nginxの方がシンプルに記述できるので、とても好きです。
これからもちょくちょくNginxを触っていこうと思います。

【レビュー】Bose QuietComfort35 wireless headphones を買って数日使ってみた

はじめに

数年前からカナル型イヤホンを使っていたのですが、家電量販店で「Bose」という
名前をよく見ていました。また、一部のエンジニアにも人気ということで
気になっていました。

そして、つい最近新しいのが出るということで
どうしようか迷っていたのですが(値段的な意味で)一大決心をして
購入に踏み切りました。

購入したのはこちら

週末と職場で使ってみたので、レビュー(感想)を書きたいと思います。

製品概要

  1. ノイズキャンセリング(以下、NP)を搭載
  2. NPで初のワイヤレス
  3. つけていても疲れない、高級感あふれ、快適な装着感
  4. バッテリー持続時間が連続使用20時間+モバイルバッテリーで充電できる

自分もこのぐらいであれば、4万も出すほどではないと思いました。
音楽を聞くだけならお手頃価格で良いものはたくさんありますし。

場所

自宅

自宅は比較的静かなので、そんな実感ないかな?思っていたのですが
すぐに実感することになりました。

まず、この時期から稼働することになるであろう「エアコン」の音がなくなりました。
これにはビックリして「まさか?!」と思ってしまうほどで、ものすごく集中することができました。

カフェ

せっかくなので、Macbook Airを持ってスタバでドヤってきました。
今まではカナル型イヤホンをつけてやっていたので、雑音+人の声+音楽の3つが
同時に聞こえて集中できていたかというとそうでもありませんでした。

そして、装着して音楽をかけたところ・・・
若干、人の声はするものの(これは音量次第でどうとでもなる)
変な雑音は一切聞こえませんでした。
「こんなに静かだったっけ?」とヘッドホンを外してみると
いつものように聞こえて、逆にいつも以上にうるさく感じてしまいました。

通勤

さすがに歩いている時に着けるのは危ないので、電車に乗ってから着けました。
そして、前評判通りキレイに雑音が消えて人の声のみとなりました。
音楽をかけなくても電車の中であの静けさを手に入れることができるのは
すごいことだなと思いました。

職場

職場は比較的静かなところなので、あまり意味がないですが
集中したりするときに装着して、長時間の装着感を主に確かめました。

結果は数時間つけていても疲れず、NPのおかげで周りの音が消え
音楽をかけていつも以上に集中することができました。

全体を通して

NPの力は偉大だとすべてを通して思えたのと、無線というのも大きかったです。
バッテリーも20時間もつので頻繁に充電しなくてもいいというのも良い。
さらにつけ心地も問題なし。

素晴らしい商品です。

まとめ

オーバーヘッドイヤホンを本格的に使うのは、かなり戸惑いました。
しかし、それを覆すほどの商品だったので、興味ある方は実際に
手にとって体感してもらえればと思います。

ただ、値段がかなり高いので覚悟を決めて買った方がいいです。
自分も半分「えい、やー!」で買ったようなものです。

【Rails】【Capistrano】SCMを使わずにデプロイする方法

はじめに

Webサービスを開発していて、かなりハマったのでメモをする。

環境

前提条件

Vagrantなどでローカル環境でSCMからソースを取得して、
デプロイできる環境となっていること。
または、SCMからソースを取得しないで、ローカルにあるファイルを
デプロイしたい場合。

詳細

通常のCapistranoは、「cap staging deploy」を実行した場合 以下の記述に沿って、デプロイしたいサーバーでSCMからソースを
pullしてからデプロイを実行します。

# config/deploy.rb
set :repo_url, 'git@github.com:[User Name]/[Repository Name].git'
set :scm, :git

ただし、サーバーからSCMにアクセスできない場合があります。
※セキュリティ的な理由だったりする。

これは自分にとってかなり困った状態となった。
Capistrano標準だと何も考えずやればよかったが、デプロイ方法を
考えなおさなければなりませんでした。

そして、1日考えたあげく解決方法として2つ見つかりました。

解決策:Capistranoコマンドを実行した箇所からファイルをコピー

その1

アクセスできないのであれば、アクセスできるところで
ファイルを取得して、それをまるっと持っていけばいいという方法です。

以下のものを使えばいけるようです。

github.com

ただし、メインの場所は開発がストップしており
フォークされたものが有志でメンテナンスしているみたいです。

github.com

余談ですが、以下のやつも同じようなことができるようです。

github.com

その2

別のものを使っても、同じようなことができます。
※Capistrano2では、もともとあった機能のようです。

github.com

使い方はQiitaの記事を見れば、簡単に実装できます。

qiita.com

まとめ

便利なものがすでに用意されており、今回ローカルマシンでというのが
メインでしたが、CIサーバで同じことをすれば問題なく動くと思います。

標準的な動作でやれることに越したことはないですが
別の方法を知っておくことで、想定外のことを想定内にしておくことって
とても大切だと思わされた内容でした。