のぴぴのメモ

自分用のLinuxとかの技術メモ

パターン認識と機械学習の詩的な説明にゾクゾク来た話

数年前、AIが流行り始めた時に機械学習がなんぞやと調べて時に出たったShieShareのイントロの「識別・認識とは?」の説明が、詩的ででもわかりやすくて、その時ゾクゾクと来たのを思い出したので、備忘録がてら引用しておきます。

ちなみに本文は数学者の方のスライドなので難しくてよくわかりませんでしたが(笑)

www.slideshare.net

上記SlideShareのP19-32から引用

認識とは、不要な情報を捨てること

特徴選択・特徴抽出が
識別・認識の本質

パターン認識機械学習においては
これを忘れてはいけません

色々な特徴や次元を
考えることは
とても役に立つことですが

知っている特徴や次元を
何も考えず全部手元に置いておくと
人間は高次元ユークリッド空間で
迷子になってしまいます

高次元ユークリッド空間は
私たちの感覚と乖離しやすく

もしあなたが無限次元の
ユークリッド空間に放り出されたら
見渡す限り全てのものが
あなたからはるかに遠くにあって
何も見分けがつかなるくなるような
そんな空間です

これは「次元の呪い」
と言われています

いいものも悪いものも
好きなものも嫌いなものも
関係あるものも関係ないものも

見分けがつかなくなってしまう
恐ろしい「呪い」ですね!

つまりあなたか
ヒルと白鳥の
雑多な集団の中から
白鳥を探し出しないのなら

まずあなたはあなたが
白鳥の
どの特徴を選択・抽出して
白鳥を白鳥と
認識しているのか
なるべく正確に
見つける必要があります

(2019/1)Appleのデバイスにプッシュ通知を行うためのAPNs設定メモ

はじめに

ここで説明すること

APNs(Apple Push Notification service)は、Appleのデバイス(iOSバイス、tvOS、macOS)に対してプッシュ通知を送るためのプラットフォームサービスです。*1
ここではアプリの通知の開発ができるようにするためのAPNsの設定を説明しています。

モバイルプッシュ関連のblog記事

全体の概要図

この記事で説明する全体の概要図です。(ProviderであるAmazon SNSへの個人情報交換ファイル取り込みは説明していません)

f:id:nopipi:20190201092820p:plain:w600

前提

  • Apple Developer Programの登録(有償)
    • プッシュ通知を利用した開発をするために必要
    • 料金は、年額で99ドル(個人または個人事業主/個人経営者)*2
    • 手順
      • Apple Developer Program - Apple Developerにアクセスする
      • 「登録」ボタンを押し、説明に従い情報を登録し、最後に料金を払う
      • 手続きが完了すると審査になります。審査には2日ほどかかる(審査中の場合、右上のログインユーザ名に"(pending)"と表示されます)
      • 審査が完了すると、メール通知がある
  • iOS開発環境

手順

iOSアプリ開発用証明書の作成

(1)Xcode連携での証明書作成

開発用途のiOSアプリの署名用に利用する証明書(以下、開発用証明書)をAPNsで作成します。手動もできますが、ここではXcode連携で作成します。

  • Xcodeを起動して、「Xcode」> 「Behaviors」> 「Edit Behaviors」を選択する

f:id:nopipi:20190126104647p:plain:w350

  • Apple IDとManage Certificates
    • 「Accounts」タブを選ぶ
    • Apple Developer Program登録したApple IDが登録できてない場合は左側の「Apple IDs」でID登録する
    • Apple Developer Program登録したApple IDを選択し、右下の「ManageCertificates」をクリックする

f:id:nopipi:20190126105602p:plain:w350

  • iOS Development」証明書の発行
    • 左下の「+」をクリックし、「iOS Development」を選択

f:id:nopipi:20190126113432p:plain:w350

  • 開発用の証明書が発行&登録される

f:id:nopipi:20190126114107p:plain:w350

(2)Apple Developerでの証明書確認

Apple Developerにログインして登録した証明書を確認できます。

f:id:nopipi:20190112015105p:plain:w350

  • 「Certificates」>「All」をクリックし登録した証明書を確認する

f:id:nopipi:20190126114917p:plain:w350

App ID の作成とNotificationsのSSLアクセス用証明書作成

(1)App ID作成

アプリケーションを識別するためのApp IDを登録します。

  • 「Identifiers」の「App IDs」をクリックし、右上の「+」をクリックする

f:id:nopipi:20190112022327p:plain:w300

  • 「Registering an App ID」で順に入力する
    • 「App ID Description」 > 「Name」: アプリケーションの名称を記載(例えばPushTest)
    • App ID Suffix
      • 「Explicit App ID」を選択し
      • 「Bundle ID」に、ユニークな名称を記載。通常はFQDNを利用し”work.nopipi.PushTest”のような感じにする
    • App Services
      • 「Push Notifications」にチェックを入れる(これ重要!!)
      • 「Continue」をクリック
  • 「Push Notifications」がConfigurableになっていることを確認し
  • 「Register」をクリック
(2) SSL証明書発行用に証明書署名要求(CSR)を作成

Macを利用して、CSR(Certificate Signing Request)を作成します。

  • キーチェーンアクセスを開きます
  • 「キーチェーンアクセス」>「証明書アシスタント」>「認証局に証明書を要求....」をクリックします
  • 必要事項を入力します
    • 「ユーザーのメールアドレス」を入力します
    • 「通称」は任意ですが、わかりやすい名称を記載(例えば"Bundle IDに設定した名前+SslCSR"とか)
    • 「CAのメールアドレス」は空欄
  • 「要求の処理」は「ディスクに保存」を選択ます
  • 「続ける」をクリックします

f:id:nopipi:20190112012806p:plain:w300
f:id:nopipi:20190112012932p:plain:w350

(3)NotificationsのSSL証明書作成
  • 作成したApp IDを開き、下段の「EDIT」をクリックする
  • 「Push Notifications」で、開発用のため「Development SSL Certificate」の「Creating Certificate」をクリック
  • SSL証明書の作成手順は以下の通り
    • Request:特になし。「Continue」をクリック
    • Generate: 準備したCSRを選択する。「Continue」をクリック
    • Download:「Download」から作成されたSSL証明書をダウンロードする。ダウンロードが完了したら「Done」する。
  • ダウンロードしたSSL証明書をダブルクリックしてキーチェーンに登録する
    • キーチェーンに登録したSSL証明書は、この後「APNs用証明書(.p12) の書き出し」で利用します。

f:id:nopipi:20190112083347p:plain:w400

バイス登録

(1)対象デバイスのUUID確認
  • Mac に端末を接続し、Xcodeを起動する
  • 「Window」>「Devices and Simulators」をクリック
  • 「identifier」としてUUIDが確認できます

f:id:nopipi:20190112031725p:plain:w400

(2)デバイスの登録
  • 「Devices」>「All」をクリックして、右上の「+」をクリック
  • 「Register Device」を選択し、端末の「Name」と「UUID」を入力
  • 完了したら「Continue」をクリックし、次の画面で「Register」をクリック

f:id:nopipi:20190112032143p:plain:w400

開発用プロビショニングプロファイルの作成

利用する App ID、開発用証明書、端末をそれぞれ紐付けプロビジョニングプロファイルを作成します。

  • 「ProvisioningProfiles」>「All」をクリックし、右上の「+」をクリック

f:id:nopipi:20190112080823p:plain:w350

  • What type of provisioning profile:
    • 「Development」>「iOS App Development」を選択する

f:id:nopipi:20190126121551p:plain:w350

f:id:nopipi:20190126121832p:plain:w350

  • Select certificates: 開発用証明書を選択
  • Select devices.:テスト用に登録したデバイスを選択
  • Name this profile and generate.:「Profile Name」にプロファイル名を設定
  • Profile Name: 「 Download」をクリックしてプロファイルをダウンロードする
  • ダウンロードが完了したら「Done」をクリック

作成したプロビショニングプロファイルは、Xcodeで開発したアプリに組み込みます。

APNs用個人情報交換ファイル(.p12) の作成

プロバイダー(サーバや、Amazon SNSAmazon PinpointなどAPNsにプッシュ通知依頼するもと)がAPNsアクセスするときに必要となるAPNs用証明書(.p12) を作成します。

f:id:nopipi:20190112084846p:plain:w400

f:id:nopipi:20190112085343p:plain

(備忘録)このblogのデザインめも

利用しているテーマ

blog.hatena.ne.jp

デザインCSS

/* <system section="theme" selected="6653812171397406126"> */
@import url("https://blog.hatena.ne.jp/-/theme/6653812171397406126.css");
/* </system> */

/* <system section="background" selected="bg5"> */
body{ background-color:#486079; background-image:url('/images/theme/backgrounds/theme5.jpg'); background-repeat: no-repeat; background-attachment:fixed; background-position: center top; background-size:cover; }
/* </system> */

table{ width:100%;} 
.scroll{ overflow: auto; white-space: nowrap;} 
.scroll::-webkit-scrollbar{height: 4px;} 
.scroll::-webkit-scrollbar-track{background: #F1F1F1;} 
.scroll::-webkit-scrollbar-thumb {background: #454545;}

@media screen and (min-width:1350px) {
  #box2 {
    float: right;
    width: 300px;
  }
  #main {
    float: right;
    width: 740px;
  }
  #wrapper {
    float: left;
    width: 1030px;
  }
  #content-inner {
    width: 1350px;
  }
}

CSSの参考にした情報

  • PC版でblogの幅を広げるCSS(for Naked)

www.shakkinhostess.com

  • 表の内容を折り返さずスクロールさせる

tamasaburo.com

Python3でナノ秒の計測をする方法

Pytho処理時間をナノ秒で計測する方法です。
python3.7で追加された、time.clock_gettime_ns()を利用することで実現しています。*1

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
import time

def main():
    start = time.clock_gettime_ns(time.CLOCK_MONOTONIC)
    <処理内容を記載>
    end = time.clock_gettime_ns(time.CLOCK_MONOTONIC)

    print('time: {}'.format(end - start))

if __name__ == "__main__":
    sys.exit(main())
  • 結果の単位は、ナノ秒(10^-9)"です。
  • time.CLOCK_MONOTONIC"は、単調増加の時間で 表現されるクロックを取得するオプションです。*2

補足

"end - start"のオーバーフローが気になる

time.clock_gettime_ns()は、int型を返します(なので上記コードのstart, endはint型)。

int型の場合overflowが気になりますが、python3のint型は仕様上上限なしでメモリサイズに空きがある限り拡大できるようです(python2のlong型がint型になった)
なので、python3の場合はオーバーフロー気にしなくて良さそうですね

Integers
PEP 0237: Essentially, long renamed to int. That is, there is only one built-in integral type, named int; but it behaves mostly like the old long type.
PEP 0238: An expression like 1/2 returns a float. Use 1//2 to get the truncating behavior. (The latter syntax has existed for years, at least since Python 2.2.)
The sys.maxint constant was removed, since there is no longer a limit to the value of integers. However, sys.maxsize can be used as an integer larger than any practical list or string index. It conforms to the implementation’s “natural” integer size and is typically the same as sys.maxint in previous releases on the same platform (assuming the same build options).
The repr() of a long integer doesn’t include the trailing L anymore, so code that unconditionally strips that character will chop off the last digit instead. (Use str() instead.)
Octal literals are no longer of the form 0720; use 0o720 instead.

https://docs.python.org/3.1/whatsnew/3.0.html#integers

Python(boto3)でSNSに通知依頼(Publish)するコード

Python+boto3でPublishするためのサンプルスクリプトです。

前提環境

  • 実行インスタンス
    • OS: Amazon Linux2(amzn2-ami-hvm-2.0.20190110-x86_64-gp)
    • Instance: t2.micro
    • Role:インスタンスSNSをPublishする権限があるRoleをアタッチしていること
  • SNS
    • Publish可能なtopicを準備すること
    • そのtopicのARNを控えておくこと

手順

(1) boto3インストール

sudo yum -y install python2-boto3

(2) AWSのプロファイル作成

$ aws configure
AWS Access Key ID [None]: 
AWS Secret Access Key [None]: 
Default region name [None]: ap-northeast-1
Default output format [None]: 
  • 補足説明
    • インスタンスロールを利用し一時クレデンシャルを取得するため、デフォルトリージョンのみ指定します。

(3) pythonプログラム

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import boto3

TOPIC_ARN=u'arn:aws:sns:ap-northeast-1:999999999:TopicName'

def main():
    # Get session
    client = boto3.client('sns')

    request = {
            'TopicArn': TOPIC_ARN,
            'Message':  u'test message',
            'Subject':  u'test'
    }
    response = client.publish(**request)

if __name__ == "__main__":
    sys.exit(main())
  • 補足
    • TOPIC_ARNに、事前準備したTopicのARNを指定する
    • boto3.client('sns')で、認証を行いセッションを確立させます
    • "request = { ・・・"でpublishに必要なパラメータを作成します
    • client.publish(**request)で実行します。

お名前.comドメイン取得し、Route53のDNS登録をしてLet's Encryptの無料の証明証を取得する手順の全体説明

はじめに

検証で自己署名証明書(オレオレ証明書)でない証明書が必要だったのですが、お金がかけられなかったのでお名前.comで安いドメインを取得し、Let's Encryptで無料証明書を取得してAWS上で検証をしました。この記事はその時の手順をまとめたものです。

f:id:nopipi:20190106154506p:plain:w600

大まかな手順

  1. ドメイン取得とRoute53との連携
    1. お名前.comでドメインを取得する
    2. Amazon Route 53で取得したドメイン名のPublic Hosted Zoneを登録する
    3. お名前.comにPublic Hosted ZoneのDNSを登録する
  2. Let's Encryptで無料の証明書を取得する
    1. AmazonLinux2のインスタンスを作りクライアントソフト(certbot)をセットアップ
    2. certbotで証明書を取得
    3. apacheサーバに組み込み

AmazonLinux2でLet's EncryptでCertbot改造せずに証明書を取得する手順

はじめに

この記事で説明すること

この記事では、Let's Encryptから無料のサーバ証明書(ワイルドカード証明書)を取得し、(複数の)apacheサーバに証明書を組み込む手順を説明してます。

Amazon Linux2でLet's EncryptをググるCertbotを改造するケースが多いですが、この手順では引数を工夫することで改造なしを実現してます。

Let's Encryptの証明書の有効期限は90日で、この記事の手順では更新毎に利用している全apacheサーバに証明書を再配布しなければならないので、PoCや検証などで一時的に正規の証明書が必要なケースを想定した手順になります。

なお、この手順の前提として証明書用のドメインを取得している必要があります。

f:id:nopipi:20190106124645p:plain:w600

関連記事

  1. 全体概要
  2. ドメイン取得とRoute53との連携
  3. Let's Encryptで無料の証明書を取得する(この記事)

Let's Encryptとは

Let's Encrypt は、「SSL/TLSサーバ証明書」を無料で発行してくれる認証局(CA)で、以下の特徴があります。

非営利団体の ISRG (Internet Security Research Group) が運営しており、シスコ(Cisco Systems)、Akamai電子フロンティア財団(Electronic Frontier Foundation)、モジラ財団(Mozilla Foundation)などの大手企業・団体が、ISRG のスポンサーとして Let's Encrypt を支援しています。

詳しくは公式サイトを参照してください。
letsencrypt.org

手順

サーバ証明書の取得

(1)"Certbot"を動かす環境を準備する

Certbotが稼働可能なLinuxMacOSUnixを準備してください。Certbotが稼働可能な環境は、Certbotの公式ページを確認してください。
今回は、CertbotではサポートされていないですがAmazon Linux 2上でCertbotを動かします。

  • 動作環境
    • OS: Amazon Linux2
    • AMI amzn2-ami-hvm-2.0.20181114-x86_64-gp2 (ami-0a2de1c3b415889d2)
    • ネットワーク:インターネットと通信できること
(2)"Certbot"のセットアップ

Certbotのセットアップは、こちらのCertbotの公式ページに説明があります。

ただAmazonLinux2はこの手順ではできませんので、以下ではAmazonLinux2で動作するように手順をカスタマイズしています。
(a)前提パッケージのインストール
pythonのvirtualenvというツールを内部で利用しているようなのでそれをインストールします。

sudo yum -y install python-virtualenv

(b)Certbotのインストール
今回は、/usr/local/binにインストールします。

$ sudo wget --directory-prefix=/usr/local/bin https://dl.eff.org/certbot-auto
$ sudo chmod a+x /usr/local/bin/certbot-auto

(c)Certbotのインストレーション実行

$ sudo /usr/local/bin/certbot-auto --no-bootstrap --install-only
Upgrading certbot-auto 0.29.1 to 0.30.0...
Replacing certbot-auto...
Creating virtual environment...
Installing Python packages...
Installation succeeded.
Certbot is installed.
  • オプションの意味
    • "--no-bootstrap" : CertbotはAmazonLinux2を検出してくれないので、検出を無効化するためこのオプションを指定します。
    • "--install-only" : 必要なパッケージのインストールのみ実行するオプションです。
(3)サーバ証明書の取得

準備が整ったらサーバ証明書を取得します。Certbotはengixやapacheなど証明書を利用したいwebソフトと連携させることができますが、今回は複数のサーバに配布するためマニュアルモードで証明書を取得します。

(a)Certbotの実行
証明書取得のためコマンドを実行します。モードはマニュアルで、ドメイン使用権の認証方法としてDNSを利用(DNS サーバのTXT レコードに指定されたキーを設定)しています。*3コマンドの詳細は、"certbot-auto --help all"で参照できます。

$ sudo /usr/local/bin/certbot-auto --no-bootstrap certonly \
     --manual \
     --manual-public-ip-logging-ok \
     --domains '*.poc.nopipi.work' \
     --email admin@poc.nopipi.work \
     --agree-tos;
  • オプションの意味
    • certonly :証明書の取得の取得のみ実施
    • --manual: ドメイン使用権者であることの認証を手動で行うモード
    • --manual-public-ip-logging-ok: 認証局でのパブリックIPロギングの自動許可
    • --domains '*.poc.nopipi.work': 証明書を取得したいドメインの指定。'*.'とするとワイルドカード証明書になる
    • --email : 証明書の期限切れ等をお知らせするメールの宛先を指定
    • --agree-tos: ライセンス条項の同意

(b)DNSレコードの登録
上記(a)を実行すると、下記のようにpoc.nopipi.workのドメインに、_acme-challengeという名前のTXTレコードで、"nmdZ・・・"という値を設定するよう指定がありますので、指示に従ってDNSサーバにTXTレコードを登録します。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.poc.nopipi.work with the following value:

nmdZGYXDo6J0DVtfKMCHwhCaXdjtl0eJuYGN4J0XMQk

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

今回poc.nopipi.workはRoute53を利用しているので、Route53でレコード登録します。

f:id:nopipi:20190106153643p:plain:w600

別コンソールでdigコマンドでレコードが確認できたら、後続に進み証明書を発行します。

$ dig TXT _acme-challenge.poc.nopipi.work 

; <<>> DiG 9.8.3-P1 <<>> TXT _acme-challenge.poc.nopipi.work
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19405
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 3

;; QUESTION SECTION:
;_acme-challenge.poc.nopipi.work. IN	TXT

;; ANSWER SECTION:
_acme-challenge.poc.nopipi.work. 60 IN	TXT	"nmdZGYXDo6J0DVtfKMCHwhCaXdjtl0eJuYGN4J0XMQk"
<以下略>

(c)作成された証明書の確認
"/etc/letsencrypt/live/ドメイン名" のディレクトリ配下にファイルが作成されますので、確認してください。

sudo ls /etc/letsencrypt/live/poc.nopipi.work
cert.pem  chain.pem  fullchain.pem  privkey.pem  README
ファイル名 項目
cert.pem サーバ証明書
privkey.pem 秘密鍵
chain.pem 中間証明書
fullchain.pem 証明書と中間証明書を連結したファイル

apacheサーバへの証明書の組み込み

(1)証明書のコピー

作成した証明書を、apacheをセットアップしているインスタンス内にコピーします。
この手順では、他インスタンスへ証明書をコピーする時作成時と同じディレクトリにデプロイされるものと仮定します。

(2)httpd.confの設定

sslの設定ファイル.ssl.confに取得したサーバ証明書関連のファイルを展示します。

<VirtualHost _default_:443>

中略

SSLCertificateFile /etc/letsencrypt/live/poc.nopipi.work/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/poc.nopipi.work/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/poc.nopipi.work/chain.pem
SSLCACertificateFile /etc/letsencrypt/live/poc.nopipi.work/fullchain.pem

中略

</VirtualHost>
(3)確認

apacheを再起動し、動作確認を行う。

sudo systemctl restart httpd

追伸

この記事を書いた後に気づきましたが、AWSのEC2のユーザガイドにも利用手順ありましたね。
docs.aws.amazon.com

お名前.comでのドメイン取得とRoute 53との連携(お名前.comへのRoute 53DNS登録)

概要

やりたいこと

この記事では「お名前.com」で取得したドメインに任意のサブドメインを作成し、そのサブドメインの管理をAmazon Route53に委任する手順を説明しています。

f:id:nopipi:20190103123159p:plain:w600

お名前.comで取得したドメイン:nopipi.work
Route53に委任するサブドメイン名:poc.nopipi.work

関連記事

  1. 全体概要
  2. ドメイン取得とRoute53との連携(この記事)
  3. Let's Encryptで無料の証明書を取得する

大まかな手順

  1. お名前.comでドメインを取得する
  2. Amazon Route 53で取得したドメイン名のPublic Hosted Zoneを登録する
  3. お名前.comにPublic Hosted ZoneのDNSを登録する

手順

(1) お名前.comでのドメイン取得

お名前.comでのドメイン取得手順は、いろいろなサイトが説明記事を書いているのでこことでは細かい説明はしません。googleで「お名前 ドメイン 取得手順」で検索すると色々情報が出ますので基本そちらを参照してください。
また、お名前.comでドメイン取得する場合の留意事項を以下に列挙します。

(2) Amazon Route 53で取得したドメイン名のPublic Hosted Zoneを登録する*1

  • AWS マネージメントコンソールにログインしてRoute 53サービスに移動する
  • 初めてRoute53を利用する場合はDNS managementを選択、すでに利用がある場合は"Hosted zones"を選択する
  • "Create Hosted"で、お名前.comで取得したドメイン(今回は、poc.nopipi.work)のパブリックホステットゾーンを作成する
    • Domain Nameに、取得したドメイン(poc.nopipi.work)を入力する
    • Typeで、"Public Hosted Zone"を選択する*2
    • "Create"でHosted Zoneを作成する

f:id:nopipi:20190106102255p:plain:w600

  • 作成したPublic Hosted ZoneのNSレコード(DNSサーバ情報)を控える
    • 登録されている4つのNSレコード(DNSサーバ情報)を控えます。
    • 控えたNSレコードはこの後のお名前.comの取得したドメインへのDNSサーバ登録で利用します

f:id:nopipi:20190106102642p:plain:w600

(3) お名前.comへのroute53 DNSサーバ情報登録

Route 53のPublic Hosted Zoneで控えたNSレコードを、お名前.comにて、取得ドメインDNSサーバとして登録します。

  • お名前.comにログインして「ドメイン設定」を選択
  • DNS関連機能の設定」を選択する
  • DNSレコード設定を利用する」を選択する

f:id:nopipi:20181126002631p:plain

  • Route53で控えた4つのNSレコードを下図のように登録する

f:id:nopipi:20190106104032p:plain:w600

(4)確認

(参考)Route53との連携方法

お名前.comで取得したドメインAWS上で利用する方法はいくつかあります。3つの例を下に示します。

管理
主体
方法メリットデメリット
お名前.comお名前.comのレコードへAWSFQDNをCNAME登録する
  • 一番簡単な方法
  • 登録ドメイントップから管理できる
AWSAmazon Route53にドメインを移管する
  • AWSで一元管理できる
下記制約があって移管面倒
  • お名前.com側:登録から60日経過している、whois登録代行を利用していないなど*3
  • AWS側:登録可能なドメインの制限(汎用jp以外、co.jpなどは対象外など)*4
サブドメインをRoute53に委任サブドメインしか管理できない

*1:参考:お名前.comのドメインをAWSで使用する4つの方法 - Qiita

*2:Public Hosted Zoneは外部からドメイン情報が参照される。Private Hosted Zoneは、関連づけられたVPCにのみ情報が参照できる

*3:https://help.onamae.com/app/answers/detail/a_id/8593

*4:Route53に登録可能なドメインこちらを参照

Macが起動しない時の対処方法

起動しなくて困ったので、そんな時の対処方法をメモしておきます。

対処方法

(1) SMCのリセット

Macのハードウェアを管理するSMC(System Management Controller)をリセットする。SMCはバッテリー、熱管理、各種センサー管理をしているユニット。
support.apple.com

(2) NVRAM または PRAM をリセット

NVRAM には、音量、画面解像度、選択されている起動ディスク、時間帯、最近起きたカーネルパニックの情報などが保存されています。この情報をリセットします。
support.apple.com

(3) セーフモードを使って Mac の問題を切り分け

上記でダメなら、セーフモードで原因切り分け。切り分けできなかったらサポートへ。
support.apple.com

RHEL7.1でENA(Elastic Network Adapter)を利用する手順

はじめに

概要

ENA(Elastic Network Adapter)は、シングルルート I/O 仮想化 (SR-IOV) を使用したAWSの拡張ネットワーキングです。RHEL7.1にはこのENAのドライバが含まれていないため、RHEL7.1環境でENAを利用する場合は個別にインストールする必要があります。この記事は、RHEL7.1環境にENAドライバをインストールして利用可能にする手順をまとめたものです。

留意事項

RHEL7でENAがサポートしているのは、RHEL7.4以降になります。RHEL7.1ではENAサポートされていないため、その点は留意下さい。

確認環境

  • リージョン: 東京リージョン
  • 利用AMI: RHEL-7.1_HVM_GA-20150225-x86_64-1-Hourly2-GP2 (ami-b1b458b1)
  • 利用インスタンス: m4.16xlarge

ENAドライバインストール手順

RHEL7.1をm4インスタンスで起動してenaをインストールします。

RHEL7.1の初期状態の確認

(1)RHELカーネルバージョン、AMI/インスタンスタイプ確認

$ cat /proc/version 
Linux version 3.10.0-229.el7.x86_64 (mockbuild@x86-035.build.eng.bos.redhat.com) (gcc version 4.8.3 20140911 (Red Hat 4.8.3-7) (GCC) ) #1 SMP Thu Jan 29 18:37:38 EST 2015

$  curl http://169.254.169.254/latest/meta-data/ami-id;echo
ami-b1b458b1

$ curl http://169.254.169.254/latest/meta-data/instance-type;echo
m4.16xlarge

(2) enaドライバの確認
RHEL7.1でAMIからインスタンスを起動した状態では、enaドライバがないことを確認します。

$ sudo modinfo ena
modinfo: ERROR: Module ena not found.

enaドライバのビルドとインストール

(1)必要なrpmパッケージのインストール

git、 makeコマンド、gccコマンドなど必要なrpmパッケージをインストールします。また、gitが内部で利用するcurlのバージョンが古くgitが動作しないので、curlだけrpmをアップデートします。

$ sudo yum -y update curl
$ sudo yum -y install git make gcc
$ sudo yum -y install kernel-devel-$(uname -r)
(2)enaドライバのソースをgitから取得

マニュアル*1の内容に従いgitからコードをダウンロードします。

$ git clone https://github.com/amzn/amzn-drivers
(3)ビルド
$ cd amzn-drivers/kernel/linux/ena
$ make
(4)動作確認
$ sudo insmod ena.ko
$ lsmod |grep ena
ena                    98319  0  <==ドライバが組み込まれていることを確認
$ sudo rmmod ena
$ lsmod |grep ena
(5)インストール

(a) modprobeのカーネルモジュールロード設定追加

$ sudo sh -c 'cat >  /etc/modules-load.d/ena.conf'
ena

(b) モジュールのコピー・依存関係の更新・dracutの更新

$ sudo cp ena.ko /lib/modules/$(uname -r)/
$ sudo depmod
$ sudo dracut -f -v
(6)動作確認
$ sudo shutdown -r 0
<SSHログイン後>
$ cat /proc/version 
Linux version 3.10.0-229.el7.x86_64 (mockbuild@x86-035.build.eng.bos.redhat.com) (gcc version 4.8.3 20140911 (Red Hat 4.8.3-7) (GCC) ) #1 SMP Thu Jan 29 18:37:38 EST 2015
$ lsmod|grep ena
ena                    98319  0 
(7)起動オプションの追加

最近のsystemdやudevでのデバイス命名は、enp5s0のような一貫性のある命名をします*2RHELのAMIから起動した場合は従来のeth0のようなデバイス名称を継続利用するために、このデバイス命名の一貫性の機能を無効化します。
(a) Grubのテンプレートファイルに設定を追加
起動オプションに、"net.ifnames=0"を追加します。

GRUB_TIMEOUT=1
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto console=ttyS0,115200n8 console=tty0 net.ifnames=0"
GRUB_DISABLE_RECOVERY="true"

(b)grub2設定更新

$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg
$ sudo shutdown -r 0

インスタンスのENA有効化

インスタンスがstopの状態で、modify-instance-attributeでENAを有効化します。そして有効化後にインスタンスを起動します。

$ aws ec2 modify-instance-attribute --instance-id i-0180f9795f32bf2c1 --ena-support
$ aws --profile dev1 ec2 start-instances  --instance-ids i-0180f9795f32bf2c1

確認

dmesgやmessagesで状態を確認します。

(1)dmesg
[   22.879003] ena: module verification failed: signature and/or required key missing - tainting kernel
[   22.883928] ena: Elastic Network Adapter (ENA) v2.0.2g
[   22.884033] ena 0000:00:03.0: Elastic Network Adapter (ENA) v2.0.2g
[   22.890297] ena: ena device version: 0.10
[   22.890299] ena: ena controller version: 0.0.1 implementation version 1
[   22.938296] ena 0000:00:03.0: LLQ is not supported Fallback to host mode policy.
[   22.938397] ena 0000:00:03.0: creating 8 io queues. rx queue size: 1024 tx queue size. 1024 LLQ is DISABLED
[   22.943929] ena 0000:00:03.0: Elastic Network Adapter (ENA) found at mem f3000000, mac addr 06:b9:68:b9:70:b2 Queues 8, Placement policy: Regular

"ena: Elastic Network Adapter (ENA) v2.0.2g"以下の行で、enaがロードされ初期化されているのがわかります。

(2)/var/log/messages
Dec 10 01:13:54 ip-10-0-0-136 NetworkManager[1190]: <info>  (eth0): carrier is OFF (but ignored)
Dec 10 01:13:54 ip-10-0-0-136 NetworkManager[1190]: <info>  (eth0): new Ethernet device (driver: 'ena' ifindex: 2)
Dec 10 01:13:54 ip-10-0-0-136 NetworkManager[1190]: <info>  (eth0): exported as /org/freedesktop/NetworkManager/Devices/0
Dec 10 01:13:54 ip-10-0-0-136 NetworkManager[1190]: <info>  (eth0): device state change: unmanaged -> unavailable (reason 'managed') [10 20 2]
(3) sysfs
$ ll /sys/class/net/eth0/
total 0
-r--r--r--.  1 root root 4096 Dec 10 02:23 addr_assign_type
-r--r--r--.  1 root root 4096 Dec 10 02:23 address
-r--r--r--.  1 root root 4096 Dec 10 02:28 addr_len
-r--r--r--.  1 root root 4096 Dec 10 02:28 broadcast
-rw-r--r--.  1 root root 4096 Dec 10 02:28 carrier
lrwxrwxrwx.  1 root root    0 Dec 10 02:23 device -> ../../../0000:00:03.0
-r--r--r--.  1 root root 4096 Dec 10 02:23 dev_id
-r--r--r--.  1 root root 4096 Dec 10 02:23 dev_port
-r--r--r--.  1 root root 4096 Dec 10 02:28 dormant
-r--r--r--.  1 root root 4096 Dec 10 02:28 duplex
-rw-r--r--.  1 root root 4096 Dec 10 02:28 flags
-rw-r--r--.  1 root root 4096 Dec 10 02:28 ifalias
-r--r--r--.  1 root root 4096 Dec 10 02:23 ifindex
-r--r--r--.  1 root root 4096 Dec 10 02:23 iflink
-r--r--r--.  1 root root 4096 Dec 10 02:28 link_mode
-rw-r--r--.  1 root root 4096 Dec 10 02:28 mtu
-rw-r--r--.  1 root root 4096 Dec 10 02:28 netdev_group
-r--r--r--.  1 root root 4096 Dec 10 02:28 operstate
-r--r--r--.  1 root root 4096 Dec 10 02:23 phys_port_id
drwxr-xr-x.  2 root root    0 Dec 10 02:28 power
drwxr-xr-x. 18 root root    0 Dec 10 02:23 queues
-r--r--r--.  1 root root 4096 Dec 10 02:28 speed
drwxr-xr-x.  2 root root    0 Dec 10 02:28 statistics
lrwxrwxrwx.  1 root root    0 Dec 10 02:23 subsystem -> ../../../../../class/net
-rw-r--r--.  1 root root 4096 Dec 10 02:28 tx_queue_len
-r--r--r--.  1 root root 4096 Dec 10 02:23 type
-rw-r--r--.  1 root root 4096 Dec 10 02:23 uevent

eth0に対応するハードウェアが、PCIの"0000:00:03.0”であることを確認し、次じそのデバイス情報を参照します。すると下記の通り、”driver -> ../../../bus/pci/drivers/ena”をドライバとして利用していることがわかり、結果eht0はenaであることが確認できます。

$ ll /sys/devices/pci0000\:00/0000\:00\:03.0/
total 0
-rw-r--r--. 1 root root  4096 Dec 10 02:26 broken_parity_status
-r--r--r--. 1 root root  4096 Dec 10 02:23 class
-rw-r--r--. 1 root root   256 Dec 10 02:23 config
-r--r--r--. 1 root root  4096 Dec 10 02:26 consistent_dma_mask_bits
-rw-r--r--. 1 root root  4096 Dec 10 02:26 d3cold_allowed
-r--r--r--. 1 root root  4096 Dec 10 02:23 device
-r--r--r--. 1 root root  4096 Dec 10 02:26 dma_mask_bits
lrwxrwxrwx. 1 root root     0 Dec 10 02:23 driver -> ../../../bus/pci/drivers/ena
-rw-r--r--. 1 root root  4096 Dec 10 02:26 enable
lrwxrwxrwx. 1 root root     0 Dec 10 02:26 firmware_node -> ../../LNXSYSTM:00/device:00/PNP0A03:00/device:1b
-r--r--r--. 1 root root  4096 Dec 10 02:26 irq
-r--r--r--. 1 root root  4096 Dec 10 02:26 local_cpulist
-r--r--r--. 1 root root  4096 Dec 10 02:23 local_cpus
-r--r--r--. 1 root root  4096 Dec 10 02:26 modalias
-rw-r--r--. 1 root root  4096 Dec 10 02:26 msi_bus
drwxr-xr-x. 2 root root     0 Dec 10 02:23 msi_irqs
drwxr-xr-x. 3 root root     0 Dec 10 02:23 net
-r--r--r--. 1 root root  4096 Dec 10 02:23 numa_node
drwxr-xr-x. 2 root root     0 Dec 10 02:26 power
--w--w----. 1 root root  4096 Dec 10 02:26 remove
--w--w----. 1 root root  4096 Dec 10 02:26 rescan
-r--r--r--. 1 root root  4096 Dec 10 02:26 resource
-rw-------. 1 root root 16384 Dec 10 02:26 resource0
-rw-r--r--. 1 root root  4096 Dec 10 02:26 rx_copybreak
lrwxrwxrwx. 1 root root     0 Dec 10 02:23 subsystem -> ../../../bus/pci
-r--r--r--. 1 root root  4096 Dec 10 02:26 subsystem_device
-r--r--r--. 1 root root  4096 Dec 10 02:26 subsystem_vendor
-rw-r--r--. 1 root root  4096 Dec 10 02:23 uevent
-r--r--r--. 1 root root  4096 Dec 10 02:23 vendor

RHUIとredhat社のインストールメディアのrpmパッケージファイルの中身に差異があるか確認してみた→結果差異はない

概要

RHUIとredhat社がカスタマーポータルで提供しているrpmパッケージの中身に差異があるのかどうかという話があったので、2つのファイルのdiffをとって確かめてみた。
→結果、差異はなかった。

確認方法

  • redhat社のカスタマーポータルRHEL7.5のDVDを取得(Red Hat Enterprise Linux 7.5 Binary DVD)
  • DVDの/Packagesの下にあるrpmパッケージファイルをを一覧化
  • その一覧を元に、AWS上のRHELインスタンスからyumdownloaderでRHUIの同じ種類・バージョン・アーキテクチャのファイルをダウンロード
  • DVDとRHUIのファイルをdiffコマンドで差分の有無を確認

確認手順詳細

(1)redhatのカスタマーポータルからISOを落とす
f:id:nopipi:20181208174231p:plain
ここから、下記のisoをダウンロード
f:id:nopipi:20181208174235p:plain
(2)ISOをループバックマウントして、rpmファイルをリスト化
RHELのサーバにダウンロードしたisoをコピーして、

mkdir dvd
sudo mount -o loop rhel-server-7.5-x86_64-dvd.iso dvd
find dvd/Packages/ -name '*.rpm' > rpmlist

(3)RHUIから同じrpmをダウンロード
リストを元にyumdownloaderでRHUIからrpmファイルを取得する以下のようなスクリプトを作成

sudo yumdownloader 389-ds-base-1.3.7.5-18.el7.x86_64
sudo yumdownloader 389-ds-base-libs-1.3.7.5-18.el7.x86_64
sudo yumdownloader ElectricFence-2.2.2-39.el7.x86_64
sudo yumdownloader ElectricFence-2.2.2-39.el7.i686
sudo yumdownloader GConf2-3.2.6-8.el7.i686
sudo yumdownloader GConf2-3.2.6-8.el7.x86_64
sudo yumdownloader GeoIP-1.5.0-11.el7.i686
sudo yumdownloader GeoIP-1.5.0-11.el7.x86_64
sudo yumdownloader ImageMagick-c++-6.7.8.9-15.el7_2.i686
sudo yumdownloader ImageMagick-c++-6.7.8.9-15.el7_2.x86_64
sudo yumdownloader ImageMagick-perl-6.7.8.9-15.el7_2.x86_64
以下略

上記スクリプトを適用に分割して、パラレル実行してrpmパッケージをダウンロード
(4)ダウンロードしたファイルをrpmディレクトリに移動

mkdir rpm
mv *.rpm rpm

(5)diffで差分があるか確認

for i in $(cat rpmlist);do file=$(basename $i);diff $i rpm/$file;done

結果

rpmパッケージファイルの中身には差分なし

yumで特定のバージョンのrpmパッケージとそのパッケージの依存パッケージをダウンロードする

RHELで、yumレポジトリに接続できない環境のRHELを、最新版でない特定バージョンのカーネルにあげたいという話があり検証した結果です。

1.検証概要

  • やること:隔離された環境のRHEL7.2(3.10.0-327.el7)をRHEL7.5相当のカーネル(3.10.0-862.14.4)にアップデートする
  • 検証利用AMI:RHEL-7.2_HVM_GA-20151112-x86_64-1-Hourly2-GP2

検証概要:代替えインスタンスでRHUIからrpmをyumdownloaderでダウンロードして、転送してrpmコマンドでアップロードする

2.手順

2.1 代替えインスタンでのrpmパッケージダウンロード

(1)作業用インスタンスとして、RHEL7.2のインスタンスを作成する

インターネット接続が可能なVPCのパブリックサブネット状に、コミュニティAMI(RHEL-7.2_HVM_GA-20151112-x86_64-1-Hourly2-GP2 )からインスタンスを作成する。

(2) yumdownloaderのインストール

代替えインスタンスログイン後、まずは必要なコマンドをインストールする

sudo yum -y install yum-utils
(3) rpm作業用ディレクトリ作成
mkdir update_packages
cd update_packages && pwd
(4) 対象カーネルrpmを確認

(a) アップデートしたいカーネルバージョンがRHUIにあるかを確認

sudo yum --showduplicate list kernel
  • "--showduplicate"はリポジトリで利用可能な全てのバージョンを表示するオプションです(通常は最新バージョンのみ表示)

(b) 該当バージョンのパッケージ名称の確認

sudo yum list kernel-3.10.0-862.14.4.el7
(5)対象rpmパッケージをダウンロードする
sudo yumdownloader --resolve kernel-3.10.0-862.14.4.el7
  • "--resolve”が、依存関係をチェックして必要なパッケージをまとめてダウンロードするオプションです。
(6)対象rpmパッケージを対象インスタンスに転送
cd ..
tar czf update_packages.tar.gz update_packages

なんらかの方法で作成したupdate_packages.tar.gzを、アップデート対象インスタンスに持ち込む

2.2 アップデート対象インスタンでアップデート

(1)現状のカーネルバージョンの確認

アップデート対象インスタンスログイン後に、

cat /proc/version 
Linux version 3.10.0-327.el7.x86_64 (mockbuild@x86-034.build.eng.bos.redhat.com) (gcc version 4.8.3 20140911 (Red Hat 4.8.3-9) (GCC) ) #1 SMP Thu Oct 29 17:29:29 EDT 2015
(2)rpmパッケージの準備
tar xzf update_packages.tar.gz 
cd update_packages
(3) カーネルアップデート
sudo rpm -U *.rpm
(4) リブートしてバージョンを確認
sudo shutdown -r 0
<再ログイン後>
cat /proc/version
Linux version 3.10.0-862.14.4.el7.x86_64 (mockbuild@x86-040.build.eng.bos.redhat.com) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-28) (GCC) ) #1 SMP Fri Sep 21 09:07:21 UTC 2018

EC2 A1(ARM base:AWS Graviton Processors)インスタンスを見てみる

今日Re:Inventで発表されたA1インスタンスのcpuinfoとかを見てみますた。
こちらのインスタンスの特徴は、AWS Graviton ProcessorsというAWS謹製のARMプロセッサを利用し、低消費電力

確認環境

  • インスタンスタイプ: a1.xlarge
  • AMI:amzn2-ami-hvm-2.0.20181114-arm64-gp2 (ami-00d2a06d6dd390d70) ARM版のAMZ2
  • リージョン: N.Virginia

まずはdmesg

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 4.14.77-81.59.amzn2.aarch64 (mockbuild@ip-10-0-3-22) (gcc version 7.3.1 20180303 (Red Hat 7.3.1-5) (GCC)) #1 SMP Mon Nov 12 21:28:57 UTC 2018
[    0.000000] Boot CPU: AArch64 Processor [410fd083]

AArch64 Processorとあって、まあ”ARM 64bit”てことがわかりますね。当たり前ですが。

/proc/cpuinfo

[ec2-user@ip-172-31-27-144 ~]$ cat /proc/cpuinfo 
processor	: 0
BogoMIPS	: 166.66
Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
CPU implementer	: 0x41
CPU architecture: 8
CPU variant	: 0x0
CPU part	: 0xd08
CPU revision	: 3

以下略

ここで注目すべきは"CPU part : 0xd08"。ARM社のページ情報によると、こちらは"Cortex-A72 processor”の設計を利用していることがわかります。"Cortex-A72 processor"は、こちらwikipediaページによると" ARMv8-A 64-bit instruction set designed by ARM Holdings. "とあるので、ARMが設計した64bit ARM(ARMv8-A 64-bit instruction set)のプロセッサをベースとしていそうですね。
"Cortex-A72 processor”は、2015年にARMが発表した64bitのARMのCPU コア IP で、Android携帯のCPUで有名な Qualcomm, Inc.のSnapdragon(Snapdragon 650)で利用されてたりします。 こちらをみると、Xperiaの一部機種で採用されているようで、スマートホンのCPUがサーバに入っていると考えると、オッ!!と思いますよね。

ECRにdockerログインしてImageをpush/pullしたりリポジトリやイメージ一覧取得)する手順

ECRにログインする

awsコマンドでECRにログインするためのdockerの認証情報を取得してログインします。

$(aws ecr get-login --no-include-email)

実行すると認証用のdockerコマンドの文字列(docker login ....)が出力されるので、それをシェルのコマンド置換"$(...)"を利用してそのまま実行してdockerログインします。

ECRにリポジトリを作成する

awsコマンドの"aws ecr create-repository"でECRのリポジトリを作成します。その際に後続のpushで利用するので、 "repositoryUri"を控えておきます。

aws ecr create-repository --repository-name sample-app
{
    "repository": {
        "registryId": "xxxxxxxxxxxx", 
        "repositoryName": "sample-app", 
        "repositoryArn": "arn:aws:ecr:ap-northeast-1:xxxxxxxxxxxx:repository/sample-app", 
        "createdAt": xxxxxxxxxxxx.0, 
        "repositoryUri": "xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/sample-app"
    }
}

ECRにイメージをpushする

(1)dockerイメージの確認
"docker images"コマンドでイメージ一覧を取得しpushするdockerイメージを確認する。今回は、sample-appをpushする。

docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
sample-app          latest              688a2109cc33        23 minutes ago      368MB
php                 7.0-apache          8e2efe9163dd        10 days ago         368MB
centos              latest              75835a67d134        2 weeks ago         200MB

(2)push用のtag付け
リポジトリにプッシュするイメージにタグを付けます。 "sample-app:latest"を"[repositoryUri]:latest"にタグ付けします。

docker tag sample-app:latest xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/sample-app:latest

(3)ECRへのdockerイメージpush
作成したタグを利用してECRのレポジトリにpushします。

docker push xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/sample-app:latest

(4)ECRレポジトリのイメージ確認
awsコマンド”aws ecr describe-images”でpushしたイメージを確認します。

aws ecr describe-images --repository-name sample-app

(5)(オプション)ローカルのdockerイメージ削除
必須でないですが、ローカルのdockerイメージを削除する場合は"docker rmi -f [Image ID] [Image ID] [Image ID]"コマンドで削除します。

ECRからイメージをpullする

ECRのレポジトリとイメージを確認する

(1)ECRレポジトリを確認する
aws ecr describe-repositories”コマンドでレポジトリ一覧を取得して、"repositoryUri"を確認します。

aws ecr describe-repositories
{
    "repositories": [
        {
            "registryId": "xxxxxxxxxxxx", 
            "repositoryName": "sample-app", 
            "repositoryArn": "arn:aws:ecr:ap-northeast-1:xxxxxxxxxxxx:repository/sample-app", 
            "createdAt": xxxxxxxxxxxx.0, 
            "repositoryUri": "xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/sample-app"
        }
    ]
}

(2)対象レポジトリ内のイメージを確認する
aws cliの”aws ecr describe-images --repository-name php-sample”コマンドでレポジトリ一覧を取得して"imageTags"を確認します。

aws ecr describe-images --repository-name sample-app
{
    "imageDetails": [
        {
            "imageSizeInBytes": 133346056, 
            "imageDigest": "sha256:8401bb0035eedc2f101d96eabdf9ed37269f76f14daed080fe924d54d9772037", 
            "imageTags": [
                "latest"
            ], 
            "registryId": "xxxxxxxxxxxx", 
            "repositoryName": "sample-app", 
            "imagePushedAt": xxxxxxxxxxxx.0
        }
    ]
}

docker pullする

(1)dockerコマンドで、"docker pull [repositoryUri]:[Tag]"でイメージをpullします。

docker pull xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/sample-app:latest

(2)"docker images"でpullしたイメージを確認する

docker images
REPOSITORY                                                     TAG                 IMAGE ID            CREATED             SIZE
xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/sample-app   latest              688a2109cc33        About an hour ago   368MB

S3クロスリージョンレプリケーションのレプリ時間を計測してみた

はじめに

あるシステムで東京リージョンとシンガポールリージョンで、S3のクロスリージョンレプリケーション構成を組んだディザスターリカバリーを検討しているのですが、DR計画のRPOの話の延長でレプリケーションの遅延時間てどれぐらいなんだろうねぇ〜という話があって、そんなにかからないだろうなという感覚はありつつ、確認したことがなかったので試しに測定してみました。

検証結果

(1)オブジェクトサイズとレプリケーション時間の関係

f:id:nopipi:20181112234614p:plain

  • オブジェクトサイズとレプリケーションの転送時間は比例関係であることを確認(リージョン間のネットワーク帯域に依存するということですね。当然ですが)
  • 1GBのオブジェクトで20秒〜1分程度、10GBのオブジェクトで3〜4分、80GBのオブジェクトになると15〜30分程度
(2)測定結果から見えるインスタンスからのPUTとレプリケーションの挙動

測定結果を見ると、インスタンスのPUT完了時間と、レプリケーションの状態がPENDINGになるのがほぼ同時刻になっていました。そのことから、インスタンスからS3バケットへのPUT処理が完了し、バケット上で新しいオブジェクトにアクセスできるようになったタイミングからレプリケーション処理が始まっているように見えます。

f:id:nopipi:20181112235946p:plain:w500

構成概要

検証構成は以下の通りです。(新しいシンプルアイコンで書いてみました)

f:id:nopipi:20181112223110p:plain:w450

検証手順

VPCに作成したインスタンスから検証用のファイルをS3バケットにPUTします。クロスリージョンレプリケーションの転送処理は、オブジェクトのレプリケーション状態をチェックしてPENDIG状態になっていた時間を測定し、その時間をレプリケーションの転送時間と皆しています。

(1)S3クロスリージョンレプリケーションの設定

下記のドキュメントなどを参考にS3バケット作成&バージョニング有効化と、クロスリージョンレプリケーションの設定をします。下記の手順ではIAMロールを手動作成するようになっていますが、マネージメントコンソールで設定する場合、IAMロース選択で「Create new role」を選ぶと必要なIAMロールを自動作成してくれます。

(2)インスタンスの準備

(a)インスタンスの選択

今回はインスタンスのネットワーク帯域やディスクIOネックならないようにするため、m5d.24xlargeを選択しています。

  • m5d.24xlargeの特徴
    • ネットワーク帯域: 25Gbps*1
    • ディスク:SSD インスタンスストアボリュームによる高IO性能

またcrr-source-bucket-xxバケットへのフルアクセスを行うIAMロールをこのインスタンスに付与しています。

(b)jqのインストール

jqをインストールします。(検証用ツール(シェルスクリプト)の中でjq コマンドを使っているので)

sudo yum -y install jq
(c)作業用インスタンスストアボリュームのフォーマット

インスタンスストアボリュームはインスタンス起動時に初期化しなければならないため、初期化します。

sudo mkfs -t xfs /dev/nvme1n1
mkdir a
sudo mount /dev/nvme1n1 ./a
sudo chown -R ec2-user:ec2-user a

(3)検証用ダミーファイル(S3へのPut用)の準備

10MBから2倍づつサイズを増やし80GBまでのS3へのPut用ファイルを作成します。ファイルはOSやVP内部の何らかの圧縮処理による影響(があった場合)を排除するために、urandomデバイスかの乱数データから作成しています。(乱数は情報のエントロピーが高く圧縮率が低くなるため、圧縮効果を極力排除することができます。逆にゼロが連続するようなデータは情報エントロピーが低くく圧縮効率が高いため、検証結果に圧縮効果の影響が出る可能性が高くなります)

cd a && mkdir data && cd data
nohup dd if=/dev/urandom  of=test_data-10M bs=1048576 count=10 &
nohup dd if=/dev/urandom  of=test_data-20M bs=1048576 count=20 &
nohup dd if=/dev/urandom  of=test_data-40M bs=1048576 count=40 &
nohup dd if=/dev/urandom  of=test_data-80M bs=1048576 count=80 &
nohup dd if=/dev/urandom  of=test_data-160M bs=1048576 count=160 &
nohup dd if=/dev/urandom  of=test_data-320M bs=1048576 count=320 &
nohup dd if=/dev/urandom  of=test_data-640M bs=1048576 count=640 &
nohup dd if=/dev/urandom  of=test_data-1.3G bs=1048576 count=1280 &
nohup dd if=/dev/urandom  of=test_data-2.5G bs=1048576 count=2560 &
nohup dd if=/dev/urandom  of=test_data-5G bs=1048576 count=5120 &
nohup dd if=/dev/urandom  of=test_data-10G bs=1048576 count=10240 &
nohup dd if=/dev/urandom  of=test_data-20G bs=1048576 count=20480 &
nohup dd if=/dev/urandom  of=test_data-40G bs=1048576 count=40960 &
nohup dd if=/dev/urandom  of=test_data-80G bs=1048576 count=81920 &
cd ..

(4)検証用スクリプトの準備

下記のスクリプトを "a"フォルダに格納し、実行権限を付与(chmod +x *.sh)します

(a)検証用コード
  • test.sh
#!/bin/sh

DATADIR="./data"
LOGGINGSH="./logging.sh"
SRCBUCKET="crr-source-bucket-xx"
SRCBUCKETURI="s3://${SRCBUCKET}"


for t in $(seq 1 10)
do
    for size in 10M 20M 40M 80M 160M 320M 640M 1.3G 2.5G 5G 10G 20G 40G 80G
    #for size in 10M 20M
    do
        TFILE="test_data-${size}-${t}"
        REPLILOG="replicate-${TFILE}.log"
        PUTLOG="put-${TFILE}.log"
        nohup ${LOGGINGSH} ${SRCBUCKET} ${TFILE} > replicate-${TFILE}.log &

        # put object
        date > ${PUTLOG}
        echo aws s3 cp "${DATADIR}/test_data-${size}" ${SRCBUCKETURI}/${TFILE}
        echo aws s3 cp "${DATADIR}/test_data-${size}" ${SRCBUCKETURI}/${TFILE} >> ${PUTLOG}
        aws s3 cp "${DATADIR}/test_data-${size}" ${SRCBUCKETURI}/${TFILE} 
        date >> ${PUTLOG}
    done
done
(b)検証コードから呼び出されるレプリケーション状態をロギングするコード
  • logging.sh
#!/bin/sh

bucket=$1
file=$2
stat=NULL

while true;
do
    A=$(date); 
    B=$(aws s3api head-object --bucket ${bucket} --key ${file} |jq '.ReplicationStatus')
    if [ "A${stat}" = "ANULL" -a "A${B}" = "A\"PENDING\"" ]; then stat="PENDING";fi

    echo ${A} ${B} ${file}

    if [ "A${stat}" = "APENDING" -a "A${B}" = "A\"COMPLETED\"" ]; then break; fi
done
(c)検証事前準備
  • put_zerofiles.sh
#!/bin/sh

DATADIR="./data"
LOGGINGSH="./logging.sh"
SRCBUCKET="s3://crr-source-bucket-xx"
ZEROFILE="dummy.dat"

touch dummy.dat

for t in $(seq 1 10)
do
    for size in 10M 20M 40M 80M 160M 320M 640M 1.3G 2.5G 5G 10G 20G 40G 80G
    do
        TFILE="test_data-${size}-${t}"
        REPLILOG="replicate-${TFILE}.log"
        PUTLOG="put-${TFILE}.log"

        # put object
        aws s3 cp ${ZEROFILE} ${SRCBUCKET}/${TFILE} 
        date >> ${PUTLOG}
    done
done

(5)ファイルの設置

測定の関係で同名称のファイルをcrr-source-bucket-xxバケットに事前配置します。

./put_zerofiles.sh

(6)測定

測定します。2〜3時間がかかるので寝かせておきます。

nohup ./test.sh

(7)結果の集計

測定が終わったら、下記の分析シェルで実行ログを分析します。

(a) インスタンスからS3へのオブジェクトput時間の分析シェル
  • analysis1.sh
#!/bin/sh

for size in 10M 20M 40M 80M 160M 320M 640M 1.3G 2.5G 5G 10G 20G 40G 80G
#for size in 10M 20M
do
    for t in $(seq 1 10)
    do
        TFILE="test_data-${size}-${t}"
        REPLILOG="replicate-${TFILE}.log"
        PUTLOG="put-${TFILE}.log"

        S=$(head -1 ${PUTLOG})
        E=$(tail -1 ${PUTLOG}) 
        echo "${TFILE}, $S, $E"
    done
done
(b) レプリケーションPENDIG時間の分析
  • analysis2.sh
#!/bin/sh

for size in 10M 20M 40M 80M 160M 320M 640M 1.3G 2.5G 5G 10G 20G 40G 80G
#for size in 10M 20M
do
    for t in $(seq 1 10)
    do
        TFILE="test_data-${size}-${t}"
        REPLILOG="replicate-${TFILE}.log"
        PUTLOG="put-${TFILE}.log"

        grep PENDING $REPLILOG > /tmp/xxx
        S=$(head -1 /tmp/xxx)
        E=$(tail -1 /tmp/xxx) 
        echo "${TFILE}, $S, $E"

    done
done