読者です 読者をやめる 読者になる 読者になる

ようへいの日々精進XP

よかろうもん

来年の isucon で泣かずに予選を終える為のメモ(1)

ISUCON メモ

tl;dr

isucon6 予選は何も出来ずに涙を飲んだので、来年は少しでも手を動かせるように過去問を触りながら isucon の雰囲気に慣れていきたい。

isucon6 予選の反省点

  • どの言語でとか等のチーム方針が明確では無かった
  • チーム方針が明確では無かったので当然役割分担も不明瞭だった
  • 過去問に触れずに挑んだ為、何をすれば良いのか全く解らなかった
  • 各種解析ツールの存在、使い方に慣れていなかった(そもそも使ったことが無かった)
  • データベースに関する知識、経験がほぼ 0 だった為、データベースのチューニングには全く手を付けることが出来なかった

ということで、今回は過去問を起動するところから、解析ツールを仕込むところまでやってみる。

過去問や解析ツールのメモ

Apache / Nginx アクセスログの解析

MySQL スローログの解析

アプリケーションの解析

過去問 matsuu さんに感謝

isucon2 から isucon5 まで用意されており、各過去問が vagrant 一発で起動させることが出来る。

isucon5 の予選で利用された問題を展開する例

$ git clone https://github.com/matsuu/vagrant-isucon.git
$ cd isucon5-qualifier-standalone
vagrant up

ブラウザでアクセスしたい場合には Vagrantfile を以下のように修正する。

$ diff -u Vagrantfile.original Vagrantfile
--- Vagrantfile.original        2016-09-25 11:35:04.349082426 +0900
+++ Vagrantfile 2016-09-24 21:27:00.276552570 +0900
@@ -28,7 +28,7 @@
 
   # Create a private network, which allows host-only access to the machine
   # using a specific IP.
-  # config.vm.network "private_network", ip: "192.168.33.10"
+  config.vm.network "private_network", ip: "192.168.33.10"
 
   # Create a public network, which generally matched to bridged network.
   # Bridged networks make the machine appear as another physical device on

ボクがログインしたらやれそうなこと...

これだったら出来そう

  • Nginx ログの解析
  • MySQL SlowLog 取得の設定
  • アプリケーション解析の設定

Nginx ログの解析

  • alp を使う場合に Nginx のアクセスログフォーマットを ltsv 形式に設定する
http {

  log_format ltsv "time:$time_local"
                  "\thost:$remote_addr"
                  "\tforwardedfor:$http_x_forwarded_for"
                  "\treq:$request"
                  "\tstatus:$status"
                  "\tmethod:$request_method"
                  "\turi:$request_uri"
                  "\tsize:$body_bytes_sent"
                  "\treferer:$http_referer"
                  "\tua:$http_user_agent"
                  "\treqtime:$request_time"
                  "\tcache:$upstream_http_x_cache"
                  "\truntime:$upstream_http_x_runtime"
                  "\tapptime:$upstream_response_time"
                  "\tvhost:$host";

  access_log  /var/log/nginx/access.log  ltsv;

  upstream app {
    server 127.0.0.1:8080;
  }

  server {
    location / {
      proxy_set_header Host $host;
      proxy_pass http://app;
    }
  }
}
  • alp でログ解析
$ sudo cat /var/log/nginx/access.log | ./alp -r | less
+-------+-------+-------+---------+-------+-------+-------+-------+--------+-----------+------------+-------------+-----------+--------+------------------------------------+
| COUNT |  MIN  |  MAX  |   SUM   |  AVG  |  P1   |  P50  |  P99  | STDDEV | MIN(BODY) | MAX(BODY)  |  SUM(BODY)  | AVG(BODY) | METHOD |                URI                 |
+-------+-------+-------+---------+-------+-------+-------+-------+--------+-----------+------------+-------------+-----------+--------+------------------------------------+
|   207 | 0.001 | 2.669 | 225.738 | 1.091 | 0.001 | 1.012 | 2.548 |  0.612 | 16285.000 |  16791.000 | 2966944.000 | 14333.063 | GET    | /                                  |
|     3 | 0.654 | 2.499 |   3.875 | 1.292 | 0.654 | 0.654 | 0.722 |  0.854 |  3476.000 |   3747.000 |   10970.000 |  3656.667 | GET    | /diary/entry/489651                |
|     9 | 0.013 | 2.292 |   3.258 | 0.362 | 0.013 | 0.025 | 0.588 |  0.704 | 53984.000 |  61469.000 |  530916.000 | 58990.667 | GET    | /diary/entries/verlie_crooks151

(snip)

MySQL SlowLog 取得の設定

  • my.cnf に設定を追加
[mysqld]

(snip)

slow_query_log                = 1
slow_query_log_file           = /var/log/mysql/mysqld-slow.log
long_query_time               = 0
log-queries-not-using-indexes = 
  • pt-query-digest で解析
$ sudo pt-query-digest /var/log/mysql/mysqld-slow.log

# 1.3s user time, 0 system time, 28.45M rss, 85.27M vsz
# Current date: Sun Sep 25 11:54:50 2016
# Hostname: vagrant
# Files: /var/log/mysql/mysqld-slow.log
# Overall: 7.45k total, 27 unique, 2.45 QPS, 0.00x concurrency ___________
# Time range: 2016-09-25 08:22:49 to 09:13:31
# Attribute          total     min     max     avg     95%  stddev  median
# ============     ======= ======= ======= ======= ======= ======= =======
# Exec time             3s     3us   204ms   432us   247us     6ms   113us
# Lock time          238ms       0     2ms    31us    44us    38us    27us
# Rows sent         21.36k       0    1000    2.94    0.99   40.61    0.99
# Rows examine       5.71M       0 488.50k  804.05    0.99  19.01k       0
# Query size       817.88k      11     226  112.42  112.70   19.13  112.70

# Profile
# Rank Query ID           Response time Calls R/Call V/M   Item
# ==== ================== ============= ===== ====== ===== ===============
#    1 0xDE6DD0309F9386F8  1.0643 33.1%     6 0.1774  0.00 SELECT relations
#    2 0xD44150558D8295E1  0.9162 28.5%  6942 0.0001  0.00 SELECT relations
#    3 0x492C7CAB538DE80D  0.8483 26.3%     6 0.1414  0.00 SELECT footprints
#    4 0x064A5B2042FC8316  0.2127  6.6%     7 0.0304  0.01 SELECT entries
#    5 0xCE3E456E0D0EFD1C  0.0584  1.8%     6 0.0097  0.01 SELECT comments entries
# MISC 0xMISC              0.1200  3.7%   483 0.0002   0.0 <22 ITEMS>

# Query 1: 0.00 QPS, 0.00x concurrency, ID 0xDE6DD0309F9386F8 at byte 317533
# Scores: V/M = 0.00
# Time range: 2016-09-25 08:23:03 to 09:13:31
# Attribute    pct   total     min     max     avg     95%  stddev  median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count          0       6
# Exec time     33      1s   168ms   204ms   177ms   198ms    13ms   163ms
# Lock time      0   176us    28us    32us    29us    31us     1us    28us
# Rows sent      5   1.24k     212     212     212     212       0     212
# Rows examine  49   2.83M 483.53k 483.53k 483.53k 483.53k       0 483.53k
# Query size     0     522      87      87      87      87       0      87
# String:
# Databases    isucon5q
# Hosts        localhost
# Users        root
# Query_time distribution
#   1us
#  10us
# 100us
#   1ms
#  10ms
# 100ms  ################################################################
#    1s
#  10s+
# Tables
#    SHOW TABLE STATUS FROM `isucon5q` LIKE 'relations'\G
#    SHOW CREATE TABLE `isucon5q`.`relations`\G
# EXPLAIN /*!50100 PARTITIONS*/
SELECT * FROM relations WHERE one = '3657' OR another = '3657' ORDER BY created_at DESC\G

(snip)

アプリケーション解析の設定

  • rack-lineprof を仕込む(事前に bundle install しておく)
$ diff -u app.rb.original app.rb
--- app.rb.original     2016-09-25 11:59:24.195894782 +0900
+++ app.rb      2016-09-25 12:00:10.071619573 +0900
@@ -4,6 +4,7 @@
 require 'tilt/erubis'
 require 'erubis'
 require 'rack-lineprof'
+require 'profiler'
 
 module Isucon5
   class AuthenticationError < StandardError; end
@@ -18,6 +19,7 @@
 end
 
 class Isucon5::WebApp < Sinatra::Base
+  use Rack::Lineprof
   use Rack::Session::Cookie
   set :erb, escape_html: true
   set :public_folder, File.expand_path('../../static', __FILE__)
  • アプリケーションにアクセス

ブラウザで 192.168.33.10/?lineprof=app.rb にアクセスする。

$ sudo journalctl -f

(snip)

 925 12:04:18 vagrant bundle[5117]:               .......
 925 12:04:18 vagrant bundle[5117]:                |  189        entry[:title] = entry[:body].split(/\n/).first
 925 12:04:18 vagrant bundle[5117]:                |  190        entries_of_friends << entry
 9月 25 12:04:18 vagrant bundle[5117]:    2.9ms     3 |  191        break if entries_of_friends.size >= 10
 9月 25 12:04:18 vagrant bundle[5117]:                |  192      end
 9月 25 12:04:18 vagrant bundle[5117]:                |  193
 9月 25 12:04:18 vagrant bundle[5117]:  151.4ms  1587 |  194      comments_of_friends = []
 9月 25 12:04:18 vagrant bundle[5117]:  114.7ms   528 |  195      db.query('SELECT * FROM comments ORDER BY created_at DESC LIMIT 1000').each do |comment|
 9月 25 12:04:18 vagrant bundle[5117]:    0.4ms    20 |  196        next unless is_friend?(comment[:user_id])
 9月 25 12:04:18 vagrant bundle[5117]:                |  197        entry = db.xquery('SELECT * FROM entries WHERE id = ?', comment[:entry_id]).first
 9月 25 12:04:18 vagrant bundle[5117]:                |  198        entry[:is_private] = (entry[:private] == 1)
 9月 25 12:04:18 vagrant bundle[5117]:               .......
 9月 25 12:04:18 vagrant bundle[5117]:                |  200        comments_of_friends << comment
 9月 25 12:04:18 vagrant bundle[5117]:                |  201        break if comments_of_friends.size >= 10
 9月 25 12:04:18 vagrant bundle[5117]:  151.8ms  1884 |  202      end
 9月 25 12:04:18 vagrant bundle[5117]:  128.2ms   627 |  203
 9月 25 12:04:18 vagrant bundle[5117]:    2.4ms    84 |  204      friends_query = 'SELECT * FROM relations WHERE one = ? OR another = ? ORDER BY created_at DESC'
 9月 25 12:04:18 vagrant bundle[5117]:                |  205      friends_map = {}
 9月 25 12:04:18 vagrant bundle[5117]:    0.4ms     2 |  206      db.xquery(friends_query, current_user[:id], current_user[:id]).each do |rel|
 9月 25 12:04:18 vagrant bundle[5117]:                |  207        key = (rel[:one] == current_user[:id] ? :another : :one)
 9月 25 12:04:18 vagrant bundle[5117]:                |  208        friends_map[rel[key]] ||= rel[:created_at]
 9月 25 12:04:18 vagrant bundle[5117]:               .......
 9月 25 12:04:18 vagrant bundle[5117]:                |  211
 9月 25 12:04:18 vagrant bundle[5117]:                |  212      query = <<SQL
 9月 25 12:04:18 vagrant bundle[5117]:  170.6ms   641 |  213  SELECT user_id, owner_id, DATE(created_at) AS date, MAX(created_at) AS updated
 9月 25 12:04:18 vagrant bundle[5117]:                |  214  FROM footprints
 9月 25 12:04:18 vagrant bundle[5117]:                |  215  WHERE user_id = ?
 9月 25 12:04:18 vagrant bundle[5117]:               .......

(snip)

上記のように行ごとに処理に要した時間が出力される。

ひとまず

解析する為の仕込みは出来た。ただ、これらから何を読み取って、どこを改善していくか...ここからが本当の isucon なんだと思う。

Nginx の rewrite を使ったリダイレクトで URL に #(アンカーリンク)が付いていたらどうなるの?

nginx メモ

追記

以下、同僚のぐっさんに教えて頂いたので追記。

tl;dr

http://xxx.xxx.xx.xxx/index.html#foo のようなリンクを http://xxx.xxx.xx.xxx/maintenance.html にリダイレクトさせた場合に、#foo ってどうなのかなと思って調べてみた。

出来れば、リダイレクト先では #foo を削除出来たら嬉しい。

memo

試した環境

bash-3.2$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.11.6
BuildVersion:   15G31

bash-3.2$ docker-machine -version
docker-machine version 0.6.0, build e27fb87

bash-3.2$ docker exec -t -i nginx nginx -v
nginx version: nginx/1.11.3

結論

  • リダイレクト先にも # はくっついてくる

雑な Nginx 設定

server {

    listen 80;
    server_name example.org;
    charset utf-8;

    location / {
        root   html;
        index  index.html index.htm;
        rewrite /index.html /maintenance.html permanent;
    }
}

Dockerfile は以下のように用意。

FROM nginx:alpine
RUN rm /etc/nginx/conf.d/default.conf
RUN mkdir /etc/nginx/html
ADD maintenance.html /etc/nginx/html/
ADD index.html /etc/nginx/html/
ADD demo.conf /etc/nginx/conf.d/

各コンテンツ。

bash-3.2$ cat index.html
index.html
bash-3.2$ cat maintenance.html
maintenance.html

以下のようにコンテナを起動。

docker run --name=nginx -d -p 80:80 inokappa/nginx-demo

curl で試す

bash-3.2$ curl -vL 'http://xxx.xxx.xx.xxx/index.html#foo'
*   Trying xxx.xxx.xx.xxx...
* Connected to xxx.xxx.xx.xxx (xxx.xxx.xx.xxx) port 80 (#0)
> GET /index.html HTTP/1.1
> Host: xxx.xxx.xx.xxx
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Server: nginx/1.11.3
< Date: Tue, 20 Sep 2016 13:59:40 GMT
< Content-Type: text/html
< Content-Length: 185
< Location: http://xxx.xxx.xx.xxx/maintenance.html
< Connection: keep-alive
<
* Ignoring the response-body
* Connection #0 to host xxx.xxx.xx.xxx left intact
* Issue another request to this URL: 'http://xxx.xxx.xx.xxx/maintenance.html'
* Found bundle for host xxx.xxx.xx.xxx: 0x7fed63d10e70
* Re-using existing connection! (#0) with host xxx.xxx.xx.xxx
* Connected to xxx.xxx.xx.xxx (xxx.xxx.xx.xxx) port 80 (#0)
> GET /maintenance.html HTTP/1.1
> Host: xxx.xxx.xx.xxx
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.11.3
< Date: Tue, 20 Sep 2016 13:59:40 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 17
< Last-Modified: Tue, 20 Sep 2016 07:12:24 GMT
< Connection: keep-alive
< ETag: "57e0e158-11"
< Accept-Ranges: bytes
<
maintenance.html
* Connection #0 to host xxx.xxx.xx.xxx left intact

よく見ると...

< Location: http://192.168.99.100/maintenance.html

Response ヘッダの Location は http://192.168.99.100/maintenance.html で返ってきているのでなんか期待できそうだ。

ブラウザで見る

f:id:inokara:20160920230716p:plain

それ、リダイレクト。

f:id:inokara:20160920230729p:plain

うおお、#foo が付いたままや。

アクセスログ見てみる

とりあえず、アクセスログを見てみる。

# curl でアクセスした場合
xxx.xxx.xx.x - - [20/Sep/2016:13:59:40 +0000] "GET /index.html HTTP/1.1" 301 185 "-" "curl/7.43.0" "-"
xxx.xxx.xx.x - - [20/Sep/2016:13:59:40 +0000] "GET /maintenance.html HTTP/1.1" 200 17 "-" "curl/7.43.0" "-"

# ブラウザでアクセスした場合
xxx.xxx.xx.x - - [20/Sep/2016:14:03:49 +0000] "GET /index.html HTTP/1.1" 301 185 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36" "-"
xxx.xxx.xx.x - - [20/Sep/2016:14:03:49 +0000] "GET /maintenance.html HTTP/1.1" 200 17 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36" "-"

あら、ログには #foo はくっついてきてませんがな。イメージとしてクエリパラメータ(?foo=bar)と同じような内容を想定していたけど。ちなみに、クエリパラメータをくっつけた場合には以下のようなログが記録される。

# curl でアクセスした場合
xxx.xxx.xx.x - - [20/Sep/2016:14:11:34 +0000] "GET /index.html?foo=bar HTTP/1.1" 301 185 "-" "curl/7.43.0" "-"
xxx.xxx.xx.x - - [20/Sep/2016:14:11:34 +0000] "GET /maintenance.html?foo=bar HTTP/1.1" 200 17 "-" "curl/7.43.0" "-"

# ブラウザでアクセスした場合
xxx.xxx.xx.x - - [20/Sep/2016:14:12:10 +0000] "GET /index.html?foo=bar HTTP/1.1" 301 185 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36" "-"
xxx.xxx.xx.x - - [20/Sep/2016:14:12:10 +0000] "GET /maintenance.html?foo=bar HTTP/1.1" 200 17 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36" "-"

ちゃんとクエリパラメータがログに記録されている。これであればサーバーサイドでパラメータを削除したり、書き換えたりすることができそう。ちなみに、クエリパラメータを削除したい場合には以下のような設定を書くことでクエリパラメータを削除した状態でリダイレクトされる。

server {

    listen 80;
    server_name example.org;
    charset utf-8;

    location / {
        root   html;
        index  index.html index.htm;
        rewrite /index.html /maintenance.html? permanent;
    }
}

ということで

アンカーリンクは...

リダイレクト先にも引き継がれてしまう。

なんで?

アンカーリンクでサーバーサイドというよりもブラウザで解釈されるものだからかなと。

誤り等あればご指摘頂ければ幸いです。

Elasticsearch の Multi Search API メモ

Elasticsearch メモ

tl;dr

  • 定期的に Elasticsearch に問い合わせを行うバッチスクリプトで Elasticsearch への問い合わせ回数を減らしたい

memo

状況

  • Amazon ES に保存されたログを検索するバッチスクリプトで特定の ID 毎に日付を範囲してログの件数を取得する
  • 当初は ID が少なかったのであまり意識していなかったけど、テストで ID を増やしていったところ CPU 負荷も上がるし、たまに Amazon ES への接続エラーも発生している(認証辺りも絡んでいるかもしれない)
  • ID 毎に Elasticsearch に問い合わせを行う実装にしていた(先に気づけよ的な話ではある)

戦略

www.elastic.co

Multi Search API で実装すれば良さそう。

Multi Search API を使う前

以下のような感じのスクリプトで ID 毎に Elaseticsearch に検索していた。

#!/bin/bash

declare -A _hash
_hash["foo"]="2016-09-19T10:00:00+09:00"
_hash["bar"]="2016-09-19T10:00:00+09:00"
_hash["baz"]="2016-09-19T10:00:00+09:00"

while true;
do
  for key in ${!_hash[@]}; do
    curl -s -XGET "https://${AMAZON_ES_ENDPOINT}/cwl-*/_search" -w "\n" -d "
    {
      \"size\": 0,
      \"query\" : {\"term\" : { \"param_id\" : \"${key}\" }},
      \"aggregations\": {
        \"id_name\": {
          \"terms\": {\"field\": \"param_id\"},
          \"aggregations\": {
            \"id_count\": {
              \"filter\":{
                \"range\": { \"@timestamp\": { \"gte\": \"${_hash[${key}]}\", \"lte\": \"now\" }}
              }
            }
          }
        }
      }
    }" | jq -c '.aggregations.id_name.buckets[0]|{"id": .key, "count": .id_count.doc_count}'
    sleep 1
  done
  sleep 3
done

実行すると以下のような出力が得られる。

{"count":867,"id":"foo"}
{"count":863,"id":"bar"}
{"count":865,"id":"baz"}

Multi Search API を使った場合

以下のような感じで検索する。コードの行数も減らせてイイ感じ。

#!/bin/bash

declare -A _hash
_hash["foo"]="2016-09-19T10:00:00+09:00"
_hash["bar"]="2016-09-19T10:00:00+09:00"
_hash["baz"]="2016-09-19T10:00:00+09:00"

while true;
do
  queries=""
  for key in ${!_hash[@]}; do
    queries+="{\"index\": \"cwl-*\"}\n"
    queries+="{\"size\": 0,\"query\" : {\"term\" : { \"param_id\" : \"${key}\" }},\"aggregations\": {\"id_name\": {\"terms\": {\"field\": \"param_id\"},\"aggregations\": {\"id_count\": {\"filter\":{\"range\": { \"@timestamp\": { \"gte\": \"${_hash[${key}]}\", \"lte\": \"now\" }}}}}}}}\n"
  done
  echo -e ${queries} | curl -s -XGET 'https://${AMAZON_ES_ENDPOINT}/_msearch' --data-binary @- | \
  jq -c '.responses[].aggregations.id_name.buckets[0]|{"count":.id_count.doc_count,"id":.key}'
  sleep 3
done

実行すると以下のような出力が得られる。

{"count":1778,"id":"foo"}
{"count":1744,"id":"bar"}
{"count":1841,"id":"baz"}

Multi Search API を使う場合、クエリは以下のような内容となる。

{"index": ${インデックス名}}
{"query" : ${実際のクエリ}
{"index": ${インデックス名}}
{"query" : ${実際のクエリ}

Elasticsearch へのリクエストは以下のような内容となる。

echo -e ${queries} | curl -s -XGET 'https://${AMAZON_ES_ENDPOINT}/_msearch' --data-binary @-

で、Multi Search API を使ったらどうなったか

以下のようにバッチを動かしているコンテナの CPU 使用率が少しだけ下がった。

f:id:inokara:20160919214204p:plain

以上

必要に応じて Multi Search API を使いましょう。

ISUCON 2016 の予選に参加して何も出来ずに泣いた

ISUCON

tl;dr

isucon.net

同僚の武川さんに声掛けて頂いて、「チーム初老丸」として初参加。参加チームの平均年齢だけであれば間違いなくダントツだったのではないか。

振り返り

どうだったのか(結果)

  • とにかく遅い Web アプリケーションサービスを目の前にまったく歯が立たず泣いた
  • 点数は書くのもはばかれる点数だったので泣いた
  • 何をすればいいのかがパッと思いつかずに辛くて泣いた
  • 雀の涙程のスキルやキャリアが全く役に立たずに泣いた

反省、感じたこと

  • 事前準備は絶対に必要(過去問をやっておくなど)
  • 調査用のコマンドはまとめておくべきだった
  • インフラもアプリケーションもプロファイリング力が最も重要
  • 「あー、ここにキャッシュを挟めば良さ気」と思っても実装を追加することが出来なかったのが辛かった
  • ということで、アプリケーションの実装力必要(実装力とまではいかないけど、コードを読むチカラは必要だと思う)
  • 各種参考実装は初期段階でスコアは出ないけど焦らない
  • インフラ側で出来ることは限られているかもしれない(今回はほとんどインフラは触れず)
  • systemd 慣れて無さすぎ

これからどうするか

  • 今年の問題が公開されたら、改めて手元でチャレンジしてみる
  • プロファイリングのチカラを付けたい

メモ、 当日得た知見等

systemd 関連

  • chkconfig の代替
sudo systemctl list-unit-files -t service
  • service xxxx [status|start|stop|restart] の代替
sudo systemctl status ${service} -l
sudo systemctl [enable|disable] ${service}
sudo systemctl [stop|start|restart|status] ${service}
  • systemd ユニットファイルを修正した後
sudo systemctl daemon-reload
  • systemd 配下のアプリケーションログ
sudo journalctl -f

Ruby 関連

  • Rack アプリケーションのプロファイルには rack-lineprof が良かった
  • String#gsub よりも String#tr が速かった
  • Gemfile の凍結方法
$ cat .bundle/config
---
BUNDLE_FROZEN: "0" #=> 1 だと凍結
BUNDLE_PATH: "vendor/bundle"
BUNDLE_DISABLE_SHARED_GEMS: "true"

Perl 関連

carton exec -- plackup -s Starlet -p ${port_number} --max-workers=5 xxxxx.psgi
carton exec -- plackup -s Starlet --listen /tmp/xxxxx.sock --max-workers=5 xxxxx.psgi

MySQL 関連

  • テーブルの index 確認
SHOW INDEX FROM ${table};
  • slow log
slow_query_log                = 1
slow_query_log_file           = /path/to/mysqld-slow.log
long_query_time               = 0
log-queries-not-using-indexes = 1

最後

来年は今年よりもスコアが取れるように頑張りたい。

参加された方々、お疲れ様でした。運営の皆様、大変お疲れ様でした。

td-agent 自体のログレベルを設定したい

td-agent fluentd メモ

tl;dr

  • td-agent 自体のログレベルを設定したい

memo

参考

docs.fluentd.org

動作確認環境

$ cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)

$ td-agent --version
td-agent 0.12.26

設定

  • /etc/td-agent/td-agent.conf
<system>
  log_level [info|warn|error|fatal|debug|trace]
</system>

infodebugtrace にしておくと、設定ファイルがログにダンプされるので、これを避けたい場合(そんなシチュエーションが在るかどうか判らないけど)には warnerror にしておくと良い。

以上

メモでした。

td-agent.conf 設定パラメータの値を環境変数から参照したい

fluentd td-agent メモ

tl;dr

  • td-agent.conf 設定パラメータの値を環境変数から参照したい

memo

動作確認環境

$ cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)

$ td-agent --version
td-agent 0.12.26

設定

  • /etc/sysconfig/td-agent
export TD_AGENT_LOG_LEVEL=debug
  • /etc/td-agent/td-agent.conf
<system>
  log_level "#{ENV['TD_AGENT_LOG_LEVEL']}"
</system>

(snip)

確認

  • service td-agent restart して /var/log/td-agent/td-agent.log を確認
(snip)

2016-09-17 09:10:04 +0900 [info]: using configuration file: <ROOT>
  <system>
    log_level debug
  </system>
  <source>
    @type forward
    bind 127.0.0.1
  </source>

(snip)

TD_AGENT_LOG_LEVEL の中身が展開されている。

以上

メモでした。

PowerShell で操作する Azure メモ(5)

Azure 雑なメモ

ども、かっぱです。

tl;dr

引続き、PowerShell で Azure を操作するメモ。

操作する環境は以下の通り。

PS C:\Users\Administrator\Downloads> [System.Environment]::OSVersion

                          Platform ServicePack                        Version                            VersionString
                          -------- -----------                        -------                            -------------
                           Win32NT                                    6.3.9600.0                         Microsoft Windows NT 6.3.9600.0

PS C:\Users\Administrator\Downloads> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      4.0
WSManStackVersion              3.0
SerializationVersion           1.1.0.1
CLRVersion                     4.0.30319.42000
BuildVersion                   6.3.9600.17400
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0}
PSRemotingProtocolVersion      2.2

内部ロードバランサを構成する

構成

f:id:inokara:20160911234015p:plain

クラウドサービス内に仮想マシンを構築

$_locationName  = "Japan West"
$_cloudService  = "oreno-cloudservice01"
$_vmType        = "Small"
$_imageName     = @(Get-AzureVMImage | ? {$_.OS -eq "Linux" -and $_.ImageFamily -eq "Ubuntu Server 16.04 LTS"} ` | Sort-Object PublishedDate –Descending | Select-Object -First 1 ).ImageName
$_adminUser     = "oreadmin"
$_adminPassword = "YourPassword!01"
$_vnetName      = @(Get-AzureVNetSite -VNetName "Group oreno-cloudservice01 TestVNet01").Name
$_subNet        = "BackEnd"
$_vmName        = "vm03"
$_vmConfig = `
New-AzureVMConfig -Name $_vmName -InstanceSize $_vmType -ImageName $_imageName `
| Add-AzureProvisioningConfig -Linux -LinuxUser $_adminUser –Password $_adminPassword `
| Set-AzureVMBGInfoExtension `
| Set-AzureSubnet -SubnetNames $_subNet `
| New-AzureVM -ServiceName $_cloudService  -VNetName $_vnetName -Location $_locationName -WaitForBoot -ReservedIPName "OrenoReservedIP"
  • 仮想マシン vm03 のエンドポイント VIP とポート番号を確認
$_vmName        = "vm03"
Get-AzureVM -ServiceName $_cloudService -Name $_vmName  | Get-AzureEndpoint | Select Name,Port,Vip
$_vmName        = "vm04"
$_vmConfig = `
New-AzureVMConfig -Name $_vmName -InstanceSize $_vmType -ImageName $_imageName `
| Add-AzureProvisioningConfig -Linux -LinuxUser $_adminUser –Password $_adminPassword `
| Set-AzureVMBGInfoExtension `
| Set-AzureSubnet -SubnetNames $_subNet `
| New-AzureVM -ServiceName $_cloudService  -VNetName $_vnetName -Location $_locationName -WaitForBoot -ReservedIPName "OrenoReservedIP"
  • 仮想マシン vm04 のエンドポイント VIP とポート番号を確認
$_vmName        = "vm04"
Get-AzureVM -ServiceName $_cloudService -Name $_vmName  | Get-AzureEndpoint | Select Name,Port,Vip

仮想マシンに雑なアプリケーションをデプロイ

itamae ssh -h ${VIP} -p ${VM01_SSH_PORT} --user=oreadmin --ask_password --sudo roles/frontend.rb --node-json node.json --log-level=debug
itamae ssh -h ${VIP} -p ${VM01_SSH_PORT} --user=oreadmin --ask_password --sudo roles/frontend.rb --node-json node.json --log-level=debug

アプリケーションは仮想マシンのホスト名を JSON で返すだけのアプリケーション。

内部ロードバランサをクラウドサービス内に作成

  • 内部ロードバランサをクラウドサービス内に作成
Add-AzureInternalLoadBalancer -InternalLoadBalancerName "OrenoInternalLB" -ServiceName $_cloudService -SubnetName $_subNet -StaticVNetIPAddress "192.168.2.100"
  • 作成した内部ロードバランサを利用してエンドポイントと負荷分散セットを作成
Get-AzureVM -ServiceName $_cloudService -Name "vm03" `
| Add-AzureEndpoint -Name "Tcp19190-vm01" -Protocol "tcp" -PublicPort 80 -LocalPort 19190 -LBSetName "OrenoInternalLB" -ProbePort 19190 -ProbeProtocol "http" -ProbePath '/api/endpoint/healthcheck' –InternalLoadBalancerName "OrenoInternalLB" `
| Update-AzureVM


Get-AzureVM -ServiceName $_cloudService -Name "vm04" `
| Add-AzureEndpoint -Name "Tcp19190-vm02" -Protocol "tcp" -PublicPort 80 -LocalPort 19190 -LBSetName "OrenoInternalLB" -ProbePort 19190 -ProbeProtocol "http" -ProbePath '/api/endpoint/healthcheck' –InternalLoadBalancerName "OrenoInternalLB" `
| Update-AzureVM

動作確認

  • run
while true; do curl ${InternalLB IP Address}/api/endpoint/hostname -w "\n"; done
  • output
(snip)

{"hostname": "vm03"}
{"hostname": "vm03"}
{"hostname": "vm03"}
{"hostname": "vm03"}
{"hostname": "vm03"}
{"hostname": "vm03"}
{"hostname": "vm03"}
{"hostname": "vm03"}
{"hostname": "vm03"}
{"hostname": "vm03"}
{"hostname": "vm03"}
{"hostname": "vm03"}
{"hostname": "vm03"}
{"hostname": "vm03"}
{"hostname": "vm03"}
{"hostname": "vm04"}
{"hostname": "vm04"}
{"hostname": "vm04"}
{"hostname": "vm04"}
{"hostname": "vm04"}
{"hostname": "vm04"}
{"hostname": "vm04"}
{"hostname": "vm04"}
{"hostname": "vm04"}
{"hostname": "vm04"}
{"hostname": "vm04"}

(snip)

交互にアクセスしているわけでは無いが、分散アクセスはされているように見える。

以上

メモでした。

PowerShell で操作する Azure メモ(4)

Azure 雑なメモ

ども、かっぱです。

tl;dr

引続き、PowerShell で Azure を操作するメモ。

操作する環境は以下の通り。

PS C:\Users\Administrator\Downloads> [System.Environment]::OSVersion

                          Platform ServicePack                        Version                            VersionString
                          -------- -----------                        -------                            -------------
                           Win32NT                                    6.3.9600.0                         Microsoft Windows NT 6.3.9600.0

PS C:\Users\Administrator\Downloads> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      4.0
WSManStackVersion              3.0
SerializationVersion           1.1.0.1
CLRVersion                     4.0.30319.42000
BuildVersion                   6.3.9600.17400
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0}
PSRemotingProtocolVersion      2.2

Web サーバーや簡単なアプリケーションに負荷分散セット経由でアクセスする

構成

f:id:inokara:20160911084913p:plain

クラウドサービス内に仮想マシンを構築

$_locationName  = "Japan West"
$_cloudService  = "oreno-cloudservice01"
$_vmType        = "Small"
$_imageName     = @(Get-AzureVMImage | ? {$_.OS -eq "Linux" -and $_.ImageFamily -eq "Ubuntu Server 16.04 LTS"} ` | Sort-Object PublishedDate –Descending | Select-Object -First 1 ).ImageName
$_adminUser     = "oreadmin"
$_adminPassword = "YourPassword!01"
$_vnetName      = @(Get-AzureVNetSite -VNetName "Group oreno-cloudservice01 TestVNet01").Name
$_subNet        = "FrontEnd"
$_ReservedIP = New-AzureReservedIP –ReservedIPName "OrenoReservedIP" –Label "OrenoReservedIP" –Location "Japan West"
$_vmName        = "vm01"
$_vmConfig = `
New-AzureVMConfig -Name $_vmName -InstanceSize $_vmType -ImageName $_imageName `
| Add-AzureProvisioningConfig -Linux -LinuxUser $_adminUser –Password $_adminPassword `
| Set-AzureVMBGInfoExtension `
| Set-AzureSubnet -SubnetNames $_subNet `
| New-AzureVM -ServiceName $_cloudService  -VNetName $_vnetName -Location $_locationName -WaitForBoot -ReservedIPName "OrenoReservedIP"
  • 仮想マシン vm01 のエンドポイント VIP とポート番号を確認
Get-AzureVM -ServiceName $_cloudService -Name $_vmName  | Get-AzureEndpoint | Select Name,Port,Vip
$_vmName        = "vm02"
$_vmConfig = `
New-AzureVMConfig -Name $_vmName -InstanceSize $_vmType -ImageName $_imageName `
| Add-AzureProvisioningConfig -Linux -LinuxUser $_adminUser –Password $_adminPassword `
| Set-AzureVMBGInfoExtension `
| Set-AzureSubnet -SubnetNames $_subNet `
| New-AzureVM -ServiceName $_cloudService  -VNetName $_vnetName -Location $_locationName -WaitForBoot -ReservedIPName "OrenoReservedIP"
  • 仮想マシン vm02 のエンドポイント VIP とポート番号を確認
Get-AzureVM -ServiceName $_cloudService -Name $_vmName  | Get-AzureEndpoint | Select Name,Port,Vip

雑なアプリケーションをデプロイ

itamae ssh -h ${VIP} -p ${VM01_SSH_PORT} --user=oreadmin --ask_password --sudo roles/common.rb --node-json node.json --log-level=debug
itamae ssh -h ${VIP} -p ${VM01_SSH_PORT} --user=oreadmin --ask_password --sudo roles/common.rb --node-json node.json --log-level=debug

インターネット向けの外部ロードバランサを設定

  • memo
- クラウドサービスにはデフォルトでインターネット向けの外部ロードバランサが提供されている
- 外部ロードバランサを利用する為には負荷分散セットを設定する必要がある
  • 外部からポート 8000 番でアクセスさせるエンドポイントと負荷分散セットを作成
Get-AzureVM -ServiceName $_cloudService -Name "vm01" `
| Add-AzureEndpoint -Name "Http8000-vm01" -Protocol "tcp" -PublicPort 8000 -LocalPort 80 -LBSetName "OrenoLB" -ProbePort 80 -ProbeProtocol "tcp" `
| Update-AzureVM

Get-AzureVM -ServiceName $_cloudService -Name "vm02" `
| Add-AzureEndpoint -Name "Http8000-vm02" -Protocol "tcp" -PublicPort 8000 -LocalPort 80 -LBSetName "OrenoLB" -ProbePort 80 -ProbeProtocol "tcp" `
| Update-AzureVM
  • 外部からポート 8001 番でアクセスさせるエンドポイントと負荷分散セットをアクセスコントロール付きで作成
#
# xxx.xxx.xxx.xxx/32 からのアクセスを許可する
#
$_acl = New-AzureAclConfig
Set-AzureAclConfig -AddRule Permit -RemoteSubnet "xxx.xxx.xxx.xxx/32" -Order 1000 -ACL $_acl -Description "Http8081-Allow"

以下のように出力される。

RuleId       : 0
Order        : 1000
Action       : Permit
RemoteSubnet : xxx.xxx.xxx.xxx/32
Description  : Http8081-Allow

アクセスコントロールを付与してエンドポイントと負荷分散セットを作成。

Get-AzureVM -ServiceName $_cloudService -Name "vm01" `
| Add-AzureEndpoint -Name "Http8081-vm01" -Protocol "tcp" -PublicPort 8081 -LocalPort 19190 -LBSetName "OrenoLB-8081" -ProbePort 19190 -ProbeProtocol "http" -ProbePath '/api/endpoint/healthcheck' -ACL $_acl `
| Update-AzureVM

Get-AzureVM -ServiceName $_cloudService -Name "vm02" `
| Add-AzureEndpoint -Name "Http8081-vm02" -Protocol "tcp" -PublicPort 8081 -LocalPort 19190 -LBSetName "OrenoLB-8081" -ProbePort 19190 -ProbeProtocol "http" -ProbePath '/api/endpoint/healthcheck' -ACL $_acl `
| Update-AzureVM

動作確認

  • アクセスコントロールで許可されている拠点より
% curl --connect-timeout 10 -I xxx.xxx.xxx.xxx:8000
HTTP/1.1 200 OK
Server: nginx/1.10.0 (Ubuntu)
Date: Sat, 10 Sep 2016 23:54:00 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Sat, 10 Sep 2016 22:09:07 GMT
Connection: keep-alive
ETag: "57d48483-264"
Accept-Ranges: bytes

% curl --connect-timeout 10 -I xxx.xxx.xxx.xxx:8081/api/endpoint/healthcheck
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 2
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Expose-Headers: Authorization
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000
Server: Werkzeug/0.11.11 Python/2.7.12
Date: Sat, 10 Sep 2016 23:55:14 GMT
  • アクセスコントロールで許可されていない拠点より
$ curl --connect-timeout 10 -I xxx.xxx.xxx.xxx:8000
HTTP/1.1 200 OK
Server: nginx/1.10.0 (Ubuntu)
Date: Sat, 10 Sep 2016 23:59:06 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Sat, 10 Sep 2016 22:18:23 GMT
Connection: keep-alive
ETag: "57d486af-264"
Accept-Ranges: bytes

#
# アクセスコントロールが効いていることが判る
#
$ curl --connect-timeout 10 -I xxx.xxx.xxx.xxx:8081/api/endpoint/healthcheck
curl: (28) Connection timed out after 10007 milliseconds

以上

エンドポイント、負荷分散セット...混乱している。

Amazon ES へのアクセスを IAM role と IP アドレスで制御する試行錯誤

Amazon ES Elasticsearch Kibana

tl;dr

kakakakakku.hatenablog.com

こちらのブログを読ませて頂いて、Amazon ES のアクセスポリシーで IAM Role と IP アドレスの同居ってどうやるんだろうと疑問に思っていたので試行錯誤してみました。

自分の要件としては以下の通り。

  • Amazon ES へのアクセスは EC2 からは IAM role で制御したい
  • Amazon ES の Kibana プラグインへのアクセスは IP アドレスで制御したい(許可された IP からは Elasticsearch への操作も許可されてしまうけど)

尚、上記のブログでは Kibana プラグインへのアクセスを IP アドレスで許可しつつ、Elasicsearch への操作は抑制したいという要件だと思います。確かに、ニーズがありそうだけど、どのように実現するのか悩ましい限り。

memo

イメージ

f:id:inokara:20160910150229p:plain

  • EC2 に付与する EC2 という IAM role にはポリシーには下図の通り何も付与していない

f:id:inokara:20160910151435p:plain

  • Kibana へのアクセスは xxx.xxx.xxx.xxx という IP アドレスからのみアクセスさせる

アクセスポリシー

以下のようなアクセスポリシーを Amazon ES に付与する。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:role/EC2"
      },
      "Action": "es:*",
      "Resource": "arn:aws:es:ap-northeast-1:123456789012:domain/oreno-es/*"
    },
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": "es:*",
      "Resource": "arn:aws:es:ap-northeast-1:123456789012:domain/oreno-es/*",
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": "xxx.xxx.xxx.xxx"
        }
      }
    }
  ]
}

動作確認

  • Kibana にアクセスすると...

f:id:inokara:20160910142419p:plain

  • curl で試すと...
$ curl -s https://search-oreno-es-xxxxxxxxxxxxxxxx.ap-northeast-1.es.amazonaws.com | jq .
{
  "Message": "User: anonymous is not authorized to perform: es:ESHttpGet on resource: oreno-es"
}

curl だとリクエストに AWS の認証を付与することが出来ないので、上記のように Elasticsearch にはアクセス出来ない。

動作確認(2)

  • リクエストに認証情報を加えて上げる必要があるので python で実装

これは、以下の記事を参考に...

inokara.hateblo.jp

  • 確認
$ python test.py | jq .
{
  "cluster_name": "123456789012:oreno-es",
  "tagline": "You Know, for Search",
  "version": {
    "lucene_version": "5.5.0",
    "build_hash": "0944b4bae2d0f7a126e92b6133caf1651ae316cc",
    "number": "2.3.2",
    "build_timestamp": "2016-05-20T07:46:04Z",
    "build_snapshot": false
  },
  "name": "Shotgun"
}

以上

疑問

  • IAM role だけ付与しておけば良い?(AmazonESFullAccess あたりのポリシーは付与しなくても問題無い?)

要望

  • Amazon ES のアクセスポリシーを変更して反映するまでの時間が長い(体感で 10 分〜 15 分)...ので改善して頂きたいです
  • AWS CLIiam list-role-policies ってマネージドポリシーはリストアップされないのですな

PowerShell で操作する Azure メモ(3)

Azure 雑なメモ

ども、かっぱです。

tl;dr

引続き、PowerShell で Azure を操作するメモ。

操作する環境は以下の通り。

PS C:\Users\Administrator\Downloads> [System.Environment]::OSVersion

                          Platform ServicePack                        Version                            VersionString
                          -------- -----------                        -------                            -------------
                           Win32NT                                    6.3.9600.0                         Microsoft Windows NT 6.3.9600.0

PS C:\Users\Administrator\Downloads> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      4.0
WSManStackVersion              3.0
SerializationVersion           1.1.0.1
CLRVersion                     4.0.30319.42000
BuildVersion                   6.3.9600.17400
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0}
PSRemotingProtocolVersion      2.2

引続き仮想ネットワークや仮想マシンをいじる

やること

改めて仮想マシンを作成

$_locationName  = "Japan West"
$_cloudService  = "your-service01"
$_vmName        = "vm01"
$_vmType        = "Basic_A0"
$_imageName     = @(Get-AzureVMImage | ? {$_.OS -eq "Windows" -and $_.ImageFamily -eq "Windows Server 2012 R2 datacenter"} ` | Sort-Object PublishedDate –Descending | Select-Object -First 1 ).ImageName
$_adminUser     = "oreadmin"
$_adminPassword = "YourPassword!01"
$_vnetName      = @(Get-AzureVNetSite -VNetName "Group your-service01 TestVNet01").Name
$_subNet        = "FrontEnd"

$_vmConfig = `
New-AzureVMConfig -Name $_vmName -InstanceSize $_vmType -ImageName $_imageName `
| Add-AzureProvisioningConfig -Windows -AdminUsername $_adminUser -Password $_adminPassword -EnableWinRMHttp `
| Set-AzureVMBGInfoExtension `
| Set-AzureSubnet -SubnetNames $_subNet `
| New-AzureVM -ServiceName $_cloudService  -VNetName $_vnetName -Location $_locationName -WaitForBoot

f:id:inokara:20160904162621p:plain

f:id:inokara:20160904163123p:plain

これは VM 拡張機能の一つ、BGInfo が有効になっている場合、他のホスト情報と合わせて掲載される。

仮想マシンのサブネットを変更する

  • 現在は FrontEnd で起動している仮想マシンを BackEnd に移動する
$_vm = Get-AzureVM –serviceName $_cloudService –Name $_vmName
#
# Set-AzureSubnet を実行して 仮想マシンのサブネットを指定
#
Set-AzureSubnet –SubnetNames "BackendEnd" –VM $_vm

#
# Update-AzureVM を実行して変更を反映
#
Update-AzureVM -Name "vm01" -VM $_vm.VM -ServiceName $_cloudService

Update-AzureVM による変更で VM は再起動が発生する。

  • ouput
OperationDescription                    OperationId                             OperationStatus
--------------------                    -----------                             ---------------
Update-AzureVM                          xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx    Succeeded
  • 変更が完了すると以下のような構成となる

f:id:inokara:20160904162526p:plain

  • 仮想マシンのデスクトップ壁紙に掲載されている DIP についても変更されている

f:id:inokara:20160904163248p:plain

DIP を割り当てる

  • $_vnetName 内で 192.168.2.100 が利用可能であるかを確認する
Test-AzureStaticVNetIP –VNetName $_vnetName –IPAddress 192.168.2.100
  • output
IsAvailable          : True
AvailableAddresses   : {}
OperationDescription : Test-AzureStaticVNetIP
OperationId          : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
OperationStatus      : Succeeded
  • 仮想マシン $_vmName の IP アドレスを 192.168.2.100 に変更する(DIP を割り当てる)
Get-AzureVM –serviceName $_cloudService  –Name $_vmName `
| Set-AzureStaticVNetIP -IPAddress 192.168.2.100 `
| Update-AzureVM

VIP の固定予約と仮想マシンへの割り当て

  • 予約済み IP アドレスの作成
$ReservedIP = New-AzureReservedIP –ReservedIPName "OrenoReservedIP" –Label "OrenoReserved –Location "Japan West"
  • 予約済み IP アドレスの確認
Get-AzureReservedIP
  • output
ReservedIPName       : OrenoReservedIP
Address              : xxx.xxx.xxx.xxx
Id                   : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Label                : OrenoReservedIP
Location             : Japan West
State                : Created
InUse                : False
ServiceName          :
DeploymentName       :
VirtualIPName        :
OperationDescription : Get-AzureReservedIP
OperationId          : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
OperationStatus      : Succeeded
  • 予約済み IP アドレスを利用して仮想マシンを作成する
$_vmConfig = `
New-AzureVMConfig -Name $_vmName -InstanceSize $_vmType -ImageName $_imageName `
| Add-AzureProvisioningConfig -Windows -AdminUsername $_adminUser -Password $_adminPassword -EnableWinRMHttp `
| Set-AzureVMBGInfoExtension `
| Set-AzureSubnet -SubnetNames $_subNet `
| New-AzureVM -ServiceName $_cloudService  -VNetName $_vnetName -Location $_locationName -WaitForBoot -ReservedIPName "OrenoReservedIP"

New-AzureVM 実行時に -ReservedIPName "OrenoReservedIP"-Location $_locationName(予約した IP アドレスと同じ地域を指定)を付与して仮想マシンを作成する。

Remove-AzureVM -Name $_vmName -ServiceName $_cloudService
  • output
OperationDescription                    OperationId                             OperationStatus
--------------------                    -----------                             ---------------
Remove-AzureVM                          xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx    Succeeded
  • Remove-AzureReservedIP を使って予約済み IP アドレスを解放
Remove-AzureReservedIP -ReservedIPName "OrenoReservedIP"
  • output
確認
Are you sure you want to remove the Reserved IP from your subscription?
[Y] はい(Y)  [N] いいえ(N)  [S] 中断(S)  [?] ヘルプ (既定値は "Y"):

OperationDescription                    OperationId                             OperationStatus
--------------------                    -----------                             ---------------
Remove-AzureReservedIP                  xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx    Succeeded

以上

引続き。