SSH経由でウェブサイトにアクセスする
使用例
SSH先のサーバからしか接続できないウェブサイト(例:学内サイト)をローカルから接続する.
方法
SSHでトンネルを掘る.
ssh -N -D 10080 user@hoge.com
ここで-f
オプションをつけるとバックグランドで動かし続けることが可能.
10080は慣習で実際は任意.
ChromiumでSSH経由で接続する.
chromium-browser --proxy-server="socks5://127.0.0.1:10080"
SOCKSプロトコルを使う.
システム設定をせずともproxy-server
オプションで可能.
なお,すでに開いているブラウザが存在するときはすべて閉じてからコマンドを実行すること.
リモートからOSをインストールする
概要
通常,OSをインストールするにはCDやUSB等のメディアを直接PCに接続し,その場で設定を行う. もちろん,インストール途中のPCにはSSHできないためリモートからこれらの作業を行うことはできない.
本記事では,すでにSSH接続できる遠隔地のPCに対し,新たにOSをインストールし,デュアルブートの形で設定する方法を解説する.
おおまかな流れとしては以下のとおりである.
背景
ローカル環境をLOCAL,リモートの環境をREMOTE,新たに作成する環境をNEWとする. なお,本記事とは直接関係ないが,中間ノードMIDが存在し,REMOTEはMID経由でしかアクセスできない. MID->REMOTEのアクセスは,mDNSを用いてIPアドレスの解決を行うことで実現している.
いま,REMOTEにSSHでき,システムが稼働中であるとする. REMOTEに存在する外部ストレージに新たにOSをインストールし,それを起動し,アクセスしたいとする. (同一ストレージデバイスの異なるパーティションに対しても今回は未検証だが,同一手順でできると思われる.この際はresize2fsで稼働中のファイルシステムを縮小し,新たなOS用の領域を確保する必要がある.) 現在稼働中のOSは/dev/sdaにあり,新たにインストールするOSは/dev/sdb1にインストールするとする.
実際の手順
仮想マシンのインストール
まずはREMOTE内でKVMを使って新たに仮想マシンを作成する. このとき,作成する仮想マシンのストレージ容量はあまり大きくならないように(例:8GB)する.
この例ではUbuntu16をインストールする.
REMOTE$ sudo virt-install \ --connect=qemu:///system \ -n ubuntu16 \ -r 1024 \ --disk path=new.img,size=8,format=raw \ --vcpus=1 \ --os-type linux \ --network network=default \ --nographics \ --extra-args='console=tty0 console=ttyS0,115200n8' \ --location http://ftp.jaist.ac.jp/pub/Linux/ubuntu/dists/xenial/main/installer-amd64/
ここで作成したOSが,新たに(仮想マシン上ではないく,ネイティブに)インストールするOSとなる. 注意点としては,
- swapを作成せずプライマリパーティションをひとつだけ作成する
- LVMを使わない
である.
なお,仮想マシンの保存先としてファイルを指定しているが,これを/dev/sdb1としてはいけない. インストール中に分かると思うが,仮想マシンでは仮想ストレージを作成するためにこれを直接起動することはできないからである.
インストールできたらシャットダウンする.
(オプション)シリアルコンソールを有効化する
Ubuntu16の場合はコンソール接続がそのままではできないので,インストール後に直接イメージファイルを編集して,コンソール接続できるようにする必要がある.
以下の記事に詳しい.
Ubuntu 16.04 LTS : KVM : 仮想マシン作成#1 : Server World
仮想マシンをセットアップ
仮想マシンを起動し,セットアップを行う.
SSHサーバのセットアップ
NEW$ sudo apt install openssh-server
.ssh/authorized_keysに公開鍵を登録する. なお,仮想マシンのIPアドレスは,
REMOTE$ virsh net-dhcp-leases default
で分かる.
(オプション)mDNSの設定
MIDからhostname.localでアクセスできるようにmDNSの設定を行う.
NEW$ sudo apt install avahi-daemon
自動シャットダウンスクリプトを仕込む
後ほどNEWを仮想マシンを経由せずに起動することになる. この際,ネットワークにエラーが発生した場合SSHで接続できず,手出しができなくなってしまう. そのため一定時間で自動的にシャットダウンするスクリプトを仕込む. 直接NEWにアクセスできなくとも,WOLを利用してMIDからREMOTEを起動することはできるのである.
/etc/rc.localにスクリプトを作成し,置いておく. 例えば10分後に自動でシャットダウンをする動作を記述. もちろん,無事にSSHできた場合はこのプロセスを殺す.
ネットワークの設定
OSごと異なる環境に移すことになるのでネットワークにも不調が出る(出た). 今回の問題は/etc/network/interfacesの記述が間違っていたことだった.
現在,
NEW$ cat /etc/network/interfaces # This file describes the network interfaces available on your system # and how to activate them. For more information, see interfaces(5). source /etc/network/interfaces.d/* # The loopback network interface auto lo iface lo inet loopback # The primary network interface auto ens2 iface ens2 inet dhcp
となっているものを,
NEW$ cat /etc/network/interfaces # This file describes the network interfaces available on your system # and how to activate them. For more information, see interfaces(5). source /etc/network/interfaces.d/* # The loopback network interface auto lo iface lo inet loopback # The primary network interface auto eno1 iface eno1 inet dhcp
と変更する.
なお,"eno1"の見つけ方であるが,これは何度か起動,自動シャットダウンを繰り返して見つけることになる. 具体的には件のシャットダウンスクリプト内部に,dmesgをダンプして保存する処理を仕込み,シャットダウンする. その後REMOTEが起動したら,NEWのパーティションをマウントし,ダンプされたファイルを確認する.
dmesg中の以下のような箇所を発見する.
[ 9.136448] e1000e 0000:00:19.0 eth0: registered PHC clock [ 9.136450] e1000e 0000:00:19.0 eth0: (PCI Express:2.5GT/s:Width x1) XX:XX:XX:XX:XX:XX [ 9.136452] e1000e 0000:00:19.0 eth0: Intel(R) PRO/1000 Network Connection [ 9.136478] e1000e 0000:00:19.0 eth0: MAC: 11, PHY: 12, PBA No: FFFFFF-0FF [ 9.136923] e1000e 0000:00:19.0 eno1: renamed from eth0
eth0が何にrenameされているか調べれば良い.
外部ストレージ(/dev/sdb)のセットアップ
fdisk等を使い,パーティション/dev/sdb1を作成する.
後から行う強引な方法のために/dev/sdb1をゼロ埋めで初期化する.
REMOTE$ sudo dd if=/dev/zero of=/dev/sdb1
仮想マシンの中身を外部ストレージに移す
まず新たに作成した仮想マシンを起動する.
先程作成した外部ストレージを仮想マシンにアタッチする.
REMOTE$ virsh attach-disk ubuntu16 /dev/sdb1 vdc --live
/dev/sda1の中身をddで外部ストレージにコピーする(!)
NEW$ sudo dd if=/dev/sda1 of=/dev/sdb1
NEWをシャットダウン.
ファイルシステムを直す.
NEWはもともと8GBのディスクに作られていたのでこのままではおかしなことになる. そこでfsckとresizeでファイルシステムを修正する.
REMOTE$ sudo e2fsck -f /dev/sdb1 REMOTE$ sudo resize2fs /dev/sdb2
GRUBをアップデート
新たに作成したOSをGRUBに登録する.
REMOTE$ sudo grub-mkdevicemap REMOTE$ sudo update-grub
リブート
NEWを起動するようにgrub-rebootを使い調整する. 表示方法は前の記事を参照のこと.
その後rebootし,無事起動してくれることを祈る.
Ubuntuカーネルビルド手順
まとめ
Ubuntu Bionic(つまりUbuntu 18系の別名)をビルドする方法を記す. 基本的に Kernel/Compile - Community Help Wiki から多大に情報を得ているが,いくつかコメントを書いた.
なぜUbuntu用カーネルをビルドするのか
もちろんオリジナルlinuxカーネルをそのままビルドしてインストールしても一応使える. Ubuntu用カーネルはオリジナルのlinuxカーネルに多少の変更がしてあるらしい.
したがって,オリジナルのlinuxカーネルをビルドしてそのままインストールした場合,
- グラフィックの様子がおかしい
- ネットワークのバーチャルブリッジ(virbr0)とかが設定されない
などの不都合が起きる(起きた). その結果として仮想マシンが正常に起動しないなどのトラブルが発生する.
ビルド手順
ソースコードダウンロード
$ git clone git://kernel.ubuntu.com/ubuntu/ubuntu-bionic.git
いくつかコメント.
- 上記URLの見つけ方はこれという決まった手順がない.
- 自分の場合はubuntu-trustyのURLを見つけたのでこれをbionicに置き換えてみた.
- 数十kB/sしかバンド幅がないのですごく時間がかかる.
apt source
でやる方法もあるらしいがうまくいかずに時間を溶かしたので最初はこちらを推奨.
ビルド
$ cd ubuntu-bionic $ git tag $ git checkout Ubuntu-4.15.0-hoge-fuga $ fakeroot debian/rules clean $ AUTOBUILD=1 fakeroot debian/rules binary-generic
- 普通は.configファイルをコピーしたり,
make oldconfig
を走らせたりするが不要.binary-debs
に応じて.configファイルが生成されるらしい.- したがって
binary-FLAVOUR
のように他のものを指定することが可能.
-j
オプションでビルドスレッド数を指定する必要もない.- 自動で物理コア数分のスレッドが立ち上がる.
- 上記サイトだと
binary-debs
を指定しているがやめたほうがいい.- generic, lowlatency, cloud, serverその他すべてのフレーバーがビルドされてしまい,時間と空間を取られる.
binary-generic
で明示的にフレーバーを指定する.- これでも物理6コアで20分かかる.
以上の操作でdebファイルが複数生成されているはずである.
$ ls ../linux-*deb ../linux-cloud-tools-4.15.0-23-generic_4.15.0-23.25_amd64.deb ../linux-headers-4.15.0-23-generic_4.15.0-23.25_amd64.deb ../linux-image-unsigned-4.15.0-23-generic_4.15.0-23.25_amd64.deb ../linux-modules-4.15.0-23-generic_4.15.0-23.25_amd64.deb ../linux-modules-extra-4.15.0-23-generic_4.15.0-23.25_amd64.deb ../linux-tools-4.15.0-23-generic_4.15.0-23.25_amd64.deb
インストール
これをインストールすれば完了である.
$ sudo apt install linux-headers-4.15.0-23 $ sudo dpkg -i linux-headers-4.15.0-23-generic_4.15.0-23.25_amd64.deb $ sudo dpkg -i ../linux-modules-4.15.0-23-generic_4.15.0-23.25_amd64.deb $ sudo dpkg -i ../linux-image-unsigned-4.15.0-23-generic_4.15.0-23.25_amd64.deb $ sudo dpkg -i linux-modules-extra-4.15.0-23-generic_4.15.0-23.25_amd64.deb
- 依存関係解消のために上の順序でインストールする必要がある.
- とくに最初の
apt
に注意.
- とくに最初の
アンインストール
なおアンインストールは以下のようにする.
$ sudo dpkg -r linux-image-unsigned-4.15.0-23-generic
GRUBで次回起動カーネルを選択
次回どのカーネルを用いて起動するのかを,rebootする前に指定する. もちろんマシンが手元にあれば手で選ぶこともできるけど,これだとリモートからでもいける.
インストールされているカーネルのリストを取得
まず何がインストールされているか調べる. 汚いawkワンライナー.
awk -F\' -v l=-1 -v ll=-1 \ '/menuentry |submenu / { if ($1=="menuentry ") {l+=1; print l "\t" $2} else if ($1=="submenu ") {l+=1; ll=-1; print l "\t" $2} else {ll+=1; print "\t" l ">" ll "\t" $2} }' \ /boot/grub/grub.cfg
なお,以上のコマンドを冒頭にシバン!#/bin/sh
を付けて,/usr/sbinにgrub-listとでも名うっておいておくと楽.
出力例.
0 Ubuntu 1 Advanced options for Ubuntu 1>0 Ubuntu, with Linux 4.15.0-29-generic 1>1 Ubuntu, with Linux 4.15.0-29-generic (recovery mode) 1>2 Ubuntu, with Linux 4.15.0-23-generic 1>3 Ubuntu, with Linux 4.15.0-23-generic (recovery mode) 2 Memory test (memtest86+) 3 Memory test (memtest86+, serial console 115200) 4 Ubuntu 16.04.5 LTS (16.04) (on /dev/sdb2) 5 Advanced options for Ubuntu 16.04.5 LTS (16.04) (on /dev/sdb2) 5>0 Ubuntu (on /dev/sdb2) 5>1 Ubuntu, with Linux 4.4.0-134-generic (on /dev/sdb2) 5>2 Ubuntu, with Linux 4.4.0-134-generic (recovery mode) (on /dev/sdb2)
次回起動カーネルの指定
major番号のみ,もしくは>でminor番号を追加して指定する.エスケープに注意.
例えば上の例で Ubuntu, with Linux 4.15.0-23-generic を指定したければ '1>2' とする.
$ sudo grub-reboot '1>2'
他のプログラムの標準出力にしたがって動くシェルスクリプト
要約
他のプログラムにパイプで繋ぐことで,そのプログラムの標準出力を受け取り,出力にしたがって動くシェルスクリプトの作成方法.
要件
今回はパフォーマンス測定のためのツールとして作成した.
ここでは,プログラム中のある点での /proc/meminfo
を知りたいとしよう.
このとき,プログラムを改変して,fork等呼び出せばできるがあまりにめんどくさい.
よってここで決められた文字列(たとえば"meminfo_record")を出力することで,これを記録するような別のスクリプトを動作させることを考える.
このとき,記録用のシェルスクリプト自体に時間を取られないことが肝要である.
まとめると以下.
- パイプで起動(e.g.
$ target_proc | measure.sh
) - 入力は基本teeみたいに受け流し.ただし特定入力(e.g.
"meminfo_record"
)については別コマンド実行. - ポーリングではなく,イベント駆動
答え
#!/bin/bash while read line do echo "$line" if [ "$line" = "meminfo_record" ]; then break fi done cat /proc/meminfo > meminfo.log
ハマった落とし穴
whileの書き方によって無限ポーリングしてハマる.
while : do read line echo "$line" if [ "$line" = "meminfo_record" ]; then break fi done
バックグラウンドで測定開始,後に終了させる
今回はmeminfo一発で終わりだが,ここでパフォーマンス測定プロセスを開始し,後にそれを終了させたいような場合を考える. このとき,
- バックグラウンド実行
- PID取得
- シグナル送信
の3つのテクニックが鍵となる.
バックグラウンド実行
some_command &
PID取得
some_command & pid=$!
シグナル送信
ここではC-cみたいなの.
kill -INT $pid
Python3の正規表現を使ってランレングス符号化
正規表現についてちょっと学んだので「個人的メモ」.
やったのは正規表現の
- 後方参照
- 連続マッチ
かな.
結局のところ,次々マッチさせたいならfinditerを使え,という結論(牛刀で切ります).
コツは()で繰り返し後方参照したいな,と思う部分をそのままfinditerにぶち込むこと. それをgroup()メソッドで取り出すこと.
import re def compress(s): ans = '' m = re.finditer(r'(.)\1*', s) for i in m: seq = i.group() ans += str(len(seq)) ans += seq[0] return ans def decompress(s): m = re.finditer(r'\d+|[a-zA-Z]+', s) n_repeat = None ans = '' for i in m: if n_repeat is None: n_repeat = int(i.group()) else: ans += i.group() * n_repeat n_repeat = None return ans
このとき,
>>> s = 'AAABBCDEFFFFF' >>> s = compress(s) >>> print(s) 3A2B1C1D1E5F >>> s = decompress(s) >>> print(s) AAABBCDEFFFFF
になる.
「ブログはじめました」
「はじめまして.ろっきーと申します.ブログはじめました.温かく見守ってください.」