RubyからS3を使ってみる


これは[JAWS-UG秋田支部　第３回勉強会](http://qiita.com/katsuyoshi/private/d693e57eadc40465e7e6)の発表で使った物です。

## 自己紹介

### コミュニティ

- Akita.m
- Akita Ruby Meeting
- デジコミュ秋田

# 言語

- Ruby
- Objective-C

# プラットフーム

- iOS
- Ruby On Rails
- Android (2015?)

# ------
# S3とは
# ------

[Amazon S3](http://aws.amazon.com/jp/s3/?nc1=h_ls)

> Amazon S3 はインターネット用のストレージサービスです。ウェブスケールの処理能力を開発者が簡単に利用できるよう設計されています。
>
Amazon S3 にはシンプルなインターフェイスが用意されており、いつでもウェブのどこからでも容量に関係なくデータを保存/取得できます。これによって、開発者は拡張可能で信頼性が高く、安全で、高速でありながら安価なインフラストラクチャを利用することが可能になります。このシステムは、Amazon が使用しているウェブサイトのグローバルネットワークと同じものです。このサービスの目的は規模のメリットを最大化で開発者に提供することです。


## 利用例

- ストレージ
	- ファイル
		- バックアップ
	- 画像
	- 動画
	- その他なんでも
- ファイルシステム
- Dropboxの様なサービスも作れるかもよ


## AWSアカウント作成

[無料アカウント作成の流れ](https://aws.amazon.com/jp/register-flow/)

[Sign up](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html?nc1=h_ct)


![Sign up](http://f.st-hatena.com/images/fotolife/g/gutskun/20140515/20140515215736.png?1400158675)

## コンソール

[AWSマネジメントコンソール](https://aws.amazon.com/jp/)


![kobito.1400159750.023471.png](https://qiita-image-store.s3.amazonaws.com/0/8941/1a6e1c54-5e17-c9b3-5d42-85fca5c830e0.png "kobito.1400159750.023471.png")

![kobito.1400159955.381855.png](https://qiita-image-store.s3.amazonaws.com/0/8941/6136759b-6492-0f7a-27ae-ef9bb7164f8b.png "kobito.1400159955.381855.png")

### S3コンソール

![kobito.1400763856.092491.png](https://qiita-image-store.s3.amazonaws.com/0/8941/307b164e-2ca9-cd88-3923-52326d9e6ad5.png "kobito.1400763856.092491.png")


# ------
# 試してみよう
# ------

## バケットを作る

入れ物。フォルダに相当。

- Create Bucketをクリック
- Bucket Nameにjaws-ug-akita-kito-3
	- 全regionでユニークな名前
- Region
	- US Standard選択(フレームワークのデフォルトになってる)
	- デフォルトはOregonになっている
- Createをクリック

![kobito.1400764277.103059.png](https://qiita-image-store.s3.amazonaws.com/0/8941/96780b46-f5d7-77c0-4fc1-cafbfc7e3215.png "kobito.1400764277.103059.png")



はいできた

![kobito.1400764377.284324.png](https://qiita-image-store.s3.amazonaws.com/0/8941/20f8b939-46d0-bfc7-31b9-4609b6892e6c.png "kobito.1400764377.284324.png")


### ファイルを入れる

バケットをクリック

![kobito.1400765277.014070.png](https://qiita-image-store.s3.amazonaws.com/0/8941/cc5b4c00-97e1-3e51-ba8d-81286aa99484.png "kobito.1400765277.014070.png")

- Upload
	- ファイル、フォルダ単位でアップロード

![kobito.1400765451.858923.png](https://qiita-image-store.s3.amazonaws.com/0/8941/c48449af-b6a0-5e51-32f8-73fd2a8d2e33.png "kobito.1400765451.858923.png")

	- プロパティで属性確認、編集できます

![kobito.1400766308.099015.png](https://qiita-image-store.s3.amazonaws.com/0/8941/f09ce6fb-450f-378d-ef1a-79f166fe14a7.png "kobito.1400766308.099015.png")


- Create Folder
	- フォルダ作成

![kobito.1400766362.318499.png](https://qiita-image-store.s3.amazonaws.com/0/8941/79a7ba6d-bdfd-aeb1-d746-c1627923d712.png "kobito.1400766362.318499.png")

- Actions
	- その他の操作
		- 削除とか

![kobito.1400766423.360301.png](https://qiita-image-store.s3.amazonaws.com/0/8941/6f2064cb-cb74-9daf-1f19-4eb1f875df7f.png "kobito.1400766423.360301.png")


# ------
# Rubyから使う
# ------

## aws-sdk-ruby

Amazon official library

[AWS SDK for Ruby](https://aws.amazon.com/jp/sdkforruby/)
[aws/aws-sdk-ruby (github)](https://github.com/aws/aws-sdk-ruby)
[api documentation](http://docs.aws.amazon.com/AWSRubySDK/latest/frames.html)


## インストール

```sh
$ gem install aws-sdk
```

### Bundler便利だよ

Gemfile作成

```sh
$ bundle init
```

使用するgemを記述。
Rubyのバージョンを記述するとrvmなどがフォルダ移動時に切替えてくれる。

```Gemfile
# A sample Gemfile
source "https://rubygems.org"

gem "aws-sdk"

ruby "2.0.0"

```

Gemの準備

```sh
$ bundle install
```

```bundle``` だけでもOK。

```sh
$ bundle
```

### aws-sdk使ってみる

```ruby
require 'aws-sdk'

AWS.config(
  :access_key_id => 'YOUR_ACCESS_KEY_ID',
  :secret_access_key => 'YOUR_SECRET_ACCESS_KEY')
```

### YOUR_ACCESS_KEY_ID & YOUR_SECRET_ACCESS_KEY

![kobito.1400163761.627451.png](https://qiita-image-store.s3.amazonaws.com/0/8941/f75c8146-6294-2147-1569-079a643fe97a.png "kobito.1400163761.627451.png")


[secret access keyの扱いが変わった](http://blogs.aws.amazon.com/security/post/Tx1R9KDN9ISZ0HF/Where-s-my-secret-access-key)

![kobito.1400767526.266092.png](https://qiita-image-store.s3.amazonaws.com/0/8941/4a5bf969-2506-3f04-c93a-95b6e6316104.png "kobito.1400767526.266092.png")

![kobito.1400767575.150540.png](https://qiita-image-store.s3.amazonaws.com/0/8941/bfe41cf0-fa54-8460-4f0f-8bbcee1b6601.png "kobito.1400767575.150540.png")


### S3を扱うには

```ruby
s3 = AWS::S3.new
```

Region指定する場合は

```ruby
s3 = AWS::S3.new "ap-northeast-1"  # Asia Pacific (Tokyo) Region
```

デフォルトはus-east-1 (US Standard)

### バケット取得

AWS::S3#buckets

AWS::S3::BucketCollection

```ruby
s3.buckets['jaws-ug-akita']
```

全てのバケット
each で回せる

```ruby
s3.buckets.each do |b|
  puts b.name
end

s3.buckets.collect(& :name)
```

### バケット作成

```
s3.buckets.create "my-bucket"
```

Optionで権限など指定できる

> Options Hash (options):
:location_constraint (String) — default: nil — The location where the bucket should be created. Defaults to the classic US region; however, if you configure a regional endpoint for Amazon S3 this option will default to the appropriate location constraint for the endpoint. For example:
s3 = AWS::S3.new(:region => "us-west-1")
bucket = s3.buckets.create("my-us-west-bucket")
bucket.location_constraint # => "us-west-1"
:acl (Symbol, String) — default: :private — Sets the ACL of the bucket you are creating. Valid Values include: * :private * :public_read * :public_read_write * :authenticated_read * :log_delivery_write
:grant_read (String)
:grant_write (String)
:grant_read_acp (String)
:grant_write_acp (String)
:grant_full_control (String)


### バケット操作

AWS::S3#Bucket

#### 削除

```
bucket = s3.buckets.create "my-bucket"
bucket.delete # 中身が無い状態で
```

```ruby
bucket.delete! # 中身を空にしてから削除
```

```ruby
bucket.clear!
bucket.delete
```


## ファイル操作

AWS::S3::BucketCollection
AWS::S3::Object

### ファイルの生成/書込み

AWS::S3::Object#write

```ruby
o = bucket.objects["helloworld.txt"]
o.write("Hello World!")
```

### ファイルの読み込み

AWS::S3::Object#read

```ruby
o = bucket.objects["helloworld.txt"]
o.read # => "Hello World!"
```


### ファイルアップロード(local -> S3)

```ruby
# "jaws-akita-1.jpg"という画像ファイルがある
o = o.bucket.objects["jaws-akita-1.jpg"]
o.write(file: "jaws-akita-1.jpg")
```


### ファイルダウンロード(S3 -> local)

```ruby
File.open("download.jpg", "w") do |f|
  o.read do |chunk|
    f.write chunk
  end
end
```

### バケット削除(内包する全てのファイルも削除)

```ruby
  bucket.delete!
```

### サーバーサイドでの暗号化

```ruby
  o = bucket.objects["enc-helloworld.txt"]
  o.write("Hello World!", :server_side_encryption => :aes256)
  o
```

### 暗号化ファイルの読込み

普通に読込みでOK

```ruby
  puts o.read
```

### フォルダ作成

path指定するだけ。簡単。

```ruby
  o = bucket.objects["folder/こんにちは.txt"]
  o.write("こんにちは")
```


### バージョニング

バージョン管理もできる。

バージョニング有効にする。

```ruby
  bucket.enable_versioning
```

ファイルを色々更新

```ruby
  o = bucket.objects['versioning.txt']
  o.write "a"
  o.write "b"
  o.delete
  o.write "c"
```

前バージョンのブラウズ

```ruby
  o.versions.each do |obj_version|
    unless obj_version.delete_marker?
      puts obj_version.read
    else
      puts "- DELETE MARKER"
    end
  end
```

最新バージョン

```ruby
  o.versions.latest
```


### ライフサイクル

1年経過で削除

```ruby
  bucket.lifecycle_configuration.update do
    add_rule('', :expiration_time => 365)
  end
```


### Glacier

> きわめて低コストのストレージサービスである Amazon Glacier は、ストレージのセキュリティと耐久性を特徴としており、データのアーカイブやバックアップに適しています。コストを低く抑えるために、Amazon Glacier は、アクセス頻度の低いデータや、取り出しに数時間かかっても問題ないデータに合わせて最適化されています。Amazon Glacier ならば、データの量にかかわらず、1 か月あたり 0.01 USD/GB という低額で安心してデータを保管できるので、オンプレミスのソリューションに比べて大幅にコストを削減できます。

バックアップなどの使用頻度が低いデータは一定期間経過後にGlacierに転送。

1ヶ月後に転送

```ruby
  bucket.lifecycle_configuration.update do
    add_rule('backups/', :glacier_transition_time => 30)
  end
```

#### 新機能

古いバージョンを定期的にGlacierに移して、更に時間が経ったら削除などもできる様になったらしい。
APIからのやり方はドキュメント見ただけでは分りませんでした。(まだ準備中？)

[Amazon S3 でバージョン管理されたオブジェクトもLifecycle管理が可能に](http://aws.typepad.com/aws_japan/2014/05/amazon-s3-lifecycle-management-update.html)

## スクリーンショットを自動的にS3に

フォルダアクションを利用

![kobito.1401110092.994632.png](https://qiita-image-store.s3.amazonaws.com/0/8941/a4143a62-ab23-73f1-9622-96d3735f5084.png "kobito.1401110092.994632.png")

シェルスクリプトを実行を追加

![kobito.1401723079.326273.png](https://qiita-image-store.s3.amazonaws.com/0/8941/987fdfa5-4e24-5cb3-74c3-ee86ddc2adef.png "kobito.1401723079.326273.png")

Ruby環境整えてbackup_screenshots.rbを実行

```sh
cd /Users/ISD/Documents/community/aws-akita/3
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
rvm 2.0.0
ruby backup_screenshots.rb "$@"
```


```ruby:backup_screenshots.rb
require 'aws-sdk'
require 'yaml'

config = YAML.load(File.read("aws.config"))

# Configuration
AWS.config(
  :access_key_id => config["ACCESS_KEY_ID"],
  :secret_access_key => config["SECRET_ACCESS_KEY"])

@s3 = AWS::S3.new


def bucket_for_screenshots
  bucket = @s3.buckets["jaws-ug-akita-kito-3-screenshots"]
  unless bucket.exists?
    bucket = @s3.buckets.create "jaws-ug-akita-kito-3-screenshots"
  end
  bucket
end


def transmit path
  bucket = bucket_for_screenshots
  name = File.basename path
  o = bucket.objects[name]
  o.write(file: path)
end


ARGV.each do |path|
  transmit path.dup.force_encoding("utf-8")
end
```


やったーできた！

<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
![kobito.1401359501.340515.png](https://qiita-image-store.s3.amazonaws.com/0/8941/d2f38c6d-8bd0-5965-a21b-3c6de15f6a3d.png "kobito.1401359501.340515.png")

それDropboxにあるじゃん…

### 比較的簡単におれおれDropbox作れそう


## ソース

https://github.com/katsuyoshi/jaws-ug-akita/tree/master/3



# おしまい