ひよっこエンジニアの雑多な日記

なんとかWeb系のエンジニアをやっています。

AWS CodeDeployを使ってGitHubにあげているリポジトリをデプロイする

AWS CodeDeployを使ってみたら思いの外、簡単に設定できてデプロイができたので覚書きです!
そういえばAWSには結構お世話になってるけど記事を書くのは初めてという事実…

CodeDeployとは

AWS CodeDeployは読んで字のごとくEC2インスタンスなどにコードをデプロイしてくれるサービスです。

aws.amazon.com

デプロイ対象のEC2にエージェントをインストールする

CodeDeployを利用するためにはCodeDeployのエージェントをEC2インスタンスにインストールしておく必要があります。
エージェントのインストールにはaws-cliでS3からエージェントをダウンロードする必要があるのでEC2にS3のread権限のロールを設定してあげる必要があります。

EC2にロールを設定する

まずはIAMにアクセスします。
https://console.aws.amazon.com/iam

ロール>新しいロールの作成でロールの作成を行う。

作成するロールは以下

ロールタイプ ポリシー
Amazon EC2 AmazonS3ReadOnlyAccess

作成したロールをデプロイ対象のEC2に設定します。

CodeDeployのエージェントをインストールする

EC2にロールを設定後、EC2にSSHログインをします。

以下コマンドを実行していきCodeDeployのエージェントをインストールします。

$ sudo yum install aws-cli
$ aws s3 cp s3://aws-codedeploy-ap-northeast-1/latest/install . --region ap-northeast-1
$ chmod +x ./install
$ sudo ./install auto

エージェントのインストールはこれで完了です!!

デプロイするアプリケーションにappspec.ymlを作成

CodeDeployでどのようにデプロイを実行するかを設定するファイルappspec.ymlをデプロイするアプリケーションのプロジェクトルートに配置します。
今回はAmazonLinuxを想定しています。

version: 0.0
os: linux
files:
  - source: /
    destination: /var/www/application

上記の設定はアプリケーションのファイル全体をEC2の/var/wwwapplication配下にデプロイするという設定を行っています。
設定内容は今回は省略しますが、以下の記事がわかりやすかったです。

dev.classmethod.jp

appspec.ymlを作成したらコミットしてGitHubにプッシュしておきます。
(CodeDeployはGitHubのデフォルトブランチをデプロイするのでプッシュしたブランチがデフォルトブランチではない場合はマージしておきます。)

CodeDeployを使ってデプロイを実行する

いよいよCodeDeployを利用してデプロイしていきます。

CodeDeploy用のロールを作成する

実行する前にCodeDeployのアプリケーションを作成するためにはCodeDeployのロールが必要なので再びIAMのダッシュボードにアクセスします。

作成するロールは以下になります。

ロールタイプ ポリシー
AWS CodeDeploy AWSCodeDeployRole

アプリケーションを作成する

AWSのダッシュボードからCodeDeployにアクセスします。
初めてCodeDeployを利用する際は以下のような画面になるので今すぐ始めるをクリックする。

f:id:kimuraysp:20170824233426p:plain

チュートリアルをやるか問われますが実施しなくても良いのでカスタムデプロイを選択してウォークスルーのスキップをクリックする。

f:id:kimuraysp:20170824233507p:plain

ウォークスルーをスキップするとアプリケーションの作成画面に遷移するので、以下の設定を行う。

項目 設定内容
アプリケーション名 任意
デプロイグループ名 任意
デプロイタイプ インプレースデプロイ
環境設定 Amazon EC2インスタンス > デプロイしたいインスタンス
デプロイ設定 CodeDeployDefault.OneAtATime
サービスロール CodeDeploy用に作成したロール

デプロイを実行する

CodeDeployダッシュボードから先ほど作成したアプリケーションのリンクにアクセスします。
デプロイグループを選択して、新しいリビジョンのデプロイをクリックします。

f:id:kimuraysp:20170824235553p:plain

画面遷移したら以下の設定を行います。

項目 設定内容
リポジトリタイプ アプリケーションはGitHubに格納されています
デプロイメントの説明 任意
GitHubアカウント GitHubの認証を行います
リポジトリ GitHubリポジトリ名(アカウント名/リポジトリ名の形式で)
コミットID デプロイしたいコミットID(省略形のコミットIDではなくフルの方で)

その他の設定は任意で行いデプロイボタンをクリックします。

するとデプロイが開始され指定したEC2へデプロイが実行されます!

最後に

設定する内容はちょいちょいありますが設定さえ行ってしまえば簡単にデプロイを実行することができるようになります!
さらにGitHubの設定をもう少し行うことでデフォルトブランチに変更が加わったのを検知して自動でデプロイを起動するといったことも可能です!(次の記事はそれかこうかな…笑)

いやー、AWSは本当に便利。設定するだけでなんでもできちゃうんじゃないかな。(ただし財力が必要)

ロードバランサーを経由してPOST投げたりするとdue to access control checkと言われて困り果てた時の対処

コンスタントに記事を更新と言ってからはや2ヶ月くらいでしょうか。。。笑
備忘録がてら出会ったことがないエラーにあったので久々に更新

概要

最近、ConoHaでアプリケーションサーバー2台の冗長環境を作ってくれないかと言われ割とお安めな価格で対処していた時のことです。
クライアントが新環境でアプリケーションの動作確認を行ってもらっていたところ

Safariでログインとかサインアップできないんだけど調査おなしゃす!!」

というあまりやりたくない系のお願いをされたのがことの発端。

それで実際にSafariで動作確認してみると確かにログイン系の処理ができない。
超勘弁。ブラウザの要素検証したらdue to access control checkという文字が。
調べて見たらCORSの対策が打ててない時にでるっぽかった。

構成

インフラ

ConoHaロードバランサー
ConoHaVPS(アプリケーションサーバー) × 2
ConoHaVPS(DBサーバー) × 1

アプリケーション

Ruby on Rails 4.2.3
Ruby 2.3.0
MariaDB

解決策

Nginxの設定でCORSに関するヘッダー情報をリクエストに追加する設定を追記

location / {
        # ここから
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods "POST, GET, OPTIONS";
        add_header Access-Control-Allow-Headers "Origin, Authorization, Accept";
        add_header Access-Control-Allow-Credentials true;
        # この辺まで追記
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header Client-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
        proxy_set_header Host $http_host;
        proxy_redirect  off;
        proxy_pass http://oceanworks-puma;
}

これでログインできるようになった。

その他

最近、疲れが取れない。。。

Rails 5.1のform_withを使ってうまくredirectできないあなたへ

かなり気まぐれですがネタができたらコンスタントにブログを投稿しようという気持ちになり始めました。
今年一年で50投稿を目指して頑張ります。

概要

Rails5.1 + sorceryを使って認証周りをサクッと作ろうとしたのですが、5.1から出てきたform_withに微妙にはめられました。
結構初歩的っぽいですが僕と同じような気持ちになる人がいるかもしれないので備忘録。
というかRailsの4.x系とか5.0系やってきた人が試しに5.1使ってみよってなったら割とハマるんじゃないかと勝手に思ったり…
※ ブログの内容的にはsorceryはもはや関与しません

事象

以下みたいな感じでログインフォームを作ってました。

<%= form_with url: sign_in_path, method: :post do %>
  <div class="field">
    <%= label_tag :email %><br />
    <%= text_field_tag :email %>
  </div>
  <div class="field">
    <%= label_tag :password %><br />
    <%= password_field_tag :password %>
  </div>
  <div class="actions">
    <%= submit_tag 'Login' %>
  </div>
<% end %>

これでログインできるか確認するためにLoginボタンを押すと

ログイン成功してるはずなのに画面遷移しない・・・・!!!

いやいやと思ってLoginボタンを連打してみるも状況は変わらず。
しかし画面再読み込みしたらログインできてる。

ログ見たら

Started POST "/sign_in" for 127.0.0.1 at 2017-07-08 23:03:12 +0900
Processing by UserSessionsController#create as JS

なんかJSをレンダリングしようとしてますやん!
そりゃ画面遷移しないわけだ。

解決策

ちゃんとform_withの仕様を把握してから使えばよかったのですが、解決策としてはなんてことない感じでした。
解決したコードがこちら

<%= form_with url: sign_in_path, method: :post, local: true do %>
  <div class="field">
    <%= label_tag :email %><br />
    <%= text_field_tag :email %>
  </div>
  <div class="field">
    <%= label_tag :password %><br />
    <%= password_field_tag :password %>
  </div>
  <div class="actions">
    <%= submit_tag 'Login' %>
  </div>
<% end %>

ほぼ変わってない感じですが、form_withlocal: trueオプションをつけてあげてます!
これでHTMLをレンダリングしてくれるので意図した動きになります!

どうもform_withはデフォルトで生成されるformタグにdata-remoteがついちゃうっぽいです。
local: trueを設定することでこれをつかないようにできるとのこと。

よくよく考えたらscaffoldで生成された_form.html.erbみるとform_withlocal: trueがついてんだよなあ
まあしかしこれで大人の階段をまた一つ登ることができました

余談

scaffoldで生成されるerbファイルのform_withのブロック変数がformになってるんですね!
いままではfがブロック変数でしたが、やはり可読性を考えると一文字よりも意味のある単語の方がよいんですかねえ

CircleCIでelasticsearchにkuromojiをインストールして起動させる

CircleCIで自動テストをしたいもののelasticsearchの処理を含んだ処理周りがうまくテストされなくて結構ハマったので備忘録。

やりたいこと

アプリケーションの機能として簡単な全文検索をelasticsearchを使って実現していたので、CircleCIにもelasticsearchを導入して全文検索用のindexを作成をアプリケーションのテストコードで行なっていた。
CircleCIを使ってGitHubでプルリクエストを上げた瞬間に自動でテストが走らせるCI環境を構築して、全テストをパスさせたい!

問題点

しかし、elasticsearchを導入してpluginとしてkuromojiを導入する必要があり、それを実現するのに四苦八苦。
elasticsearchを動かすだけならできるのだが、kuromojiを導入する方法がわからない…

ひとまずここみたら全てが解決しました。

解決法

circle.ymldependenciesに以下を追記してあげるだけでOK

dependencies:
  post:
    - wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.3.2.tar.gz
    - tar -xvf elasticsearch-5.3.2.tar.gz
    - elasticsearch-5.3.2/bin/elasticsearch-plugin install analysis-kuromoji
    - elasticsearch-5.3.2/bin/elasticsearch: {background: true}
    - sleep 10 && wget --waitretry=5 --retry-connrefused -v http://127.0.0.1:9200/

これ書いておくとelasticsearchをwgetでダウンロードして、解凍して、kuromojiインストールして、elasticsearchを起動してくれる。

毎回wget走るの重くなりそうでいややなーとなる場合は以下みたいな感じに書き換える。

dependencies:
  cache_directories:
    - elasticsearch-5.3.2
  post:
    - if [[ ! -e elasticsearch-5.3.2 ]]; then wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.3.2.tar.gz && tar -xvf elasticsearch-5.3.2.tar.gz && elasticsearch-5.3.2/bin/elasticsearch-plugin install analysis-kuromoji; fi
    - elasticsearch-5.3.2/bin/elasticsearch: {background: true}
    - sleep 10 && wget --waitretry=5 --retry-connrefused -v http://127.0.0.1:9200/

cache_directoriesを使うとディレクトリをキャッシュできるようなので、wgetして解凍したディレクトリをキャッシュしてくれるようになる。
! -e elasticsearch-5.3.2のところでディレクトリの存在確認をしてくれるのでキャッシュされてなかったらwget、解凍、インストールしてくれるし、キャッシュされてたらこの処理を飛ばしてくれるようになるので無駄なオーバーヘッドなくなるぽい。

これでelasticsearchをCircleCI上でも使えるようになってめでたしめでたし。

ちなみに

machine:
  services:
    - elasticsearch

最初、これでelasticsearch立ち上がるやん!と喜んでいたのですが、この記述をしているとwgetで落としてきたelasticsearchとは別物の子が動いちゃうので、いくらkuromojiをインストールしてもpluginがインストールされていないことになってテストが全く通らなくて禿げ上がりそうでした。
この記述に気づかず1時間ぐらい消費したのは愚かでした…

CentOS7系でhttpアクセスを許可する

毎度ConoHaでサーバー構築する際に忘れてしまうので備忘録

操作

httpを許可する

$ firewall-cmd --add-service=http --zone=public --permanent

httpsを許可する

$ firewall-cmd --add-service=https --zone=public --permanent

ファイアウォールをリロード

$ firewall-cmd --reload

ファイアウォールが正しく設定されているか以下のコマンドで確認

$ firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources:
  services: dhcpv6-client http https ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  sourceports:
  icmp-blocks:
  rich rules:

serviceのあたりにhttpとhttpsが追加されていればOK

CentOS7で毎度環境構築するたびに忘れてて、検索するのがだるいのでブログ化
あとserviceコマンドに慣れすぎててsystemctlもよくど忘れする
あとmysqlいれたつもりになってるとmariadbが入ってて焦るときがある(ほぼmysqlと一緒だけど…)

【Rails】enumで特定の値を選択肢から省きたい

きむらです。またもやenum関連ですがちょっとなるほどと思ったことがあったので備忘録。

enumに設定している値を全て取り出す

例えばセレクトボックスに選択肢としてenumに設定している値を出す場合などによく使うとおもいます。

# blogというモデルに公開範囲(非公開、公開、一部に公開)のようなステータスがある想定
class Blog < ActiveRecord::Base
  enum status: { unpublish: 0, publish: 1, part_publish: 2 }
end

# enumに設定したstatusの状態をすべて取得する
Blog.statuses
=> {"unpublish"=>0, "publish"=>1, "part_publish"=>2}

てな感じでモデル.enumを設定した属性の複数系と書くことでenumに設定した値を取得することができます!
これを使えばブログの公開範囲選択セレクトボックスを作成するのが簡単になったりします!

enumに設定している特定の値だけを取得したい

便利とはいえ特定の状態だけを選択させたくなるときもあります。
例えば一部に公開(part_publish)を特定の箇所では選択肢に入らないようにしたいとか

そんなときはsliceexceptを使うと幸せになれます!

sliceを使ってpart_publishを省く

Blog.statuses.slice(:unpublish, :publish)
=> {"unpublish"=>0, "publish"=>1}

sliceを用いると引数に指定した値だけを取り出すことができます。
特定の値を省くというより、特定の値だけを取り出すという感じですね!

exceptを使ってpart_publishを省く

Blog.statuses.except(:part_publish)
=> {"unpublish"=>0, "publish"=>1}

exceptを用いると引数に指定した値は取得しないようになります!
省くという意味合いではexceptの方が正しそうですね。

といった感じで簡単にenumに設定した特定の値だけを取得できるようになります!
これらを使ってクラスメソッドなんか作ってあげるとスマートっぽい気がしますね!

class Blog < ActiveRecord::Base
  enum status: { unpublish: 0, publish: 1, part_publish: 2 }

  def self.restrict_statuses
    statuses.except(:part_publish)
  end
end

Blog.restrict_statuses
=> {"unpublish"=>0, "publish"=>1}

slice、exceptは何者か

この二つはActiveSupportのメソッドのようです!
enumを設定して設定内容を取得したもののクラスが以下にになります!

Blog.statuses.class
=> ActiveSupport::HashWithIndifferentAccess

つまりBlog.statusesで取得できるものはハッシュってことになります。
RailsだとハッシュはActiveSupportパイセンの力でちょいちょい強化されていて、その強化された力を用いることで割と簡単にハッシュ操作ができたりします…。sliceexceptはその力の一部であるということです…。

ほんとActiveSupportActiveRecordあたりはよしなにいろんなことをやってくれるので便利すぎるなあという気持ちになります。

最近RailsのよしなにしてくれるところにあぐらかいてRuby力がなくなってきている(そもそもそんなにない)ので、その辺鍛え直さないとなあ…。

2017年が始まったので今年の目標を掲げてみる

お久しぶりです。きむらです。
めちゃめちゃブログサボってました…もはや存在忘れそうになってました…笑

2017年は気持ちを改めてブログ書きます!目標は3日で1記事!
というわけで2017年最初の記事は今年の目標を綴っていきたいと思います!(戒めのためにも)

2017年の個人テーマ

  • コミュニケーション
  • 興味関心
  • 意思決定

2017年に掲げる個人テーマは上記3点です! それぞれ少し深堀します。

コミュニケーション

これは若干コミュ障気味の自分を変えていくために意識したいなあと…。

仲のいい友達や職場の人とは大体喋れるんですけど、ちょっと苦手だなあと感じる人や微妙な距離感の人、初対面の人と向き合うと途端に喋れなくなる(もはや逃げ出したくなる)という状態を解消しなければ…と思っています…。
何かの本でコミュニケーションは人生を左右する云々のことが書いてあって、そうだよなあと思いつつコミュニケーションをないがしろにしていた感はあります(反省)

お正月休みにKindleでコミュニケーションに関するコミックエッセイを読んで、コミュニケーションを楽にする方法みたいなものを学んだ感があるので、それを実践していきたい所存です。

興味関心

いろんなことに興味関心を持つようにしたいです!

というのも自分が興味関心あることが今ぱっとでないという完全に無趣味無関心人間になってしまっていたという状態を解消したいです…。

無関心状態があることによって人と話したりしても、そんなん言われても興味ないんだよなあとか、人自体に興味関心がわかないんだよなあみたいな、ある意味中二病とも言える病に20半ばの今でもかかっているという事態を解消するというのがこのテーマを掲げた一番の理由ですかね…
このテーマはコミュニケーションにもつながりますしね…

意思決定

これは仕事、プライベート共にですね…。

仕事でもプライベートでも色々考えすぎて意思決定まで時間がかかりすぎたり、決定することを人に任せてしまったりということが多々あったので、もっと自分で何かを決定するということをしていかねばと…。
もはやご飯いくところも完全に人任せばっかりだったし…

なのでちょっとずつ自分で何かを決めていける、決めるまでのスピードを早められるようにするということをやっていきたいと思います!

おわりに

個人的に今年一年は自分自身の人生がどうなるかというのが色々な意味で占われる一年になるのではないかなあと思っています。
そんな一年で自分をきちんと見つめ直して、本当に興味あることや今後どのようになっていきたいかを見つけて豊かな人生を構築する足がけにしていきたいと思います!

そして今年こそ彼女をば…!!!笑