Docker入門:DevOpsの簡素化
公開: 2022-03-11クジラが好きな場合、またはソフトウェアを本番環境に迅速かつ簡単に継続的に配信することに興味がある場合は、この入門的なDockerチュートリアルをお読みください。 すべてがソフトウェアコンテナがITの未来であることを示しているように思われるので、コンテナクジラのMobyDockとMollyと一緒にちょっとひと泳ぎしましょう。
見栄えの良いクジラのロゴで表されるDockerは、ソフトウェアコンテナ内でのアプリケーションのデプロイを容易にするオープンソースプロジェクトです。 その基本的な機能は、Linuxカーネルのリソース分離機能によって有効になりますが、その上にユーザーフレンドリーなAPIを提供します。 最初のバージョンは2013年にリリースされ、それ以来非常に人気があり、eBay、Spotify、Baiduなどの多くの大手プレーヤーによって広く使用されています。 前回の資金調達ラウンドで、Dockerは9,500万ドルの巨額の資金を調達し、DevOpsサービスの定番になる予定です。
商品のアナロジーの輸送
Dockerの背後にある哲学は、次の簡単な例えで説明できます。 国際輸送業界では、フォークリフト、トラック、電車、クレーン、船など、さまざまな手段で商品を輸送する必要があります。 これらの商品はさまざまな形とサイズで提供され、さまざまな保管要件があります。砂糖の袋、ミルク缶、植物などです。歴史的に、荷積みと荷降ろしのためのすべての通過点での手動介入に依存する苦痛なプロセスでした。
それはすべて、インターモーダルコンテナの採用によって変化しました。 それらは標準サイズで提供され、輸送を念頭に置いて製造されているため、関連するすべての機械は、最小限の人間の介入でこれらを処理するように設計できます。 密閉容器の追加の利点は、敏感な商品の温度や湿度などの内部環境を保護できることです。 その結果、運輸業界は商品自体の心配をやめ、AからBへの移動に集中することができます。
そして、ここでDockerが登場し、ソフトウェア業界に同様のメリットをもたらします。
仮想マシンとの違いは何ですか?
一見すると、仮想マシンとDockerコンテナは似ているように見えるかもしれません。 ただし、次の図を見ると、主な違いが明らかになります。
ハイパーバイザーとは別に、仮想マシンで実行されているアプリケーションには、オペレーティングシステムの完全なインスタンスとサポートライブラリが必要です。 一方、コンテナはオペレーティングシステムをホストと共有します。 ハイパーバイザーは、コンテナーのライフサイクルを管理するという意味で、コンテナーエンジン(イメージではDockerとして表されます)に匹敵します。 重要な違いは、コンテナー内で実行されているプロセスがホスト上のネイティブプロセスとまったく同じであり、ハイパーバイザーの実行に関連するオーバーヘッドが発生しないことです。 さらに、アプリケーションはライブラリを再利用して、コンテナ間でデータを共有できます。
両方のテクノロジーには異なる長所があるため、仮想マシンとコンテナーを組み合わせたシステムを見つけるのが一般的です。 完璧な例は、Dockerのインストールセクションで説明されているBoot2Dockerという名前のツールです。
Dockerアーキテクチャ
アーキテクチャ図の上部には、レジストリがあります。 デフォルトでは、メインレジストリはパブリックイメージと公式イメージをホストするDockerHubです。 組織は、必要に応じてプライベートレジストリをホストすることもできます。
右側には画像とコンテナがあります。 イメージは、レジストリから明示的に( docker pull imageName
)、またはコンテナの起動時に暗黙的にダウンロードできます。 画像がダウンロードされると、ローカルにキャッシュされます。
コンテナは画像のインスタンスです-それらは生き物です。 同じイメージに基づいて複数のコンテナが実行されている可能性があります。
センターには、コンテナーの作成、実行、監視を担当するDockerデーモンがあります。 また、画像の作成と保存も行います。 最後に、左側にDockerクライアントがあります。 HTTP経由でデーモンと通信します。 同じマシン上でUnixソケットが使用されますが、HTTPベースのAPIを介してリモート管理が可能です。
Dockerのインストール
最新の手順については、常に公式ドキュメントを参照してください。
DockerはLinux上でネイティブに実行されるため、ターゲットディストリビューションによっては、 sudo apt-get install docker.io
と同じくらい簡単な場合があります。 詳細については、ドキュメントを参照してください。 通常、Linuxでは、Dockerコマンドの前にsudo
を付けますが、わかりやすくするために、この記事ではスキップします。
DockerデーモンはLinux固有のカーネル機能を使用するため、MacOSまたはWindowsでDockerをネイティブに実行することはできません。 代わりに、Boot2Dockerというアプリケーションをインストールする必要があります。 このアプリケーションは、VirtualBox仮想マシン、Docker自体、およびBoot2Docker管理ユーティリティで構成されています。 MacOSおよびWindowsの公式インストール手順に従って、これらのプラットフォームにDockerをインストールできます。
Dockerの使用
このセクションを簡単な例から始めましょう。
docker run phusion/baseimage echo "Hello Moby Dock. Hello Molly."
次の出力が表示されます。
Hello Moby Dock. Hello Molly.
ただし、舞台裏では、想像以上に多くのことが起こっています。
- イメージ'phusion/ baseimage'はDockerHubからダウンロードされました(まだローカルキャッシュにない場合)
- この画像に基づくコンテナが開始されました
- コマンドechoはコンテナ内で実行されました
- コマンドが終了したときにコンテナが停止しました
最初の実行時に、テキストが画面に印刷されるまでに遅延が発生する場合があります。 画像がローカルにキャッシュされていたとしたら、すべてがほんの一瞬でした。 最後のコンテナーに関する詳細は、 docker ps -l
を実行することで取得できます。
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES af14bec37930 phusion/baseimage:latest "echo 'Hello Moby Do 2 minutes ago Exited (0) 3 seconds ago stoic_bardeen
次のダイビングをする
お分かりのように、Docker内での単純なコマンドの実行は、標準の端末で直接実行するのと同じくらい簡単です。 より実用的なユースケースを説明するために、この記事の残りの部分では、Dockerを利用して単純なWebサーバーアプリケーションをデプロイする方法を説明します。 簡単にするために、「/ ping」へのHTTPGETリクエストを処理し、文字列「pong\n」で応答するJavaプログラムを作成します。
import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; public class PingPong { public static void main(String[] args) throws Exception { HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0); server.createContext("/ping", new MyHandler()); server.setExecutor(null); server.start(); } static class MyHandler implements HttpHandler { @Override public void handle(HttpExchange t) throws IOException { String response = "pong\n"; t.sendResponseHeaders(200, response.length()); OutputStream os = t.getResponseBody(); os.write(response.getBytes()); os.close(); } } }
Dockerfile
ジャンプして独自のDockerイメージを構築する前に、DockerHubまたはアクセスできるプライベートレジストリに既存のイメージがあるかどうかを最初に確認することをお勧めします。 たとえば、Javaを自分でインストールする代わりに、公式イメージjava:8
を使用します。

イメージを作成するには、まず、使用するベースイメージを決定する必要があります。 FROM命令で表されます。 ここでは、DockerHubからのJava8の公式イメージです。 COPY命令を発行して、Javaファイルにコピーします。 次に、 RUNでコンパイルします。 EXPOSE命令は、イメージが特定のポートでサービスを提供することを示します。 ENTRYPOINTは、このイメージに基づくコンテナーが開始されたときに実行する命令であり、 CMDはそれに渡すデフォルトのパラメーターを示します。
FROM java:8 COPY PingPong.java / RUN javac PingPong.java EXPOSE 8080 ENTRYPOINT ["java"] CMD ["PingPong"]
これらの命令を「Dockerfile」というファイルに保存した後、次のコマンドを実行して、対応するDockerイメージをビルドできます。
docker build -t toptal/pingpong .
Dockerの公式ドキュメントには、Dockerfileの作成に関するベストプラクティス専用のセクションがあります。
実行中のコンテナ
イメージが作成されると、コンテナーとしてそれを実現できます。 コンテナを実行する方法はいくつかありますが、簡単な方法から始めましょう。
docker run -d -p 8080:8080 toptal/pingpong
ここで、 -p [port-on-the-host]:[port-in-the-container]は、それぞれホストとコンテナのポートマッピングを示します。 さらに、 -dを指定して、コンテナーをデーモンプロセスとしてバックグラウンドで実行するようにDockerに指示しています。 'http:// localhost:8080 / ping'にアクセスして、Webサーバーアプリケーションが実行されているかどうかをテストできます。 Boot2dockerが使用されているプラットフォームでは、「localhost」をDockerが実行されている仮想マシンのIPアドレスに置き換える必要があることに注意してください。
Linuxの場合:
curl http://localhost:8080/ping
Boot2Dockerを必要とするプラットフォームの場合:
curl $(boot2docker ip):8080/ping
すべてがうまくいけば、次の応答が表示されます。
pong
やあ、私たちの最初のカスタムDockerコンテナは生きていて、泳いでいます! コンテナをインタラクティブモード-i-tで起動することもできます。 この例では、 entrypointコマンドをオーバーライドして、bashターミナルを表示します。 これで、必要なコマンドを実行できますが、コンテナーを終了すると停止します。
docker run -i -t --entrypoint="bash" toptal/pingpong
コンテナの起動に使用できるオプションは他にもたくさんあります。 もう少し取り上げましょう。 たとえば、コンテナの外部でデータを永続化する場合は、 -vを使用してホストファイルシステムをコンテナと共有できます。 デフォルトでは、アクセスモードは読み取り/書き込みですが、コンテナ内のボリュームパスに:ro
を追加することで、読み取り専用モードに変更できます。 ボリュームは、画像に保存されるべきではないコンテナ内のクレデンシャルや秘密鍵などのセキュリティ情報を使用する必要がある場合に特に重要です。 さらに、たとえば、ローカルのMavenリポジトリーをコンテナーにマッピングして、インターネットを2回ダウンロードする手間を省くことにより、データの重複を防ぐこともできます。
Dockerには、コンテナーをリンクする機能もあります。 リンクされたコンテナは、どのポートも公開されていない場合でも相互に通信できます。 これは、 –linkother-container-nameを使用して実現できます。 以下は、上記のパラメータを組み合わせた例です。
docker run -p 9999:8080 --link otherContainerA --link otherContainerB -v /Users/$USER/.m2/repository:/home/user/.m2/repository toptal/pingpong
その他のコンテナおよびイメージ操作
当然のことながら、コンテナとイメージに適用できる操作のリストはかなり長いです。 簡潔にするために、それらのほんの一部を見てみましょう。
- stop-実行中のコンテナを停止します。
- start-停止したコンテナを開始します。
- commit-コンテナの変更から新しいイメージを作成します。
- rm-1つ以上のコンテナを削除します。
- rmi-1つ以上の画像を削除します。
- ps-コンテナを一覧表示します。
- images-画像を一覧表示します。
- exec-実行中のコンテナでコマンドを実行します。
最後のコマンドは、実行中のコンテナの端末に接続できるため、デバッグの目的で特に役立ちます。
docker exec -i -t <container-id> bash
マイクロサービスの世界のためのDockerCompose
相互接続されたコンテナが2つ以上ある場合は、docker-composeなどのツールを使用するのが理にかなっています。 構成ファイルでは、コンテナーを開始する方法と、コンテナーを相互にリンクする方法を記述します。 関係するコンテナーの量とそれらの依存関係に関係なく、 docker-compose up
という1つのコマンドですべてのコンテナーを稼働させることができます。
Docker in the Wild
プロジェクトのライフサイクルの3つの段階を見て、友好的なクジラがどのように役立つかを見てみましょう。
発達
Dockerは、ローカル開発環境をクリーンに保つのに役立ちます。 Java、Kafka、Spark、Cassandraなどのさまざまなサービスの複数のバージョンをインストールする代わりに、必要に応じて必要なコンテナーを開始および停止することができます。 さらに一歩進んで、依存関係のバージョンの混同を避けて、複数のソフトウェアスタックを並べて実行できます。
Dockerを使用すると、時間、労力、およびお金を節約できます。 プロジェクトの設定が非常に複雑な場合は、プロジェクトを「ドッカー」します。 Dockerイメージを作成するという苦痛を一度経験すれば、この時点から、誰もがすぐにコンテナーを開始できます。
また、「統合環境」をローカル(またはCI)で実行し、スタブをDockerコンテナーで実行されている実際のサービスに置き換えることもできます。
テスト/継続的インテグレーション
Dockerfileを使用すると、再現性のあるビルドを簡単に実現できます。 Jenkinsまたはその他のCIソリューションは、ビルドごとにDockerイメージを作成するように構成できます。 後で参照できるように、一部またはすべてのイメージをプライベートDockerレジストリに保存できます。
Dockerを使用すると、テストする必要があるものだけをテストし、環境を方程式から外します。 実行中のコンテナーでテストを実行すると、状況をより予測しやすくすることができます。
ソフトウェアコンテナを持つことのもう1つの興味深い機能は、同じ開発セットアップでスレーブマシンを簡単にスピンアウトできることです。 これは、クラスター化されたデプロイメントの負荷テストに特に役立ちます。
製造
Dockerは、開発者と運用担当者の間の共通のインターフェースであり、摩擦の原因を排除します。 また、パイプラインのすべてのステップで同じイメージ/バイナリを使用することをお勧めします。 さらに、環境の違いなしに完全にテストされたコンテナーをデプロイできることは、ビルドプロセスでエラーが発生しないようにするのに役立ちます。
アプリケーションを本番環境にシームレスに移行できます。 かつては退屈で不安定なプロセスであったものが、今では次のように単純になります。
docker stop container-id; docker run new-image
また、新しいバージョンをデプロイするときに問題が発生した場合は、いつでもすばやくロールバックしたり、他のコンテナーに変更したりできます。
docker stop container-id; docker start other-container-id
…混乱を残したり、一貫性のない状態のままにしないことが保証されています。
概要
Dockerの機能の概要は、Docker独自のモットーであるBuild、Ship、Runに含まれています。
- ビルド-Dockerを使用すると、開発環境と本番環境の間の不整合を心配することなく、またプラットフォームや言語にロックすることなく、マイクロサービスからアプリケーションを作成できます。
- 出荷-Dockerを使用すると、アプリケーションの開発、テスト、配布のサイクル全体を設計し、一貫したユーザーインターフェイスで管理できます。
- 実行-Dockerは、さまざまなプラットフォームにスケーラブルなサービスを安全かつ確実にデプロイする機能を提供します。
クジラと一緒に泳ぐのを楽しんでください!
この作品の一部は、エイドリアン・ムアットによる優れた本「Dockerの使用」に触発されています。