Dockerが起動しなかったときにやったこと

今日、会社で使っているDockerが、サーバー再起動後からサービスが起動しないことがありました。
その際に実施した対処方法です。

状況

$ sudo service docker start

としても、サービスが起動せず、下記のようなエラーがログに出力されてました。

$ sudo cat /var/log/upstart/docker.log

WARN[0000] /!\ DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING /!\
INFO[0000] [graphdriver] using prior storage driver "aufs"
INFO[0000] API listen on [::]:2375
INFO[0000] API listen on /var/run/docker.sock
INFO[0000] Firewalld running: false
FATA[0000] Error starting daemon: Error initializing network controller: could not delete the default bridge network: network bridge has active endpoints

ブリッジ接続用のネットワーク設定がおかしくなっているようなエラーで、サーバーをもう一度再起動しても解消せず。

対処方法

エラーログの内容でググってみたら、下記Dockerのissueでもやり取りされており、対処方法が記載されていました。

念のため mv して様子をみることに。

$ sudo mv /var/lib/docker/network/files/local-kv.db ~/

今回はこの方法で解決することができました。

ほんの少しDockerの気持ちになれた気がしました。

iptablesでstringモジュールを使う

知らなかったのだけど、iptablesのstringモジュールを使うと文字列で色々処理することができるらしいです。

例えば”/hoge.php”というアクセスを遮断したい場合。
通常Webサーバーや.htaccessなどを使うことが多いと思いますが、iptablesでも遮断することができました。

こんな感じで設定できます。

$ sudo /sbin/iptables -I INPUT -m string --algo bm --string "/hoge.php" -j DROP

保存しておきたければ、下記を実行すると良いと思います。

$ sudo /sbin/service iptables save

設定後はこんな風になります。

% sudo iptables -nL
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
DROP       all  --  0.0.0.0/0            0.0.0.0/0           STRING match "/hoge.php" ALGO name bm TO 65535

実際にこれで/hoge.phpへアクセスしたところ、タイムアウトして、接続できませんでした。
他にも使い所がありそうなので使っていきたいですね。

シェルスクリプトでリモート先にコマンドを実行する際のTips

仕事でとあるサーバーから別のサーバーにあるシェルスクリプトをsudo付きで実行したいことがあった。
そして、

$ ssh USER@hostname sudo shellscript
sudo: sudo を実行するには tty がなければいけません。すみません

見事にこのようなエラーが出て、実行ができなかった。
シェルスクリプト&sudoの超あるある案件だ。
これをググると対応方法の中に、sudoersファイルの”Defaults requiretty”をコメントアウトすると良いと書かれている。
どのサイトにもこれはセキュリティ上よくないから!と書かれているが、それをやってる。
確かにvisudoで見てみると、

#
# Disable "ssh hostname sudo <cmd>", because it will show the password in clear.
#         You have to run "ssh -t hostname sudo <cmd>".
#

と書かれている。
ここにはパスワードがクリアで表示されてしまうからダメだと書かれている。
ログインシェルを実行してttyを割当ないと、パスワードをecho offできないからダメらしい。

確かにこちらにもLinuxのシステムコールioctl()で、パスワードのechoをoffにしていることが書かれていた。

http://d.hatena.ne.jp/itotto/20120214/1329191401

なるほどという感じ。そのため、パスワードを表示させないように-tオプションで仮想的に端末を割り当てるように書かれている。

検証

失敗パターン

ssh user01@vagrant.local sudo ls -l
user01@vagrant.local's password:
sudo: sudo を実行するには tty がなければいけません。すみません

成功パターン

ssh user01@vagrant.local -t sudo ls -l
user01@vagrant.local's password:
user01@vagrant.local's password:
[sudo] password for user01:
合計 117580
drwx------ 7 user01 user01      4096  1月  3 00:39 2016 Maildir
-rw-r--r-- 1 user01 user01 117764308 11月 10 18:09 2014 archive.zip

調べている際に下記サイトを見つけたのだけど、わかりやすく書かれていてためになった。

http://language-and-engineering.hatenablog.jp/entry/20110617/p1

そして他にも色々出来そうだということ、対処方法などが見つかったのでTipsとして書いておく。

パスワードを変数に入れてシェルスクリプトで使用する

http://keens.github.io/blog/2015/06/17/shell_scriptwokakutokinikiwotsuketaikoto/

こちらのサイトに記載があったのだけど、readコマンドのオプション-sで入力文字を表示させないようにできるらしい。
これが便利そうに思った。

echo -n "Type your password: "
read -s SSHPASS

これで”Type your password:”の後にパスワードを入力させるプロンプトが出せる。
read で標準入力から SSHPASS へパスワードをセットする。
read -s にするとパスワードが表示されないので、パスワード入力用のプロンプトとして使用できる。
下記では例としてecho “パスワード”と記載しているけれど、基本的には入力させるようにした方が良いと思う。

sshpassでパスワードをワンライナーで読み込む

パスワードを標準入力でsshに渡せるようなのだけど、その際にsshpassコマンドを使用するようだ。

$ sshpass -pパスワード | ssh ユーザー@ホスト名 ls -l

sshpassについて、CentOSでepelがあれば下記でインストール可能だ。
-fでファイルから読み込むこともできるようだ。

$ sudo yum install sshpass

epelはyumの標準レポジトリで追加できる拡張パッケージなので下記でインストールできる。

$ sudo yum install epel-release

標準入力からパスワードをsudoに渡す

標準入力からsudoにもパスワードを渡すことができる。それにはsudo -Sとするとよい。

$ echo "パスワード" | ssh hoge sudo -S cat /var/log/message

複数のコマンドをリモート先で実行する(sudoが必要なパスワードを標準入力で渡す)

もっと良い書き方がありそうだけど、こんな感じでヒアドキュメントで、SSHPASSの変数にセットしたパスワードを読み込ませてリモートでsudoを実行できる。
-tだけで実行できれば問題ないのだけど、SSHした先で更にSSHさせるような場合は-ttを使用しないと怒られる。

$ ssh hoge@hogepiyo.com -tt << EOL
 echo "${SSHPASS}" | sudo -S コマンド1
 echo "${SSHPASS}" | sudo -S コマンド2
 echo "${SSHPASS}" | sudo -S コマンド3
EOL

sudoでrootのHOMEの環境変数を読み込む

sudo -H を使用すると、rootのHOMEの環境変数を読み込んでくれる。

$ ssh hoge@hogepiyo.com sudo -H mysqladmin ping

http://perezvon.hatenablog.com/entry/20091115/1258269745

注意点

但し、注意点として、これらの方法で完璧にパスワードを隠蔽できるわけではなく、sh -xとかpsとかするとパスワードが表示されてしまう。
sttyを使って、echoをoffにしたりする方法もあるようだけど、結果的には同じことで、ASKPASSプログラムを実行できるプログラムの方が望ましいらしい。
特にexpectなどが良いらしいので、不安がある場合はexpectで実行するのが良いと思う。
上記Tipsを使用する場合は、留意していただきたい。

こんな感じでなんとかオプションを駆使すれば、リモート先でsudoでコマンドを実行できるし、更にシェルスクリプトを実行することも可能だということが分かった。
また、長いことモヤモヤしていた所ではあったので、何故ダメなのかって所が分かってよかった。