AWS + Nginx + PHP + Laravel

nginx + php + LaravelをAWS上に構築してみる

nginx

  • インストールと起動
$ sudo yum -y install nginx
・・・・・
完了しました!

$ sudo service nginx start
Starting nginx:                                            [  OK  ]
  • バージョンやconfigurationの内容を知りたいときは下記コマンド
$ nginx -V
  • configurationで使いそうなやつメモ
設定 説明 デフォルト
–error-log-path HTTPアクセスログのエラーのパス /var/log/nginx/error.log
–http-log-path HTTPアクセスログのパス /var/log/nginx/access.log
–conf-path nginxの設定ファイルのパス /etc/nginx/nginx.conf
–http-proxy-temp-path プロキシを実行している場合、ここで指定したディレクトリが一時ファイルの格納パスになる /var/lib/nginx/tmp/proxy
  • モジュールで気になるところメモあたり(他にもあったけど、メモるの面倒でdown)
モジュール名 説明 利用場面 デフォルト
http_ssl https対応(OpenSSLライブラリが必要)。 プロキシ 有効
http_realip L7ロードバランサなどの後に配置する場合有効にする必要あり。複数のクライアントが同一IPアドレスから通信してくるように見える環境で使用。 プロキシ 有効
http_geoip クライアントのIPアドレスに基づく地理的位置に応じた処理を行うための様々な変数を設定 Web、プロキシ 有効
http_stub_status Nginx自身の統計情報の収集を手助けする Web、プロキシ 有効

※有効化(–with-<モジュール名>module)、無効化(–without-<モジュール名>module)

PHP7のインストール

  • CentOS6用のPHP7のリポジトリを追加(これがないとインストールできないくさい)
$ sudo yum install --enablerepo=webtatic-testing 
                 php70w php70w-devel php70w-fpm php70w-mysql 
                 php70w-mbstring php70w-pdo
  • 他にも必要であればインストールしておく(json系とか)

nginxとphpの紐付け

  • index.phpのセット

    • /var/www/default ディレクトリ作成
    • ここにindex.phpを配置 (最初はとりあえずphpinfoを吐くだけ)
  • /etc/php-fpm.d/www.confの編集 (backupを取った上で編集)
$ diff -uN www.conf.backup_20160710 www.conf
--- www.conf.backup_20160710    2016-07-10 08:00:45.267704077 +0000
+++ www.conf    2016-07-10 08:01:38.451085053 +0000
@@ -5,9 +5,11 @@
 ; Note: The user is mandatory. If the group is not set, the default user's group
 ;       will be used.
 ; RPM: apache Choosed to be able to access some dir as httpd
-user = apache
+; user = apache
+user = nginx
 ; RPM: Keep a group allowed to write in log dir.
-group = apache
+; group = apache
+group = nginx
  • /etc/nginx/nginx.confの編集 (backupを取った上で編集)
$ diff -uN nginx.conf.backup_20160710 nginx.conf
--- nginx.conf.backup_20160710  2016-07-10 07:49:38.694839828 +0000
+++ nginx.conf  2016-07-10 07:59:49.564346085 +0000
@@ -32,13 +32,14 @@
     # for more information.
     include /etc/nginx/conf.d/*.conf;

-    index   index.html index.htm;
+    index   index.php index.html index.htm;

     server {
         listen       80 default_server;
         listen       [::]:80 default_server;
         server_name  localhost;
-        root         /usr/share/nginx/html;
+        #root         /usr/share/nginx/html;
+        root         /var/www/default;

         # Load configuration files for the default server block.
         include /etc/nginx/default.d/*.conf;
@@ -46,8 +47,17 @@
         location / {
         }

-        # redirect server error pages to the static page /40x.html
+        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
         #
+        location ~ .php$ {
+            root           /var/www/default;
+            fastcgi_pass   127.0.0.1:9000;
+            fastcgi_index  index.php;
+            fastcgi_param  SCRIPT_FILENAME  /var/www/default$fastcgi_script_name;
+            include        fastcgi_params;
+        }
+
+        # redirect server error pages to the static page /40x.html
         error_page 404 /404.html;
             location = /40x.html {
         }
@@ -64,16 +74,6 @@
         #    proxy_pass   http://127.0.0.1;
         #}

-        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
-        #
-        #location ~ .php$ {
-        #    root           html;
-        #    fastcgi_pass   127.0.0.1:9000;
-        #    fastcgi_index  index.php;
-        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
-        #    include        fastcgi_params;
-        #}
-
  • 再起動して、phpinfoページが見れればOK (http://<>)
$ sudo service php-fpm start
Starting php-fpm:                                          [  OK  ]
$ sudo service nginx restart
Stopping nginx:                                            [  OK  ]
Starting nginx:                                            [  OK  ]
  • ついでにサーバ起動時などに自動で起動するものも設定
$ sudo chkconfig nginx on
$ sudo chkconfig php-fpm on

nginxとphp-fpmの接続をsocketにする

  • php-fpmの設定変更
$ diff -uN www.conf.backup_20160710 www.conf
--- www.conf.backup_20160710    2016-07-10 08:00:45.267704077 +0000
+++ www.conf    2016-07-10 08:19:03.630366042 +0000
@@ -19,7 +21,8 @@
 ;                            (IPv6 and IPv4-mapped) on a specific port;
 ;   '/path/to/unix/socket' - to listen on a unix socket.
 ; Note: This value is mandatory.
-listen = 127.0.0.1:9000
+; listen = 127.0.0.1:9000
+listen = /var/run/php-fpm/php-fpm.sock

@@ -32,6 +35,8 @@
 ;                 mode is set to 0660
 ;listen.owner = nobody
 ;listen.group = nobody
+listen.owner = nginx
+listen.group = nginx
 ;listen.mode = 0660
  • nginxの設定変更
$ diff -uN nginx.conf.backup_20160710 nginx.conf
--- nginx.conf.backup_20160710  2016-07-10 07:49:38.694839828 +0000
+++ nginx.conf  2016-07-10 08:20:37.741301066 +0000
@@ -46,8 +47,17 @@
-            fastcgi_pass   127.0.0.1:9000;
+            fastcgi_pass   unix:/var/run/php-fpm/php-fpm.sock;
  • 再起動
$ sudo service php-fpm restart
Stopping php-fpm:                                          [  OK  ]
Starting php-fpm:                                          [  OK  ]
$ sudo service nginx restart
Stopping nginx:                                            [  OK  ]
Starting nginx:                                            [  OK  ]

Laravel5を入れてみる

  • Composerをインストール
$ curl -sS https://getcomposer.org/installer | php
$ sudo mv /home/ec2-user/composer.phar /usr/local/bin/composer
  • Laravelのインストール
$ sudo /usr/local/bin/composer global require "laravel/installer"
Changed current directory to /root/.composer
Using version ^1.3 for laravel/installer
./composer.json has been created
Loading composer repositories with package information
Updating dependencies (including require-dev)
  - Installing symfony/process (v3.1.2)
    Downloading: 100%         

  - Installing symfony/polyfill-mbstring (v1.2.0)
    Downloading: 100%         

  - Installing symfony/console (v3.1.2)
    Downloading: 100%         

  - Installing guzzlehttp/promises (1.2.0)
    Downloading: 100%         

  - Installing psr/http-message (1.0)
    Downloading: 100%         

  - Installing guzzlehttp/psr7 (1.3.1)
    Downloading: 100%         

  - Installing guzzlehttp/guzzle (6.2.0)
    Downloading: 100%         

  - Installing laravel/installer (v1.3.3)
    Downloading: 100%         

symfony/console suggests installing symfony/event-dispatcher ()
symfony/console suggests installing psr/log (For using the console logger)
Writing lock file
Generating autoload files
  • php-xmlのインストール (laravelで必要になる)
$ sudo yum install --enablerepo=webtatic-testing php70w-xml
  • プロジェクト作成
$ pwd
/var/www/default
$ sudo /usr/local/bin/composer create-project --prefer-dist laravel/laravel darmaso
Installing laravel/laravel (v5.2.31)
  - Installing laravel/laravel (v5.2.31)
    Downloading: 100%         

Created project in darmaso
> php -r "copy('.env.example', '.env');"
Loading composer repositories with package information
Updating dependencies (including require-dev)
・・・・・ (下記の結果と同じ)

$ cd darmaso
$ sudo /usr/local/bin/composer install
Loading composer repositories with package information
Updating dependencies (including require-dev)
・・・・・
Writing lock file
Generating autoload files
> IlluminateFoundationComposerScripts::postUpdate
> php artisan optimize
Generating optimized class loader

※php-xmlをインストールしておかないと、下記のようなエラーが出るので注意
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - phpunit/phpunit 4.8.9 requires ext-dom * -> the requested PHP extension dom is missing from your system.
・・・・・
    - Installation request for phpunit/phpunit ~4.0 -> satisfiable by phpunit/phpunit[4.0.0, 4.0.1, 4.0.10, 4.0.11, 4.0.12, 4.0.13, 4.0.14, 4.0.15, 4.0.16, 4.0.17, 4.0.18, 4.0.19, 4.0.2, 4.0.20, 〜
・・・・・
  To enable extensions, verify that they are enabled in those .ini files:
    - /etc/php.ini
    - /etc/php.d/bz2.ini
    - /etc/php.d/calendar.ini
・・・・・
  You can also run `php --ini` inside terminal to see which files are used by PHP in CLI mode.
  • Applicationキーの生成 (composerでインストールした場合セットされているらしいが念のため)
$ sudo php artisan key:generate
Application key [base64:YVeCf2A+5IjUbk2qVL4HhPiecBdYuo8irJrEYjJKZWY=] set successfully.
  • Laravel用にnginx設定を修正し、再起動
$ diff -uN nginx.conf.backup_20160710 nginx.conf
+        #root         /var/www/default;
+        root         /var/www/default/darmaso/public;
・・・・・
         location / {
+            try_files $uri $uri/ /index.php?$query_string;
         }
・・・・・
+            #root           /var/www/default;
+            root           /var/www/default/darmaso/public;
・・・・・
+            #fastcgi_param  SCRIPT_FILENAME  /var/www/default$fastcgi_script_name;
+            fastcgi_param  SCRIPT_FILENAME  /var/www/default/darmaso/public$fastcgi_script_name;

$ sudo service php-fpm restart
$ sudo service nginx restart
  • これで動作確認するとエラーになるので下記の設定をしてみる
$ sudo chmod -R 777 storage/
$ sudo chmod -R 777 vendor/

※本来は、サーバアカウントをちゃんと定義してやるべきだが、今回は試しなのでこのままでOKとする

  • 一部の設定を変えてみる
config/app.php
$ diff -uN config/app.php.backup_20160710 config/app.php
--- config/app.php.backup_20160710  2016-07-10 09:37:07.881735079 +0000
+++ config/app.php  2016-07-10 09:40:54.263419145 +0000
@@ -52,7 +52,7 @@
     |
     */

-    'timezone' => 'UTC',
+    'timezone' => 'Asia/Tokyo',

     /*
     |--------------------------------------------------------------------------
@@ -65,7 +65,7 @@
     |
     */

-    'locale' => 'en',
+    'locale' => 'jp',

     /*
     |--------------------------------------------------------------------------
@@ -78,7 +78,7 @@
     |
     */

-    'fallback_locale' => 'en',
+    'fallback_locale' => 'jp',

これで構築した環境にアクセスしたところ、無事いけました!
設定内容が荒いところもありますが、上記まででPHP+Nginx自体はいけちゃいますね。

Nginxの設定はあまり大したことはできませんでしたが、今後は色々と勉強してみようと思いますmm

参考

続きを読む

serverless frameworkを使ってデプロイ

serverless frameworkってなんなん

YAMLに設定を書いておくと、CLIでAWSのデプロイ/設定が行えます。
簡単に言うと、デプロイの自動化ができます。

環境

項目 version
node 6.10.2
serverless framework 1.19.0

インストール

serverless frameworkをglobalにインストール。

npm install -g serverless

config credentials

serverless framework docs AWS – Config Credentials

プロジェクト作成

serverless frameworkのコマンドを使用してプロジェクトを作成します。

mkdir serverless-sample
serverless create -t aws-nodejs

以下内容のファイルが作成されます。試してみたら見れますがw

handler.js
'use strict';

module.exports.hello = (event, context, callback) => {
  const response = {
    statusCode: 200,
    body: JSON.stringify({
      message: 'Go Serverless v1.0! Your function executed successfully!',
      input: event,
    }),
  };

  callback(null, response);

  // Use this code if you don't use the http event with the LAMBDA-PROXY integration
  // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event });
};
serverless.yml
# Welcome to Serverless!
#
# This file is the main config file for your service.
# It's very minimal at this point and uses default values.
# You can always add more config options for more control.
# We've included some commented out config examples here.
# Just uncomment any of them to get that config option.
#
# For full config options, check the docs:
#    docs.serverless.com
#
# Happy Coding!

service: serverless-sample

# You can pin your service to only deploy with a specific Serverless version
# Check out our docs for more details
# frameworkVersion: "=X.X.X"

provider:
  name: aws
  runtime: nodejs6.10

# you can overwrite defaults here
#  stage: dev
#  region: us-east-1

# you can add statements to the Lambda function's IAM Role here
#  iamRoleStatements:
#    - Effect: "Allow"
#      Action:
#        - "s3:ListBucket"
#      Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ]  }
#    - Effect: "Allow"
#      Action:
#        - "s3:PutObject"
#      Resource:
#        Fn::Join:
#          - ""
#          - - "arn:aws:s3:::"
#            - "Ref" : "ServerlessDeploymentBucket"
#            - "/*"

# you can define service wide environment variables here
#  environment:
#    variable1: value1

# you can add packaging information here
#package:
#  include:
#    - include-me.js
#    - include-me-dir/**
#  exclude:
#    - exclude-me.js
#    - exclude-me-dir/**

functions:
  hello:
    handler: handler.hello

#    The following are a few example events you can configure
#    NOTE: Please make sure to change your handler code to work with those events
#    Check the event documentation for details
#    events:
#      - http:
#          path: users/create
#          method: get
#      - s3: ${env:BUCKET}
#      - schedule: rate(10 minutes)
#      - sns: greeter-topic
#      - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
#      - alexaSkill
#      - iot:
#          sql: "SELECT * FROM 'some_topic'"
#      - cloudwatchEvent:
#          event:
#            source:
#              - "aws.ec2"
#            detail-type:
#              - "EC2 Instance State-change Notification"
#            detail:
#              state:
#                - pending
#      - cloudwatchLog: '/aws/lambda/hello'
#      - cognitoUserPool:
#          pool: MyUserPool
#          trigger: PreSignUp

#    Define function environment variables here
#    environment:
#      variable2: value2

# you can add CloudFormation resource templates here
#resources:
#  Resources:
#    NewResource:
#      Type: AWS::S3::Bucket
#      Properties:
#        BucketName: my-new-bucket
#  Outputs:
#     NewOutput:
#       Description: "Description for the output"
#       Value: "Some output value"

region設定

regionの設定を追記します。

serverless.yml
--- 省略 ---
provider:
  name: aws
  runtime: nodejs6.10
  region: ap-northeast-1
--- 省略 ---

API Gateway設定

上記ロジックを呼ぶエンドポイントの設定を追記。

serverless.yml
--- 省略 ---
functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: serverless-sample
          method: get
--- 省略 ---

デプロイ

serverless frameworkのコマンドを使用してデプロイします。
serverless.ymlに記載の内容でデプロイされます。

serverless deploy

参考

serverless

続きを読む

Running Kubernetes Cluster on AWS

Following this guide https://kubernetes.io/docs/getting-started-guides/kops/, set up Kubernetes cluster on AWS using kops.

1. Install kops

According to the guide, kops is:

kops helps you create, destroy, upgrade and maintain production-grade, hig… 続きを読む

MySQLが統計情報を計算するタイミングで再起動してしまう

対象バージョン

MySQL 5.6.35, 5.7.17

現象

AWS より RDS 上の MySQL のうち 5.6.19a, 5.6.19b, 5.6.21, 5.6.21b, 5.6.22, and 5.6.23 の各バージョンが廃止となるという連絡があり、その時点での最新バージョンである 5.6.35 にアップデートを実施した。
するとバージョンアップ後しばらくして以下のエラーが発生し、断続的に再起動を繰り返すようになってしまった。
(ログは一部改変しています)

terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check
06:01:31 UTC - mysqld got signal 6 ;
This could be because you hit a bug. It is also possible that this binary
or one of the libraries it was linked against is corrupt, improperly built,
or misconfigured. This error can also be caused by malfunctioning hardware.
We will try our best to scrape up some info that will hopefully help
diagnose the problem, but since we have already crashed, 
something is definitely wrong and this may fail.
key_buffer_size=xxxxxxxx
read_buffer_size=xxxxxxxx
max_used_connections=xxxx
max_threads=xxxx
thread_count=xxxx
connection_count=xxxx
It is possible that mysqld could use up to 
key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = xxxxxx K bytes of memory
Hope that's ok; if not, decrease some variables in the equation.
Thread pointer: 0x0
Attempting backtrace. You can use the following information to find out
where mysqld died. If you see no messages after this, something went
terribly wrong...
stack_bottom = 0 thread_stack 0x40000
/rdsdbbin/mysql/bin/mysqld(my_print_stacktrace+0x33)[0x876d73]
/rdsdbbin/mysql/bin/mysqld(handle_fatal_signal+0x35c)[0x64089c]
/lib64/libpthread.so.0(+0x10f90)[0x7fecc63d2f90]
/lib64/libc.so.6(gsignal+0x37)[0x7fecc57e8167]
/lib64/libc.so.6(abort+0x16a)[0x7fecc57e95ea]
/usr/lib64/libstdc++.so.6(_ZN9__gnu_cxx27__verbose_terminate_handlerEv+0x16d)[0x7fecc60e017d]
/usr/lib64/libstdc++.so.6(+0x73fc6)[0x7fecc60ddfc6]
/usr/lib64/libstdc++.so.6(+0x74011)[0x7fecc60de011]
/usr/lib64/libstdc++.so.6(+0x74228)[0x7fecc60de228]
/usr/lib64/libstdc++.so.6(_ZSt20__throw_out_of_rangePKc+0x139)[0x7fecc613e869]
/rdsdbbin/mysql/bin/mysqld[0xa8e394]
/rdsdbbin/mysql/bin/mysqld[0xa8fb59]
/rdsdbbin/mysql/bin/mysqld[0xa90ec0]
/lib64/libpthread.so.0(+0x7f18)[0x2ada4e15bf18]
/lib64/libc.so.6(clone+0x6d)[0x2ada4f2a5b2d]
The manual page at http://dev.mysql.com/doc/mysql/en/crashing.html contains
information that should help you find out what is causing the crash.
…

原因

以下 URL にある通り、MySQL の 5.6.35, 5.7.17 でのみ発生するバグとのこと。
https://bugs.mysql.com/bug.php?id=84940

対応

以下2つの対応方法がある。

1. 問題のあるバージョンを回避する

次のバージョンで FIX されているため、5.6.36, 5.7.18 以降のバージョンにアップデートすればよい。

ただ、RDS の場合はちょっと厄介で、2017/8/14 の時点では 5.7.18 以降を選択できないため、5.7.17 になっている場合はダウングレードが必要となってしまう。
(問題の発生した環境は運良く 5.6.35 だったので、5.7.16 にバージョンアップをすることで回避できた)

RDS は現在より前のバージョンを選択できず、スナップショットからの復元でもバージョンは選択できないので、新たにインスタンスを立ち上げて、そこにデータを流し込む方法になると思われる。

2. インデックス統計を永続化しない

前述の URL によると、削除行のインデックス統計判定の不具合(※MariaDBでの修正箇所です)が原因とのこと。
なので、クエリパラメータより以下の設定をすればよいらしい。

[mysqld]
innodb-stats-persistent             = 0
innodb-stats-transient-sample-pages = 20
innodb-stats-auto-recalc            = 0

ただし、この変更によりインデックス統計が非永続的になり、性能劣化が予測されるため、今回は選択しなかった。

備考

MySQL 5.6 と 5.7 の互換性に注意が必要である。
ハマったところで言うと、以下の2つ。

  • sql_mode の ONLY_FULL_GROUP_BY,NO_ZERO_IN_DATE,NO_ZERO_DATE がデフォルトで ON
  • ROW_FORMAT=FIXED が廃止

RDS の場合は新しいパラメータグループを作成するが、複数のパラメータグループを比較できるので、それを利用すれば分かりやすいかもしれない。

スクリーンショット 2017-08-15 11.40.15.png

character_set_server を latin1 から utf8mb4 にしなければいけないのもここで気づくことができた。

続きを読む

Amazon API Gateway + AWS Lambdaで、iOSでの定期購読をリアルタイムでSlackへ投稿する

2017年7月18日のnewsで、自動更新登録を含むすべてのレシートに、カスタマーの登録のステータスに関するリアルタイムの情報が含まれるように、なったためリアルタイムでslack通知するためにサクッと作りました。
Amazon API Gateway + AWS Lambda のレシピ用意されてて簡単だったので、ぜひ :roller_coaster:

構成

server-notifications.jpeg

  1. iTunes Connect

    • Server notifications for auto-renewable subscriptions
  2. Amazon API Gateway
  3. AWS Lambda
  4. Slack

Lambda 準備

Amazon API Gateway + AWS Lambda の構成はレシピ用意されている。
今回は、python3.6のfunctionを利用(node.js・python2.7も用意されている)

Lambda code

Webhook URLを取得して以下のコード
http://qiita.com/vmmhypervisor/items/18c99624a84df8b31008

import json
import urllib.request
import time

print('Loading function')

def respond(err, res=None):
    return {
        'statusCode': '400' if err else '200',
        'body': err.message if err else json.dumps(res),
        'headers': {
            'Content-Type': 'application/json',
        },
    }

class Receipt:
    def __init__(self, params):
         # 必要に応じて追加する
        self.notification_type = params['notification_type']
        self.product_id        = params['latest_receipt_info']['product_id']
        self.bid               = params['latest_receipt_info']['bid']

def send_slack(channel, receipt): 
    # slack webhook URLは入れ替え 
    url = 'https://hooks.slack.com/services/xxxxxxxxx/xxxxxxxxxxx'
    attachments = [
            {
                "fallback": "iOS Subscription Report",
                "color": "#36a64f",
                "author_name": "mikan",
                "author_link": "http://mikan.link",
                "author_icon": "http://flickr.com/icons/bobby.jpg",
                "title": "購読レポート",
                "text": "App: " + receipt.bid,
                "fields": [
                    {
                        "title": "購読",
                        "value": receipt.notification_type,
                        "short": False
                    },
                    {
                        "title": "商品id",
                        "value": receipt.product_id,
                        "short": False
                    }
                ],
                "image_url": "http://my-website.com/path/to/image.jpg",
                "thumb_url": "http://example.com/path/to/thumb.png",
                "footer": "Server notifications for auto-renewable subscriptions",
                "footer_icon": "https://platform.slack-edge.com/img/default_application_icon.png",
                "ts": time.time()
            }
        ]
    params = {"channel": channel, "username": "dekopon", "attachments": attachments}
    params = json.dumps(params).encode("utf-8")
    req = urllib.request.Request(url, data=params, method="POST")
    res = urllib.request.urlopen(req)

def lambda_handler(event, context):
    params = json.loads(json.dumps(event))
    body = params['body']
    receipt = Receipt(json.loads(body))
    send_slack("playground", receipt)
    return respond(None, "Post slack successfully!")

処理できるかテスト

以下のような方法で、jsonをPOSTしてみてテスト
sample jsonは記事下部に掲載しておきました。

  • Lambdaでテストイベントを設定して実行
  • curlやDHCでPOST実行

Subscription Status URL を設定

iTunes ConnectのMy Appsから、対象アプリを選択して、Subscription Status URLに作成したAPI GateWayのエンドポイントを指定
App StoreApp InformationSubscription Status URL

https://help.apple.com/itunes-connect/developer/#/dev0067a330b

あとは購読してもらえるものを作り込みましょう :rocket:

sample json

{
    "body": {
        "auto_renew_product_id": "link.mikan.sub.sample", 
        "auto_renew_status": "true", 
        "environment": "PROD", 
        "latest_receipt": "xxxxxxxxx", 
        "latest_receipt_info": {
            "app_item_id": "xxxxxxxxx", 
            "bid": "link.mikan.sample", 
            "bvrs": "1", 
            "expires_date": "123456", 
            "expires_date_formatted": "2017-09-05 22:19:54 Etc/GMT", 
            "expires_date_formatted_pst": "2017-09-05 15:19:54 America/Los_Angeles", 
            "item_id": "xxxxxxxxx", 
            "original_purchase_date": "2017-08-05 22:19:56 Etc/GMT", 
            "original_purchase_date_ms": "1501971596000", 
            "original_purchase_date_pst": "2017-08-05 15:19:56 America/Los_Angeles", 
            "original_transaction_id": "730000169590752", 
            "product_id": "link.mikan.sub.sample", 
            "purchase_date": "2017-08-05 22:19:54 Etc/GMT", 
            "purchase_date_ms": "1501971594000", 
            "purchase_date_pst": "2017-08-05 15:19:54 America/Los_Angeles", 
            "quantity": "1", 
            "transaction_id": "xxxxxxxxx", 
            "unique_identifier": "xxxxxxxxx", 
            "unique_vendor_identifier": "xxxxxxxxx", 
            "version_external_identifier": "xxxxxxxxx", 
            "web_order_line_item_id": "xxxxxxxxx"
        }, 
        "notification_type": "INITIAL_BUY", 
        "password": "xxxxxxxxx"
    }
}

参考

Lambda 関数を公開するための API を作成する
Amazon API Gatewayを使ってAWS LambdaをSDKなしでHTTPS越しに操作する
Advanced StoreKit – WWDC 2017 – Videos – Apple Developer

続きを読む

サーバーレスアプリケーションを管理する(SERVER LESS)

前置き

だんだんと Lambda function が増えてきたので管理してみようと思いました。今回は Serverless を使ってみます。

インストール

ますはインストールします。

事前準備

以下をインストールします。

Serverless framework をインストール

この記事 を参考に、各プロジェクトごとにインストールをします。

package.json
{
  "name": "project-name",
  "devDependencies": {
    "serverless": "^1.16.0"
  },
  "scripts": {
    "sls": "serverless"
  }
}

エラーが出るとき

インストールしたときに怒られちゃいました・・・

Error: Cannot find module ‘/path/to/project/node_modules/serverless/node_modules/tabtab/src/cli.js’

issueを参考に、オプションをつけて再度インストールしたところ成功!
無事インストールが完了しました!

$ sls --version
1.16.0

サービスを作成する

Serverless framework では、サーバーレスアプリケーションを service という単位で切り分けるようです。
まずは Serverless framework が提供しているテンプレートを利用して作成してみまんす。

$ sls create --help
Plugin: Create
create ........................ Create new Serverless service
    --template / -t (required) ......... Template for the service. Available templates: "aws-nodejs", "aws-python", "aws-python3", "aws-groovy-gradle", "aws-java-maven", "aws-java-gradle", "aws-scala-sbt", "aws-csharp", "azure-nodejs", "openwhisk-nodejs", "openwhisk-python", "openwhisk-swift", "google-nodejs", "plugin" and "hello-world"
    --path / -p ........................ The path where the service should be created (e.g. --path my-service)
    --name / -n ........................ Name for the service. Overwrites the default name of the created service.

ふむふむ、テンプレートがたくさん良いされてますな。今回は AWS Lambda で python3 なので、 aws-python3 を選択します。

$ sls create -t aws-python3 -p service
Serverless: Generating boilerplate...
Serverless: Generating boilerplate in "/path/to/project/service"
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  ___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.16.0
 -------'

Serverless: Successfully generated boilerplate for template: "aws-python3"

でけた!ファイルが何個かできてますね。

ls -la srvice
total 24
drwxr-xr-x  5 user  staff   170  6 22 10:50 .
drwxr-xr-x  6 user  staff   204  6 22 10:47 ..
-rw-r--r--  1 user  staff   192  6 22 10:47 .gitignore
-rw-r--r--  1 user  staff   490  6 22 10:47 handler.py
-rw-r--r--  1 user  staff  2787  6 22 10:47 serverless.yml

何ができるのかな?

$ sls

Commands
* Serverless documentation: http://docs.serverless.com
* You can run commands with "serverless" or the shortcut "sls"
* Pass "--help" after any <command> for contextual help

config ........................ Configure Serverless
config credentials ............ Configures a new provider profile for the Serverless Framework
create ........................ Create new Serverless service
install ....................... Install a Serverless service from GitHub
package ....................... Packages a Serverless service
deploy ........................ Deploy a Serverless service
deploy function ............... Deploy a single function from the service
deploy list ................... List deployed version of your Serverless Service
deploy list functions ......... List all the deployed functions and their versions
invoke ........................ Invoke a deployed function
invoke local .................. Invoke function locally
info .......................... Display information about the service
logs .......................... Output the logs of a deployed function
login ......................... Login or sign up for the Serverless Platform
logout ........................ Logout from the Serverless Platform
metrics ....................... Show metrics for a specific function
remove ........................ Remove Serverless service and all resources
rollback ...................... Rollback the Serverless service to a specific deployment
rollback function ............. Rollback the function to a specific version
slstats ....................... Enable or disable stats

Plugins
AwsCommon, AwsCompileAlexaSkillEvents, AwsCompileApigEvents, AwsCompileCloudWatchEventEvents, AwsCompileCloudWatchLogEvents, AwsCompileCognitoUserPoolEvents, AwsCompileFunctions, AwsCompileIoTEvents, AwsCompileS3Events, AwsCompileSNSEvents, AwsCompileScheduledEvents, AwsCompileStreamEvents, AwsConfigCredentials, AwsDeploy, AwsDeployFunction, AwsDeployList, AwsInfo, AwsInvoke, AwsInvokeLocal, AwsLogs, AwsMetrics, AwsPackage, AwsProvider, AwsRemove, AwsRollback, AwsRollbackFunction, Config, Create, Deploy, Info, Install, Invoke, Login, Login, Logs, Metrics, Package, Platform, Remove, Rollback, SlStats

お、ローカルでのテスト用コマンドもあるみたいですね。試してみましょ。

テスト

まずはテンプレートで作成されたファンクションをテストしてみまんす。

$ cd service
$ sls invoke local -f hello

すると・・・

Error: spawn python3.6 ENOENT

まーた怒られちゃいました・・・どうやらローカル環境のpythonが3.6じゃないようですね。
pyenv と pyenv-virtualenv で解決しました!

デプロイ

では実際にAWSへデプロイしてみます!

その前に

デプロイの前にAWSのクレデンシャル設定をします。

$ aws configure

すでに複数のクレデンシャルを管理している場合は

$ export AWS_PROFILE="profileName" && export AWS_REGION=ap-northeast-1

いけます!

デプロイ!

これを実行するだけ!

$ sls deploy
Serverless: Packaging service...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (1.35 MB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
.........
Serverless: Stack update finished...
Service Information
service: service
stage: dev
region: ap-northeast-1
api keys:
  None
endpoints:
  None
functions:
  update: service

AWSコンソールでLambdaを確認すると・・・できてました!

Tips

環境でリソースを使い分ける

今回はテストコードでしたが、実際はステージングや本番で同じコードを利用した運用がしたいと思います。
例えば・・・

DB更新したいからVPCにLambdaをおきたいけど、ステージングと本番でVPCわけちゃってるやー

こんな時、デプロイの設定で配置するVPCがわけられたら素敵ですよね!そんな時はこうします!

18 # ステージによって使い分けたい設定を記述
19 custom:
26   vpc:
27     staging:
28       securityGroupIds:
29         - sg-sgsgsgsg
30       subnetIds:
31         - subnet-aaaaaaaa
32         - subnet-cccccccc
33 
34 provider:
35   # ステージの値をデプロイ時のパラメータで上書き(デフォルトはdev)
37   stage: ${opt:stage, self:custom.defaultStage}
38   # ステージの値を利用して値を使い分ける
42   vpc: ${self:custom.vpc.${self:provider.stage}}

こんな感じでserverless.ymlに設定します。

あとはデプロイコマンドにパラメータを追加すればOK!

$ sls deploy --stage staging
Serverless: Packaging service...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (1.35 MB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
.........
Serverless: Stack update finished...
Service Information
service: service
stage: staging
region: ap-northeast-1
api keys:
  None
endpoints:
  None
functions:
  update: update-pageviews-staging-update

stageが前回はdevでしたが、今回はstagingに変わってますね!この仕組みを利用すれば環境変数などもステージにより使い分けることができますので、より捗ります!

最後に

バージョン管理からデプロイまで管理できることにより、非常にサーバーレスヘの敷居が低くなりました。サーバレスアプリケーションは開発が簡単な分、運用への意識が低くなり、どうしても「今ってどのバージョンが動いてるんだっけ?」「これっていつ誰が作ったの?」など、逆にコストがかかることもありましたが、サーバーレスフレームワークを利用することにより、今までと変わらない開発、テスト、運用が適用できるようになりますね!

続きを読む

Dockerとホストのネットワーク on EC2

全然理解していなかったのでちゃんと勉強してみました。

試した環境

AMIは Amazon Linux AMI amzn-ami-hvm-2017.03.1 (ami-3bd3c45c) を使用しています。
インスタンスタイプは t2.micro です。
ポートは :22 (ssh) だけ開けました。

予め、docker をインストールします。

$ sudo yum install -y docker
$ sudo service docker start

本投稿では sudo は省略 (alias) しています。

$ vi ~/.bash_profile

# これを追加
alias docker='sudo docker'
alias ip='sudo ip'
alias brctl='sudo brctl'

$ source ~/.bash_profile

コンテナが2つある時のネットワーク

図にするとこんな感じです

default.png

まずはコンテナ2つを立ち上げる

Container 1, Continer 2 を立ち上げます。実行するプロセスは sleep 1000000

$ docker run -d --name container1 alpine sleep 1000000
$ docker run -d --name container2 alpine sleep 1000000

ちゃんと動いてるか確認します。

$ docker ps

CONTAINER ID     IMAGE     COMMAND           CREATED           STATUS          PORTS   NAMES
ac2ece448844     alpine    "sleep 1000000"   5 seconds ago     Up 4 seconds            container2
e1147e5ec006     alpine    "sleep 1000000"   14 seconds ago    Up 13 seconds           container1

ホストのネットワークを見てみる

ホスト側のネットワークを見てみます。↑図と大体同じような感じになっています。

$ ifconfig

# "veth0000001", "veth0000002" のブリッジ
docker0   Link encap:Ethernet  HWaddr 02:42:DE:AF:0E:4C  
          inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:deff:feaf:e4c/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:28 errors:0 dropped:0 overruns:0 frame:0
          TX packets:14 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:1744 (1.7 KiB)  TX bytes:1068 (1.0 KiB)

eth0      Link encap:Ethernet  HWaddr 06:AC:37:4A:1A:AD  
          inet addr:172.30.1.211  Bcast:172.30.1.255  Mask:255.255.255.0
          inet6 addr: fe80::4ac:37ff:fe4a:1aad/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:9001  Metric:1
          RX packets:45727 errors:0 dropped:0 overruns:0 frame:0
          TX packets:22649 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:63486801 (60.5 MiB)  TX bytes:1659723 (1.5 MiB)

...

# 図中の "veth0000001" に該当
veth2b8058a Link encap:Ethernet  HWaddr F2:BD:7F:6A:C2:88  
          inet6 addr: fe80::f0bd:7fff:fe6a:c288/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:14 errors:0 dropped:0 overruns:0 frame:0
          TX packets:42 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:1068 (1.0 KiB)  TX bytes:3204 (3.1 KiB)

# 図中の "veth0000002" に該当
vethd2804f4 Link encap:Ethernet  HWaddr B6:2C:76:4A:0B:DD  
          inet6 addr: fe80::b42c:76ff:fe4a:bdd/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:14 errors:0 dropped:0 overruns:0 frame:0
          TX packets:28 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:1068 (1.0 KiB)  TX bytes:2048 (2.0 KiB)

ホストの routing table はこう↓です。

$ route -n

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.30.1.1      0.0.0.0         UG    0      0        0 eth0
169.254.169.254 0.0.0.0         255.255.255.255 UH    0      0        0 eth0    # これはEC2 metadata用.
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
172.30.1.0      0.0.0.0         255.255.255.0   U     0      0        0 eth0

コンテナの名前空間を見てみる

Dockerはプロセスの実行環境をホストOSや他コンテナと分離をするサービスです。Linuxの ネットワーク名前空間 / マウント名前空間 / PID名前空間 / etc… 機能を利用して実現しています。

各コンテナの名前空間を探す為に、まずホスト側からコンテナプロセスのPIDを探します。 PID 3100, 3211 がそれですね。

$ ps auxf

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
...
root      2810  0.0  4.1 435916 42528 pts/0    Sl   03:31   0:01 /usr/bin/dockerd --default-ulimit nofile=1024:4096
root      2816  0.0  0.9 228760  9912 ?        Ssl  03:31   0:00  \_ docker-containerd -l unix:///var/run/docker/libcontainerd/...
root      3084  0.0  0.2 135792  2568 ?        Sl   03:40   0:00      \_ docker-containerd-shim ... /var/run/docker/libcontainerd/...
root      3100  0.0  0.0   1524     4 ?        Ss   03:40   0:00      |   \_ sleep 1000000
root      3188  0.0  0.2 201328  2504 ?        Sl   03:40   0:00      \_ docker-containerd-shim ... /var/run/docker/libcontainerd/...
root      3211  0.0  0.0   1524     4 ?        Ss   03:40   0:00          \_ sleep 1000000

この PID=3100 sleep 1000000 プロセスが実行されている名前空間は↓で確認できます。このうち net がネットワーク名前空間になります。

$ sudo ls -l /proc/3100/ns/

total 0
lrwxrwxrwx 1 root root 0 Jul 23 04:08 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Jul 23 04:08 ipc -> ipc:[4026532159]
lrwxrwxrwx 1 root root 0 Jul 23 04:08 mnt -> mnt:[4026532157]
lrwxrwxrwx 1 root root 0 Jul 23 03:40 net -> net:[4026532162]
lrwxrwxrwx 1 root root 0 Jul 23 04:08 pid -> pid:[4026532160]
lrwxrwxrwx 1 root root 0 Jul 23 04:08 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Jul 23 04:08 uts -> uts:[4026532158]

コンテナのネットワークを見てみる

次に ip コマンドを使って、コンテナのネットワーク名前空間上で bash プロセスを立ち上げてみます。

ip コマンドは /var/run/netns/ 以下のネットワーク名前空間しか扱えないので、まずはシンボリックリンクを貼ってやります。

$ sudo mkdir -p /var/run/netns/
$ sudo ln -s /proc/3100/ns/net /var/run/netns/container1

ネットワーク名前空間 container1 上で bash プロセスを立ち上げます。

$ ip netns exec container1 bash

root#

“$ ip netns exec {ネットワーク名前空間名} {実行したいコマンド}”

コンテナ側のネットワークを盗み見る事ができました。

root# ifconfig

eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02  
          inet addr:172.17.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:45 errors:0 dropped:0 overruns:0 frame:0
          TX packets:15 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:3414 (3.3 KiB)  TX bytes:1138 (1.1 KiB)

...

コンテナの routing table も見てみます。

root# route -n

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.0.1      0.0.0.0         UG    0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

コンテナにNICを手動で追加してみる

図にするとこんな感じです

2nic.png

準備

まず、 Container 2 は邪魔なので落としておきます

$ docker stop container2
$ docker rm container2

ブリッジを操作するコマンド brctl をインストールします。

$ sudo yum install -y bridge-utils

ホストのブリッジ情報を表示してみます。

$ brctl show

bridge name   bridge id           STP enabled   interfaces
docker0       8000.0242deaf0e4c   no            veth2b8058a

veth (Virtual Ethernet) を追加する

veth (1ケーブルで接続済の仮想NICのペア) を追加します。ホスト側のブリッジ docker0 と接続する方を veth-host, コンテナ側を veth-con とします。

$ ip link add name veth-host type veth peer name veth-con
$ ip link set veth-host up

ホスト側NIC veth-host をブリッジ docker0 に接続します。

$ brctl addif docker0 veth-host

この時はまだ veth-host, veth-con 共にホスト側のネットワーク名前空間に属している為、ホスト側から両方とも見えます。

$ ifconfig veth-host

veth-host Link encap:Ethernet  HWaddr 3A:D3:41:66:58:F8  
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)

$ ifconfig veth-con

veth-con Link encap:Ethernet  HWaddr 5E:98:45:07:48:00  
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)

コンテナ側NIC veth-con のネットワーク名前空間を container1 に変更します。

$ ip link set veth-con netns container1

ホスト側からは見えなくなります。

$ ifconfig veth-con

veth-con: error fetching interface information: Device not found

逆にコンテナ側は見える様になります。

$ ip netns exec container1 ifconfig veth-con

veth-con  Link encap:Ethernet  HWaddr B2:45:A8:96:1B:AA  
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)

コンテナ側NICの設定

まずはNIC名を veth-coneth1 に変えてやります。

$ ip netns exec container1 ip link set veth-con name eth1

“$ ip netns exec container1 …” → コンテナ側 (netns) でコマンド実行している

NIC eth1 にIP 172.17.0.99/24 を割り当てます。

$ ip netns exec container1 ip addr add 172.17.0.99/24 dev eth1
$ ip netns exec container1 ip link set eth1 up

コンテナ側からIPが見れる様になります。

$ ip netns exec container1 ifconfig eth1

eth1      Link encap:Ethernet  HWaddr B2:45:A8:96:1B:AA  
          inet addr:172.17.0.99  Bcast:0.0.0.0  Mask:255.255.255.0
          inet6 addr: fe80::b045:a8ff:fe96:1baa/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:5714 errors:0 dropped:0 overruns:0 frame:0
          TX packets:4448 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:121496019 (115.8 MiB)  TX bytes:309958 (302.6 KiB)

コンテナ側 routing table の変更

せっかく追加したNIC eth1 が全く使われていないので、routing table を変更してやります。

$ ip netns exec container1 ip route delete default
$ ip netns exec container1 ip route add default via 172.17.0.1 dev eth1

この通り、外部アクセスが新規追加したNIC eth1 経由となりました。

$ ip netns exec container1 route -n

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.0.1      0.0.0.0         UG    0      0        0 eth1
172.17.0.0      0.0.0.0         255.255.255.0   U     0      0        0 eth1
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

eth0 で入って来たのが eth1 から出てしまいますが、今回は無視します

コンテナに侵入して確認してみる

実際にコンテナに侵入して、意図したとおりに動いているか見てみます。

$ docker exec -it container1 sh

/ # ps aux
PID   USER     TIME   COMMAND
    1 root       0:00 sleep 1000000
    5 root       0:00 sh
   10 root       0:00 ps aux

元からあった eth0 (172.17.0.2) と、追加した eth1 (172.17.0.99) が見えます。

# ifconfig

eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02  
          inet addr:172.17.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:2040 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1320 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:48591073 (46.3 MiB)  TX bytes:97477 (95.1 KiB)

eth1      Link encap:Ethernet  HWaddr B2:45:A8:96:1B:AA  
          inet addr:172.17.0.99  Bcast:0.0.0.0  Mask:255.255.255.0
          inet6 addr: fe80::b045:a8ff:fe96:1baa/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:5714 errors:0 dropped:0 overruns:0 frame:0
          TX packets:4448 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:121496019 (115.8 MiB)  TX bytes:309958 (302.6 KiB)
...

routing table も先程設定したとおりです。

# route -n

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.0.1      0.0.0.0         UG    0      0        0 eth1
172.17.0.0      0.0.0.0         255.255.255.0   U     0      0        0 eth1
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

curl をインストールしてみます。

apkAlpine Linux のパッケージ管理システム

/ # apk update

fetch http://dl-cdn.alpinelinux.org/alpine/v3.6/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.6/community/x86_64/APKINDEX.tar.gz
v3.6.2-40-gf1c202674f [http://dl-cdn.alpinelinux.org/alpine/v3.6/main]
v3.6.2-32-g6f53cfcccd [http://dl-cdn.alpinelinux.org/alpine/v3.6/community]
OK: 8436 distinct packages available

/ # apk add curl

(1/3) Installing libssh2 (1.8.0-r1)
(2/3) Installing libcurl (7.54.0-r0)
(3/3) Installing curl (7.54.0-r0)
Executing busybox-1.26.2-r5.trigger
OK: 231 MiB in 41 packages

google.com にアクセスしてみます。

/ # curl google.com

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.co.jp/?gfe_rd=cr&amp;ei=3UN0WduOBrGL8QfG9JGIBQ">here</A>.
</BODY></HTML>

続きを読む

AWSからS3のセキュリティについて警告メールが来た時の対処方法

AWSからS3の警告メールが来たら

S3バケットのポリシーに関するTIPSです。
SORACOMの松井さんに教えていただいて大変助かったので情報共有として記事にします。

いきなりメールが来る

AWSからある日こんなメールが届きました。どうも特定の条件の人に一斉にメール送ってるようです。

Subject: Securing Amazon S3 Buckets [AWS Account: ******]

Hello,

We’re writing to remind you that one or more of your Amazon S3 bucket access control lists (ACLs) are currently configured to allow access from any user on the Internet. The list of buckets with this configuration is below.

By default, S3 bucket ACLs allow only the account owner to read contents from the bucket; however, these ACLs can be configured to permit world access. While there are reasons to configure buckets with world read access, including public websites or publicly downloadable content, recently, there have been public disclosures by third parties of S3 bucket contents that were inadvertently configured to allow world read access but were not intended to be publicly available.

We encourage you to promptly review your S3 buckets and their contents to ensure that you are not inadvertently making objects available to users that you don’t intend. Bucket ACLs can be reviewed in the AWS Management Console (http://console.aws.amazon.com ), or using the AWS CLI tools. ACLs permitting access to either “All Users” or “Any Authenticated AWS User” (which includes any AWS account) are effectively granting world access to the related content.

For more information on configuring your bucket ACLs, please visit: https://docs.aws.amazon.com/AmazonS3/latest/dev/S3_ACLs_UsingACLs.html

For additional assistance reviewing your bucket ACLs, please visit http://aws.amazon.com/support to create a case with AWS Developer Support.

Your list of buckets configured to allow access from anyone on the Internet are:

バケットの名前

要約すると「おめー、S3のバケットを世界中から見られるように設定してるけどまずいんじゃね?ちゃんと制限しろよ」ということのようです。

とはいえ

指摘されたバケットはいずれもstatic web hostingで使っているバケットです。その性質上、世界中から見えないとあまり意味がないです。
公式ドキュメントでも以下のように「該当バケット以下のすべてのオブジェクトに対するGetObjectメソッドを、全てのアクセスに対して許可しろ」と書いてあります。

http://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/WebsiteAccessPermissionsReqd.html

これは困った・・。

そこに救いの手が

Facebookで相談したところ、元・中の人の松井さんが教えてくれました。

Bucket policy でアクセス元IPアドレスを 0.0.0.0/1 と 128.0.0.0/1 からのみ許可するというライフハック

これはどういうことかというと

  • 0.0.0.0/0を開放するとこれは全開放になっちゃうのでこれまでと変わらないから多分また警告が来る
  • ネットマスクを最小値の1として0.0.0.0/1とするとこれは0.0.0.1~127.255.255.255.254のレンジになる
  • 追加で128.0.0.0/1を許可すると、これが128.0.0.1~255.255.255.254になる
  • 結局、2つ合わせると0.0.0.0/0とするのとほぼ等価になる(厳密にいうとブロードキャストアドレスの分があるけど、そんなアドレスからのアクセスはないだろう)

ということになります。ネットマスクの計算については割愛します。

というわけで

以下のように書き換えたら無事終了。

{
    "Version": "2008-10-17",
    "Statement": [
        {
            "Sid": "PublicReadForGetBucketObjects",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "s3:GetObject",
            "Resource": "バケットのARN/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "0.0.0.0/1",
                        "128.0.0.0/1"
                    ]
                }
            }
        }
    ]
}

将来的なことを考えるとv6アドレスも足すべきでしょうけどとりあえずはこれでよさそうです。

しかし、そもそもstatic web hostingがONになってる人は対象から外すとかしてくれればいいんですけどねぇ・・。

あと、これで本当に警告が来なくなるのかは未検証です(しばらく待ってみないとわからないので)のでご了承ください。
また届いたら記事をアップデートします。

続きを読む

Alexaに日本語を喋ってもらう

背景

  • Pollyで文字から音声を生成できる
  • Alexa Voice Serviceを使うとmp3が再生できる

つまり日本語を話せるAlexaが作れるのでは…?:thinking:

概要

日本語で話しかける :arrow_right: 日本語で答えてくれる

題材として、「挨拶」と「天気予報を」を選んだ。
「おはよう」
「今日の天気を教えて」
「明日の天気は?」
などに応答してくれる。

こんな感じで会話できます。
(Echo持ってないのでAVSで動かしてます…:cry:)

https://youtu.be/6GKvik7QOXA

Alexa Skills Kit

まず、自分で作ったアプリを登録し、AlexaからLambda関数を読み出せるための設定が必要です。
これらの作業は https://developer.amazon.com/ で行う必要があるため、アカウントを取得して下さい。
また、アカウント作成の際に、日本の通販のAmazonで使っているものと異なるメールアドレスで登録するようお願いします。

Skillの作成

トップページ[ALEXA]タブ :arrow_right:[Add a New Skill]
よりスキルを作成できます。
スキル作成にあたって、設定が必要な箇所があるので簡単に説明します。
(本題とは逸れるのであまりしっかりは説明しません)

・Skill Information

[Name]

表示される名前です(なんでもいい)

[Invocation Name]

Alexaに呼びかけてこのスキルを起動する時の名前です
自分は “nihon go” と入力しているので、 “ask nihon go” でスキルが起動します。

・Interaction Model

Lambda関数と同じくらい大切なところ。

[Intent Schema]

自分の例は以下。
type に入っているものが単語の集合で、この下の [Custom Slot Types] で設定します。 name はその単語をLambdaに渡す際の名前をここで決めています。

{
  "intents": [
    {
      "slots": [
        {
          "name": "greetings",
          "type": "JP_Greetings"
        }
      ],
      "intent": "GreetingWords"
    },
    {
      "slots": [
        {
          "name": "dates",
          "type": "JP_Dates"
        }
      ],
      "intent": "Questions"
    },
    {
      "intent": "AMAZON.HelpIntent"
    }
  ]
}

[Custom Slot Types]

こんなかんじ。(てきとう)

スクリーンショット 2017-07-11 15.50.15.png

[Sample Utterances]

上で定義したインテント名とスロット名を使います。
発話を受け取り、どのタイプの会話であるかを判断します。
<インテント名> <会話内容>という書き方で、”{xxx}”となっているものは、上で設定したスロット名のスロットタイプに含まれる単語の何かしらを受け取れます。
以下書き方の例。

GreetingWords {greetings}
Questions {dates} no tenki o oshiete
Questions {dates} no tenki wa

・Configuration

こんなかんじでLamnda指定。(てきとう)

スクリーンショット 2017-07-11 15.55.45.png

構成

Alexa Voice Service から Alexa Skill Kit(lambda関数) を呼び出して処理しています。
全てus-east-1 (バージニア北部) のリソースを使っています。

先日Lexも公開されたのですが、mp3の再生が出来ないようなので保留。
(Lexのほうがlambda関数を短く書けて楽な上に、Slotなどの管理も手軽なので使いたかった…)

スクリーンショット 2017-06-08 17.14.44.png

処理の流れ

処理としては上の図の3つのLambda関数が軸になっているので、それぞれの関数に沿って説明します。

AVSlink.js

AVSと連携しているlambda関数で、AVSからのリクエストを受け付けています。
音声の入力に応じて、S3に保存されているmp3を再生しています。

▼Lamnda関数

https://github.com/marceline-git/AlexaFunctions/blob/master/AVSlink.js

説明が面倒なので省略しますが コードを見ればなんとなく動きがわかると思います。
一応説明しておくべき場所を以下にまとめました。
cheerio-httpcliを使っているため、npm install cheerio-httpcliしてzipで固めてLambdaにアップロードして下さい。
function onIntentでインテントの名前からどの関数を実行するかを決めています。
<バケット名>/output以下のフォルダに、発話させたいmp3ファイルを置いてます。
・常にshouldEndSession = falseなので、特に終了させる会話などは決めていません。
repromptTextは一定時間発話が無かった際に送られるものです。(聞いたことないけど)

getData.js

天気予報APIを叩いて、発話させたい日本語文をDynamoDBに格納。
Dynamoにはこんな感じでデータが入っています。idを主キーとして、値はunixtimeを入れています。

スクリーンショット 2017-07-11 16.54.41.png

発話するためのmp3を生成する際はここのデータを引っ張ってきています。
データが増えすぎないように、天気の情報を取得するたびに古いものは削除しています。

▼Lamnda関数

https://github.com/marceline-git/AlexaFunctions/blob/master/getData.js

ちょっとした説明。
asyncを使っているため、npm install asyncしてzipで固めてLambdaにアップロードして下さい。
・livedoorの天気APIを使っています。住所などは適当にいじって下さい。
・CloudWatch Eventsをトリガーに、定期実行しています。

convert.js

Pollyの生成するmp3ファイルは、フォーマットの問題で直接AVSから再生できません。
以下のフォーマットに変換する必要があります。

コーデック: mp3
チャンネル数: 2
サンプリング周波数: 16000kHz
ビットレート: 48kbps
* Converting Audio Files to an Alexa-Friendly Format

ドキュメントではffmpegで変換しているのですが、lambdaにffmpegを乗せるのは結構面倒で…。
(ffmpegとlibmp3ame入れつつ軽量化するのが大変)
EC2インスタンス建てっぱなしにするのもスマートじゃないので悩んでいたら、ElasticTranscoderというサービスで解決しそうなので採用。

▼ElasticTranscoderの使い方

Pipelineの作成

[Elastic Transcoder]→[Create New Pipeline]より作成。
PipelineIdは後ほどLambdaで使います。

スクリーンショット 2017-06-08 17.58.18.png

Presetの作成

[Elastic Transcoder]→[Create New Preset]より作成。
PresetIdは後ほどLambdaで使います。

スクリーンショット 2017-06-08 18.15.48.png

Jobの作成

こちらはマネジメントコンソールで作成する必要がありません。Lambda関数内で生成します。

▼Lamnda関数

https://github.com/marceline-git/AlexaFunctions/blob/master/convert.js

ちょっとした説明。
asyncを使っているため、npm install asyncしてzipで固めてLambdaにアップロードして下さい。
・DynamoDBから文章を取ってきて、発話して、一旦mp3を生成して、変換して、古いmp3削除して、Dynamoからも削除して、みたいな流れです。
・発話時にpollyでSampleRate: "16000"を指定しているため、変換時に上のPresetでは[auto]でもうまく動きます。
PipelineIdPresetIdは先程作成したものを利用して下さい。
・CloudWatch Eventsをトリガーに、定期実行しています。

S3のフォルダ構成 :arrow_down:

  • <バケット名>/tmp
    pollyにより発話されたmp3ファイル(変換前)が一旦保存されるフォルダ
  • <バケット名>/output
    tmpフォルダからmp3ファイルを引っ張ってきて、ElasticTranscoderにより変換されたmp3ファイルが保存されるフォルダ

お疲れ様でした :sweat:

一部だけをかいつまんで説明したのですが、ElasticTranscoderなどの説明で結構長くなってしまいました。
大体がaws-sdkを利用しているので、リファレンスを読めばなんとなくわかると思います。
* AWS SDK for JavaScript
わからないことがあれば、コメント欄に書いてもらえれば回答します(多分(暇な時))。

余談

前もって定期実行して発話すべきmp3ファイルを持っておくのはどうなのかと思い、Alexaに問い合わせがあった際にLambda内で動的生成を行うものも作成しました。
が、返事まで30秒近く時間がかかってしまいスマートさが欠片も感じられなかったので使うのはやめました。

続きを読む

EC2 Systems ManagerでLinuxのパッチを適用してみた

Linuxの環境に対してPatchを適用できるようになったようです。

Amazon EC2 Systems Manager Now Supports Linux Patching

Previously, Patch Manager only supported Windows managed instances. 
If you wanted to patch Linux managed instances, you needed to use in-house or Linux distribution-specific tools. 
Now, you can manage Linux patches for AWS and on-premises managed instances using the same tool as you do for Windows. 
Just like with Windows patching, Patch Manager lets you automate your Linux patching process using defined auto-approval rules, which lets you only deploy vetted packages. 
This also gives you a single patch compliance view for both your Linux and Windows managed instances.

これまで、Windows Serverに対してはメンテナンスウィンドウやパッチベースラインを利用してパッチの適用ができていましたが、Linuxでも同じ要領でパッチの適用ができるようになったようです。

これは時間の節約ができそうです。早速試します。

Management Consoleを確認

ドキュメント

“AWS-RunPatchBaseline”なるドキュメントが提供されていました。

EC2 Management Console_2.png

パッチベースライン

Amazon Linux、RHEL、Ubuntu用のパッチベースラインが提供されていました。

EC2 Management Console.png

使ってみる

東京リージョンで試します。

コマンド
export AWS_DEFAULT_REGION="ap-northeast-1"

メンテナンスウィンドウの作成

まず、メンテナンスウィンドウを作成します。(これまでと同じです)

コマンド
aws ssm create-maintenance-window 
    --name "LinuxPatching" 
    --no-allow-unassociated-targets 
    --schedule "cron(0 10 10 ? * SAT *)" 
    --duration 2 
    --cutoff 1
結果
{
    "WindowId": "mw-xxxxxxxxxxxxxxxxx"
}

ターゲットとなるLinuxインスタンスの作成

今回はAmazon Linuxを用意します。

ログインするのがめんどいので、UserDataでSSM Agentをインストールします。

また、インターネットにアクセス可能なSubnetに配置しましょう。また、適切なインスタンスプロファイルを設定します。

EC2 Systems Managerの動作要件は、以下のドキュメントを確認してください。

UserData
#!/bin/bash
cd /tmp
sudo yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm

ターゲットの指定

ここもこれまでの手順と変わりません。

コマンド
MAINTENANCE_WINDOW_ID="mw-xxxxxxxxxxxxxxxxx"
INSTANCE_ID="i-xxxxxxxxxxxxxxxxx"
コマンド
aws ssm register-target-with-maintenance-window 
    --window-id ${MAINTENANCE_WINDOW_ID} 
    --resource-type "INSTANCE" 
    --targets "Key=InstanceIds,Values=${INSTANCE_ID}"
結果
{
    "WindowTargetId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

(割愛)パッチベースラインの作成

今回はデフォルトのパッチベースラインと使って動作を確認します。

パッチベースラインの一覧を確認します。

コマンド
aws ssm describe-patch-baselines
結果
{
    "BaselineIdentities": [
        {
            "BaselineName": "AWS-AmazonLinuxDefaultPatchBaseline",
            "DefaultBaseline": true,
            "BaselineDescription": "Default Patch Baseline for Amazon Linux Prov                                                                                                                                                            ided by AWS.",
            "BaselineId": "arn:aws:ssm:ap-northeast-1:486716784251:patchbaseline                                                                                                                                                            /pb-0221829c157d721d8",
            "OperatingSystem": "AMAZON_LINUX"
        },
        {
            "BaselineName": "AWS-DefaultPatchBaseline",
            "DefaultBaseline": true,
            "BaselineDescription": "Default Patch Baseline Provided by AWS.",
            "BaselineId": "arn:aws:ssm:ap-northeast-1:486716784251:patchbaseline                                                                                                                                                            /pb-04ba050f612fba3a6",
            "OperatingSystem": "WINDOWS"
        },
        {
            "BaselineName": "AWS-RedHatDefaultPatchBaseline",
            "DefaultBaseline": true,
            "BaselineDescription": "Default Patch Baseline for Redhat Enterprise                                                                                                                                                             Linux Provided by AWS.",
            "BaselineId": "arn:aws:ssm:ap-northeast-1:486716784251:patchbaseline                                                                                                                                                            /pb-0adf5cb7136a2984d",
            "OperatingSystem": "REDHAT_ENTERPRISE_LINUX"
        },
        {
            "BaselineName": "AWS-UbuntuDefaultPatchBaseline",
            "DefaultBaseline": true,
            "BaselineDescription": "Default Patch Baseline for Ubuntu Provided b                                                                                                                                                            y AWS.",
            "BaselineId": "arn:aws:ssm:ap-northeast-1:486716784251:patchbaseline                                                                                                                                                            /pb-0ec96a11368349171",
            "OperatingSystem": "UBUNTU"
        }
    ]
}

Amazon Linux用のパッチベースラインを確認します。

コマンド
aws ssm get-patch-baseline 
    --baseline-id arn:aws:ssm:ap-northeast-1:486716784251:patchbaseline/pb-0221829c157d721d8
結果
{
    "BaselineId": "arn:aws:ssm:ap-northeast-1:486716784251:patchbaseline/pb-0221829c157d721d8",
    "Name": "AWS-AmazonLinuxDefaultPatchBaseline",
    "PatchGroups": [],
    "RejectedPatches": [],
    "GlobalFilters": {
        "PatchFilters": [
            {
                "Values": [
                    "AmazonLinux2012.03",
                    "AmazonLinux2012.09",
                    "AmazonLinux2013.03",
                    "AmazonLinux2013.09",
                    "AmazonLinux2014.03",
                    "AmazonLinux2014.09",
                    "AmazonLinux2015.03",
                    "AmazonLinux2015.09",
                    "AmazonLinux2016.03",
                    "AmazonLinux2016.09",
                    "AmazonLinux2017.03",
                    "AmazonLinux2017.09"
                ],
                "Key": "PRODUCT"
            }
        ]
    },
    "ApprovalRules": {
        "PatchRules": [
            {
                "PatchFilterGroup": {
                    "PatchFilters": [
                        {
                            "Values": [
                                "Security"
                            ],
                            "Key": "CLASSIFICATION"
                        },
                        {
                            "Values": [
                                "Critical",
                                "Important"
                            ],
                            "Key": "SEVERITY"
                        }
                    ]
                },
                "ApproveAfterDays": 7,
                "ComplianceLevel": "UNSPECIFIED"
            },
            {
                "PatchFilterGroup": {
                    "PatchFilters": [
                        {
                            "Values": [
                                "Bugfix"
                            ],
                            "Key": "CLASSIFICATION"
                        }
                    ]
                },
                "ApproveAfterDays": 7,
                "ComplianceLevel": "UNSPECIFIED"
            }
        ]
    },
    "ModifiedDate": 1499203527.709,
    "CreatedDate": 1499203527.709,
    "ApprovedPatchesComplianceLevel": "UNSPECIFIED",
    "OperatingSystem": "AMAZON_LINUX",
    "ApprovedPatches": [],
    "Description": "Default Patch Baseline for Amazon Linux Provided by AWS."
}

タスクを指定

使用するドキュメントを確認します。

コマンド
DOCUMENT_NAME="AWS-RunPatchBaseline"

aws ssm describe-document 
    --name ${DOCUMENT_NAME}
結果
{
    "Document": {
        "Status": "Active",
        "Hash": "d5c29590f323c144ce0338b8424970e2284f780b404dc164b2bc96dae5415218",
        "Name": "AWS-RunPatchBaseline",
        "Parameters": [
            {
                "Type": "String",
                "Name": "Operation",
                "Description": "(Required) The update or configuration to perform on the instance. The system checks if patches specified in the patch baseline are installed on the instance. The install operation installs patches missing from the baseline."
            },
            {
                "DefaultValue": "",
                "Type": "String",
                "Name": "SnapshotId",
                "Description": "(Optional) The snapshot ID to use to retrieve a patch baseline snapshot."
            }
        ],
        "DocumentType": "Command",
        "PlatformTypes": [
            "Linux"
        ],
        "DocumentVersion": "1",
        "HashType": "Sha256",
        "CreatedDate": 1499451553.857,
        "Owner": "Amazon",
        "SchemaVersion": "2.2",
        "DefaultVersion": "1",
        "LatestVersion": "1",
        "Description": "Scans for or installs patches from a patch baseline to a Linux or Windows operating system."
    }
}

タスクを設定する際には、IAMロールを指定する必要があります。

Configuring Roles and Permissions for Maintenance Windows

コマンド
ROLE_ARN_FOR_MAINTENANCE_WINDOW="arn:aws:iam::XXXXXXXXXXXX:role/AmazonSSMMaintenanceWindowRole"

また、実行結果を格納するS3バケットも予め用意しておきます。

コマンド
BUCKET_NAME="XXXXXXXX"
PREFIX="logs"

PATCH_BASELINE_LOGGING_FILE_NAME="patch_baseline_logging.json"

cat << EOF > ${PATCH_BASELINE_LOGGING_FILE_NAME}
{
    "S3BucketName": "${BUCKET_NAME}",
    "S3KeyPrefix": "${PREFIX}",
    "S3Region": "${AWS_DEFAULT_REGION}"
}
EOF

その他のパラメーターを確認し、タスクを登録します。

コマンド
PATCH_BASELINE_PARAMETER_FILE_NAME="patch_baseline_parameter.json"

cat << EOF > ${PATCH_BASELINE_PARAMETER_FILE_NAME}
{
    "Operation": {
        "Values": [
            "Install"
        ]
    }
}
EOF
コマンド
TASK_TYPE="RUN_COMMAND"
PRIORITY="1"
MAX_COCCURRENCY="1"
MAX_ERRORS="1"
コマンド
aws ssm register-task-with-maintenance-window 
    --window-id ${MAINTENANCE_WINDOW_ID} 
    --targets "Key=InstanceIds,Values=${INSTANCE_ID}" 
    --task-arn ${DOCUMENT_NAME} 
    --service-role-arn ${ROLE_ARN_FOR_MAINTENANCE_WINDOW} 
    --task-type ${TASK_TYPE} 
    --task-parameters file://${PATCH_BASELINE_PARAMETER_FILE_NAME} 
    --priority ${PRIORITY} 
    --max-concurrency ${MAX_COCCURRENCY} 
    --max-errors ${MAX_ERRORS} 
    --logging-info file://${PATCH_BASELINE_LOGGING_FILE_NAME}
結果
{
    "WindowTaskId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

実行結果の確認

メンテナンスウィンドウで指定した時刻になるまで待ちます。

細かいところをとばして、S3に出力された実行結果を確認します。

結果
/usr/bin/python
Loaded plugins: priorities, update-motd, upgrade-helper
Resolving Dependencies
--> Running transaction check
---> Package python26-requests.noarch 0:1.2.3-5.10.amzn1 will be installed
--> Processing Dependency: python(abi) = 2.6 for package: python26-requests-1.2.3-5.10.amzn1.noarch
--> Processing Dependency: python26-urllib3 >= 1.7 for package: python26-requests-1.2.3-5.10.amzn1.noarch
--> Processing Dependency: python26(dist-packages) for package: python26-requests-1.2.3-5.10.amzn1.noarch
--> Processing Dependency: python26-chardet for package: python26-requests-1.2.3-5.10.amzn1.noarch
--> Processing Dependency: python26-ordereddict for package: python26-requests-1.2.3-5.10.amzn1.noarch
--> Running transaction check
---> Package python26.x86_64 0:2.6.9-2.88.amzn1 will be installed
--> Processing Dependency: libpython2.6.so.1.0()(64bit) for package: python26-2.6.9-2.88.amzn1.x86_64
---> Package python26-chardet.noarch 0:2.0.1-7.7.amzn1 will be installed
---> Package python26-urllib3.noarch 0:1.8.2-1.5.amzn1 will be installed
--> Processing Dependency: python26-backports-ssl_match_hostname for package: python26-urllib3-1.8.2-1.5.amzn1.noarch
--> Processing Dependency: python26-six for package: python26-urllib3-1.8.2-1.5.amzn1.noarch
--> Running transaction check
---> Package python26-backports-ssl_match_hostname.noarch 0:3.4.0.2-1.12.amzn1 will be installed
--> Processing Dependency: python26-backports for package: python26-backports-ssl_match_hostname-3.4.0.2-1.12.amzn1.noarch
---> Package python26-libs.x86_64 0:2.6.9-2.88.amzn1 will be installed
---> Package python26-six.noarch 0:1.8.0-1.23.amzn1 will be installed
--> Running transaction check
---> Package python26-backports.x86_64 0:1.0-3.14.amzn1 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

================================================================================
 Package                              Arch   Version            Repository
                                                                           Size
================================================================================
Installing:
 python26-requests                    noarch 1.2.3-5.10.amzn1   amzn-main  94 k
Installing for dependencies:
 python26                             x86_64 2.6.9-2.88.amzn1   amzn-main 5.8 M
 python26-backports                   x86_64 1.0-3.14.amzn1     amzn-main 5.2 k
 python26-backports-ssl_match_hostname
                                      noarch 3.4.0.2-1.12.amzn1 amzn-main  12 k
 python26-chardet                     noarch 2.0.1-7.7.amzn1    amzn-main 377 k
 python26-libs                        x86_64 2.6.9-2.88.amzn1   amzn-main 697 k
 python26-six                         noarch 1.8.0-1.23.amzn1   amzn-main  31 k
 python26-urllib3                     noarch 1.8.2-1.5.amzn1    amzn-main  98 k

Transaction Summary
================================================================================
Install  1 Package (+7 Dependent packages)

Total download size: 7.0 M
Installed size: 22 M
Downloading packages:
--------------------------------------------------------------------------------
Total                                              1.9 MB/s | 7.0 MB  00:03     
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : python26-2.6.9-2.88.amzn1.x86_64                             1/8 
  Installing : python26-libs-2.6.9-2.88.amzn1.x86_64                        2/8 
  Installing : python26-chardet-2.0.1-7.7.amzn1.noarch                      3/8 
  Installing : python26-six-1.8.0-1.23.amzn1.noarch                         4/8 
  Installing : python26-backports-1.0-3.14.amzn1.x86_64                     5/8 
  Installing : python26-backports-ssl_match_hostname-3.4.0.2-1.12.amzn1.n   6/8 
  Installing : python26-urllib3-1.8.2-1.5.amzn1.noarch                      7/8 
  Installing : python26-requests-1.2.3-5.10.amzn1.noarch                    8/8 
  Verifying  : python26-requests-1.2.3-5.10.amzn1.noarch                    1/8 
  Verifying  : python26-chardet-2.0.1-7.7.amzn1.noarch                      2/8 
  Verifying  : python26-urllib3-1.8.2-1.5.amzn1.noarch                      3/8 
  Verifying  : python26-libs-2.6.9-2.88.amzn1.x86_64                        4/8 
  Verifying  : python26-six-1.8.0-1.23.amzn1.noarch                         5/8 
  Verifying  : python26-2.6.9-2.88.amzn1.x86_64                             6/8 
  Verifying  : python26-backports-1.0-3.14.amzn1.x86_64                     7/8 
  Verifying  : python26-backports-ssl_match_hostname-3.4.0.2-1.12.amzn1.n   8/8 

Installed:
  python26-requests.noarch 0:1.2.3-5.10.amzn1                                   

Dependency Installed:
  python26.x86_64 0:2.6.9-2.88.amzn1                                            
  python26-backports.x86_64 0:1.0-3.14.amzn1                                    
  python26-backports-ssl_match_hostname.noarch 0:3.4.0.2-1.12.amzn1             
  python26-chardet.noarch 0:2.0.1-7.7.amzn1                                     
  python26-libs.x86_64 0:2.6.9-2.88.amzn1                                       
  python26-six.noarch 0:1.8.0-1.23.amzn1                                        
  python26-urllib3.noarch 0:1.8.2-1.5.amzn1                                     

Complete!
07/08/2017 10:30:55 root [INFO]: Attempting to acquire instance information from ssm-cli.
07/08/2017 10:30:55 root [INFO]: ssm-cli path is: /usr/bin/ssm-cli.
07/08/2017 10:30:55 root [INFO]: Instance metadata from ssm-cli is: {"instance-id":"i-xxxxxxxxxxxxxxxxx","region":"ap-northeast-1","release-version":"2.0.847.0"}.
07/08/2017 10:30:55 urllib3.connectionpool [INFO]: Starting new HTTPS connection (1): s3.dualstack.ap-northeast-1.amazonaws.com
07/08/2017 10:30:56 urllib3.connectionpool [INFO]: Starting new HTTPS connection (1): s3.dualstack.ap-northeast-1.amazonaws.com
07/08/2017 10:30:57 root [INFO]: Attempting to acquire instance information from ssm-cli.
07/08/2017 10:30:57 root [INFO]: ssm-cli path is: /usr/bin/ssm-cli.
07/08/2017 10:30:57 root [INFO]: Instance metadata from ssm-cli is: {"instance-id":"i-xxxxxxxxxxxxxxxxx","region":"ap-northeast-1","release-version":"2.0.847.0"}.
07/08/2017 10:30:57 root [INFO]: Operation type: Install.
07/08/2017 10:30:57 root [INFO]: Snapshot ID: e62016f7-257d-4aee-b520-b58b10ad3cdd.
07/08/2017 10:30:57 root [INFO]: Instance ID: i-xxxxxxxxxxxxxxxxx.
07/08/2017 10:30:57 root [INFO]: Region ID: ap-northeast-1.
07/08/2017 10:30:57 botocore.vendored.requests.packages.urllib3.connectionpool [INFO]: Starting new HTTP connection (1): 169.254.169.254
07/08/2017 10:30:57 botocore.vendored.requests.packages.urllib3.connectionpool [INFO]: Starting new HTTP connection (1): 169.254.169.254
07/08/2017 10:30:57 botocore.vendored.requests.packages.urllib3.connectionpool [INFO]: Starting new HTTPS connection (1): ssm.ap-northeast-1.amazonaws.com
07/08/2017 10:30:57 root [INFO]: Product: AmazonLinux2017.03.
07/08/2017 10:30:57 root [INFO]: Snapshot download URL: https://patch-baseline-snapshot-ap-northeast-1.s3-ap-northeast-1.amazonaws.com/325e6910d69bd8861bea653821b277cecf2df85952414e32ec904b9a32a4a88b-788063364413/AMAZON_LINUX-e62016f7-257d-4aee-b520-b58b10ad3cdd?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20170708T103057Z&X-Amz-SignedHeaders=host&X-Amz-Expires=86400&X-Amz-Credential=AKIAILTSCHNHVBZOKOSA%2F20170708%2Fap-northeast-1%2Fs3%2Faws4_request&X-Amz-Signature=833c5f22664d48aa9b6fe5a4db9d04ee878293efb56d3bd581e1e8f0ce421de7.
07/08/2017 10:30:57 urllib3.connectionpool [INFO]: Starting new HTTPS connection (1): patch-baseline-snapshot-ap-northeast-1.s3-ap-northeast-1.amazonaws.com
07/08/2017 10:30:57 root [INFO]: Patch baseline: {u'baselineId': u'pb-0221829c157d721d8', u'name': u'AWS-AmazonLinuxDefaultPatchBaseline', u'modifiedTime': 1499203527.709, u'description': u'Default Patch Baseline for Amazon Linux Provided by AWS.', u'rejectedPatches': [], u'globalFilters': {u'filters': [{u'values': [u'AmazonLinux2012.03', u'AmazonLinux2012.09', u'AmazonLinux2013.03', u'AmazonLinux2013.09', u'AmazonLinux2014.03', u'AmazonLinux2014.09', u'AmazonLinux2015.03', u'AmazonLinux2015.09', u'AmazonLinux2016.03', u'AmazonLinux2016.09', u'AmazonLinux2017.03', u'AmazonLinux2017.09'], u'key': u'PRODUCT'}]}, u'approvalRules': {u'rules': [{u'filterGroup': {u'filters': [{u'values': [u'Security'], u'key': u'CLASSIFICATION'}, {u'values': [u'Critical', u'Important'], u'key': u'SEVERITY'}]}, u'complianceLevel': u'UNSPECIFIED', u'approveAfterDays': 7}, {u'filterGroup': {u'filters': [{u'values': [u'Bugfix'], u'key': u'CLASSIFICATION'}]}, u'complianceLevel': u'UNSPECIFIED', u'approveAfterDays': 7}]}, u'createdTime': 1499203527.709, u'approvedPatchesComplianceLevel': u'UNSPECIFIED', u'operatingSystem': u'AMAZON_LINUX', u'approvedPatches': [], u'accountId': u'486716784251'}.
07/08/2017 10:30:57 root [INFO]: Patch group: .
07/08/2017 10:30:57 root [INFO]: Operating system: AMAZON_LINUX.
07/08/2017 10:30:57 root [WARNING]: Unable to gain necessary access for possible kernel updates, code: 1.
07/08/2017 10:30:58 botocore.vendored.requests.packages.urllib3.connectionpool [INFO]: Starting new HTTP connection (1): 169.254.169.254
07/08/2017 10:30:58 botocore.vendored.requests.packages.urllib3.connectionpool [INFO]: Starting new HTTP connection (1): 169.254.169.254
Loaded plugins: priorities, update-motd, upgrade-helper
07/08/2017 10:30:58 root [INFO]: No updates, skipping.
Loaded plugins: priorities, update-motd, upgrade-helper
07/08/2017 10:30:59 root [INFO]: 
Patch compliance initialized with instance ID:i-xxxxxxxxxxxxxxxxx, 
baseline ID: pb-0221829c157d721d8, snapshot ID: e62016f7-257d-4aee-b520-b58b10ad3cdd, patch group: ,
start time: 2017-07-08 10:30:58.177869, end time: 2017-07-08 10:30:59.590999, upload NA compliance: False

07/08/2017 10:30:59 root [INFO]: Start to upload patch compliance.
07/08/2017 10:30:59 root [INFO]: Summary: {'ContentHash': 'b71836e461121012e37c8f25eb2846ade95a267c9fc237d5e5af36deaf8048f8', 'TypeName': 'AWS:PatchSummary', 'SchemaVersion': '1.0', 'CaptureTime': '2017-07-08T10:30:59Z', 'Content': [{'OperationStartTime': '2017-07-08T10:30:58Z', 'FailedCount': '0', 'PatchGroup': u'', 'OperationType': u'Install', 'BaselineId': u'pb-0221829c157d721d8', 'MissingCount': '0', 'NotApplicableCount': '249', 'OperationEndTime': '2017-07-08T10:30:59Z', 'InstalledOtherCount': '377', 'SnapshotId': u'e62016f7-257d-4aee-b520-b58b10ad3cdd', 'InstalledCount': '20'}]}
07/08/2017 10:30:59 botocore.vendored.requests.packages.urllib3.connectionpool [INFO]: Starting new HTTPS connection (1): ssm.ap-northeast-1.amazonaws.com
07/08/2017 10:31:00 root [INFO]: Upload complete.
07/08/2017 10:31:00 root [INFO]: Report upload is successful.

感想

動作確認をどうするのかとか、適用を除外したい/別途ラインでは該当しないけど適用したいなどの例外処理(パッチベースラインで設定可能)をどうするのかなど、予め考えていくことはありますが、できるだけ仕事しなくていいようにがんばりましょう!

続きを読む