20191124のAWSに関する記事は12件です。

AWSにdjango開発環境構築メモ(VSCode Remote SSH用)

前提

この構築のゴールは、AWS環境ではsshのみ開けて、サーバサイドの開発、デバックをClientPCのVSCodeでできるようにすることです。

Client
  Windows10
サーバ 
 CentOS7(AWSで動作)

※手順全部書いたつもりです。参考になるところあったら使ってください。
※毎回これするのも大変なのでansible化するかdokerイメージにしたい。
※VSCodeでのdjangoデバック環境は次の機会に。

ssh 設定

.ssh/sshconfigにAWSで起動したCentOSののログイン情報を記載してSSHでパス無しでログインできるようにする。
LocalForwardの行は、Djangoのポートへの。PCでlocalhost:8000を開くとサーバ側に転送されて便利。

# Read more about SSH config files: https://linux.die.net/man/5/ssh_config
Host myserver
    HostName xxx.xxx.xxx.xxx
    User centos
    IdentityFile ~user/.ssh/xxxx.pem
    LocalForward 8000 localhost:8000

VSCodeのRemote SSHで接続できる事を確認しておく
VSCodeにpythonのプラグインをインストールする

サーバ側の変更

CentOS7のGitをVersion2に変更する

$ sudo yum -y remove git
$ sudo yum -y install https://centos7.iuscommunity.org/ius-release.rpm
$ sudo yum -y install git2u

venv環境を作ってdjangoをインストール。後で使う、mysqlclientもインストール

$ sudo pip3.6 install --upgrade pip
$ cd ~/envs/activate
$ python3 -m venv django
$ source ~/envs/django/bin/a
$ pip install django
$ sudo yum install python-devel mysql-community-devel
$ pip install mysqlclient

djangoのサンプルアプリ作成

$ cd ~/web/
$ django-admin startproject mysite

Cent7のSQliteのバージョンだとdjangoが動かない。
SQLiteは諦めMysqlをインストール

$ sudo yum localinstall https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
$ yum info mysql-community-server
$ yum -y install mysql-community-server
$ sudo yum -y install mysql-community-server
$ sudo systemctl enable mysqld.service
$ sudo systemctl start mysqld.service
$ sudo systemctl status mysqld.service
$ sudo cat /var/log/mysqld.log|grep password

Mysqlのセキュリティ設定

[root@ip-172-31-33-248 ~]# mysql_secure_installation 

Securing the MySQL server deployment.

Enter password for user root: 

The existing password for the user account root has expired. Please set a new password.

New password: 
Re-enter new password: 
The 'validate_password' component is installed on the server.
The subsequent steps will run with the existing configuration
of the component.
Using existing password for root.

Estimated strength of the password: 100 
Change the password for root ? ((Press y|Y for Yes, any other key for No) : No

 ... skipping.
By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.

Remove anonymous users? (Press y|Y for Yes, any other key for No) : y
Success.


Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y
Success.

By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.


Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y
 - Dropping test database...
Success.

 - Removing privileges on test database...
Success.

Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y
Success.

All done! 
[root@ip-172-31-33-248 centos]# 

MysqlのユーザとDB作成

mysql> create database django01;
mysql> create user django@localhost identified by '************';
mysql> grant all on django01.* to django@localhost;

venvの適用方法(メモ)

[centos@ip-172-31-33-248 web]$ source venv/bin/activate
(venv) [centos@ip-172-31-33-248 web]$ python -V
Python 3.6.2
(venv) [centos@ip-172-31-33-248 web]$ pip list
Package    Version
---------- -------
Django     2.2.7  
pip        19.3.1 
pytz       2019.3 
setuptools 28.8.0 
sqlparse   0.3.0  

djangoのDBをMysqlに変更

$ git diff
diff --git a/mysite/settings.py b/mysite/settings.py
index 94fdb96..cf0a816 100644
--- a/mysite/settings.py
+++ b/mysite/settings.py
@@ -75,8 +75,15 @@ WSGI_APPLICATION = 'mysite.wsgi.application'

 DATABASES = {
     'default': {
-        'ENGINE': 'django.db.backends.sqlite3',
-        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+        'ENGINE': 'django.db.backends.mysql',
+        'NAME': 'django01',
+        'USER': 'django',
+        'PASSWORD': '********',
+        'HOST': 'localhost',
+        'PORT': '3306',
+        'OPTIONS': {
+                'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
+                },
     }
 }
python manage.py migrate
python manage.py runserver

クライアントPCでhttp://localhost:8000を開くとdjangoサーバにつながります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS EC2でWindows2008から2012にインプレースアップグレードを試してみた

Windows Server 2008 R2 の期限が 2020年1月に切れます(現在2019年11月)。新規にEC2を構築して移行すればよいのですが、Windowsに インプレースアップグレード っていうのがあるらしいので試してみました。

概要
インプレースアップグレードというのは、Windows Server 2008R2 から 2012に変更できるみたいです。Microsoft公式では2世代までOKと書いているのですが、Win2008R2からWin2012R2はダメでした(Win2008R2からWin2012はOKでした)

注意点
ドキュメントにネットワークドライバを更新せよと書いてあったので更新すると、リモートデスクトップで接続できなくなり、実験サーバーなので破棄しました。みなさんも注意してください。

AWS 資料
インプレースアップグレードを実行する

事前準備

今回は Windows Server 2008 R2 から Windows Server 2012 にアップグレードします。まずは現状のインスタンスにおまじない的な作業を3つ行います。

1 EC2Config サービスをアンインストール

[コントロールパネル][プログラムと機能] から EC2ConfigService をアンインストールします。

2 EC2Launch サービスのインストール

以下の2つをダウンロードします。
https://s3.amazonaws.com/ec2-downloads-windows/EC2Launch/latest/EC2-Windows-Launch.zip
https://s3.amazonaws.com/ec2-downloads-windows/EC2Launch/latest/install.ps1
zipは解凍せずにそのままです。同じ位置にps1を置きます(両方デスクトップに置きました)install.ps1 を右クリック「PowerShellで実行」してください。その後 C:\ProgramData\Amazon で確認してください(隠しフォルダなのでパスを直接入力)

3 AWS Systems Manager SSM エージェントのインストール

以下のダウンロードして実行してください。
https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/windows_amd64/AmazonSSMAgentSetup.exe

インストールメディアの作成

Windows のインストールメディアを用意するのですが、AWS の場合はメディア4GBのボリュームを作り、Dドライブにマウントさせます(おークラウドっぽい)

4 アベイラビリティーゾーン(AZ)とインスタンスIDを控えます。

5 メディアのボリュームの作成

[EC2][スナップショット] で「パブリックスナップショット」を選択します。説明に Windows 2012 と入れて検索します。Windows 2012 Japaneseで「ボリュームの作成」を実行します。先ほどのAZを指定します。

6 ボリュームをアタッチ

作成した4GBのボリュームを選択し「ボリュームのアタッチ」を実行します。インスタンスIDを指定します。

Windows アップグレード

インストールメディアを使ってアップグレードを行います。

7 EC2にリモートデスクトップでログインします。

Dドライブにインストールメディアが表示されています。Setup.exe を実行します。
<起動してすぐ終了する場合>
私の場合 Win2012R2 のインストールメディアが起動できず、Win2012 にするとできました。

8 実行中

強制再起動から10分くらい待ちました。

9 確認

システムが使えるかを確認します。

まとめ

Win2008から2012なら新規に2019を作った方がいいかもしれません。当然ながら無理やり2012になるので、細かいところでトラブルが発生するかもしれません。昔Win7からWin10のアップグレードのトラブルで苦労しました。1点モノのどうしようもないサーバーで、お客から催促されているならこの方法はアリかもしれません。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Go使ってAWS Lambdaでラムダ計算した

tl; dr

ソースコードはこちら
エンドポイントは
https://nd88j25ztg.execute-api.ap-northeast-1.amazonaws.com/dev/lambda
でヘッダにContent-type: application/jsonX-API-KEY: uwuZMJIWbqpmTpfzdEci2YaMGWFSvWz9ZfWFIjVfを仕込んで{"step":1,"src":"(λx.x)a"}みたいにPostしてください。curlでやると

$ curl -X POST -H "Content-type: application/json" -d '{"step":1, "src": "(λx.x)a"}' -H 'X-API-KEY: uwuZMJIWbqpmTpfzdEci2YaMGWFSvWz9ZfWFIjVf' https://nd88j25ztg.execute-api.ap-northeast-1.amazonaws.com/dev/lambda

みたいな感じ。なお予告なく削除することもあるのでご了承を。

前置き

AWS Lambdaでラムダ計算をするというしょうもないネタ、絶対誰かやってると思ったんですが案外誰もやってない。そんじゃいっちょやってみっかてな感じで、じゃあ言語どうするかって考えたらやっぱ静的型付けがいいよねということでGoに決定。Goやるやる詐欺やめて触ってみるいい機会なのでやってみました。パッケージわけが面倒だったので全部mainです。

そもそもラムダ計算とは

正しく説明できそうにないので参考文献を挙げるにとどめておきます……。ここでは形無しラムダ計算のみ考えます。

ラムダ計算入門 https://www.slideshare.net/_yingtai/lambda-guide
ラムダ計算ABC - Sendai Logic Homepage https://sites.google.com/site/sendailogichomepage/files/ref/ref_03

ラムダ計算のモデルを使ってもチューリングマシンと同じ表現力がありますよというお話。

Goで実装する

ラムダ計算

型システム入門を読みながらポチポチやってたらめっちゃ簡単でした

lambda.go
package main

import (
    "sort"
    "strconv"
)

type Name string

type Names []Name

func (xs Names) Len() int{
    return len(xs)
}

func (xs Names) Less(i, j int) bool {
    return xs[i] < xs[j]
}

func (xs Names) Swap(i, j int) {
    xs[i], xs[j] = xs[j], xs[i]
}

type Var struct {
    name Name
}

type Lam struct {
    name Name
    expr Expr
}

type App struct {
    f Expr
    arg Expr
}

type Sym struct{
    symbol rune
}

type Expr interface {
    reduce() Expr
}

func (x Var) reduce() Expr {
    return x
}

func (x Lam) reduce() Expr {
    return x
}

func (x App) reduce() Expr {
    switch g := x.f.(type) {
    case Var:
        return App{g, x.arg.reduce()}
    case Lam:
        return subst(g.name, x.arg.reduce(), g.expr.reduce())
    case App:
        return App{x.f.reduce(), x.arg.reduce()}.reduce()
    default:
        panic("")
    }
}

func (x Sym) reduce() Expr {
    return x
}

var cnt = 0

func subst(x Name, s Expr, y Expr) Expr {
    switch z := y.(type) {
    case Var:
        if x == z.name {
            return s
        } else {
            return y
        }
    case Lam:
        if x == z.name {
            return z
        } else {
            if !elem(z.name, free(s)) {
                return Lam{z.name, subst(x, s, z.expr)}
            } else {
                n := Name((string)(z.name) + strconv.Itoa(cnt))
                cnt++
                return  Lam{n, subst(x, s, subst(z.name, Var{n}, z.expr))}
            }
        }
    case App:
        return App{subst(x, s, z.f), subst(x, s, z.arg)}

    default:
        panic("")
    }
}

func free(x Expr) Names {
    switch y := x.(type) {
    case Var:
        return Names{y.name}
    case Lam:
        return remove(y.name, free(y.expr))
    case App:
        return union(free(y.f), free(y.arg))
    default:
        return Names{}
    }
}

Go言語で union とか直和型のようなデータを表現したいときは interface を使う - 嵐の小舟より https://tmrtmhr.info/tech/sum-type-in-golang/
こちらを参考にADTっぽいものをやってみました。中々それっぽく出来ていい感じ。

パーサー

こっちのほうが難航したという。まず以下の部分で逆ポーランド記法に直してます。

parser.go
func toRpn(str string) ([]rune, error) {
    stack := []rune{}
    rpn := []rune{}
    isParam := false
    lamCnt := 0
    for _, c := range str {
        switch c {
        case '\\', 'λ':
            if isParam {
                return nil, errors.New("lmbda in parameters")
            }
            stack = push('\\', stack)
            isParam = true
        case '.':
            for {
                xs, x, err := pop(stack)
                if err != nil {
                    return nil, errors.New("mismatched lambda")
                }
                stack = xs
                if x == '\\' {
                    break
                }
                rpn = append(rpn, x)
            }
            isParam = false
        case '(':
            if isParam {
                return nil, errors.New("parens in parameters")
            }
            stack = push('(', stack)
        case ')':
            if isParam {
                return nil, errors.New("parens in parameters")
            }
            for {
                xs, x, err := pop(stack)
                if err != nil {
                    return nil, errors.New("mismatched parens")
                }
                stack = xs
                if x == '(' {
                    break
                }
                rpn = append(rpn, x)
            }
            for i := 0; i < lamCnt; i++ {
                rpn = append(rpn, '\\')
            }
            lamCnt = 0

        case ' ', ' ':
        default:
            rpn = append(rpn, c)
            if isParam {
                lamCnt++
                rpn = append(rpn, '.')
            }
        }
    }
    if isParam {
        return nil, errors.New("lacking expression")
    }
    for {
        xs, x, err := pop(stack)
        if err != nil{
            break
        }
        if x == '(' || x == ')' || x == '\\' || x == '.' {
            return nil, errors.New("invalid tokens remain")
        }
        stack = xs
        rpn = append(rpn, x)
    }
    for i := 0; i < lamCnt; i++ {
        rpn = append(rpn, '\\')
    }
    return rpn, nil
}

逆ポーランド記法にすることにより括弧を除去できます。これをパーサに読み込ませてASTを得ます。

parser.go
func parse(str string) (Expr, error) {
    rpn, err := toRpn(str)
    if err != nil {
        return nil, err
    }
    stack := []Expr{}
    for _, t := range rpn {
        switch t {
        case '\\':
            lam := true
            for lam {
                xs, x, _ := popExpr(stack)
                ys, y, err := popExpr(xs)
                if err != nil {
                    return nil, errors.New("token exhausted")
                }
                stack = ys
                if w, ok := x.(Sym); ok {
                    x = Var{Name(string([]rune{w.symbol}))}
                }
                if z, ok := y.(Sym); ok {
                    if z.symbol == '.' {
                        vs, v, err := popExpr(stack)
                        if err != nil {
                            return nil, errors.New("argument notfound")
                        }
                        stack = vs
                        if u, ok := v.(Sym); ok {
                            stack = pushExpr(Lam{Name(string([]rune{u.symbol})), x}, stack)
                            lam = false
                        } else {
                            return nil, errors.New("argument must be symbol")
                        }
                    } else {
                        y = Var{Name(string([]rune{z.symbol}))}
                        stack = pushExpr(App{y, x}, stack)
                    }
                }
            }

        default:
            stack = pushExpr(Sym{t}, stack)
        }
    }
    for {
        xs, x, err1 := popExpr(stack)
        if err1 != nil {
            return nil, errors.New("no result")
        }
        if x0, ok := x.(Sym); ok {
            x = Var{Name(string([]rune{x0.symbol}))}
        } 
        ys, y, err2 := popExpr(xs)
        if err2 != nil {
            return x, nil
        } else {
            if y0, ok := y.(Sym); ok {
                y = Var{Name(string([]rune{y0.symbol}))}
            } 
            stack = pushExpr(App{y, x}, ys)
        }
    }
}

λExprを消費しつつAppにまとめていってます。

prettify

てけとーにASTを文字列に直してるだけなので特に語ることなし。

main

Serverless Framework(Go) でHello worldしてみる - Qiita https://qiita.com/seike460/items/b54a61ec8d07b2be8c87

こちらを参考に、リクエストに対してレスポンスを返す関数を書くだけでした。簡単!

感想

AWS LambdaでWebAPIをさらっと作りたいときはserverless本当に便利ですね。Terraformの特化版のよう。Goは初めて書きましたが思いの外サクサク書けて良い感じ。C言語のような原初の風景も感じますが、エディタの補完が強力なので気持ちよく書けます。今度は非同期処理とかもやってみたいですね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Amazon Transcribeを試してみた

twitterで「Amazon Transcribeがリリースされた」との情報をゲットしたため使ってみた。

Amazon Transcribeとは?

AWSの音声認識のサービス。音声ファイルをS3にアップロードすると、数分で自動で文字起こししてくれるサービス。

検証環境など

  • iphoneのボイスメモを利用。
  • 静かな部屋(周りに人がいないかつテレビ等も消した状態)でボイスメモの録音を実施。
  • iphoneと発言者の距離は十数cm。
  • つまり録音時の環境は良好。

結論

  • 上記環境で利用する分には文字起こしの精度は非常に高い。(認識率100%)

検証方法

  • 音声を録音する。

    • iphoneの「ボイスメモ」機能を利用し音声を録音する。
    • 音声ファイルをiphoneからPCに転送する。
  • PCでAWSマネジメントコンソールにログインする。 

    • 省略。
  • 録音した音声ファイルをS3にアップロードする。

    • バケットを作成する。(もちろん既存の物があればそれでOK。)
    • 音声ファイルをバケットにアップロードする。
    • アップロード完了したらバケットのバスをコピーしておく。
  • Amazon Transcribeのジョブを新規作成する。

    • マネジメントコンソールのトップページで「Amazon Transcribe」と入力する。
    • 当該ページが表示されたら、「Create job」をクリックする。
    • 「Job settings」「Input data」の各項目を入力する。
      • 「format(音声ファイルの形式)」に制限あり。mp3、mp4、wav、flacのみ対応。
      • 「Audio sampling rate」は音声ファイルのプロパティで確認可能なので、そこの情報をもとに記入する。※ここ間違うと、文字起こしに失敗する。 iOS の画像.jpg

    - 「Output Data」は今回すべてデフォルトのままにする。(よくわかんない)
    - 「Create」を押下。
iOS の画像-4.jpg

  • 「Status」が「In progress」から「Complete」になるまで待つ。
    iOS の画像-2.jpg

    • 「Status」が「Complete」になったら文字起こしの結果を確認する。 iOS の画像-5.jpg
      • 今回は音声ファイルも小さかったせいか1分ほどで文字起こし完了。ちゃんと認識されていますね。

今後の課題ややってみたいこと

  • 議事録作成に応用できないか実験する。
    • 職場のがやがやした環境の中で、どのくらいの精度を発揮できるか実験する。
    • もちろん、文字起こしされたテキストを構造化し直すタスクは自身でやらないといけないが…)
  • コールセンター業務に活用できないか考える。
    • コールセンター業務で音声データの録音をやってるはず。これを「Amazon Transcribe」で文字起こししして、テキストマイニングかけて、チャットボットの精度向上に役立てるとか
    • Amazon Connectと連携できないか。

つぶやき

音楽ファイルでやってみたけど、だめだった笑(あわよくば歌詞をすべて文字起こしして欲しかった)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

8万語の辞書を持ったインテリBotを常時利用できるようにした話

やったこと

fugaしか答えない残念なBotに8万語の辞書を持たせてインテリBotにした話の続き、常時起動できないLINE Botだったので、Heroku化して常時利用できるようにしました。あと、AWSのAPI GatewayにAPIキーを設定してアクセス制御しました。

構成変更

  • 変更前
    • Nodejsが個人パソコン上にあるためLINE Botを常時起動するにはよくない構成でした

  • 変更後
    • 個人パソコン上の環境をHeroku化することで常時起動に適した環境にしました。
    • 辞書APIのアクセス制御(APIキー)を設定しました。

参考サイト


では設定方法を紹介します。

1.[AWS] API GatewayにAPIキーを設定しよう

  • API Gatewayで作成した辞書BotにAPIキーを設定します。

1-1.使用量プラインを作成しよう

AWSコンソールで、APIキーを設定するAPIを開き、使用量プランをクリックします。
名前、レートなどの項目を設定し次へボタンをクリックします。

APIステージの追加で、APIキーを設定するAPIを設定し次へボタンをクリックします。(※辞書Botは、AWS上ではdemo-apiステージdemoで登録しています)

これで使用量プランの作成が完了しました。

1-2.APIキーを作成しよう

AWSコンソールで、APIキーを設定するAPIを開き、アクション->APIキーの作成をクリックします。

名前を設定し保存ボタンをクリックします。

手順1-1で作成した使用量プランを設定します。

これで、APIキーの作成が完了しました。APIキーはここに表示されます。あとで使うのでどこかにコピーしておきます。

2.API GatewayでAPIキーを有効化しよう

作成したAPIキーを辞書Bot(API Gateway)のAPIで有効にします。
メソッドのリクエストをクリックします。

APIキーの必要性をTrueにします。

これでAPIキーの有効化が完了しました。API Gatewayをデプロイすれば完了です。

3.動作確認しよう

APIキーによる制御ができるか動作確認します。

3-1.検証① APIキー無しで辞書APIにアクセスする

APIキー無しで辞書APIにアクセスすると、{"message":"Forbidden"}となり、辞書の情報が返ってきません、これは想定した動作になります。

$ curl https://xxx.execute-api.ap-northeast-1.amazonaws.com/demo?test_id=book
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    23  100    23    0     0    306      0 --:--:-- --:--:-- --:--:--   315{"message":"Forbidden"}

3-2.検証② APIキー有りで辞書APIにアクセスする

APIキー有りで辞書APIにアクセスすると、辞書の情報が返ってきました。これは想定した動作になります。

$ curl https://xxx.execute-api.ap-northeast-1.amazonaws.com/demo?test_id=book --header "x-api-key:xxxxxx"
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   107  100   107    0     0    104      0  0:00:01  0:00:01 --:--:--   104{"name": "(1) \u30db\u30c6\u30eb\u306e\u4e88\u7d04\u4fc2\u306b\u767b\u9332\u3059\u308b", "test_id": "book"}

4.Nodejsで作ったLINE Botを更新しよう

Nodejsで作成したLINE Botを更新し以下の対応をします。

  • APIキー対応
  • Heroku化対応
server.js
'use strict';

const express = require('express');
const line = require('@line/bot-sdk');
const axios = require('axios');
const PORT = process.env.PORT || 3000;

const config = {
    channelSecret: 'xxxx',
    channelAccessToken: 'xxxx'
};

const app = express();

app.post('/webhook', line.middleware(config), (req, res) => {
    console.log(req.body.events);
    Promise
      .all(req.body.events.map(handleEvent))
      .then((result) => res.json(result));
});

const client = new line.Client(config);

function handleEvent(event) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }

  let mes = ''
  mes = '' + event.message.text + '』の意味は…'
  getNodeVer(event.source.userId , event.message.text);

  return client.replyMessage(event.replyToken, {
    type: 'text',
    text: mes
  });
}

const getNodeVer = async (userId, argKey) => {
    // 辞書API(API Gateway)のエンドポイント
    let apiUrl = 'https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/demo?test_id='+ argKey;
    apiUrl = encodeURI(apiUrl); // URLエンコード
    // ↓ヘッダーにAPIキーの設定なし
    //const res = await axios.get( apiUrl );
    // ↓ヘッダーにAPIキーを設定
    const res = await axios.get( apiUrl , {
      headers: { "x-api-key": "ここに、手順1.2で作成したAPIキーを設定する" }
    });

    console.log(res.data.name);

    await client.pushMessage(userId, {
        type: 'text',
        text: res.data.name,
    });
}

//Heroku非対応↓
//app.listen(PORT);
//Heroku対応↓
app.listen(process.env.PORT || 8080);
console.log(`Server running at ${PORT}`);

5.Nodejsで作ったLINE BotをHeroku化しよう

ローカルのNodejs環境をHerokuにアップロードします。Procfile.gitignoreファイルを作成し、いくつかコマンドを実行するとHeroku化が完了します。

※ Herokuにログインした状態で実行します

Procfileファイルを作り、Herokuにアップロードした後に実行するコマンドを指定します。

procfile
web: node server.js

.gitignoreファイルを作り、Herokuにアップロード不要なファイルを指定します。

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# next.js build output
.next

以下コマンドを実行しHeroku化します。

# 初期化
git init

# ファイル追加
git add --a

# コミット
git commit -m "commit"

# アプリ名を設定
heroku create アプリ名

# Herokuにプッシュ
git push heroku master

git push …まで実行完了するとHeroku化成功です(2回目以降は、アプリ名の設定heroku create …は不要です)

6.LINE Botの設定を変更しよう

LINE DevelopersでBotのWebhookをHeroku化したサイトに設定します。

image.png

トラブルシュート

git push heroku masterでエラーになりました。heroku create アプリ名で失敗していたのが原因でした。

PS C:\Users\fuga> git push heroku master
remote: !       Your account hoge@gmail.com does not have access to fugabot.
fatal: unable to access 'https://git.heroku.com/fugabot.git/': The requested URL returned error: 403   

このエラーが出たとき、configに[remote "heroku"]の情報がありませんでした。

PS C:\Users\fuga> cat .git\config
[core]
        repositoryformatversion = 0
        filemode = false
        bare = false
        logallrefupdates = true
        symlinks = false
        ignorecase = true

上記のようになったときのheroku createコマンドの実行結果がこれ↓

PS C:\Users\fuga> heroku create fugabot
Creating  fugabot... !
 !    Name fugabot is already taken

heroku createコマンドがエラー無く実行できたときはこんな感じになります。

PS C:\Users\fuga> heroku create fugabot2
Creating  fugabot2... done
https://fugabot2.herokuapp.com/ | https://git.heroku.com/fugabot2.git

heroku createコマンド実行後のconfigはこんな感じでした。

PS C:\Users\fuga> cat .\.git\config
[core]
        repositoryformatversion = 0
        filemode = false
        bare = false
        logallrefupdates = true
        symlinks = false
        ignorecase = true
[remote "heroku"]
        url = https://git.heroku.com/fugabot2.git
        fetch = +refs/heads/*:refs/remotes/heroku/*
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[AWS SDK for PHP]署名付きPOSTを使い、直接クライアント側からAWS S3にファイルアップロード(PostObjectV4インスタンスを使用)

以下の流れで実装しました。

  • PostObjectV4 のインスタンスを使い、署名付きPOSTに必要な情報を発行
  • Vue.jsで、アプリケーションサーバを介さず、クライアント側から直接S3にファイルをアップロード

画面はこんな感じで、簡単にアップロード画面を作ってます。
スクリーンショット 2019-11-18 23.51.42.png

準備

AWS

S3でバケットを作成してください。
※IAMの設定は省略します

S3 CORSの設定

CORSを設定しておかなければなりません。

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

AWS-SDK-PHPのインストール

$ composer require aws/aws-sdk-php

実装

署名付きPOSTに必要なデータを発行するPHPの処理と、ファイルアップロードするVue.jsの処理を記載します。
実装した処理は以下の通りです。

  • 署名付きPOSTに必要なデータ形式のjsonを返すAPI
  • Vue.jsから↑のAPIを叩き、レスポンスを取得
  • レスポンスを利用し、ファイルアップロード

API(PHP)

<?php
    // laravel apiのcontrollerの処理を一部抜粋
    public function getPresignedUrl(Request $request)
    {
        $s3Client = new \Aws\S3\S3Client([
            'credentials' => [
                'key' => env('AWS_ACCESS_KEY_ID'),
                'secret' => env('AWS_SECRET_ACCESS_KEY'),
            ],
            'region' => env('AWS_DEFAULT_REGION'),
            'version' => 'latest'
        ]);

        $bucket = env('AWS_BUCKET');
        $requestData = $request->all();
        $formInputs = [
            'acl' => 'public-read',
            'key' => 'hoge/' . $requestData['filename'] . '.' . $requestData['fileext'],
        ];
        $options = [
            ['acl' => 'public-read'],
            ['bucket' => $bucket],
            ['starts-with', '$key', 'hoge/'],
        ];
        $expires = '+20 minutes';
        $postObject = new \Aws\S3\PostObjectV4(
            $s3Client,
            $bucket,
            $formInputs,
            $options,
            $expires
        );

        $formAttributes = $postObject->getFormAttributes();
        $formInputs = $postObject->getFormInputs();

        return response()
            ->json([
                'url' => $formAttributes['action'],
                'fields' => $formInputs
            ]);
    }

Client側(Vue.js)

<script>
    export default {
        name: 'AwsS3Upload',
        methods: {
            async upload() { 
                const upload_files = document.getElementById('upload-file');
                const upload_file = upload_files.files[0];
                // 署名付きPOSTのAPI叩く
                let preSignedUrl = await this.getPresignedUrl();
                // S3へアップロード
                let uploadS3Path = await this.uploadS3(preSignedUrl, upload_file);
            },
            async getPresignedUrl() {
                // ↓ここのファイル名は仮置きで適当になってますw
                let filename = 'fuga';
                let filetype = 'image/jpeg'
                let fileext = 'jpg'
                try {
                    const url = '/api/get-presigned-url?filename=' +  filename + '&filetype=' + filetype + '&fileext=' + fileext;
                    let response = await axios.get(url);
                    console.log('S3署名付きURL取得 成功');

                    return response;
                } catch (error) {
                    console.log('S3 署名付きURL取得 失敗');
                }
            },
            async uploadS3(presignedUrl, up_file) {
                let data = presignedUrl.data;
                try {
                    var formdata = new FormData();
                    for (let key in data.fields) {
                        formdata.append(key, data.fields[key]);
                    }
                    formdata.append("file", up_file);
                    const headers = {
                        "content-type": "multipart/form-data",
                    }
                    console.log('S3 アップロード 開始');
                    let response = await axios.post(
                        data.url,
                        formdata,
                        {
                            headers: headers,
                        }
                    );
                    console.log('S3 アップロード 成功');
                    return data.url + '/' + data.fields.key;
                } catch (error) {
                    console.log('S3 アップロード エラー');
                }
            },
        }
    }
</script>

結論

署名付きPOSTで、S3へ直接クライアントサイドからファイルアップロードができました。

参考

【AWS S3】S3 Presigned URLの仕組みを調べてみた
CORS(Cross-Origin Resource Sharing)について整理してみた
PresignedPost.php
ブラウザからS3へのダイレクトアップロード

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS/GCP】データベース、クラウドストレージ、CDN、DNSの簡単な比較

データベース、クラウドストレージ、CDN、DNS

AWSとGCPのサービスのどちらを使おうとなったときに、調べたメモです。

データベース

比較対象

下記3つです。
AWS Aurora
Spanner
Cloud SQL

SpannerとCloud SQLの比較

オンライントランザクション処理などが想定されない限り、Spannerは too muchな気がしました。
なので、Cloud SQLで良さそうと感じています。
Cloud Spannerの概要と設計上の要点など
[ GCP ] メガネと学ぶ GCP (12) Cloud SQL と Spanner の比較 ~ 共通点、差異、料金 ~

AWS AuroraとCloudSQLの比較

レプリケーションに関しては、Replica Lag(マスターとスレーブの間で起きる書き込みの遅延のこと)が短くなるので、Auroraではないかと思っています。
ここら辺は運用しながら、知識をつけていこうと思っています。
Amazon RDS for MySQLとAmazon AuroraとGoogle Cloud SQL(2nd Generation)のレプリケーションの違い

その他

GKEからAWS Auroraにアクセスした時の注意事項
GCP を利用したセキュリティ要件対応 : VPC Service Controls を試してみた (その 1 : 概念の確認)

クラウドストレージ

パフォーマンス

読み取り

  • AWS S3:5,500 回以上の GET/HEAD リクエスト
  • Google Cloud Storage:5,000 件の読み取りリクエスト

書き取り

  • AWS S3:3,500 回以上の PUT/COPY/POST/DELETE リクエスト
  • Google Cloud Storage:毎秒 1,000 件の書き込みリクエスト

AWS S3
Google Cloud Storage

料金

リクエスト数に対する料金 GET 料金

  • Amazon S3:$0.037/10,000リクエスト
  • Google Cloud Storage:$0.05/10,000リクエスト

AWS S3料金公式
Google Cloud Storage

ストレージ料金

  • Amazon S3:$0.025/GB
  • Google Cloud Storage:$0.023/GB

クラウドストレージ比較解説まとめ
S3の料金体系が分かりにくいと聞かれたので纏めた

転送料金

ここもっと考慮すべき.......

現状の結論

現状だと、S3を使う方が良いのではと考えています。
パフォーマンスでは、S3の性能がよく、料金に関しては、ほとんど差分はないのが理由です。

CDN

料金

AWS CloudFront よりも Google Cloud CDNの方が安い。
https://blog.haramishio.xyz/entry/compare-cf-cloudcdn?referrer=https%3A%2F%2Fwww.google.com%2F

パフォーマンス

レイテンシ

下記の比較ツールを確認すると、グローバルではGoogle Cloud CDNの方がレイテンシは速いです。
Asiaだと、どちらも譲っていません。

CDNPerf
Performance Report(グローバル)
Performance Report(Asia)

可用性

CloudFrontは平均値としては、Google Cloud CDNよりも高いが、一時的に可用性が大幅に落ちている期間があるのが懸念です。
一方、Google Cloud CDNは安定的にサービスを提供できているのがうかがえる
CDNPerf
Performance Report(Global)
Performance Report(Asia)

補足

さらに大事なこととして、*障害をどのように検知するか、そしてどのように対応するかが重要になると思います。
障害の発生確率は、下記よりGoogle Cloud CDNは、可用性の数値から年に4日落ちると想定されてます。
なのでこの4日間を検知する仕組みが必要となることを頭にいおれておく。

可用性:98.782%

Google Cloud CDN 可用性

[可用性の参考数値]
 99%(ツーナイン)
  年:3.65日
  月:7.2時間
  週:1.68時間
  日:14.4分

 99.9%(スリーナイン)
  年:8.76時間
  月:43.2分
  週:10.1分
  日:1.44分

 99.99%(フォーナイン)
  年:52.56分
  月:4.32分
  週:6.05分
  日:8.64秒

 99.999%(ファイブナイン)
  年:5.26分
  月:25.9秒
  週:6.05秒
  日:0.86秒

現状の結論

CloudFrontの可用性は気になりつつも、Cloud Frontのように細かいキャッシュの設定ができないのは難点かもしれません。
一方で、簡単に設定することができることは、Google Cloud CDNの大きなメリットと言えると思います。

DNS

料金

料金がかかるところは2つ
①ホストゾーン→0.30ドルの違い
②トラフィック→料金同じ→Consになるほどデメリットではない

GCP DNS
Route53

機能面

DNSSECが差分になりうる?

AWS Route53
AWS Route53の特徴

[Pros]

[Cons]
DNSSECがサポートされていない

Google Cloud DNS
[Pros]
・DNSSECがサポートされている

[Cons]

参考記事
クラウドDNSサービス比較解説まとめ

DNSSECが本当に必要?

メリット
- DNS のリクエスト・レスポンスを改ざん、偽造を防止できる
DNSのセキュリティ拡張"DNSSEC"入門

デメリット
- DNSSECは、公開鍵認証を使うので、処理が遅くなる可能性がある
- 導入事例があまりない
あまりDNSSEC使ってるよという記事が見つからなかった....なぜだろう

DNSSEC はなぜダメなのか
DNSSEC 設定

DNSSEC設定する場合は、Google Cloud DNSは容易に設定が可能そうですね。
めちゃ殴り書きになってしまいましたが、終わりでうす。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS/GCP】データベース、クラウドストレージ、CDN、DNSの簡単な比較メモ

データベース、クラウドストレージ、CDN、DNS

AWSとGCPのサービスのどちらを使おうとなったときの自分用のメモです。
今後もうちょっとボリューミーにしていきたい。

データベース

比較対象

下記3つです。
AWS Aurora
Spanner
Cloud SQL

SpannerとCloud SQLの比較

オンライントランザクション処理などが想定されない限り、Spannerは too muchな気がしました。
なので、Cloud SQLで良さそうと感じています。
Cloud Spannerの概要と設計上の要点など
[ GCP ] メガネと学ぶ GCP (12) Cloud SQL と Spanner の比較 ~ 共通点、差異、料金 ~

AWS AuroraとCloudSQLの比較

レプリケーションに関しては、Replica Lag(マスターとスレーブの間で起きる書き込みの遅延のこと)が短くなるので、Auroraではないかと思っています。
ここら辺は運用しながら、知識をつけていこうと思っています。
Amazon RDS for MySQLとAmazon AuroraとGoogle Cloud SQL(2nd Generation)のレプリケーションの違い

その他

GKEからAWS Auroraにアクセスした時の注意事項
GCP を利用したセキュリティ要件対応 : VPC Service Controls を試してみた (その 1 : 概念の確認)

クラウドストレージ

比較対象

AWS S3
Google Cloud Storage

パフォーマンス

読み取り

  • AWS S3:5,500 回以上の GET/HEAD リクエスト
  • Google Cloud Storage:5,000 件の読み取りリクエスト

書き取り

  • AWS S3:3,500 回以上の PUT/COPY/POST/DELETE リクエスト
  • Google Cloud Storage:毎秒 1,000 件の書き込みリクエスト

AWS S3
Google Cloud Storage

料金

リクエスト数に対する料金 GET 料金

  • Amazon S3:$0.037/10,000リクエスト
  • Google Cloud Storage:$0.05/10,000リクエスト

AWS S3料金公式
Google Cloud Storage

ストレージ料金

  • Amazon S3:$0.025/GB
  • Google Cloud Storage:$0.023/GB

クラウドストレージ比較解説まとめ
S3の料金体系が分かりにくいと聞かれたので纏めた

転送料金

ここもっと考慮すべき.......

現状の結論

現状だと、S3を使う方が良いのではと考えています。
パフォーマンスでは、S3の性能がよく、料金に関しては、ほとんど差分はないのが理由です。

CDN

比較対象

AWS CloudFront
Google Cloud CDN

料金

AWS CloudFront よりも Google Cloud CDNの方が安い。
https://blog.haramishio.xyz/entry/compare-cf-cloudcdn?referrer=https%3A%2F%2Fwww.google.com%2F

パフォーマンス

レイテンシ

下記の比較ツールを確認すると、グローバルではGoogle Cloud CDNの方がレイテンシは速いです。
Asiaだと、どちらも譲っていません。

CDNPerf
Performance Report(グローバル)
Performance Report(Asia)

可用性

CloudFrontは平均値としては、Google Cloud CDNよりも高いが、一時的に可用性が大幅に落ちている期間があるのが懸念です。
一方、Google Cloud CDNは安定的にサービスを提供できているのがうかがえる
CDNPerf
Performance Report(Global)
Performance Report(Asia)

補足

さらに大事なこととして、*障害をどのように検知するか、そしてどのように対応するかが重要になると思います。
障害の発生確率は、下記よりGoogle Cloud CDNは、可用性の数値から年に4日落ちると想定されてます。
なのでこの4日間を検知する仕組みが必要となることを頭にいおれておく。

可用性:98.782%

Google Cloud CDN 可用性

[可用性の参考数値]
 99%(ツーナイン)
  年:3.65日
  月:7.2時間
  週:1.68時間
  日:14.4分

 99.9%(スリーナイン)
  年:8.76時間
  月:43.2分
  週:10.1分
  日:1.44分

 99.99%(フォーナイン)
  年:52.56分
  月:4.32分
  週:6.05分
  日:8.64秒

 99.999%(ファイブナイン)
  年:5.26分
  月:25.9秒
  週:6.05秒
  日:0.86秒

現状の結論

CloudFrontの可用性は気になりつつも、Cloud Frontのように細かいキャッシュの設定ができないのは難点かもしれません。
一方で、簡単に設定することができることは、Google Cloud CDNの大きなメリットと言えると思います。

DNS

比較対象

AWS Route53
Google Cloud DNS

料金

料金がかかるところは2つ
①ホストゾーン→0.30ドルの違い
②トラフィック→料金同じくらい

GCP DNS
Route53
クラウドDNSサービス比較解説まとめ

パフォーマンスに関しては、また調べないとなー。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

例の経営統合のニュースをAmazon Transcribeに文字起こしさせてみた

はじめに

AWSの自動音声認識サービスAmazon Transcribeが日本語に対応したとのことで、日本語音声を入力して文字起こしを試してみました。

題材

以下のニュース動画を利用しました。

1人のアナウンサーが1分間ほどニュースを読み上げる内容となっていて、複数人による会話などはありません。

文字起こし方法

Transcribeは、

  • マネジメントコンソール
  • AWS CLI
  • AWS SDK for Python (Boto)

にて利用できますが、今回はAWS CLIを使ってみます。

1. 変換をリクエストする

あらかじめ以下のJSONを用意しておいた上で、aws transcribe start-transcription-jobを実行します。

request.json
{
  "TranscriptionJobName": "yl",
  "LanguageCode": "ja-JP",
  "MediaFormat": "mp3",
  "Media": {
    "MediaFileUri": "https://foobar.s3-ap-northeast-1.amazonaws.com/yl.mp3"
  }
}
$ aws transcribe start-transcription-job --cli-input-json file://request.json

リクエストが受け付けられると、以下のようなレスポンスが返ってきます。

{
    "TranscriptionJob": {
        "TranscriptionJobName": "yl",
        "TranscriptionJobStatus": "IN_PROGRESS",
        "LanguageCode": "ja-JP",
        "MediaSampleRateHertz": 48000,
        "MediaFormat": "mp3",
        "Media": {
            "MediaFileUri": "https://foobar.s3-ap-northeast-1.amazonaws.com/yl.mp3"
        },
        "CreationTime": 1574510851.993
    }
}

2. 変換ジョブのステータスを確認する

以下コマンドで変換ジョブのステータスを確認します。

$ aws transcribe list-transcription-jobs --job-name-contains "yl"

もし変換が完了していればステータスはCOMPLETEDで返ってきます。

{
    "TranscriptionJobSummaries": [
        {
            "TranscriptionJobName": "yl",
            "CreationTime": 1574510995.946,
            "CompletionTime": 1574511071.683,
            "LanguageCode": "ja-JP",
            "TranscriptionJobStatus": "COMPLETED",
            "OutputLocationType": "SERVICE_BUCKET"
        }
    ]
}

なお、今回の1分間の音声の変換ジョブの完了には、約1分15秒の処理時間がかかっていました。

3. 変換結果を取得する

以下コマンドで変換結果ファイルのURIを取得します。

$ aws transcribe get-transcription-job --transcription-job-name "yl"
{
    "TranscriptionJob": {
        "TranscriptionJobName": "yl",
        "TranscriptionJobStatus": "COMPLETED",
        "LanguageCode": "ja-JP",
        "MediaSampleRateHertz": 44100,
        "MediaFormat": "mp3",
        "Media": {
            "MediaFileUri": "https://foobar.s3-ap-northeast-1.amazonaws.com/yl.mp3"
        },
        "Transcript": {
            "TranscriptFileUri": "https://s3.ap-northeast-1.amazonaws.com/aws-transcribe-ap-northeast-1-prod/(略)/asrOutput.json?X-Amz-Security-Token=xxxxxxxx&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20191123T122051Z&X-Amz-SignedHeaders=host&X-Amz-Expires=900&X-Amz-Credential=xxxxxxxx&X-Amz-Signature=xxxxxxxx"
        },
        "CreationTime": 1574510995.946,
        "CompletionTime": 1574511071.683,
        "Settings": {
            "ChannelIdentification": false
        }
    }
}

TranscriptFileUriが変換結果ファイルのURIなので、ここからファイルを取得します。

取得したファイルは以下のようになっていました(一部を抜粋)。

結果はtranscriptsitemsに分かれています。

{
  "jobName": "yl",
  "accountId": "xxxxxxxxxxxx",
  "results": {
    "transcripts": [
      {
        "transcript": "検索 サービス ヤフー ジャパン の (略) 発表 し 、 ます"
      }
    ],
    "items": [
      {
        "start_time": "0.04",
        "end_time": "0.54",
        "alternatives": [
          {
            "confidence": "1.0",
            "content": "検索"
          }
        ],
        "type": "pronunciation"
      },
      {
        "start_time": "0.54",
        "end_time": "1.18",
        "alternatives": [
          {
            "confidence": "1.0",
            "content": "サービス"
          }
        ],
        "type": "pronunciation"
      },
      {
        "start_time": "1.25",
        "end_time": "1.73",
        "alternatives": [
          {
            "confidence": "0.5202",
            "content": "ヤフー"
          }
        ],
        "type": "pronunciation"
      },
      {
        "start_time": "1.73",
        "end_time": "2.1",
        "alternatives": [
          {
            "confidence": "0.5202",
            "content": "ジャパン"
          }
        ],
        "type": "pronunciation"
      },
      {
        "start_time": "2.1",
        "end_time": "2.23",
        "alternatives": [
          {
            "confidence": "1.0",
            "content": "の"
          }
        ],
      },
// 
      {
        "start_time": "59.13",
        "end_time": "59.48",
        "alternatives": [
          {
            "confidence": "1.0",
            "content": "発表"
          }
        ],
        "type": "pronunciation"
      },
      {
        "start_time": "59.48",
        "end_time": "59.63",
        "alternatives": [
          {
            "confidence": "1.0",
            "content": "し"
          }
        ],
        "type": "pronunciation"
      },
      {
        "start_time": "59.63",
        "end_time": "60.05",
        "alternatives": [
          {
            "confidence": "1.0",
            "content": "ます"
          }
        ],
        "type": "pronunciation"
      }
    ]
  },
  "status": "COMPLETED"
}

文字起こし結果

前述のJSONのtranscriptの値が文字起こし結果全体となります。

検索 サービス ヤフー ジャパン の 親会社 セット ホールディングス と 通信 アプリ 大手 の ライン は 今日 経営 統合 する こと で 合意 し た と 発表 し、 まし た 利用 者 数 億 人 規模 の 巨大 相手 企業 が 誕生 し ます 両社 が 発表 し た。 合意 案 で は 最終 的 に セット ホールディングス の 親会社 の ソフトバンク と ライン の 親会社 の 韓国 ネバー が 磯 パーセント ずつ 出資 する、 新 会社 を 作り ます その 傘下 に ホールディングス を 置い て ヤフー や ライン を 子会社 に し、 ます ライン と ヤフー の 親会社 と なる セット ホールディングス の 代表 に は 今 の セット ホールディングス の 川辺 健太郎 社長 が 代表 取締役 社長 県 娘 を ライン の 入れ ザワ 剛 社長 が 代表 取締役 権 更新 よう と し て 共同 で、 着き ます 両社 は 今日 の 午後 五 時 から 改憲 を 開い て 統合 の 狙い など を 発表 し、 ます

固有名詞や同音異義語などを除くと、目立った誤変換として挙げられるのは以下でしょうか。

  • 数億人規模 : 1億人規模 (注:ニュースでは1億人と言っています)
  • 巨大相手企業 : 巨大IT企業
  • 磯パーセント : 50パーセント
  • 代表取締役社長県娘を : 代表取締役社長兼Co-CEO
  • 代表取締役兼更新よう : 代表取締役兼Co-CEO

Co-CEO(こ・しーいーおー)は難しかったようです。

磯パーセントは、よくわかりません:thinking:

解説

items

さきほどのtranscriptには、ところどころに半角スペースが見受けられますが、Amazon Transcribeでは

  • 全体的な文字起こし結果をtranscript

  • 品詞単位の文字起こし結果をitems

返すようになっていて、transcriptには、これら品詞単位の区切りに半角スペースが入っています。

{
  "jobName": "yl",
  "accountId": "xxxxxxxxxxxx",
  "results": {
    "transcripts": [
      {
        "transcript": "検索 サービス ヤフー ジャパン の (略) 発表 し 、 ます"
      }
    ],
    "items": [
      {
        "start_time": "0.04",
        "end_time": "0.54",
        "alternatives": [
          {
            "confidence": "1.0",
            "content": "検索"
          }
        ],

confidence

また、品詞ごとの変換結果の信頼性がconfidenceに格納されています。

試しにconfidence

  • 1.0(最高値)であれば
  • 0.9以上1.0未満であれば濃い灰色
  • 0.9未満であれば薄い灰色

で表示するよう、取得したJSONファイルを加工してみました。

import json


def conv_color(confidence: float) -> str:
    if confidence == 1:
        return "black"
    elif confidence >= 0.9:
        return "gray"
    else:
        return "silver"


with open('./transcript.json') as f:
    d = json.load(f)

    for item in d['results']['items']:
        color = conv_color(float(item['alternatives'][0]['confidence']))

        print(f'<font color="{color}">', end='')
        print(item['alternatives'][0]['content'], end='')
        print('</font>', end='')

すると、以下のような結果になりました。薄い部分はAmazon Transcribeも変換結果に自信が無い箇所・・・ということになります。

検索サービスヤフージャパン親会社セットホールディングス通信アプリ大手ライン今日経営統合すること合意発表まし利用規模巨大相手企業誕生ます両社発表合意最終セットホールディングス親会社ソフトバンクライン親会社韓国ネバーパーセントずつ出資する会社作りますその傘下ホールディングス置いヤフーライン子会社ますラインヤフー親会社なるセットホールディングス代表セットホールディングス川辺健太郎社長代表取締役社長ライン入れザワ社長代表取締役更新よう共同着きます両社今日午後から改憲開い統合狙いなど発表ます

費用

1秒の音声変換に、0.0004USDがかかります。ただし、15秒未満の場合は15秒分の料金がかかるとのこと。

今回の音声は約1分なので、おおよそ2〜3円ということになります。

なお、使い始めから1年間は、毎月60分の無料利用枠があります。

最後に

アナウンサーによるはっきりとした音声でも、いくつかの誤変換は発生していました。Amazon Transcribeでは変換結果の信頼度合い(confidence)を品詞ごとに持っているので、これをどう活用するかがポイントなのかもしれません。

また、今回は試せていませんが、音声内の話者数を2人から10人まで指定することが可能で、それら話者ごとの変換ができるようです。テレビ番組や会議の音声を文字起こしさせてみたら面白そうです。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Saving Plansによるコスト試算

Saving Plansによるコスト試算
はじめに
AWSで運用しているシステムでコスト効率を上げるため、Saving Plansのコスト試算に関して調べました。
基本料金とSaving Plansのコスト試算についてまとめています。

EC2の料金
Amazon EC2 料金表を確認しましょう。
基本的に常時稼働のEC2インスタンスではリザーブドインスタンス(RI)を購入して運用している方が多いと思います。
Saving Plansでは、常時稼働ではないが定期的・不定期に停止・起動を行っているようなサーバに適用することでコスト削減が望めそうです。

Fargateの料金
AWS Fargateの料金を確認しましょう。
2019/11/23現在、東京リージョン(ap-northeast-1)では以下の料金となっていました。

リソースタイプ 料金(per hour)
1 vCPU $0.05056
1 GB MEM $0.00553
Saving Plansでのコスト試算
AWSマネジメントコンソールのうち、EC2サービスにSaving Plansのメニューがあるので選択します。
※こちらに記載されている説明文(英語)はPurchase Saving Plansのリンク先に日本語訳があるので無視して大丈夫です
※請求ダッシュボード→Cost Explorer→コストエクスプローラ→Saving Plansからもいけます

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS で MFA 必須の IAM アカウントを作成し、ユーザに受け渡す手順について

多段階認証 (MFA) が必須の IAM アカウントを作成して、ユーザに受け渡す手順について。

MFA 必須でパスワードリセット可のポリシーについて

公式のドキュメントは以下の2つです。

基本的にはドキュメントの通りにやればいいのですが、このままだと、初回のパスワードリセットが許可されません。

この点についての説明が、英語版と日本語版で異なっていました。

注記
このポリシー例では、サインイン時のパスワードのリセットをユーザーに許可していません。新しいユーザーおよびパスワードの期限が切れているユーザーは、これを行う場合があります。これを許可するには、iam:ChangePassword をステートメント DenyAllExceptListedIfNoMFA に追加します。

英語版だと、

Note
This example policy does not allow users to reset a password while signing in. New users and users with an expired password might try to do so. You can allow this by adding iam:ChangePassword and iam:GetAccountPasswordPolicy to the statement DenyAllExceptListedIfNoMFA.

英語版に従っておくのが無難そうなので、以下の2つを DenyAllExceptListedIfNoMFA に追加します。

  • iam:ChangePassword
  • iam:GetAccountPasswordPolicy

追加した JSON は以下です。(実際に設定するときは、公式のドキュメントからコピペしてください)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowViewAccountInfo",
            "Effect": "Allow",
            "Action": [
                "iam:GetAccountPasswordPolicy",
                "iam:GetAccountSummary",       
                "iam:ListVirtualMFADevices"
            ],
            "Resource": "*"
        },       
        {
            "Sid": "AllowManageOwnPasswords",
            "Effect": "Allow",
            "Action": [
                "iam:ChangePassword",
                "iam:GetUser"
            ],
            "Resource": "arn:aws:iam::*:user/${aws:username}"
        },
        {
            "Sid": "AllowManageOwnAccessKeys",
            "Effect": "Allow",
            "Action": [
                "iam:CreateAccessKey",
                "iam:DeleteAccessKey",
                "iam:ListAccessKeys",
                "iam:UpdateAccessKey"
            ],
            "Resource": "arn:aws:iam::*:user/${aws:username}"
        },
        {
            "Sid": "AllowManageOwnSigningCertificates",
            "Effect": "Allow",
            "Action": [
                "iam:DeleteSigningCertificate",
                "iam:ListSigningCertificates",
                "iam:UpdateSigningCertificate",
                "iam:UploadSigningCertificate"
            ],
            "Resource": "arn:aws:iam::*:user/${aws:username}"
        },
        {
            "Sid": "AllowManageOwnSSHPublicKeys",
            "Effect": "Allow",
            "Action": [
                "iam:DeleteSSHPublicKey",
                "iam:GetSSHPublicKey",
                "iam:ListSSHPublicKeys",
                "iam:UpdateSSHPublicKey",
                "iam:UploadSSHPublicKey"
            ],
            "Resource": "arn:aws:iam::*:user/${aws:username}"
        },
        {
            "Sid": "AllowManageOwnGitCredentials",
            "Effect": "Allow",
            "Action": [
                "iam:CreateServiceSpecificCredential",
                "iam:DeleteServiceSpecificCredential",
                "iam:ListServiceSpecificCredentials",
                "iam:ResetServiceSpecificCredential",
                "iam:UpdateServiceSpecificCredential"
            ],
            "Resource": "arn:aws:iam::*:user/${aws:username}"
        },
        {
            "Sid": "AllowManageOwnVirtualMFADevice",
            "Effect": "Allow",
            "Action": [
                "iam:CreateVirtualMFADevice",
                "iam:DeleteVirtualMFADevice"
            ],
            "Resource": "arn:aws:iam::*:mfa/${aws:username}"
        },
        {
            "Sid": "AllowManageOwnUserMFA",
            "Effect": "Allow",
            "Action": [
                "iam:DeactivateMFADevice",
                "iam:EnableMFADevice",
                "iam:ListMFADevices",
                "iam:ResyncMFADevice"
            ],
            "Resource": "arn:aws:iam::*:user/${aws:username}"
        },
        {
            "Sid": "DenyAllExceptListedIfNoMFA",
            "Effect": "Deny",
            "NotAction": [
                "iam:CreateVirtualMFADevice",
                "iam:EnableMFADevice",
                "iam:GetUser",
                "iam:ListMFADevices",
                "iam:ListVirtualMFADevices",
                "iam:ResyncMFADevice",
                "sts:GetSessionToken",

                "iam:ChangePassword",
                "iam:GetAccountPasswordPolicy"
            ],
            "Resource": "*",
            "Condition": {
                "BoolIfExists": {
                    "aws:MultiFactorAuthPresent": "false"
                }
            }
        }
    ]
}

初期ユーザ用・MFA 設定済みユーザ用ポリシー

ポリシーを2つ作ります。

  • パスワードリセットを許可したポリシー (初期ユーザ用)
  • パスワードリセットにMFA が必要なポリシー (既存ユーザ用)

前者のポリシー名と説明を、以下のように設定します。
説明文に URL が書けないので、後から参照できるように公式ドキュメントのタイトルを書くことにしました。

MFARequiredOnlyForTheFirstLogin
Created YYYY-MM-DD - Copied and edited the official sample JSON to enable password reset - AWS Allows MFA-Authenticated IAM Users to Manage Their Own Credentials on the My Security Credentials Page

ポリシーの JSON は、上で説明した通り、公式ドキュメントからコピペして、Action を2つ追加したものを設定します。

そして、このポリシーだけを設定したグループ NotYetLoginUsers を作成します。

後者のポリシー名と説明は、以下のように設定します。

MFARequiredForCurrentUsers
Created YYYY-MM-DD - Copied from the official document - AWS Allows MFA-Authenticated IAM Users to Manage Their Own Credentials on the My Security Credentials Page

ポリシーの JSON は、公式ドキュメントのものをそのまま使います。

IAM アカウントの受け渡し

以下の手順で受け渡します。

  1. アカウントを作成し、NotYetLoginUsers グループにだけ所属させる
  2. メール等で仮のパスワードを伝えて、パスワードリセットと MFA 登録を依頼する
  3. 本人の MFA 登録が確認できたら、NotYetLoginUsers グループから外し、MFARequiredForCurrentUsers と必要な権限を設定する

2 の時点では何も権限がないので、パスワードはメールで送ってもよいことにしています。

パスワードポリシーの影響について

パスワードポリシーに、ユーザにパスワードの変更を許可する Allow users to change their own password というオプションがあります。

image.png

このオプションは、オンにしておく方が良さそうでした。

オフの場合、

  • ポリシーで明示的に指定しない限り、パスワードを変更できなくなる
  • ユーザ作成時にパスワードリセットを求めると、自動的に IAMUserChangePassword が追加される

という挙動になるようです。

image.png

逆に、ポリシーを設定さえすれば、そちらが優先されるようです。全ユーザに、上記 MFA 必須のポリシーを設定するのであれば、どちらでも基本的には同じ動作になります。

ただし、オフにすると、新規ユーザ作成時に勝手に IAMUserChangePassword ポリシーが設定されてしまうので、オンにしておくのが無難だと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Saving Plansによるコスト試算

Saving Plansによるコスト試算

はじめに

AWSで運用しているシステムでコスト効率を上げるため、Saving Plansのコスト試算に関して調べました。
基本料金Saving Plansのコスト試算についてまとめています。

EC2の料金

Amazon EC2 料金表を確認しましょう。
基本的に常時稼働のEC2インスタンスではリザーブドインスタンス(RI)を購入して運用している方が多いと思います。
Saving Plansでは、常時稼働ではないが定期的・不定期に停止・起動を行っているようなサーバに適用することでコスト削減が望めそうです。

Fargateの料金

AWS Fargateの料金を確認しましょう。
2019/11/23現在、東京リージョン(ap-northeast-1)では以下の料金となっていました。

リソースタイプ 料金(per hour)
1 vCPU $0.05056
1 GB MEM $0.00553

Saving Plansでのコスト試算

AWSマネジメントコンソールのうち、EC2サービスにSaving Plansのメニューがあるので選択します。
※こちらに記載されている説明文(英語)はPurchase Saving Plansのリンク先に日本語訳があるので無視して大丈夫です
※請求ダッシュボード→Cost Explorer→コストエクスプローラ→Saving Plansからもいけます

image.png

Saving Plansについて

上記の画面でPurchase Saving Plansのリンクをクリックすると以下の画面が表示されます。
以下の説明文にある通り、2種類のSaving Plansを提供しているようです。

  • Compute Saving Plans
  • EC2 Saving Plans

主にAmazon ECS on AWS EC2Amazon ECS on AWS Fargateで使い分ける感じでしょうか:thinking:

image.png

Saving Plansでのコスト試算について

推奨する Compute Saving Plans推奨する EC2 Instance Saving Plansにある通り、コストエクスプローラにより自動で算出された推奨プランを提示してくれる様です。
頭捻って色々試算しないといけないなと思ってましたが、トグルスイッチをポチポチ切り替えるだけでSaving Plansの種類や期間に応じた推奨プランを提示してくれるのでコスト試算するのはそんなに難しくないですね。

image.png

Saving Plansの注意点について

  • Compute Saving Plans
    • どのECS Clusterに適用されるのか意識して購入しましょう
  • EC2 Instance Saving Plans
    • どのEC2インスタンスに対して何が適用されるか意識して購入しましょう
      • Saving Plans上はインスタンスファミリまでしか表示されません
      • 脳死で推奨プラン通りに購入してしまって、実は不要な前払い料金を払ってしまった・・・なんてことも発生しうると思います。
      • (Saving Plansで使用傾向は加味して推奨プランを提示してくれますが)定常的に起動/停止していない変則的に利用するサーバなどが含まれている可能性があります
    • 1年以内に廃止する予定のサーバなど含まれていないか考慮しましょう
      • 損益分岐点がいつなのかも考慮できると良さそうです

参考リンク

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む