Docker +さびによる第一歩


TL;DR: We are going to install Docker and create five different containers for a Rust program, each one a little more complex than the other.


こんにちは!このポストでは、あなたの錆プログラムをDockerizeする方法をあなたに教えます.私たちは非常に簡単なコンテナから始めて、それからより洗練されたもの(我々がコンパイル時間とイメージサイズの世話をする)に構築します.
私は、あまりにも粒状化の代わりにちょうど最後のものにジャンプすることについて考えました、しかし、私はこれらのポストと簡潔であるよりむしろ明らかであるのを好みます.あなたのためにあまりにも明白で、何があいまいなままであったかについて、私に尋ねて、何でもジャンプするために自由に感じてください.

インストール
まず、Dockerをインストールします.ガイドを取得ガイドをしてMac OS , Linux and Windows .
インストールしたら、このコマンドを実行して実行してテストします.
$ docker run hello-world
それはプルする必要がありますhello-world からのイメージDocker Hub そして、詳細を説明するテキストブロックを返します.

用語集
あなたがDockerに全く新しいならば、私が以下の用語を使うとき、私が意味するものの明確な理解があるのを助けます

  • Docker:我々は(または、より正確には、私たちのイメージやコンテナに対処するために使用するDockerデーモン)をインストールするアプリケーション;

  • Dockerfile :ファイル名Dockerfile これにはDockerが実行するコマンドが含まれます.錆プロジェクトでは、マニフェストと並んでいるCargo.toml ファイル;

  • コマンドを実行するときbuild で指定したすべての画像を作成しますDockerfile . 画像の結果をコンテナに実行します.例えば、我々Dockerfile Webサーバーを構築して実行するための指示を持っている場合、イメージはプログラムを含んでいる(すなわち、Webサーバ自体).

  • ベースイメージ:我々が我々のベースに使うイメージです.例えば、私たちのために、錆ベースのイメージ(我々は手動で構築されません、我々はそれを使用する準備ができてダウンロード);

  • Container画像を実行した結果.コンテナーは、アプリケーションを実行するために必要なすべてを含むコンピュータ上で実行中のプロセスです.より良い理解のためにthis presentation by Liz Rice .

  • サンプルプロジェクト
    私は、使用して構築されたREST APIを使用するつもりですwarp . 自分でビルドしたいなら、チェックしてくださいない場合は、無料でそれをダウンロードしたり、独自のプロジェクトを使用してください;私は、あなたがコマンドを写像する問題がないと思っています.

    There are a few differences between the code you'll find in the guide and the one I am using here:

    • I am now using IP 0.0.0.0 instead of 127.0.0.1. I changed this so I don't have to tell Docker which IP to bind;
    • The old version has two crates: binary (main.rs) and library (lib.rs). That made things harder for Docker (and would make my explanations here too complex) so I just maintained the binary crate and moved the library crate content to a module.


    第一Dockerfile

    This and all other files are available . You will identify them by their numbers.


    私は非常にシンプルなバージョンから始めて、それを数回改善します.ここでは、私が上記のプロジェクトに取り組んでいますholodeck (プロジェクトを使用している場合は変更する必要があります).
    # 1. This tells docker to use the Rust official image
    FROM rust:1.49
    
    # 2. Copy the files in your machine to the Docker image
    COPY ./ ./
    
    # Build your program for release
    RUN cargo build --release
    
    # Run the binary
    CMD ["./target/release/holodeck"]
    
    これにより、以下のコマンドを実行しますDockerfile そうです.
    $ docker build -t holodeck .
    
    これはイメージを作成します.それを確認するには、あなたのDockerアプリを見たり、コマンドを使用することがありますdocker images .
    $ docker images
    REPOSITORY  TAG       IMAGE ID       CREATED          SIZE
    holodeck    latest    aad6ff7c3b4d   47 seconds ago   2.42GB
    
    これを実行するには、次のようにコマンドを発行します.
    $ docker run -p 8080:3030 --rm --name holodeck1 holodeck
    Warp 6, Engage!
    
    パラメータを展開します.
  • -p ポートをマップするので、Dockerの中の3030(港が我々のワープサーバーが使用している)は8080外で、すなわち、あなたのマシン(あなたがそうしないならば、Dockerはランダムなポートをマップします)を通してアクセス可能です
  • --rm 閉じるこの動画はお気に入りから削除されています--rm それから実行docker ps -a すべてのコンテナをリストしてからdocker rm containername を削除する).
  • 今では、それをテストすることが可能ですlocalhost:8080 .
    $ curl --location --request POST 'localhost:8080/holodeck' \
    --header 'Content-Type: application/json' \
    --header 'Content-Type: text/plain' \
    --data-raw '{
        "id": 2,
        "name": "Bride Of Chaotica!"
    }'
    
    Simulation #1 created.
    
    容器を止める
    $ docker stop holodeck1
    holodeck1
    
    あなたが私のようなイメージを走らせるならば、あなたの端末は凍られます.これを避けるために、パラメータを追加することによって-d :
    $ docker run -dp 8080:3030 --rm --name holodeck1 holodeck
    
    すごい!これはすばらしい.何度も何度も何度もビルドしなければならない(ということもありますが).なぜこれが問題なのか.コンパイル時間.毎回走るdocker build , 錆は、すべての建物のプロセス再びすべての;そして、我々がリリースのために建設している事実は、それをより悪くします.
    それを直しましょう.

    二番目Dockerfileこれはより具体的な選択肢です.
    # Rust as the base image
    FROM rust:1.49
    
    # 1. Create a new empty shell project
    RUN USER=root cargo new --bin holodeck
    WORKDIR /holodeck
    
    # 2. Copy our manifests
    COPY ./Cargo.lock ./Cargo.lock
    COPY ./Cargo.toml ./Cargo.toml
    
    # 3. Build only the dependencies to cache them
    RUN cargo build --release
    RUN rm src/*.rs
    
    # 4. Now that the dependency is built, copy your source code
    COPY ./src ./src
    
    # 5. Build for release.
    RUN rm ./target/release/deps/holodeck*
    RUN cargo install --path .
    
    CMD ["holodeck"]
    

    I am using install, but this is the same as build, except that it places the binary on the indicated path, in this case, the WORKDIR.


    このようにしてコンパイラaeonを回避します.新しいプログラムに接続された依存性だけを構築することによってDockerfile , 我々のプログラム(コマンド4と5)を構築してください、我々はキャッシュを無視してDockerを止めます.なぜそれは機能しますか?何故なら私たちのすべての命令だからですDockerfile 新規作成layer , これは画像の変更です.我々が走るときdocker build , 修正された層だけが更新され、残りはローカルキャッシュから取得されます.実際には、マニフェストを変更しない限り、依存関係を再構築する必要はありません.
    私のケースでは、323.6秒を取った最初のビルドの後、2番目の1つ(私はちょうど変更しました)main.rs ) のみ33.9秒かかりました.すごい!
    しかし...別の問題があります:イメージサイズ.たとえば、私のものは1.65 GBを持ちました.Let's put a little fixin' on it .

    第三DockerfileIsaacのポストを訪れたら、2つのベースイメージを使って「連鎖する」ビルドでこれを管理しているのがわかるでしょう.彼は最初から何でもしたFROM rust , これは、すべてが構築され、別のと呼ばれるビルドですFROM rust , 最初のビルドから必要なファイルだけをコピーします.これは最終的なイメージがこれらの最後のコピーされたファイルだけを保持するのを許します、したがって、イメージサイズを減らします.
    このようにします.
    FROM rust:1.49 as build
    
    # create a new empty shell project
    RUN USER=root cargo new --bin holodeck
    WORKDIR /holodeck
    
    # copy over your manifests
    COPY ./Cargo.lock ./Cargo.lock
    COPY ./Cargo.toml ./Cargo.toml
    
    # this build step will cache your dependencies
    RUN cargo build --release
    RUN rm src/*.rs
    
    # copy your source tree
    COPY ./src ./src
    
    # build for release
    RUN rm ./target/release/deps/holodeck*
    RUN cargo build --release
    
    # our final base
    FROM rust:1.49
    
    # copy the build artifact from the build stage
    COPY --from=build /holodeck/target/release/holodeck .
    
    # set the startup command to run your binary
    CMD ["./holodeck"]
    
    それは、1.66 GBから1.26 GBまでイメージサイズを減らしました.しかし、私はDockerfile , それで、あなたは我々がよりよくすることができるということをすでに知っています.

    第四Dockerfile我々が今することは、我々が使っているさび画像タグを変えることです.タグは「イメージ変種」、すなわち特定の目標を満たすように設計された代替画像を言う別の方法です.それで、我々がスペースを節約しているイメージが欲しいならば.it is a tag that we're looking for .
    そして、すべてはちょうど2番目を取り替えることを意味しますFROM
    FROM rust:1.49-slim-buster
    
    このイメージタグは、Debianのタグに組み込まれた錆を使用しますbuster slim よりコンパクトなイメージを作成するには.現在、1.26 GBの代わりに、642.3 MBを持ちます.

    Some people might wonder why I didn't use Alpine. Well, I did, and buster-slim was 10MB smaller. But the real reason why I avoided Alpine will be clear in the next step.



    5番目のDockerfile私は、最小限のイメージサイズのためのこの狩りが常に必要であると思いません;あなたは理由がある.
    私が理由(あなたにそれを示す)を持っているように、私は本当に小さいDockerイメージを与える1つの最終的な変化をします.このためには、実行されるバイナリだけの錆がないイメージを必要とします(これは結局コンパイルされた言語の美しさの一つです).
    そのようなことを達成するために、我々はバイナリベースを構築するために錆びベースのイメージを使用して、ちょうどバイナリをLinuxイメージにさびないで動かします.そして、それを行うには、我々は使用されますdebian:buster-slim 自身.

    Again, regarding Alpine. I didn't use it here either for two reasons:

    1. To run a Rust code in Alpine it has to be compiled with MUSL, which adds an extra layer of complexity to this beginner-intended post;
    2. I am not sure that MUSL is a good option.

    結果:75.39 MB.それは2.42 GBから長い道のりです.
    全体的な比較をしましょう.

    それだ!今までのところ、ありがとうございました.バイ!
    カバーイメージAron Yigin