スペシャリストから学ぶコンテナ技術 第 1 回

2021-04-02
デベロッパーのためのクラウド活用方法

Author : 原田 和則 / 林 政利

こんにちは、テクニカルソリューションアーキテクトの原田です。
普段は、業種業態や技術領域を問わず、様々なお客様の AWS 活用支援を担当しています。

皆さんは「コンテナ」という単語を聞いたことはありますか ? 今日、多くのお客様が本番環境でコンテナを採用し、ビジネスに活かしております。その一方で、「コンテナを使ってみたいけど、コンテナ自体がよく分からない」「何から勉強して良いのかわからない」「なんとなくコンテナを使い始めたけれど、これでいいのか不安」といったコンテナ自体に関するご相談をいただくこともあります。

本記事では、AWS 上でのコンテナの利用方法といった AWS 自体の話からは少し離れて「コンテナ」自体にフォーカスして、そもそもコンテナとは?なぜコンテナか ? (What Containers ? Why Containers ?) についてお話していきます。

今回は、コンテナスペシャリスト ソリューションアーキテクトの 林さん (@literalice) を招いてインタビュー形式で進めていきます。それではお楽しみください 。

「スペシャリストから学ぶコンテナ技術」の連載記事はこちら

選択
  • 選択
  • スペシャリストから学ぶコンテナ技術 第 1 回
  • Docker が生まれるまでの課題と背景とは ?
  • コンテナイメージを実際に作成してみよう !
  • コンテナイメージを運んで、別環境で起動してみよう !

コンテナとは ? コンテナのメリットとは ?

原田「こんにちは。原田です。よろしくお願いします。」

「こんにちは、コンテナスペシャリスト ソリューションアーキテクトの林です。よろしくお願いします。」

(写真左) 原田 和則 テクニカルソリューションアーキテクト
(写真右) 林 政利 コンテナスペシャリスト ソリューションアーキテクト

原田「本題に入る前に、『コンテナスペシャリスト ソリューションアーキテクト』という職種は読者の方はあまり馴染みがないかと思いますので、どういう職種なのか簡単に教えていただけますでしょうか ?」

 「はい、『コンテナスペシャリスト ソリューションアーキテクト』というのは、コンテナ周りに特化して、お客様がビジネスを進める上での技術課題を解決するための支援を行う職種です。」

原田 「なるほど、ありがとうございます。まさにコンテナのスペシャリストというわけですね。早速ですが、お客様からよくいただくご相談について、いくつか質問させてください。コンテナとは一体なんなのでしょうか ? そして、コンテナはどういったメリットがあるのでしょうか ?」


アプリケーションの構成要素

「そうですね、コンテナそのものについて説明する前に、少しアプリケーション自体の話をさせてください。ちょっと唐突な質問ですが、アプリケーションを構成するコンポーネントって何でしょうか ? 例えば、Node.js で書いたアプリケーションが動作するのに必要なコンポーネントとか。」

原田「ラップトップでもサーバーでも何でもいいので、そこに Node.js をインストールして、アプリケーションコードを用意して実行すれば、最低限動きそうな気がします。」

「そうですね。シンプルなものであれば、アプリケーションコードと Node.js だけで動くと思います。ただ、実際の開発だとライブラリやパッケージといった依存物も利用することがほとんどではないでしょうか。アプリケーションコード内でそのライブラリやパッケージをインポートして利用する形ですね。」

原田「ということは、アプリケーションが動くのに必要なコンポーネントは、アプリケーションコードライブラリなどの依存物ランタイム (例えば Node.js) の 3 つということでしょうか?」

「実はまだ足りないんです。設定値というものがあります。同じアプリケーションでも、開発・ステージング・本番など動作する環境によって値を変えたい場合が出てきます。例えば、データベースの接続情報だったりですね。そういった環境によって異なる値をアプリケーションコードの中に直接書くという方法もあると思います。ただ、この場合、何が起きるかというと、アプリケーションをデプロイする度に環境を確認して、適切な値に書き換えてからデプロイしないといけません。これどうなると思いますか ?」

原田「効率がいいとは言えませんね。そして、ステージングのつもりが間違えて本番用の値を入れてデプロイしてしまい、本番環境のデータベースに接続してしまったりといったミスオペレーションも起きそうです。」

「それ、かなり怖いですよね。ですので、そういった環境によって値が変わるものは設定値としてアプリケーションコードの外に出してしまいます。この設定値はファイルのときもあれば、環境変数のようなものを使うときもあります。」

原田「なるほど。ということは、アプリケーションを構成するコンポーネントは、アプリケーションコード、ライブラリなどの依存物、ランタイム、設定値の 4 つが必要ということでしょうか ?」

「はい、その通りです。」

アプリケーションを構成する 4 つのコンポーネント


アプリケーションの動作環境

「アプリケーションの構成要素が分かったところで、次に、このアプリケーションがどうやってデプロイされるかお話したいと思います。あくまでも一例ですが、開発者がローカル環境でコードで書きます。それが終わるとなんらかの方法でステージングや QA 環境のサーバーにデプロイします。そして、テストを行って問題なければ、本番環境のサーバーにデプロイします。」

「そのなんらかの方法は、例えばデプロイ対象のサーバーに SSH で入って、git や共有ストレージなどからアプリケーションコードを持ってきて、プロセスやサーバーの再起動をしてデプロイを行うというのが、シンプルな例ですね。この流れをスクリプトやツールなどで自動化している場合もあると思います。」

原田「私の前職でも、多少違う部分はありますが、似たようなデプロイを行っていましたね。」

デプロイのフロー例

「このデプロイ環境 (ローカル 、ステージング / QA 、本番) の中で、ランタイムはそれぞれの環境に既にインストールされていることがほとんどです。デプロイ時はアプリケーションコードだけを各環境に運び、ランタイムやライブラリ、設定値は既に各環境に用意されているものを使います。つまり、各環境はアプリケーションコードのみ同一で、それ以外のコンポーネント (ランタイム、ライブラリなどの依存物、設定値) は各環境で用意されているものを使用します。

環境間でアプリケーションコードのみ運ばれる


アプリケーションの動作環境の差異

原田「質問があります。これ (環境間でアプリケーションコードのみ同一で、それ以外のランタイムといったコンポーネントは各環境にあらかじめ用意されているものを使う) のなにが問題になるのでしょうか ? 各環境の構築を行うときに、OS やランタイムなどのバージョンを揃えて構築するのって、みなさんやられていると思います。つまり、ランタイムは各環境にインストール済みなものを使うけど、バージョンが揃っているので、アプリケーションコードが同じものであれば、アプリケーションの動作に問題は発生しないと思います。」

「はい、その通りです。が、運用を続けていくと、ランタイムのバージョンがずれていくことがあります。これはかなり極端な例ではありますが、例えば、開発者が書いたアプリケーションコードをステージング / QA 環境にデプロイして、QA 担当者がテストを行っています。しかし、バグが発生して、テストが通らない。そこで、切り分けのため、ステージング / QA 環境のランタイムのバージョンを上げてみました。そうするとバグが出なくなったので、開発者にフィードバックにしました。フィードバックをもらった開発者は、ランタイムのバージョンが上がっていることに気づき、後方互換性を保つようにアプリケーションコードを修正したのですが、ローカル環境のランタイムのバージョンを戻すのを忘れていました。同時に、QA 担当者もトラブルシューティングで上げたステージング / QA 環境のランタイムのバージョンを元に戻すのを忘れてしまいました。その結果、ローカル環境、ステージング / QA 環境、本番、それぞれのランタイムのバージョンが異なってしまいました。でも、アプリケーションコードは、後方互換性を保っているため、本番にデプロイしても問題は発生せず、誰もバージョン差異 (動作環境の差異) に気づいていません。繰り返しになりますが、これはかなり極端な例ですが、一定期間運用を続けていくと、程度に差はあれ、環境差分はわりと発生すると思います。」

環境ごとにランタイムのバージョンが異なってしまう場合がある


本番だけ落ちる ?

「こうやってランタイムが各環境にべったりくっついてアプリケーションコードだけが運ばれていくことで、ローカルやステージング / QA ではアプリケーションが問題なく動いたけど、本番では動かないといったことが起こりえます。」

原田「なるほど。分かりやすくするために、例えば、ローカルが Node.js v13、ステージングが Node.js v14、本番が Node.js v12 という、意図せず各環境のランタイムバージョンが異なっている場合を想定します。そして、たまたま、開発者が v13 から実装された API を使ったアプリケーションコードを書いたとします。開発者は、ステージングと本番の Node.js のバージョンが異なっているとは思ってもいないので、テストのためにステージング環境にデプロイします。ローカルの v13 からステージングの v14 は、後方互換性が保たれている場合、v14 でも問題なく動作するので、テストを通過しました。そして、v12 の本番にデプロイします。しかし、v12 には存在しない API を利用しているため、本番でのみアプリケーションが動かないといったことが発生しますね。」

本番だけアプリケーションが動かない

「そうです。運用チームから本番だけ落ちる (問題が発生する) んですけど、といった問い合わせが開発チームに来るみたいなことっていままでの経験でなかったですか ?」

原田「よくありましたね (笑) 開発でもステージングでも再現しなくて、結局、本番環境に入らせてもらったり、細かいログもらったりで、トラブルシューティングした結果、『え、ランタイムのバージョン違ってますね・・・』とか。」

「そうなんですよね。このようなことが起こるとデプロイのライフサイクルを信用できなくなって、アプリケーションをデプロイする上での心理的な障壁が大きくなってしまいます。本当はどんどんデプロイして、フィードバックをもらって、修正して、すぐにまたデプロイを繰り返すといったフィードバックループを回したいにも関わらず、なかなかデプロイができないといった事態が発生しかねません。」

「この、時間の経過により各環境に差異が発生するみたいなことを解決するために、どんな方法がありますかね ?」

原田「例えば、構成管理ツール・サービスを使って、環境差分が発生しないようする。万が一発生した場合でも、すぐに気付く仕組みを作る とかですか ?」

「はい、それも有効な方法の 1 つだと思います。今回は深くは触れないですが、Ansible といったソフトウェアを導入されているお客様も多いと思います。別な選択肢として、『コンテナ』を利用するという方法もあります。」

原田「お、いよいよコンテナの登場ですね。」


環境差分をなくすために「コンテナ」という解決策

「コンテナってどういう概念を示しているかというと、ざっくりいうと、『アプリケーションが動くのに必要な、アプリケーションコード、ランタイム、ライブラリなどの依存物を1つにパッケージングしちゃいましょう』です。さきほどお話したように、アプリケーションコードのみ運んで、ランタイムなどは各環境ごとに予め用意されたもの利用する。その結果、ランタイムのバージョンが各環境ごとに異なってしまい問題が発生してしまう。であれば、『アプリケーションコード、ランタイム、ライブラリも一緒にまとめて運んでしまおう』ということですね。

コンテナの概念

原田「なるほど。シンプル イズ ベストなアイデアですね。『環境間のバージョン差異で問題が発生するならそのまま全部運べばいいよね』というのは。でも、『設定値』はパッケージングしていないんですね、これはどういう理由なのでしょうか ?」

「いいポイントですね。もちろん、設定値を含めてパッケージングすることは可能です。ただ、実務上、設定値を含めることはあまりありません。というのは、設定値は、環境ごとに設定すべき値が変わることがほとんどですよね。例えば、開発、ステージング、本番環境はまったく同じアプリケーションコードを使用しますが、異なる設定値を使用することで、環境ごとに接続先のデータベースを変えたり、出力するログの粒度を変えたりします。つまり、設定値は環境差分があることが当たり前なので、コンテナの中には入れません。」

「逆に、設定値を無理にパッケージング (コンテナ化) してしまうと、コンテナを各環境に運ぶたび、つまりデプロイするたび、パッケージを紐解いて、中身を確認して、設定値を環境に合わせて変えて、もう一度パッケージングして、コンテナを起動するといったことにもなりかねません。」

原田「なるほど、確かに。効率は良くないですし、ミスオペレーションも発生してしまう可能性もありますし、そもそも環境ごとに再パッケージングする時に、ランタイムのバージョンといった環境差分も発生しそうですね。」

「はい、そうなんです。環境差分をなくすためにコンテナを利用するので、環境差分が発生しうるオペレーションは極力避けた方がいいと思います。なので、その原因となりうる設定値は、コンテナの中に含めないことがほとんどです。」

コンテナと設定値


コンテナとは ? Docker とは ?

原田「なるほど、よく分かりました。では、この設定値はどうやってコンテナで起動するアプリケーションに反映させるのでしょうか ?」

「お、かなり具体的な質問ですね。原田さん、もしかすると、今、コンテナと言いつつも、頭の中では Docker コンテナのことを想像されていらっしゃいませんか ? 事実上、Docker もしくは Docker コンテナのことを単に『コンテナ』と呼ぶことも多いのですが、せっかくの機会なので、この部分についてもお話したいと思います。」

原田「はい、ぜひ。コンテナと Docker の違いについては普段あまり意識することはないので、言われて見れば気になる・・・という読者の方もいらっしゃると思います。」

コンテナ技術は、ホスト OS からアプリケーションの動作環境・プロセスを隔離するための技術 (アイソレーション技術) のことで、そのコンテナ技術により隔離した環境・プロセスをコンテナといいます。このプロセスの隔離は、Linux の場合は cgroup や namespace といった Kernel の機能で実現しています。この部分の詳細については中々イメージが湧かないと思うので、実際にデモをお見せしながら、別途説明したいと思います。ですので、ここでは、コンテナ技術はホスト OS 上で動くプロセスの隔離技術だとなんとなく覚えていただければと思います。」

「このコンテナ技術の実装は古くからあり、例えば、Solaris Containers (2005 年) や LXC (2008 年) などが有名です。広義だと、chroot もそうですね。」

原田「なるほど、確かに、chroot もファイルシステムの隔離なので、隔離技術の 1 つですね。」

「 Docker もこのコンテナ技術を実装するソフトウェアの 1 つであり、Docer により隔離された環境のことを Docker コンテナといます。そして、この Docker は、事実上、コンテナ技術実装のデファクトスタンダードとなっており、コンテナと言えば Docker (もしくは Docker コンテナ) のことを表していることがほとんどです。」

「もちろん Solaris Containers や LXC といった Docker 以前からあるコンテナ実装ソフトウェア、もしくは、rkt といった Docker 以後に登場したコンテナ実装ソフトウェアを利用されているお客様はいらっしゃると思いますが、おそらくほとんどの読者の方は Docker について改めて知りたいと思われているかなと思います。ですので、これ以降は コンテナ = Docker という前提でお話をさせていただければと思います。」

原田「ここで 1 つ疑問が。コンテナ技術とその実装方法は、Docker 以前からあることが分かりました。でも、開発者の間でコンテナが流行り初めたのは、Docker が登場 (2013 年 3 月) してからだと思います。ということは、Docker 以前のコンテナ実装ソフトウェアと Docker は、何か決定的な違いがあると思うのですが、具体的に何が違うのでしょうか ?」


「これもいい質問ですね。ただ、この説明をするには、Docker 自身についてもう少し深く掘り下げる必要があるので、まずはその部分について説明させてください。」

原田「はい、分かりました。今までは、『コンテナとはなにか ? コンテナのメリットは ?』というコンテナ全般についての話だったかと思います。ここからは『Docker』の話になるかと思いますので、ここで一旦まとめさせていただいて、Docker については次号以降で詳しくお話を聞かせてください。」

「はい、よろしくお願いします。」


まとめ

アプリケーションには 4 つの構成要素 (アプリケーションコード、ランタイム、ライブラリなどの依存物、設定値) があります。この中で、デプロイの際に、各環境間で同一なものを利用するのはアプリケーションコードのみで、それ以外の要素は各環境にあらかじめセットアップされたものを利用するというデプロイフローを採用している場合、時間の経過とともに、意図せず各環境のランタイムのバージョンが異なってしまう、つまり、環境差分が発生することがあります。その結果、本番環境だけアプリケーションが動かないといった問題が発生することがあります。

そのようなことが起きると、デプロイのライフサイクルを信用できなくなり、プロダクトの価値向上のためにフィードバックループを高速に回すことができなくなってしまいます。

その環境差分をなくすための手段の1つとして、アプリケーションの構成要素のうち、アプリケーションコード、ランタイム、ライブラリなどの依存物をパッケージングして、隔離された環境で実行するコンテナならびにコンテナ技術について紹介しました。

次回以降では、コンテナ実装のソフトウェアとしてデファクトスタンダードになっている Docker について、掘り下げていきたいと思います。

「スペシャリストから学ぶコンテナ技術」の連載記事はこちら

選択
  • 選択
  • スペシャリストから学ぶコンテナ技術 第 1 回
  • Docker が生まれるまでの課題と背景とは ?
  • コンテナイメージを実際に作成してみよう !
  • コンテナイメージを運んで、別環境で起動してみよう !

builders.flash メールメンバーへ登録することで
AWS のベストプラクティスを毎月無料でお試しいただけます

筆者プロフィール

原田 和則
アマゾン ウェブ サービス ジャパン合同会社
テクニカルソリューションアーキテクト

インフラエンジニアとして経験を積む中で、クラウドに携わりたい想いで AWS へ。
業種業態、技術領域を問わず、様々なお客様の AWS 活用支援を行っています。

林 政利 (@literalice)
アマゾン ウェブ サービス ジャパン合同会社
コンテナスペシャリスト ソリューションアーキテクト

フリーランスや Web 系企業で業務システムや Web サービスの開発、インフラ運用に従事。近年はベンダーでコンテナ技術の普及に努めており、現在、AWS Japan で Amazon ECS や Amazon EKS でのコンテナ運用や開発プロセス構築を中心にソリューションアーキテクトとして活動中。

AWS を無料でお試しいただけます

AWS 無料利用枠の詳細はこちら ≫
5 ステップでアカウント作成できます
無料サインアップ ≫
ご不明な点がおありですか?
日本担当チームへ相談する