docker phusion/baseimageを起動してsshする


# Goal

* dockerコンテナをssh付きで起動する
* dockerコンテナにsshできるようにする
* まずは開発環境で上記を実現する（この記事の鍵設定のまま公開サーバでセットアップすると超危険です）

# はじめに

dockerは1コンテナ1プロセスが基本だが、supervisorなどのプロセスコントロールシステムを使えば複数プロセス起動させることもできる. 以下の記事では、1コンテナ1プロセスの制約は規模の小さいシステムではけっこう厳しいことを指摘している. かわりにロールベースでコンテナ起動させることを提案している.
http://postd.cc/docker-misconceptions/
> * 誤解その2：Dockerコンテナごとに1つのプロセスだけを持たせる
> * ロールに基づいたDockerイメージを使用する

phusion社はロールベースのコンテナ管理に適したベースイメージを提供している.
ubuntuベースにはなくてphusion/baseimageにあるものは以下リンクに一覧されている.
https://github.com/phusion/baseimage-docker#whats_inside_overview
ssh, cronなどが積まれていて、プロセスコントロールとしてrunitが導入されている.

# phusion/baseimageでsshできるまでの手順

1. phusion/baseimageを落としてくる
	* デフォルトではsshdはインストールされているが、起動されない
* baseimageを元にsshd有効の新規イメージを作成する
* ローカルPCにsshログイン用の秘密鍵を配置する
* sshd有効新規イメージを指定してdocker containerを起動する
	* 起動コマンドで先ほど配置した秘密鍵と対になるrootユーザの公開鍵を配置する
	* （Windows/Macでdocker起動している場合?）docker machineとdocker containerのポートフォワードを指定する
* 秘密鍵を指定してsshログイン

![スクリーンショット 2015-11-01 19.04.42.png](https://qiita-image-store.s3.amazonaws.com/0/36978/9d3476f3-4173-edb7-41de-c7c00535b81c.png "スクリーンショット 2015-11-01 19.04.42.png")

## (1) phusion/baseimageを落としてくる

```bash
## 
## docker runコマンドでコンテナ起動する
## localにないイメージはdocker hubからdownloadしてきて起動する
## 
docker run phusion/baseimage hostname
  # Unable to find image 'phusion/baseimage:latest' locally
  # latest: Pulling from phusion/baseimage
  # Status: Downloaded newer image for phusion/baseimage:latest
  # 4028824b96c3

## 
## localにもってるimageの一覧を確認
## phusion/baseimageが仲間になった
## 
docker images
  # phusion/baseimage   latest              e9f50c1887ea        3 months ago        237.7 MB
```

## (2) baseimageを元にsshd有効の新規イメージを作成する

前述の通り、デフォルトでbaseimageはsshがインストールされているが起動しないようになっている.
有効にするためにオリジナルのDockerfileを作成し、sshd有効バージョンのイメージを作成する.
Dockerfileの参考は以下.
https://github.com/phusion/baseimage-docker#enabling_ssh

```
## 
## 適当なdir作成して直下にDockerfileを配置する
## 
mkdir docker-trial
cd docker-trial
vi Dockerfile
```

```Dockerfile
FROM phusion/baseimage:latest

RUN rm -f /etc/service/sshd/down

# Regenerate SSH host keys. baseimage-docker does not contain any, so you
# have to do that yourself. You may also comment out this instruction; the
# init system will auto-generate one during boot.
RUN /etc/my_init.d/00_regen_ssh_host_keys.sh
```

```bash
## 
## docker buildコマンドで新規イメージ名とビルドするディレクトリパスを指定
## baseimage_sshという名前で、カレントディレクトリをビルドする
## baseimage_sshがdocker image仲間になる
## 
docker build -t baseimage_ssh .
  # baseimage_ssh   latest              ba085bb0e0c0        About an hour ago   240.5 MB

docker images
  # REPOSITORY           TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
  # baseimage_with_ssh   latest              ba085bb0e0c0        19 hours ago        240.5 MB
  # phusion/baseimage    latest              e9f50c1887ea        3 months ago        237.7 MB
```

## (3) ローカルPCにsshログイン用の秘密鍵を配置する

https://github.com/phusion/baseimage-docker
にデフォルトの秘密鍵がコミットされているのでそれを探してdownloadしてくる.
2015.11現在は以下手順のcurlで取得できる.
もちろんこのセットを公開サーバで使うと第三者がログインし放題になるので注意.

```bash
cd docker-trial

curl -o insecure_key -fSL https://github.com/phusion/baseimage-docker/raw/master/image/services/sshd/keys/insecure_key
chmod 600 insecure_key
```

## (4) sshd有効新規イメージを指定してdocker containerを起動する

先ほどビルドしたイメージbaseimage_sshを起動する.

### 鍵を有効にして起動

sshdは起動するようになったが、`/sbin/my_init --enable-insecure-key`を実行しないと"鍵"が有効にならない.

```bash
docker run baseimage_ssh /sbin/my_init --enable-insecure-key
```

↑のコマンドは処理戻ってこないが、`docker run`に`-d`を指定するとデーモン起動できる.
`/sbin/my_init --enable-insecure-key`を実行すると、root@(docker container)の`~/.ssh/authorized_keys`に公開鍵が配置される.
これが前述curlでdownloadしておいた秘密鍵と対になる.

### port forwardを有効にして起動

Windows/Macにdockerコンテナを直接起動できないので、docker-machineが各コンテナへのプロキシ用vmとしてホストになる. Windows/Macはあくまでsshクライアントで、docker-machineがサーバとなりその中にdocker containerが起動すると考えるとよさそう（mac/docker-machine/docker containerの関係は一番上の図を参考）.
(boot2dockerというコマンドは非推奨らしく、2015.11現在はdocker-machineコマンドを使う. https://docs.docker.com/installation/mac/)

自分の環境ではvirtualbox環境でdocker-machineが起動されている.

```bash
docker-machine ls
  # default   *        virtualbox   Running   tcp://192.168.99.100:2376
```

dockerコンテナはこのdocker-machine上に起動されるのでsshさせるためにはport forwardが必要.
（要確認:port forwardはdocker-machineが存在するときのみ必要なのか？複数コンテナ起動させることを考えるとlinux上で動かすときもsshさせるためにはport forward必須な気もする.）

```bash
docker run -p 2222:22 baseimage_with_ssh /sbin/my_init --enable-insecure-key
```

`docker run`の`-p`オプションでcontainer:22をhost:2222にbindする.

## (5) 秘密鍵を指定してsshログイン

一番上図に記載したように、Windows/Mac環境ではdocker-machineがdocker containerのホストとなる.
docker containerのip addressは`docker inspect (コンテナID)`で確認できるが、このipはdocker machineからしかアクセスできないためこのipを使ってsshログインすることはできない（要確認:たぶんlinux環境ではできる）.
前述の手順でport forward設定つきでコンテナ起動しているので、フォワード元のアドレス:ポートへ向かってsshリクエストする.

```bash
## 
## 現在起動しているコンテナを一覧する
## 
docker ps
  # CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                  NAMES
  # fbdf5a494392        baseimage_ssh   "/sbin/my_init --enab"   4 hours ago         Up 4 hours          0.0.0.0:2222->22/tcp   sick_stallman

## 
## docker ps結果で確認できるcontainer idを使って、
## baseimage_sshの22番にセットされているport mappingを確認する
## 
docker port fbdf5a494392 22
  # 2222

## 
## 再度docker-machineのアドレスを確認
## 
docker-machine ls
  # NAME      ACTIVE   DRIVER       STATE     URL                         SWARM
  # default   *        virtualbox   Running   tcp://192.168.99.100:2376
```

```bash
cd docker-trial
ssh -i insecure_key root@192.168.99.100 -p 2222
```

`-i`に前述の手順でdownloadした秘密鍵のパスを指定する.

# Debug

```bash
docker run baseimage_ssh --debug
```

`--debug`オプションでデバッグを出力できる. `docker run`の結果がいつまで経っても終わらない場合などどこで失敗してるかかなり参考になる.

```bash
ssh root@(docker container) -i insecure_key -vvv
```

sshクライアントで`-vvv`付きで実行すると、デバッグ情報を出力できる.
そもそもtcpリクエストがコンテナ:22に到達していないのか、鍵が間違っているのか、などを切り分けることができる.

```bash
docker run baseimage_ssh netstat -an | grep "LISTEN "
```

baseimage_sshを起動して、22番ポートがlistenされているかなどを確認できる.

```bash
docker run -t -i baseimage_ssh bash -l
  # -i: 標準入力
  # -t: 擬似ターミナル
  # Ctrl + P + Qでデタッチする（bg起動状態になる）
  # exitで終了

# または
docker exec (container id) bash -l
```

らちがあかないときは、terminalに直接入って調査したほうが速い.

```bash
docker-machine ssh default
```

`docker-machine ls`の結果でわかるdocker-machine名(default)を指定するとdocker-machineにログインできる.
docker-machineからdocker containerがどう見えているか確認することで調査の役に立つかも

```bash
docker ps
docker inspect (container id)
```

現在起動しているdocker container一覧.
container idを指定してコンテナの詳細情報を表示する.


# References

* https://github.com/phusion/baseimage-docker#enabling_ssh
* https://docs.docker.com/mac/step_four/