PPTP vs L2TP/IPSec vs OpenVPN vs IKEv2
iOS10からPPTPクライアントが廃止されてしまい、 家のバッファロールータで動いていたPPTPサーバにアクセスできなくなってしまったので、この際きちんとVPNサーバーを立ててみる。
まずはVPNの方式について調査。
VPN方式の違い
PPTP
古くからある方式だが、脆弱性があるため現在は基本的に使用しない。
- メリット
- 歴史が古く、多くのクライアントがある。
- 構築がかんたん
- 高速
- デメリット
- 安全ではない(が、今でも広く使われている)
L2TP or L2TP/IPsec
現在一般的な方式。L2TP単体ではなくIPsecと組み合わせて構築する。
- メリット
- 安全(と思われる)
- 構築がかんたん
- 対応クライアントが多い
- OpenVPNより高速
- デメリット
- クラック済みといううわさがある(詳しくは参考記事を参照)
- UDP:500を使用するためポートフォワーディングが必要
OpenVPN
- メリット
- デメリット
SSTP
Microsoftが開発した比較的新しい方式。
IKEv2
- メリット
- デメリット
まとめ
参考サイトにある通り、OpenVPN > iKEv2 > L2TP/IPsec >> SSTP >>>>> PPTP(論外) という感じかな。
クライアントは主にiOS, macOSだし、外出先からつなぎたいケースがほとんどだから、IKEv2で作ってみよう。
参考
非常にわかりやすい解説だった。
Docker on vagrant on Windows10
Docker on vagrant
Dockerをvagrant上に構築してみる。 ネット上の情報を参考にしてみてもうまくいかなかったので、だいぶ試行錯誤した
目指す構成は以下のとおり
Docker Container (CentOS6) on Vagrant (CentOS6) on Windows 10
※今回はHadoopクラスタ構築を目標にしているので、Hadoopという文字列がちらほら出てきますが、そこは任意です
Why docker on vagrant
ネット上の記事を見ると、vagrantで仮想環境を立てて、その上にさらにDockerによるコンテナを構築する例が多いけど、 docker(仮想) on vagrant (仮想)と、2重に仮想環境を構築する意味が最初わからなかった。
自分で調べてみたところでは、
- DockerはLXCを利用しており、Linux上でしか動作しない
- そのため、OSXやWindows上では、VagrantでまずLinux環境を構築してから、Dockerを入れる。
- 逆にホストOSが最初からLinuxであれば、Dockerコンテナを直に立てればいい。
利点として、どのOSで作業をしようが、どこでもDockerコンテナを立てることができるので、 別OSに環境を移植する際もDockerコンテナを持っていけばよいということかな。
(Vagrantごと持って行くと、Linux上ではLinux - Vagrant - Dockerとなり、 コンテナ型仮想化であるDockerを直接利用するよりオーバーヘッドが大きい)
Docker provision vs Docker provider
VagrantでDockerを扱うには、provisionとproviderが2つあって、どちらを使えばいいのかよくわからなかったので整理。
VagrantでDockerを立てる方法は主に2つある。
Provision:
- Vagrantが立てるVM上に、Dockerを構築する。
あくまでVMを立ててからDockerをインストールする形になるので、ホストOSがLinuxである場合にもLinux - VM - Dockerという構成になる。
Vagrant v1.6まではこの構成?
Provider:
- Vagrant ver1.6から追加された機能。
VagrantがVMを構築する際に、VirtualBox等によるVMでなく、Dockerによるコンテナを指定できるというもの。
MacやWindowsなど、直接Dockerが構築できないホストOS上では、Vagrantが自動で中間のLinux VMを立ててくれる。
一方で、ホストOSがLinuxの場合は直接Dockerコンテナを立てるため、無駄がないのかな(未確認)。
どのOSでも使え、設定が簡単そうなProviderがよさそう。
Docker on Vagrant on Window10
Windows10にVagrant を立てて、その上にDockerコンテナを構築する
準備
以下をインスト-ル(詳細は割愛)
- Vagrant 1.8
Vagrantfile
mkdir {任意のディレクトリ}/hadoop # 以下、D:/virtualbox_vms/hadoopとする cd D:/virtualbox_vms/hadoop mkdir host
hadoop/Vagrantfile
にDockerコンテナ自体の構築手順を、
hadoop/host/Vagrantfile
にDockerをインストールするVMのVagrantfileを置く。
ここらへんは、ドキュメントも豊富なのでそちらを参考に。。(そのうち追記するかも)
- http://blog.scottlowe.org/2015/02/10/using-docker-with-vagrant/
- http://qiita.com/ike_dai/items/fb4d7616a14c51a99592
Vagrantfile
VAGRANTFILE_API_VERSION = "2" ENV['VAGRANT_DEFAULT_PROVIDER'] = 'docker' Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.define "hadoop-container" do |h| h.vm.provider "docker" do |docker| docker.vagrant_vagrantfile = "./host/Vagrantfile" docker.name = 'hadoop-container' docker.build_dir = '.' end end end
Dockerfile
FROM centos:centos6 RUN yum update -y ### 以下、Dockerコンテナの構築コマンド(省略
host/Vagrantfile
# -*- mode: ruby -*- # vi: set ft=ruby : Vagrant.configure(2) do |config| config.vm.hostname = "docker-host" config.vm.box = "bento/centos-6.7" config.vm.box_check_update = false # provisoned by docker config.vm.provision "docker" end
以上のファイルを準備したら、hadoopディレクトリ以下で、
vagrant up
と実行すれば、host/以下のVMも含めてdocker コンテナの立ち上げまでやってくれる。 はずだった。。
Permisson denied
DockerでのProvider実行時にPermisson Deniedになった。
D:\virtualbox_vms\hadoop>vagrant up Bringing machine 'hadoop-container' up with 'docker' provider... ==> hadoop-container: Docker host is required. One will be created if necessary... hadoop-container: Docker host VM is already ready. ==> hadoop-container: Building the container from a Dockerfile... hadoop-container: stat /var/lib/docker/docker_build_7afac34b3a4f4be525c3d67a8eef89c3: permission denied A Docker command executed by Vagrant didn't complete successfully! The command run along with the output from the command is shown below. Command: "docker" "build" "/var/lib/docker/docker_build_7afac34b3a4f4be525c3d67a8eef89c3" Stderr: stat /var/lib/docker/docker_build_7afac34b3a4f4be525c3d67a8eef89c3: permission den ied Stdout:
同様の事例がissueに報告されている。 https://github.com/mitchellh/vagrant/issues/6822
これは、/var/lib/dockerがvagrant構築時にはroot権限になっているが、dockerコマンドを実行するのはvagrantユーザーであるから。
以下の行をhost/Vagrantfileに追記し、/var/lib/dockerディレクトリをvagrantユーザーのものにしておく。
# provisoned by docker config.vm.provision "docker" ## 追記 config.vm.provision "shell", inline: <<-SHELL sudo chown vagrant:vagrant /var/lib/docker SHELL
privisonは複数指定できるみたい。
これでとりあえずDockerコンテナが立ち上がるところまで確認できた。
MarkdownからConfluence HTMLを生成するConverterを作った。
サーバー上での作業途中など、普段の業務メモは手元のエディタにmarkdown表記で記録している。
ところが、技術系の資料はConfluenceにまとめることになっているため、作業終了後はmarkdownで書いた記録を、再度Confluence上で作成しなおすことになる。
そのConfluenceも、あるバージョンからwiki記法が使えなくなり、仕方なくウェブUIで編集しているが、
これが頻繁にレイアウトがおかしくなったり、けっして使い勝手が良いとはいえない状態。
Confluenceにはmarkdownマクロも用意されてはいるものの、コードブロックの表示にシンタックスハイライトがきかずに、全体的な見た目もいまいち。
markdownからHTMLに変換するライブラリは世の中にたくさんあるので、少しConfluence用にカスタマイズすればできるのでは?ということで、ConfluenceのHTMLを自動生成するツールを作った。 github.com
見た目にもずいぶんましになったし、ちまちま手で移行させる必要もないので便利ー
今後追加したい機能
- Upload機能
Capistranoでオペレーション自動化をしようとして諦めた
社内のチームで数十台~のサーバーを管理していて、その上でElasticSearchやHadoopを構築している。 これまで、そのクラスタのオペレーションをほぼ手作業なりシェルスクリプトでやっていて、 手順の再利用性もないし何よりめんどくさいので、 何か自動化できるツールを導入したいと思った。
そこで注目したのがCapistranoだった。
Capistranoはデプロイツールであるけれども、シェルコマンドの自動化にも使えるらしい。
以下、実験的にいくつかオペレーションをCapistrano3に移行してみて、結果挫折した話。
なぜCapistranoを選んだか
チームにRubyエンジニアが多く、また構成管理はChefがデファクトになりつつあって、 Rubyで書ける仕組みが欲しかった。
デプロイ作業もrsync上等!でやっていて、将来的にきちんとCI環境を整えたく、 後々デプロイツールとしても利用できるものを使いたかった。
Capistranoの壁
実際にタスクをCapistranoにしてみて、いくつか壁があった。
学習コストが高い
Capistranoは学習コストが高い。 確かにきちんと環境とタスクを切り離して管理したり、HostFilterの仕組みも便利だった。
しかし、仕組みがしっかり作られることによって、逆に学習コストが高くなってしまっている。 Chefと同じくタスクの記述がDSLになっていて、いちいち覚える事が多い。
設定ファイルのローディング順やCapistranoがどうやってタスクを生成しているか理解していないと、
- setした値がfetchできない
- setできてるのにタスクに反映されない
みたいなことが頻繁にあり、
「あれ、この記述どこに書けばいいんだっけ」
となることが多かった。
さらに、Capistrano3になってからオプションや記述方法の変更が入っていて、 ネット上のノウハウも2と3が混在してしまっている状況。
別に自分たちがバージョンを上げなければ問題ない話なのだけれど、せっかく積み上げたネット上のノウハウが 陳腐化したりバージョンで分断されたりするのはもったいない。。
チームで使っていくにあたって、ここらへんの学習コストなりツールの更新によるメンテナンスが問題になりそうだなぁとは初期の段階から感じた。
並列志向であること
もともとデプロイツールということを考えると仕方がないところだけど、Capistranoは並列志向だ。 原則、タスクは並列に実行される。
デプロイツールではそれで問題ないというか、そのほうが反映ラグが少なくていいのだろうけど、 サーバーオペレーションだと並列に実行するというシチュエーションはそれほど多くないと思う。
むしろ1台ずつ状況を確認しながら実行したいし、 やりたかったのがESのローリングリスタートだったので、なおさら直列にしか実行してはいけないものだった。
一応Capistranoでも、タスクにin: sequence
とかけばを直列実行できるオプションは用意されている。
でもこいつが曲者。
例えば、あるタスク(parent task)から別のタスク(child task)を呼び出すような場合
role :web, %w{host1, host2} task :parent do on roles(:web), in: :sequence do |host| puts 'parent start@%s' % host invoke 'child' puts 'parent end@%s' % host end end task :child do on roles(:web) do |host| puts 'child exec@%s' % host end end """ $ cap production parent parent start@host1, child exec@host1, child exec@host2 parent end@host1, parent start@host2 parent end@host2 """
host02のchildがparentより先に呼ばれてしまっている。
最初にあれ?っと思ったけど、よくよく調べればinvoke 'child'
の時点でhost02も呼ばれてしまうのだった。
これはchildにin: :sequence
を指定しても変わらない。
んー、仕組みがわかれば納得なんだけど、全然直感的じゃないというか、 普通にtask AからBを呼ぶ、みたいなことはやるわけで、それがさくっとできないのはつらい。
capistrano2ではinvoke 'child', hosts=>host
とすれば実現できた。なぜなくなったし。。
カスタマイズしづらい
上の入れ子タスクの問題をなんとか実行時に解決するすべはないかとコードを追ってみたけれど、
Capistranoはタスク設定時にroleやhostを決めてしまっていて、
実行時にset :hosts, XXX
でむりやり実行サーバーを限定する、のようなことができなかった。
残念
結論: Capistranoはデプロイツールであってオペレーションツールではない
そもそもCapistranoはデプロイツールなわけで、がんばってオペレーションもこれでできなくはないけど、 そこまでする意味はなかったかなと。。
すでにCapistranoガッツリ使ってるわけでないのであれば、わざわざ学習してまで導入するメリットはなさそう。 もちろんCapistranoのが悪いわけではなく、デプロイツールとしては実績あるいいフレームワークだと思う。
そしてFabricへ
結局、Capistranoは諦めてFabricを導入することにした。
FabricはCapistranoに比べて学習コストが低く、チームで導入しても負担が少ない。 (そもそもほとんどシェルコマンドだし)
薄いフレームワークだけ提供されているので、 コードを読むのも楽だし、独自の処理を差し込むのが簡単だ。
実際、CapistranoにあるHostFilter、RoleFilterの機能をデコレーターを独自に実装して導入している。
今回学んだことは、
- ツールは本来の目的に使用してこそ力を発揮する
- 学習コストを慎重に検討するべき。まず試すならシンプルなものを。 simple is best
ということ。
しばらくFabricを試してみよう。
GangliaでHDD温度監視
Gangliaにカスタムモジュールを入れてHDDの温度監視をしてみる。
前提 |
---|
CentOS 7.1 |
Gangalia 3.7 |
セキュリティを重視していないので、実験用環境での使用を想定しています
Package インストール
python モジュールで拡張するので、以下のパッケージをインストールする
ganglia-3.7.2-2.el7.x86_64 ganglia-gmetad-3.7.2-2.el7.x86_64 ganglia-web-3.7.1-2.el7.x86_64 ganglia-gmond-python-3.7.2-2.el7.x86_64 ganglia-gmond-3.7.2-2.el7.x86_64
ganglia-gmond-python package
ganglia-gmond-pythonパッケージには以下のファイルが入っている
... /usr/lib64/ganglia/modpython.so /etc/ganglia/conf.d/modpython.conf ...
modpython.soはPython拡張を有効にするためのモジュール。 modpython.confの中身は以下のようになっている。
modules { module { name = "python_module" path = "modpython.so" params = "/usr/lib64/ganglia/python_modules" } } include ("/etc/ganglia/conf.d/*.pyconf")
- modules ... Python拡張モジュールを有効にするための、modpython.soを読み込んでいる。 また、拡張モジュールの配置場所をpathによって設定している。
- include ... Python拡張モジュール用の設定ファイルであるpyconfファイルを、conf.d以下から一括で読み込むように指定している。
拡張用Pythonモジュールの書き方
上のpython拡張パッケージがインストールされていれば、pythonモジュールは使えるようになっているはず。
あとは拡張用モジュールの用意と、設定ファイルを用意する。
Python モジュール
拡張用のPythonモジュールでは、以下の関数を実装すればよい。
- def metric_init(params): 初期化のために一度だけ実行される関数
- def metric_cleanup(): gmondが終了する時に一度だけ呼ばれる関数
- def metric_handler(name): 監視目的の値を返す関数。名前は自由
詳細は https://github.com/ganglia/monitor-core/wiki/Ganglia-GMond-Python-Modules
コード
例えば、/dev/sda
の温度をsmartctlから取得するコードは以下。
# -*- coding: utf-8 -*- import os import re import random from subprocess import check_output NAME_PREFIX = 'disk_temp' def get_disktemp(name): disk = name.replace(NAME_PREFIX + '_', '') disk_info = check_output(['sudo', '/sbin/smartctl', '-a', '/dev/%s' % disk]) temp_line = [line for line in disk_info.split('\n') if line.find('Temp') >= 0][0] return float(re.split('[\s\t]+', temp_line)[-1]) def metric_init(params): units = 'Celcius' disks = ['sda'] descriptors = [{ 'name': '_'.join([NAME_PREFIX, disk]), # metircs name 'call_back': get_disktemp, 'time_max': 60, 'value_type': 'float', 'units': units, 'slope': 'both', 'format': '%f', 'description': 'Disk temperature (%s) on disk /dev/%s' % (units, disk), 'groups': 'disk' } for disk in disks] return descriptors def metric_cleanup(): pass
このファイルをdisktemp.py
として、/usr/lib64/ganglia/python_modules
に配置する
pyconf 設定ファイル
実装した拡張モジュールで監視を行うための設定を追加する
modules { module { name = "disktemp" # my python module name language = "python" } } collection_group { collect_every = 180 # metrics span time_threshold = 60 # metrics send span metric { name_match = "disk_temp_(.+)" } }
ここでは取得間隔を180sec、gmetadへの通知間隔を60secにしている。
sudoers設定
gangliaを実行しているユーザーがroot出ない場合(例えばgangliaユーザー)、sudoersの設定が必要
# ttyなしでsudo実行 Defaults:ganglia !requiretty # /sbin/smartctl 実行許可 Cmnd_Alias LOOK_SMART = /sbin/smartctl -a /dev/* ganglia ALL=(ALL) NOPASSWD: LOOK_SMART
結果
gmondを再起動して、ちゃんとメトリクスが収集されているか確認
※うまく収集されていない、gmondが起動しない場合、/var/log/messages
を確認する。
descriptorについて
今回遭遇したトラブル
- descriptorのvalue_typeとformatが違っていてgmondが起動しない
- 公式によると予期せぬ測定値になるとあるが、エラーを吐いて起動しなかった
- value_type: float, format: %f にちゃんと揃える
- value_typeを途中から変更した場合にgmetadがエラー
- おそらく過去のrrdデータと不整合が起きるためだと思う。 int -> floatは問題ないが、逆だとだめそう。
- rrdtoolのデータを削除して解決
CentOS7のKernelを最新版に更新する(yumで)
docker1.9のoverlay networkを試すにはLinux kernel3.16が必要だが、CentOS7では3.10までしか提供されていない。 kernelの更新はelrepoを使えば簡単にできるようなので試してみた。
注意: kernelの更新は危険なオペレーションのため、壊れても良い環境で試して下さい。
現在のkernel |
---|
3.10.0-229.14.1.el7.x86_64 |
elrepoの追加
yumのrepolistにelrepoを追加
$ rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org $ rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm
elrepo-kernelを有効にする。enabled=0
になっているのでenabled=1
とする
$ vim /etc/yum.repos.d/elrepo.repo ---- [elrepo-kernel] name=ELRepo.org Community Enterprise Linux KÂernel Repository - el7 baseurl=http://elrepo.org/linux/kernel/el7/$basearch/ http://mirrors.coreix.net/elrepo/kernel/el7/$basearch/ http://jur-linux.org/download/elrepo/kernel/el7/$basearch/ http://repos.lax-noc.com/elrepo/kernel/el7/$basearch/ http://mirror.ventraip.net.au/elrepo/kernel/el7/$basearch/ mirrorlist=http://mirrors.elrepo.org/mirrors-elrepo-kernel.el7 enabled=1 <==== 0から1に変更 gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-elrepo.org protect=0
install
# 古いkernelのパッケージを削除 $ yum remove kernel-headers-3.10.0-123.9.2.el7.x86_64 kernel-tools-3.10.0-123.9.2.el7.x86_64 kernel-tools-libs-3.10.0-123.9.2.el7.x86_64 $ yum update $ yum install kernel-ml.x86_64 kernel-ml-devel.x86_64 kernel-ml-headers.x86_64 kernel-ml-tools.x86_64 kernel-ml-tools-libs.x86_64
grub起動設定変更
$ awk -F\' '$1=="menuentry " {print $2}' /etc/grub2.cfg --- CentOS Linux 7 (Core), with Linux 4.3.0-1.el7.elrepo.x86_64 CentOS Linux 7 (Core), with Linux 3.10.0-229.20.1.el7.x86_64 CentOS Linux 7 (Core), with Linux 3.10.0-229.14.1.el7.x86_64
更新したいKernel4.3が1行目にあるので
# 起動Kernel $ grub2-set-default 0 # 設定反映 $ grub2-mkconfig -o /boot/grub2/grub.cfg # 再起動 $ reboot
再起動後、
$ uname -r
4.3.0-1.el7.elrepo.x86_64
更新されている!
kernel version
以下のページから利用できるrpmを知ることができるが、kernel3はもうないみたい http://elrepo.org/linux/kernel/el7/x86_64/RPMS/
参考
http://wiki.mikejung.biz/CentOS_7#Upgrade_CentOS_7_Kernel_to_4.0.1
RundeckからGmailを使ってメール送信する
Rundeckをジョブスケジューラとして使い始めて、メールをGmail経由で送れるようにした。 OSはCentOS7だが、他でも変わらないはず。
Rundeckのインストール
インストールは難しくない。yumで入るはず。
起動もsystemctl start rundeckd.service
でできる。
詳細は割愛
設定
※以下、rundeckの設定は/etc/rundeck配下にあるものとしています。
公式ドキュメントには一応設定はある。 http://rundeck.org/docs/administration/email-settings.html localhostにsmtpサーバーを立てている場合は
grails.mail.host=localhost grails.mail.port=25
でいいらしいが、今回はSSL認証が必要はため別の手段が必要。
rundec-config.groovy
まずはより詳細な設定ができるように設定ファイルをGroovy形式のファイルに置き換える。
rundeck-config.propertiesと同じディレクトリにrundeck-config.groovyを作成する。
デフォルトのpropertiesは使わないので適当にリネームしておく。
$ mv rundeck-config.properties rundeck-config.propertties.bak $ touch rundeck-config.groovy
基本設定はrundeck-config.propertiesと同じになるようにする。 それにメール設定を以下のように設定する。
// #### デフォルト設定 #### loglevel.default="INFO" rdeck.base="/var/lib/rundeck" rss.enabled=false dataSource { dbCreate="update" url="jdbc:h2:file:/var/lib/rundeck/data/rundeckdb;MVCC=true;TRACE_LEVEL_FILE=4" } grails { serverURL="http://localhost:4440" // #### Mail 設定 #### mail { host="smtp.gmail.com" port = 465 username="XXXXXX@gmail.com" password="XXXXXXX" props = ["mail.smtp.auth":"true", "mail.smtp.socketFactory.port":"465", "mail.smtp.socketFactory.class":"javax.net.ssl.SSLSocketFactory", "mail.smtp.socketFactory.fallback":"false"] } }
grails.mail以下に上のようにGmail用の設定を記述すればOK.
起動オプション変更
上記で作成した.groovyファイルを読み込んで起動するように、 CONFIG_DIR/profile
ファイルに以下の行を追加
# Add to load custom config RDECK_JVM="$RDECK_JVM -Drundeck.config.location=/etc/rundeck/rundeck-config.groovy"
systemctl restart rundeckd.service
でちゃんと再起動するか確認。
エラーが出る場合はgroovyファイルに間違いがないかどうか確認する。
ジョブ作成
メールは送信できるようになっているはずなので、あとはNotificationにメールを設定するだけだ。
うーん、それにしてもRundeckが相当DiskIO食ってるんだけどなんでだろう。。IO waitかなり出ている。。