What's?

Home / nodejs aws-sdkでs3 ファイルアップロード とcloudfront create invalidation

nodejs aws-sdkでs3 ファイルアップロード とcloudfront create invalidation
February 05, 2018

DEVELOPMENT

web
js
aws
s3
cloudfront
node

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);
    });
  });
});
  1. fs を使い、localのpublic dir以下のファイルを取得します。
  2. parasのBucketはバケット名、keyは配布されるときのファイル名、bodyがファイルの中身(fs.readFileSyncを使った)、contentTypeはmime-typeで取得したtypeを指定
  3. 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
うかい@代表取締役兼エンジニア株式会社UKAI
Nobuyuki Ukai

株式会社UKAI 代表取締役CEO。建築を専攻していたが、新卒でYahoo!Japanにエンジニアとして入社。その後、転職、脱サラ、フリーランスエンジニアを経て、田舎へ移住し、ゲストハウスの開業、法人成り。ゲストハウス2軒、焼肉店、カフェ、食品製造業を運営しています。詳細はこちらから

🙏よかったらシェアお願いします🙏
WRITTEN BY
うかい / 株式会社UKAI
うかい@代表取締役兼エンジニア株式会社UKAI

Nobuyuki Ukai

株式会社UKAI 代表取締役CEO。建築を専攻していたが、新卒でYahoo!Japanにエンジニアとして入社。その後、転職、脱サラ、フリーランスエンジニアを経て、田舎へ移住し、ゲストハウスの開業、法人成り。ゲストハウス2軒、焼肉店、カフェ、食品製造業を運営しています。詳細はこちらから

CONACT
入力して下さい
Slack からもどうぞ

※お気軽にどうぞ!(6月20日まで有効!お早めに)

COPYRIGHT © 2020 UKAI CO., LTD. ALL RIGHTS RESERVED.