LaravelとElastic Beanstalkでサクッとスタブサーバを作る

概要

とにかく大至急スタブAPIサーバが必要でした。

Laravelのルーティング設定だったらすぐできるな

サーバどうしよう。PHP7のサーバが手元にない

Elastic Beastalkでできるかな

Laravelの準備

Laravelのプロジェクトを新規に作成。

Laravelプロジェクトを作成
composer create-project --prefer-dist laravel/laravel stub-server --no-secure-http

モックなのでルーティングだけ書いて済ませます。

routes/api.php
Route::get('test', function () {
    $res = <<< END
{
  "token": "token"
}
END;
    return response($res)
        ->withHeaders([
            'Content-Type' => 'application/json',
        ]);
});

アプリ側はこれだけです。
リクエストパラメータのバリデーションや、ステータス200以外も返したい場合はこれだと対応できないので、コントローラに書く必要があります。

zipでまとめる

Beanstalkにデプロイするにはいくつか方法がありますが、今回はzipファイルにして管理コンソールからアップします。

zipファイル作成
$ cd stub-server
$ zip ../laravel.zip -r * .[^.]*

Elastic Beanstalkの設定

管理コンソールのBeanstalkの画面で 新しいアプリケーションの作成 をクリックします。
アプリケーション名を入力して 作成 ボタンをクリック

1.jpg

以下のような画面に遷移するので 今すぐ作成しましょう をクリック

2.jpg

開いたウィンドウの ウェブサーバー環境 を選択して 選択 をクリック

3.jpg

URLを決めて 使用可能かチェック をクリックします。使用可能なら下記のようになります。

4.jpg

プラットフォームに PHP 、アプリケーションコードに コードのアップロード を選択し アップロード ボタンをクリックします。

5.jpg

先ほど作成したZIPファイルを選択し アップロード します。

6.jpg

作成が始まります。

7.jpg

5分ほどで作成完了します。 ※現在アプリは削除済みです

8.jpg

ただ、このままではアクセスしても403エラーになるので、最後にドキュメントルートの設定を行います。

9.jpg

10.jpg

設定後、自動的に環境に反映されるのを待って ドメイン/api/XXXXXXXXX にアクセスすると、、、

11.jpg

表示されました😃

今回はここまでですが、HTTPS化したいですね。

続きを読む

phpでlocalstackのs3にファイルをアップロード

AWS周りのものをローカルで開発する場合 localstack を使うと便利だというのを聞いたので試してみました。 github.com localstackは、GUIはあまり提供されていない用で、主にawscliコマンドを使います。 s3にファイルをアップロードしたい場合は、 –endpoint-url=http:… 続きを読む

Beanstalk運用の日常風景

ハンズラボ Advent Calendar 2017 11日目の記事です。

Elastic Beanstalkの運用をそれなりに続けてきたので、溜め込んだTIPS+失敗事例を放出します。
プラットフォームはPHPです。

Daily Buildしましょう

「いやいやうちはデイリーどころか1日複数回buildしてdeployですよ」という方もいらっしゃるでしょうが、すべてのアプリケーションに対して毎日、というわけではないのでは?
「同じソースコードをeb deployして昨日は通ったのに今日は落ちる」ということがあります。
AWSは日夜プロダクトを改善していて、ユーザとして恩恵に預かっているわけですが、ときに牙をむくことがあります。
ということで、平日の出勤時間帯にdeployスクリプトをスケジュール実行しておいて、deploy成功していると安心して出勤できます。

  • 2016年9月、eb-activity.logにて、ascii以外の文字列が入っているエラーが出てdeploy失敗しました。
    (コメントに入ってもNG)
  • 本番以外の環境で、immutableかrolling with additional batchでのdeploy検証できていると、安心です。この二つはEC2を新規に起動するので、後述のpreinit hookのスクリプトから順に動くためです。
    • と言いつつ、.ebextensionsでシンボリックリンクを貼る、みたいなことをしているときに、already existsで落ちるケースも。本番deployして初めて失敗する、みたいなケースは辛い・・・。

ライブラリのバージョンを固定しましょう

常に最新版のライブラリを適用するのがセキュリティ的には望ましいですが、なかなかそうはいかないのが悩ましいところです。。。
検証環境では最新のライブラリ、本番環境は検証済みライブラリ、とかで分けて管理できればいいのですが・・・。なかなか腰が重いです。

  • とあるpeclライブラリをバージョン指定せずにpecl installしていたところ、最新版がPHP7のみのサポートになってdeployに失敗しました。。。
  • プラットフォームのバージョンは検証環境のみ「管理された更新」を適用しています。これも便利。動作に問題がなければ本番環境へ。

eb-activity.logを読みましょう

Beanstalkが管理しているEC2が起動するときや、Application Versionをdeployするときにeb-activity.logが更新されます。
実際に動いてるのは/opt/elasticbeanstalk/hooks配下のスクリプトです。ここに、.ebextensionsで書いた設定やらシェルスクリプトやらも入ってきます。

$ pwd
/opt/elasticbeanstalk/hooks
$ ls
appdeploy  configdeploy  postinit  preinit  restartappserver
  • deployがtimeoutする原因について調べていたところ、composer updateは–no-devがついて実行されていたのに、composer installはオプション無しで実行されていました。.ebextensionsで記述していないAWS製のdeployスクリプトの中で、EC2新規起動時はcomposer installを実行する作りになっていました。
  • 試行錯誤の結果、下記のようにcomposer_optionsで–no-dev指定することにしました。合わせて、hirakさんのprestissimoを使ってcomposer install/updateの並列実行を実現しています。
    • EC2の起動が遅い問題、C5/M5インスタンスが東京リージョンに来てパッと解決してほしい・・・。
composer.config
commands:
  01_update_composer:
    command: export COMPOSER_HOME=/root && /usr/bin/composer.phar self-update 1.5.2 && /usr/bin/composer.phar global require hirak/prestissimo

option_settings:
  - namespace: aws:elasticbeanstalk:application:environment
    option_name: COMPOSER_HOME
    value: /root
  - namespace: aws:elasticbeanstalk:container:php:phpini
    option_name: composer_options
    value: --no-dev

Time Based Scaling しましょう

Elastic BeanstalkはAuto Scalingもよしなにやってくれますが、スパイクアクセスには弱いです。
日常的にiOS/Androidアプリへモバイルプッシュなどを行っていると、プッシュのタイミングでスパイクアクセスが発生します。
プッシュを登録する担当者と相談して、プッシュ送信する時間帯を制限し、その時間帯はスケールアウトしておくことで対策しています。
BeanstalkだけでなくDynamoDBもTime Based Scalingに対応しましたね!(こちらはまだAWS CLIのみで設定可能・・・)

  • BeanstalkのメトリクスだけではELBへの負荷がわからない場合があります。その場合はELBのメトリクスを参照しましょう。AWS CLIでcloudwatchのメトリクスとるときも、NamespaceはELBのものを使います。
  • CPU負荷、デフォルトの平均じゃなくて最大でみたほうがいいことがあります。CPU使用率の平均40%だから平気平気、と思ってたらELBが503返してて、CPU使用率を最大で見たら90%超えててEC2が死んでた、とかあるので・・・。
  • サポートの方に「503頻発してELB足りないぽいから日常的にPreWarmingお願いします」と依頼したら、「SpillOverCount(過剰数)のカウントが上がっていますのでEC2増やしてください」と返答ありました。AWSサポートの皆様、スキル高くて頼りになります。
  • NLB化も検討したいところ。

まとめ

Elastic Beanstalk、AWSにおまかせできる部分が多くて楽ができますが、特有の癖みたいなものがあるので気をつけて使うと安全安心です。

ハンズラボ Advent Calendar 2017 明日12日目は@sr-mtmtです!

続きを読む

中途入社のAWSエンジニアが、稼働中サービスの運用状況をキャッチアップするために意識すること

Classiアドベントカレンダー11日目です。
今回は、AWSエンジニアが稼働中のAWSの管理アカウントを渡されて、ビクビクしながらキャッチアップを行っていったときのメモになります。

1.TL;DR

AWSアカウントのログイン前に準備できることもあるし、AWSアカウントにログインしてわかることもあるし、サーバーにログインしてわかることもある。それぞれのレイヤーでどういったことを確認するかを意識しながらキャッチアップを進めていきましょう。

2.AWSアカウントログイン前の事前準備

pre_aws.png

サービスが稼働しているのであれば、AWSアカウントにログインせずとも、たくさんの情報をキャッチアップすることができます。1日目から何らかの大きなアウトプットを出さないと解雇するような会社は、(おそらく)存在しない筈です。まずは落ち着きましょう^^;

2-1.ドキュメント読み込み

サービスのインフラにAWSが使われることが多くなったからといって、入社前に経験したAWS運用フローがそのまま活かせる訳ではありません。まずは、前任者や運用中のドキュメント管理ツールの中から、今までどのような運用を行っていたかを確認します。
ドキュメントを見たときに意識する観点としては、

  • フロー型:時間による鮮度の劣化があるドキュメント
  • ストック型:システム仕様など、メンテナンスが求められるドキュメント

どちらの情報であるかを意識して読むことが重要です。
フロー型の情報は、障害などで一時的な対応用にメモっていることもあり、運用の中で解決済みのことがあります。そのため、ストック型のドキュメントを中心に見ることが素早いキャッチアップになると思います。
とはいえ、ドキュメントの全てがメンテナンスされている会社というのは稀だと思いますので、各種ドキュメントを見ながら、仮説程度に自分なりのシステム構成図などを書いてみましょう。
要件定義書や各種構成図の変更履歴、課題管理表、リスクコントロール表といったドキュメント類があるのであれば、目を通しておきましょう。

2-2.運用フローを観察する

サービス側のドキュメントについては、まだ文書化されてることが多いですが、運用系ツールに関しては、ドキュメント化されていないことがあります。今の開発スタイルであれば、何らかのチャットツール(Slack,ChatWork,HipChat)上で、

  • デプロイ
  • 各種の通知
  • 運用Bot

の運用といったことが行われていると思います。また、チャットだけでなく、メールでの運用フローも存在しているかもしれません。
こうした運用系ツールの存在は、今後自分がリファクタするときに、「必須要件ではないが、重宝している」ということで、「リファクタ後にも、あの機能を実装して欲しい」といった声が社内から上がると思います。
そのため、このような運用フローがどこで実装されているかを見極めることが重要になってきます。

2-3.インフラ部分のコード読み

「俺はフルスタックエンジニアだ!」という強い意思がある方は、この時点で稼働中のアプリ側のコードまで読み込んでいただければよいですが、まずは入社前に期待されたであろう、インフラまわりのコード化部分を把握しておきましょう。どのみち、いずれはメンテナンスを任されたり、質問されることが増えてきますので、自分のメンテナンスする部分を優先的に確認しておきましょう。
実サーバーの運用はAWSに任せているので、ここで意識しておくことは、

  • Infrastructure Orchestration Tools:Terraform, CloudFormationなど
  • Server Configuration Tools:Chef,Ansible,Itamaeなど

あたりのコードがgithubなどに保存されているからといって、メンテナンスされていない可能性もあります。
コードの設計方針などを確認するのは当然必要なのですが、コードの変更履歴が年単位で放置されていないかどうかも見ておきましょう。特に、AWS関連のコードについては、担当する人がアプリ側よりも少ないので、構築当初のコードのままなのか、運用されているコードなのかはPRなどで確認しておいた方がよいです。

3.AWSのアカウント内を調査する

aws_kansatsu.png

実際にAWSアカウントにログインしたり、APIで各種設定を確認していきます。Web系サービスであれば、TCP/IPモデルやC/Sモデルを意識しながら、下層レイヤー回りから調査していき、ネットワークがどうせ設定されているかを確認していきます。
おそらく、ここで多くの疑問(場合によっては、絶望)が生まれる段階です。「あれ?ドキュメントにこう記述されているけど、設定上は違うような…」という沼にハマることがあるでしょう。負けないでください、一人で抱え込まずに闇を共有できる仲間を見つけましょう。

3-1.外部システム連携の確認

関連するAWSサービス

VPC関連のサービスを中心に、自AWSアカウント以外の連携がないかの確認を行います。

関連しやすいAWSサービス例)

  • DirectConnect
  • NAT Gateway
  • Peering Connection
  • Customer Gateways
  • Virtual Private Gateways
  • VPN Connections
  • NetWorkACL
  • SecurityGroup
  • EIP

などに、何らかのインスタンスが稼働していて、productionやhonbanなどの文言がついたものがあれば、それはドキュメント上には存在しないが、サービス上何らかの理由で稼働しているものである可能性があります。
自社のサービスがAWSアカウント内だけで完結しているのであればよいのですが、誤ってここのインスタンスなどを削除すると、場合によってはシステム復旧できないぐらいの痛手になるので、慎重に確認していきましょう。
特に、SecurityGroupは、最近でこそInboundルールにDescriptionをつけられるようになりましたが、数年運用されているシステムには、何で利用しているIPアドレスなのかがわからないことがあるので、設定確認中に不明なIPアドレスを見つけたら社内で有識者に聞いてみましょう。

3-2.システム導線の確認

関連するAWSサービス

インスタンス障害があるとユーザー影響がありそうな、システム導線を追っていきます。

関連しやすいAWSサービス例)

  • ELB(CLB,ALB,NLB)
  • CloudFront
  • EC2
  • ElasticCache(redis,memcached)
  • RDS(Aurora,MySQL,PostgreSQL,SQLServer)
  • ElasticSearch
  • DynamoDB
  • S3

各種のインスタンスサイズが適切かを確認するのはもちろんですが、DB関連についてはバックアップ関連の設定がちゃんと行われているかどうかも確認しておきましょう。バックアップウィンドウの世代数やメンテナンスウィンドウの時間が営業時間内になっているとかは、結構ありがちな設定漏れケースになります。パラメータストアの設定については、本番で稼働している設定が正義なので、設計と違う場合は、社内で経緯を追ってみましょう。

3-3.運用導線の確認

関連するAWSサービス

直接のユーザー影響はないものの、バッチ系およびログインやログ連携など、システム運用で必要な運用導線を追っていきます。

関連しやすいAWSサービス例)

  • EC2
  • Lambda
  • ElasticSearch(& kibana)
  • IAM
  • CloudTrail
  • AWS Config
  • CloudWatch Logs
  • S3
  • Glacier

24224というポート開放を見れば、そのシステムはfluentd関連のフローがあるのはほぼ確定なので、ログの発生から可視化ツールおよびバックアップのフローまで追っていきましょう。また、バッチ系のEC2に関しては、最近のAWSだと、FargateやECS、Lambdaなどで定期バッチを行うことも可能なので、単一障害点をなくすことができないか、今後の計画のために、バッチ系が整理されているドキュメントなどを探してみましょう。

4.サーバー内の設定を確認する

server_chosa.png

最近だと、Server Configuration Toolsが大分普及していたり、コンテナ系の運用が発達してきているので、このあたりのキャッチアップ期間が少なくなるのかなと思います。とはいえ、SSH接続を頻繁に行うサーバーや起動時間が長いサーバーだと、コードの設定と異なる部分が出てきていることがあるかもしれません。
OSの設定やミドルウェアのバージョンなど、SSH接続すると確認した方がよいところは多々ありますが、Server Configuration Toolsの設定と異なっていたり、運用中のアラート設定などで差異がでやすそうな部分を以下に記載します。

4-1.各種メトリクス確認

メモリやプロセスの状況は、通常CloudWatchだけではわからないので、MackerelやZABBIXなどの監視ツールエージェントを入れているのであれば、各サーバーのメトリクスを確認しておきましょう。

4-2.稼働プロセスの確認

pstreeなどで、稼働しているプロセスを確認します。SSH接続が禁止されているのであれば、AWSのSSMエージェントなりで確認できないかを検討してみましょう。設計上のソフトウェアスタックに存在しないプロセスが常駐している場合は、何のエージェントが動いているかを追っておきましょう。

4-3.不要なファイルが出力されていないかの確認

ログレベルがデバッグのままだったり、ログファイルのローテートがなされていない場合があり、アラートは上がっていないけど、サーバー内のリソースを侵食しているときがあります。また、生成されるログファイルが小さすぎると、ディスクに余裕がありそうに見えても、inodeが先に枯渇するときもあります。lsofdf -iなどを可視化するなどして、サーバー内のディスク状況を確認しておきましょう。

4-4.同期処理と非同期処理のプロセス確認

同期処理のプロセスは意識しやすいので、監視対象に入っている可能性が高いです。ただ、非同期系プロセス(Rubyだとsidekiq,Pythonだとcelery,PHPだとphp-resqueなど)が監視対象に入っていないこともあるので、どのサーバーで非同期処理が行われているかを把握しておきましょう。

5.まとめ

AWSや他のパブリッククラウドが全盛になった今でも、3層アーキテクチャのシステム構成やOSI7階層などのレイヤーを意識しながらキャッチアップを行うと、システムを俯瞰しながらキャッチアップを進めることができるのではないかなと思います。とはいえ、前任者がコード化しきれなかった部分もある筈なので、そこは社内で過去経緯を知っている人に笑顔で質問をしてみましょう。技術が発達しても、人に蓄積されるノウハウはまだまだ多いので…
AWSエンジニアが転職する際などのご参考になれば。

続きを読む

AWS SDK for JavaScript with Angular で Upload to S3.

欠員が出たということで、穴埋めさせていただきます。

概要

本記事は、AngularAWS SDK for JavaScriptを利用して、S3にファイルをアップロードするという内容です。
Angular メインですので、AWSサービスの使い方や設定については割愛いたします。ご了承ください。

環境

$ uname -a
Linux ip-10-4-0-188 4.9.62-21.56.amzn1.x86_64 #1 SMP Thu Nov 16 05:37:08 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
$ ng -v

    _                      _                 ____ _     ___
   /    _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
  / △  | '_  / _` | | | | |/ _` | '__|   | |   | |    | |
 / ___ | | | | (_| | |_| | | (_| | |      | |___| |___ | |
/_/   __| |_|__, |__,_|_|__,_|_|       ____|_____|___|
               |___/

Angular CLI: 1.5.5
Node: 8.9.1
OS: linux x64
Angular: 5.0.0
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, router

@angular/cli: 1.5.5
@angular-devkit/build-optimizer: 0.0.35
@angular-devkit/core: 0.0.22
@angular-devkit/schematics: 0.0.41
@ngtools/json-schema: 1.1.0
@ngtools/webpack: 1.8.5
@schematics/angular: 0.1.10
@schematics/schematics: 0.0.10
typescript: 2.4.2
webpack: 3.8.1
package.json
{
  "name": "qiita",
  "version": "0.0.0",
  "license": "MIT",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^5.0.0",
    "@angular/common": "^5.0.0",
    "@angular/compiler": "^5.0.0",
    "@angular/core": "^5.0.0",
    "@angular/forms": "^5.0.0",
    "@angular/http": "^5.0.0",
    "@angular/platform-browser": "^5.0.0",
    "@angular/platform-browser-dynamic": "^5.0.0",
    "@angular/router": "^5.0.0",
    "core-js": "^2.4.1",
    "rxjs": "^5.5.2",
    "zone.js": "^0.8.14"
  },
  "devDependencies": {
    "@angular/cli": "1.5.5",
    "@angular/compiler-cli": "^5.0.0",
    "@angular/language-service": "^5.0.0",
    "@types/jasmine": "~2.5.53",
    "@types/jasminewd2": "~2.0.2",
    "@types/node": "~6.0.60",
    "codelyzer": "^4.0.1",
    "jasmine-core": "~2.6.2",
    "jasmine-spec-reporter": "~4.1.0",
    "karma": "~1.7.0",
    "karma-chrome-launcher": "~2.1.1",
    "karma-cli": "~1.0.1",
    "karma-coverage-istanbul-reporter": "^1.2.1",
    "karma-jasmine": "~1.1.0",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.1.2",
    "ts-node": "~3.2.0",
    "tslint": "~5.7.0",
    "typescript": "~2.4.2"
  }
}

手順

1) AWS SDK for JavaScriptをインストール

$ npm i --save-prod aws-sdk

2) src/app/tsconfig.app.json を編集

tsconfig.app.json
{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/app",
    "baseUrl": "./",
    "module": "es2015",
-    "types": []
+    "types": ["node"]
  },
  "exclude": [
    "test.ts",
    "**/*.spec.ts"
  ]
}

参照: Usage_with_TypeScript

3) S3アップロード用コンポネントを作成

$ ng g component s3-upload
  create src/app/s3-upload/s3-upload.component.css (0 bytes)
  create src/app/s3-upload/s3-upload.component.html (28 bytes)
  create src/app/s3-upload/s3-upload.component.spec.ts (643 bytes)
  create src/app/s3-upload/s3-upload.component.ts (280 bytes)
  update src/app/app.module.ts (408 bytes)

4) 各種ファイルを編集

src/app/app.component.html

+ <app-s3-upload></app-s3-upload>

src/app/app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';


import { AppComponent } from './app.component';
import { S3UploadComponent } from './s3-upload/s3-upload.component';
import { S3Service } from './s3-upload/s3.service';

@NgModule({
  declarations: [
    AppComponent,
    S3UploadComponent,
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
  ],
  providers: [
    S3Service,
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

src/app/s3-upload/s3-upload.html

<div class="form">
  <div class="form-group">
    <label class="col-xs-2">select file</label>
    <div class="col-xs-10">
      <input type="file" (change)="upload($event)">
    </div>
  </div>
</div>
<div class="debug_print">
  <p>httpUploadProgress {{ httpUploadProgress | json }}</p>
</div>

src/app/s3-upload/s3-upload.component.ts

import { Component, OnInit } from '@angular/core';
import { S3Service } from './s3.service';
import * as AWS from 'aws-sdk';

@Component({
  selector: 'app-s3-upload',
  templateUrl: './s3-upload.component.html',
  styleUrls: ['./s3-upload.component.css']
})
export class S3UploadComponent implements OnInit
{
  public httpUploadProgress: {[name: string]: any} = {
    ratio : 0,
    style : {
      width: '0',
    }
  };


  /**
   * @desc constructor
   */
  constructor(private s3Service: S3Service)
  {
    this.s3Service.initialize()
      .subscribe((res: boolean) => {
        if (! res) {
          console.log('S3 cognito init error');
        }
      })
  }


  /**
   * @desc Angular LifeCycle
   */
  ngOnInit()
  {
    this.s3Service.progress
      .subscribe((res: AWS.S3.ManagedUpload.Progress) => {
        this.httpUploadProgress.ratio = res.loaded * 100 / res.total;
        this.httpUploadProgress.style.width = this.httpUploadProgress.ratio + '%';
      });
  }


  /**
   * @desc file upload
   */
  public upload(event: Event): void
  {
    this.httpUploadProgress.ratio = 0;
    this.httpUploadProgress.style.width = '0';
    this.s3Service.onManagedUpload((<HTMLInputElement>event.target).files[0]);
  }
}

src/app/s3-upload/s3.service.ts

import { Injectable, EventEmitter } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import * as AWS from 'aws-sdk';
import { AWS_ENV } from '../../environments/environment';

@Injectable()
export class S3Service
{
  private s3: AWS.S3;
  public progress: EventEmitter<AWS.S3.ManagedUpload.Progress> = new EventEmitter<AWS.S3.ManagedUpload.Progress>();


  constructor(private http: HttpClient) { }


  /**
   * @desc set CognitoIdentityId
   * 
   * @return string IdentityId: ex) ap-northeast-1:01234567-9abc-df01-2345-6789abcd
   */
  public initialize(): Observable<boolean>
  {
    return this.http.get('/assets/cognito.php')
      .map((res: any) => {
        // resに対する例外処理を追加する
        // ...

        // Amazon Cognito 認証情報プロバイダーを初期化します
        AWS.config.region = AWS_ENV.region;
        AWS.config.credentials = new AWS.CognitoIdentityCredentials({
          IdentityId: res.results[0].IdentityId,
        });
        this.s3 = new AWS.S3({
          apiVersion: AWS_ENV.s3.apiVersion,
          params: {Bucket: AWS_ENV.s3.Bucket},
        });
        return true;
      })

      .catch((err: HttpErrorResponse) => {
        console.error(err);
        return Observable.of(false);
      });
  }

  /**
   * @desc AWS.S3
   */
  public onManagedUpload(file: File): Promise<AWS.S3.ManagedUpload.SendData>
  {
    let params: AWS.S3.Types.PutObjectRequest = {
      Bucket: AWS_ENV.s3.Bucket,
      Key: file.name,
      Body: file,
    };
    let options: AWS.S3.ManagedUpload.ManagedUploadOptions = {
      params: params,
      partSize: 64*1024*1024,
    };
    let handler: AWS.S3.ManagedUpload = new AWS.S3.ManagedUpload(options);
    handler.on('httpUploadProgress', this._httpUploadProgress.bind(this));
    handler.send(this._send.bind(this));
    return handler.promise();
  }

  /**
   * @desc progress
   */
  private _httpUploadProgress(progress: AWS.S3.ManagedUpload.Progress): void
  {
    this.progress.emit(progress);
  }

  /**
   * @desc send
   */
  private _send(err: AWS.AWSError, data: AWS.S3.ManagedUpload.SendData): void
  {
    console.log('send()', err, data);
  }
}

src/environments/environment.ts

// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `.angular-cli.json`.

export const environment = {
  production: false
};

export const AWS_ENV = {
  region: 'YOUR_REGION',
  s3: {
    apiVersion: 'YOUR_VERSION',
    Bucket: 'YOUR_BACKET',
  },
};

5) ビルド&実行&確認

test.png

$ aws s3 ls s3://YOUR_BACKET/
2017-12-10 08:13:54   10485760 10MB.bin

解説

AWS SDKを使ってファイルをアップロードするには、PutObject()を使うのが手っ取り早いですが
JSからファイルをアップロードするときには、UI/UXの観点からプログレスを表示してあげるのがよいので
それに対応したメソッドである、ManagedUpload()を利用しました。

5.0.0 では、zoneを意識することなく、プログレスがきちんとレンダリングされましたので
プログレスバーの実装は容易に行なえます。

以上、穴埋め記事でした。

7日目は、@segawm さんです。

続きを読む

大手SNSサイト サーバ管理・保守・運用(AWS

【PHP】 大手SNSサイト サーバ管理・保守・運用(AWS)に関する案件情報 【案件ナビ】 |フリーランス、フリーエンジニアの方への業務委託の常駐の仕事情報を紹介しています。高額なインフラ、開発、ネットワークのお仕事も多数あります! 続きを読む

カテゴリー 未分類 | タグ

AWS Cloud9 のPHP/MySQL を 7.1/5.7 にしてみる

PHP Advent Calendar 2017 の9日目です。

Docker を絡めた内容にすると予告してましたが、がらっと変更してしまいました・・・
新しく選んだテーマは、「AWS Cloud9」です。

AWS Cloud9 とは

「AWS Cloud9」とは、今年の11月末から12月頭にかけて開催された「AWS re:Invent 2017」で発表された新しいサービスです。

Cloud9 自体は以前からサービスされていたもので、2016年7月に Amazon に買収されて、とうとう AWS に統合されたという流れです。

Cloud9 は、ブラウザ上で動作する IDE で、複数の開発言語に対応し、共同作業が可能という特徴があるサービスです。それが、AWSに統合されたということで、IAMベースのユーザ管理や、ネットワークの制御等もできるので、より細かい管理ができるという形になります。

セットアップしてみる

とりあえずは、AWSのアカウントが必要なので、もし持っていない場合は作成する必要があります。アカウントの作成が終われば、「AWS Cloud9」の環境構築となります。

「AWS Cloud9」は現在以下のリージョンのみで提供されています。

  • EU(アイルランド)
  • アジアパシフィック(シンガポール)
  • 米国東部(バージニア北部)
  • 米国東部(オハイオ)
  • 米国西部(オレゴン)

残念ながら、東京リージョンには来ていないので、今回は「米国東部(バージニア北部)」(us-east-1)で試してみます。

welcome 画面

Welcome to AWS Cloud9.png

まずは、「AWS Cloud9」のサービストップの「Create environment」をクリックします。

Step1 Name environment

step1.png

Step1として、環境名(Name)と説明文(Description)を入力して、Step2へ行きます。

Step2 Configure settings

step2.png

Step2では、 作業するための環境設定を行います。

Environment Type としては、以下の2つを選ぶことになります。

  • 新しい EC2 インスタンスをこの環境用に起動する
  • 既存のサーバーに SSH 接続して作業をする

今回は、新しいインスタンスを立てますが、既存サーバーへの接続での共同編集というのも面白そうですね。

Environment Type で新しいインスタンスを使うことを選択した場合は、EC2 のインスタンスタイプを選択します。

また、コストを抑えるための設定があります。デフォルトでは、IDEを閉じてから30分後にインスタンスが停止され、再度IDEを開くとインスタンスが再起動するというものです。

それ以外の設定として、使用する IAM role と ネットワークの設定が行なえます。特に設定しなければ、Cloud9しか制御できない IAM role で、新しい VPC ネットワーク が設定されます。

ちなみに、既存のサーバーに SSH 接続する方を選択すると以下の選択肢になります。

step2-ssh.png

Step3 Review

step3.png

確認画面です。内容に問題がなければ、「Create environment」ボタンを押して、環境作成を開始します。

この画面では、以下のような注意が表示されます。

step3-info.png

「Create environment」ボタンを押すと、環境作成中画面ということで次のような画面になります。環境は、だいたい 2 〜 3 分くらいで作成されました。

build-cloud9.png

「AWS Cloud9」 IDE 画面

cloud9.png

IDE の画面としては、オーソドックスな画面で、左側にソースツリー、右側の上部のメインとなる部分にソース等の表示がありますが、右側の下部がターミナルになっているというのが面白いですね。

ここで、起動したインスタンスの情報を見てみるとこんな感じでした。

uname.png

さらに、起動したインスタンスの PHP と MySQL のバージョンをみてみると・・・

default_php_mysql_version.png

PHP はともかく、MySQLが 5.5 というのがちょっとつらい。

というわけで、アップグレードするためのシェルを準備しました。以下のものをターミナルから実行するとPHPとMySQLがバージョンアップできます。

sh -c "$(curl -fsSL https://gist.githubusercontent.com/kunit/c2cc88d18d4ce9ad972bab2bdc3b6f3f/raw/27f538fe5d21d024f72a6dfbee7563dc7247ad46/aws-cloud9-php71-mysql57.sh)"

実行する sh の内容を貼っておくと以下のような感じです。

(2017/12/10 10:12 追記) 最初書いていたスクリプトは、わざわざ PHP 5.6を削除してましたが、 alternatives の機能を使えば、PHPの切り替えができたので、7.1をインストールして、 alternatives で切り替えるものにしました

https://gist.github.com/kunit/c2cc88d18d4ce9ad972bab2bdc3b6f3f

#!/bin/sh

sudo service mysqld stop
sudo yum -y erase mysql-config mysql55-server mysql55-libs mysql55
sudo yum -y install mysql57-server mysql57
sudo service mysqld start

sudo yum -y install php71 php71-cli php71-common php71-devel php71-mysqlnd php71-pdo php71-xml php71-gd php71-intl php71-mbstring php71-mcrypt php71-opcache php71-pecl-apcu php71-pecl-imagick php71-pecl-memcached php71-pecl-redis php71-pecl-xdebug
sudo alternatives --set php /usr/bin/php-7.1 
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/bin/composer

この sh を実行すると、以下のように、PHP 7.1.11 および MySQL 5.7.20 の環境になります。

upgrade_php_mysql_version.png

では、実際のコードを編集および動作させてみよう

環境を作っただけで満足してしまいそうですが、実際のコードを動かしてみたいと思います。

サンプルとして使用させていただいたのは、CakePHP Advent Calendar 2017 2日目の @tenkoma さんの記事、CakePHP 3 のチュートリアルにユニットテストを追加する (1) のコードです。

AWS Cloud9 のターミナルから、以下のコマンドを実行し、ソースコードの取得及び compose install を行います。(us-east-1 で起動しているので、composer install もさくっと終わります)

git clone https://github.com/tenkoma/cakephp_cms.git
cd cakephp_cms
composer install

そして、サンプルを動かすために、MySQLにテスト用のデータベースを作らないと行けないので、以下のコマンドを実行します。

mysql -u root -e 'CREATE DATABASE test_cake_cms CHARACTER SET utf8mb4;GRANT ALL  ON test_cake_cms.* TO cakephp@localhost IDENTIFIED BY "AngelF00dC4k3~";FLUSH PRIVILEGES;'

あとは、Cloud9 の IDE 上から、 cakephp_cms/config/app.php のテストデータベースの設定部分を編集して、ターミナル上から phpunit を実行すると、次のようになります。

edit_app_and_phpunit.png

ターミナル部分を拡大するとこんな感じです。

phpunit.png

キーバインド

IDEの設定項目がありますが、最初に変更したのがこちら。

keybinding.png

プルダウンの種類的には、以下の4つでした。

  • default
  • Vim
  • Emacs
  • Sublime

ダッシュボード

IDEを開いたタブを閉じても、ダッシュボードに行けば再度 IDE を開き直せます。

dashboard.png

何もせずに、環境構築時に設定した時間が経過したらインスタンスは自動的に停止され、次にIDEを開いたときに再起動されます。

AWS Cloud9 の料金

AWS Cloud9 自体は無料で、使用する EC2 インスタンスに対する課金のみとなります。そういった意味で、IDEを閉じたら、30分後にEC2を自動停止してくれるというのは結構ありがたいですね。

最後に

AWS Cloud9 ですが、ちょっとした共同作業の環境として使えるだけではなく、使いようによってはおもしろい使い方ができるかもと思っています。

普段 PhpStorm という超強力な IDE を使っているので、それとくらべて IDE としての使い勝手はどうなんだということも今後いろいろと試してみたいなと思ったりもしています。

AWS アカウントさえあれば、本当に簡単に起動できるので、みなさんも試してみるのはいかがでしょうか?

明日の担当は、@hanhan1978 さんです。

続きを読む

AWS Cloud9でLambdaアプリの開発をしたり共同編集をしてみた

この記事はAmazon Web Services Advent Calendar 2017の9日目の記事になります。

結構気になっていたAWS re:Invent 2017での発表があります。

AWS Cloud9

です。実際どの程度便利なのか、使ってみました。

環境作成

利用開始をしようとすると、環境作成のページに飛ばされました。まずはAWS Cloud9が動く環境を準備する必要があるんですね。(そういえばオリジナルのCloud9もそうだったような。。。)

スクリーンショット 2017-12-05 19.31.16.png

とりあえずテスト環境を作成します。
テスト環境なので、設定はデフォルトで。30分以上放置してたら作成したインスタンスを止めてくれるとか、気が利いてますね!

スクリーンショット 2017-12-05 19.48.41.png

環境作成の直前に推奨の設定やらが案内されましたが、とりあえず無視します。

スクリーンショット 2017-12-05 19.52.29.png

環境が作成されるまでしばし待ち。。。(しかし画面かっこいいな)

スクリーンショット 2017-12-05 19.53.49.png

コーディングしてみる

環境が整えばいよいよコーディングです。が、色々と便利そうなビューになってます。
タブでファイルが分割できたり、

スクリーンショット 2017-12-05 20.29.42.png

ターミナルがあったり。これもうVisual Studio Codeと変わらないな。

スクリーンショット 2017-12-05 20.30.45.png

ちなみに実態はEC2インスタンスなので、上記のようにコマンドでライブラリをインストールすることができます。実際にインストールすると、左側のフォルダツリーにリアルタイムに構成が反映されます。

スクリーンショット 2017-12-05 20.30.58.png

で、コーディングはエディタのキャプチャの通り書いてみました。GoogleにRequestを飛ばす一般的な処理です。

実行してみる

もちろんこのままだとファイルパスがマッチせずに実行時にインポートエラーが発生するので

スクリーンショット 2017-12-05 20.30.31.png

こんな感じでライブラリをインストールするようにして、

$ mkdir lib
$ pip install requests -t ./testrequests/testrequests/lib/

ソースと同じディレクトリにライブラリをインストールするようにします。

スクリーンショット 2017-12-06 7.30.06.png

コードも少し修正しました。

import sys
import os

sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'lib'))

import requests

def lambda_handler(event, context):
    res = requests.get("http://www.google.co.jp/")
    return res.status_code

これでうまく動きそうです。

もう一回実行してみる

スクリーンショット 2017-12-06 7.30.36.png

きちんと結果が得られました。無事動いたようです。
ただ、1点気をつけないといけないのは、あくまでこれはEC2インスタンス上のエディタで実行した、というだけなので、実際のLambdaには何も保存されていません。

ちなみに今回はPythonを使ったのでデバッグはサポートされていませんが、Node.jsやPHP、Goであればデバッグ実行もできるようです。これは便利。

スクリーンショット 2017-12-07 1.05.31.png

最初にファンクションを作成時、Lambdaは登録されるのですが、デプロイするまでは中身は初期化されたままになっています。(当然ではあるのですが、忘れやすいかもこれ)

スクリーンショット 2017-12-07 1.13.48.png

Lambdaでファンクションを選択しても、先ほど書いたコードは存在していません。デプロイをするとLambdaに実際に反映されるようになります。

デプロイをしてLambdaに更新を反映する

Cloud9上からLambdaへのデプロイを行います。やり方はとても簡単で、ファンクションリストから該当のファンクションを右クリックして「Deploy」を選択するだけ。正直Serverless Frameworkなどを使うよりずっと簡単です。

スクリーンショット 2017-12-07 1.16.42.png

これだけの操作でLambdaが更新されます。

共同編集をしてみる

他にアカウントを作成して、共同編集を試してみました。テスト用に「test」というアカウントを作成します。画面右上の「Share」より共有設定を開きます。

スクリーンショット 2017-12-07 1.22.19_dec.png

するとこんな感じの共有用URLが表示されますので、これを別アカウントのブラウザで開いてみます。が、共有の設定をしないともちろんアクセスできません。400で怒られます。

スクリーンショット 2017-12-07 1.23.02_dec.png

共有設定で自分以外に共有したいIAMユーザーのアカウントを追加すれば設定は完了です。

スクリーンショット 2017-12-07 1.23.21.png

testユーザーでアクセスすると、共有設定画面のユーザーのステータスがOfflineからOnlineに変更になります。

スクリーンショット 2017-12-07 1.23.47.png

あとはお互いに編集しているポイントがリアルタイムに反映されていくので、とても便利ですね。キャプチャだけだとなんのことかわかりづらいですが、自アカウントで編集したものがリアルタイムでtestユーザーの画面にも反映されます。

スクリーンショット 2017-12-07 1.24.44.png

スクリーンショット 2017-12-07 1.25.00.png
※キャプチャ右上のアカウントの並びが異なるので、それぞれ異なるユーザーの画面だということは見てわかるかな(^^;。

実際にAWS Cloud9を使ってみての感想

思った以上にできることが多いので、かなり可能性を感じました。自分は今仕事の関係上ミャンマーにいるのですが、多少ネットが遅くてもリアルタイムにインターネットにアクセスできれば、開発していて不便だと感じることはありませんでした。実際に開発したパッケージをデプロイしようとした際には、ローカル10MBなどの重いファイルをアップロードするために何分も待たされる、というのもCloud9ならなさそうですし、ありがたい新サービスです。

続きを読む

AWSのインスタンスにLAMP環境を構築する際に使用したコマンドについて解説する

AWSにインスタンスを作成したあとに・・・

AWSにインスタンスを作成したあと、SSHのキーを使ってインスタンスに入るところから解説します。

使用するインスタンス

  • 無料枠のEC2
  • OSはAmazon Linux
  • セキュリティグループはSSH

インスタンスができたら

使用する端末がwinの場合はツールをインストールしてください。macの場合はターミナルを起動してください。
macのターミナルの場所:アプリケーション>ユーティリティ>ターミナル

1インスタンスに入る

①SSHのキーの設定

インスタンス作成の際にダウンロードしたキーを使用します。
chmod 600 ~/hoge/hoge.pem
⇨このキーの権限を設定するよ!
【入力内容】
:sunny:~/hoge/hoge.pem のところには
 ダウンロードしたキーのファイルパスを入力してください。

【コマンドの解説】
:cherry_blossom: chmod
チェンジモードchange modeの意味でアクセス権を変更するときに使用します。

:cherry_blossom: 600
3桁の数字はアクセス権を示します。

600:1桁目は所有者の権限です。
600:2桁目はグループの権限です。
600:3桁目はその他の権限です。

さらにそれぞれの数字に権限の意味があります。
6:読み込み権限と書き込み権限
0:権限なし

つまり600というのは、
所有者の権限には読み込みと書き込みの権限を与え、
グループの権限とその他の権限には権限を何も与えない
ということになります:astonished:

:cherry_blossom: キーのファイルパス
権限を与える対象のファイルを指定することになります。

【参考サイト】
chmodについて詳しく!
chmod? chown? よくわからんって人のための、ファイル権限系まとめ
権限の数字について詳しく!
【 chmod 】 ファイルやディレクトリのアクセス権を変更する
コマンド操作を楽ラクにしたい!
ブクマ必至!Linuxコマンド一覧表【全33種】 2.2 覚えておくと便利なショートカットキー

②SSHのキーを使用して入る

①で使用したキーをここでも使用します。
ssh ec2-user@hoge -i ~/hoge/hoge.pem
⇨このキーでインスタンスに入るよ!
【入力内容】
:sunny:ec2-user@hoge のhogeにはインスタンスのIPv4 パブリック IPを入力してください。
:sunny:~/hoge/hoge.pem のところには①同様、
 ダウンロードしたキーのファイルパスを入力してください。

【コマンドの解説】
:cherry_blossom: ssh
インスタンス作成時のセキュリティグループでタイプSSHを選択しました。
それです。

:cherry_blossom: ec2-user@hoge
アクセス先を指定する。

:cherry_blossom: -i
informationのiです。付加情報がある際にはこのあとに記述します。

:cherry_blossom: ~/hoge/hoge.pem
今回の付加情報です。
「このキーでインスタンスに入るよ!」の「このキー」というのが付加情報になります。

③質問されるので答える

②を実行すると以下の文章が表示されます。

Are you sure you want to continue connecting (yes/no)?

⇨接続することは同意ですか?

同意なので
yes
と入力してください。

④入れた!

以下のAAが表示されたらインスタンスに入れました!おめでとう:heart_eyes:

  __|  __|_  )
  _|  (     /   Amazon Linux AMI
 ___|___|___|

2環境を整える

①インスタンスを更新する

インスタンスを最新の状態にしたいので、アップロードするものがあればアップロードするようにします。
sudo yum update -y
⇨管理者権限でアップデートするよ!
これを実行するとズラズラ文章が流れていきます。

【コマンド解説】
:cherry_blossom: sudo
superuser do の略で、管理者権限で実行することを意味します。
これを入れ忘れると、データが保存されなかったり、
実行しても権限がないと言われてしまうので、入れ忘れに注意してください。
superuserはrootのことです。

:cherry_blossom: yum update
yumはパッケージを取得してそれをどうするかの指定です。
どうするかは今回はupdateなので更新します。
つまりupdateのところをinstallにすれば、パッケージのインストールができます。

:cherry_blossom: -y
何か質問されたらyesで答えるときに使用します。
毎回質問に対して返事するのが面倒なときに使うと便利です。

【参考サイト】
rootとは?
【完全初心者向け】Linuxのrootユーザとは?

②Apache,PHP,MySqlをインストールする

LAMP環境と言われるAMPの部分です。
ちなみにLは(Amazon) LinuxのLです。
sudo yum install -y httpd24 php70 mysql56-server php70-mysqlnd
⇨管理者権限でインストールするよ!
インストールするものは
・Apache
・PHP
・MySql
・PHPのMySql用ドライバー
だよ!

これを実行するとズラズラ文章が流れていきます。

Complete!

が表示すれば成功です。
【入力内容】
:sunny: 数字はバージョンを表しています。インストールするときによって
 使用するバージョンが異なるのでチェックしてください。

【コマンド解説】
:cherry_blossom: sudo yum install -y
詳細は前述済みです。
何をインストールするかの指定を-y以降に記述します。

:cherry_blossom: httpd24
Apache2.4をインストールします。
Apacheとはwebサーバーのことです。
webサーバーがないとPHPなどのプログラムが動かないので必要です。

:cherry_blossom: php70
今回の主役、PHPです。PHP7.0をインストールします。

:cherry_blossom: mysql56-server
今回使用するデータベースはMySqlです。MySql5.6のサーバーの方をインストールします。
サーバーの方と言うだけあって、クライアント(端末)の方もあります。
今回はインスタンス(サーバー)に入れたいので、サーバーの方のMySqlをインストールします。

:cherry_blossom: php70-mysqlnd
PHPでMySqlを使うためのドライバーをインストールします。
これがないとPHPでMySqlを使うことができないです。

サーバーを起動する

力尽きたので後日書きます。

続きを読む