LVM で論理ボリュームを作成する

Vagrantfile

検証に Vagrant を使います。
1GB のディスクを 2 つ追加しています。
この 2 つのディスクを使い、論理ボリュームを作成します。

# -*- mode: ruby -*-
# vi: set ft=ruby :

ENV["VAGRANT_EXPERIMENTAL"] = "disks"

Vagrant.configure("2") do |config|
  config.vm.box = "bento/ubuntu-18.04"
  config.vm.disk :disk, size: "1GB",  name: "disk-0"
  config.vm.disk :disk, size: "1GB",  name: "disk-1"
end

ディスクの確認

vagrant@vagrant:~$ lsblk 
NAME                   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda                      8:0    0   64G  0 disk 
└─sda1                   8:1    0   64G  0 part 
  ├─vagrant--vg-root   253:0    0   63G  0 lvm  /
  └─vagrant--vg-swap_1 253:1    0  980M  0 lvm  [SWAP]
sdb                      8:16   0    1G  0 disk 
sdc                      8:32   0    1G  0 disk 

sdb にパーティションを作成

vagrant@vagrant:~$ sudo fdisk /dev/sdb

Welcome to fdisk (util-linux 2.31.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0x27a74be3.

Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): 

Using default response p.
Partition number (1-4, default 1): 
First sector (2048-2097151, default 2048): 
Last sector, +sectors or +size{K,M,G,T,P} (2048-2097151, default 2097151): 

Created a new partition 1 of type 'Linux' and of size 1023 MiB.

Command (m for help): t
Selected partition 1
Hex code (type L to list all codes): 8e
Changed type of partition 'Linux' to 'Linux LVM'.

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

sdc にパーティションを作成

vagrant@vagrant:~$ sudo fdisk /dev/sdc

Welcome to fdisk (util-linux 2.31.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0xb7872d57.

Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): 

Using default response p.
Partition number (1-4, default 1): 
First sector (2048-2097151, default 2048): 
Last sector, +sectors or +size{K,M,G,T,P} (2048-2097151, default 2097151): 

Created a new partition 1 of type 'Linux' and of size 1023 MiB.

Command (m for help): t
Selected partition 1
Hex code (type L to list all codes): 8e
Changed type of partition 'Linux' to 'Linux LVM'.

Command (m for help): w

The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

パーティションの確認

vagrant@vagrant:~$ lsblk 
NAME                   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda                      8:0    0   64G  0 disk 
└─sda1                   8:1    0   64G  0 part 
  ├─vagrant--vg-root   253:0    0   63G  0 lvm  /
  └─vagrant--vg-swap_1 253:1    0  980M  0 lvm  [SWAP]
sdb                      8:16   0    1G  0 disk 
└─sdb1                   8:17   0 1023M  0 part 
sdc                      8:32   0    1G  0 disk 
└─sdc1                   8:33   0 1023M  0 part 

物理ボリュームを作成する

vagrant@vagrant:~$ sudo pvcreate /dev/sdb1 /dev/sdc1 
  Physical volume "/dev/sdb1" successfully created.
  Physical volume "/dev/sdc1" successfully created.

ボリュームグループを作成する

vagrant@vagrant:~$ sudo vgcreate lvg-test /dev/sdb1 /dev/sdc1 
  Volume group "lvg-test" successfully created

作成したボリュームグループの確認する

vagrant@vagrant:~$ sudo vgdisplay
  --- Volume group ---
  VG Name               lvg-test
  System ID             
  Format                lvm2
  Metadata Areas        2
  Metadata Sequence No  1
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                0
  Open LV               0
  Max PV                0
  Cur PV                2
  Act PV                2
  VG Size               1.99 GiB
  PE Size               4.00 MiB
  Total PE              510
  Alloc PE / Size       0 / 0   
  Free  PE / Size       510 / 1.99 GiB
  VG UUID               zMcDi1-xfrc-y6ae-KFgL-ZN90-moNz-cteZdu
   
  --- Volume group ---
  VG Name               vagrant-vg
  System ID             
  Format                lvm2
  Metadata Areas        1
  Metadata Sequence No  3
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                2
  Open LV               2
  Max PV                0
  Cur PV                1
  Act PV                1
  VG Size               <64.00 GiB
  PE Size               4.00 MiB
  Total PE              16383
  Alloc PE / Size       16383 / <64.00 GiB
  Free  PE / Size       0 / 0   
  VG UUID               0hdOem-2LyY-XIrh-cxIR-bYG4-6LXM-WMZjo5

論理ボリュームを作成する

vagrant@vagrant:~$ sudo lvcreate -n lv-test -L 1.99g lvg-test
  Rounding up size to full physical extent 1.99 GiB
  Logical volume "lv-test" created.

論理ボリュームにファイルシステムを作成する

vagrant@vagrant:~$ sudo mkfs.ext4 /dev/lvg-test/lv-test 
mke2fs 1.44.1 (24-Mar-2018)
Creating filesystem with 522240 4k blocks and 130560 inodes
Filesystem UUID: 24bbc802-618d-4b4e-9542-603ddd573de9
Superblock backups stored on blocks: 
    32768, 98304, 163840, 229376, 294912

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (8192 blocks): done
Writing superblocks and filesystem accounting information: done 

論理ボリュームをマウントする

vagrant@vagrant:~$ sudo mount /dev/lvg-test/lv-test /mnt
vagrant@vagrant:~$ ls /mnt/
lost+found
vagrant@vagrant:~$ df -hT
Filesystem                     Type      Size  Used Avail Use% Mounted on
udev                           devtmpfs  461M     0  461M   0% /dev
tmpfs                          tmpfs      99M  5.1M   94M   6% /run
/dev/mapper/vagrant--vg-root   ext4       62G  1.6G   58G   3% /
tmpfs                          tmpfs     493M     0  493M   0% /dev/shm
tmpfs                          tmpfs     5.0M     0  5.0M   0% /run/lock
tmpfs                          tmpfs     493M     0  493M   0% /sys/fs/cgroup
vagrant                        vboxsf    457G  121G  337G  27% /vagrant
tmpfs                          tmpfs      99M     0   99M   0% /run/user/1000
/dev/mapper/lvg--test-lv--test ext4      2.0G  6.0M  1.9G   1% /mnt

参考

「入門 監視」を読んだメモ

書籍情報

https://www.oreilly.co.jp/books/9784873118642/

1.1 アンチパターン 1: ツール依存

  • 成功したチームが使っているから、という安直な理由でツールを採用してはいけない
  • 自分や自分のチームにツールが合っている必要がある

1.3 アンチパターン 3: チェックボックス監視

  • 「動いている」とはどういう意味か。「動いている」かどうかを監視しよう
    • 高レベルなチェックが実施できるか検討しよう
    • Web アプリケーションなら / に GET して、200 が返るか、ページに特定の文字列があるか、リクエストのレイテンシが小さいかなど
  • メトリクスは最低でも 60 秒に 1 回すべき

1.4 アンチパターン 4: 監視を支えにする

  • 問題を解決するためにアプリケーションを改修するのではなく、監視項目を追加することは避ける

2.1 デザインパターン 1: 組み合わせ可能な監視

  • モノシリックな監視ツールより、専門化されたツールを組み合わせて、監視プラットフォームを作ったほうがいい
  • モノシリックな監視ツール全体を置き換えるより、特定のツールだけ変更できるほうがよい
  • 監視システムを構成する要素
    • データ収集
    • データストレージ
    • 可視化
    • 分析とレポート
    • アラート

データ収集

  • 収集方法にはプッシュ型とプル型が存在する
  • メトリクスデータとは
    • カウンタ: Web サイトの累計訪問者数など
    • ゲージ: ある時点の値
  • ログデータとは
    • 非構造化ログ

      192.34.63.77 - - [26/Jun/2016:14:06:22 -0400] "GET / HTTP/1.1" 301 184 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/47.0.2526.111 (StatusCake)" "-"

    • 構造化ログ

      { "remote_addr": "192.34.63.77",
      "remote_user": "-",
      "time": "2016-06-26T14:06:22-04:00",
      "request": "GET / HTTP/1.1",
      "status": “301”,
      "body_bytes_sent": “184”,
      "http_referrer": "-",
      "http_user_agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36
      (KHTML, like Gecko) Chrome/47.0.2526.111 (StatusCake)",
      "http_x_forwarded_for": "-" }

分析とレポート

  • SLO などが関連する
  • 監視対象のシステムが依存コンポーネントを持っている場合、システムはそのコンポーネントの可用性を超えることはできない
    • クラウドプラットフォームの可用性が 99.95% なら、システムの可用性は 99.95% を超えることができない

3.1 どうしたらアラートをよくできるか

  • アラート=緊急の対応が求められるもの
    • 例. Web サーバのダウンなど
  • まずは対応を自動化できないか検討する
  • オンコール担当のローテーション間隔は 3 週間以上を推奨する
  • アラートをレポートとして出力できると、システム改善の役に立つ
  • ある値が X(固定のしきい値) を超えた場合のアラート(チェック監視)には意味がないこともある。変化量を監視したほうがいいこともある(メトリクス監視)
    • 空き容量が 10% 以下でアラート よりも 一晩でディスク使用量が 50% 増加でアラート のほうが役に立つかも
  • 不要なアラートは削除・しきい値の変更をする。または対応を自動化できないか検討する
    • 削除前にはアラートに対する過去のアクションを分析してもいい
  • アラートへの対応
    • すぐにアクションが必要なアラートへの対処(アラートの本来の定義)
      • SMS や PagerDuty などを使う
    • 注意が必要だが、すぐにアクションは必要ないアラートへの対処
      • 社内チャットやメール
    • 履歴や診断のために保存しておくアラートへの対処
      • ログファイルに保存する

4. 統計入門

  • 移動平均
    • 平滑化することで極端な値を隠す。ただし重要かも知れないデータも見えなくなる
  • 中央値
    • 一方向に大きな偏りがあるデータセットを扱うときに使うと良い
  • パーセンタイル
    • 50パーセンタイル=中央値

5. ビジネスを監視する

  • ビジネスの KPI を計測するために技術的なメトリクスを利用する(対応付けをする)
  • Reddit のビジネスの KPI と技術的なメトリクスの対応例
    • 現在サイトに滞在しているユーザ: 現在サイトに滞在しているユーザ
    • ユーザのログイン: ユーザのログイン失敗、ログインのレイテンシ
    • コメント投稿: コメント投稿失敗、投稿のレイテンシ
    • スレッド作成: スレッド作成失敗、作成のレイテンシ
    • 投票: 投票失敗、投票のレイテンシ
    • プライベートメッセージの送信: プライベートメッセージ送信失敗、送信のレイテンシ
    • Gold 購入: 購入失敗、購入のレイテンシ
    • 広告購入: 購入失敗、購入のレイテンシ

6.2 フロントエンド監視の 2 つのアプローチ

  • リアルユーザ監視(Real User Monitoring=RUM)
    • メトリクスに実際のユーザトラフィックを使う
    • 各ページに JavaScript を仕込み、ユーザがページをロードすると、監視サービスに対してメトリクスを送信する
  • シンセティック監視(Synthetic Monitoring)

6.3 DOM

  • ページロード時間は 4 秒以下を目指す
  • ページ表示時にロードされる JavaScript が多いと、それだけロード時間が増加する
  • Navigation Timing API を使い、ロード時間を計測する

7. アプリケーション監視

  • Go の構造化ロガー
  • StatsD: メトリクス保存に使われるツール。アプリケーションにコードを追加する
  • ビルドやデプロイなどの情報も監視データとして保存しておくと、他のメトリクスと組み合わせることができる
    • 特定のデプロイから500エラーが増加しているなどが判明するかも
  • マイクロサービスでは監視に分散トレーシングが使われることがある
  • /health エンドポイントを追加する
    • 特定の IP のみアクセスを許可すること。ユーザには公開しないほうがいい
    • 本文は構造化フォーマットがおすすめ
    • 以下はアプリケーションが依存する MySQL と Redis も確認している例
from django.db import connection as sql_connection
from django.http import JsonResponse
import redis


def check_sql():
    try:
        with sql_connection.cursor() as cursor:
            cursor.execute("SELECT 1 FROM table_name")
            cursor.fetchone()
        return {"okay": True}
    except Exception, e:
        return {"okay": False, "error": e}


def check_redis():
    try:
        redis_connection = redis.StrictRedis()
        result = redis_connection.get("test-key")
        if result == "some-value":
            return {"okay": True}
        else:
            return {"okay": False, "error": "Test value not found"}
    except Exception, e:
        return {"okay": False, "error": e}


def health():
    if all(check_sql().get("okay"), check_redis().get("okay")):
        return JsonResponse({"status": 200}, status=200)
    else:
        return JsonResponse(
            {
                "mysql_okay": check_sql().get("okay"),
                "mysql_error": check_sql().get("error", None),
                "redis_okay": check_redis().get("okay"),
                "redis_error": check_redis().get("error", None),
            },
            status=503,
        )

8. サーバ監視

9. ネットワーク監視

  • 帯域幅
    • ある接続から一度に送れる理論上の最大情報量
    • 秒間メガビット(Mbps)などが使われる。秒間メガバイト(MBps)と混同しないように注意する
    • 高速道路で例えるなら車線数
  • スループット
    • ある接続から一度に送れる実際の最大情報量
    • スループット計測の便利ツール: iperf2
    • 高速道路で例えるなら実際に通行している車の数
  • レイテンシ
    • パケットがネットワークリンクを通じてやり取りされるのにかかる時間
    • 高速道路で道路の長さ

10. セキュリティ監視

付録 C 実践 監視 SaaS

  • 監視 SaaS の利点
    • コスト
    • 難易度の高い監視ツールの運用を SaaS 提供者に任せることができる
    • 利用者はプロダクト開発に集中できる
    • 使いやすいデザインが提供されることで、チーム全員が監視システムに積極的にアクセスでき、属人化を避けることができる
    • バージョンアップ作業が不要
  • OS メトリクスの収集の役割を 健康診断 で例える
    • 健康診断で肝機能の γ-GPT が高かったとする
    • 多分お酒の飲みすぎが原因
    • この場合、本来監視すべきは酒量だが、大まかな変化は検出できた
  • ユーザ視点のシンセティック監視(URL 外形監視)から監視を始めるのがおすすめ

Go の string と range

string を range したときに返るインデックスは
文字列中でのバイト位置を表しているということを知りました。
今まで何文字目というインデックスが返るものと勘違いしてました。
忘れないようにメモしておきます。

参考

https://golang.org/doc/effective_go#for

サンプルコード

https://play.golang.org/p/0HDIL562LUe

package main

import (
    "fmt"
)

func main() {
    for pos, r := range "Aあ1" {
        fmt.Printf("character %c starts at byte position %d\n", r, pos)
    }
}

実行結果

character A starts at byte position 0
character あ starts at byte position 1
character 1 starts at byte position 4

「新しいシェルプログラミングの教科書」を読んだメモ

一時ファイル名を作る

$$ で現在のプロセスのプロセス ID を取得できる。これは一時ファイルの名前生成に利用できる。

$ tmpfile=/tmp/$$
$ echo $tmpfile
/tmp/157490

文字列の長さを得る

expr を使う。

$ expr length "pewpewpew"
9
$ foo=hello; expr length $foo
5

$変数 と "$変数" の違い

$ cat test.sh 
#!/bin/bash

list=("foo" "bar" "hello world")
for i in ${list[@]}
do
    echo $i
done

echo -----

for i in "${list[@]}"
do
    echo $i
done
$ ./test.sh 
foo
bar
hello
world
-----
foo
bar
hello world

算術式評価

  • (( )) を使う
  • カッコ内の変数の型(以下の例では a )は文字列なことに注意する
$ x=10; y=20; ((a=x+y))
$ echo $a
30
$ a=1+1
$ echo $a
1+1

読み取り専用変数

declare -rreadonly は同じ動作になる。

$ declare -r foo=bar
$ foo=pew
bash: foo: 読み取り専用の変数です
$ readonly bark=bow
$ bark=wanwan
bash: bark: 読み取り専用の変数です

整数型の変数

  • declare -i で宣言する。通常の文字列型と違い、右辺に式が書ける
  • sum=x+y のように式の中で変数を参照する時に $ は不要
$ declare -i x=50
$ declare -i y=10
$ declare -i sum=x+y
$ echo $sum
60

配列

  • ( ) を書いて、中に要素を並べると配列になる
    • 明示的に宣言するには declare -a mylist のようにする
    • list=() のように () だけだと空の配列になる
  • 要素を参照するには ${配列名[インデックス]} する
  • ${#配列名[@]} で配列の要素数を得る
  • ${配列名[@]} で全ての要素を得る
  • 配列名[インデックス]=値 で要素を変更する
  • 要素削除には unset を使う
$ dogs=(koro sophia bunta)
$ echo ${dogs[0]}
koro
$ echo ${dogs}
koro
$ echo ${#dogs[@]}
3
$ dogs[0]=KORO
$ echo ${dogs[0]}
KORO
$ echo ${dogs[@]}
KORO sophia bunta
  • 先頭に要素追加
$ dogs=(louis "${dogs[@]}")
$ echo ${dogs[@]}
louis KORO sophia bunta
  • 末尾に要素追加
$ dogs+=(mona)
$ echo ${dogs[@]}
louis KORO sophia bunta mona
  • ${配列名[@]:開始位置:終了位置} で指定の要素を取り出せる
$ echo ${dogs[@]}
louis KORO sophia bunta mona foo
$ echo ${dogs[@]:1:3}
KORO sophia bunta

連想配列

  • declare -A book のようにする
  • 使い方は基本的に配列と同じ
$ declare -A book
$ book=([author]=taro [title]=fugafuga)
$ echo ${book[title]}
fugafuga
$ echo ${book[@]}
fugafuga taro
$ echo ${#book[@]}
2
$ book[publisher]=hogehoge
$ echo ${book[@]}
hogehoge fugafuga taro

パス名展開

パス名展開はシェルが行っている。一致するファイルが無い場合は、もとの記号がそのまま出力される。

$ ls
foo.cpp  foo.txt
$ echo foo.*
foo.cpp foo.txt
$ echo boo.*
boo.*
$ ls foo.*
foo.cpp  foo.txt
$ ls boo.*
ls: 'boo.*' にアクセスできません: そのようなファイルやディレクトリはありません

文字列の切り出し

${変数名:開始位置:終了位置} で切り出せる。

$ path=/etc/systemd/
$ echo ${path:1:3}
etc

拡張子を得る

  • ${変数名#パターン} では 前方一致 したパターン部分を除いて展開される
  • # だと最短一致、 ## だと最長一致になる。拡張子を得るなら ## がよく使われる
$ path=/tmp/foo.tar.gz
$ echo ${path#*.}
tar.gz
$ echo ${path##*.}
gz

ファイル名を得る

$ echo ${path##*/}
foo.tar.gz

ディレクトリ名を得る

  • ${変数名%パターン} では 後方一致 したパターン部分を除いて展開される
  • % で最短一致させる所がポイント
$ echo ${path%/*}
/tmp

if 文

  • シェルスクリプトには boolean型 が無い。if 文ではコマンド実行結果で条件判定を行う
  • コマンド実行結果が 0 なら真と判定される
  • : は常に 0 を返す、組み込みコマンド
$ cat test.sh
#!/bin/bash

# if の直後にはコマンドが来る
# ; が無いと then もコマンドの引数として認識されてしまう
if ls > /dev/null; then
    echo foo
fi

if [ "foo" = "foo" ]; then
    # noop する時は : を使う
    # : は常に 0 を返す、組み込みコマンド
    :
fi

# 常に真になる if 文
if : ; then
    echo true
fi
$ ./test.sh 
foo
true

test コマンド

  • 文字列や数値の比較、ファイルの存在などを判定するコマンド
  • if 文と組み合わせることが多い
  • [test は基本的に同じ
$ test "foo" = "bar"; echo $?
1
$ [ "foo" = "bar" ]; echo $?
1
$ [ "foo" = "foo" ]; echo $?
0
$ [ "foo" = "foo" -a 100 -ge 10 ]; echo $?
0

標準出力と標準エラー出力をまとめる

&> を使うと便利。

$ ls foo
ls: 'foo' にアクセスできません: そのようなファイルやディレクトリはありません
$ ls foo &> result

ヒアストリング

$ cat <<< hello
hello

サブシェル

() で囲われた処理は、現在のシェルの子プロセスとして新しく起動されたシェルで実行される。 () 内での環境変数などの変更は現在(親)のシェルに影響を与えない。

$ export foo=bar; (foo=pewpewpew); echo $foo
bar
$ pwd; (cd /); pwd
/home/fuga/test
/home/fuga/test

コマンドのグループ化

{} または () で複数のコマンドを1つのコマンドとしてまとめることができる。

$ { ls /dev/pts/; echo hello; } > out
$ cat out 
0
1
ptmx
hello

trap によるシグナルの補足

$ cat test.sh 
#!/bin/bash

handler()
{
    echo "catch INT"
    # exit しないとシェルスクリプトが最後まで実行される
    exit
}

trap handler INT

echo start
sleep 10
echo end
$ ./test.sh 
start
^Ccatch INT

grep コマンド

  • -v で検索パターンにマッチしなかった行が出力される
$ cat << EOF | grep -v -E "^a"
> aaa
> abc
> zzz
> bbb
> baa
> EOF
zzz
bbb
baa
  • -o で検索パターンにマッチした部分だけを出力する
$ cat << EOF | grep -o -E "foo|bar"
> aaafooaaa
> bbbddd
> aaa
> bbbbarbbb
> EOF
foo
bar

env コマンド

環境変数を一時的に変更してコマンドを実行する。bash の場合は 変数名=値 コマンド だけでも同じ動作になる。

$ cat main.go 
package main

import (
   "fmt"
   "os"
)

func main() {
    fmt.Println(os.Getenv("foo"))
}
$ foo=hello
$ env foo=bar go run main.go 
bar
$ foo=bar go run main.go 
bar
$ echo $foo
hello

Bats でのテスト

Bats のインストール。

$ sudo apt install bats
$ bats --version
Bats 1.2.0-dev

テストを記述するファイルの拡張子は bats にする。

$ cat mul.sh 
#!/bin/bash
echo $(($1 * $2))
$ cat mul.bats 
PATH="${BATS_TEST_DIRNAME}:$PATH"

@test 'mul test' {
  run mul.sh 2 3
  [[ $status -eq 0 ]]
  [[ $output == 6 ]]
}
$ bats mul.bats 
 ✓ mul test

1 test, 0 failures

mkcert と golang の net/http を使い、ローカル環境に HTTPS サーバを立てる

Linux 環境で mkcert をインストール(ビルド)する

https://github.com/FiloSottile/mkcert#linux

$ sudo apt install libnss3-tools
$ git clone https://github.com/FiloSottile/mkcert && cd mkcert
$ go build -ldflags "-X main.Version=$(git describe --tags)"

mkcert で証明書とキーを作成する

$ mkcert -install
The local CA is already installed in the system trust store! 👍
The local CA is already installed in the Firefox and/or Chrome/Chromium trust store! 👍

$ mkcert -key-file key.pem -cert-file cert.pem 127.0.0.1 ::1

Created a new certificate valid for the following names 📜
 - "127.0.0.1"
 - "::1"

The certificate is at "cert.pem" and the key at "key.pem" ✅

It will expire on 18 October 2023 🗓

$ ls *.pem
cert.pem  key.pem

HTTPS サーバのサンプルコード

作成した cert.pemkey.pem のパスを http.ListenAndServeTLS に渡します。

package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Protocol: %s\n", r.Proto)
    })
    if err := http.ListenAndServeTLS(":5000", "cert.pem", "key.pem", nil); err != nil {
        log.Fatal(err)
    }
}

動作確認

$ curl https://127.0.0.1:5000
Protocol: HTTP/2.0

参考にさせていただいたサイト

Linux のネットワーク関連コマンド

iptables と dnsmasq も後で追記したいです。

nc

TCPUDPのデータが送受信ができるコマンド。
TCP で Listen は nc -l 12345 、Connect は nc localhost 12345 にする。
UDP にする時は -u を付ける。

tcpdump

パケットをキャプチャできるコマンド。
-t で時刻を表示しない。
-nIPアドレスの名前解決をしない。
-i でキャプチャするインタフェースを指定する。-i any だと全てのインタフェースをキャプチャする。
-A でデータをASCIIで表示する。

別のターミナルから ping 8.8.8.8 -c 2 を実行し、ICMP パケットをキャプチャする例

$ sudo tcpdump -tn -i any icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked v1), capture size 262144 bytes
IP 192.168.0.10 > 8.8.8.8: ICMP echo request, id 5, seq 1, length 64
IP 8.8.8.8 > 192.168.0.10: ICMP echo reply, id 5, seq 1, length 64
IP 192.168.0.10 > 8.8.8.8: ICMP echo request, id 5, seq 2, length 64
IP 8.8.8.8 > 192.168.0.10: ICMP echo reply, id 5, seq 2, length 64
^C
4 packets captured
4 packets received by filter
0 packets dropped by kernel

UDP でポートを指定してキャプチャする例

$ sudo tcpdump -tnlA -i any "udp and port 12345"
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked v1), capture size 262144 bytes
IP 127.0.0.1.37527 > 127.0.0.1.12345: UDP, length 4
E.. ..@.@.?A..........09....foo

IP 127.0.0.1.37527 > 127.0.0.1.12345: UDP, length 6
E..".z@.@.<O..........09...!hello

^C
2 packets captured
4 packets received by filter
0 packets dropped by kernel

lsof

プロセスが開いているファイルを表示できるコマンド。
-i でソケットだけを表示できる。-i:ポート番号 で絞り込みも可能。
-p でプロセスを指定できる。

$ lsof -i
COMMAND  PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nc      1298 vagrant    3u  IPv4  28252      0t0  TCP *:12345 (LISTEN)
nc      1339 vagrant    3u  IPv4  29509      0t0  TCP *:9999 (LISTEN)
$ lsof -i:12345
COMMAND  PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nc      1298 vagrant    3u  IPv4  28252      0t0  TCP *:12345 (LISTEN)
$ lsof -p 1339
COMMAND  PID    USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
nc      1339 vagrant  cwd    DIR    8,3     4096 5638785 /home/vagrant
nc      1339 vagrant  rtd    DIR    8,3     4096       2 /
nc      1339 vagrant  txt    REG    8,3    43664 4325590 /usr/bin/nc.openbsd
nc      1339 vagrant  mem    REG    8,3  2029224 4328519 /usr/lib/x86_64-linux-gnu/libc-2.31.so
nc      1339 vagrant  mem    REG    8,3   101320 4328538 /usr/lib/x86_64-linux-gnu/libresolv-2.31.so
nc      1339 vagrant  mem    REG    8,3    96728 4328287 /usr/lib/x86_64-linux-gnu/libbsd.so.0.10.0
nc      1339 vagrant  mem    REG    8,3   191472 4328477 /usr/lib/x86_64-linux-gnu/ld-2.31.so
nc      1339 vagrant    0u   CHR  136,0      0t0       3 /dev/pts/0
nc      1339 vagrant    1u   CHR  136,0      0t0       3 /dev/pts/0
nc      1339 vagrant    2u   CHR  136,0      0t0       3 /dev/pts/0
nc      1339 vagrant    3u  IPv4  29509      0t0     TCP *:9999 (LISTEN)

openssl s_client

openssl s_client -connectSSL/TLS 接続に関する情報を表示できる。

$ echo -e 'HEAD / HTTP/1.1\r\nHost: www.hatena.ne.jp\r\n\r\n' | openssl s_client -connect www.hatena.ne.jp:443 -quiet
depth=2 C = US, O = Amazon, CN = Amazon Root CA 1
verify return:1
depth=1 C = US, O = Amazon, OU = Server CA 1B, CN = Amazon
verify return:1
depth=0 CN = www.hatena.ne.jp
verify return:1
HTTP/1.1 200 OK
Date: Tue, 13 Jul 2021 05:29:25 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 291348
Connection: keep-alive
Server: nginx
Vary: Accept-Encoding
Vary: Accept-Encoding
ETag: "47214-Bl7Cq7MeA3CEtqJhoXukBQe/L7k"
Vary: Accept-Encoding
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block

^C

Linux で SMB 共有をマウントする

//192.168.1.100/test/tmp/smb-test にマウントする例です。
uid=$(id -u),gid=$(id -g) が無いと、スーパーユーザ権限でマウントされ色々と面倒なので付けています。

$ sudo mount -t cifs -o uid=$(id -u),gid=$(id -g),user=foo,password=bar //192.168.1.100/test /tmp/smb-test
$ sudo umount smb-test/