nginx(EC2)とngx_small_lightで画像をリサイズしてs3でcacheしたい - その2

背景

nginx(EC2)とngx_small_lightで画像をリサイズしてs3でcacheしたい - その1 – ときさんブログ – Web Developer from elevennines, Inc.の続き。

残課題

ファイルをs3にcacheする→ proxy_cache でLocalにcacheはできるんだろうけどs3ってどうしたらいいんだろう。s3fsとか使いたくない…

取った方法(結論)

  • cacheするWeb Appを書く or nginxのmoduleを書く

前者のほうがお手軽だしphpでWeb App書くことにした。

php-fpmが入ってなかった

yumで入れるべし

nginx.confの修正

user  nginx nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log;

events {
	worker_connections  1024;
}


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;
	keepalive_timeout  65;
	include /etc/nginx/conf.d/*.conf;

	server {
		listen	   80;
		server_name  localhost;
		index   index.html index.htm index.php; # index.php追加
:
:

		# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
		# 追加分
+		location ~ \.php$ {
+			root		   /var/www/html;
+			#fastcgi_pass   127.0.0.1:9000;
+			fastcgi_pass   unix:/var/run/php-fpm/php-fpm.sock;
+			fastcgi_index  index.php;
+			fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
+			include		fastcgi_params;
+			client_max_body_size 100M;
+		}
	}
}

aws.pharを使う

ここから落としてきて使う。

php側で以下のようにrequireして使う。

<?php
require '/path/to/aws.phar';

あと、~/.aws/credentialsを作っておく。それとnginxユーザー(/home/nginx/.aws/credentials)も同じモノを用意しておく。

[ec2-user@ip-12-3-4-567 ~]$ cat ~/.aws/credentials
[profile-name]
aws_access_key_id = '{AWS ACCESS KEY}'
aws_secret_access_key = '{AWS ACCESS SECRET}'

phpスクリプト

仕様

  • /resize.php?w={幅}&h={高さ}&file={ファイル名}で動作
  • リネームルール
    • {ファイル名(拡張子抜)}-w{幅}-h{高さ}.{拡張子}
  • オリジナル画像
    • bucket直下に置いてる
      • 存在しなければエラー→これ使ってエラーコード.jpgとしてbucket/httpに保存して使うことにしたけど404しか確認してないw
  • https://{region}.amazonaws.com/{bucketname}/cache/{リネーム名}が存在するかしないかで切り分ける
    • not exist(存在しない)
      • http://localhost/w/{幅}/h/{高さ}/{ファイル名}/var/www/html/tmpに保存(mkdir & chmod 777しといて)
      • 保存したファイルをs3のcacheフォルダにアップロードしてURLリダイレクト
    • exists(存在する)
      • s3のcacheにURLリダイレクト

resize.phpはこんな感じ

<?php
require 'aws.phar';
use Aws\S3\Exception\S3Exception;

// client access to AWS s3
$sdk = new Aws\Sdk([
    'profile' => '{profile-name}',
    'version' => 'latest',
    'region'  => 'ap-northeast-1'
]);
$client = $sdk->createS3();
$bucket_name = '{bucket-name}';

$s3_bucket_url = 'https://s3-ap-northeast-1.amazonaws.com/'.$bucket_name;
$hostname = 'localhost';
$w =  $_GET['w'];
$h =  $_GET['h'];
$file =  $_GET['file'];

$param_error = false;
// Validate Parameters
if((!$w)||(!$h)||(!$file)){ $param_error = true; }
if((!is_numeric($w))||(!is_numeric($h))){ $param_error = true; }

function check_s3object($client, $bucket_name, $key_name){
	$status_code = '200';
	try{
		$result = $client->getObject([
			'Bucket' => $bucket_name,
			'Key' => $key_name
		]);
	} catch (S3Exception $e) {
		$status_code = $e->getStatusCode();
		print("status code: $status_code <br/>\n");
	}
	return $status_code;
}

function upload_s3($client, $local_uri, $filename, $bucket_name, $key_name){
	$data = file_get_contents($local_uri);
	$file_path = './tmp/'.$filename;
	file_put_contents($file_path,$data);
	$mimetype = mime_content_type($file_path);

	// upload to s3
	$result = $client->putObject([
		'Bucket' => $bucket_name,
		'Key' => $key_name,
		'ContentType' => $mimetype,
		'SourceFile' => $file_path
	]);

	// delete local file
	unlink($file_path);
}

function redirect_error($s3_bucket_url, $err_code){
	$err_url = $s3_bucket_url."/http/".$err_code.".jpg";
	header("Location: {$err_url}");
}

if(!$param_error){
	$local_uri = "http://".$hostname."/w/".$w."/h/".$h."/".$file;
	$filename = pathinfo($file, PATHINFO_FILENAME)."-w".$w."-h".$h.".". pathinfo($file, PATHINFO_EXTENSION);
	$s3_uri = $s3_bucket_url."/cache/".$filename;
	$key_name = "cache/".$filename;
	// check s3 object exists
	$original_status = check_s3object($client, $bucket_name, $file);
	$cache_status = check_s3object($client, $bucket_name, $key_name);
	if($original_status != '200'){
		redirect_error($s3_bucket_url, $original_status);
	} else {
		if($cache_status != '200'){
			upload_s3($client, $local_uri, $filename, $bucket_name, $key_name);
		}
		header("Location: {$s3_uri}");
	}
} else {
	redirect_error($s3_bucket_url, '404');
}

?>

テスト用HTML

<html>
<head>
        <title>cdn test</title>
</head>
<body>
        <div>
                <img src="./resize.php?w=500&h=262&file=test.jpg">
        </div>
</body>
</html>

ngx_small_light-001

<html>
<head>
        <title>cdn test</title>
</head>
<body>
        <div>
                <img src="./resize.php?w=500&h=262&file=nosuchimage.jpg">
        </div>
</body>
</html>

ngx_small_light-002

Written on February 12, 2016