ラズパイのリソースが余っていたので、semaphore を導入して遊んでみようと思います。
※ 事前に下記を導入する必要ありです。
・MySQL >= 5.6.4/MariaDB >= 5.3
・git >= 2.x
【Raspberry Pi】CentOS7 に Zabbix をソースからインストールしてみる
ラズベリーパイで Zabbix を構築しようと思ったんですが、CentOS7 用のパッケージがなかったんですよね…
なんで、ソースからインストールしなきゃ、ってことで備忘録です。
ついでに Nginx と php-fpm もソースから最新版を導入してみます。
【Lambda】CloudWatch の通知を Lambda で Chatwork に飛ばしてみる【Python】
こんにちは。
表題の通り、CloudWatch の Alarm 通知を Chatwork に通知してみます。
ランタイムは前回と同じく python 3.7 です。
ROOMNO にメッセージを通知するルームナンバ、 TOKEN に ChatWorkToken を定義すれば動きます。
import boto3
import json
import logging
import os
import urllib
from base64 import b64decode
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError
# Chatwork のルームナンバ定義
ROOMNO = 'xxxxxxxxxxxxxxxx'
# WEB_HOOKURL
URL = f'https://api.chatwork.com/v2/rooms/{ROOMNO}/messages'
# ChatWorkToken 定義
TOKEN = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
logger.info("Event: " + str(event))
# メッセージ取得
message = json.loads(event['Records'][0]['Sns']['Message'])
logger.info("Message: " + str(message))
alarm_name = message['AlarmName']
new_state = message['NewStateValue']
reason = message['NewStateReason']
# ヘッダ情報
headers = {
'X-ChatWorkToken': TOKEN,
}
# 通知内容
sns_message = {
'body': "%s state is now %s: %s" % (alarm_name, new_state, reason),
}
# エンコード
msns_message = urllib.parse.urlencode(sns_message)
msns_message = msns_message.encode('utf-8')
# リクエスト発行
req = Request(URL, data=msns_message, headers=headers)
with urlopen(req) as res:
result = json.loads(res.read().decode("utf-8"))
【Python】JMeter の実行結果をスプレッドシートに出力するスクリプトを書いてみた【gspread】
こんにちは。
JMeter が出力する結果を Google のスプレッドシートに出力してみようと考えまして、調べてみると Python に便利なライブラリがあったんで作ってみました。
※ 下記の JMeter デプロイ用 Playbook にも入れているのでよければご利用くださいませ。
https://github.com/keisukesanuki/jmeter-MS
Python スクリプト
#!/usr/bin/python3
import gspread
import json
import csv
import sys
import itertools
# シークレットキーを絶対パスで指定
SECRETJSON = "/usr/local/jmeter/bin/sacred-drive.json"
# スプレッドシートキーを定義
SPREADSHEET_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
############################################################################
## 関数
# 数字と文字コンバーター
def num2alpha(num):
if num<=26:
return chr(64+num)
elif num%26==0:
return num2alpha(num//26-1)+chr(90)
else:
return num2alpha(num//26)+chr(64+num%26)
#############################################################################
## 認証
# お約束
from oauth2client.service_account import ServiceAccountCredentials
scope = ['https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive']
# ダウンロードした json ファイルを定義
credentials = ServiceAccountCredentials.from_json_keyfile_name(SECRETJSON, scope)
# Google API にログイン
gc = gspread.authorize(credentials)
# スプレッドシートのシート1を開く
worksheet = gc.open_by_key(SPREADSHEET_KEY).sheet1
##############################################################################
## 処理
# コマンドライン引数を取得
args = sys.argv
csvfile = args[1]
# CSVファイルの内容を配列に代入
with open(csvfile) as fp:
results_list_ex = list(csv.reader(fp))
# 2次元配列を1次元配列に変換
results_list = list(itertools.chain.from_iterable(results_list_ex))
# カウント変数初期化
COUNT_NUM = 1
# 空白行探索
while str(len(worksheet.cell(COUNT_NUM, 1).value)) != "0":
COUNT_NUM += 1
# 編集する範囲を指定
cell_list = worksheet.range('A'+str(COUNT_NUM)+':'+num2alpha(len(results_list))+str(COUNT_NUM))
# cell_listにresults_listの配列を代入
for i,cell in enumerate(cell_list):
cell.value = results_list[i]
# 結果の保存
worksheet.update_cells(cell_list)第一引数に csv ファイルを指定することで、結果をスプレッドシートに出力するスクリプトです。
このスクリプトを後述の JMeter 起動用スクリプトで利用します。
シェルスクリプト
#!/bin/sh
DATE=$(date +"%Y%m%d")
OPTIME=$(date +"%Y%m%d-%H%M%S")
# 結果の出力先ディレクトリを指定
LOGDIR=/var/www/html/${DATE}
# JMXファイルを指定
FILE_JMX=/usr/local/jmeter/bin/templates/build-web-test-plan.jmx
# 日付ディレクトリの作成
mkdir -p ${LOGDIR}
# JMeter 起動
/usr/local/jmeter/bin/jmeter -Dsun.net.inetaddr.ttl=0 -n -t ${FILE_JMX} -j ${LOGDIR}/${OPTIME}.log -l ${LOGDIR}/${OPTIME}.jtl -e -o ${LOGDIR}/${OPTIME}_th${JMETER_THREAD}${2}/ -r
# CSV ファイルの作成
cat ${LOGDIR}/${OPTIME}_th${JMETER_THREAD}${2}/statistics.json | jq -r ". [] | [.transaction,.sampleCount,.errorCount,.errorPct,.meanResTime,.minResTime,.maxResTime,.pct1ResTime,.pct2ResTime,.pct3ResTime,.throughput,.receivedKBytesPerSec,.sentKBytesPerSec] | @csv" | grep "Total" > ${LOGDIR}/${OPTIME}_th${JMETER_THREAD}${2}/statistics.csv
# スプレッドシートに結果を出力
/usr/local/bin/main.py ${LOGDIR}/${OPTIME}_th/statistics.csvJMeter は json で結果を出力するので jq で無理やり csv に変換してます。
Python だと簡単に実装できて楽ですね。
補足
スクリプトの実行に下記のパッケージ導入が必要です。
yum install python3 python-devel jq pip3 install gspread pip3 install oauth2client
【Ansible】Ansible で AWS の3層ネットワークを構築する【IaC】
こんにちは。
表題の通り AWS の 3層ネットワークを構築する playbook を用意してみます。
※ 詳細は README を参照ください。
https://github.com/keisukesanuki/aws-vpc-3layer
作るもの
・VPC
・SUBNET
・INTERNETGATEWAY
・NATGATEWAY
・ROUTETABLE
ディレクトリ構造
. ├── README.md ├── ansible.cfg ├── hosts ├── roles │ └── aws_vpc │ ├── tasks │ │ └── main.yml │ └── vars │ └── main.yml └── vpc_create.yml
playbook
---
# tasks file for aws_vpc
- name: create_vpc
ec2_vpc_net:
name: "{{ vpc_name }}"
cidr_block: "{{ vpc_cidr }}"
region: "{{ region }}"
profile: "{{ profile }}"
dns_hostnames: yes
dns_support: yes
register: vpc_info
# PUBLIC_SUBNET 作成
- name: create_public_subnet
ec2_vpc_subnet:
vpc_id: "{{ vpc_info.vpc.id }}"
cidr: "{{ item.pub_subnet_cidr }}"
az: "{{ item.subnet_az }}"
region: "{{ region }}"
resource_tags: { "Name":"{{ item.pub_subnet_name }}" }
profile: "{{ profile }}"
register: pubsub_info
with_items:
- "{{ pub_subnet }}"
# DMZ_SUBNET 作成
- name: create_dmz_subnet
ec2_vpc_subnet:
vpc_id: "{{ vpc_info.vpc.id }}"
cidr: "{{ item.dmz_subnet_cidr }}"
az: "{{ item.subnet_az }}"
region: "{{ region }}"
resource_tags: { "Name":"{{ item.dmz_subnet_name }}" }
profile: "{{ profile }}"
register: pubsub_info
with_items:
- "{{ dmz_subnet }}"
# PRIVATE_SUBNET 作成
- name: create_private_subnet
ec2_vpc_subnet:
vpc_id: "{{ vpc_info.vpc.id }}"
cidr: "{{ item.pri_subnet_cidr }}"
az: "{{ item.subnet_az }}"
region: "{{ region }}"
resource_tags: { "Name":"{{ item.pri_subnet_name }}" }
profile: "{{ profile }}"
register: prisub_info
with_items:
- "{{ pri_subnet }}"
# IGW 作成
- name: create_igw
ec2_vpc_igw:
vpc_id: "{{ vpc_info.vpc.id }}"
region: "{{ region }}"
tags: { "Name":"{{ igw_name }}" }
profile: "{{ profile }}"
register: igw_info
# ROUTETABLE 作成(IGW)
- name: create_route_table
ec2_vpc_route_table:
vpc_id: "{{ vpc_info.vpc.id }}"
subnets: "{{ atache_igw_subnet }}"
routes:
- dest: 0.0.0.0/0
gateway_id: "{{ igw_info.gateway_id }}"
region: "{{ region }}"
profile: "{{ profile }}"
resource_tags: { "Name":"{{ rttable_pub_name }}" }
# NGW の ID を取得
- name: get_subnet_id
shell: aws ec2 describe-subnets --region {{ region }} --profile {{ profile }} --output text | grep -B 1 {{ ngw_subnet_name }} | awk 'NR==1 {print $12}'
register: ngw_subnet_id
#- name: show
# debug:
# msg: "{{ ngw_subnet_id.stdout }}"
# NGW 作成
- name: create_ngw
ec2_vpc_nat_gateway:
subnet_id: "{{ ngw_subnet_id.stdout }}"
region: "{{ region }}"
profile: "{{ profile }}"
register: ngw_info
#- name: show
# debug:
# msg: "{{ ngw_info.nat_gateway_id }}"
# NGW 作成まで待つ
- name: wait_for_ngw
pause:
minutes: 5
# ROUTETABLEの作成(NGW)
- name: create_route_table2
ec2_vpc_route_table:
vpc_id: "{{ vpc_info.vpc.id }}"
subnets: "{{ atache_ngw_subnet }}"
routes:
- dest: 0.0.0.0/0
gateway_id: "{{ ngw_info.nat_gateway_id }}"
region: "{{ region }}"
profile: "{{ profile }}"
resource_tags: { "Name":"{{ rttable_dmz_name }}" }NATGATEWAY の ID が上手く取得できなかったので awscli の結果をパースして ngw_subnet_id に渡しています。
変数定義
---
# vars file for aws_vpc
# REGION
region: "ap-northeast-1"
# PROFILE
profile: "default"
# VPC
vpc_name: "sanuki-wd-vpc2"
vpc_cidr: "10.10.0.0/16"
# IGW
igw_name: "sanuki-igw2"
# NGW
ngw_name: "sanuki-ngw2"
# NGWを作成するサブネット名
ngw_subnet_name: "sanuki-wd-public-subnet2-a"
# ROUTETABLE(PUBLIC)
rttable_pub_name: "sanuki-pub-rt2"
# ROUTETABLE(DMZ)
rttable_dmz_name: "sanuki-dmz-rt2"
# PUBLIC_SUBNET
pub_subnet:
- { pub_subnet_cidr: "10.10.10.0/24" ,subnet_az: "ap-northeast-1a" ,pub_subnet_name: "sanuki-wd-public-subnet2-a" }
- { pub_subnet_cidr: "10.10.20.0/24" ,subnet_az: "ap-northeast-1c" ,pub_subnet_name: "sanuki-wd-public-subnet2-c" }
# DMZ_SUBNET
dmz_subnet:
- { dmz_subnet_cidr: "10.10.30.0/24" ,subnet_az: "ap-northeast-1a" ,dmz_subnet_name: "sanuki-wd-dmz-subnet2-a" }
- { dmz_subnet_cidr: "10.10.40.0/24" ,subnet_az: "ap-northeast-1c" ,dmz_subnet_name: "sanuki-wd-dmz-subnet2-c" }
# PRIVATE_SUBNET
pri_subnet:
- { pri_subnet_cidr: "10.10.50.0/24" ,subnet_az: "ap-northeast-1a" ,pri_subnet_name: "sanuki-wd-private-subnet2-a" }
- { pri_subnet_cidr: "10.10.60.0/24" ,subnet_az: "ap-northeast-1c" ,pri_subnet_name: "sanuki-wd-private-subnet2-c" }
# IGWに紐付けるサブネット
atache_igw_subnet:
- "10.10.10.0/24"
- "10.10.20.0/24"
# NGWに紐付けるサブネット
atache_ngw_subnet:
- "10.10.30.0/24"
- "10.10.40.0/24"NatGateway が片方の AZ にしかないため、冗長性の観点からは ? となりますが、まぁいいでしょう。
↓ 2層の playbook はこちら
【AWS】Data Lifecycle Manager を CloudFormation で設定してみた【dlm】
EBS のスナップショットを取得する Data Lifecycle Manager というマネージドサービスがございます。
こちらを一括で設定する CloudFormation のテンプレートを作成しました。
AWSTemplateFormatVersion: "2010-09-09"
Description: "DLM Configuration YAML"
# パラメータセッティング
Parameters:
ProjectName:
Type: String
LotateNum:
Type: Number
Default: 3
GetTime:
Type: String
Default: "18:00"
Resources:
# DLM IAM ロール作成
CreateDlmRole:
Type: AWS::IAM::Role
Properties:
RoleName: 'AWSDataLifecycleManagerDefaultRole'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- dlm.amazonaws.com
Action:
- sts:AssumeRole
Path: /service-role/
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSDataLifecycleManagerServiceRole
# DLM 作成
BasicLifecyclePolicy:
Type: "AWS::DLM::LifecyclePolicy"
Properties:
Description: !Join [ "-", [ !Ref ProjectName, dlm ] ]
State: "ENABLED"
ExecutionRoleArn: !Sub "arn:aws:iam::${AWS::AccountId}:role/service-role/AWSDataLifecycleManagerDefaultRole"
PolicyDetails:
ResourceTypes:
- "VOLUME"
TargetTags:
-
Key: "dlmtarget"
Value: "true"
Schedules:
-
Name: !Join [ "-", [ !Ref ProjectName, daily-schedule ] ]
TagsToAdd:
-
Key: "type"
Value: !Join [ "-", [ !Ref ProjectName, scheduled-snapshot ] ]
CreateRule:
Interval: 24
IntervalUnit: "HOURS"
Times:
- !Ref GetTime
RetainRule:
Count: !Ref LotateNum
CopyTags: true各種パラメータは下記の通りに設定して下さい。
・ProjectName ⇒ DLM リソース の prefix
・LotateNum ⇒ スナップショットの保持期間を指定
・GetTime ⇒ スナップショットの取得時間を UTCで指定 ( 例:10:00、08:35、02:48 )
【AWS】EBS のスナップショットを取得して世代管理してみる【シェルスクリプト】
こんにちは。
表題の通りです。
DLM でもよいのですが、最長のインターバルが 24 時間なので、要件が合わない時のために。
#!/bin/sh
# スナップショットの保持世代数を定義
LOTATE_NUM=3
# ホストネームを定義
HOSTNAME=
# スナップショットを取得するボリュームIDを定義
VOLID=
# スナップショットを取得
aws ec2 create-snapshot --volume-id $VOLID --tag-specification 'ResourceType="snapshot",Tags=[{Key="Name",Value="script-create"}]' --description "$HOSTNAME snapshot"
# 指定した世代数分になるようにスナップショットを削除
SNAPSHOTS_NUM=`aws ec2 describe-snapshots --output text | grep $VOLID | grep "$HOSTNAME snapshot" | wc -l`
while [ ${SNAPSHOTS_NUM} -gt ${LOTATE_NUM} ]
do
aws ec2 delete-snapshot --snapshot-id `aws ec2 describe-snapshots --output text | grep $VOLID | grep "$HOSTNAME snapshot" | sort -k 8 | awk 'NR==1 {print $7}'`
SNAPSHOTS_NUM=`aws ec2 describe-snapshots --output text | grep $VOLID | grep "$HOSTNAME snapshot" | wc -l`
done
# awscli の導入
curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py" sudo python get-pip.py sudo pip install awscli aws configure
【Python】Excel から Ansible のコードを自動生成する①【構築自動化】
Excel から必要な情報を抜き出して、Ansible の ini ファイルを置換する Python スクリプトを書いてみました。
#!/usr/bin/python3
# coding: UTF-8
import openpyxl
import sys
# Ansible の ini ファイルを定義(置換前)
org_file_name = "all.yml.org"
# Ansible の ini ファイルを定義(置換後)
file_name = "all.yml"
# コマンドライン引数の数を確認
if len(sys.argv) != 2:
print("input error")
sys.exit(1)
# Excel ファイル名を変数に代入
args = sys.argv
target = args[1]
# Excel データを取得
wb = openpyxl.load_workbook(target)
sheet = wb.get_sheet_by_name('Sheet1')
# セルデータの取得関数
def get_cell(x, y):
param = sheet.cell(row=x,column=y).value
return param
# 必要なセルの情報を取得
domain = get_cell(2, 2)
docroot = get_cell(3, 2)
# 置換前の ini ファイルを開く
with open(org_file_name, encoding="cp932") as f:
data_lines = f.read()
# 置換
data_lines = data_lines.replace("xxx", domain)
data_lines = data_lines.replace("yyy", docroot)
# 置換後のiniファイルを作成
with open(file_name, 'w', encoding="cp932") as f:
f.write(data_lines)スクリプトのコマンドライン引数としてExcelファイル(.xlsx)を指定して実行してください。
【C言語】単純なTCPサーバをdemontoolsでデーモン化する【demontools】
C 言語で単純な TCP サーバを作って demontools でデーモン化してみます。
※ demontools を使う機会があったので備忘録を兼ねています。
TCPサーバ
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(){
int sockfd, sock_size, sock;
struct sockaddr_in server;
struct sockaddr_in client;
/* ソケット作成 */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
server.sin_family = AF_INET;
server.sin_port = htons(8888);
server.sin_addr.s_addr = INADDR_ANY;
/* ソケットにポート番号割り当て */
bind(sockfd, (struct sockaddr *)&server, sizeof(server));
/* 割り当てたポート番号へ接続が作成できることをシステムに伝える */
listen(sockfd, 5);
/* 接続要求を受ける度にソケットを新しく取得 */
while(1){
sock_size = sizeof(client);
sock = accept(sockfd, (struct sockaddr *)&client, &sock_size);
write(sock, "TEST\n", 5);
/* クライアントとの接続をクローズ */
close(sock);
}
close(sockfd);
return 0;
}エラー処理は省いています。
適当なディレクトリにコンパイルしてください。
# ディレクトリ移動 cd /usr/local/bin vi main.c =================== *上記コード =================== # コンパイル gcc main.c -o simple-server
demontools
demontools の設定です。
# demontoolsの導入 mkdir -p /package chmod 1755 /package cd /package wget http://cr.yp.to/daemontools/daemontools-0.76.tar.gz gunzip daemontools-0.76.tar tar -xpf daemontools-0.76.tar rm -f daemontools-0.76.tar cd admin/daemontools-0.76 cd src/ # ヘッダファイル修正 vi error.h ======================= extern int errno; ↓ #include <errno.h> ======================= # インストール cd .. package/install # centos7 では使用しないのでコメントアウト vi /etc/inittab ======================= #SV:123456:respawn:/command/svscanboot ======================= # サービスファイル作成 vi /etc/systemd/system/demontools.service ====================================================== [Unit] Description=run demontools during boot After=network.target [Service] User=root Group=root Type=simple RemainAfterExit=yes ExecStart=/command/svscanboot Restart=always LimitNOFILE=20480 [Install] WantedBy=multi-user.target ====================================================== # プロセスのデーモン化 mkdir /service/simple-server/ vi /service/simple-server/run ====================================================== #!/bin/sh exec /usr/local/bin/simple-server ====================================================== # ログ出力設定 mkdir /service/simple-server/log/ mkdir /var/log/simple-server vi /service/simple-server/log/run ============================================== #!/bin/sh exec /usr/local/bin/multilog t /var/log/simple-server ============================================== # 権限変更 chmod 755 /service/simple-server/run chmod 755 /service/simple-server/log/run # demontools 起動/自動起動設定 systemctl start demontools systemctl enable demontools
【シェルスクリプト】だいたいのサーバ情報を取得する便利スクリプト【サーバ移設】
取り敢えずこのスクリプトを実行すれば、ある程度のサーバ情報を取得できるよ、ってだけのスクリプトです。
#!/bin/sh
# 情報取得関数
function addinfo(){
# 情報を出力するファイル名を定義
OUTPUT=serverinfo-`hostname`.txt
# 情報内容を出力
echo "####### $1 #########" >> $OUTPUT
# コマンド結果を出力
$2 >> $OUTPUT
return 0
}
# ホストネーム
addinfo hostname "hostname"
# プロセス一覧
addinfo process-list "ps auxwwf"
# Listenポート一覧
addinfo listen-port "sudo netstat -lntp"
# ルートテーブル
addinfo route-table "sudo netstat -rn"
# rpmパッケージ
addinfo rpm-package "sudo rpm -qa | sort"
# 自動起動リスト
addinfo chkconfig "sudo chkconfig --list"
# OSバージョン
addinfo os-version "cat /etc/redhat-release"
# CPU
addinfo cpu-info "cat /proc/cpuinfo"
# メモリ
addinfo memory-info "free -m"
# ディスク
addinfo disk-info "df -hT"
# fstab
addinfo fstab "cat /etc/fstab"
# iptables
addinfo iptables "sudo service iptables status"
# ifconfig
addinfo ifconfig "ifconfig"