AWS EFSのファイル読み込みのスループットを計測する

AWS EFS Oregon regionのファイル読み込みのスループットを計測する。複数のEC2から同時にファイルを読み込んだ場合のスループットも計測する。

また、すべてのEFSは100 MiB/秒のスループットまでバーストするとマニュアルに記載があるが、読み込み時にバーストされているか確認する。

 

方法 

1. EFSを立ち上げる。5GBのファイルをEFSに配置。

2. EC2 を立ち上げる。5GBのファイルをEFS⇨EC2へコピーする。

3. コピーにかかった時間を計測する。転送速度を算出する。

 

マシンスペック 

EFS

Performance mode Max I/O,

Encrypted No,

Metered size 105GB,

Availability zone us-west-2a 

EC2

AMI ubuntu-xenial-16.04-amd64-server-20180522 (ami-db710fa3),

Instance type m4.large,

volume tpye gp2 (8GB),

Availability zone us-west-2a 

・マウントにはEFS Mountを使用した。

・Metered sizeが大きいほどスループットのバースト時間は長くなる。そのためEFSにファイルを>100GB 配置している。

  • Burst to 100 MiB/s for up to 72 minutes each day, or

  • Drive up to 5 MiB/s continuously

 英文は下のサイト(マニュアル)から引用

https://docs.aws.amazon.com/efs/latest/ug/performance.html

・EC2がスループットボトルネックにならないようなスペックにしている。

 

結果

EC2の数 ave(real time) スループット (EC2 1台あたり) スループット * EC2の数
1 93.51 53.47MiB/s 53.47MiB/s
2 101.95 49.04MiB/s 98.08MiB/s
4 203.33 25.49MiB/s 101.96MiB/s
8 407.73 12.26MiB/s 98.08MiB/s

・EFSは100MiB/sの回線を共有して使用する。(バースト時)
・EC2 1台だと50MiB/sくらい。100MiB/sの速度はでない。
スループットはave(real time)から算出しているため、実際のスループットとは数MiBのズレがある。 

マニュアルをみてもファイルシステムごとに100 MiB/sのスループットが使用できるという認識で間違いないと思う。

All file systems, regardless of size, can burst to 100 MiB/s of throughput, and those over 1 TiB large can burst to 100 MiB/s per TiB of data stored in the file system. For example, a 10 TiB file system can burst to 1,000 MiB/s of throughput (10 TiB x 100 MiB/s/TiB).

 英文は下のサイト(マニュアル)から引用
https://docs.aws.amazon.com/efs/latest/ug/performance.html

 

結果詳細

EC2 1台

# real time user time sys time
1 93.51 0.01 5.26

EC2 2台で同時読み込み

# real time user time sys time
1 101.76 0.00 4.69
2 102.14 0.00 4.85

EC2 4台で同時読み込み

# real time user time sys time
1 202.66 0.00 4.96
2 203.27 0.00 4.81
3 203.62 0.00 4.89
4 203.77 0.02 4.98

EC2 8台で同時読み込み

# real time user time sys time
1 405.71 0.00 5.08
2 406.76 0.00 4.91
3 407.62 0.00 4.90
4 407.72 0.02 5.05
5 407.89 0.00 4.95
6 408.54 0.02 5.30
7 408.74 0.02 5.15
8 408.91 0.00 5.10

 

バーストクレジットについて

Cloud WatchのBurstCreditBalanceとPermittedThroughputを使用すると理解しやすい。

BurstCreditBalance

・データコピーを実施したらバーストクレジットが減っていった。

・データコピーをしていないときはバーストクレジットが回復していく。Metered size が10GBより100GBの方が回復量が大きい。

PermittedThroughput

・EFSの最大スループットが表示される。今回はクレジットに余裕があったため、105MB/sから下がることはなかった。

 

メモ

・EFSにファイルを配置したからといって、即座にMetered sizeが増えるわけではない。どこかのタイミングでディスク使用量が増える。

・EFSへの大量のアクセスが予想されたため、Max I/Oを選択したが、マニュアルの「Using The Right Performance Mode」を実施しGeneral Purpose Performance Modeが使用可能であるかチェックするべきであった。

https://docs.aws.amazon.com/efs/latest/ug/performance.html

・EFSでは英語版のマニュアルが日本語版よりかなり充実している。

 

 

Azure Batch サンプルプログラムのカスタマイズ

目的

Azure Batchのpythonサンプルプログラムを、ゲノムシークエンスデータ解析に使いやすいようにカスタマイズしたのでメモしておく。

 

カスタマイズしたプログラム

github.com

オリジナルのサンプルプログラム

github.com

 

azurebatchmonの実行環境

Azure 仮想マシン Standard DS1 v2 (1 vcpu、3.5 GB メモリ)  Ubuntu

 

Azureのアカウントが必要

・Azure アカウント (メインのアカウント)
・Azure Batchアカウント( Azure Portal で Batch アカウントを作成する | Microsoft Docs 
・ストレージアカウント( Azure Portal でストレージ アカウントを作成… | Microsoft Docs 

 

Pythonのモジュールのインストール

# azure-batchとazure-strageにアクセスするためのpythonパッケージ
pip install azure-batch
pip install azure-storage

  

Azurebatchmon概要

f:id:ken0-1n:20180403134741p:plain

事前準備

リファレンスゲノム、FASTQ Fileと実行ScriptをAzureストレージにアップロードしておく。Docker imageをDockerHubに登録しておく

1.AzurebatchのJobを作成

2.Azurebatchのpoolを作成

3.タスク(実行するプログラム)の登録

  Azureストレージから解析に必要なデータをダウンロード

  docker imageをpullしてくる

  解析処理の実行

4.タスクをモニタリングする

5.解析が完了したら、結果をAzure Storageにアップロードする

 

オリジナルpythonスクリプトの説明はこちら

Azure クイック スタート - Batch ジョブの実行 - Python | Microsoft Docs

 

 

カスタマイズのポイント

1.シークエンスデータは数十~数百GBのビックデータなのでローカルからのアップロードはしない

ゲノムデータはストレージに置いておく。Microsoft Genomicsもデータはストレージはじまりでストレージ終わり。このやり方が無難。

 

2.ストレージのデータに対するダウンロードとアップロードにazcopyを使う。

azcopyの利点

・recursiveが可能

・Storageアカウント、コンテナ名とファイル名を1つのpathとして記載できるので便利。(cliだとファイル名とは別にコンテナ名を指定する必要があった)

・destに指定したファイルパスに、ディレクトリがない場合は作成される

 

サンプルコード(ダウンロード
azcopy \
--source https://storage_account.file.core.windows.net/my_container/ \
--destination /mnt \
--source-key storage_account_key \
--recursive

サンプルプログラムにあるTaskAddParameterを用いてストレージからのファイルダウンロードは、recursiveができないっぽいので使わなかった。

 

3.Pool作成時のStartタスクでDockerをインストールする。

そしてタスクで解析ツールが入っているDocker imageをダウンロードして、解析処理を実行する。

 

Pool作成時のStartタスクでDockerをインストール

pool_start_commands = [dockerインストール]
PoolAddParameter(command_line=common.helpers.wrap_commands_in_shell('linux',pool_task_commands),
・・略・・)

 

タスクでDockerを使った解析処理を実行する

commands = [docker run イメージ]
tasks.append(batch.models.TaskAddParameter(
'azmon-task-{}'.format(idx),
common.helpers.wrap_commands_in_shell('linux', commands),
user_identity=run_elevated))

 

便利だったところ

・スタートタスクが失敗してもリトライされる。

VMが起動してタスクが投入されるところをコンソールから確認できる。

 

困ったところ

・pool中のVMのタスクが失敗した場合の戻り値をどうやってとるかわからない。

・東日本リージョン混んでる(2018年3月時点)low priority VMを使ったけど、かなり割り込みが多かった。→西日本リージョンに移動した。

 

改善ポイント

・オートスケーリング機能を使用して、idleのVMをdeleteした方が良い。

・タスクにリトライ機能があるので使った方が良い。

・ログをストレージに保存するように設定する。現時点ではプールの削除とともにログも消える。

 

クラウドって

・データのリージョン間コピーのお値段高いので気をつける。(Azureに限らないけど)

 

最後に

改善ポイントはまだあるけど、ほかにもやりたいことあるし、3月にできるだけやろうと考えていたので、Time's upとしよう。

 

 

Salt StackでGoogle Cloud Platform (GCP) をマネージメントしたい

E

目的

インフラ構成管理ソフトについて勉強中。AWSで使ってみて、使用感が良かったので、GCPでも使用してみる。

 

この記事でやること

SaltStackの公式ドキュメント [Getting Started With Google Compute Engine] をやってみる。

 

Salt StackでGCPをマネージメントするために用意しておくこと

  • なし ←事前準備が"なし"というのがGCPのすごいところ!

 

Salt Stackを実行するCompute Engineを用意する

次のCompute Engineをコンソールから作成した。

 

ssh-keyを作成して、Compute Engineのメタデータに登録する

一般的なやり方なのでわかりやすい。以下のサイトを見ると簡単に登録できる

SSH 認証鍵ペアによるインスタンス アクセスの管理  |  Compute Engine ドキュメント  |  Google Cloud Platform

 

Salt Stackのインストール

作成したCompute Engineにログインし、SaltStackの公式ドキュメント [Ubuntu] を参照してインストールを行う。このsalt-masterをインストールした環境が管理サーバとなる。


# apt-getのアップデー
apt-get update

#一般的な ネットワークアクセスを行うためのパッケージ
apt-get install salt-api

# public cloud VM をマネージメントするパッケージ
apt-get install salt-cloud

# 管理サーバに入れるパッケージ
apt-get install salt-master

# クライアントサーバに入れるパッケージ
apt-get install salt-minion

# リモート操作をするためのパッケージ
apt-get install salt-ssh

# 分散リモート実行システムパッケージ
apt-get install salt-syndic

# おまじない
salt-cloud -u

#おまじないについて

[salt-cloud] Minion doesn't install on some providers after upgrading to 2015.8.0 · Issue #26699 · saltstack/salt · GitHub

# file_ignore_glob関連のWARNINGが大量に出力されてしまうので、対応しておく

[WARNING ] Key 'file_ignore_glob' with value None has an invalid type of NoneType, a list is required for this value · Issue #33706 · saltstack/salt · GitHub

公式ドキュメントに書いておいてほしいですね。

 

Create a Service Account

サービスアカウントのキーを作成してダウンロードする。下記のマニュアルをみて、デフォルトのサービスアカウントのjsonファイルを生成して、Compute Engineにアップロードしておく

サービス アカウント キーの作成と管理  |  Cloud Identity and Access Management のドキュメント  |  Google Cloud Platform

 

Salt Cloudを使用してクライアントサーバを構築する

2つのCompute Engine構築のための設定ファイルを用意する。これによりインフラ構築環境を再現することができる。

1つめ:/etc/salt/cloud.providers

# プロバイダー名。設定をこの名前を使って取り込む重要な名前
gce-config
  # Set up the Project name and Service Account authorization
  project: "your-project-id"
  service_account_email_address: "123-a5gt@developer.gserviceaccount.com"
  service_account_private_key: "/path/to/your/NEW.pem"
  
  # masterのprivate ip アドレスをいれておく
  minion: 
    master: xx.xx.xx.xx
    
  # このままでいい
  grains: 
    node_type: broker
    release: 1.0.1
    
  driver: gce

2つめ:/etc/salt/cloud.profiles

# プロファイル名。salt-cloud実行時にこの名前を使って指定する。
my-gce-profile:
  image: ubuntu-1604
  size: n1-standard-1
  location: asia-east1-c
  network: default
  subnetwork: default
  use_persistent_disk: True
  delete_boot_pd: False
  deploy: True
  make_master: False
  provider: gce-config
  ssh_username: your_login_user
  ssh_keyfile: /home/your_login_user/.ssh/id_rsa

↑で使用しているssh_keyfileのpublic key (id_rsa.pub) をCompute Engineのメタデータに登録する。ほかに本家のマニュアルを見ればもっと細かいことをやっているが、こちらは最小設定。

 

Salt Cloudを実行する

# Usage: salt-cloud -p <プロファイル名> <新たに作られるインスタンスのName(任意)>
# インスタンスを立てる
salt-cloud -p my-gce-profile kchiba-test-instance

 GCPのコンソールを見ると、新しいインスタンスができてる。

 

MasterからMinionのコマンドを起動する

 # minionサーバのコマンドが実行できた。
# salt kchiba-test-instance test.ping 
  kchiba-test-instance
    : True 
    
# pythonも実行できる
# salt kchiba-test-instance cmd.run 'python --version' 
kchiba-test-instance: 
  Python 2.7.12 

便利っぽい。

 

おかたづけ(インスタンスを削除する)

 #Compute Engineをdestroyするコマンドの実行
# salt-cloud -d kchiba-test-instance
The following virtual machines are set to be destroyed:
 gce-config:
   gce:
     kchiba-test-instance

Proceed? [N/y] y

 # Masterの設定も初期化されたかをみてみる。
# salt-key
Accepted Keys:
# kchiba-test-instanceが設定されていたのが消えている

Compute Engineを削除すると同時にsalt-masterとsalt-minionの関係も解消してくれた。

 

使ってみて感想

Compute Engineインスタンスを簡単に作成できる。

ssh-keyなどGoogle独自の方法ではなく、一般的な方法が使えるのでわかりやすい

ほとんどAWSと同じコマンドだった。

 

おわり。

 

Azure BatchでDNAシークエンスデータをアライメントしてみる

目的

Azure BatchでDNAシークエンスデータをアライメントしてみる。勉強目的。

 

この記事でやること

Azure Batchでbwaを実行してみる。以下の記事に沿って勉強する。

チュートリアル - Python 向け Azure Batch SDK を使用する | Microsoft Docs

インストール方法やAzure Batchを実行するためのscriptは↑このページを参照した。今回はAzure BatchでBWAを実行することに主眼を置く。

 

実行環境

Azure 仮想マシン Standard DS1 v2 (1 vcpu、3.5 GB メモリ)  Ubuntu

 

アカウントが必要

・Azure アカウント (メインのアカウント)
・Azure Batchアカウント( Azure Portal で Batch アカウントを作成する | Microsoft Docs 
・ストレージアカウント( Azure Portal でストレージ アカウントを作成… | Microsoft Docs 

 

Pythonのモジュールのインストール

# azure-batchとazure-strageにアクセスするためのpythonパッケージ
pip install azure-batch
pip install azure-storage

 

Azure Batchってなに?

・並列処理が簡単にできる
・コンピューティングリソースを自動的に拡大/縮小できる
解析したい検体数の仮想マシンが自動的に立ち上がることを期待したい!

 

ゲノム解析でとても効果的な機能

・低優先度VMが使用できる。VMの割り込みが起こったタスクは再度キューに登録される。
・コンピューティングノードの最大数が指定できる。

 

プールとは

VMをデプロイする領域
VMのスケール(最低→最大VM数)の指定をする
・AZ_BATCH_NODE_SHARED_DIRとあるが、物理的にshareのなディスクにおいているわけではない

 

ジョブとは

・タスクの置き場、タスクをキューで登録できる
・タスクとは引数ありの実行コマンドとほぼおなじ

 

処理概要

f:id:ken0-1n:20180105112841p:plain

-事前準備

・リファレンスゲノム(bwa index付き)をストレージにアップロードしておく
・アライメントするFASTQファイルをストレージにアップロードしておく
・実行Scriptをgithubにアップロードしておく

-RUNすると

1. python moduleのインポート
2. Container outputを作成する
3. poolを作成する
4. Jobを作成する
5. taskを登録する→poolに空きがあればTASKが実行される
6. taskの完了を待つ

-taskに登録されるscript

・自作したpython_bwa_task.pyについて
 

1. python moduleのインポート

# azure-batchとazure-strageにアクセスするためのpythonパッケージ
import azure.storage.blob as azureblob
import azure.batch.batch_service_client as batch
import azure.batch.batch_auth as batchauth
import azure.batch.models as batchmodels

2. container output を作成する

# まずはblob clientを生成する。Containerの作成や削除、Blobの操作など、
# Strage Accountでの操作を行うためのインスタンス。
blob_client = azureblob.BlockBlobService(
account_name=_YOUR_STORAGE_ACCOUNT_NAME,
account_key=_YOUR_STORAGE_ACCOUNT_KEY)
# container outputの作成
output_container_name = 'output'
blob_client.create_container(output_container_name, fail_on_exist=False)

3. poolを作成する

# まずはbatch clientを生成する。poolの作成や削除、jobの作成や削除など、
# Batch Accountでの操作を行うためのインスタンス。
credentials = batchauth.SharedKeyCredentials(
_YOUR_BATCH_ACCOUNT_NAME, _YOUR_BATCH_ACCOUNT_KEY)
batch_client = batch.BatchServiceClient(
credentials, base_url=_BATCH_ACCOUNT_URL)

VMインスタンスが立ち上がった時に実行されるコマンドの作成
task_commands = [
  'curl -fSsL https://bootstrap.pypa.io/get-pip.py | python',
  'pip install azure-storage==0.32.0',
  'apt-get update && apt-get install -y wget bzip2 make gcc zlib1g-dev',
  'wget http://sourceforge.net/projects/bio-bwa/files/bwa-0.7.15.tar.bz2',
  'tar xjvf bwa-0.7.15.tar.bz2',
  'cd bwa-0.7.15',
  'make',
  'cd ..',
  'cp -rp bwa-0.7.15 $AZ_BATCH_NODE_SHARED_DIR',
  'wget https://github.com/ken0-1n/AzureBatchTutorialBwa/archive/v0.1.0.tar.gz',
  'tar xzvf v0.1.0.tar.gz',
  'cp -p AzureBatchTutorialBwa-0.1.0/{} $AZ_BATCH_NODE_SHARED_DIR'.format(_TUTORIAL_TASK_FILE)
  ]

# VMに指定するイメージの取得
sku_to_use, image_ref_to_use = \
  common.helpers.select_latest_verified_vm_image_with_node_agent_sku(
  batch_service_client, 'Canonical', 'UbuntuServer', '16')
 
# ユーザ権限の設定
user = batchmodels.AutoUserSpecification(
  scope=batchmodels.AutoUserScope.pool,
  elevation_level=batchmodels.ElevationLevel.admin)

# poolの定義, pool IDにはアカウント内でユニークな名前をつけること
new_pool = batch.models.PoolAddParameter(
  id=pool_id,
  virtual_machine_configuration=batchmodels.VirtualMachineConfiguration(
  image_reference=image_ref_to_use,
  node_agent_sku_id=sku_to_use),
  vm_size=_POOL_VM_SIZE, # 'BASIC_A2'を指定
  target_dedicated_nodes=_POOL_NODE_COUNT, # 2を指定。pool内に作られるVMの最大数
  start_task=batch.models.StartTask(
  command_line=common.helpers.wrap_commands_in_shell('linux',
  task_commands),
  user_identity=batchmodels.UserIdentity(auto_user=user),
  wait_for_success=True))

batch_service_client.pool.add(new_pool)

4. jobを作成する

# poolは先ほど作成したpoolを指定する。
job = batch.models.JobAddParameter(_JOB_ID,
   batch.models.PoolInformation(pool_id=POOL_ID))
batch_service_client.job.add(job)

5. taskを登録する

# taskを登録するときにStrageにあるBlobの情報を指定し、
ResourceFileインスタンスを生成しなければならない。そのためのメソッド。
def get_resource(block_blob_client, container_name, blob_name):
   # containerにアクセスするためのtokenの生成
   sas_token = block_blob_client.generate_blob_shared_access_signature(
   container_name,
   blob_name,
   permission=azureblob.BlobPermissions.READ,
   expiry=datetime.datetime.utcnow() + datetime.timedelta(hours=2))
   # blobのurlの生成
   sas_url = block_blob_client.make_blob_url(container_name,
   blob_name,
   sas_token=sas_token)    # blobの情報を設定したインスタンスの生成    return batchmodels.ResourceFile(file_path=blob_name,  blob_source=sas_url)
# StrageにおいてあるFASTQファイルの情報が設定されたインスタンスを生成する
input_container_name = 'fastq'
input_files1 = [get_resourcefile(blob_client, ref_container_name, ref_file_path)
for ref_file_path in ['5929T/sequence1.fastq', '5929N/sequence1.fastq']]
input_files2 = [get_resourcefile(blob_client, ref_container_name, ref_file_path)
for ref_file_path in ['5929T/sequence2.fastq', '5929N/sequence2.fastq']]

# Strageにおいてあるリファレンスゲノムの情報が設定されたインスタンスを生成する
ref_container_name = 'ref'
ref_files = [get_resourcefile(blob_client, ref_container_name, ref_file_path)
for ref_file_path in ['hg19/chr22.fa', 'hg19/chr22.fa.amb',
'hg19/chr22.fa.ann','hg19/chr22.fa.bwt','hg19/chr22.fa.pac','hg19/chr22.fa.sa']]
 # container outputにアクセスするためのtokenの生成
output_container_sas_token = get_container_sas_token(
blob_client,
output_container_name,
azureblob.BlobPermissions.WRITE)

# 実行コマンドをTaskに登録する(5929T)
command = ['python $AZ_BATCH_NODE_SHARED_DIR/python_bwa_task.py --storageaccount chiba1sa --storagecontainer output --sastoken "xxxxxxxxxx" --bwapath $AZ_BATCH_NODE_SHARED_DIR/bwa-0.7.15/bwa --refgenome hg19/chr22.fa --samplename 5929T --fastq1 5929T/sequence1.fastq --fastq2 5929T/sequence2.fastq]
tasks.append(batch.models.TaskAddParameter(
'topNtask1',
common.helpers.wrap_commands_in_shell('linux', command),
resource_files=[5929T/sequence1.fastq, 5929T/sequence2.fastq])

# 実行コマンドをTaskに登録する(5929N)
command = ['python $AZ_BATCH_NODE_SHARED_DIR/python_bwa_task.py --storageaccount chiba1sa --storagecontainer output --sastoken "xxxxxxxxxx" --bwapath $AZ_BATCH_NODE_SHARED_DIR/bwa-0.7.15/bwa --refgenome hg19/chr22.fa --samplename 5929N --fastq1 5929N/sequence1.fastq --fastq2 5929N/sequence2.fastq]
tasks.append(batch.models.TaskAddParameter(
'topNtask2',
common.helpers.wrap_commands_in_shell('linux', command),
resource_files=[5929N/sequence1.fastq, 5929N/sequence2.fastq])

batch_service_client.task.add_collection(job_id, tasks)

6. taskの完了を待つ

timeout_expiration = datetime.datetime.now() + timeout
while datetime.datetime.now() < timeout_expiration:
  tasks = batch_service_client.task.list(job_id)
  incomplete_tasks = [task for task in tasks if task.state != batchmodels.TaskState.completed]
  if not incomplete_tasks:
    return True
  else:
    time.sleep(1)

自作したpython_bwa_task.pyの中身

# モジュールのimport
from __future__ import print_function
import argparse
import collections
import os
import string
import subprocess
import sys

import azure.storage.blob as azureblob

if __name__ == '__main__':

    # 引数の処理
    parser = argparse.ArgumentParser()
    parser.add_argument('--storageaccount')
    parser.add_argument('--storagecontainer')
    parser.add_argument('--sastoken')
    parser.add_argument('--bwapath', required=True)
    parser.add_argument('--fastq1', required=True)
    parser.add_argument('--fastq2', required=True)
    parser.add_argument('--refgenome', required=True)
    parser.add_argument('--samplename', required=True)
    args = parser.parse_args()

    bwa = os.path.realpath(args.bwapath)
    fastq1 = os.path.realpath(args.fastq1)
    fastq2 = os.path.realpath(args.fastq2)
    ref_fa = os.path.realpath(args.refgenome)
    samplename = args.samplename

    output_sam = samplename +'.sam'
    error_log = samplename +'.error.log'

    # bwaを実行する
    sam =  open(output_sam, 'w')
    error =  open(error_log, 'w')
    proc = subprocess.Popen([bwa, 'mem', ref_fa, fastq1, fastq2], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    output = proc.stdout
    for line in output:
        sam.write(line)
    output = proc.stderr
    for line in output:
        error.write(line)
    sam.close()
    error.close()

    # blobにアクセスするためのインスタンスを生成
    blob_client = azureblob.BlockBlobService(account_name=args.storageaccount,
                                             sas_token=args.sastoken)
    # 結果をアップロードする
    output_sam_path = os.path.realpath(output_sam)
  blob_client.create_blob_from_path(args.storagecontainer,
                                      output_sam,
                                      output_sam_path)
    error_log_path = os.path.realpath(error_log)
    blob_client.create_blob_from_path(args.storagecontainer,
                                      error_log,
                                      error_log_path)

 

使ってみて感想

Pythonで記載されたAzure Batchを動かすサンプルがあったので便利。

1検体につき、1VMインスタンスが割り当ててほしいが、Auto Scaleがそのように、割り当ててくれるか検証が必要。

Docker Swarmを使用できるとのことなので、やってみなくてはならない

 

参考

github.com

Celery + AWS Redis で使ってみる

目的

Celeryなるツールを使ってみる。勉強目的。

 

この記事でやること

Celery + Redisを使ってみる。Djangoは使わない。とりあえずCeleryのマニュアルのFirst Stepsは理解したい。

First Steps with Celery — Celery 4.1.0 documentation

 

環境

AWS EC2 Oregon

ubuntu-xenial-16.04-amd64-server-20170619.1 (ami-835b4efa)

 

Celeryってなに?

・非同期処理が作れる

・スケジューリングもできる

上記の機能を使用する際にpythonでスタンダードなツール

 

Message Brokerなるものが必要

タスクメッセージをCeleryに登録したり、そのタスクを取り出すBrokerなるツールが必要で、以下のツールをサポートしている。

Brokers — Celery 4.1.0 documentation

この記事ではRedisを使用してみるAmazon SQSも気になるけど単体で使用するツールではなさそうなので、単体でも使用できそうなRedisを指定する。

 
Redisってなに?

以下のSlide Shareを見てもらうと手っ取り早い。RDBのデータをキャッシュする感じで使うのですかね。便利そうですね。

Redisの特徴と活用方法について

 

AWSにRedisでも立ててみる

料金について。無料利用枠があるとのことなのでcache.t2.microを使う。


AWS コンソールから作成してみる

f:id:ken0-1n:20171201152156p:plain

 

クライアントのEC2と同じセキュリティーグループにいれて、inboudを許可したらコネクトできました。

ElastiCacheのredisをEC2で使う - Qiita

 

CeleryとRedisはどうやってつながるの?

Celery instanceが必要だというので立ててみる。

tasks.pyをつくる

from celery import Celery
app = Celery('tasks', broker='redis://ubuntu@your.primary.endpoint.cache.amazonaws.com')
@app.task
def add(x, y):
  return x + y

 

Celeryデーモンの起動

celery -A tasks worker --loglevel=info

なんかサーバたった。

 

別のプロセスを立ち上げでタスクを投げてみる

>>> from tasks import add
>>> result = add.delay(4, 4)
<AsyncResult: bf6d2799-2461-4b42-8ee1-f5bddb867f05>
>>> result.get()
(省略)
NotImplementedError: No result backend is configured.

returnされたけど見えない。(ここでは見えなくて正解。backendの処理が必要)

 

結果を保持する

tasks.pyを更新する。赤字の設定を追加

backendに指定したストアに結果が保持される保持する。

from celery import Celery
app = Celery('tasks', broker='redis://ubuntu@your.primary.endpoint.cache.amazonaws.com', backend='redis://ubuntu@your.primary.endpoint.cache.amazonaws.com')
@app.task
  def add(x, y):
  return x + y

 

再実行

Ctrl + C (サーバ止める)
celery -A tasks worker --loglevel=info

 

結果

>>> from tasks import add
>>> result = add.delay(4, 4)
>>> result.get()
8

 

Redisのデータがどうなっているか気になるので見てみる
redis-cliを使用する

# redisに接続
redis-cli -h your.primary.endpoint.cache.amazonaws.com
# key検索
> keys *
"celery-task-meta-xxxxxxxx-xxxx-xxxx-xxxxxxxxx"
# 登録したタスクがいっぱい出てくる
# 登録したタスクの検索
get celery-task-meta-xxxxxxxx-xxxx-xxxx-xxxxxxxxx
# 格納されてた
"{\"status\": \"SUCCESS\", \"traceback\": null, \"result\": 8, \"task_id\": \"xxxxxxxx-xxxx-xxxx-xxxxxxxxx\", \"children\": []}"

 

使ってみて感想

簡単に非同期処理ができてとても便利。いろいろと使えそう。

 

参考

http://docs.celeryproject.org/en/latest/index.html

https://www.slideshare.net/yujiotani16/redis-76504393

https://qiita.com/tackeyy/items/258903cb6b24a3beae08

http://blog.eiel.info/blog/2014/08/26/remember-redis/

Salt StackでAWSにNFSをたててみる

目的

Amazon EFSのようなファイルシステムがほしいけど、TokyoリージョンにないのでNFSをたててみる

 

この記事でやること

Salt Stackを使ってNFSサーバとクライアントをたてる。データをNFSサーバにコピーしてクライアントからみられるか確認する。

 

Requirment

AWS EC2にSalt Stackがインストールされており、使用できる状態であること。インストール手順は、前回の記事を参照してください。

Salt StackでAWSをマネージメントしたい - ken0-1nのブログ

 

NFSサーバとなるインスタンスの作成

Salt Stackのマスターがインストールされている、AWS EC2インスタンスにログインし、下記の定義を/etc/salt/cloud.profilesに追加する。

# providerは、AWSキーペアとかセキュリティーグループが定義されているファイルを参照してる。(前回の記事を参照)
# NFSクライアントが参照するファイルを置きたいのでVolumeSizeは大きめ(100GB)
base_ec2_nfs:
    provider: my-ec2-southeast-private-ips
    image: ami-835b4efa
    size: m4.xlarge
    ssh_username: ubuntu
    block_device_mappings:
    - DeviceName: /dev/sda1
      Ebs.VolumeSize: 100
      Ebs.VolumeType: gp2

# インスタンスの作成
salt-cloud -p base_ec2_nfs ami.nfs_server

 

NFSサーバの設定

1. サーバ設定を行う.shファイルを作成&実行

# mount_server.sh

#!/bin/bash
set -xv

apt-get -y install awscli
apt-get -y install nfs-kernel-server
mkdir -p /mnt/data
echo "/mnt *(rw,fsid=0,no_subtree_check,sync)" >> /etc/exports
echo "/mnt/data *(rw,nohide,insecure,no_subtree_check,sync)" >> /etc/exports
# デーモンの数を変えたい。数値の置換の方が良かったかな?
mv /etc/default/nfs-kernel-server /etc/default/nfs-kernel-server.bk
echo "RPCNFSDCOUNT=32" > /etc/default/nfs-kernel-server
cat /etc/default/nfs-kernel-server.bk | awk 'NR>=3' >> /etc/default/nfs-kernel-server
# 設定の反映
systemctl restart nfs-config
#サーバ起動
service nfs-kernel-server restart
# サーバーにファイルをコピー
salt-cp ami.nfs_server ./mount_server.sh ~/.

# 実行
salt 'ami.nfs_server' cmd.run 'bash /root/./mount_server.sh'

2.マウントポイントにデータをコピーする.shファイルを作成&実行

# data_copy_server.sh

#!/bin/bash
set -xv
export AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxx
export AWS_ACCESS_KEY_ID=xxxxxxxxxxxxxxxxxxxx
export AWS_DEFAULT_REGION=us-west-2
aws s3 cp --recursive s3://kchiba-test-bucket/data/database /mnt/data
# サーバーにファイルをコピー
salt-cp ami.nfs_server ./data_copy_server.sh ~/.

# 実行
salt 'ami.nfs_server' cmd.run 'bash /root/./data_copy_server.sh'

# 戻り値 ファイルのコピーは成功しているのに、正常終了にならない。バグかなー。
ami.nfs_server:
 VALUE_TRIMMED

# 仕方ないのでsshでami.nfs_serverにログインしてdata_copy_server.shを実行した。 
→正常終了した。

# nfs serverのrestert
salt 'ami.nfs_server' cmd.run 'service nfs-kernel-server restart'

 

NFSクライアントとなるインスタンスの作成&実行

Salt Stackのマスターがインストールされている、AWS EC2インスタンスにログインし、下記の定義を/etc/salt/cloud.profilesに追加する。

base_ec2_client:
    provider: my-ec2-southeast-private-ips
    image: ami-835b4efa
    size: m4.large
    ssh_username: ubuntu

# インスタンスの作成
salt-cloud -P -p base_ec2_client ami.nfs_client1 ami.nfs_client2 ami.nfs_client3 ami.nfs_client4

 

 NFSクライアントの設定

1. fstabを編集。大きいファイルサイズのデータを扱いたいのでオプションを変更

LABEL=cloudimg-rootfs   /        ext4   defaults,discard,rsize=1048576,wsize=1048576    0 0
# クライアントにファイルをコピー
salt-cp 'ami.nfs_mini*' fstab /etc/fstab

2. マウントコマンドが記載された.shファイルを作成 # mount_server.sh

#!/bin/bash
set -xv

nfs_server=$1
apt-get -y install nfs-common
mkdir -p /mnt
# 編集したfstabを読み込む
systemctl daemon-reload
mount -v -t nfs4 ${nfs_server}:/ /mnt
# クライアントにファイルをコピー
salt-cp 'ami.nfs_client*' mount_client.sh ~/.

# サーバ側のホスト名を調べる
salt 'ami.nfs_server' cmd.run 'hostname'
ami.nfs_server:
ip-172-31-xx-xx

# ホスト名に引数を入れて実行
salt 'ami.nfs_client*' cmd.run 'bash /root/./mount_client.sh ip-172-31-xx-xx'

# マウントされたファイルがみえるか確認
salt 'ami.nfs_client*' cmd.run 'ls /mnt/data'

 

使ってみて感想

salt cmd.runでVALUE_TRIMMEDがreturnされて原因がわからない(17/11/20)。そこそこメモリの大きいインスタンスを立てているはずだがうまくいかない。

 

 参考

https://siguniang.wordpress.com/2015/08/09/setup-nfsv4-on-ubuntu-1404/

http://uramocha02.blogspot.jp/2017/02/etcfstab.html

https://docs.saltstack.com/en/latest/ref/cli/salt-cp.html

Salt StackでAWSをマネージメントしたい

目的

インフラ構成管理ソフトについて勉強中。とりあえずSaltStack使ってみるよ。

 

この記事でやること

SaltStackの公式ドキュメント [Getting Started With AWS EC2] をやってみる。

 

Salt StackでAWSをマネージメントするために用意しておくこと

  • EC2 access credentialsの作成
  • Key Pairの作成
  • Security Groupの作成
  • リージョンをどこにするか考える

 

Salt Stackを実行するEC2インスタンスを用意する

次のEC2インスタンスを作成した。Key PairやSecurity Groupはデフォルトではなく用意したものを使用した。

 

Salt Stackのインストール

用意したEC2インスタンスにログインし、SaltStackの公式ドキュメント [Ubuntu] を参照してインストールを行う。このsalt-masterをインストールした環境が管理サーバとなる。

#一般的な ネットワークアクセスを行うためのパッケージ
sudo apt-get install salt-api

# public cloud VM をマネージメントするパッケージ
sudo apt-get install salt-cloud

# 管理サーバに入れるパッケージ
sudo apt-get install salt-master

# クライアントサーバに入れるパッケージ
sudo apt-get install salt-minion

# リモート操作をするためのパッケージ
sudo apt-get install salt-ssh

# 分散リモート実行システムパッケージ
sudo apt-get install salt-syndic

# おまじない
sudo salt-cloud -u

[salt-cloud] Minion doesn't install on some providers after upgrading to 2015.8.0 · Issue #26699 · saltstack/salt · GitHub

おまじないは必須です。公式ドキュメントに書いておいてほしいですね。

 

Salt Cloudを使用してクライアントサーバを構築する

2つの設定ファイルを用意する。ファイルに構築環境を記録しておくことにより再現可能となる。さっそく[Getting Started With AWS EC2] を参考にして書いてみよう。

1つめ:/etc/salt/cloud.providers


# プロバイダー名。設定をこの名前を使って取り込む重要な名前。
my-ec2-southeast-private-ips:
 # salt-masterをインストールした(管理側)のEC2のプライベートIPアドレス。
 # ドキュメントではEC2インスタンスNAMEでもよさげだったけどできなかった。
  # Set up the location of the salt master
  #
  minion:
    master: 172.31.7.10

 # EC2はプライベートIPで接続する
  # Specify whether to use public or private IP for deploy script.
  #
  # Valid options are:
  #     private_ips - The salt-master is also hosted with EC2
  #     public_ips - The salt-master is hosted outside of EC2
  #
  ssh_interface: private_ips

 # とりあえずデフォルト
  # Optionally configure the Windows credential validation number of
  # retries and delay between retries.  This defaults to 10 retries
  # with a one second delay betwee retries
  win_deploy_auth_retries: 10
  win_deploy_auth_retry_delay: 1

 # AWSで作ったEC2 access credentialsを設定する
  # Set the EC2 access credentials (see below)
  #
  id: '*****************'
  key: '*****************'

  # AWSで作ったキーペアを設定する
  # Make sure this key is owned by root with permissions 0400.
  #
  private_key: '/root/.ssh/プライベートキー.pem'
  keyname: 'キーネーム'

  # AWSで作ったセキュリティーグループを設定する
  # This one should NOT be specified if VPC was not configured in AWS to be
  # the default. It might cause an error message which says that network
  # interfaces and an instance-level security groups may not be specified
  # on the same request.
  #
  securitygroup: 'セキュリティーグループ名'

 # リージョンを指定する。うちはオレゴンを使った。
  # Optionally configure default region
  #
  location: us-west-2
  availability_zone: us-west-2c

 # ubuntuを使っているのでubuntuにする
  # Configure which user to use to run the deploy script. This setting is
  # dependent upon the AMI that is used to deploy. It is usually safer to
  # configure this individually in a profile, than globally. Typical users
  # are:
  #
  # Amazon Linux -> ec2-user
  # RHEL         -> ec2-user
  # CentOS       -> ec2-user
  # Ubuntu       -> ubuntu
  #
  ssh_username: ubuntu

  # オプションなのでとりあえず指定しないでコメントアウトしておく
  # Optionally add an IAM profile
  # iam_profile: 'my other profile name'

  driver: ec2

2つめ:/etc/salt/cloud.profiles

# プロファイル名。salt-cloud実行時にこの名前を使って指定する。
base_ec2_private:
 # 1つめのcloud.providersで指定したプロバイダー名
  provider: my-ec2-southeast-private-ips 
  image: ami-835b4efa
  size: t2.micro
  ssh_username: ubuntu

設定終わり。本家のマニュアルを見ればもっと細かいことをやっているが、こちらは最小設定。

 

Salt Cloudを実行する

# Usage: salt-cloud -p <プロファイル名> <新たに作られるEC2インスタンスのName(任意)>
# 2つインスタンスを立てる
salt-cloud -p base_ec2_private ami.slave01
salt-cloud -p base_ec2_private ami.slave02

 AWSのコンソールを見ると、新しいEC2インスタンスができてる。

 

MasterからMinionのコマンドを起動する

 # minionサーバのコマンドが実行できた。
root@ip-172-31-2-47:/etc/salt# salt 'ami.slave*' cmd.run 'ls -la /etc/hostname'
ami.slave02:
    -rw-r--r-- 1 root root 17 Oct 24 04:20 /etc/hostname
ami.slave01:
    -rw-r--r-- 1 root root 15 Oct 24 04:18 /etc/hostname    
 # pythonも実行できる
root@ip-172-31-2-47:/etc/salt# salt 'ami.slave*' cmd.run 'python --version'
ami.slave02:
    Python 2.7.12
ami.slave01:
    Python 2.7.12

便利っぽい。

 

おかたづけ(EC2インスタンスを削除する)

 #EC2をdestroyするコマンドの実行
root@ip-172-31-2-47:/etc/salt# salt-cloud -d ami.slave01
The following virtual machines are set to be destroyed:
  my-ec2-southeast-public-ips:
    ec2:
      ami.slave01

Proceed? [N/y] y

root@ip-172-31-2-47:/etc/salt# salt-cloud -d ami.slave02
The following virtual machines are set to be destroyed:
  my-ec2-southeast-public-ips:
    ec2:
      ami.slave02

Proceed? [N/y] y
... proceeding
 # Masterの設定も初期化されたかをみてみる。
root@ip-172-31-2-47:/etc/salt# salt-key
Accepted Keys:
# ami.slave01, ami.slave02が設定されていたのが消えている

EC2を削除すると同時にsalt-masterとsalt-minionの関係も解消してくれた。

 

使ってみて感想

EC2インスタンスを簡単に作成できる。設定ファイルもわかりやすい。

AWSサービスがどこまでsalt-cloudで使用できるか調べる必要はある。

EC2を作成すると同時にsalt-masterとsalt-minionの関係が作られるのが楽ちん。

日本で使っている人少ないかもしれない。

 

おわり。