キチログ

Keep it simple, stupid.

ERROR! The server quit without updating PID file の対処

http://unix-like.dyndns-web.com/?p=242

OSX Lion, Homebrewで入れたmysqlが起動しない夜 - ワインのばか

いろいろ調べていろいろやってみた。

PIDファイルは直接の原因ではなく別の要因で起動に失敗しているようだ。

/usr/local/var/mysqlのownerが_mysqlになっていたのでそれを変更したら一度は起動したがまた起動しなくなった。

権限があやしいが、結果完全に直せなかったのであきらめて再インストールしたら完治した。

brew uninstall mysql

sudo rm -rf /usr/local/var/mysql

brew install mysql

NodeアプリケーションをAmazon EC2にデプロイ

Node(Express) × MongoDB(Mongoose)アプリケーションをAWS EC2にデプロイして公開します。

AWS EC2 セットアップ

このへんはぱぱっとメモしておきます。

  1. AWSアカウント登録(http://aws.amazon.com/jp/

    最小サイズのAmazon EC2 Micro Instanceの使用は、1年間 750h/月まで無料で利用できます。(2014/8時点)

  2. サインイン

  3. Amazon EC2ダッシュボードを開き、メニューのInstancesをクリック
  4. 担当サーバーの地域を変更

    右上のUSなんたらとなっているのをAsia Pacific(Tokyo)に変更。

  5. Launch Instanceを押して新たにインスタンスを作成

  6. wap, dbそれぞれのインスタンスを作成
  7. wap, dbそれぞれのSecurity Groupを変更
    • wap: Inbound > Edit > Add Rule > Type:All TCP, Source:Anywhere > Save
    • db: Inbound > Edit > Add Rule > Type:HTTP, Source:Anywhere > Save

以上でサーバーが完成しました。

wap, dbそれぞれへのアクセス方法は同ページのConnectボタンをクリックすると詳しく記述されてます。(以下抜粋)


To access your instance:

Open an SSH client. (find out how to connect using PuTTY)

Locate your private key file (aws_key_tokyo.pem). The wizard automatically detects the key you used to launch the instance.

Your key must not be publicly viewable for SSH to work. Use this command if needed:

chmod 400 aws_key_tokyo.pem

Connect to your instance using its Public IP:

54.92.70.194

Example:

ssh -i aws_key_tokyo.pem ec2-user@54.92.70.194

Please note that in most cases the username above will be correct, however please ensure that you read your AMI usage instructions to ensure that the AMI owner has not changed the default AMI username.

If you need any assistance connecting to your instance, please see our connection documentation.



では、

wap, db各サーバーにアクセスしてデプロイしていきます。

DBサーバー セットアップ

参考

mongodbインストール

yumでmongodb-org-serverとmongodb-org-shellをインストール。

$ sudo yum -y update

$ echo "[MongoDB]
name=MongoDB Repository
baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64
gpgcheck=0
enabled=1" | sudo tee -a /etc/yum.repos.d/mongodb.repo

$ sudo yum install -y mongodb-org-server mongodb-org-shell

インストールしたらさっそく起動。

$ sudo service mongod start

コンソール立ち上げてみる。

$ mongo

起動を確認できたら次は、nodeアプリから接続してみる。ただし、そのままだとホストがバインドされているのでアクセスできません。設定していきます。

接続設定

設定ファイル/etc/mongod.confを書き換える。

$ sudo vi /etc/mongod.conf

接続可能なホストを設定

デフォルトの設定だと、接続可能なホストがローカルホストにバインドされている。とりあえずコメントアウトしてホストの制限を解除。

bind_ip=127.0.0.1
↓
# bind_ip=127.0.0.1

ポートを指定

# port=27017
↓
port=27017

以上二点。変更したら再起動。再起動しないと設定は反映されない。

$ sudo service mongod restart

これで外部からDBサーバーのmongodbにアクセスできるようになった。

アプリ側のURLを変更

これまでローカル開発してきたなかでURLは以下のようになっていたはず。

mongoose.connect('mongodb://localhost/sampledb');
or
mongoose.connect('mongodb://127.0.0.1/sampledb');

以下のような感じで書き換えればOK。

mongoose.connect('mongodb://sample.com/sampledb');

こんなかんじで、アプリと外部に設置したmongodbを連携することができるようになった。

次は、認証かけます。

認証設定

ユーザーを追加

続けてDBさーばーで作業します。コンソールに入る。

$ mongo DB名

ユーザー作ります。

> db.addUser("user", "pass");

認証を有効にする

デフォルトでは認証が無効になっています。さきほどと同様/etc/mongod.confを書き換えます。

# auth=true
↓
auth=true

再起動。

$ sudo service mongod restart

接続してみる。

// mongoシェル起動時に認証
$ mongo -u user -p pass DB名

// mongoシェル内で認証
> db.auth('user', 'pass');

ちなみに、

$ mongo DB名

でシェル内には入れるけど、ちゃんと認証しないと情報はみれません。

アプリ側のURLを変更

認証をかけたので、アプリ側のURLにも認証情報を追記しないといけません。

以下のようなかんじ。

mongoose.connect('mongodb://user:pass@sample.com/sampledb')

WEBサーバー セットアップ

参考

ポート番号の書き換え

いままでローカルで開発してきたので、プログラムのportをHTTP(80)に変更する必要があります。

node, npmインストール

$ sudo yum -y update
$ sudo yum -y install nodejs npm --enablerepo=epel

gitインストール

今回githubレポジトリからアプリケーションをもってくるのでgit入れます。

$ sudo yum -y install git

デプロイ(仮)

とりあえずホームディレクトリにアプリをクローン。

$ mkdir app
$ cd app

$ git clone レポジトリURL

そしたら、nodeモジュールとかbowerライブラリとか入れましょう。

$ cd アプリケーションディレクトリ

$ npm install
$ npm install -g bower
$ bower install

あとはアプリを立ち上げればOK。とりあえず永続化は置いておいて、nodeコマンドで起動してwebからアクセスしてみたらよし。いけた。

デプロイ(永続化) = リリース

nodejsはコマンドアプリケーションのため、コンソール閉じるとアプリが終了してしまいます。

そのため、永続的に起動するには、コンソールからnodejsを切り離す。

やり方としては

  • nohupコマンド
  • foreverパッケージを利用

があるみたい。今回はforeverでやる。https://github.com./nodejitsu/forever

foreverはハンドルされていない例外が発生してプログラムが停止した場合自動で再起動やってくれる。一応プログラムがエラーで勝手に止まっちゃう心配はなし。

foreverをインストール

$ sudo npm install -g forever

foreverめも

書式
forever [options] [action] SCRIPT [script-options]
よく使いそうなaction
// プログラムを実行
forever start SCRIPT

// 実行中のプロセスを確認. ここで表示されるログファイルなどチェック
forever list

// プログラムを停止. プロセス番号はforever listで確認
forever stop プロセス番号

// プログラムを再起動. プロセス番号はforever listで確認
forever restart プロセス番号

プログラムの実行権限の変更

UNIX系OSの場合、1023番以下のポートで待ち受けを行うにはroot権限が必要となる。

そのためHTTP(80)やHTTPS(443)で待ち受けるには、アプリケーションをroot権限で動作させる必要がある。

しかしそうなると、攻撃されたときなど被害が拡大する恐れがある。

ので、root権限で実行して必要処理が終わり次第、一般ユーザーに権限変更する処理を行う。

ユーザーとグループの追加
$ sudo groupadd node
$ sudo useradd -g node -s /sbin/nologin node
process.setuid()

アプリケーションの実行スクリプトのlistenメソッドのコールバック関数内に追記します。

var server = app.listen(app.get('port'), function() {
    /* >>> 追記 >>>*/
    if (process.getuid() == 0) {
        process.setgid('node');
        process.setuid('node');
    }
    /* <<<<<<<<<<<*/
    debug('Express server listening on port ' + server.address().port);
});

以下rootで実行したらnodeユーザー権限で実行されることがわかります。

// 一般ユーザーで実行
$ node SCRIPT
$ ps aux | grep www

出力結果:

root 7280 0.0 0.2 182436 2632 pts/0 S+ 08:40 0:00 sudo node bin/www

root 7281 0.6 3.9 1031540 40504 pts/0 Sl+ 08:40 0:00 node bin/www

ec2-user 7316 0.0 0.0 114496 892 pts/1 S+ 08:41 0:00 grep www

// rootユーザーで実行
$ sudo node SCRIPT
$ ps aux | grep www

出力結果:

root 7430 0.0 0.2 182436 2636 pts/0 S+ 08:47 0:00 sudo node bin/www

node 7431 1.3 3.9 1031680 40540 pts/0 Sl+ 08:47 0:00 node bin/www

ec2-user 7438 0.0 0.0 114496 888 pts/1 S+ 08:47 0:00 grep www

永続化デプロイを実行

満を持してやってみます

$ sudo -s
# forever start SCRIPT

ログ監視してみます。

# forever list
でログファイルの場所を確認。

# tail -f LOGFILE

ちゃんとログ吐いています!

プログラムを修正してデプロイし直す場合はforever restart 0とかやればいいですね。

NodeでRSS情報をfbいいね順に取得する

nodeで何か実装する際は、使えそうなapiがないか調べてみるとよい。

たとえば今回、facebookいいねを取得したかったので以下のように検索してみたらでてきた。

$ npm search facebook | grep like

何件かでてきたので、使えそうなもんがあれば使おう。

使用するnpm

  • google-feed-api -> 各メディアのフィード情報を取得できる
  • count-shares -> いろんなソーシャルリアクション数を取得できる

とりあえず両npmの動作確認までやります。

API使用方法

[ google-feed-api ]

ref. Google Feed API Developer's Guide

使い方かんたん。一例

var gfeed = require('google-feed-api');

var feed = new gfeed.Feed("http://gamy.jp/feed");

// feed.XMLに載ってないものをGoogleが保存してくれているのでそれも含めて取得する
feed.includeHistoricalEntries() 

// 取得数をセット
feed.setNumEntries(30);

feed.listItems(function(items) {
    // ココでitemsをいじいじ
})

listItems()配列を返す。しかしこれだとフィードの名前(ここではgamy.jp)とかとれなくて各エントリーの情報しかとれない。

jsonとして受け取るにはload()を使用する

feed.load(callback(result));

こんなかんじでresult.feedとやるとエントリーを配列として持つフィードオブジェクトを操作できる。

わかりにくかったと思うので、以下。

// フィード情報を取得
result.feed.title // -> gamy.jp

// フィードのエントリー(記事)情報を取得
result.feed.entries[0].title // -> 【海外の反応】ロックマンが人気すぎて発狂する人たち

詳細なオブジェクト構造はこちらをみてください。

[ count-shares ]

あるURLに対してのソーシャルリアクション数を取得します。

とりあえず、使い方をどんと載っけちゃいます。

var countShares = require('count-shares');

countShares.get('ページURL', function(err, result) {
    console.log(result.facebook);
    console.log(result.twitter);
    console.log(result.pinterest);
    console.log(result.linkedin);
});

かんたんですね。

しかし、非同期処理なのに注意!!

このモジュールの用途を考えると同期処理できるようにしてくれてそうなものですが、こちら特にそういったものは用意していないみたいです。残念。

非同期メソッドを同期的に処理するにはいくつか方法がある。

  1. promise, defferedとか使う(あんま覚えてないけど)
  2. 再起処理で済ます

他にもあるのかも。がんばってみよう。

 

Nodeを使ってcron処理してみる

調べてみたらOSがもっているcronを使わずにnodeだけで定期処理できそうなのでいまからやってみます。

参考URL

使用するnpm

環境

構成

.
├── cron.js
└── node_modules
    ├── cron
    └── time

ファイル作成

まずは動作確認したいのでお試し用にディレクトリ作成。

$ mkdir crontest
$ cd crontest

実行ファイル作ります。

$ touch cron.js

インストール

$ npm init
$ npm install cron --save

さて。

If you want to specify timezones, you'll need to install the time module or place an entry for it in your package.json file.

cronモジュール使用時にタイムゾーンを指定したい場合等にはtimeモジュールが必要らしいのでいっしょにインストール。

$ npm install time

ちなみに複数モジュールインストールはスペース空けでできるみたい。

$ npm install cron time

書いてみる

ソース

[cron.js]

var mycron = require('cron').CronJob;
var job = new mycron({
  cronTime: '* * * * * *', //とりま毎秒実行
  onTick: function() {
    console.log("onTick!!");
  },
  start: false, //newした後即時実行するかどうか
  timeZone: 'Japan/Tokyo'
});
job.start();

実行

$ node cron.js

実行すると毎秒コンソール出力されます。

これで定期的にバッチ処理できるね。

もっと詳しくは、https://github.com/ncb000gt/node-cron

CronTimeの設定方法

ちなみに、cronの処理する時間の設定の記述パターンもよく知らなかったのでメモっておく。

Seconds: 0-59
Minutes: 0-59
Hours: 0-23
Day of Month: 1-31
Months: 0-11
Day of Week: 0-6

例1. 平日毎日11:30

'00 30 11 * * 1-5'

例2. 毎30分

'*/30 * * * *'

となる。

詳しくはhttp://crontab.org/

mongoDB使ってみる

@author Yukichi Tamura

@date 2014.7.17

いまやってるプロジェクトで、なにかしらストレージ使う必要性がでてきたので、mongoDB使ってみます。

いままでmysqlとredisしか使った事がないですが、今回やりたいことがRSSで取得した記事情報(jsonオブジェクト)を溜め込んでいきたいということで、

mongoDBはjsonと相性がいいというのを聞いたことがあったので今回は好機!テーブル定義とかとくにないらしくポンポンjsonオブジェクト登録できる(?)

「はじめてのNode.js」第8章を参考に進める。

MongoDBの特徴

以下拾った情報まとめ

  • ドキュメント志向DB。
  • データ=ドキュメント
  • ドキュメントの集合をコレクションとして管理
  • 各ドキュメントは任意の構造をもつことができ、スキーマの束縛がない
  • RDBSとKVSの特徴を併せ持っている
  • ドキュメントとしてBSONというJSON互換の形式を使用する。だからjsとの親和性がたかい。
  • データベース内でjavascriptをいろいろ実行できる。

mongoDBを使う

インストール

homebrewでmongoDBをインストールします。

$ brew install mongodb

現時点で最新版は2.6.0だそうな。

起動

$ mongod

しかし、以下のエラー…。

*********************************************************************
 ERROR: dbpath (/data/db) does not exist.
 Create this directory or give existing directory in --dbpath.
 See http://dochub.mongodb.org/core/startingandstoppingmongo
*********************************************************************

デフォルトでは /data/db/ にデータベースを作成する設定になっているらしいので、作ってやる。

$ sudo mkdir -p /data/db

ちなみに -p オプションを使用するとディレクトリを含んだディレクトリを複数作成できる。はじめて知ったよ。これからはmkdirを何回も叩く必要はない。

$ mongod

これで起動できました。

ちなみに指定したディレクトリにデータベースをつくることも可能。

$ mongod --dbpath ./mongodb

なお、デフォルト設定ではユーザー・パスワードによる認証は無効なってる。

mongodbのセキュリティに関しては、http://docs.mongodb.org/manual/administration/security/

mongoシェルからアクセス

mongodbには、データベースに対話的な操作が出来る mongoシェルというのが用意されている。

アクセスするには、

$ mongo [option] [database] [exec-file]

mysqlmysqlコマンドに相当。

sampledbというデータベースにアクセスする。存在しないデータベースの場合自動的に空のデータベースが作成される。

$ mongo sampledb

デフォルトでは27017ポートで待ち受けるが、他を使いたい場合は

$ mongo hostname[:port]/database

でおk。mongo sampledbは内部的にはmongo 127.0.0.1[:27017]/sampledbをやってることになるね。

mongoシェルからdb操作

とりあえずなにかinsertしてみる。

> var hogehoge = {
>   name: 'yukichi',
>   old: 24
> };
> db.topics.insert(hogehoge);

入った!このtopicsに当たるものはコレクションと呼ぶらしい。mysqlでいうTABLEにあたるぽい。

コレクションが存在しない場合は勝手に作成されます。

次は入ったデータを取得して確認してみる。使うのはfind。

db.topic.find();

ちゃんとあるね!

findの引数に条件queryを与えることで検索してしゅとくもできる。たとえば

db.topic.find({name:'yukichi'});

他にもいろいろあるが、割愛。mongodbけっこう柔軟にいろいろできるのでたのしいかも。

Node.jsからMongoDBを使う

環境

.
├── access.js
├── node_modules
│   └── mongodb
└── package.json

まずディレクトリを作る。

$ mkdir mongodbtest
$ cd mongodbtest

実行ファイルを作成

$ touch access.js

npm管理下に。package.jsonが作成される。

$ npm init

npmインストール

$ npm install mongodb --save

Node.jsからdb操作

さきほどと同様に、insertしてfindしてみた。以下ソース。 [acccess.js]

var mongodb = require('mongodb');

var server = new mongodb.Server('localhost', 27017);
var db = new mongodb.Db('sampledb', server, {safe: true});

db.open(function(err, db) {
  if (err) {
    throw err;
  }

  var collection = db.collection('topics');

  // insert
  var topic1 = {
    id: 12,
    title: 'たいとるううううううう',
    text: 'あああああてきすとです',
    date: new Date(),
    postBy: 'saiki daisuke'
  };
  collection.insert(topic1, function(err, result) {
    if (err)
        throw err;
    console.log(result.length + '件のデータをinsertしました!!');
    console.log(result);
  });

  // find
  var cursor = collection.find();
  cursor.each(function(err, doc) {
    if (err)
        throw err;
    console.log(doc);
  });

});

上の、

var db = new mongodb.Db('sampledb', server, {safe: true});

は、操作を実行した際に正常に終了したかどうかをドライバー側に通知するためのオプション。デフォルトではfalseなので設定しといたほうがいい。

以上。これ以上の使い方は調べながらやっていくことにする。

ゼロからのNodeJS Expressアプリケーション構築

「はじめてのNode.js」を参考に進める。 参考書は3.0.3だが、最新のExpress4を使う。

Node環境

homebrewを入れている場合は

$ brew install node

nodeとともにnpmもインストールされる。

グローバルに管理されるnodeモジュールの場所は、/usr/local/lib/node_modules

プロジェクト環境

プロジェクトを進めていくディレクトリを作成します。

$ mkdir myapp
$ cd myapp

Express環境

expressをインストール

$ npm install express

node_modules/expressが作成されている。

ケルトンコードを作成する

※スケルトンコードとは? アプリケーションの骨組み。これをベースに肉付けしてく。(ちなみにスケルトンは骸骨の意)

expressコマンドを実行。

$ ./node_modules/.bin/express

デフォルトではテンプレートエンジンはjade、cssはピュアなcssファイルとなるが、オプションをつけることで変更もできる。

今回は、stylusを使ってみようと思うので、以下のようにする。(オプションはここでみれる)

$ ./node_modules/.bin/express --css stylus

>>> ./binがnode_modulesに作成されない場合

express 4 から、express-generatorという違うパッケージに分かれているみたい。 なので、別個インストール。

$ npm install express-generator

expressスクリプトを実行するとなにやらファイルとかたくさんできる。これをベースとしてやってく。

依存モジュールを入れる

package.jsonのdependenciesに依存モジュールが記述されている。これをインストルする。

$ npm install

アプリケーションを実行

// express3.xの場合
$ node app.js

// express4.xの場合
$ node bin/www

3.xと4.xでは構成(スケルトンコード)がだいぶ異なるよう。ソースの中身もけっこう違う…。 (あるいはexpress-generatorで作る構成が異なるのかもしれない。未確認)

実行を確認

ブラウザで http://localhost:3000 にアクセスして画面が表示されていれば成功。

expressの使い方

app.js

expressアプリケーションのメインスクリプト

モジュールを読み込む

var routes = require('./routes/index');

appオブジェクトを作成

var app = express();

ミドルウェアを登録

app.use([path], function)

app.use('/', routes);

pathとはリクエストURLのこと。

pathを省略した場合、「/」。つまり全てのリクエストに対して、指定したミドルウェアが使用される。

expressの設定

設定方法
app.set(key, value)
app.get(key, value)

true, falseの設定の場合以下も可能

app.enable(key) //set
app.enabled //get

app.disable(key) //set
app.disabled //get
expressがデフォルトで参照する設定(キー名)

env, trust proxy, jsonp callback name, json replacer, json spaces, case sensitive routing, strict routing, view cache, view engine, views

環境によって設定を切り替える

app.configure([env], callback)

※express4のスケルトンコードはなぜかif (app.get('env') === 'development') のようになってる。

HTTPによる待ち受けを開始する

app.set('port', process.env.PORT || 3000);
app.listen(app.get('port'));

仕様は

app.listen(port, [hostname], [backlog], [callback])

リクエストに関する情報を取得する

Expressのオブジェクト。

GETで送信された値

req.queryプロパティ

※そういえば、純粋なreqオブジェクト(http.ServerRequest)だと以下のようになる。

var obj = url.parse(req.url, true);↲

obj.queryプロパティ。

obj.query.fruitとかobj.query.vegというように値を取得する。

POSTで送信された値

req.bodyプロパティ

レスポンスを返す

Expressのresオブジェクト。

いろいろあるよ。

res.send([status], [body]) //本文として送信

res.json([status], [body]) //JSONデータとして送信 

res.jsonp([status], [body]) //JSONPデータとして送信 

res.render(view, [locals], [callback]) //レン」ダリング結果を送信

Grunt, Bowerを導入

ここからは、参考書の範囲はずれるよー。

grunt-cli, bowerをグローバルインストール

まずnpmでグローバルインストールしたものを確認してみる。

$ ls /usr/local/lib/node_modules

なければ、

-g オプションでグローバルインストールできる。 グローバルで管理すべきものは、各プロジェクトに依存しないようなモジュールであるべし(?)

$ npm install grunt-cli -g
$ npm install bower -g

依存モジュールを追加

package.jsonのdependenciesに以下のように追記する。 [package.json]

"dependencies": {
    "express": "~4.2.0",
    "static-favicon": "~1.0.0",
    "morgan": "~1.0.0",
    "cookie-parser": "~1.0.1",
    "body-parser": "~1.0.0",
    "debug": "~0.7.4",
    "jade": "~1.3.0",
    "stylus": "0.42.3",
    // ここから追記
    "grunt": "~0.4.2",
    "load-grunt-tasks": "^0.4.0",
    "grunt-bower-install": "~1.0.0"
}

※カンマ忘れないように。エラーなります。

記述したらインストールしる。

$ npm install

[追記] こんなめんどいことしなくても以下で済みます

$ npm install grunt load-grunt-tasks grunt-bower-install --save

Gruntfile.jsを作成

https://www.npmjs.org/package/grunt-bower-installを参考にして以下のように書いた。

[Gruntfile.js]

module.exports = function(grunt) {
    require('load-grunt-tasks')(grunt);
    grunt.initConfig({
        bowerInstall: {
            target: {
                src: ['views/*.jade']
            }
        }
    });
    grunt.registerTask('default', ['bowerInstall']);
};

bower初期化

$ bower init

勝手にbower.jsonという設定ファイルが作成されます。これもpackage.jsonと同様、プロジェクトの依存関係をまとめたファイル。

何かインストールしてみる。ということでjqueryをしてみる。

まず探してみる。

$ bower search jquery

jqueryという文字列を含むものが一覧できる。

ということでインストールする。--save オプションを付与するとbower.jsonに自動で追記してくれる。これはnpmでも同様 to package.json

$ bower install jquery --save

するとbower_components/jqueryが作成された。

この後、このライブラリをhtmlファイルもしくはテンプレートファイルで読み込む(linkタグやscriptタグを挿入する)のだが、ここで便利なのがgrunt-bower-install。 これ使うと、依存ライブラリを指定箇所に勝手に挿入してくれます。

.jadeファイルに挿入箇所を記述

[views/layout.jade]

doctype html
    html
    head
        title= title
        // bower:css
        // endbower

        // bower:js
        // endbower
    body
        block content

// bower:css// endbower で挟まれた部分に自動挿入される。jsは // bower:js で同様に。

htmlファイルの場合は、\ \ のようにすればOK。

grunt-bower-installを実行

gruntタスクを実行する。

$ grunt bowerInstall

views/layout.jadeを確認したら、挿入されてるはずです。

また、grunt bowerInstallしたときに実行時エラーになるのがたまにあるが、これはそのbowerモジュール配下にbower.jsonがないため。

最新版のbower.jsonがあるやつをインストールするか、自分でbower.jsonに追記してやるか、あきらめてファイルに直接タグを挿入してやるか。

ちなみにライブラリファイルのパスは、node_modules/XXXXX/bower.jsonのmainキーに指定されているよう。

[TODO] :挿入されるパスは相対パスになる。現環境の設定だと、静的ファイルのルートパスがpublic/なので、../public/bower_components/XXXXX と挿入されるとパスが違う。どうにか/bower_components/XXXXXとなるようにしたい、あとで。

[追記] 解決した。

    grunt.initConfig({
        bowerInstall: {
            target: {
                src: ['views/*.jade'],
                ignorePath: '../public'
            }
        }
    });

とすればok。調べてもよくわからなかったのでオプションてきとーに試してたらできた。笑。ignorePathで指定した文字列が切り取られて挿入されれる