- lifeisegg
- May 22, 2019
- Tags
なぜあえてDocker(コンテナ)を使わなければならいか?
サーバーの限界を超えて、コンテナを使用する理由
はじめ:なぜDockerを使わなければならないか?
コンテナは、アプリケーションを環境にかかわらず実行する技術です。一例として、GitLabというツールをUbuntuにインストールするには、GitLab公式文書では、次のように案内しています。
sudo apt-get update sudo apt-get install -y curl openssh-server ca-certificates sudo apt-get install -y postfixあ curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.deb.sh | sudo bash sudo EXTERNAL_URL="http://gitlab.example.com" apt-get install gitlab-ee
CentOSを使用する場合のコマンドは少し異なります。
sudo yum install -y curl policycoreutils-python openssh-server sudo systemctl enable sshd sudo systemctl start sshd sudo firewall-cmd --permanent --add-service=http sudo systemctl reload firewalld sudo yum install postfix sudo systemctl enable postfix sudo systemctl start postfix curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.rpm.sh | sudo bash sudo EXTERNAL_URL="http://gitlab.example.com" yum install -y gitlab-ee
しかし、コンテナツールDockerがインストールされている場合は、どの環境でも関係なく、次のコマンドを使用してGitLabを実行することができます。
$ docker run --detach \ --hostname gitlab.example.com \ --publish 443:443 --publish 80:80 --publish 22:22 \ --name gitlab \ --restart always \ --volume /srv/gitlab/config:/etc/gitlab \ --volume /srv/gitlab/logs:/var/log/gitlab \ --volume /srv/gitlab/data:/var/opt/gitlab \ gitlab/gitlab-ce:latest
このように利便性と拡張性を持ったコンテナが長い時間が経って世界を変化させたが、まだコンテナを話すと、いくつかの質問を受けたりするが、その中で私を最も悩むことにした質問は次のとおりです。
Dockerがなくても配布/運営しているが、私たちは何も不便を感じません。 なぜDockerを書くのですか?
私もコンテナに接してしばらくその利点を実現及ばないが、ある瞬間コンテナを好きになり、コンテナ本当に良いという言葉だけであったが、この記事では、その理由を整理しようとします。その後、自然に、既存のサーバーと比べてもDockerが良い部分もある程度答えるだろうと思います。Dockerコマンドなどの「活用法」は、すでに多く知られているため、この記事では、サーバーをコードで構成して管理する方法としてDockerが持つ利点を話そうとします。
運営し作成された雪の結晶サーバー(Snowflake Servers)
サーバーの運用を長くしてみた人でも、最初に入るサーバーでは、思い通りに問題を解決することは困難である。これは、サーバーを扱う技術とは別に、各サーバーごとに操作履歴が異なるからです。同じことをする、両方のサーバーがあるとしても、Aサーバーは1ヶ月前の設定して、Bサーバーは、今まさに設定した場合、OSからコンパイラ、インストールされたパッケージに、完全に同じであることは容易でありません。そして、これらの違いが障害を起こして怯え。AサーバーはよくなるがサーバーBはなぜ死んだ?のようなこと(あるいはその逆)が行われるでしょう。このように、互いに形状が他のサーバーが存在する状況を雪サーバー(Snowflakes Server)とも呼ばれます。すべてのスノーフレークの形状が違うよう、サーバーも異なる姿というね。
AサーバーとBサーバーにImageMagickというツールをインストールすると仮定してみましょう。Aサーバーは先月にサーバーを構成し、ImageMagickをインストールし、サーバーBは今まさに構成状況だから、新しくImageMagickをインストールしました。そして、Webサービスを更新して、各サーバーに配布します。Aサーバーで障害が発生しました。このような状況では、障害発生の原因は、おおよそ次のように推測することができます。
- WebサービスでのImageMagick最新バージョンに新しく追加された機能を使用した。
- Webサービスのアップデート部分のコードにバグがある
- ImageMagickのバージョンが違う
- ImageMagickが依存しているライブラリのバージョンが違う
障害の原因を迅速に見つけるには、サーバーAをよく知っている人が必要ハルテンデ完了Aサーバーを構成していた人がチームを移動したり、退社して横にありません。Bサーバーを構成した作業者は、Aサーバーが構成され、オペレーティングされたすべてのプロセスを把握しようと努めを書くでしょう。ようサーバーBとの違いを把握することができますからね。
ここでは、両方のサーバー間の構成の時点で一ヶ月しか差がないが、いざ現場では何年チャイナ場合もあります。最初は、各サーバーの間の違いが雪つだけ小さいかもしれないが、サーバーを長く運営しているとだんだん大きくなって後には家を飲み込む巨大な雪だるまになっているでしょう。
サーバーをコードで構成して管理するさまざまな方法
このような状況を改善しようと、さまざまな方法で、サーバーのオペレーティング記録を保存してせていたします。最も通常はサーバーでどのような操作を実行するたびに、これを社内ドキュメントに記録しておくか、複数のサーバーに同時接続して、一度にコマンドを実行するtmux-xpanesのようなツールを使用することもね。
しかし、文書に書かれた通りみてもうまくいかない場合が生じて(その時は打たれ、今は間違い)、複数のサーバーを一度に操作する時も、特定のサーバーだけの問題を引き起こす場合があまたね。したがって、サーバーの動作記録をコード化する様々な試みが登場します。ベイグロントゥVagrantやシェフChef、パペットPuppet、アンサーブルAnsibleなどのツールには、すべてのサーバーの運用記録を後でも再現しようとする意図が込められています。ImageMagickをインストールするアンサーブルコードを見てみましょう。(内容を理解する必要はありません。)
# imagemagickを設置するAnsible playbook # code by https://github.com/treetips/ansible-playbook-imagemagick/blob/master/main.yml --- # ansible v2.0.0.2 - hosts: all become: no vars: - autoconf_dir_name: "autoconf-latest" - autoconf_archive_name: "{{ autoconf_dir_name }}.tar.gz" - autoconf_dl_url: "http://ftp.gnu.org/gnu/autoconf/{{ autoconf_archive_name }}" - imageMagick_dir_name: "ImageMagick-latest" - imageMagick_archive_name: "ImageMagick.tar.gz" - imageMagick_dl_url: "http://www.imagemagick.org/download/{{ imageMagick_archive_name }}" tasks: ... 略 ... - block: - name: downlaod imagemagick get_url: url={{ imageMagick_dl_url }} dest=/usr/local/src/{{ imageMagick_archive_name }} - name: unarchive imagemagick archive shell: chdir=/usr/local/src mkdir -p {{ imageMagick_dir_name }} && tar xzvf {{ imageMagick_archive_name }} -C {{ imageMagick_dir_name }} --strip-components 1 # see configure options http://www.imagemagick.org/script/advanced-unix-installation.php - name: configure imagemagick shell: chdir=/usr/local/src/{{ imageMagick_dir_name }} ./configure - name: make imagemagick shell: chdir=/usr/local/src/{{ imageMagick_dir_name }} make - name: make imagemagick shell: chdir=/usr/local/src/{{ imageMagick_dir_name }} make install when: imagemagick_archive.stat.exists == False become: yes
そして、私たちが話をするDockerです。Dockerで使用されるDockerfileも前述したサーバーのオペレーティング記録をコード化したものです。
# Nginxを構成するDockerfile FROM debian:stretch-slim RUN apt-get update \ && apt-get install -y \ imagemagick
このDockerfileにDocker imageを作成することができます。Dockerfileがサーバーのオペレーティング記録であれば、Docker imageは、オペレーティング記録を実行する時点とすることができます。
Dockerfile = さーばー運営記録コード化 Docker image = Docker file + 実行時点
例えば前述のansibleのplaybookでサーバーにImageMagickをインストールするとしましょう。作業者が1年前にこのplaybookで、サーバーAを構成しており、今日のサーバーBを構成する場合は、両方のサーバーのImageMagickがインストールされた時点では、1年の差が発生します。 しかし、Dockerでは、前述Dockerfileにイメージを作成しておけば、サーバーが構成されている時点では、イメージを作成した時点で固定されます。このイメージを使用して1年前にAサーバーにコンテナを配置して、今日のBサーバーにコンテナを配置しても、両方のコンテナのすべてのImageMagickがインストールされた時点では同じです。
これがDockerが普通のサーバー構成ツールと最も異なる部分です。他のツールはすべてのツールを実行する時点でサーバーの状態が決定されるのに比べ、Dockerは、作業者がその時点を事前に決めておくことができます。おかげでサーバーを常に同じ状態にすることができるのです。
一方、Dockerを初めて接した方が不快に思う部分の一つがDockerfileですが。コマンドが難しくいうより一度作成してイメージをビルドまで成功している場合が稀である見て、修正して再構築するプロセスを繰り返す必要があるためです。さらに、構築する時間がますます長くなり、まるでコードの作成後、コンパイル時間のように感じられます。
ところで、この不便さを別の方法で見ると、むしろDockerだけの利点になることがあります。
テスト駆動開発の観点からDockerfile眺め
ソフトウェアの作成に役立つテクニックの一つであるTest Driven Developmentは、すでによくご存知でしょう。
- TDDでは、まず、テストを作成し、
- テストに失敗し、
- コードを書く/修正した後、
- テストを成功します。
- 重複したコードなどをリファクタリングします。
- 1番に戻ります。
Dockerfileも、このように考えてみることができます。
- Dockerfileを作成し
- Docker imageを作成するに失敗し、
- Dockerfileを作成/変更した後、
- Dockerイメージの作成に成功します。
- 必要のない部分は消去結合できるコマンドはあります。(=効率化)
- 1番に戻ります。
少し奇妙な音かもしれないが、サーバーを作成するときに、あらかじめ失敗することは非常に重要です。なぜなら今あらかじめ経験した失敗は少しの待機と面倒だけだが、今経験していない失敗は、後にサービス障害につながるからです。私はサービスの障害なしでサーバーを変更することができているというDockerの利点とTDDが与える安心感が互いに脈絡が触れていると思います。
このプロセスを一度経験してみよう、先に見たImageMagick取付用Dockerfileを自分で作ってみましょう。まず、ベースイメージを、Ubuntuに選択します。
# Dockerfile FROM ubuntu:latest
そしてImageMagickをインストールします。
# Dockerfile FROM ubuntu:latest RUN apt install imagemagick
これで、イメージを作成してみます。
$ docker build -t my-imagemagick . Sending build context to Docker daemon 23.26MB Step 1/2 : FROM ubuntu:latest ---> 93fd78260bd1 Step 2/2 : RUN apt install imagemagick ---> Running in 81d55446049c Reading package lists... Building dependency tree... Reading state information... E: Unable to locate package imagemagick The command '/bin/sh -c apt-get install imagemagick' returned a non-zero code: 100
ImageMagickパッケージが見つからなくて失敗しました。パッケージリストを更新していなかったからです。このプロセスを追加します。
# Dockerfile FROM ubuntu:latest RUN apt update RUN apt install imagemagick
再構築してみましょう。
$ docker build -t my-imagemagick . Sending build context to Docker daemon 23.26MB Step 1/3 : FROM ubuntu:latest ---> 93fd78260bd1 Step 2/3 : RUN apt update ---> Running in b7d442841e90 WARNING: apt does not have a stable CLI interface. Use with caution in scripts. Get:1 http://security.ubuntu.com/ubuntu bionic-security InRelease [83.2 kB] ... 略 ... Reading package lists... Building dependency tree... Reading state information... 4 packages can be upgraded. Run 'apt list --upgradable' to see them. Removing intermediate container b7d442841e90 ---> 5345ed18a95b Step 3/3 : RUN apt install imagemagick ---> Running in f3cb19701d3f WARNING: apt does not have a stable CLI interface. Use with caution in scripts. Reading package lists... Building dependency tree... Reading state information... The following additional packages will be installed: dbus fontconfig fontconfig-config fonts-dejavu-core fonts-droid-fallback ... 略 ... Need to get 36.3 MB of archives. After this operation, 135 MB of additional disk space will be used. Do you want to continue? [Y/n] Abort. The command '/bin/sh -c apt install imagemagick' returned a non-zero code: 1
パッケージをインストールするかどうかを尋ねているが、入力をしてくれなかったので、エラーコードと一緒にシェルが終了しました。この問題を解決しようとapt install部分に-yオプションを追加します。
# Dockerfile FROM ubuntu:latest RUN apt update RUN apt install -y imagemagick
再構築します。
$ docker build -t my-imagemagick . ... 略 ... Successfully tagged my-imagemagick:latest
イメージがうまく作成されます。このようにコマンドを追加して、 → 失敗し → 修正するプロセスを介してDockerfileを完成することができます。
一つのヒントを言えば、ベースのイメージでコンテナを一つ実行して、そこから必要なコマンドを入力して、目的の結果が出たときに、そのコマンドをDockerfileに移すように作業すると、失敗 → 修正のプロセスをはるかに高速繰り返すことができています。
最後の過程でイメージを作成することに成功しましたので、このイメージにサーバーを実行してみましょう。
$ docker run -d my-imagemagick ... 略 ...
Docker imageでサーバーを実行すると、Dockerコンテナが作成されます。前述したが、コンテナをいつ実行するかどうかのイメージが変わらなかった場合、コンテナの内容も完全に同じです。いよいよ配布(あるいは実行)する時点に関係なくサーバーの内容を同等に作成は私達の努力が成功したようです。
クラスとインスタンスのようDockerイメージ眺める
Dockerイメージでは、いつでも同じ型のサーバを実行(=Dockerコンテナ)することができます。ところが、コードやDockerfileを全く変更しないまま、明日Docker imageを構築するとどうでしょうか?サーバーがまったく同じことを期待するが、実際には異なる場合があります。なぜなら、サーバーにインストールするパッケージは、セキュリティの問題を経ることによって、一日の間にパッチしているかすることができるからです。その後、Dockerを使用する利点が衰退さでしょうか?
これまでサーバーを同じように作成するために努力を傾けたが、実際にはサーバーに変わらなければならない部分もあります。一例として、あるコンピュータからAというDockerコンテナを二つ配置した場合は、この二つをどのように区別さでしょうか?Dockerで内部規則に従ってハッシュ値(=コンテナid)と、任意の名前(=コンテナの名前)を付けます。もちろんIPも違うよ。Dockerはこう変わるべき部分を環境変数に入れて管理するように勧めます。これらのDockerイメージの特徴は、ソフトウェアの分野のクラスとpublic変数で、private変数に比肩することができます。
Dockerfileに実行時点を加えたものDockerイメージであれば、Dockerイメージの実行時に変更しなければならない情報を加えたものDockerコンテナです。
Docker file == サーバー運営記録 Docker image == Docker file + 実行時点 Docker container == Docker image + 環境変数
ソフトウェアで非表示に部分は隠し露出部分は、露出されたおかげで、堅牢さと柔軟性の両方を得ることができたように、これで、サーバーもそのように使用することができます。先ほどわざわざサーバーを使用すると表現しました。Docker(正確にはコンテナ技術)のおかげで、サーバーをインストールして動作の記録を個別に管理する疲れてだるさせずに、よく作られたサーバーを使用することができます。さらに私が作ったサーバーがなくてもね。(Docker Hubに行く他の人が作成したDockerイメージを参照することができます。)
最終的にはこの時点では、サーバーとソフトウェアは大きく変わりません。インストールするのがそう難しいだったRedmineやGitLabなどもすでにDockerイメージで管理されているので簡単に使用することができます。そしてソフトウェアで、クラスにすることができるインスタンスの数に制限がないようにDocker imageで作成することができるコンテナ本数も制限がありません。
サーバーコードの利点
これまで説明した内容がすべてサーバーコードがもたらしたメリットです。
- サーバー製作過程に堅牢さと柔軟性を加えるだけでなく、
- 他の人が作成したサーバーソフトウェアを使用するように持って書くことができ
- 複数に配置することができる拡張性
このような点のおかげでサーバーの知識が不足している私のようなバックエンドの開発者も大きな力をかけずにサーバーを運営することができます。
おわりに:なぜDockerを書くのですか?(繰り返し)
今冒頭で述べた質問に答えをみようかします。
Dockerがなくても配布/運営しているが、私たちは何も不便を感じません。
なぜDockerを書くのですか?
サーバーの展開と運用にDockerを必ず使わなければすることはありません。しかし、今の状況にも慣れて問題と感じない問題はないでしょうか?水平拡張が自由ですか?サーバーの堅牢性を確保しながらも、動的に変えることができるフレキシブルさが存在するか?退社をしたり、部門を移動する必要がして他の人に、サーバーのオペレーティング記録を引き継ぐには、どのくらい時間がかかりますか?
Dockerがなくても、すでに他の方法で問題を解決することができますが、私にはいまだにDockerが最も便利な解決方法でした。ありがとうDocker、ありがとうコンテナ世界。
Comments
Add your comment