kentana20 技忘録

技術ネタを中心に、セミナー、勉強会、書籍、会社での出来事を綴っていきます。不定期更新。

Railsでpaperclipを使ってリサイズしつつS3へ画像をアップロードする

RubyonRailsアプリで、画像アップロード機能を作るにあたって、paperclipを試すことにしたので、技忘録。

想定するユースケース

  • エンドユーザ向け画面/管理画面で画像アップロード機能を作りたい
  • アップロードした画像はいくつかのサイズにリサイズして使うことを想定する
  • 画像はWebサーバ内部ではなく、オンラインストレージを使用して保存する
  • アップした画像はWebアプリから参照したい
  • アップロードはWebアプリからのみ許可したい
  • なるべくシンプルに作りたい

構成

これらをOSX Yosemite上で実行し、オンラインストレージにはAmazon S3を使います。

前提

  • RubyRailsは既にインストール済みであること
  • 何らかのRailsアプリが動く状態にあること
  • 画像を追加するモデル"Hoge"は既に定義されていること
  • AWSアカウントが既にあること

事前準備

画像のリサイズにはimagemagickを使うのでbrewでインストール

$ brew install imagemagick

:warning: CentOSとかならyumでインストールしてください

  • Gem追加

paperclipとaws-sdk, rmagickのGemを追加して

gem 'paperclip'
gem 'aws-sdk'
gem 'rmagick'

bundle install します

$ bundle install

Gemfile.lockが更新されます。

Model

  • Modelに画像保存用の設定を追加する
class Hoge < ActiveRecord::Base
  has_attached_file :image,
                    :styles => {
                        :thumb  => "90x60",
                        :medium => "180x120",
                        :large => "600x400"
                    },
                    :storage => :s3,
                    :s3_permissions => :private,
                    :s3_credentials => "#{Rails.root}/config/s3.yml",
                    :path => ":attachment/:id/:style.:extension"

  validates_attachment_content_type :image, :content_type => ["image/jpg", "image/jpeg", "image/png"]

  def authenticated_image_url(style)
    image.s3_object(style).url_for(:read, :secure => true)
  end

end
  • Migrationを作る
$ rails g migration AddAttachmentImageToHoges
  • migrationファイルの中身はこんな感じ
class AddAttachmentImageToHoges < ActiveRecord::Migration
  def change
    change_table :hoges do |t|
      t.has_attached_file :image
    end

    drop_attached_file :hoges, :image
  end
end
  • Migrate
$ rake db:migrate

これで

  • image_file_name
  • image_content_type
  • image_file_size
  • image_updated_at

の4つのカラムがDBに追加されます。

Controller, View

次にControllerとViewを作っていきます。

$ rails g controller hoges index show new edit

Controller

class HogesController < ApplicationController
  before_action :set_hoge, only: [:show, :edit]

  def index
    @hoges = Hoge.all
  end

  def new
    @hoge = Hoge.new
  end

  def show
  end

  def edit
  end

  # とりあえず、createだけ追加
  def create
    @hoge = Hoge.new(hoge_params)

    respond_to do |format|
      if @hoge.save
        format.html { redirect_to @hoge, notice: 'Hoge was successfully created.' }
        format.json { render action: 'show', status: :created, location: @hoge }
      else
        format.html { render action: 'new' }
        format.json { render json: @hoge.errors, status: :unprocessable_entity }
      end
    end
  end

  private
    def set_hoge
      @hoge = Hoge.find(params[:id])
    end

    def hoge_params
      params.require(:hoge).permit(:name, :image)
    end

end

View

  • 新規登録画面
  <div class="field">
    <%= f.label :name %>
    <%= f.text_field :name %><br>
    <%= f.label :image %>
    <%= f.file_field :image %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
  • 一覧画面
    <% @hoges.each do |hoge| %>
      <tr>
        <td><%= hoge.id %></td>
        <td><%= image_tag(hoge.authenticated_image_url(:thumb)) if hoge.image.present? %></td>
        <td><%= link_to 'show', hoge %></td>
        <td><%= link_to 'edit', edit_hoge_path(hoge) %></td>
        <td><%= link_to 'destroy', hoge, method: :delete, data: { confirm: 'are you sure?' } %></td>
      </tr>
    <% end %>
  • 部分テンプレート
  <%= @hoge.name %>
  <%= image_tag(@hoge.authenticated_image_url(:large)) if @hoge.image.present? %>

Routes

hogesへのrouteを追加します。

  resources :hoges

S3

Bucketを作る

AWSのManagementConsole上でS3のBucketを作ります。

f:id:kentana20:20141202230827j:plain

f:id:kentana20:20141202230840j:plain

接続情報

  • config/s3.yml として、S3への接続情報を記述します
bucket: 'bucket_name'
access_key_id: '12345678'
secret_access_key: '12345678901234567890'
s3_host_name: 's3-ap-northeast-1.amazonaws.com' # tokyoリージョンの場合

これで準備は完了です。

実行

Railsアプリを動かして /hoges/ へアクセスして、"new hoge"リンクを押下して画像データを追加します。

CreateしたらAWSのコンソール上でS3のBucketの中身を確認します。

f:id:kentana20:20141202230910j:plain

所感

  • paperclip便利
    • めちゃ便利です
    • S3、ImageMagickとの連携が非常に手軽に行えます
  • 静的コンテンツをWebサーバに置かなくていいのはラク
    • 静的コンテンツをWebサーバ内に置かなくていいのは非常に良いですね
    • S3ならそのままCloudFrontでCDN対応もできます
    • Webサーバをスケールアウトしても静的コンテンツはそのままで良いし、運用もラクです
  • 画像ファイルのURL生成をRails側で処理することについては...
    • 一方、画像URL生成をRailsで処理させることになるので、ここはフラグメントキャッシュを使って、キャッシュした方が良い部分かもしれません
  • CarrierWave
    • 対抗馬と目される、Carrierwaveも試してみようと思います

参考

TravisCIを使ってHerokuへ自動デプロイする

前回のエントリで RubotyをHerokuにデプロイして、Slackで動かす についてまとめました。

今回はGitHubリポジトリを変更した際に、TravisCIを使ってGitHubに変更があったときに自動でHerokuへデプロイされるようにしたいと思います。この手のお話は結構エントリがあるので、今更感もありますが、自分的に整理しておきたいので技忘録。

f:id:kentana20:20141103210518p:plain

前提・準備

デプロイするアプリケーション

TravisCIの設定

該当リポジトリをTravisCIの実行対象にする

  • TravisCIにログインしたら、Accountsメニューから該当リポジトリのスライダーをonに変更します

f:id:kentana20:20141103204414p:plain

travis gem のインストール

  • GitHubとTravisCIを連携するためのファイルとして .travis.yml を作る必要があるのですが、TravisCI周りの設定をCUIからいい感じにできるGemがあるので利用します
$ gem install travis

.travis.ymlの作成

  • ローカルにCloneしたリポジトリルートへ移動して、以下のコマンドを実行します
$ travis init
Shell completion not installed. Would you like to like to install it now? |y| y
Detected repository as kentana20/ruboty-template, is this correct? |yes| yes
Main programming language used: |Ruby| Ruby
.travis.yml file created!

これで、 .travis.yml が作成されます。Credentialのエラーが出た場合は travis login —auto コマンドを実行して認証をしてから再度実行してみてください。travis report を実行するとエラーの詳細が確認できます。

.travis.ymlにHerokuの設定を追加する

  • 今度は作成した .travis.yml にHerokuの設定を追加します。これもtravis gemの機能を利用してCUIで行います
$ travis setup heroku
Heroku application name: |ruboty-template| $heroku_app_name
Deploy only from kentana20/ruboty-template? |yes| yes
Encrypt API key? |yes| yes

Heroku application nameはHeroku上のアプリケーション名を入力します。これで、 .travis.yml にHerokuの設定が追加されます。出来上がったファイルは以下。

language: ruby
rvm:
- 2.0.0
deploy:
  provider: heroku
  api_key:
    secure:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  app: $heroku_app_name
  on:
    repo: kentana20/ruboty-template

設定ファイルができたらGitHubへpushしておきます。

$ git push origin master

これでTravisCIの設定は完了です。

動作確認

Pull RequestでTravisCI

  • まずはmasterブランチから別のブランチへ作業ブランチを切り替えて、何らかの作業をします。今回は単なる bundle update でGemfile.lockを更新してPull Requestを作成します
$ bundle update
$ git add .
$ git commit -m “gem update”
$ git push origin f/bundle_update

GitHubでPull Requestを作成すると、以下のようにコミットしたリビジョンに対してTravisCIが走り、実行結果をGitHub上で見ることができます。

f:id:kentana20:20141103204529p:plain

これで、master merge前にCIを走らせて、masterに毒が仕込まれるのを防ぐことができます。また、このときのCIジョブはPull Request起因なので、Herokuへのデプロイは行っていません。

f:id:kentana20:20141103204544j:plain

master mergeでTravisCI

  • 先ほどのPull Requestをmergeすると、もう1度TravisCIが動いて、今度はHerokuへのデプロイも実行されます。

f:id:kentana20:20141103204612j:plain

これで、前回のエントリで紹介したHerokuへのデプロイ git push heroku master をすることなく、masterにmergeするだけで、Herokuへのデプロイが完了します。便利ですね〜。

所感

  • Travis Gem超便利
    • Travis Gem、今まで知らなかったので手動で .travis.yml 作ってましたが、これは使わない手はないですね。便利です。Herokuの設定に関してはAPI KeyのEncryptもやってくれるし、スグレモノです。
  • TravisCIはちょっと遅い
    • TravisCIは変更を検知してからの実行が気持ち遅いかな、と感じます。無料版なので贅沢は言えないですが、もう少しサクサク動くことを期待したいです。
  • master mergeからの自動デプロイはラク
    • 会社でも少しは自動化していますが、やはりmaster mergeをフックにデプロイができると良いですね。デプロイ運用に関わっているメンバーの心理的負担も減らせますし、お決まりの作業はどんどん自動化するべきだと強く感じます。
  • コミットリビジョン毎にTravisの実行結果が見られるのも良い
    • リビジョン単位でCIを走らせることで「このPull RequestはCIが通っている」と一目でわかるので、安心してmergeができてこれも心理的負担を軽くできます。メンバーの人数やCIジョブのボリュームによっては「CI待ち」みたいな状態を作りかねないので注意が必要ですが、スピードアップを目指せば良いわけで、これも会社のスタンダードにしていきたいです。
  • ブランチ毎にデプロイ先を分けて運用なども
    • 参考にしたOnishiさんのエントリにもありましたが、devブランチはStaging環境へ、masterブランチはProduction環境へデプロイする、みたいな設定を作っておけば、どちらもデプロイを自動化できて非常にラクにデプロイ運用を行う事ができてTravis便利だと思いました。
  • CircleCIはどうなんだろう
    • 最近はCircleCIの方が流行りっぽいので、今後はCircleCIも試してみたいと思いました。
  • ForkしたリポジトリはPull Requestの送り先に注意
    • 完全に本題とは外れますが、個人的な反省の意味を込めて。今回のデプロイ対象リポジトリid:r7kamuraさんのリポジトリをForkしてるんで、Pull Requestの送り先を間違えるとFork元に飛んでしまいます。今回は実際にPull Requestを飛ばしてしまって「間違ってるよ」と指摘をいただいてしまいました。。反省です。

f:id:kentana20:20141103204658p:plain

これで自動デプロイの設定までできたので、もうちょいためになる挙動を足していこうと思います。個人的にBrowserStackが気になっているので、次回は「Rubotyに話しかけてBrowserStackの結果をSlack上で確認する」をお届けしようと思います。

参考

RubotyをHerokuにデプロイしてSlackで使う

人気のチャットアプリであるSlackと id:r7kamura さんが作ったRuby製Hubotクローンである Ruboty を試してみたかったので、技忘録。

f:id:kentana20:20141103005647p:plain

最近チームメンバーに編成があって、「まゆゆ」というニックネームの仲間が少しの間、旅に出ることになり、とっても寂しいので寂しさを紛らわすために「まゆゆbot」を作ってみることにします。

前提

RubotyはHerokuにデプロイしますので、Herokuアカウントの作成やHeroku Toolbeltのインストールは済ませてあることを前提とします。

Slack側の設定

Gatewayの設定

  • XMPP Gatewayの設定を有効にします
    • こちら からTeam Settingsの画面を開き、Permisssionsタブをクリックして「Gateways」項目から「Enable XMPP gateway (SSL only)」のチェックを入れてSaveします

f:id:kentana20:20141102174946j:plain

Botアカウントを作る

  • AdministrationのManage Your Teamを開き、Invite New Membersから適当なメールアドレスを入力してInvitationメールを送信します

f:id:kentana20:20141102175023p:plain

  • Invationメールが届いたら、Activationして適当に画像を設定しておきます

Ruboty

ruboty-templateをForkする

Rubotyをカスタマイズしますので、r7kamuraさんの ruboty-templateをForkします。

ForkしたRubotyをHeroku上にデプロイする

ForkしたリポジトリのREADMEにあるHerokuボタンを押して、RubotyをHerokuにデプロイします。

デプロイ画面で以下の内容を入力してDeploy for Freeをクリックします

  • SLACK_PASSWORD
    • mayubotアカウントでログインして、Account SettingsのGateway Configurationを開くとXMPPのパスワードがあるので、それを入力
  • SLACK_ROOM
    • botを常駐させたいRoom Nameを入力
  • SLACK_TEAM
    • Team Name(xxx.slack.com のxxx部分)
  • SLACK_USERNAME
    • botアカウントの名前(いまはmayubot)

f:id:kentana20:20141102175110j:plain

これで、HerokuにRubotyがデプロイされます。

f:id:kentana20:20141102175139p:plain

動作確認

Rubotyがデプロイできたら、Slack上で話しかけてみます。

f:id:kentana20:20141102175227p:plain

う、う、うごいた〜!! ここまで、コードは1行も書いてません。オドロキ。

RubotyはHubotとは異なり、Rubyで動作しており、その挙動はすべてGemfileによってGemプラグインとして管理されています。そのため、Botに新しい役割を任せたい・挙動を増やしたい場合には新しくGemを作って公開する必要があります。

Hubotの場合は script ディレクトリ内に .coffee ファイルを置いてBotを再起動すれば挙動が追加できたので、手軽さという意味ではHubotの方が良いかもしれませんが

  • Rubyで挙動が書ける
  • Gemで管理できる(配布のラクさ)

といった点ではRubotyにも良い点はありますね。

プラグインを追加する

GemをGistで作成する

さて、無事SlackとRubotyが連携できたので、自作のプラグインを作って新しい挙動を追加してみます。「まゆゆ」はおさわり探偵小沢里奈なめこが大好きだったので、「@mayubot なめこ」と唱えると、「んふんふ」と返すプラグインを作ってみます。Gemで公開する必要があるので、GistでGemを公開したいと思います。

nfu.gemspec

この2つをGistで作成します。こんな感じです。

Gemfileに追加

続いて、ローカルにCloneしたリポジトリのGemfileに以下を追記して、 bundle install します。

source "https://rubygems.org"

gem "rake"
gem "ruboty-alias"
gem "ruboty-cron"
gem "ruboty-google_image"
gem "ruboty-redis"
gem "ruboty-slack"
gem "nfu", :git => "https://gist.github.com/e0f5147312c921ba6ee0.git” # これを追記

Gemがインストールできたら、herokuへpushしてデプロイします。

$ git add .
$ git commit -m “add nfu gem”
$ git push heroku master

なめこを唱えてみる

デプロイが完了したら、いよいよSlack上で @mayubot へ向けて呪文を発動。

f:id:kentana20:20141102180025p:plain

動いた〜!!!!!カンタンにプラグインを追加できました。

所感

  • Rubyプラグインが作れるのがGood
  • Gemで管理できるのも良い
    • プラグインをGemで管理するのはエレガントというか、スマートなので賛否あると思うけど個人的には好き
  • GistでGemを公開するのはすばらし
    • これもr7kamuraさんのエントリを参考にしました。すばらし。普通Gemを公開するなら、bundle gem して、 gem build して gem push するみたいなことが必要なんですが、省略できます。
  • Herokuボタンすごい
    • Herokuボタン、すごいです。超カンタンにアプリをHeroku上にデプロイできます。
  • Ruboty-Template
    • こいつをForkすれば自分が好きにいじれるのでTravisCIを組み合わせればmaster mergeを契機にデプロイを走らせるみたいなこともできてGoodです
  • Botを擬人化するのがオモロイ
    • 他社で見てて良いと思ってやってみたのですが、実際良かったです。オモロイです。オモロイだけじゃなくて、その人のアイデンティティというか、例えば「まゆゆ」の場合だと、テストや共有が好きなエンジニアだったので、「 @mayubot テストおねがい。STね。」とかお願いすることで、E2EのテストをST環境で実行したりとか、デプロイするときに「デプロイいただきまゆゆ」とかできたら更にオモロくて便利になるな、と思いました。冗談抜きで、卒業するメンバーがいたらBotにするとかは面白いかもと考えていたりします。

おまけ(Herokuの設定)

HerokuアプリをローカルにCloneして、デプロイする

SSH公開鍵の登録

$ heroku keys:add

で公開鍵を登録します。鍵がなければ ssh-keygen コマンドを使って鍵ペアを作成して再度上記コマンドを実行します。

HerokuアプリをCloneする

$ heroku git:clone -a $heroku_project_name

でHerokuアプリをCloneできます。

Herokuアプリをデプロイする

$ git push heroku master

でHerokuへローカルのリポジトリをpushしてデプロイできます。


次回は「RubotyサーバとGitHubを連携して自動デプロイする」をお送りします(仮)。

参考

Railsアプリのバックグラウンド処理をWheneverを使ってCron化する

Railsアプリの話。というかWheneverの話。

Railsアプリケーションを実装していて、「この処理はオンラインではなくて、バックグラウンドでバッチ処理にして、Cronで定期実行したいな」っていうとき、ありますよね。そんな時は whenever というgemを使えば、カンタンにバッチ処理をCron化できます。

Wheneverを使ってバックグラウンド処理をCron化する

Wheneverのインストール

まずはBundlerを使って、Wheneverをインストールします。

# Gemfile
gem 'whenever', :require => false

Gemfileに書いたら、bundle install します。

$ bundle install

インストールできたら、一応 gem list でwheneverがインストールできているかを確認します。

$ gem list

インストールされているgemにwheneverが追加されていればOKです。

Wheneverで動かすバックグラウンド処理を作る

続いて、Wheneverで動かすバックグラウンド処理(バッチプログラム的なもの)を作っていきます。Railsのお作法的には、バックグラウンド処理は

  • /lib/tasks/

配下に書くのが正しいカタチのようなので、お作法に従ってバックグラウンド処理を書いていきます。

# /lib/tasks/test.rb
class Test
  def self.hoge
    puts "hoge"
  end
end

続いて、 /lib/ 配下をロードするように /config/application.rb に以下を追加します。

# /config/application.rb
module xxx # railsアプリ名
  class Application < Rails::Application
    config.autoload_paths += %W(#{config.root}/lib)
    config.autoload_paths += Dir["#{config.root}/lib/**/"]
  end
end

ここまで出来たら、以下のコマンドを実行してバックグラウンドで動作する処理が正しく動くことを確認します。

$ rails runner Test.hoge # 'hoge'と返ってくればOK

Wheneverを使ってCronジョブを設定する

以下のコマンドを入力して、wheneverを動かすためのひな形(schedule.rb)を作成します。

$ wheneverize . # /config/schedule.rb が作成されます

作成した schedule.rb にCronで動作させたい処理を記述します。記述方法についてはこちらを参照くださいませ。

# /config/schedule.rb
set :environment, :development
set :output, {:error => 'log/error.log', :standard => 'log/cron.log'}

# Testなので、3分毎に動作するように設定します
every 3.minute do
  # cronのコマンドライン上で動くので、二重引用符で囲っておきます
  runner "Test.hoge"
end

schedule.rb の内容をCronへ登録します。

$ bundle exec whenever --update-cron

これで、crontabにジョブが登録されます。登録内容を確認したければ、

$ bundle exec whenever

とか

$ crontab -e

とかで確認可能です。

登録したジョブを削除(Cron設定の解除)をしたい場合は

$ bundle exec whenever --clear-cron

とすれば削除できます。いや〜、カンタンですね。

所感

今回、初めてWheneverを触りましたが

  • バックグラウンドに移したい処理が既にある
  • Cronの設定方法をある程度理解している

という状況であれば、学習コストは殆どナシでCron化できて便利です。また、Railsアプリの一部(レポジトリを1つ)としてCron設定を管理できるので

  • Cron設定をレポジトリ管理できる
  • RubyでCronを記述できる
  • Webアプリとセットで管理できる

など、イロイロな面でメリットがあるな、と感じました。

また、Capistranoとかと連携すればアプリのデプロイ時に

  • /lib/tasks/ 配下
  • /config/schedule.rb

に変更があった場合は bundle exec whenever --update-cron する、みたいなことを deploy.rb に書いておいてCron設定まで自働化しておけば、「一部のノードだけCron設定を更新し忘れた」みたいなこともなくなるハズなので、いい感じでアプリを管理できそうです。

Railsの便利さ(Wheneverの便利さ?)を改めて感じた3連休最終日でした。

OS XでRedisをインストールしてRuby on Railsで使う(gem 'redis')

連休中にRuby on Railsを使ってWebアプリを作っていて、Redisにデータ登録するとこまでやったので備忘録のために書いておきます。

Redisは高速で動作するインメモリ型のKVSでありながら、非同期でディスクに書き込みを行い、データを永続化してくれるありがたい代物です。

公式サイトは英語ですが、こちらにドキュメントの日本語訳があります。

f:id:kentana20:20140506174657p:plain

日本語ドキュメントがあるので、Redisについての詳細な説明は省きますが、以下のような特徴があります。

Redisの特徴

  • インメモリ型
    • インメモリ型で動作するため、非常に高速
  • データ永続化
    • 非同期でディスクへ書き込むため、データを永続化できる
  • データ構造
    • リスト型、セット型、ハッシュ型といった多彩なデータ構造をサポートしている
  • 豊富な言語サポート(ライブラリ)
    • Ruby, Python, Scala, PHP, Javaなど、様々な言語でライブラリが提供されているため、利用がカンタン
  • レプリケーション

MacOS XRuby on Rails + Redisなアプリを動かす

Redisのインストール

まずはHomebrewでRedisをインストールします。

brew install redis

インストールが完了したら、redis-serverコマンドでバージョンを確認します。

redis-server --version

redis.conf編集

インストールが終了したら、/usr/local/etc/redis.conf を編集します。これは、デフォルトの状態だと /usr/local/var/ 直下にdbファイルなどが作られてしまうための対応です。

/usr/local/var/ を /usr/local/var/redis/ に変更

Redisを起動し、redis-cliで動作確認

confファイルを変更したら、Redisを起動し、redis-cliというコマンドラインで使えるRedisのクライアントルールを起動し、動作確認を行います。

redis-server /usr/local/etc/redis.conf

"set $key $value"でデータ登録、"get $key"でデータ取得ができます。カンタンですね〜。

redis-cli

127.0.0.1:6379> set key val
127.0.0.1:6379> get key ' valが返却

Gemのインストール

redis-cliでの動作確認が完了したら、'redis'というgemをインストールして、RailsアプリケーションのGemfileに'redis'を追加します。

  • gem 'redis' のインストール
gem install 'redis'
  • Gemfile
gem 'redis'

Redis接続情報を作成

/config/inisitalizers/redis.rb を作成し、Redisの接続情報を設定します。

require 'redis'
Redis.current = Redis.new(:host => '127.0.0.1', :port => 6379)

Redisへのデータ登録

Redisでキャッシュしたいデータについて、登録処理を記述します。(ここでは、コントローラに書いています)

class TestController < ApplicationController
require 'redis'

  def test
    Redis.current.set("hoge", "fuga")
  end
end 

登録したデータをredis-cliで確認

redis-cli

127.0.0.1:6379> get "hoge" ' "fuga"が返却

ホントはlib/配下にクラスかモジュールを作って動かすか、app/model/配下にモデルクラスを作ってActiveRecordと連携して使うのが実用的っぽいんですが、今回はRedisを素のままでつかってみたかったので、こういうカタチにしました。

所感

Redisに対する知識は殆どゼロの状態でスタートして、半日程度でWebアプリに組み込むことができたので、学習コストはそれほど高くないという印象です。

ただし、実運用を行う場合は

といった面で、しっかり設計しなければいけないと感じました。 とは言え、キャッシュサーバとして利用するには良いKVSなのでは、と思います。

このアプリのソースはGitHubに上げてあるので、「使い方が違うんじゃ、、」とか「こういう利用方法もある」とか、ご指摘・コメントをいただけたら、とても嬉しいです。

そのうち、EC2上で公開しようと思っていますので、今後をお楽しみに〜!