Docker



Sitemap | Profile | タグ一覧
最近の更新
ドライランのありがたみを改めて知る
2024/04/04
伊豆半島
2024/03/31
お出かけチェックリスト
2024/03/29
Ruby
2024/03/27
Kubernetes
2024/03/22
音楽データをDisplayAudioで聞く
2024/03/09
Redmine
2024/02/05
git
2024/02/02
経済
2024/01/08
どうする家康
2023/12/17
MX-Linux
2023/11/06
國體関連学-休学のご連絡
2023/08/13
Debian
2023/08/02
CentOS
2023/06/13
Dell-XPS13
2023/05/23
ベルト
2023/05/18
SourceForge
2023/04/17
確定申告
2023/02/19
さらば「まぐまぐ」
2023/01/09
風猷縄学
2022/11/23


Docker なるものを使ってみる。

Linux デスクトップを使用している僕としては原理的に vmware や virtualbox より良さげ。

[-] 1. 概要

  1. chroot(8) の発展形。 つまり古くて新しいアプローチ。 vmware などの CPU + memory の仮想化とは根本的に発想が異なる。
  2. chroot なので原理的にホストOS は Linux 限定。僕は Ubuntu ユーザなので 問題ないな。
    1. しかし、Linux OS が後方互換性に注意深く発展してないと、 新しいLinux(Ubuntu16.04など)ホストの上で古いLinux(Centos6など)は 動かないわけで、Linux OS のサポートがあっての Docker なわけだ。
    2. もう1つ、Linux が cgroup という機能をサポートしてないと Docker のようなコンテナは動作しないので、ここでも改めて Linux kernel の優秀さを認識せざるを得ない。

https://fa-works.com/blog/visualizing-docker-containers-and-images の図が 分かりやすいのだけど、僕なりにまとめたのがこちら:

[-] 1.1. サンプル

  • いきなり実行
    • CentOS7
      $ docker run centos:7 cat /etc/centos-release
      CentOS Linux release 7.4.1708 (Core)
    • ubuntu 16.04
      $ docker run ubuntu:16.04 cat /etc/lsb-release
      DISTRIB_ID=Ubuntu
      DISTRIB_RELEASE=16.04
      ...
    • 補足: "docker run イメージ コマンド" でいきなり指定したイメージ (≒ OS)にてコマンドを実行できる。イメージが手元にない場合はダウンロードまで 自動的に行ってくれる。次回実行からは(当然ながら) 一度ダウンロードされたものが使用される。

[-] 1.2. run != create + start

上の図では run = create + start と書いたけど、厳密には違うようだ。

例えば、 docker run -d オプションは create にも start にもない。 ここら辺の細かい動作は僕はまだよく分かってない。

参考: https://stackoverflow.com/questions/45771746/docker-run-vs-createstart-why-are-created-containers-different

[-] 2. Tips

[-] 2.1. firewalld を入れると外部に繋がらなくなる

[-] 2.1.1. 現象

firewalld を docker container に入れるとしばらくして外につながらなくなる:

$ wget http://www.yahoo.co.jp
...
wget: unable to resolve host address ‘www.yahoo.co.jp’

[-] 2.1.2. 原因

不明(2019/07 時点)

[-] 2.1.3. 応急対応

取り敢えず コンテナ内の /etc/resolv.conf に

nameserver 8.8.8.8

を1行目に追加することで対応。 google 謹製 DNS とのこと。

[-] 2.2. コンテナ間通信

[-] 2.2.1. --link オプションでつなげる

これはもう非推奨の模様

[-] 2.2.2. docker compose で ports 指定

[-] 2.2.3. network をシェア

これが僕の場合はいいかも

127.0.0.1:13306 を 172.29.0.2:3306 につなげたいのだけど、その方法として

  • ssh portforward
    $ sudo systemctl start sshd
    $ ssh -N -L 13306:172.29.0.2:3306 localhost
  • firewalld の場合
    $ sudo firewall-cmd --zone=external --add-forward-port=port=13306:proto=tcp:toaddr=172.29.0.2:3306

[-] 2.3. 別ネットワークの構築と通信

  • 'docker network create' で別ネットワークを構築可能。 例えば 172.29.0.0/16:
    $ docker network create --subnet 172.29.0.0/16 my-fixed-ip
  • そのネットワーク上にコンテナも構築可能(ここでは A とする)。
  • その場合、元のネットワーク 'bridge' との通信には下記コマンドが必要:
    $ docker network connect bridge A

[-] 2.3.1. 背景

サーバ用途に固定IPを付与したかったので別ネットワーク 'my-fixed-ip' 172.29.0.0/16 を作ったけど、その中のコンテナ A は元のネットワーク 'bridge' と デフォルトでは通信できなかったので、 上記コマンドが必要だった次第。

[-] 2.4. add-host

新しい docker (少なくとも v1.13.1 以上では対応されている) では、 docker run に --add-host オプションを使って /etc/hosts にエントリーを追加できる。

[-] 2.5. clean uninstall

$ sudo apt purge docker.io
$ sudo rm -rf /var/lib/docker

[-] 2.6. port を追加

一旦 commit して image から作りなおさないといけないようだ:

$ docker stop [CONTAINER]
$ docker rename [CONTAINER] [CONTAINER-bkp]
$ docker commit [CONTAINER-bkp] [REPO]:TAG]
$ docker run ... -p NEW_PORT:NEW_PORT ...

[-] 2.7. sshd を Docker環境内で走らせる

[-] 2.7.1. 背景

  1. 某アプリで ssh 経由アクセスが必要。 (具体的には itamae ssh。itamae docker がなぜか Docker API timeout したり 大量の無名コンテナを作成したりと、どうも使い方がよく分からないので、 itamae ssh して docker コンテナにアクセスしたいのだった)
  2. 他方、動作環境の OS を隔離するために Docker を使用したい。

…と言う2つのニーズを満たすために、sshd を Docker で走らせる必要があった。

[-] 2.7.1.1. 余談1

「Docker にて sshd を走らせるのは良くない」と言う記事があるけれど ( http://postd.cc/docker-ssh-considered-evil/ ) 今回は「sshd 必要環境」を用意する必要があるので、この論点の対象には 入らないかな。

[-] 2.7.1.2. 余談2

上記記事では代替案として nsenter なるものを紹介しているけれど、 いまだと docker exec ... bash で ok。 ココらへんは本家記事でも議論されていた

[-] 2.7.2. 方法

凡例:

[APP-USER]:コンテナユーザ。例: my_app
[CONTAINER-DIR]:コンテナディレクトリ。 -v でホスト側に接続。例: /home/MY/docker/。⇔ [HOST-DIR]
[DPORT]:docker port で得るポート番号。例: 32768
h$:ホストプロンプト。⇔ c$
[HOST-DIR]:ホスト側ディレクトリ。例: /home/MY/docker/。⇔ [CONTAINER-DIR]
c#:コンテナプロンプト(root)
c$:コンテナプロンプト。⇔ h$
[MY-APP-HOST]:コンテナホスト
[MY-APP-WITH-SSHD-CONTAINER]:コンテナ名
[MY-APP-WITH-SSHD-IMAGE]:イメージ名
[UID]:[APP-USER] uid。例: 1000
  1. Dockerfile 作成
    FROM    centos:7
    RUN     yum install -y openssh-server tar which wget
    RUN     yum install -y iproute openssh-clients  # CentOS7 only
    RUN     mkdir -p /etc/chef/ohai/plugins         # itamae の bug 回避。itamae 用途以外では不要
  2. イメージ作成(build)
    h$ docker build -t [MY-APP-WITH-SSHD-IMAGE] - <Dockerfile
  3. コンテナ作成
    h$ docker run -P -d \
        -v          [HOST-DIR]:[CONTAINER-DIR] \
        --hostname  [MY-APP-HOST] \
        --name      [MY-APP-WITH-SSHD-CONTAINER] \
        --privileged \
        [MY-APP-WITH-SSHD-IMAGE] \
        /sbin/init
    • --privileged 過剰かも。--cap-add SYS_ADMIN が動作すればそれに
    • /sbin/init は、コンテナを daemon 起動させる centos7 での方法
  4. sshd 実行
    h$ docker exec -d [MY-APP-WITH-SSHD-CONTAINER] /usr/sbin/sshd -D
  5. ssh できることを確認
    h$ docker port [MY-APP-WITH-SSHD-CONTAINER]
    22/tcp -> 0.0.0.0:[DPORT]               # コンテナ側ポート 22 に対応するホスト側ポート [DPORT] を知る
    h$ ssh -p [DPORT] root@localhost

以降は、セキュリティ強化のために行っておくこと:

  1. Rootログイン禁止、Password ログインを禁止
    c$ sudo vi /etc/ssh/sshd_config
    ...
    PermitRootLogin no
    ...
    PasswordAuthentication no
    ...
    下記を改変:
    • ssh Rootログインを許可しているが、これは行わない
    • sshd は起動しない。必要に応じて起動するだけ。

一度構築したコンテナで、以降 sshd が不要であればもう起動する必要はない

[-] 2.7.3. 旧方法

※ この節で書いた方法は、 https://docs.docker.com/engine/examples/running_ssh_service/ を参考に しているけど、僕の用途では過剰な設定なので、もはや不要。

  1. Dockerfile 作成
    FROM    centos:6
    RUN     yum install -y openssh-server tar which wget cronie
    RUN     yum install -y openssh-clients    # scp サーバ側動作に必要
    RUN     /etc/init.d/sshd start            # key の生成に必要
    RUN     sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
    ENV     NOTVISIBLE "in users profile"
    RUN     echo "export VISIBLE=now" >> /etc/profile
    EXPOSE  22
    CMD     ["/usr/sbin/sshd", "-D"]
    参考: https://docs.docker.com/engine/examples/running_ssh_service/
  2. イメージ作成(build)
    h$ docker build -t [MY-APP-WITH-SSHD-IMAGE]  - <Dockerfile
    ※ "Downloading Packages" で5分ほど反応がないが、待つ。
  3. コンテナ作成
    h$ docker run -P -d \
        -v          [HOST-DIR]:[CONTAINER-DIR] \
        --hostname  [MY-APP-HOST] \
        --name      [MY-APP-WITH-SSHD-CONTAINER] \
        [MY-APP-WITH-SSHD-IMAGE]
    • デバッグ方法
      • exit(-1)ですぐ終了する場合、 docker run のコマンドを "tail -f /dev/null" などに置き換えて docker exec -it bash で入ってコマンドラインから
        # /usr/sbin/sshd -D -d
        してみる。
  4. コンテナ内にてアプリ用ユーザ [APP-USER](uid=ホストUID)を作成
    h$ docker exec -it [MY-APP-WITH-SSHD-CONTAINER] bash
    c# adduser -u [UID] [APP-USER]
    c# yum install passwd
    c# passwd [APP-USER]
  5. sshd 実行
    h$ docker exec -d [MY-APP-WITH-SSHD-CONTAINER] /usr/sbin/sshd -D
  6. ssh できることを確認
    h$ docker port [MY-APP-WITH-SSHD-CONTAINER]
    22/tcp -> 0.0.0.0:[DPORT]
    h$ ssh -p [DPORT] [APP-USER]@localhost
    以下、docker 内で:
    c$ mkdir .ssh/
    c$ chmod go-rwx .ssh
  7. key-pair をセット
    h$ scp -P [DPORT] ~/.ssh/id_rsa.pub [APP-USER]@localhost:~/.ssh/authorized_keys
    [APP-USER]@localhost's password: *********
    以降、key-pair でログイン可能
  8. Rootログイン禁止、Password ログインを禁止
    c$ sudo vi /etc/ssh/sshd_config
    ...
    PermitRootLogin no
    ...
    PasswordAuthentication no
    ...
    下記を改変:
    • ssh Rootログインを許可しているが、これは行わない
    • sshd は起動しない。必要に応じて起動するだけ。
  9. term を実行
    h$ docker exec -it [MY-APP-WITH-SSHD-CONTAINER] bash -c 'su - [APP-USER']
    注: docker exec の -u(--user) オプションは、[APP-USER] に docker コンテナに root 権限を与えるようで、/etc/sudoers なども見放題となってしまう。通常のユーザ権限の範囲で実行するには 上にように su する必要があるようだ。

[-] 2.7.4. context

分かっていなかったのでメモ。build するとき、何も考えずに

$ docker build -t [tag] .       # 僕の場合では間違っていた方法

としていたのだけど、この '.' はイメージをを作る際の起点となるようで。 . 以下全データが docker daemon に送られるとのこと。

僕は . 以下に開発リポジトリなど持っていたところ、数G のイメージが 作られてしまった…。はい、アホです。

僕の用途では必要ないので、そういう時は

$ docker build -t [tag] - <Dockerfile

とするのが正解のようだ。

[-] 2.8. よく使うコマンド

  • docker ps
  • docker ps -a

[-] 2.8.1. たまに使うコマンド

コミット:docker commit
イメージ一覧:docker images

[-] 2.8.2. 現コンテナを image に保存し、新しく run(create & start)

  1. image に保存
    $ docker stop myproject-dev
    $ docker rename myproject-dev myproject-dev-before-ubuntu-16.04
    $ docker commit myproject-dev-before-ubuntu-16.04 リポジトリ名:タグ名
  2. create
    $ docker create ..
  3. start
    $ docker start myproject-dev

[-] 2.9. ネットワークが動作しない (2016/03/09)

  1. 原因
    • なぜかコンテナ内の /etc/resolv.conf が root 以外読めないように:
      -rw------- 1 root root 146  3月  9 09:59 2016 /etc/resolv.conf
  2. 応急対策
    • 取り急ぎ sudo chmod a+r /etc/resolv.conf で直った。

[-] 3. 環境

ホスト:MX Linux 21 (Debian 11(bullseye))
コンテナ:CentOS 6.7

[-] 4. インストール

  1. install Docker
    $ sudo apt install docker.io
  2. sudo 無しで実行できるよう、ユーザを docker グループに追加
    $ sudo adduser [USER] docker
  3. ユーザを docker グループに所属させるために logout & login
  4. apparmor のインストールが必要な模様
    $ sudo apt install apparmor
    これがないと docker build 時に下記エラーに:
    AppArmor enabled on system but the docker-default profile could not be loaded: running `apparmor_parser apparmor_parser --version` failed with output:
    error: exec: "apparmor_parser": executable file not found in $PATH
  5. CentOS 6 をダウンロード
    $ sudo docker pull centos:6
  6. 実行
    $ sudo docker run -it centos:6
  7. ユーザ追加。uid をホストと合わせておく
    # adduser -u [NNNN] [MyName]
    # su - [MyName]
  8. ファイル共有
    $ mkdir -p SOME/DIRECTORY
  9. 一旦コミット
    $ sudo docker commit [commit-id] [name]
    例:
    $ sudo docker commit 2fb761c8c516 add-MyName
  10. ホストOS のファイルを共有
    $ sudo docker run -it -v [HOST-DIR]:[GUEST-DIR] [name]
  11. ネットワーク周り
    1. docker
    2. CentOS ユーティリティ類のインストール

[-] 5. 性能比較

VirtualBox + 同ゲスト(CentOS 6.7) + ホストとは NFS 共有、 という環境と比較する。

どちらも Rails アプリ(DB = MySQL)を走らせ、 rake test:performance で計る。

結論から言うと、Dockerの方が倍近く速かった ( ・∀・)イイ!!

速すぎなので、逆に VirtualBox の NFS が今まで悪い環境だったのかと 思ったりも…。

[-] 5.1. 環境詳細

項目 Docker VM
rubyソース ホストvolume上 ホストfs NFS経由
MySQLデータ ホストvolume上 ゲストfs

[-] 5.2. 後記

「速度云々」は僕の開発マシンでの話し。

他方、Dockerにまつわる誤解とベストプラクティスについて にて「『速度のためにDockerを使うべき』は誤解」とあるけれど、 この著者も冒頭で念押しされているけれど、こちらはミッションクリティカルでの話し。

両者は Docker の使用目的が全然違うので、矛盾しているわけではないと思っている。

[-] 5.3. Ubuntu 12.04 を入れてみる

  1. install
    $ docker pull ubuntu:12.04
    $ docker run ubuntu:12.04 cat /etc/lsb-release
    ...
    DISTRIB_RELEASE=12.04
    ...
    $ docker run ubuntu:12.04 apt-get update
  2. postgres install 既に古いので、postgres がそのままではインストールできない
    $ docker run -it ubuntu:12.04 bash

[-] 6. 参考文献






Generated by juli 2.3.2