コンテンツにスキップ

Recent Posts

Android StudioからGAE for Javaアプリケーションをdeployするのに必要なFacet

こちらの記事を参考にGAE for JavaアプリケーションをAndroid Studio + Gradleでセットアップし、サンプルアプリケーションを開発してみました。

早速GAEにdeployしてみようと、メニューバーの Build から Deploy Module to App Engine... を選択してdeployを実行...ところがタスクが走らずうんともすんとも言わないので調べてみました。

結論

以下の設定を app.iml ファイルに追記する

<facet type="android-gradle" name="Android-Gradle">
  <configuration>
    <option name="GRADLE_PROJECT_PATH" value=":app" />
  </configuration>
</facet>
<facet type="java-gradle" name="Java-Gradle">
  <configuration>
     <option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
     <option name="BUILDABLE" value="true" />
  </configuration>
</facet>

こちらは少々特殊な方法でmoduleを作成しているのでFacetの設定が不十分となってしまった模様。

Facetとは

FacetはIntelliJ IDEAに用意された機能で、使用するフレームワークや言語に合わせたFacetを設定することでIntelliJ IDEAが必要なコンポーネントのダウンロードや各種補完機能の設定などを行ってくれるもの。

Android StudioはIntelliJ IDEAをベースとして開発されたIDEなのでFacetの機能を継承している。

参照

DockerでRails環境を構築した手順

2016/07/10 修正: docker-compose.ymlnginx.conf の一部を修正しました

とある経緯で Docker を使って Rails の環境をセットアップした手順です。

setting files

まずは用意した file から。

docker-compose.yml

``` yml docker-compose.yml

not use datastore container now

datastore:

build: Dockerfiles/datastore

mysql: image: mysql:5.6.26 environment: MYSQL_ROOT_PASSWORD: 'pass' ports: - '3306:3306'

volumes_from:

- datastore

nginx: build: Dockerfiles/nginx ports: - '80:80'

volumes_from:

- datastore

links: - web

web: build: .

command: bundle exec unicorn -c config/unicorn.rb

volumes_from:

- datastore

volumes: - .:/usr/src/app ports: - '3000:3000' links: - mysql environment: RAILS_ENV: development MYSQL_ROOT_PASSWORD: 'pass' DATABASE_URL: mysql2://root:pass@mysql:3306 SECRET_KEY_BASE: hogehoge


## Dockerfile
``` dockerfile Dockerfile
FROM rails:onbuild

Dockerfiles/nginx/Dockerfile

``` dockerfile Dockerfile FROM nginx:1.7.9

COPY nginx.conf /etc/nginx/nginx.conf


## Dockerfiles/nginx/nginx.conf
``` bash nginx.conf
user  nginx;
worker_processes  1;

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

events {
  worker_connections 1024; # increase if you have lots of clients
  accept_mutex off; # "on" if nginx worker_processes > 1
}

http {
  include mime.types;
  default_type application/octet-stream;
  log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

  access_log  /var/log/nginx/access.log  main;

  sendfile on;

  tcp_nopush on; # off may be better for *some* Comet/long-poll stuff
  tcp_nodelay off; # on may be better for some Comet/long-poll stuff

  gzip on;
  gzip_http_version 1.0;
  gzip_proxied any;
  gzip_min_length 500;
  gzip_disable "MSIE [1-6]\.";
  gzip_types text/plain text/html text/xml text/css
             text/comma-separated-values
             text/javascript application/x-javascript
             application/atom+xml;

  upstream app_server {
    # for UNIX domain socket setups:
    # server unix:/path/to/.unicorn.sock fail_timeout=0;

    # for TCP setups, point these to your backend servers
    # server 192.168.0.7:8080 fail_timeout=0;
    server web:3000 fail_timeout=0;
  }

  server {
    listen       80;
    server_name  localhost;
    client_max_body_size 4G;
    keepalive_timeout 5;

    # path for static files
    root /usr/your_app/home/system/public;

    try_files $uri/index.html $uri.html $uri @app;

    location @app {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;
      proxy_pass http://app_server;
    }

    # Rails error pages
    error_page 500 502 503 504 /500.html;
    location = /500.html {
      root /usr/your_app/home/system/public;
    }
  }
}

Setup Tutorial

Download Tools

VirtualBox

https://www.virtualbox.org/wiki/Downloads

please install version >= 5.x

Homebrew

http://brew.sh/index_ja.html

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Docker Tools

Docker
$ brew install docker
Docker Machine
$ brew install docker-machine
Docker Compose
$ brew install docker-compose

Download Application

$ cd ~/path/to/workspace
$ git clone git@github.com:your/App.git your_app
$ cd your_app

Setup Docker Machine

$ docker-machine create --driver virtualbox dev
...

$ docker-machine ls
NAME   ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER    ERRORS
dev    -        virtualbox   Running   tcp://192.168.99.100:2376           v1.10.0
$ eval "$(docker-machine env dev)"

$ echo 'eval "$(docker-machine env dev)"' >> ~/.bashrc
$ docker-machine start dev
...

$ docker-machine ip dev
192.168.99.100

Setup Application

Build Docker Images and Start Containers

# ~/path/to/workspace/your_app
$ docker-compose build
...

$ docker-compose up
...

please open another tab

Setup DB

$ docker-compose run web rake db:create
$ docker-compose run web rake db:migrate

Access Application

$ docker-machine ip dev
192.168.99.100

access to 192.168.99.100:3000

plenv で perl を管理する

Perl をバージョンごと、あるいはプロジェクトごとに管理するためのツールである plenv の導入手順メモ

plenv をインストールする

homebrew の update

$ brew update
Updated Homebrew from c0fae05 to bfe20af.
No changes to formulae.

先ほど rbenv をインストールする手順 で同じことをやったばかりなので更新なし

plenv と perl-build のインストール

これも どこか で見たような手順

perl-buildplenv のプラグイン

$ brew install plenv perl-build
==> Downloading https://github.com/tokuhirom/plenv/archive/2.2.0.tar.gz
==> Downloading from https://codeload.github.com/tokuhirom/plenv/tar.gz/2.2.0
...

plenv init

$ echo 'eval "$(plenv init -)"' >> ~/.bash_profile
$ source ~/.bash_profile

plenv init - でやっていることは以下の通り

$ plenv init -
export PATH="/Your/Home/Directory/.plenv/shims:${PATH}"
export PLENV_SHELL=bash
source '/usr/local/Cellar/plenv/2.2.0/libexec/../completions/plenv.bash'

plenv() {
  local command

  command="$1"
  if [ "$#" -gt 0 ]; then
    shift
  fi

  case "$command" in
  rehash|shell)
    eval "`plenv "sh-$command" "$@"`";;
  *)
    command plenv "$command" "$@";;
  esac
}

perl のインストール

インストールできる perl のバージョンを確認

$ plenv install -l
Available versions:
 5.6.0
 5.6.1-TRIAL1
 5.6.1-TRIAL2
...

最新の安定版であるバージョン 5.22.1 をインストールする

$ plenv install 5.22.1
Installing 5.22.1 as 5.22.1
...

インストールされたバージョンを確認

$ plenv versions
* system (set by /My/Home/Directory/.plenv/version)
  5.22.1

使用する perl を設定

$ plenv global 5.22.1
$ plenv versions
  system
* 5.22.1 (set by /My/Home/Directory/.plenv/version)

perl に cpanm をインストールする

現在使用している perl に cpanm をインストールする

$ plenv install-cpanm
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   314    0   314    0     0   2078      0 --:--:-- --:--:-- --:--:--  2079
100  296k  100  296k    0     0   367k      0 --:--:-- --:--:-- --:--:-- 2135k
...

cpanm のパスが変わっていることを確認

$ which cpanm
/My/Home/Directory/.plenv/shims/cpanm

参照

rbenv で ruby を管理する

Ruby をバージョンごと、あるいはプロジェクトごとに管理するためのツールである rbenv の導入手順メモ

rbenv をインストールする

homebrew の update

$ brew update
Updated Homebrew from b369c25 to c0fae05.
...

rbenv と ruby-build のインストール

rbenv と同時に ruby-build もインストールする

ruby-buildrbenv のプラグインで rbenv install コマンドを提供する

$ brew install rbenv ruby-build
==> Installing dependencies for rbenv: autoconf, pkg-config, openssl, ruby-build
...

rbenv init

$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ source ~/.bash_profile

rbenv init - でやっていることは以下の通り

$ rbenv init -
export PATH="/Your/Home/Directory/.rbenv/shims:${PATH}"
export RBENV_SHELL=bash
source '/usr/local/Cellar/rbenv/1.0.0/libexec/../completions/rbenv.bash'
command rbenv rehash 2>/dev/null
rbenv() {
  local command
  command="$1"
  if [ "$#" -gt 0 ]; then
    shift
  fi

  case "$command" in
  rehash|shell)
    eval "$(rbenv "sh-$command" "$@")";;
  *)
    command rbenv "$command" "$@";;
  esac
}

ruby のインストール

インストールできる ruby のバージョンを確認

$ rbenv install -l
Available versions:
  1.8.6-p383
  1.8.6-p420
  1.8.7-p249
...

バージョン 2.2.0 をインストールする

$ rbenv install 2.2.0
Downloading ruby-2.2.0.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.2/ruby-2.2.0.tar.bz2
Installing ruby-2.2.0...
...

インストールされたバージョンを確認

$ rbenv versions
* system (set by /My/Home/Directory/.rbenv/version)
  2.2.0

使用する ruby を設定

$ rbenv global 2.2.0
$ rbenv versions
  system
* 2.2.0 (set by /My/Home/Directory/.rbenv/version)

ブログを管理しているディレクトリは system ruby にしておく

$ cd git/blog/
$ rbenv local system
$ rbenv versions
* system (set by /My/Home/Directory/git/blog/.ruby-version)
  2.2.0
$ cd
$ rbenv versions
  system
* 2.2.0 (set by /My/Home/Directory/.rbenv/version)

参照

minil を使った Changes ファイルの更新

CPAN モジュールの bug fix を行ったので修正版をリリース。

minil 様様と思いながら minil release コマンドを打つのだが、 いつも Changes ファイルの更新のところで、どこに何を書けば良いのだっけ?となってしまうのでここにメモしておくことにした。

{{$NEXT}} の下に書く

今回のリリースだとこうなった

Revision history for Perl extension JSON-MergePatch

{\{$NEXT}}

    - (bug fix) diff() :when the same hash-refs are present in the hash values of source and target (thanks bessarabov)
    - refactoring

0.02 2015-09-13T09:08:20Z

    - use JSON::MaybeXS and fix keys arg

0.01 2015-07-02T18:29:20Z

    - original version

{{$NEXT}} となっているところにバージョンやら日付やらが入る。

参照

Minilla チュートリアルドキュメント

Chef のリモート実行

前回 対象サーバで直接 Chef を実行してみました。

今回は手元からリモートのサーバに対して Chef を実行する仕組みを試してみます。

knife-solo のインストール

手元のクックブックをリモートのサーバに転送して chef-solo コマンドを実行するまでの一連の作業を実行できる knife-solo コマンドをインストールする

knife-solo コマンドは gem でインストールできる。手元の Mac OS でインストール

$ sudo gem install knife-solo
...
Thanks for installing knife-solo!
...
36 gems installed

Berkshelf のインストール

クックブックの依存関係を管理する Berkshelf というツールもこのタイミングでインストールする。これは knife-solo が他の gem のインストール状況によってデフォルトのオプションが変わるため

$ sudo gem install berkshelf
...
25 gems installed

ローカルにリポジトリを作る

まずはローカルにリポジトリを作る

Vagrantfile があるディレクトリで以下のコマンドを実行して作成する

$ knife solo init .
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/rubygems/specification.rb:2007:in `raise_if_conflicts': Unable to activate rspec-3.0.0, because rspec-core-3.4.0 conflicts with rspec-core (~> 3.0.0), rspec-expectations-3.4.0 conflicts with rspec-expectations (~> 3.0.0), rspec-mocks-3.4.0 conflicts with rspec-mocks (~> 3.0.0) (Gem::LoadError)

エラーが発生した

rspec と rspec-core のバージョンが合っていなかったので rspec を update する

$ sudo gem update rspec
...
Gems updated: rspec rspec-collection_matchers

再度リポジトリの作成を実行

$ knife solo init .
WARNING: No knife configuration file found
Creating kitchen...
Creating knife.rb in kitchen...
Creating cupboards...
Setting up Berkshelf...

これで実行ディレクトリ内に様々な雛形ディレクトリ、ファイルが作成された

リモートのサーバに Chef Solo をインストールする

今回リモートサーバとして想定する Vagrant の環境に対して SSH の設定を以下のようにしておく

$ vagrant ssh-config --host testhost >> ~/.ssh/config

以下のコマンドで Chef Solo をリモートサーバに対してインストール

$ knife solo bootstrap testhost
Bootstrapping Chef...
...
Thank you for installing Chef!
...
Chef Client finished, 0/0 resources updated in 06 seconds

今回は前回 Chef Solo をインストールした環境に対して打ったので最終的な結果は 0/0 resources updated になっている

クックブックの作成

ローカルにクックブックを作成する。今回は git をインストールするためのクックブックを作る

自作のクックブックは site-cookbooks 以下に置くことが慣例になっているので出力先に site-cookbooks を指定している

$ knife cookbook create git -o site-cookbooks

これで site-cookbooks 以下に git クックブックの雛形が出来上がる

レシピの編集

レシピの雛形 site-cookbooks/git/recipes/default.rb を編集していく

$ vim site-cookbooks/git/recipes/default.rb
$ cat site-cookbooks/git/recipes/default.rb
#
# Cookbook Name:: git
# Recipe:: default
#
# Copyright 2015, YOUR_COMPANY_NAME
#
# All rights reserved - Do Not Redistribute
#
package "git" do
    action :install
end

Node オブジェクトの編集

Chef で管理する Node (サーバ)の状態を記述し、それぞれの Node に対してどのクックブックが適用されるかを設定する Node オブジェクトを編集する

Node オブジェクトは knife solo bootstrap testhost 実行時に nodes/testhost.json として作成されている

今回はここに先ほど作成した git クックブックの適用を記述する

$ vim nodes/testhost.json
$ cat nodes/testhost.json 
{
  "run_list": [
    "recipe[git]"
  ],
  "automatic": {
    "ipaddress": "testhost"
  }
}

クックブックの実行

準備が整ったのでいよいよクックブックをリモートサーバに対して実行する

以下のコマンドで実行

$ knife solo cook testhost
Running Chef on testhost...
...
Chef Client finished, 0/1 resources updated in 07 seconds

これも同じく前回の環境ですでに git をインストール済みなので 0/1 resources updated として正常に実行された

これでリモートへの Chef 実行完了!

参照

初めてのChef

Chef を使ってみます。 Vagrant で環境をつくっておいてそこで色々試してみます。

今回はゲスト側でクックブック、レシピを作って実行してみます。

Chef のインストール

vagrant ssh で Vagrant の環境に入って Chef をインストールする

$ curl -L https://www.opscode.com/chef/install.sh | sudo bash
...
Thank you for installing Chef!

Chef Solo がインストールされているか確認

$ chef-solo -v
Chef: 12.5.1

クックブックを作る

Chef をインストールすると knife というコマンドもインストールされる。 この knife コマンドを使ってクックブックを作る

今回は git をインストールするための git クックブックを作る

コマンドは以下のように指定する

knife cookbooks create [クックブック名]

今回は出力先を指定する -o オプションを指定

$ sudo knife cookbook create git -o /var/chef/cookbooks

このコマンドで git という名前のクックブックが作成され、 /var/chef/cookbooks/git/recipes/default.rb にレシピの雛形が作られる

レシピの編集

レシピの雛形に git をインストールするレシピを書く

$ sudo vi /var/chef/cookbooks/git/recipes/default.rb
$ cat /var/chef/cookbooks/git/recipes/default.rb
#
# Cookbook Name:: git
# Recipe:: default
#
# Copyright 2015, YOUR_COMPANY_NAME
#
# All rights reserved - Do Not Redistribute
#

package "git" do
  action :install
end

クックブックの実行

作成したクックブックを実行する

$ sudo chef-solo -o git
...
Compiling Cookbooks...
Converging 1 resources
Recipe: git::default
  * yum_package[git] action install
    - install version 1.7.1-3.el6_4.1 of package git

Running handlers:
Running handlers complete
Chef Client finished, 1/1 resources updated in 38 seconds

git がインストールされたか確認

$ git --version
git version 1.7.1

Chef の特徴

OS の違いを吸収してくれる

上記 git の例ではこちらで指定していないにも関わらず、実行した環境が CentOS であることを解釈して yum パッケージでインストールが行われた

実行された環境の OS 毎の違いを吸収してくれる

冪等性が担保されている

先ほどのクックブックをもう一度実行してみる

$ sudo chef-solo -o git
...
Chef Client finished, 0/1 resources updated in 07 seconds

今回は何もせずに正常に終了したことが分かる

Chef ではクックブックを何度実行しても、クックブックに規定された状態になる冪等性が担保されている

参照

余談: Chef に関する記事は web 上にも色々ありますが、 Chef は用途によって様々なツール、使い方があり、基本的な用語や概念などを理解できていないと思わぬところでハマってしまいがちです。 Chef 実践入門 は Chef に関して体系的に理解できるので最初にサラッと読んでしまうのが近道だと感じました。

InnoDBにおけるSQL別ロックの挙動

研修時代に書いた InnoDB に関するメモ第二弾。

ロックの挙動に関しては基礎の基礎でちょっと考えれば分かるものの、開発しているとふとしたところで考慮が漏れていたりするので注意したい。

SELECT ... FROM

一貫性読み取りであり、データベースのスナップショットを読み取り、トランザクションの遮断レベルが SERIALIZABLE に設定されなければロックは設定しません。SERIALIZABLE レベルの場合、検索時に直面したインデックスレコード上に共有ネクストキーロックが設定されます。

SELECT ... FROM ... LOCK IN SHARE MODE

_検索時に直面したすべてのインデックスレコード上_に 共有ネクストキーロック が設定されます。

SELECT ... FROM ... FOR UPDATE

_検索で特定されたインデックスレコード_に対し、 排他ネクストキーロック が設定され、ほかのセッションが SELECT ... FROM ... LOCK IN SHARE MODE を実行したり、特定のトランザクション遮断レベルで読み取りを行ったりできないようにします。 ただし、ギャップロックの部分に関しては共有ロックとなります

UPDATE ... WHERE ...

_検索が直面するすべてのレコード上_に 排他ネクストキーロック を設定します。

DELETE FROM ... WHERE ...

_検索が直面するすべてのレコード上_に 排他ネクストキーロック を設定します。

INSERT

挿入される行に排他ロック を設定します。このロックはネクストキーロックではなくインデックスレコードロックである (つまりギャップロックが存在しない) ため、ほかのセッションは挿入行の前にあるギャップへの挿入を自由に行えます。

参照

InnoDBにおけるロックの種類

MySQL でよく使う InnoDB のロックについて研修時代に書いたメモ。

種類

  • レコードロック: インデックスレコードの ロック
  • ギャップロック: インデックスレコード間にあるギャップのロック、先頭のインデックスレコードの前や末尾のインデックスレコードの後にあるギャップのロック、のいずれか
  • ネクストキーロック: インデックスレコードに対するレコードロックと、そのインデックスレコードの前、または後ろにあるギャップに対するギャップロックとを組み合わせたもの

InnoDBの行ロック(レコードロック)

InnoDBは行ロックができる、とよく言いますが、 正確には インデックスレコード にロックをかけているので、 primary key や、unique key といったレコードを一意に特定できるインデックスを使用せずにロックをかけるとテーブルロックの様な挙動を示します。(実際には隠しクラスタインデックスが生成、使用される。)

ギャップロック、ネクストキーロック

ギャップロック、ネクストキーロックは

  • 範囲を指定して(複数のレコードにまたがって)ロックを獲得しようとしたとき
  • 存在しないレコードに対してロックを獲得しようとしたとき

のみ起こりうる。

また、 ギャップロックは常に共有ロックと同じ挙動 を示す

前提:id(primary key)が10, 20, 30のレコードが入っているテーブル

select from table where id = 15 for update;    #id 11~19にギャップロック
select from table where id < 15 for update;    #id ~20にネクストキーロック
select from table where id < 20 for update;    #id ~20にネクストキーロック
select from table where id <= 20 for update;   #id ~30にネクストキーロック
select from table where id > 15 for update;    #id 11~にギャップロック
select from table where id = 35 for update;    #id 31~にギャップロック

参照

実践ハイパフォーマンスMySQL 第3版

Rails アプリを MySQL で作るときのメモ

Rails 4.0.5 のアプリを MySQL で立てるときのメモ

rails new にオプションをつける

オプションを付けずに rails new すると SQLite で立てられてしまうので、以下のようにする。

$ rails new app_name -d mysql

mysql2 のバージョンを指定

2015/09/21 時点の mysql2 は rails 上での実行時にバグを含んでいるようなのでバージョン指定する。

```ruby Gemfile gem 'mysql2', '~> 0.3.20'

```bash
$ bundle install

mysql のパスワード設定

config/database.yml に mysql のパスワードを設定する。環境変数の指定は以下のようにする。 ```yml config/database.yml development: adapter: mysql2 encoding: utf8 database: app_name_development pool: 5 username: root password: <%= ENV['MYSQLPASS'] %> socket: /var/lib/mysql/mysql.sock


### database の作成
最後に database を作って完了。
```bash
$ rake db:create

参照