2017年5月12日金曜日

Rails5.1でdockerの開発環境を整える

環境

  • ruby 2.4.1
  • Rails 5.1.0(+Puma)
  • MySQL 5.7
  • Wercker CI
  • RSpec + FactoryGirl + Faker
  • Rubocop
  • Brakeman

Dockerfile


FROM ruby:2.4.1

ENV APP_ROOT /usr/src/app
ENV ENTRYKIT_VERSION 0.4.0

WORKDIR $APP_ROOT
EXPOSE 3000

## SSLのレポジトリをインストールできるようにします
RUN apt-get update && apt-get install -y apt-transport-https


## yarnのレポジトリをインストールします
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
## Nodejsのレポジトリをインストールします
RUN curl -sL https://deb.nodesource.com/setup_6.x | bash -

# 依存ライブラリをインストールします
RUN apt-get update && apt-get install -y \
      nodejs \
      mysql-client \
      postgresql-client \
      sqlite3 \
      yarn \
      --no-install-recommends && rm -rf /var/lib/apt/lists/*

# EntryKitのインストール
RUN apt-get install openssl \
  && rm -rf /var/cache/apk/* \
  && wget https://github.com/progrium/entrykit/releases/download/v${ENTRYKIT_VERSION}/entrykit_${ENTRYKIT_VERSION}_Linux_x86_64.tgz \
  && tar -xvzf entrykit_${ENTRYKIT_VERSION}_Linux_x86_64.tgz \
  && rm entrykit_${ENTRYKIT_VERSION}_Linux_x86_64.tgz \
  && mv entrykit /bin/entrykit \
  && chmod +x /bin/entrykit \
  && entrykit --symlink

# Rubyのライブラリをインストール
COPY Gemfile $APP_ROOT
COPY Gemfile.lock $APP_ROOT

RUN bundle install --jobs=4

# レポジトリの内容をコピーしておきます
COPY . $APP_ROOT

# サーバー起動前の処理を定義します
ENTRYPOINT [ \
  # 起動前準備スクリプトです。実行権限をつけます。
  "prehook", "chmod +x boot.sh", "--", \
  # 起動前準備スクリプトを実行します。
  "prehook", "bash ./boot.sh", "--"]

解説

アプリのルートディレクトリは/usr/src/appにしていますがこれは特に理由はありません。好みでOKです。

yarnのレポジトリがSSLになっているのですが、使っているイメージruby-2.4.1では下記のエラーが出てインストールできませんでした。
E: The method driver /usr/lib/apt/methods/https could not be found.
apt-transport-httpsを入れて解決してあります。
## SSLのレポジトリをインストールできるようにします
RUN apt-get update && apt-get install -y apt-transport-https

更にEntryKitを使って、サーバー起動前の処理(boot.sh)に繋いでいます。

boot.sh


# Rubyのバージョンを表示します。
ruby -v
# Rubyのライブラリをインストールします。
bundle install -j4
# フロントのライブラリをインストールします。
yarn install --no-optional
# 特定のサーバー・ポートが起動するまで待つスクリプトです。実行権限をつけます。
chmod +x wait-for-it.sh
# MySQL起動を待ちます
./wait-for-it.sh mysql:3306
# DBを更新します。
rake db:create
rake db:migrate
# railsサーバーが起動済だったら殺します
kill -s 9 `pgrep -f 'rails s' `
# pidファイルを消します
rm -f app/tmp/pids/server.pid

boot.shでは以下を行っています。
  • 依存ライブラリの解決
  • MySQLの起動待ち
  • DBの更新
  • rails sの二重起動防止(killspidファイルも消し、)

MySQLの起動待ちにはwait-for-itを使っています。(rootに配置)

docker-compose.yml



version: '3'
services:
  # Railsサーバー
  app:
    build: . # Dockerfileを元にビルドします
    environment:
      RAILS_ENV: development
      DATABASE_URL: mysql2://root:pass@mysql:3306
      PORT: 3000
    ports:
      - 3000:3000
    volumes:
      - .:/usr/src/app
      - bundle:/usr/local/bundle
    depends_on:
      - mysql
    command: ["rails", "s", "-b", "0.0.0.0"]

  # MySQL
  mysql:
    image: mysql:5.7.10
    environment:
      MYSQL_ROOT_PASSWORD: 'pass'
    ports:
      - 7207:3306
    volumes:
      - mysql-data:/var/lib/mysql
# グローバルにvolumesを書くとホストボリュームになり、ファイルを永続化できます。
volumes:
  mysql-data:
    driver: local
  bundle:
    driver: local

docker-composeのバージョン3からホストvolume(グローバルにvolumesを書く)を使ってファイルを永続化しています。
これによりbundle installにやり直しが発生しません。MySQLのデータも永続化している為、開発環境のデータが毎回クリアされることもありません。
また、rails5.1からPORT:3000と指定しないとデフォルトの9292ポートでpumaが起動してしまいます。(バグかは追っていません)

config/application.rb


require_relative 'boot'

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module App
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.1

    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.
    config.generators do |g|
      g.stylesheets false
      g.javascripts false
      g.helper false
      g.test_framework :rspec, view_specs: false, helper_specs: false, fixture: true
      g.template_engine = :slim
    end
  end
end


rails g(enerate) のコマンドの設定を書いています。
  • スタイルシート・JS・ヘルパーの生成を無効に(必要なファイルだけ後で生成します)
  • テストフレームワークはrspecに
  • テンプレートエンジンはslimに
※RSpecでテストを実行する前に、忘れずにrails generate rspec:installを実行してください。

Gemfile


source 'https://rubygems.org'

git_source(:github) do |repo_name|
  repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
  "https://github.com/#{repo_name}.git"
end


# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.1.0'
# Use mysql2 as the database for Active Record
gem 'mysql2'
# Use Puma as the app server
gem 'puma', '~> 3.7'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# See https://github.com/rails/execjs#readme for more supported runtimes
gem 'therubyracer', platforms: :ruby

# Use CoffeeScript for .coffee assets and views
gem 'coffee-rails', '~> 4.2'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.5'
# Use Redis adapter to run Action Cable in production
gem 'redis', '~> 3.0'
# Use ActiveModel has_secure_password
gem 'bcrypt', '~> 3.1.7'
# テンプレートエンジンにslimを使います
gem 'slim-rails'

# Use Capistrano for deployment
gem 'capistrano-rails', group: :development

group :development, :test do
  # セキュリティチェックのBrakemanを導入
  gem 'brakeman', :require => false
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  # Fixtureの代替となるFactoryGirlを導入
  gem 'factory_girl_rails'
  # テストデータ生成のFakerを導入
  gem 'faker'
  # Adds Support for RSpec unit testing
  gem 'rspec-rails', '~> 3.5'
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '~> 2.13.0'
  gem 'selenium-webdriver'
  # CSチェック
  gem 'rubocop', require: false
end

group :development do
  # HTML/ERBからslimに変換します
  gem 'html2slim'
  gem 'listen', '>= 3.0.5', '< 3.2'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
  # Access an IRB console on exception pages or by using <%= console %> anywhere in the code.
  gem 'web-console', '>= 3.3.0'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]


Gemfileは日本語注釈がついたものを追加したのと、redis, bcryptあたりは後々使いそうだったのでコメントを外しています。

開発運用

docker-compose up -d(初回のみ)
docker-compose logs(うまく動かない時のログを見る)
docker-compose restart(gem等がうまくrailsサーバーに伝わらない時実行)
docker-compose down(コンテナを落とす)
docker-compose rm(イメージを消す)
docker-compose exec app bash (擬似的にシェルログインできます。アプリサーバーでコマンド実行 ※これで普通にrailsコマンドが実行できるようになります)

wercker.yml


# 下記を参考に作成しています
# http://qiita.com/masashi-sutou/items/d0fcec3a14c1c89ae702

# This references the default Ruby container from
# the Docker Hub.
# https://registry.hub.docker.com/_/ruby/
# If you want to use a specific version you would use a tag:
# ruby:2.2.2
box: ruby:2.4.1
# You can also use services such as databases. Read more on our dev center:
# http://devcenter.wercker.com/docs/services/index.html
# services:
    # - postgres
    # http://devcenter.wercker.com/docs/services/postgresql.html

    # - mongo
    # http://devcenter.wercker.com/docs/services/mongodb.html

services:
  - id: mysql
    env:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_USER: test_user
      MYSQL_PASSWORD: test_password
      MYSQL_DATABASE: test_database

# This is the build pipeline. Pipelines are the core of wercker
# Read more about pipelines on our dev center
# http://devcenter.wercker.com/docs/pipelines/index.html
build:
    # Steps make up the actions in your pipeline
    # Read more about steps on our dev center:
    # http://devcenter.wercker.com/docs/steps/index.html
    steps:
        - install-packages:
            name: Install mysql client
            packages: mysql-client
        - rails-database-yml:
            service: mysql-docker
        - bundle-install:
            jobs: 4
        - script:
            name: Run RSpec
            code: bundle exec rspec
        - script:
            name: Run Brakeman
            code: bundle exec brakeman -qz

mysql clientをインストールする前にbundle installすると、bundle install時にリンクに失敗しているのか、libmysqlclientが見つからないエラーが出ます。
bundle installの結果は永続化されている為、2回目以降のビルドが高速です。

開発が進んだ後で、アプリのビルドイメージを作ってレポジトリに上げたものを使うようにwerckerの設定を修正する予定です。

参考記事・サイト

2016年8月27日土曜日

Vagrant+ChefでNodejsをバージョン指定していれる

Nodejsの案件対応が発生した為、NodejsをVagrant+Chef環境で動かそうとしました。
誰かがまとめてくれているだろうと調べましたが、意外にも情報がほとんどありませんでした。
調べた結果をご紹介します。

前提

  • CentOS7
    • ubuntuだとバイナリのインストールがうまくいきませんでした
    • 6でも問題ないとは思いますが検証していません
  • cookbook

Gemfile

 source 'https://rubygems.org'  
 gem 'berkshelf'  
 gem 'knife-solo'  

Berksfile

 source "https://supermarket.chef.io"  
 cookbook "nodejs"  


bundlerをインストール(gem install bunbler)をし、
下記コマンドでcookbookをインストールします

$ bundle exec berks vendor ./cookbooks
$ bundle exec knife cookbook create base -o site-cookbooks
これでcookboks以下に外部のcookbook、site-cookbooksに実行するcookbookの用意ができました。

レシピは `site-cookbooks/base/recipes/default.rb` に作成します.

 include_recipe "nodejs"  

上記でnodejsのレシピを読み込んで使っています

バージョン指定等の属性は以下のファイルに書きます
`site-cookbooks/base/attributes/default.rb`

 node.default['nodejs']['install_method'] = 'binary'  
 node.default['nodejs']['version'] = '5.9.0'  
 node.default['nodejs']['binary']['checksum'] = '99c4136cf61761fac5ac57f80544140a3793b63e00a65d4a0e528c9db328bf40'  

checksumやバージョンは以下でリストを見れます
https://nodejs.org/dist/
今回はCentOS 64bit、4.4.7をインストールしたいので次のバイナリが該当
https://nodejs.org/dist/v4.4.7/node-v4.4.7-linux-x64.tar.gz
チェックサムは同じディレクトリのSHASUMS256.txtを確認する
https://nodejs.org/dist/v4.4.7/

おまけ

Vagrantfile


 # -*- mode: ruby -*-  
 # vi: set ft=ruby :  
 # All Vagrant configuration is done below. The "2" in Vagrant.configure  
 # configures the configuration version (we support older styles for  
 # backwards compatibility). Please don't change it unless you know what  
 # you're doing.  
 Vagrant.configure("2") do |config|  
  # The most common configuration options are documented and commented below.  
  # For a complete reference, please see the online documentation at  
  # https://docs.vagrantup.com.  
  # Every Vagrant development environment requires a box. You can search for  
  # boxes at https://atlas.hashicorp.com/search.  
  config.vm.box = "centos/7"  
  # Disable automatic box update checking. If you disable this, then  
  # boxes will only be checked for updates when the user runs  
  # `vagrant box outdated`. This is not recommended.  
  # config.vm.box_check_update = false  
  # Create a forwarded port mapping which allows access to a specific port  
  # within the machine from a port on the host machine. In the example below,  
  # accessing "localhost:8080" will access port 80 on the guest machine.  
  # config.vm.network "forwarded_port", guest: 80, host: 8080  
  # Create a private network, which allows host-only access to the machine  
  # using a specific IP.  
  # config.vm.network "private_network", ip: "192.168.33.10"  
  config.vm.network :private_network, ip: "192.168.240.100"  
  # config.nfs.map_uid = 500  
  config.vm.synced_folder ".", "/host_mount",  
   id: "vagrant-root", :nfs => true  
  config.bindfs.bind_folder "/host_mount","/srv", :owner => "vagrant", :group => "vagrant", :'create-as-user' => true, :perms => "u=rwx:g=rwx:o=rwx", :'create-with-perms' => "u=rwx:g=rwx:o=rwx", :'chown-ignore' => true, :'chgrp-ignore' => true, :'chmod-ignore' => true  
  ## provision等の前に共有ディレクトリを解除してキャッシュが使われることを防ぐ  
  config.trigger.before [:reload, :up], stdout: true do  
   run "rm -f .vagrant/machines/default/virtualbox/synced_folders"  
  end  
  config.vm.provision :chef_solo do |chef|  
   chef.cookbooks_path = ["./cookbooks", "./site-cookbooks"]  
   chef.json = {  
   }  
   chef.run_list = %w[  
    recipe[base]  
   ]  
  end  
 end  


2016年4月30日土曜日

[iOS] NCMBとFacebookSDKの競合の解決

ニフティクラウド mobile backend(NCMB)を使ってiOSアプリを開発しています。
NCMBのライブラリとFacebookSDKの一部のライブラリが、CocoaPodsのuse_frameworks!を使っている場合うまく動作しなかったので、その解決をしました。
経緯と解決方法、ライブラリとサンプルアプリ等をまとめてqiitaに投稿しました。

NCMBでPodのuse_frameworks!有効時にFacebookSDKが入れられないことを解決した
http://qiita.com/hiromi2424@github/items/01bd4530c176fbe2db2e

NCMBを使ってiOSアプリ開発をする場合は是非参考にしてみてください。

2015年9月15日火曜日

執筆しました。

僭越ながら執筆させて頂きました。 これからWEBアプリについて勉強する方や始めて間もない方へ特におすすめです。

2013年4月25日木曜日

2013/04/25 CakePHP講師情報


2013/04/25(木)に株式会社インテリジェンス様主催でCakePHP勉強会がマルチメディアスクールWAVE様にて行われました。

その際に講師をやらさせて頂きましたのでご報告させて頂きます。

http://atnd.org/event/inte4


2013年3月29日金曜日

2013/03/29 CakePHP講師情報


2013/03/29(金)にマルチメディアスクールWAVE様にてCakePHPハンズオンが行われました。

その際に講師をやらさせて頂きましたのでご報告させて頂きます。

http://atnd.org/events/37963


2013年3月27日水曜日

2013/03/27 TwitterBootstrapで覚えるHTML5とjQuery


2013/03/27(水)に株式会社インテリジェンス様主催で勉強会を行いました。

その際に講師をやらさせて頂きましたのでご報告させて頂きます。

http://atnd.org/event/inte3