DEVELOPMENT
nodejs で aws s3 にアップロードする方法です。 webpackを使ってたので、npmでs3-plugin-webpackを使ってdeployを試みましたが、設定ファイルのこのプラグインの設定を入れるとbuildが終わらず、まったくアップロードできなかった(materializeを使ってますが、そこのコンパイルで全く進まなくなる)ので、aws-sdkを使って自作でスクリプトを作成しました。
▶ 追記 2020/02 ※ 本記事 AWS CLIコマンド使えば不要な気がしてます。
前提
- aws s3の設定がされていること
- cloudfrontを使う前提で distributionの設定がされていること
- iamの設定(s3 の使用するバケットへのputの許可、cloudfrontアクセスの許可を持っている)がされていること
s3へのアップロード
sdkを入れます
インストール
$ npm install aws-sdk --save or --savve-dev
keyなど設定をべた書きしたくないのでdotenvを使いました
$ npm install dotenv --save-dev
s3にファイルを上げる時、content-typeがないと、ちゃんとファイルを認識してくれないので、mimetypeを読んで、指定してアップするため
$npm install mime-type --save-dev
.envファイルを作り、AWS_ACCESS_KEY_IDなどの設定を書く
AWS_ACCESS_KEY_ID = xxxxxxxxxxxxxxxxxx
AWS_SECRET_ACCESS_KEY = xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
CLOUDFRONT_DISTRIBUTION_ID = xxxxxxxxxxxxxxxx
CLOUDFRONT_DISTRIBUTION_ID_WWW = xxxxxxxxxxxxxxxx
AWS_REGION = xxxxxxxx
AWS_BUCKET_NAME = xxxxxxxxxxxxxx
読み込み
require('dotenv').config();
var AWS = require('aws-sdk');
var fs = require('fs');
var mime = require('mime-types')
Aws ロード
AWS.config.update({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
region: process.env.AWS_REGION
});
public配下(状況によって変えて下さい)をバケット直下に配布する
var dir = "./public"
var s3 = new AWS.S3();
fs.readdir(dir, function(err, files){
if (err) throw err;
files.filter(function(file){
var params = {
Bucket: process.env.AWS_BUCKET_NAME,
Key: file,
Body: fs.readFileSync(dir + file),
ContentType: mime.lookup(file)
};
s3.putObject(params, function(err, data) {
if (err) console.log(err, err.stack);
else console.log(data);
});
});
});
- fs を使い、localのpublic dir以下のファイルを取得します。
- parasのBucketはバケット名、keyは配布されるときのファイル名、bodyがファイルの中身(fs.readFileSyncを使った)、contentTypeはmime-typeで取得したtypeを指定
- pubObjectで上げる AWS-SDK s3 リファレンス
cloudfrontにcreate invalidationする(cacheを消す)
僕の場合は、www用(リダイレクト)、wwwなし用(それぞれhttps対応)があるため、一応両方のdistributionに対して、createInvalidationしています。
var cloudfront = new AWS.CloudFront({apiVersion: '2017-03-25'});
var timestamp = new Date();
var string_timestamp = String(timestamp.getTime());
var invalidate_items = ['/*'];
var item_count = invalidate_items.length;
var invalidations = invalidate_items.map(encodeURI)
var distributionIds = [process.env.CLOUDFRONT_DISTRIBUTION_ID, process.env.CLOUDFRONT_DISTRIBUTION_ID_WWW];
distributionIds.forEach( function( distributionId ) {
var params = {
DistributionId: distributionId,
InvalidationBatch: {
CallerReference: string_timestamp,
Paths: {
Quantity: invalidations.length,
Items: invalidations
}
}
};
cloudfront.createInvalidation(params, function(err, data) {
if (err) console.log(err, err.stack);
else console.log(data);
});
});
最初どんなにやってもエラーが出てしまい、うまく行かなかったのですが、invalidate itemに対して、encodeURI したところ、うまくいきました。 CallerReferenceは、timestamp、PathのQuantityは、itemの数、Itemsは、消す対応のitemになります。 AWS-SDK cloudfront リファレンス
全体のソースコード
s3-upload.js
require('dotenv').config();
var AWS = require('aws-sdk');
var fs = require('fs');
var mime = require('mime-types')
AWS.config.update({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
region: process.env.AWS_REGION
});
var dir = "./public"
var s3 = new AWS.S3();
fs.readdir(dir, function(err, files){
if (err) throw err;
files.filter(function(file){
var params = {
Bucket: process.env.AWS_BUCKET_NAME,
Key: file,
Body: fs.readFileSync(dir + file),
ContentType: mime.lookup(file)
};
s3.putObject(params, function(err, data) {
if (err) console.log(err, err.stack);
else console.log(data);
});
});
});
var cloudfront = new AWS.CloudFront({apiVersion: '2017-03-25'});
var timestamp = new Date();
var string_timestamp = String(timestamp.getTime());
var invalidate_items = ['/*'];
var item_count = invalidate_items.length;
var invalidations = invalidate_items.map(encodeURI)
var distributionIds = [process.env.CLOUDFRONT_DISTRIBUTION_ID, process.env.CLOUDFRONT_DISTRIBUTION_ID_WWW];
distributionIds.forEach( function( distributionId ) {
var params = {
DistributionId: distributionId,
InvalidationBatch: {
CallerReference: string_timestamp,
Paths: {
Quantity: invalidations.length,
Items: invalidations
}
}
};
cloudfront.createInvalidation(params, function(err, data) {
if (err) console.log(err, err.stack);
else console.log(data);
});
});
実行
$ node s3-upload.js(上記を保存したファイル名)
これを、webpackを使ってるなら、packeages.jsonのscript部分に設定すれば、npm runコマンドでbuild後に実行するようにすればOKです。
まとめ
今後は、buildされたファイルをバージョン管理し、rollback的なものもできたらいいと思います。
株式会社UKAI 代表取締役CEO。建築を専攻していたが、新卒でYahoo!Japanにエンジニアとして入社。その後、転職、脱サラ、フリーランスエンジニアを経て、田舎へ移住し、ゲストハウスの開業、法人成り。ゲストハウス2軒、焼肉店、カフェ、食品製造業を運営しています。詳細はこちらから