:>/dev/null

ラガードエンジニアの不撓不屈の精神/unlearning/go beyond

cloudmapperに入門した

awsの構成変更を行う場合、Document更新を忘れるので良い方法がないか調査した。
本来なら構成変更を行ったタイミングで自動化してDocument更新をするのが良いが効果的な方法が見つからない。
cloudmapperを使用した場合、現時点での構成が図表されるので代替え案として検討した。
導入する為に行った時の勉強メモ。

  • 以下構築要件
    • awsの構成管理を行う(現時点で運用されてる構成図を表示)
    • awsのec2インスタンス上にcloudmapperをインストール
    • cloudmapperをインストールしたインスタンスから各インスタンスへ接続可能
    • cloudmapperをインストールしたインスタンスにグローバルからアクセス可能
      • EIPを割当済みの場合、IP変更が発生せず便利

■下記に導入〜動作確認までを記載する

● OSに必要環境セットアップ

$sudo yum install autoconf automake libtool python3-devel.x86_64 python3-tkinter python34-devel awscli w3m jq
$virtualenv venv
$python --version
$pip install -r requirements.txt

● cloudmapperインストール

$git clone https://github.com/duo-labs/cloudmapper.git

● ユーザーが未作成の場合、コンソールより作成

$aws --profile cloudmapper iam create-user --user-name cloudmapper

● accounts確認

[ec2-user@ip-172-31-xxx-xxx cloudmapper]$ cat config.json
{  "accounts":
    [
        {"id": "123456789012", "name": "aws-account-1", "default": true}
    ],
    "cidrs":
    {
        "1.1.1.1/32": {"name": "SF Office"},
        "2.2.2.2/28": {"name": "NY Office"}
    }
}

● credentialsファイル確認

[ec2-user@ip-172-31-xxx-xxx cloudmapper]$ cat ~/.aws/credentials
[default]
aws_access_key_id = *********
aws_secret_access_key = *********

[cloudmapper]
aws_access_key_id = *********
aws_secret_access_key = *********

● 起動

$cd /home/ec2-user/cloudmapper
$./collect_data.sh --account aws-account-1 --profile cloudmapper
$python cloudmapper.py prepare --account aws-account-1
$python cloudmapper.py webserver --public --port 8001

※ 一部起動パラメータが変更になっているので調整する

$ python cloudmapper.py webserver {args}

def run(arguments):
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument(
"--port",
help="Port to listen on",default=8000,type=int)
parser.add_argument(
"--public",
dest='is_public',help="Allow connections from 0.0.0.0 (or :: if --ipv6 was provided) as opposed to only localhost",action='store_true')
parser.add_argument(
"--ipv6",
dest='is_ipv6',help="Listen on IPv6",action='store_true')

● 動作確認

$curl http://localhost:8001/
$w3m http://localhost:8001/

以下のように、VPCやSubnetのレイアウトやSecurity Groupによるアクセス許可を可視化できる
(README.mdより引用) f:id:oguguman:20190517164146p:plain

ref)
https://qiita.com/bukaz/items/4a769065cd14b192319f

Ansibleを使用した構成管理に入門した

ansibleを使用して構成管理をする場合の条件分岐方法の調査を行った時の勉強メモ。

  • 以下構築要件
    • Ansibleで構成管理を行う(冪等性の担保)
    • Ansibleで各環境毎に設定内容を書き換える
      • PRD(Production)/STG(Staging)/sandbox等

■下記に各設定サンプルのconfファイルを記載する

  • template/prd.confの設定
<source>
  @id prd_src
  @type   config_expander
  <config>
    @type tail
    @label @{{ td_agent_label }}
    read_from_head true
    path /home/prd/logs/*.log
    pos_file /var/log/td-agent/prd.pos
    format none
    message_key log_line
    tag {{ td_agent_tag }}
  </config>
</source>
  • template/sbx.confの設定
<source>
  @id sbx_src
  @type   config_expander
  <config>
    @type tail
    @label @{{ td_agent_label }}
    read_from_head true
    path /home/sbx/logs/*.log
    pos_file /var/log/td-agent/sbx.pos
    format none
    message_key log_line
    tag {{ td_agent_tag }}
  </config>
</source>
  • template/td-agent.confの設定
{% if is_sandbox %}
@include sbx.conf
{% else %}
@include prd.conf
{% endif %}
  • group_vars/servers.ymlの設定
is_sandbox: True
tdagent_force_restart: False
tdagent_conf_dir: "{{ inventory_dir }}/templates/td-agent"
td_agent_label: test-pjt
td_agent_tag: stage-src-tag
td_agent_loginfo_group: test-grp
tdagent_conf_files:
 - { src: "{{ tdagent_conf_dir }}/td-agent.conf.j2", dest: "td-agent.conf" }
 - { src: "{{ tdagent_conf_dir }}/in.www.nginx.access.conf.j2", dest: "in.www.nginx.access.conf" }
 - { src: "{{ tdagent_conf_dir }}/in.www.nginx.error.conf.j2", dest: "in.www.nginx.error.conf" }
 - { src: "{{ tdagent_conf_dir }}/out.conf.j2", dest: "out.conf" }
tdagent_root_exec: True
  • hostsの設定(inventory)
[all:vars]
ansible_connection=ssh
ansible_user=username
ansible_ssh_pass=userpwd
ansible_sudo_pass=rootpwd

[servers]
vm1234 ansible_host=172.31.100.1 newrelic_install=true
  • servers.ymlの設定(playbook)
---
- hosts: servers
  become: yes
  strategy: free
  become_method: su
  become_user: root
  roles:
    - { role: newrelic, when: "newrelic_install == 'true'" }
  • playbook実行
# ansible-playbook -i hosts -u username servers.yml -K -S --diff

Ansibleを使用した構成管理構成を構築した。
冪等性の担保、コンテナ化した構成管理時に効率的に運用管理が行う事が可能。
CI/CD、デプロイ等を絡めた構成管理が前提の状況な為、知識を確実に体系化する必要がある。

Amazon Kinesis Client Library (KCL)を使用したログ収集基盤構成

Amazon Kinesis Client Library (KCL)を使用したログファイル収集基盤構成を構築する必要があり、調査を行った時の勉強メモ。

  • 以下構築要件

    • apacheaccess_logを集約サーバへ収集する
    • 集約サーバでAmazon Kinesis Client Library (KCL) ライブラリを使用して送信←今回、構築部分
    • KCL → aws kinesis stream へ送信
    • aws kinesis stream → s3/aes等へ送信
      • バックアップ/可視化など
  • KCLの設定

[ec2-user@ip-172-xx-xx-xx aws-kinesis]$ cat agent.json
{
  "awsAccessKeyId": "******",
  "awsSecretAccessKey": "******",
  "cloudwatch.endpoint": "monitoring.ap-northeast-1.amazonaws.com",
  "cloudwatch.emitMetrics": true,
  "kinesis.endpoint": "",
  "firehose.endpoint": "firehose.ap-northeast-1.amazonaws.com",

  "flows": [
    {
      "filePattern": "/tmp/test.log",
      "deliveryStream": "teststream",
      "dataProcessingOptions": [
         {
             "optionName": "LOGTOJSON",
             "logFormat": "COMMONAPACHELOG",
             "matchPattern": "^([\\d.]+) - - \\[([\\w:/]+).*\\] \"(\\w+) /(\\w+).*(\\d.+)\" (\\d{3}) (\\d+) \"(\\S+)\" \"(.*?)\" ([\\d.]+) \"(.*?)\" (\\d+);(\\d+)",
             "customFieldNames": ["client_ip", "time_stamp", "verb", "uri_path", "http_ver", "http_status", "bytes", "referrer", "agent", "response_time", "graphql", "company_id", "user_id"]
         }
      ]
    }
  ]
}
[ec2-user@ip-172-xx-xx-xx ~]$ cat test.sh
#!/bin/bash

start=$(date)
for i in $(seq 1 ${1})
do
    echo ${i}
    echo -e "$( echo $(cat sample.json))" >> /tmp/test.log
    sleep 0.01s
done
echo ${start}
date
  • サンプルデータのフォーマット確認
[ec2-user@ip-172-xx-xx-xx ~]$ cat sample.json
111.111.111.111 - - [02/Dec/2016:13:58:47 +0000] "POST /graphql HTTP/1.1" 200 1161 "https://www.myurl.com/endpoint/12345" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36" 0.172 "query user userMessages hasPermissions F0 F1" 11111;222222

KCL ライブラリを使用したログ収集基盤構成を構築した。
収集時、アグリゲーターでtd-agentを使用した環境と比較し、安易に送信及び構築が可能な為、今後は本環境を使用した基盤構成を行うケースが増えそうです。

aws cloud watchの各使用状況詳細

aws cloudwatchで各使用状況を確認出来るが、各コストに関して詳細に調査する必要があり、調査を行った時の勉強メモ。

  • 請求ダッシュボード -> Cost Explorer ->

    • サービス別の月別使用量ビュー
    • リンクアカウント別の月別使用量ビュー
    • 日別使用量ビュー
      • cost reports
  • 各数値に関して詳細を確認

・Daily total cost
https://console.aws.amazon.com/cost-reports/home?#/custom?groupBy=Service&hasBlended=false&hasAmortized=false&excludeDiscounts=true&excludeTaggedResources=false&timeRangeOption=Custom&granularity=Daily&reportName=&reportType=CostUsage&isTemplate=true&filter=%5B%5D&chartStyle=Group&forecastTimeRangeOption=None&usageAs=usageQuantity&startDate=2018-12-24&endDate=2019-01-18
・有償メトリクス(s3/kinesis shard)
https://console.aws.amazon.com/cost-reports/home?#/custom?groupBy=Operation&hasBlended=false&hasAmortized=false&excludeDiscounts=true&excludeTaggedResources=false&timeRangeOption=Custom&granularity=Daily&reportName=&reportType=CostUsage&isTemplate=true&filter=%5B%7B%22dimension%22:%22Service%22,%22values%22:%5B%22AmazonCloudWatch%22%5D,%22include%22:true,%22children%22:null%7D%5D&chartStyle=Stack&forecastTimeRangeOption=None&usageAs=usageQuantity&startDate=2018-12-30&endDate=2019-01-20

Gourp by : API Operation
Filters > Service : CloudWatch

PutMetricDataの詳細情報取得 -> CloudTrail logにてAPI Callが記録
・Kinesisデータ保持期間
https://console.aws.amazon.com/cost-reports/home?#/custom?groupBy=UsageType&hasBlended=false&hasAmortized=false&excludeDiscounts=true&excludeTaggedResources=false&timeRangeOption=Custom&granularity=Daily&reportName=&reportType=CostUsage&isTemplate=true&filter=%5B%7B%22dimension%22:%22Service%22,%22values%22:%5B%22Amazon%20Kinesis%22%5D,%22include%22:true,%22children%22:null%7D%5D&chartStyle=Stack&forecastTimeRangeOption=None&usageAs=usageQuantity&startDate=2018-12-25&endDate=2019-01-20

Group by : Usage Type
Filters > Service : kinesis

cloud watchを使用したモニタリング環境での各値確認まで完了した。
サーバレスアーキテクチャ等でモニタリング監視を行うケースが増えそうなので確認方法を確立しておく必要ありそうです。

fluentdで送信recordに文字列を代入してから送信する

タイトル通り実装する要件があり、調査・設定行った時の勉強メモ。
fluentdを使用したログ集約環境で、送信データの特定フィールドの値をごにょごにょ加工したい(次工程に渡す)っていう要件があります。
調査の結果、fluentdのfilter_record_transformerプラグインで実装可能との事で設定してみた。

record_transformer Filter Plugin | Fluentd

  • 構築手順
    • td-agent-gem install fluentd -v 0.12.x
      • ※今回はVersion0.12.xを使用
      • ※fluentdに内包されているのでプラグインのインストールは必要ありません
    • out.conf(送信設定conf)作成
    • td-agent再起動(設定反映)

書き方は以下ようになります。ディレクティブの中にフィールド名とその値を書きます。
タイトルで代入と記載してますが、代入時に同名のフィールドがあればその値が代入項目にマップされる動作になっています。

<filter foo.bar>
  @type record_transformer
  <record>
    hostname "#{Socket.gethostname}"
    tag ${tag}
  </record>
</filter>

また、enable_rubyオプションを有効にした場合、Ruby式の評価結果を値にする事が可能です。 計算処理や文字列操作なんかで使えそうで便利です。
以下にサンプル処理を記載します。
特定recordに新規項目代入・含まれる特定の文字列削除(gsubメソッド使用)・更新等で使用可能です。

#  ### sample log scrubbing filters
#  #replace social security numbers
# <filter reform.**>
#   @type record_transformer
#   enable_ruby true
#   <record>
#     log ${record["log"].gsub(/[0-9]{3}-*[0-9]{2}-*[0-9]{4}/,"xxx-xx-xxxx")}
#   </record>
# </filter>
# # replace credit card numbers that appear in the logs
# <filter reform.**>
#   @type record_transformer
#   enable_ruby true
#   <record>
#      log ${record["log"].gsub(/[0-9]{4} *[0-9]{4} *[0-9]{4} *[0-9]{4}/,"xxxx xxxx xxxx xxxx")}
#   </record>
# </filter>
# # replace email addresses that appear in the logs
# <filter reform.**>
#   @type record_transformer
#   enable_ruby true
#   <record>
#     log ${record["log"].gsub(/[\w+\-]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+/i,"user@email.tld")}
#   </record>
# </filter>
# # replace url addresses that appear in the logs
# <filter reform.**>
#   @type record_transformer
#   enable_ruby true
#   <record>
#     log ${record["log"].gsub(/\.sub\.test\.com|\.sub\.test\.co\.jp/,"")}}
#   </record>
# </filter>
# ### end sample log scrubbing filters

これでログ集約時、送信前に加工処理し送信可能です。

amazon linux2でのpython3環境構築

Lambdaをpython3で書く必要があり、まずは環境構築を行った時の勉強メモ。

  • 構築手順
    • python3 install
    • pip3 install
    • reqest package作成
    • boto3 package作成
    • Token取得
      • ※取得したTokenが正常か確認
・python3 install
$ sudo yum install python36 python36-virtualenv python36-pip
$ python3 -V
Python 3.6.5

・pip3 install
install python3-pip

・reqest package
pip3 install requests -t ./
rm -rf *.dist-info bin
pip3 install pipdeptree
sudo pip3 install pipdeptree
zip -r reqest.zip ./*

・boto3 package
pip install -t ./python boto3
zip -r boto3-1.9.67.zip python
cp boto3-1.9.67.zip /home/ec2-user/

[2019.02.14 add] aws linux(ec2/旧環境)で「No package」対応
># yum install python3
>Loaded plugins: priorities, update-motd, upgrade-helper
>amzn-main/latest                            | 2.1 kB     00:00
>amzn-updates/latest                      | 2.5 kB     00:00
>21 packages excluded due to repository priority protections
>No package python3 available.
>Error: Nothing to do

・現環境確認
pip --version
・Repository確認
yum list available | grep "python" | grep "libs"
・python3インストール
yum install python36 python36-virtualenv python36-pip
pip-3.6 -V
・必要パケージ収集
mkdir lambda_test/
cd lambda_test/
pip install --upgrade pip
pip-3.6 install requests bs4 slackweb -t .
rm -rf *.dist-info *.egg-info bin
・パケージ化
zip -r scraping_pkg.zip ./*

・Token取得について
https://api.slack.com/apps/AE******/oauth? ->[OAuth&Permission] ->「Bot User OAuth Access Token」

Tokenが正常認証許可するか確認
https://slack.com/api/chat.postMessage?token=xoxb-xxxxxx-xxxxxx-xxxxxx&channel=test&text=%22Hello%22
↓結果
{"ok":true,"channel":"CERG265JT","ts":"1545287527.000100","message":{"type":"message","subtype":"bot_message","text":"\"Hello\"","ts":"1545287527.000100","username":"slack-test-func","bot_id":"BE9TMPEUQ"}}

まず、python3→Token取得まで確認した。
サーバレスアーキテクチャでLambdaを選択する場合に使えそう。

ref)
https://goodbyegangster.hatenablog.com/entry/2018/05/22/024513
https://qiita.com/SHASE03/items/16fd31d3698f207b42c9
https://qiita.com/hayao_k/items/b9750cc8fa69d0ce91b0
https://qiita.com/ykhirao/items/3b19ee6a1458cfb4ba21

aws cuiを使用してKinesis streamデータ登録・確認

Kinesisはライブラリとして使用する事が多い為、実際の挙動を把握せず使ってるので調査した時の勉強メモ。
実際の挙動を把握する事で障害対応等で効率的に行動出来るようにする。

■ストリーム作成

aws kinesis create-stream --stream-name <ストリーム名> --shard-count <シャード数>

■レコード登録

# "ShardId": "shardId-000000000000" と出力されればOK
aws kinesis put-record --stream-name <ストリーム名> --partition-key 123 --data <レコードに保存したい文字列>

■レコード確認

aws kinesis get-shard-iterator --shard-id shardId-000000000000 --shard-iterator-type TRIM_HORIZON --stream-name <ストリーム名> --query 'ShardIterator'
{
    "ShardIterator": "AAAAAAAAAAE2R*******************=="
}

aws kinesis get-records --shard-iterator "AAAAAAAAAAE2R*******************=="
{
    "Records": [
        {
            "Data": "aG9nZWhvZ2U=",
            "PartitionKey": "123",
            "ApproximateArrivalTimestamp": 1546849899.19,
            "SequenceNumber": "49591791737946085028906975044094438871988285374419959810"
        },
        {
            "Data": "aG9nZTE=",
            "PartitionKey": "123",
            "ApproximateArrivalTimestamp": 1546851156.579,
            "SequenceNumber": "49591791737946085028906975051711880461380150184625831938"
        }
    ],
    "NextShardIterator": "AAAAAAAAAAFQkY****************==",
    "MillisBehindLatest": 0
}

■簡易確認の為、上記手順をスクリプト

$ cat chk-kinesis-record.sh
#!/bin/bash

KINESIS_NAME=<ストリーム名>

# 引数チェック
#echo "args = "$#
ARGS1=${1:?}
#echo $ARGS1

# レコード登録
aws kinesis put-record --stream-name $KINESIS_NAME --partition-key 123 --data $ARGS1

# shardIdからiterator値取得
SHARD_ITERATOR=$(aws kinesis get-shard-iterator --shard-id shardId-000000000000 --shard-iterator-type TRIM_HORIZON --stream-name $KINESIS_NAME --query 'ShardIterator')

# レコード取得
aws kinesis get-records --shard-iterator $SHARD_ITERATOR

kinesis→レコード登録・確認

$ ./chk-kinesis-record.sh hoge1  
{
    "ShardId": "shardId-000000000000",
    "SequenceNumber": "49591791737946085028906975051711880461380150184625831938"
}
{
    "Records": [
        {
            "Data": "aG9nZWhvZ2U=",
            "PartitionKey": "123",
            "ApproximateArrivalTimestamp": 1546849899.19,
            "SequenceNumber": "49591791737946085028906975044094438871988285374419959810"
        },
        {
            "Data": "aG9nZTE=",
            "PartitionKey": "123",
            "ApproximateArrivalTimestamp": 1546851156.579,
            "SequenceNumber": "49591791737946085028906975051711880461380150184625831938"
        }
    ],
    "NextShardIterator": "AAAAAAAAAAFQkY****************==",
    "MillisBehindLatest": 0
}

指定データをKinesisBase64 エンコーディング後、Dataに文字列が格納される。
Base64 デコーディングする事により元データ参照可能。
Base64 エンコーディング・デコーディングサイト: Base64 Decode and Encode - Online

また、時刻に関してはtimestamp形式で格納される。
UNIX時間(UNIX時刻)から日付に変換サイト: UNIX時間⇒日付変換 - 高精度計算サイト

■ストリーム削除

aws kinesis delete-stream --stream-name <ストリーム名>

AWS WEBコンソールからKinesisのData Streamの挙動モニタリング
AWS Kinesis → Data Stream → ストリーム名 → モニタリングへ移動

  • 下記図を確認
    • GetRecords.Bytes
    • GetRecords.Records
    • PutRecord.Bytes
    • PutRecords.Records

図の中に青い丸(単一データ)、又は青い線(複数データ)でグラフ化されているば正常

  • ※ 上部赤い線は制限値(Maxの値)なので無視で問題ない