最近Dockerを学習しています。当初Dockerに抱いてたイメージが、学習を通して大きく変わったので、学習の途中ですが、Dockerに対するイメージの変遷をメモしようかなと思います。
筆者の現状のレベル感は、DockerとDockerComposeを使えるようになり、公式ドキュメントやDockerHubの各Imageの説明文、イメージのソースコード(Github上)を読んでなんとか公開Imageを使えるようになったレベルです。
kubernetesについては、ハンズオンとしては触っておらず、Web上の説明文を読んだことがある程度です。
まだ学習し始めたばかりなので、経験がある人から見たらおかしな事、間違っている事を書いているかもしれませんが、ど素人が触るとどんな感想を抱くのかの読み物として、読んでいただけたらと思います。
イメージの変遷
勉強前になんとなく抱いていたDockerのイメージは、
「ふつうの仮想環境よりも軽量な仮想化の技術」
こんなイメージだったんですが、今は
「サーバー環境をただのプロセスにする(=サービス化)技術」
というイメージです。
勘違い?の始まり
私みたいな何も知らない人が最初にDockerで見る図といえば、このようなモノと思います。

これがハンズオンしていない人が、軽量な仮想環境と認識しやすい理由だと感じています。
仮想マシンとDockerが比較されるため、単純に「ゲストOS」がない分だけ軽くて早い!という認識になるのではないでしょうか。私は単純にそう考えました。実際にVirtualBoxを使っていて起動に時間がかかる!と感じていたのも大きいと思います。
未知との遭遇 -first contact-
初めて触ってみて思ったのは、「おぉ早い!」でした。公式Imageをdocker runする速さは、仮想環境の立ち上げと比べて雲泥の差です。
しかし違和感もありました。初めて起動したのは適当なLinux(debianとか)のImageだったのですが、起動すると勝手に終了するのです。
DockerはPID=1のプロセスが終了すると、そのコンテナが終了します。軽量な仮想環境だと思っていたので、勝手にサーバーがシャットダウンするように感じました。
学習してみて
それから学習が進み、DockerやDockerComposeなどを触りどんどん「軽量な仮想環境」というイメージが消えていきました。
仮想マシンとDockerでのWebサーバーを立ち上げた場合を考えると、私のイメージは以下です。
Docker:Webサーバーの機能(=HTMLを返す)だけが欲しく、サーバー環境を隠蔽する。
仮想マシン:独立したWebサーバーを作る。サーバー環境を丸ごと作る。
Dockerでは、Webサーバーの機能だけが欲しいのです。特定のIPアドレスにHTTPで通信したらHTMLが返ってくる機能だけが欲しく、裏でサーバーが存在し、ディレクトリや設定ファイルが置かれているファイルシステムを感知したくないのです。
docker runすればソフトウェアのWebサーバーを全く認知せず、自分のPC上でプロセス(=サービス)が起動するようなイメージです。
仮想マシンは、サーバーが欲しいのです。Webサーバー用にちゃんとディレクトリや設定ファイルが構成されたファイルシステムを持ったWebサーバーが欲しいのです。そのサーバーの中で動いているソフトウェアとしてのWebサーバーなども認知できるのです。
これは自分のPCとは別にWebサーバーが起動する(実際は自分のPC上)ようなイメージです。
最初に持った違和感の”LinuxのみのImageを起動するとすぐ終了する”ですが、サービスと捉えると合点がいきます。何の機能も提供しないサービスはあり得ません。サービスであれば機能を提供するためにプロセスが起動し続けているはずなのです。なのでコンテナはPID=1のプロセスが起動し続けていることが前提なのです。
ちなみにLinuxのみのImageはベースとなるためのImageで、利用者がそこに機能を追加しサービスとして完成(=別のImageとして保存)させます。そのままでは何の機能も提供しないため終了します。
導入環境について
ここまではDockerはサーバー環境をただのプロセス(=サービス)にするという話でした。
このイメージを持ったことで開発環境でDockerを使用する事と、本番環境でDockerを使用する事に対して自分なりの意見を持つことが出来たので、それについて書いていきます。
特に本番環境でのDocker使用に関しては、学習前後で大きな変化がありました。
開発環境に導入
Webサーバー、APサーバー、DBサーバーがあるシステムを考えたとして各開発者のローカル開発環境の構築をすることを考えます。
僕自身SI業界で働いているのですが、よくあるのが環境構築に苦戦するメンバーが出ることです。SI業界では、既存システムの改修の経験しかない人も多くいます。そういったメンバーはJavaなどのソースコードは書けても、WebサーバーやAPサーバーを構成したことがないので、手順書通りで動かない場合に対応できないのです。
上記のような場合、Dockerであれば最初にWebサーバー、DBサーバーのImageとdocker-compose.ymlさえ作成すれば、どんな人でもdocker compose upのコマンドを入力するだけで、サーバー環境を隠蔽するため、設定などを全くせずローカル開発環境が構築ができます。
また、ローカル開発環境以外にも、同じ環境が作れるので共有サーバーにテスト環境を作成する場合も全く同じ環境を作成、さらに量産できます。
IT(シナリオテスト)などでは、あるシナリオが別のシナリオに影響するため、同時に実施できない場合があると思います。同じ環境を量産できるのでそれぞれのシナリオ用の環境を作ってしまえばいいのです。
上記の使い方は仮想環境と同じでしょう。違いとしてはDockerはDockerComposeがあるので、さらに自動化できる範囲が広く、infra AS code されている認識。(仮想環境でもinfra AS codeする機能はあるかもです。)
本番環境で導入
ここからは本番環境での使用を考えてみます。ここからはkubernatesなどのコンテナオーケストレーションをハンズオンしたことがないので、想像的な要素を多分に含みます。しかし学習によるイメージの変遷が激しかったので記録として記載します。
大まかに学習前後の比較をすると、
学習する前では、本番環境でも導入するのが当たり前と感じていました。なぜならDockerは環境差異なく環境構築するものというイメージだったため、本番環境こそ環境差異を発生させたくないと感じていたからです。
学習後では、本番環境にDockerを導入する意義は、環境差異をなくすことよりも、サービスの負荷に柔軟に対応することが主眼だと感じています。
ここでは「本番環境でも使用(従来構成をDocker化)」「本番環境でも使用(マイクロサービス化)」の2パターンで考え、最後にそれらについてまとめます。
本番環境で導入(従来構成をDocker化)
従来構成とは何を指すのか?ですが、Webサーバー、APサーバー、DBサーバーがあるといった構成とします。(単純化のため複数サーバ+ロードバランサなどの負荷分散はないモノとします。)
つまり、よくある三層レイヤのシステムをそのままDocker化する事を考えます。

開発環境では、一台のPC/サーバーにDockerを用いて、WebサーバーやDBサーバーを共存させました。本番環境でも一台のサーバーにWebサーバー、DBサーバーのコンテナを起動するのでしょうか?
もちろんしないでしょう。一台のサーバーに全ての負荷が集中してしまいます。では、3台それぞれにDockerを起動し、それぞれのサーバー内のコンテナがサーバーを跨いで通信できるのでしょうか?
サーバーを跨いでのコンテナ間の通信は可能です。Dockerは仮想的なネットワークを構成しますが、仮想ネットワークにoverlayネットワークという種類があります。これは複数サーバー内で起動するDocker内のコンテナ同士でネットワークを構成できます。つまりコンテナがサーバーを跨いで通信することが可能です。

これで、本番環境にも従来通りの構成でImageをデプロイすることができます。
しかしそれで良いのしょうか?Dockerの目的は環境差異を無くすことですが、本番環境においては、そのシステム専用のサーバーであることが多く、また別環境でうまく行った手順で構築するので、無駄なソフトウェアもない綺麗な環境なはずです。
環境構築作業も最初に1度のみ実施し、後は改修差分を設定するのみです。ここを自動化しても大きな効率化にはならないでしょう。
ローカル開発環境では、そのPCはAシステムの改修プロジェクトのために環境変数やPathを設定し環境構築し、別案件に異動すればBシステムのための環境構築をします。
異なるプロジェクトに参加したメンバーが今度はCシステムの改修に参画するため、各メンバーのPCは全く異なる環境となり、同じ手順でも環境を構築できないなどが発生します。また、メンバーが多いほど環境構築を繰り返すことになります。
そのため開発環境では恩恵は大きいですが、本番環境をそのままDocker化しても恩恵が少なく、むしろDocker分だけリソースが無駄に消費されます。
本番環境で導入(マイクロサービス化)
私は学習前する前から「Dockerでシステムが負荷変動に柔軟に対応できる」のような事を聞いた覚えがありました。負荷変動ということは本番環境での話のはずです。
しかしこれは、kubernetes導入とDocker導入、さらにはマイクロサービス化する話が色々と混同してしまったため理解だったと思われます。
kubernetesは負荷に対して、システムを柔軟にスケールアウトするためのものです。スケールする際は迅速、軽量なコンテナが内部で使用されています。
マイクロサービスアーキテクチャは、システムを1つの大きなシステムと捉えるのではなく、機能1つごとに別システムとして切り出す事です。
「本番環境でも使用(従来構成をDocker化)」でのシステムの内、外部APIの連携機能とメール送信処理機能をマイクロサービスとして切り出したとして考えましょう。(APサーバのみ考えます。)

またAWSのようなサーバーをすぐに調達できるクラウド上にシステムを構成していた場合、負荷が上昇し特に外部API機能が高負荷になったとします。その場合は、自動でサーバーを調達し外部API機能のコンテナを稼働させ高負荷に対応します。

また負荷が低減した場合は、サーバーを返却するためコストダウンが出来ます。
私がよく耳にした「Dockerでシステムが負荷変動に柔軟に対応できる」は、kubernetesとマイクロサービス化の利点でした。Dockerはkubernetesの内部でコンテナのために利用され、そのコンテナのImage作成のために開発環境で利用されているという話でした。
Docker自身のメリットではありません。
導入環境についてまとめ
開発環境と本番環境と分けて、Dockerを導入することについて考えました。
- チームの環境構築を”迅速”に”同様”にするためのDocker(開発環境へ導入)
- 可用性アップのために、システムをマイクロサービス化しkubernetesで運用。kubernetes内で動作するDocker(本番環境へ導入)
Docker自身の利点は1ですが、2についてはマイクロサービス化とkubernetesが提供するものです。Dockerはkubernetesが各サービスを容易にスケールするために、「サーバーのプロセス化(=サービス化)」する手段として内部的に利用されているにすぎないです。
私は上記1、2を混同していました。
もう一歩踏み込んで、全てのシステムは2のマイクロサービス+kubernetesを目指すべきなのか?について考えます。
2の利点はシステムの負荷変動に柔軟に対応できることです。つまり負荷変動が激しくないシステムの場合は意味がありません。企業の基幹システムのように負荷がほぼ一定なら無駄になるでしょう。
つまりは全てのシステムで、マイクロサービス化+kubernetesが良い訳ではなく、上記のメリットがないシステムがこのような構成にしても、恩恵が薄いだけでなくマクロサービス化の改修コストとkubernetesの学習コストだけかかります。
最後に
実際にハンズオンしてみる事でDocker、kubernetes、マイクロサービス化を分けて考えることができ、それぞれを導入することの話は開発環境での話なのか、本番環境での話なのかが整理することが出来たように感じます。
それぞれ単体の機能はWeb上の情報で知っていたつもりですが、実際にハンズオンしなければそれぞれの利点をちゃんと自分の中で整理しきれないという事を改めて実感しました。
また、実はDockerとよくセットで語られるCI/CD環境についてですが、そこについて自分はまだ勉強できていないです。Jenkinsとかと組み合わせたり、GitHubActionと組み合わせるみたいですが、CI/CD環境についてはこれからハンズオンして勉強していこうかと思います。
Jenkinsやkubernetesを実際に触ることでDockerへのイメージがまた変わるかもしれないですね。以上、ど素人がDockerを触るとどうなるかの雑記でした。
追記 マイクロサービスアーキテクチャについて
元々は記載していたマイクロサービス化について内容は長かったため以下の別記事に分離しました。自分なりの目線で、基幹システム、自社サービスで導入する観点でや、バックエンドエンジニア目線での話も記載しています。
おまけ
ここではDockerについて学習している中で、不思議に思った点などを列挙します。
Dockerのバージョンについて
Dockerのバージョンの数字は途中でかなり飛んでいます。これは途中からDockerのバージョン番号の付け方が途中から「年.月.マイナーバージョン」に変更されたため。
kubernetesのDocker非推奨化/廃止!?
Docker調べるとこのタイトルの記事も散見すると思います。これはどうも誤解を生みやすい表現みたいです。このサイトが分かりやすかったです。(現在では廃止までいっている。)
私の理解もここで記述します。Docker内部のコンテナ実行環境(=containerd)が標準に準拠したのでDockerとdockershimを廃止し、containerdのみを利用するようになった。
そのためDocker廃止となっているが、kubernetesで使用するイメージはDockerで作成したイメージを今まで通り利用できる。
overlayネットワークについて
本文中に登場したoverlayネットワークは、複数ホスト間でネットワークを構成するものです。しかしDocker公式の標準機能ですが、本文中のように目で見えるような形で使うことはほぼないのでは?と思っています。
複数サーバー間でDockerを使用する場合、本文中にあるように本番環境での利用が主でしょう。その場合の目的はスケーラビリティの獲得です。しかしDocker単体ではこのスケーラビリティの獲得はできません。Dockerが提供する機能はサーバー環境のプロセス化です。スケーラビリティはコンテナオーケストレーションが提供する機能です。
ですので、このoverlayネットワークはkubernetesが内部的に利用するだけで、kubernetes利用者が直接構成することはないのでは?と考えています。(kubernetes触ってないので予想です。そもそもネットワーク構成はkubetnetesが自前でやっている可能性もあります。)
そのためかWeb上を検索しても参考になる資料は少なく、また参考になりそうな資料は大抵古いです。それはコンテナオーケストレーションが世にあまり浸透していないときはDocker単体で複数ホスト間のネットワークを構成する必要があったためだと考えています。
ちなみに公式資料(またはその翻訳サイト?)では、overlayネットワークの説明がありますが、こちらもコンテナオーケストレーションを使うこと前提な書き方が多いです。また公式サイトなので、使用するコンテナオーケストレーションは、Docker公式のDockerSwarmでの説明です。
オーバーレイネットワークの利用
https://matsuand.github.io/docs.docker.jp.onthefly/network/overlay/
オーバーレイネットワークのチュートリアル
https://matsuand.github.io/docs.docker.jp.onthefly/network/network-tutorial-overlay/
コメント