dockerで SSHコンテナを 作ろう

Pocket

サマリーイメージ(summary image)

序文

はい。

最近、お仕事でdockerを使っているKaBAです。

起動が速く、メモリも喰わず、ディスクも喰わない、なかなか軽い仮想化環境ですね。

自分の手持ちのレンタルVPSでも、dockerを使った練習をしています。

しかし、このdockerコンテナ、コンテナ内部には「docker exec」にて入ることができるため、あまりSSH関連のサポートはされていません。

そこで!今回は、dockerでSSHログインできるようにする方法を解説します。

それでは、行ってみましょう!

データ永続化せずにSSHコンテナを使って見る

とりあえず、コンテナだけ立ち上げてみた

とりあえず、ホスト側OSをCentOS7で、コンテナ側もCentOS7で起動するよう、以下のシェルスクリプトを組みました。

~/work/docker/ssh-con/ssh-con-test.sh

docker run -d -it --privileged --restart=always \
  --name=ssh-con-test \
  -h ssh-con-test \
  -p 23:22 \
  -d centos:centos7 \
  /sbin/init

実行してみましょう。

# ./ssh-con.sh

次に、SSHコンテナにsshdをインストールしましょう。

[root@localhost ssh-con]# docker exec -it ssh-con-test bash
[root@ssh-con-test /]# yum install openssh-server

SSHコンテナにsshdをインストールしたら、そのコンテナをイメージ「centos7:latest」として保存します。
このようにイメージ化しないと、コンテナに後からインストールしたsshdなどのソフトウェアは、コンテナ破棄時にすべて消えてしまいます。
イメージ化して、次回からそのイメージを使用してコンテナを立ち上げるようにすると、sshdなどのイメージに含まれるソフトウェアは、コンテナ破棄後もイメージ中に存在し、インストール済みの状態でコンテナも立ち上がります。

それでは、sshdをインストールしたコンテナをイメージに変換してみます。

[root@ssh-con-test /]# exit
exit
[root@localhost ssh-con]# docker container stop ssh-con-test
ssh-con-test
[root@localhost ssh-con]# docker container commit ssh-con-test centos7:latest
sha256:4cd9aa8e3b18ef3f8afa42d92a0b4d368a0cb325cd6f08847dd3666a9aa12eac

イメージを作ったので、SSHコンテナ起動シェルスクリプトも変更しておきます。

~/work/docker/ssh-con/ssh-con-test.sh

docker run -d -it --privileged --restart=always \
  --name=ssh-con-test \
  -h ssh-con-test \
  -p 23:22 \
  -d centos7:latest \
  /sbin/init

次にsshログインしておきましょう。

ただし、その前にssh-con-testコンテナのrootパスワードを設定しておく必要があります。

~/work/docker/ssh-con/ssh-con-test.sh

[root@localhost ssh-con]# docker exec -it  ssh-con-test bash
[root@ssh-con-test /]# passwd
Changing password for user root.
New password:
Retype new password:

次に、SSHコンテナにsshでログインします。

ssh localhost -p 23
The authenticity of host '[localhost]:23 ([::1]:23)' can't be established.
ECDSA key fingerprint is SHA256:hXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXjGj84.
ECDSA key fingerprint is MD5:09:yy:yy:yy:yy:yy:yy:yy:yy:yy
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[localhost]:23' (ECDSA) to the list of known hosts.
root@localhost's password:
[root@ssh-con-test ~]#

無事SSHログインできました。

これでOK?

これでOKじゃないの?

という疑問が湧きますが、コンテナは、「データを永続化」しない限り、データを保存しません。

先ほど入力した「rootパスワード」も同様です。

試しに、SSHコンテナを削除して、もう一度SSHコンテナを起動します。

~/work/docker/ssh-con/ssh-con-test.sh

# docker container stop ssh-con-test
# docker container rm ssh-con-test
# ./ssh-con-test.sh
# ssh localhost -p 23
root@localhost's password:
Permission denied, please try again.
root@localhost's password:
Permission denied, please try again.
root@localhost's password:

ハイ!パスワード入力で失敗します。

SSHコンテナがパスワードを覚えていなかったのですね。


/etcを永続化してみる

/etc/passwdなどの単体ファイルを永続化しようとすると。。。

そのため、ユーザー名や、パスワードを保存してある/etc/passwd/etc/shadowなどを永続化してみましょう。

# mkdir ssh-con-test-etc
# cd ssh-con-test-etc/
# docker cp ssh-con-test:/etc/passwd .
# docker cp ssh-con-test:/etc/shadow .
# docker cp ssh-con-test:/etc/group .
# docker cp ssh-con-test:/etc/gshadow .
# mkdir -p /var/docker/ssh-con-test/etc/
# cp * /var/docker/ssh-con-test/etc/

しかし、/etc/passwdや/etc/shadowなどの単体ファイルを永続化しても、編集できません。
つまり、useraddなどのコマンド実行に失敗します。

まずはSSHコンテナを起動してみましょう。

~/work/docker/ssh-con/ssh-con-test.sh

docker run -d -it --privileged --restart=always \
  --name=ssh-con-test \
  -h ssh-con-test \
  -p 23:22 \
  -v /var/docker/ssh-con-test/etc/passwd:/etc/passwd \
  -v /var/docker/ssh-con-test/etc/shadow:/etc/shadow \
  -v /var/docker/ssh-con-test/etc/group:/etc/group \
  -v /var/docker/ssh-con-test/etc/gshadow:/etc/gshadow \
  -d centos7:latest \
  /sbin/init

次にuseraddを実行してみます。

[root@localhost ssh-con]# docker exec -it ssh-con-test bash
[root@ssh-con-test /]# useradd test1
useradd: failure while writing changes to /etc/passwd

このように、/etc/passwdなどのみを永続化すると、システム上不都合が起きると考えられます。

/etcフォルダごと永続化

そこで、/etcフォルダごと永続化します。

ただし、以下のように、いきなり/etcを永続化マウントすると、パーミッションの関係でうまく/etcが共有されません。

~/work/docker/ssh-con/ssh-con-test.sh

docker run -d -it --privileged --restart=always \
  --name=ssh-con-test \
  -h ssh-con-test \
  -p 23:22 \
  -v /var/docker/ssh-con-test/etc:/etc \
  -v /var/docker/ssh-con-test/home:/home \
  -d centos7:latest \
  /sbin/init

そこで、一旦、以下のようなSSHコンテナを作成し、起動します。

~/work/docker/ssh-con/ssh-con-test.sh

docker run -d -it --privileged --restart=always \
  --name=ssh-con-test \
  -h ssh-con-test \
  -p 23:22 \
  -d centos7:latest \
  /sbin/init

そして、SSHコンテナに「docker exec」でログインし/etcフォルダをパーミッション付きオプション(zcvfpのpオプション)を指定したのtar.gzファイルに保存します。

その後、/var/docker/ssh-con-testにetcを展開します。

[root@localhost ssh-con]# docker exec -it ssh-con-test bash
[root@ssh-con-test /]# tar zcvfp etc_ssh-con-test.tgz ./etc/
[root@ssh-con-test /]# mv etc_ssh-con-test.tgz /root/
[root@ssh-con-test /]# exit
[root@localhost ssh-con]# docker cp ssh-con-test:/root/etc_ssh-con-test.tgz .
[root@localhost ssh-con]# docker container stop ssh-con-test
[root@localhost ssh-con]# docker container rm ssh-con-test
[root@localhost ssh-con]# mkdir -p /var/docker/ssh-con-test
[root@localhost ssh-con]# cp etc_ssh-con-test.tgz /var/docker/ssh-con-test/
[root@localhost ssh-con]# cd /var/docker/ssh-con-test/
[root@localhost ssh-con-test]# tar zxvfp etc_ssh-con-test.tgz

ここで、以下のようなSSHコンテナ起動シェルスクリプトを書きます。

~/work/docker/ssh-con/ssh-con-test.sh

docker run -d -it --privileged --restart=always \
  --name=ssh-con-test \
  -h ssh-con-test \
  -p 23:22 \
  -v /var/docker/ssh-con-test/etc:/etc \
  -v /var/docker/ssh-con-test/home:/home \
  -d centos7:latest \
  /sbin/init

/etcと/homeを永続化していますね。

[root@localhost ssh-con]# ./ssh-con-test.sh
89b5c55a83540a077098d632bf92fa6295b001545e1dbd38c54d93c4352c9751
[root@localhost ssh-con]# docker exec -it ssh-con-test bash
[root@ssh-con-test /]# useradd test2
[root@ssh-con-test /]# passwd test2
Changing password for user test2.
New password:
BAD PASSWORD: The password is shorter than 7 characters
Retype new password:
passwd: all authentication tokens updated successfully.

ユーザーtest2を作り、パスワードを設定しました。
useraddコマンドの実行が成功していることが、前回と違いますね。
また、passwdコマンドの実行にも成功しています。
両者とも、/etc/passwd/etc/shadowを変更するコマンドです。

試しにホスト側からssh接続してみましょう。

[root@ssh-con-test /]# exit
exit
[root@localhost .ssh]# ssh test2@localhost -p 23
The authenticity of host '[localhost]:23 ([::1]:23)' can't be established.
ECDSA key fingerprint is SHA256:EOt2HJlXRWAkLlArJG9AXCx8I3FDg91LIED4YZDaGOY.
ECDSA key fingerprint is MD5:ef:dd:d8:34:5e:f8:d9:28:10:ae:a2:35:b6:a4:8b:00.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[localhost]:23' (ECDSA) to the list of known hosts.
test2@localhost's password:
[test2@ssh-con-test ~]$

まずは、sshログインに成功しました。

SSHコンテナ再起動後も、sshログインできるでしょうか?
ログイン情報の永続化をテストしてみましょう。

[root@localhost ssh-con]# docker stop ssh-con-test
ssh-con-test
 [root@localhost ssh-con]# docker container rm ssh-con-test
ssh-con-test
[root@localhost ssh-con]# ./ssh-con-test.sh
7b579af8767a931359e74fca09ea41d9053067b90c11f0c2ab7925fcee78fd2c
[root@localhost ssh-con]# ssh test2@localhost -p 23
test2@localhost's password:
[test2@ssh-con-test ~]$

無事、SSHコンテナ再起動後も、sshログインできているようです。

まとめ

皆さん、大変お疲れ様でした。

ここまで読んで頂いて誠にありがとうございました。

今日の学びを以下にまとめます。

  • イメージにsshdが入っていない場合は、いったんコンテナに入りyumでsshdをインストールする。
    その後、コンテナをstopし、commitすることでsshdを含む新しいイメージを作成する。
  • /etcを永続化してないSSHコンテナに、ユーザー登録やパスワード登録しても、SSHコンテナ再起動後は、ユーザー名やパスワードの情報が失われていてsshログインできない。
  • /etc/passwdや、/etc/shadowなどの単体のファイルを永続化しても、うまくユーザー名やパスワードを設定できない。システム上の問題と考えられる。
  • /etcを、tarで「パーミッション情報を含む」アーカイブにする(tar zcvfp)し、データ永続化フォルダにパーミッション情報を含んだまま展開する(tar zxvfp)と、/etcを正常に永続化できる。
    ただし、SSHコンテナのOSとホスト側OSの種類が同じでない場合は、例えばapacheなどのユーザーIDに違いが出て、不具合が出るかも知れない。
  • /etcを永続化すれば、SSHコンテナを削除し再度起動しても、sshログインできるようになる
    また、この際、/homeも永続化しておくこと

SSHコンテナのポートフォワード先を、8022番などにしておくと、ホスト側SSHの22番と被らずに、SSHコンテナに8022番などでログインできるため、何かと便利です。

それではー またー (^_^)/