AWS Cloud9に移行しました

Cloud9が終了するということでAWS Cloud9に移行しました。 とても親切な移行手順だったので特に困ることはありませんでした。

12月まで使えると思っていましたので、6月30日に使えなくなるのに驚きました。 f:id:unokun3:20190519134515p:plain

メールはちゃんと読まないといけませんね....

we plan to discontinue the ability to create new or to use existing workspaces on c9.io on June 30, 2019 and to discontinue all access on December 31, 2019. We would love it if you would join us on AWS Cloud9.

同時ログイン禁止(後勝ち)

実装

Spring Web Applicationで同時ログイン禁止(後勝ち)を実装するためには、WebSecurityConfigurerAdapterで以下の記述をする。

Spring Security 使い方メモ セッション管理 - Qiita

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests().antMatchers("/", "/home").permitAll().anyRequest().authenticated()
            .and().formLogin()
                .loginPage("/login").permitAll()
            .and()
                .logout().permitAll()
            .and()
                .sessionManagement().maximumSessions(1)
                .maxSessionsPreventsLogin(false)
                .expiredSessionStrategy(new MySessionInformationExpiredStrategy());
    }
}
public class MySessionInformationExpiredStrategy implements SessionInformationExpiredStrategy {

    @Override
    public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
        DefaultRedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
        redirectStrategy.sendRedirect(event.getRequest(), event.getResponse(), "/login");
    }
}

動作

  1. ブラウザAでログイン
  2. ブラウザBでログイン
  3. ブラウザAでログイン後ページを更新 ブラウザAはログイン画面に遷移する。

ただし、ブラウザのタブで同時ログインした場合は、同じセッションIDを使い回すので、この方法ではできない。

java – Spring Securityで複数のブラウザタブを管理できますか? - コードログ

また、UsernamePassword認証をカスタマイズしている場合、UsernamePassword認証のFilterの方が先に実施されるため、この方法(セッション管理)は期待通りの動きにならない。

UsernamePassword認証Filterより前に実行されるようにできれば良いのだが...。

以下はMySessionInformationExpiredStrategyが実行されている場合のスタックトレースf:id:unokun3:20190519090523p:plain

Headless-Chrome on AWS Lambda

以下の記事を参考にAWS Lambda上でHeadless-Chromeを動かしてみました。

注) Serverlessは事前にインストールしておく必要があります。

AWS Lambda上でのWebクローリング実行に少し近づいてきました。

ファイル構成

適当なディレクトリ以下に二つのディレクトリ(lambda、selenium-layer)を作成していきます。

mkdir crowler(任意)
cd crowler

$ tree -L 2
.
├── lambda
│   ├── handler.py
│   └── serverless.yml
├── selenium-layer
│   ├── chromedriver
│   ├── selenium
│   └── serverless.yml

selenium-layer

selenim(pythonモジュール)とchromedriver(chromedriver, headless-chrome)をLayerとして登録します。

参照した記事は、chromedriverディレクトリ以下の構成が少しわかりにくかったです。

chromedriver

$ cd selenium-layer
$ mkdir chromedriver
$ cd chromedriver

# headless-chromiumダウンロード
$ curl -SL https://github.com/adieuadieu/serverless-chrome/releases/download/v1.0.0-41/stable-headless-chromium-amazonlinux-2017-03.zip > headless-chromium.zip
$ unzip headless-chromium.zip
$ rm headless-chromium.zip

# chromedriverダウンロード
$ curl -SL https://chromedriver.storage.googleapis.com/2.37/chromedriver_linux64.zip > chromedriver.zip
$ unzip chromedriver.zip
$ rm chromedriver.zip

$ tree
.
├── chromedriver(実行モジュール)
└── headless-chromium(実行モジュール)

selemium

pythonモジュールを追加します。

$ cd selenium-layer
$ mkdir selenium
$ cd selenium
$ pip install -t selenium/python/lib/python3.6/site-packages selenium
$ tree -L 3
.
└── python
    └── lib
        └── python3.6

serverless.yml

chromedriverとseleniumをLayer定義します。

$ cat serverless.yml
service: selenium-layer

provider:
  name: aws
  runtime: python3.6
  stage: dev
  region: ap-northeast-1

layers:
  selenium:
    path: selenium
    description: selenium layer
    CompatibleRuntimes:
      - python3.6
  chromedriver:
    path: chromedriver
    description: chrome driver layer
    CompatibleRuntimes:
      - python3.6

resources:
  Outputs:
    SeleniumLayerExport:
      Value:
        Ref: SeleniumLambdaLayer
      Export:
        Name: SeleniumLambdaLayer
    ChromedriverLayerExport:
      Value:
        Ref: ChromedriverLambdaLayer
      Export:
        Name: ChromedriverLambdaLayer

deploy

deployします。awscliのインストールおよび設定は事前に済ませておく必要があります。

$ serverless deploy

AWSコンソールで登録内容を確認することができます。

lambda

登録したselenium-layerを使う関数をLambdaに登録します。

handler.py

Lambda登録したモジュールは/opt以下に配置されます。

$ cat handler.py
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

def hello(event, context):
    options = Options()
    options.binary_location = '/opt/headless-chromium'
    options.add_argument('--headless')
    options.add_argument('--no-sandbox')
    options.add_argument('--single-process')
    options.add_argument('--disable-dev-shm-usage')

    driver = webdriver.Chrome('/opt/chromedriver', chrome_options=options)

    driver.get('https://qiita.com/')
    body = f"Blog title is: {driver.title}"

    driver.close();
    driver.quit();

    response = {
        "statusCode": 200,
        "body": body
    }

    return response

serverless.yml

service: crawler-with-selenium

provider:
  name: aws
  runtime: python3.6
  stage: dev
  region: ap-northeast-1
  timeout: 900
  environment:
    SELENIUM_LAYER_SERVICE: selenium-layer

functions:
  hello:
    handler: handler.hello
    layers:
      - ${cf:${self:provider.environment.SELENIUM_LAYER_SERVICE}-${opt:stage, self:provider.stage}.SeleniumLayerExport}
      - ${cf:${self:provider.environment.SELENIUM_LAYER_SERVICE}-${opt:stage, self:provider.stage}.ChromedriverLayerExport}

deploy

$ serverless deploy

実行

$ seleverless invoke -f hello
{
    "statusCode": 200,
    "body": "Blog title is: Qiita"
}

実行した時に以下のエラーが発生しましたが、しばらく時間をおいたら正常に動作しました。deployには少し時間がかかるのかも。

  Serverless Error ---------------------------------------

  The role defined for the function cannot be assumed by Lambda.

Lambda Layers by Serverless

以下の記事を参考にLambda Layerを試してみました。

LambdaのLayerをServerless Frameworkで - Qiita

Lambda Layersとは

Layer化することによりより複雑な処理が実行できるということかな? AWS Lambda レイヤー - AWS Lambda

layer追加

serverlessのnodejs版(hello)にLayerを追加します。

Layerに追加する関数作成

$ cd my-project
$ tree
.
├── handler.js
├── my-layer
│   └── nodejs
│       └── node_modules
│           └── pow
│               └── index.js
├── serverless.yml

serverless.ymlを修正

cat serverless.yml
layers:
  mylayer:
    path: my-layer

deploy

$ serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service my-service.zip file to S3 (1.81 KB)...
Serverless: Uploading service mylayer.zip file to S3 (207 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
..................
Serverless: Stack update finished...
Service Information
service: my-service
stage: dev
region: ap-northeast-1
stack: my-service-dev
resources: 6
api keys:
  None
endpoints:
  None
functions:
  hello: my-service-dev-hello
layers:
  mylayer: arn:aws:lambda:ap-northeast-1:881710576594:layer:mylayer:1

deployされているか確認します。

$ aws lambda list-layers
{
    "Layers": [
        {
            "LayerName": "mylayer",
            "LayerArn": "arn:aws:lambda:ap-northeast-1:881710576594:layer:mylayer",
            "LatestMatchingVersion": {
                "LayerVersionArn": "arn:aws:lambda:ap-northeast-1:881710576594:layer:mylayer:1",
                "Version": 1,
                "CreatedDate": "2019-05-04T05:00:56.274+0000"
            }
        }
    ]
}

はじめてのServerless(AWS)

Serverless(AWS)を使ってみました。

AWS Lambda上にクローラーを設置するのがゴールです。

インストール

Serverless Getting Started Guide

$ npm install -g serverless

# shell再読込
$ exec -l $SHELL

# グローバルにインストールしたくない場合には--save-devオプションを付ける
# ただし、パスを通すのが面倒かも
$ npm install --save serverless

プロジェクト作成

Serverless Framework - AWS Lambda Guide - Quick Start

$ serverless create --template aws-nodejs --path my-service
$ cd my-service
$ ls
handler.js         serverless.yml

deploy

awscliのインストールおよびユーザー作成をしておく必要があります。 ユーザーにはadmin権限を追加しました。 必要最小限の権限については調査中です。

serverless.yml修正

regionを追加する。

$ cat serverless.yml
...
region: ap-northeast-1
...

handler.jsの修正は不要です。

deploy

作成したnodejsアプリ(handler.js)をdeployします。

$ serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service my-service.zip file to S3 (1.81 KB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
................
Serverless: Stack update finished...
Service Information
service: my-service
stage: dev
region: ap-northeast-1
stack: my-service-dev
resources: 5
api keys:
  None
endpoints:
  None
functions:
  hello: my-service-dev-hello
layers:
  None

deploy時に以下のエラーが出た場合には、Admin権限を追加してみてください。(xxx,yyy,zzzは適当に読み替えてください)

  ServerlessError: User: arn:aws:iam::xxx:user/yyy is not authorized to perform: cloudformation:DescribeStacks on resource: arn:aws:cloudformation:ap-northeast-1:zzz:stack/my-service-dev/*

実行

$ serverless invoke -f hello
{
    "statusCode": 200,
    "body": "{\n  \"message\": \"Go Serverless v1.0! Your function executed successfully!\",\n  \"input\": {}\n}"
}

AWSコンソール

Lambda上にdeployされていることが確認できます。

f:id:unokun3:20190504110343p:plain
AWS Lambda

リンク

はじめてのServerless(AWS)

Serverless(AWS)を使ってみました。

AWS Lambda上にクローラーを設置するのがゴールです。

インストール

Serverless Getting Started Guide

$ npm install -g serverless

# shell再読込
$ exec -l $SHELL

# グローバルにインストールしたくない場合には--save-devオプションを付ける
# ただし、パスを通すのが面倒かも
$ npm install --save-dev serverless

プロジェクト作成

Serverless Framework - AWS Lambda Guide - Quick Start

$ serverless create --template aws-nodejs --path my-service
$ cd my-service
$ ls
handler.js         serverless.yml

deploy

awscliのインストールおよびユーザー作成をしておく必要があります。 ユーザーにはadmin権限を追加しました。 必要最小限の権限については調査中です。

serverless.yml修正

regionを追加する。

$ cat serverless.yml
...
region: ap-northeast-1
...

handler.jsの修正は不要です。

deploy

作成したnodejsアプリ(handler.js)をdeployします。

$ serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service my-service.zip file to S3 (1.81 KB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
................
Serverless: Stack update finished...
Service Information
service: my-service
stage: dev
region: ap-northeast-1
stack: my-service-dev
resources: 5
api keys:
  None
endpoints:
  None
functions:
  hello: my-service-dev-hello
layers:
  None

deploy時に以下のエラーが出た場合には、Admin権限を追加してみてください。(xxx,yyy,zzzは適当に読み替えてください)

  ServerlessError: User: arn:aws:iam::xxx:user/yyy is not authorized to perform: cloudformation:DescribeStacks on resource: arn:aws:cloudformation:ap-northeast-1:zzz:stack/my-service-dev/*

実行

$ serverless invoke -f hello
{
    "statusCode": 200,
    "body": "{\n  \"message\": \"Go Serverless v1.0! Your function executed successfully!\",\n  \"input\": {}\n}"
}

AWSコンソール

Lambda上にdeployされていることが確認できます。

f:id:unokun3:20190504110343p:plain
AWS Lambda

リンク

AWS CodeCommitを使ってみる

Crawller開発のため以下の本のCodeCommit(2章)から写経しています。

AmazonWebServicesアプリ開発運用入門 | 戌亥 稔, 上迫 淳也, 三上 大輔, 百瀬 吉伸 |本 | 通販 | Amazon

Windows版は、403(Access Forbidden)が出た。 公式の対応も実施してみましたがうまく動きません。 * 認証情報ヘルパーと AWS CodeCommit への HTTPS 接続のトラブルシューティング - AWS CodeCommit

MacOS環境は以下のページを参照したらgit clone成功しました。 このままこの本を読むか思案中。