Nginx、ngx_small_light を Amazon EC2 へ導入し S3 の画像をリアルタイムに変換する


画像変換は EC2 に導入した ngx_small_light で行い、画像の実体は Nginx のプロキシ機能を使って WEB ホスティングした S3 から取得する構成です（EC2 はリバースプロキシ＆画像変換サーバとして動作する）。既に画像を S3 の WEB ホスティングで配信しているサービスであれば、リバースプロキシ＆画像変換サーバを S3 の前段に置くことで画像変換機能を付与することが出来ます。

簡単に試してみたので、本投稿はその手順のメモです。

> ngx_small_light の概要はこちらのスライドが分かりやすかったです。
> ⇒ [実践ngx_small_light入門 by Tatsuhiko Kubo【Speaker Deck】](https://speakerdeck.com/cubicdaiya/shi-jian-ngx-small-lightru-men)

# 環境構築の手順

## EC2 の用意

今回は `クイックスタート` の一番上にある、このマシンイメージ(AMI)を利用しました。OS は `Amazon Linux` になります。

![スクリーンショット 2015-11-19 14.27.43.png](https://qiita-image-store.s3.amazonaws.com/0/35733/0b75518d-4c68-d156-91a6-84a29ff213b0.png "スクリーンショット 2015-11-19 14.27.43.png")

> インスタンスの作成手順については、ここでは割愛します。

## Nginx のインストール

Nginx は `yum` でなくソースからインストールします(後で `ngx_small_light` を組み込むので)。

### Nginx 用のユーザ/グループを作成

```
$ sudo useradd --shell /sbin/nologin nginx
```

> `/etc/passwd` と `/etc/group` に `nginx` ユーザ/グループが追加されているはずです。

### Nginx のビルドで必要となるソフトウェアの導入

```
$ sudo yum install -y gcc
$ sudo yum install -y pcre pcre-devel
$ sudo yum install -y zlib zlib-devel
```

> 自分の場合は上記のもので大丈夫でしたが、環境によって異なると思うので、Nginx ビルド時のエラーメッセージに従って必要なものを導入してください。ちなみに今回は SSL は利用しない想定なので `openssl` `openssl-devel` は導入していません。

### Nginx パッケージの取得とインストール

http://nginx.org/en/download.html の `Stable version` のバージョンを調べます。執筆時点では `1.8` なので、それをインストールします。適当なディレクトリで作業します(今回は`~/work`)。

```
$ cd ~
$ mkdir work
$ cd work
$ wget http://nginx.org/download/nginx-1.8.0.tar.gz
$ tar zxvf nginx-1.8.0.tar.gz
$ cd nginx-1.8.0
$ ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx
```

`configure` に成功すると次のようにサマリーが表示されます。

![スクリーンショット 2015-11-19 15.17.01.png](https://qiita-image-store.s3.amazonaws.com/0/35733/5094ff65-48bf-83e2-144f-0d04352f6cce.png "スクリーンショット 2015-11-19 15.17.01.png")

コンパイルとインストールを行います。

```
$ make 
$ sudo make install
```

### Nginx の起動設定

`/etc/init.d/nginx` を新規に作成します。

```
$ sudo touch /etc/init.d/nginx
$ sudo chmod +x /etc/init.d/nginx
```

上記の `/etc/init.d/nginx` を `vi` 等で開き、https://www.nginx.com/resources/wiki/start/topics/examples/redhatnginxinit/ の内容をコピーして貼り付けた後、今回の環境に合わせて次のように編集します。

```diff:/etc/init.d/nginx
...

-nginx="/usr/sbin/nginx"
+nginx="/usr/local/nginx/sbin/nginx"

...

-NGINX_CONF_FILE="/etc/nginx/nginx.conf"
+NGINX_CONF_FILE="/usr/local/nginx/conf/nginx.conf"

...
```

### Nginx のチューニング

`ngx_small_light` 向けにやっておいた方が良さそうなので一応やっておきます。`/etc/sysconfig/nginx` を新規に作成します。

```
$ sudo touch /etc/sysconfig/nginx
```

次の一文を書きます。

```/etc/sysconfig/nginx
export OMP_NUM_THREADS=1
```

ワーカープロセス数も増やしておきます。

```diff:/usr/local/nginx/conf/nginx.conf
-worker_processes 1
+worker_processes 10
```

### Nginx を起動してみる

```
$ sudo service nginx start
```

ブラウザで EC2 のパブリックIPにアクセスしてみて、次のように表示されればOKです。

<img src="https://qiita-image-store.s3.amazonaws.com/0/35733/ac083e66-44e8-1873-b091-daade19d1a33.png" width=50%>

ちなみに Nginx の再起動は `$ sudo service nginx restart` 、停止は `$ sudo service nginx stop`、設定ファイルの修正内容の反映は `$ sudo service nginx reload` で実行できます。

### Nginx の自動起動設定

EC2 サーバの立ち上げ時に自動で Nginx も立ち上がるようにしておきます。

```
$ sudo chkconfig nginx on
```

以上で Nginx のインストールは完了です。

> 後に説明する `ngx_small_light` のインスール時に Nignx を再ビルドすることになりますが、いちおう Nginx 単体の動作確認をした感じです。

ちなみに Nginx のドキュメントルートや設定ファイル類、ログは `/usr/local/nginx` 配下にまとまっています。

## ngx_small_light のインストール

ngx_small_light は画像変換用の Nginx モジュールです。GitHub で公開されています。
⇒ https://github.com/cubicdaiya/ngx_small_light
執筆時点の最新バージョンは `v0.6.11` で、今回はこの最新バージョンを利用しました。

今回は `ImageMagic` だけを使う想定なので `Imlib2` `GD` は導入しませんが、必要あらば上記 Github の README や [Wiki](https://github.com/cubicdaiya/ngx_small_light/wiki) 、この投稿の最後に記載した参考記事を元に導入してください。

### ngx_small_light の取得とセットアップ

適当なディレクトリで作業します(今回は`~/work`)。

```
$ cd ~/work
$ sudo yum install -y git
$ git clone https://github.com/cubicdaiya/ngx_small_light.git
$ sudo yum install -y ImageMagick ImageMagick-devel
$ cd ngx_small_light
$ ./setup
```

> `Git` と `ImageMagic` も導入していますが、既に環境に入っていればこの手順は不要です。また今回は `ImageMagic` だけを使う想定なので `Imlib2` `GD` は導入していません。

`setup` が成功すると `config is generated.` と表示されます。

### Nginx の再ビルド・再インストール

```
$ cd ~/work/nginx-1.8.0
$ ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --add-module=/home/ec2-user/work/ngx_small_light/
$ make
$ sudo make install
```

> `/home/ec2-user/work/ngx_small_light/` のところは `ngx_small_light` をセットアップしたディレクリを指定します。環境に合わせて変更してください。

上記で問題なければ Nginx を再起動します。

```
$ sudo service nginx restart
```

# ngx_samll_light を使って S3 の画像を変換してみる

今回は単純に `jpeg` 画像を縮小してみます。

> `ngx_small_light` の詳しい使い方は [Wiki](https://github.com/cubicdaiya/ngx_small_light/wiki) を見ると良いかと思います。

WEB ホスティングした S3 に適当な画像を置きます。今回は次のような `1000 × 667` px の画像を用意しました。

<img src="https://qiita-image-store.s3.amazonaws.com/0/35733/73fde911-802a-93d5-fe3a-1e00b80f0264.png" width=50%>

S3 上のURLは次のようになっているものとします。

`http://hoge.s3-us-west-2.amazonaws.com/photo/cat.jpg`

`/usr/local/nginx/conf/nginx.conf` を開き `jpeg` 画像へのリクエストの場合は横幅 `300` px に縮小する設定を書いてみます。

```diff:/usr/local/nginx/conf/nginx.conf
http {

    # ...

    server {

        # ...    

+        small_light on;
+        small_light_getparam_mode on;
+        small_light_pattern_define option dw=300,jpeghint=y;
+
+        location ~ ^/(photo/.+)$ {
+           set $path $1;
+
+           proxy_pass http://hoge.s3-us-west-2.amazonaws.com;
+
+           # jpeg 画像の場合のみ変換
+           if ($path ~ ".+\.jpg$") {
+               rewrite .* /$path?p=option break;
+           }
+
+           # jpeg 画像でない場合はそのまま流す
+           rewrite .* /$path break;
+        }

        # ...    
```

修正したら Nginx をリロードします。

```
$ sudo service nginx reload
```

ブラウザで EC2 のパブリックIPにアクセスしてみます。次のように縮小されました。

<img src="https://qiita-image-store.s3.amazonaws.com/0/35733/4f8d9ba9-0e6f-607b-4c4b-10ded910ba81.png" width=50%>

### 注意

`ngx_small_light` のクエリで変換オプションを指定するモード(`small_light_getparam_mode on`)を利用する場合、この Nginx の `server` で受ける全てのHTTPリクエストが画像である必要があります(そうでない場合は HTTP 415 エラー《Unsupported Media Type》となりました)。

# おわりに

`ngx_small_light` は画像の縮小だけでなく、画像の合成ができたり、画像を WebP 形式に変換できたりするようなので、モバイル向け画像変換として応用範囲が広そうです。今後もいろいろ試してみようと思いました。

実運用では画像変換の負荷が心配なので、さらに前段に CloudFront や Akamai のような CDN を利用するのが良いかと思います。

# 参考にさせて頂いた記事/スライド

- [Nginxインストールメモ【Qiita】](http://qiita.com/nenokido2000/items/3cbb76dac2b9940f339e)
- [Nginxをソースコードからインストール【Qiita】](http://qiita.com/HayneRyo/items/eccc36302623088ad7f3)
- [ngx_small_light で動的に画像リサイズ【akishin999の日記】](http://d.hatena.ne.jp/akishin999/20130619/)
- [[nginx]S3をバックエンドにngx_small_lightで画像を動的にリサイズ【Siguniang's Blog】](https://siguniang.wordpress.com/2014/01/12/nginx-image-processing-server-with-s3-and-ngx_small_light/)
- [実践ngx_small_light入門 by Tatsuhiko Kubo【Speaker Deck】](https://speakerdeck.com/cubicdaiya/shi-jian-ngx-small-lightru-men)
- [c2にngx_small_lightを使用して、画像のリサイズ(縮小・拡大)をする画像サーバを立てる的なお話【適当な感じでプログラミングとか！】](http://watanabeyu.blogspot.com/2015/08/ec2ngxsmalllight.html)