Plan9日記

2014-09-29

[] AWSおさらい

Amazon Web Services 基礎からのネットワークサーバー構築」という本が出ていたので、AWSのおさらいも兼ねて読んでみる。AWSの上で、インフラ技術を学ぶという趣旨。クラウドが当たり前になって、クラウドじゃないレガシーなシステムが目の前から消えていくと(半分現実になりつつある気がするが)、近い将来にはこんなテイストのテキストが普通になるのかなと感じた。本書はAWSの入門に必要最低限のネットワーク周りの解説が載っているけど、教科書的解説+クラウドで演習といった形式でね。

さて、VPCを触るのは初めてだけど、VPCを作って、その中のインスタンスApacheを動かすところまで確認した。Tokyo regionだと、RTTは9秒強ぐらいだな。

インスタンスをstopして、続きはまた明日。

余談だけど、Amazon Linuxはちゃんとshellshock対策されてるね。

[ec2-user@ip-10-0-1-10 ~]$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
this is a test

2014-09-24

[] brewでGo言語をインストール

A Tour of Goを進んでいくと、HTTPサーバの例が。お、Playgroundで通信ができるのか?と思ったら、案の定、ローカルで実行せよとのこと。

というわけで、brewインストール

$ brew update
$ brew install go
==> Downloading https://downloads.sf.net/project/machomebrew/Bottles/go-1.3.1.mavericks.bottle.1.tar
######################################################################## 100.0%
==> Pouring go-1.3.1.mavericks.bottle.1.tar.gz
==> Caveats
As of go 1.2, a valid GOPATH is required to use the `go get` command:
  http://golang.org/doc/code.html#GOPATH

`go vet` and `go doc` are now part of the go.tools sub repo:
  http://golang.org/doc/go1.2#go_tools_godoc

To get `go vet` and `go doc` run:
  go get code.google.com/p/go.tools/cmd/godoc
  go get code.google.com/p/go.tools/cmd/vet

You may wish to add the GOROOT-based install location to your PATH:
  export PATH=$PATH:/usr/local/opt/go/libexec/bin

Bash completion has been installed to:
  /usr/local/etc/bash_completion.d

zsh completion has been installed to:
  /usr/local/share/zsh/site-functions
==> Summary
  /usr/local/Cellar/go/1.3.1: 4341 files, 114M

コメントに従って、.bash_profileに環境変数の設定を追加。

export GOPATH=$HOME/go
export GOROOT=/usr/local/opt/go/libexec
export PATH=$PATH:$GOPATH/bin:$GOROOT/bin

bashの補完も効くようなので、続けてbash-completionをインストール

$ brew install bash-completion
==> Downloading http://bash-completion.alioth.debian.org/files/bash-completion-1.3.tar.bz2
######################################################################## 100.0%
==> Patching
patching file bash_completion
==> ./configure --prefix=/usr/local/Cellar/bash-completion/1.3
==> make install
==> Caveats
Add the following lines to your ~/.bash_profile:
  if [ -f $(brew --prefix)/etc/bash_completion ]; then
    . $(brew --prefix)/etc/bash_completion
  fi

Homebrew's own bash completion script has been installed to
  /usr/local/etc/bash_completion.d

Bash completion has been installed to:
  /usr/local/etc/bash_completion.d
==> Summary
  /usr/local/Cellar/bash-completion/1.3: 188 files, 1.1M, built in 6 seconds

こちらもコメントに従って.bash_profileに次の記述を追加。ちゃんと補完が効くようになった。

if [ -f $(brew --prefix)/etc/bash_completion ]; then
  . $(brew --prefix)/etc/bash_completion
fi

デフォルトでパッケージ管理システムが組み込まれている訳ね。ドキュメントをインストールしておく。Mercurialを使うので、これも前もってbrew install hgで入れておく。環境変数GOROOT以下にgodocというコマンドがインストールされた。

$ go get code.google.com/p/go.tools/cmd/godoc

はい、ちゃんとHTTPサーバの例題が動きましたとさ。

$ go build 57.go
$ ./57

また、"code.google.com/p/go-tour/wc"のようなパッケージをimportしている例題もあるけど、これをローカルで動かすときは、これもgo getしてくればよい。

$ go get code.google.com/p/go-tour/wc

$GOPATH/src以下にソースコードが、$GOPATH/pkg以下に*.a形式のバイナリパッケージが配置される。

ということで今日は#58まで。

ちなみにCentOS 7のパッケージではGo 1.2になるようだ。

2014-09-07

systemdとcgroup

systemdではcgroupを活用しているようだ。サービスごとにcgroupでアイソレーションされているので、関係するプロセスを一網打尽で殺せるし、サービスごとの資源利用量を観測できる。確かにpidをファイルに記録しておいて、殺すってのはダサいよね。流れとしてはユニットファイルでExecStopで指定されているコマンドを実行し、それでも当該グループのプロセスが残っている場合は、SIGTERM、SIGKILLの順でシグナルを投げるそうな。詳細はレッドハット中井さんの「Linux女子部 systemd徹底入門」とか。

次はsystemd-cgtopの実行例。

Path                                                         Tasks   %CPU   Memory  Input/s Output/s

/                                                               86    0.3   197.3M        -        -
/system.slice/NetworkManager.service                             2      -        -        -        -
/system.slice/auditd.service                                     1      -        -        -        -
/system.slice/avahi-daemon.service                               2      -        -        -        -
/system.slice/crond.service                                      1      -        -        -        -
/system.slice/dbus.service                                       1      -        -        -        -
/system.slice/firewalld.service                                  1      -        -        -        -
/system.slice/iprdump.service                                    1      -        -        -        -
/system.slice/iprinit.service                                    1      -        -        -        -
/system.slice/iprupdate.service                                  1      -        -        -        -
/system.slice/lvm2-lvmetad.service                               1      -        -        -        -
/system.slice/polkit.service                                     1      -        -        -        -
/system.slice/postfix.service                                    3      -        -        -        -
/system.slice/rsyslog.service                                    1      -        -        -        -
/system.slice/sshd.service                                       1      -        -        -        -
/system.slice/system-getty.slice/getty@tty1.service              1      -        -        -        -
/system.slice/systemd-journald.service                           1      -        -        -        -
/system.slice/systemd-logind.service                             1      -        -        -        -
/system.slice/systemd-udevd.service                              1      -        -        -        -
/system.slice/tuned.service                                      1      -        -        -        -
/system.slice/vboxadd-service.service                            1      -        -        -        -
/user.slice/user-1000.slice/session-4.scope                      4      -        -        -        -

大きく分けるとsystem.sliceとuser.sliceってのがある。/sys/fs/cgroup/systemdがルートね。

systemd-cglsでcgroupの使われ方を見ることができる。

[vagrant@localhost ~]$ systemd-cgls
├─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 23
├─user.slice
│ └─user-1000.slice
│   └─session-4.scope
│     ├─2407 sshd: vagrant [priv]
│     ├─2410 sshd: vagrant@pts/0 
│     ├─2411 -bash
│     ├─2471 systemd-cgls
│     └─2472 systemd-cgls
└─system.slice
  ├─polkit.service
  │ └─747 /usr/lib/polkit-1/polkitd --no-debug
  ├─auditd.service
  │ └─501 /sbin/auditd -n
  ├─systemd-udevd.service
  │ └─455 /usr/lib/systemd/systemd-udevd
  ├─lvm2-lvmetad.service
  │ └─440 /usr/sbin/lvmetad -f
  ├─systemd-journald.service
  │ └─426 /usr/lib/systemd/systemd-journald
  ├─dbus.service
  │ └─543 /bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation
  ├─systemd-logind.service
  │ └─542 /usr/lib/systemd/systemd-logind
  ├─sshd.service
  │ └─1109 /usr/sbin/sshd -D
  :

冒頭で触れた挙動を確認するため、ちょっとソースコードを眺める。systemd本体はsrc/core以下なのかな。サービスユニットの上げ下げはsrc/core/service.cとかsrc/core/unit.cあたりかな。確かにSysVinitでシェルスクリプトで実装されていた分が全部Cで書かれているわけね。たしかにこれはビッグチェンジだなぁ。

service_stop()がsystemctl stopで呼ばれる関数。ユニットごとに状態遷移マシンになっていて、service_enter_stop()でExecStop、service_enter_stop_post()でExecStopPostに登録されたコマンドを順に実行する。コマンドの実行に失敗した場合は、service_enter_signal()を経由してunit_kill_context()でプロセスにSIGTERMを投げる。それでも死なないプロセスはwatchdogで回収され、同様にunit_kill_context()でSIGKILLを投げる。

unit_kill_context()が参照するKillContextにはkill_modeというメンバ変数があり、ユニットはKILL_CONTROL_GROUPに初期化されている(SysVinit互換のケースはKILL_PROCESSになっている)。unit_kill_context()ではcg_kill_recursive()を呼んで、cgroupのプロセスにシグナルを投げる。

cg_*関数の定義はsrc/shared/cgroup-util.c。cgroupの実装がファイルシステムというのがよくわかる。

Google Compute Engine事始め

佐藤さんの講演を聴いて、プロモーションコードをゲットしたことだし*1、GCEを少し試してみることにした。中身を見ずに「Google Compute Engine入門」という書籍も買ってみたのだけど、すでに内容が古くなっている気が。。。本書ではgutilというCLIツールを使っているのだけど、すでにgutilからgcloudというツールに乗り換えることが推奨されている。

この辺を見ながらgcloudを含むSDKをインストール

$ curl https://sdk.cloud.google.com | bash

GCEを使うためのOAuthの設定のためにgcloud auth loginを実行する。実行すると勝手にブラウザが認証用ページに飛び、よしなにしてくれる。

$ gcloud auth login

Developers consoleでプロジェクトを作り、早速インスタンスを立ち上げてみる。asia-east1-cってゾーンがあるね。東アジアリージョンは比較的新しいので、IvyBridgeのサーバを使っているようだ。自宅からだとpingで50ms(どこかで台湾と読んだが、本当か?)。OSはCentOS 7を選択。コマンドラインから実行する場合は、次のようになる。

$ gcloud compute instances create instance-1 --machine-type f1-micro --image centos-7 --zone asia-east1-c --project  shaped-producer-XXX
NAME       ZONE         MACHINE_TYPE INTERNAL_IP   EXTERNAL_IP     STATUS
instance-1 asia-east1-c f1-micro     10.240.192.83 XXX.XXX.XXX.XXX RUNNING

なお、選択可能なインスタンスタイプ(machine-types)は次のコマンドで調べることができる。OSイメージはEC2ほど選択肢はない。

$ gcloud compute machine-types list --zone asia-east1-c --project shaped-producer-XXX
NAME           ZONE         CPUS MEMORY_GB DEPRECATED
f1-micro       asia-east1-c 1     0.60
g1-small       asia-east1-c 1     1.70
n1-highcpu-16  asia-east1-c 16   14.40
n1-highcpu-2   asia-east1-c 2     1.80
n1-highcpu-4   asia-east1-c 4     3.60
n1-highcpu-8   asia-east1-c 8     7.20
n1-highmem-16  asia-east1-c 16   104.00
n1-highmem-2   asia-east1-c 2    13.00
n1-highmem-4   asia-east1-c 4    26.00
n1-highmem-8   asia-east1-c 8    52.00
n1-standard-1  asia-east1-c 1     3.75
n1-standard-16 asia-east1-c 16   60.00
n1-standard-2  asia-east1-c 2     7.50
n1-standard-4  asia-east1-c 4    15.00
n1-standard-8  asia-east1-c 8    30.00

(Webコンソールから)インスタンスが起動すると、ダッシュボードにインスタンスが表示されるので、SSHというボタンを押す。すると、「gcloud compute --project "shaped-producer-XXX" ssh --zone "asia-east1-c" "instance-1"」のような文字列がポップアップされるので、これをターミナルにコピペする。SSH公開鍵を登録してない場合は、新たに生成されるようだ。このようなSSHのラッパーのほか、ファイルを転送するためのpush/pullコマンドなども用意されている。

$ gcloud compute --project "shaped-producer-XXX" ssh --zone "asia-east1-c" "instance-1"
WARNING: You do not have an SSH key for Google Compute Engine.
WARNING: [/usr/bin/ssh-keygen] will be executed to generate a key.
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /Users/oraccha/.ssh/google_compute_engine.
Your public key has been saved in /Users/oraccha/.ssh/google_compute_engine.pub.
The key fingerprint is:
3d:8c:58:eb:c7:6d:9a:ae:af:59:e6:db:81:d6:64:e6 oraccha@MBA11.local
The key's randomart image is:
+--[ RSA 2048]----+
|                 |
|                 |
|        .        |
|       o =       |
|      . S + +    |
|       . . X     |
|        . B E    |
|         B = .   |
|        +=B..    |
+-----------------+
Updated [https://www.googleapis.com/compute/v1/projects/shaped-producer-XXX].
Warning: Permanently added 'XXX.XXX.XXX.XXX' (RSA) to the list of known hosts.
Saving password to keychain failed
Identity added: /Users/oraccha/.ssh/google_compute_engine (/Users/oraccha/.ssh/google_compute_engine)
Warning: Permanently added 'XXX.XXX.XXX.XXX' (RSA) to the list of known hosts.
[oraccha@instance-1 ~]$ uname -a
Linux instance-1 3.10.0-123.6.3.el7.x86_64 #1 SMP Wed Aug 6 21:12:36 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

ちゃんとKVMで動いているようね。

$ systemd-detect-virt 
kvm

ちょっとネットワーク周りを見てみると、eth0にはプライベートアドレスが割り当てられているから、NATでルーティングされているようね。MTUが1460バイト。40バイトはどこへ行ったのでしょう。やはり、GoogleのSDN「Andromeda」がらみかなぁ。あと、デバドラはvirtio_net。

$ ip a show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1460 qdisc pfifo_fast state UP qlen 1000
    link/ether 42:01:0a:f0:c0:53 brd ff:ff:ff:ff:ff:ff
    inet 10.240.192.83/32 brd 10.240.192.83 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::4001:aff:fef0:c053/64 scope link 
       valid_lft forever preferred_lft forever

$ ip r
default via 10.240.0.1 dev eth0  proto static  metric 1024 
10.240.0.1 dev eth0  proto static  scope link  metric 1 

インスタンスの生成・削除ももちろんgcloudコマンドから操作可能。あと、gcloud config set project XXXを実行しておけば、いちいち--projectオプションを指定する必要はない。

$ gcloud compute instances delete instance-1 --zone asia-east1-c
The following instances will be deleted. Attached disks configured to 
be auto-deleted will be deleted unless they are attached to any other 
instances. Deleting a disk is irreversible and any data on the disk 
will be lost.
 - [instance-1] in [asia-east1-c]

Do you want to continue (Y/n)?  

Deleted [https://www.googleapis.com/compute/v1/projects/shaped-producer-XXX/zones/asia-east1-c/instances/instance-1].

確かにEC2と比較すると、CLI周りはよくできているな。

*1https://cloud.google.com/developers/starterpack/からプロモーションコードを入力することで500 USD分無料で使えるようになる。

2014-09-06

systemdについて

前回の続きで、systemdを少し調べてみる。systemdはsysvinitに代わってRedhatやDebianで採用されているが、「Linus様がSystemdにぶちきれる」とかboycott systemdとか、物議を醸しているようだ。

CentOS 6.5だと、PID 1は当然initだけど、CentOS 7はsystemdになっているのがわかる。

$ pstree -h
init─┬─acpid
     ├─agetty
     ├─crond
     ├─6*[mingetty]
     ├─ntpd
     ├─rpc.statd
     ├─rpcbind
     ├─rsyslogd───3*[{rsyslogd}]
     ├─sshd───sshd───sshd───bash───pstree
     └─udevd───2*[udevd]
[vagrant@localhost ~]$ pstree
systemd─┬─NetworkManager─┬─dhclient
        │                └─3*[{NetworkManager}]
        ├─VBoxService───7*[{VBoxService}]
        ├─agetty
        ├─auditd───{auditd}
        ├─avahi-daemon───avahi-daemon
        ├─crond
        ├─dbus-daemon───{dbus-daemon}
        ├─firewalld───{firewalld}
        ├─iprdump
        ├─iprinit
        ├─iprupdate
        ├─lvmetad
        ├─master─┬─pickup
        │        └─qmgr
        ├─polkitd───5*[{polkitd}]
        ├─rsyslogd───2*[{rsyslogd}]
        ├─sshd───sshd───sshd───bash───pstree
        ├─systemd-journal
        ├─systemd-logind
        ├─systemd-udevd
        └─tuned───4*[{tuned}]

/sbin/initがsystemdへのシンボリックリンクになっているのね。

[vagrant@localhost ~]$ ls -l /sbin/init 
lrwxrwxrwx. 1 root root 22 Aug  1 08:41 /sbin/init -> ../lib/systemd/systemd

systemdは高速起動が売りの一つとのことだけど、systemd-analyzeってコマンドで起動時間や何処で時間を食っているかなどを調べることができる。

[vagrant@localhost ~]$ systemd-analyze time
Startup finished in 431ms (kernel) + 1.326s (initrd) + 7.844s (userspace) = 9.603s

[vagrant@localhost ~]$ systemd-analyze blame
          2.167s firewalld.service
          1.825s kdump.service
          1.584s tuned.service
          1.442s vboxadd.service
          1.166s network.service
          1.102s lvm2-monitor.service
          :

また、ログ周りもsyslogdからjournaldという独自の実装に変わっている。

[vagrant@localhost ~]$ sudo journalctl
-- Logs begin at Fri 2014-09-05 01:45:16 EDT, end at Sat 2014-09-06 00:32:19 EDT. --
Sep 05 01:45:16 localhost.localdomain systemd-journal[80]: Runtime journal is using 4.0M (max 24.5M, leaving 36.7M of free 241.1M, current limit 24.5M).
Sep 05 01:45:16 localhost.localdomain systemd-journal[80]: Runtime journal is using 4.0M (max 24.5M, leaving 36.7M of free 241.1M, current limit 24.5M).
Sep 05 01:45:16 localhost.localdomain kernel: Initializing cgroup subsys cpuset
Sep 05 01:45:16 localhost.localdomain kernel: Initializing cgroup subsys cpu
Sep 05 01:45:16 localhost.localdomain kernel: Initializing cgroup subsys cpuacct
Sep 05 01:45:16 localhost.localdomain kernel: Linux version 3.10.0-123.6.3.el7.x86_64 (builder@kbuilder.dev.centos.org) (gcc version 4.8.2 20140120 (Red Hat 4.8.2-16) (GCC) ) #1 SMP Wed Aug 6 21:12:36 UTC 2014
Sep 05 01:45:16 localhost.localdomain kernel: Command line: BOOT_IMAGE=/vmlinuz-3.10.0-123.6.3.el7.x86_64 root=/dev/mapper/centos-root ro rd.lvm.lv=centos/swap vconsole.font=latarcyrheb-sun16 vconsole.keymap=jp106 rd.lvm.lv=centos/root crashkernel=auto rhgb quiet LANG=en_US.UTF-8
:

オプションに"-b"を指定すればブート時のもの、_SYSTEMD_UNIT=sshd.serviceまたは'which sshd'(デーモンのパス)を指定すればそのログのみが取り出せる。

[vagrant@localhost ~]$ sudo journalctl _SYSTEMD_UNIT=sshd.service
-- Logs begin at Fri 2014-09-05 01:45:16 EDT, end at Sat 2014-09-06 00:34:34 EDT. --
Sep 05 01:45:24 localhost.localdomain sshd[1099]: Server listening on 0.0.0.0 port 22.
Sep 05 01:45:24 localhost.localdomain sshd[1099]: Server listening on :: port 22.
Sep 05 01:45:30 localhost.localdomain sshd[2202]: Accepted publickey for vagrant from 10.0.2.2 port 49275 ssh2: RSA dd:3b:b8:2e:85:04:06:e9:ab:ff:a8:0a:c0:0
Sep 05 01:48:34 localhost.localdomain sshd[3895]: Accepted publickey for vagrant from 10.0.2.2 port 49326 ssh2: RSA dd:3b:b8:2e:85:04:06:e9:ab:ff:a8:0a:c0:0

systemdのメインコマンドはsystemctl。これでサービス(systemd用語ではユニットというのかな)の有効・無効などを制御できる。serviceコマンドのレベルでは互換性を保っているようなので、取りあえずは戸惑いなく使えるのかなぁ。それに加えて、systemctl rebootとかpoweroffってのもできる。ふむ、/usr/sbin/rebootなどがsystemctlへのシンボリックリンクになっている。結構システム全体に影響あるんだなぁ。

あと話は脱線するけど、systemd-detect-virtというハイパーバイザを認識するコマンドがある。

[vagrant@localhost ~]$ systemd-detect-virt 
oracle

どんな実装になっているのかな。gitリポジトリを眺めてみたところ、このへんだね。CPUIDやDMIを使って検出するようね。VirtualBoxの場合は、/sys/class/dmi/id/sys_vendorが"innotek GmbH"であれば、VirtualBoxと判定されるようだ。

関連して、hostnamectlってコマンドもあるようだ。Chassisは"vm"になりそうなものの、"n/a"になっているね。

[vagrant@localhost ~]$ sudo hostnamectl 
   Static hostname: localhost.localdomain
         Icon name: computer
           Chassis: n/a
        Machine ID: 42223b0ecc4b406f8c15a34a4ad16be9
           Boot ID: c140fb95493041e7ab58a6ddbe4b74f6
    Virtualization: oracle
  Operating System: CentOS Linux 7 (Core)
       CPE OS Name: cpe:/o:centos:centos:7
            Kernel: Linux 3.10.0-123.6.3.el7.x86_64
      Architecture: x86_64

2009-12-11

[] Mitaka.rb & 三鷹プログラマーズカフェ合同忘年会

Webアプリ系しかもRubyの集まりっぽいからあまり縁のない世界なのだと思っていたのだが、プログラマーズカフェって何?って気になっていたので、急遽参加を決めた。とはいえ世間は狭いので、思いがけない再会があったり、見知った顔も何人かいた。ともかく普段とは経路の違う話が聞けて楽しかった。

で、ご飯を食べて返るってのも何なので、Webっぽいネタでと頭をひねって、Plan 9 + Pegasus + RitでLTすることにした。PegasusはWebサーバ、RitはPHPやebashみたいにHTMLの中にRcスクリプト埋めることができるドキュメント埋込み型言語。どちらも有澤先生の作品。LTではちゃんと説明する時間はなかったのだが、ごくごくシンプルな掲示板っぽいアプリを書いてみた。久々にRcのコードを書いたので結構構文を忘れていたのだが、POSTリクエストをパースしてってのも割と簡単に書ける。URLデコードだけは自分で書くのが面倒だったので、wercのライブラリを使った。

Pegasusのセットアップ方法も書こうかと思ったけど、またの機会に。ドキュメント通りにやれば特に迷うところはないと思うけど、/lib/ndb/localにドメイン名書いておかないと起動に失敗するとか、CGIを実行するときには、次のようなハンドラファイルを書く必要があった。

$web/etc/handler:
*.cgi	text/html	0	$target

資料はこちら。「Plan 9とWebプログラミング