Docker 内で Docker を実行した方法とそこから得られたもの

こんにちは、みんな! 彼の中で 前の記事, Docker での Docker の実行と、このレッスンを使用する実践的な側面について話すことを約束しました。 約束を守る時が来ました。 経験豊富な開発者は、おそらく、Docker 内で Docker を必要とする人は、Docker デーモン ソケットをホストからコンテナに転送するだけで、99% のケースでこれで十分であると反対するでしょう。 ただし、急いで私にクッキーを投げないでください。Docker 内で実際に Docker を実行する方法について説明します。 このソリューションには多くの応用例があり、この記事はそのうちの XNUMX つについて説明します。座って腕を前に伸ばしてください。

Docker 内で Docker を実行した方法とそこから得られたもの

開始

すべては、5 月の雨の夜、Digital Ocean で 24 ドルでレンタルしたマシンを掃除していたときに始まりました。このマシンは、Docker がイメージとコンテナーで XNUMX GB の利用可能なディスク領域をすべて埋め尽くしていたため、フリーズしていました。 皮肉なことに、これらのイメージとコンテナはすべて一時的なものであり、ライブラリまたはフレームワークの新しいバージョンがリリースされるたびにアプリケーションのパフォーマンスをテストするためにのみ必要だったということです。 シェル スクリプトを書いたり、ゴミをクリーンアップする cron スケジュールを設定したりしてみましたが、役に立ちませんでした。毎回必然的にサーバーのディスク領域が使い果たされ、サーバーが (よくても) ハングアップして終了しました。 ある時点で、コンテナ内で Jenkins を実行する方法と、コンテナに転送された Docker デーモン ソケットを通じてビルド パイプラインを作成および削除する方法についての記事を見つけました。 このアイデアは気に入ったのですが、さらに進んで、Docker 内で Docker を直接実行して実験してみることにしました。 当時、私には、Docker イメージをダウンロードし、テストに必要なすべてのアプリケーションのコンテナを別のコンテナ (ステージング コンテナと呼びましょう) 内に作成するという、完全に論理的な解決策のように思えました。 このアイデアは、ステージング コンテナーを -rm フラグで起動し、停止時にコンテナー全体とそのすべての内容を自動的に削除するというものでした。 Docker 自体から Docker イメージをいじってみました (https://hub.docker.com/_/docker)、しかし、それはあまりにも面倒であることが判明し、必要な方法で動作させることができなかったので、最後まで自分でやりたいと思いました。

練習する。 コーン

私はコンテナを思いどおりに動作させることに着手し、実験を続けた結果、無数の芽が生まれました。 私の自虐の結果、次のアルゴリズムが生まれました。

  1. Docker コンテナを対話モードで起動します。

    docker run --privileged -it docker:18.09.6

    コンテナのバージョンに注意して、右または左に移動すると、DinD がカボチャに変わります。 実際、新しいバージョンがリリースされると、頻繁に問題が発生します。
    私たちはすぐに殻の中に入る必要があります。

  2. どのコンテナが実行されているかを調べようとしています (答え: なし) が、とにかくコマンドを実行してみましょう。

    docker ps

    少し驚くかもしれませんが、Docker デーモンが実行されていないことがわかります。

    error during connect: Get http://docker:2375/v1.40/containers/json: dial tcp: lookup docker on 
    192.168.65.1:53: no such host

  3. 自分で実行してみましょう:

    dockerd &

    もう一つの不愉快な驚き:

    failed to start daemon: Error initializing network controller: error obtaining controller instance: failed 
    to create NAT chain DOCKER: Iptables not found

  4. iptables および bash パッケージをインストールします (すべて、sh よりも bash で作業する方が快適です)。

    apk add --no-cache iptables bash

  5. bashを起動しましょう。 ようやくいつものシェルに戻りました

  6. もう一度 Docker を起動してみましょう。

    dockerd &

    次で終わる長いログ シートが表示されるはずです。

    INFO[2019-11-25T19:51:19.448080400Z] Daemon has completed initialization          
    INFO[2019-11-25T19:51:19.474439300Z] API listen on /var/run/docker.sock

  7. Enterを押します。 バッシュに戻ってきました。

今後は、Docker コンテナ内で他のコンテナを起動できるようになりますが、Docker コンテナ内で別の Docker コンテナを起動したい場合や、何か問題が発生してコンテナがクラッシュした場合はどうなるでしょうか? 最初からやり直します。

独自の DinD コンテナーと新しい実験

Docker 内で Docker を実行した方法とそこから得られたもの
上記の手順を何度も繰り返さないようにするために、独自の DinD コンテナーを作成しました。

https://github.com/alekslitvinenk/dind

DinD ソリューションが機能することで、Docker 内で Docker を再帰的に実行し、より冒険的な実験を行うことができるようになりました。
ここでは、MySQL と Nodejs を実行する、そのような (成功した) 実験の XNUMX つについて説明します。
最もせっかちな人は、ここがどうだったかが分かるだろう

例文:

  1. DinD を対話モードで起動します。 このバージョンの DinD では、子コンテナが使用できるすべてのポートを手動でマップする必要があります (これについてはすでに取り組んでいます)。

    docker run --privileged -it 
    -p 80:8080 
    -p 3306:3306 
    alekslitvinenk/dind

    bash に入り、そこからすぐに子コンテナの起動を開始できます。

  2. MySQL を起動します。

    docker run --name mysql -e MYSQL_ROOT_PASSWORD=strongpassword -d -p 3306:3306 mysql

  3. ローカルに接続するのと同じ方法でデータベースに接続します。 すべてが機能することを確認しましょう。

  4. XNUMX 番目のコンテナを起動します。

    docker run -d --rm -p 8080:8080 alekslitvinenk/hello-world-nodejs-server

    ポートマッピングは正確に行われることに注意してください。 8080:8080、ホストから親コンテナへのポート 80 をポート 8080 にすでにマッピングしているためです。

  5. ブラウザで localhost にアクセスし、サーバーが「Hello World!」と応答することを確認します。

私の場合、ネストされた Docker コンテナーを使用した実験は非常に良い結果をもたらしたので、プロジェクトの開発を継続し、ステージングに使用するつもりです。 これは、Kubernetes や Jenkins X よりもはるかに軽量なソリューションであるように思えます。しかし、これは私の主観的な意見です。

今日の記事はこれで終わりだと思います。 次の記事では、Docker 内で Docker を再帰的に実行し、ネストされたコンテナの奥深くにディレクトリをマウントする実験について詳しく説明します。

PS このプロジェクトが役立つと思われる場合は、GitHub でスターを付け、フォークして友達に伝えてください。

Edit1 2 つのビデオを中心にエラーを修正しました

出所: habr.com

コメントを追加します