web-dev-qa-db-ja.com

Dockerを使用したコンパイル済みアプリケーションの構築

私はC++で記述されたサーバーを構築していて、Dockerを docker-compose で使用してデプロイしたいと考えています。それを行う「正しい方法」は何ですか? Dockerfileからmakeを呼び出すか、手動でビルドし、サーバーにアップロードしてから、DockerfileからCOPYバイナリをアップロードする必要がありますか?

16

docker-composeを使用してビルドを自動化するのが難しく、結局すべてにdocker buildを使用することになりました。

構築のための3つの層

実行→開発→ビルド

次に、ビルド出力を「デプロイ」イメージにコピーします。

実行→展開

遊ぶ4つのレイヤー:

  • アプリケーションの実行に必要なすべてのパッケージが含まれています(例: libsqlite3-0
  • FROM <projname>:run
  • ビルドに必要なパッケージが含まれています
    • 例えばg ++、cmake、libsqlite3-dev
  • Dockerfileは外部ビルドを実行します
    • 例えばboost-python3をビルドする手順(パッケージマネージャーリポジトリではない)
  • FROM <projname>:develop
  • ソースを含む
  • Dockerfileは内部ビルドを実行します(頻繁に変更されるコード)
  • ビルドされたバイナリは、デプロイで使用するためにこのイメージからコピーされます
  • FROM <projname>:run
  • イメージにコピーされてインストールされたビルドの出力
  • RUNまたはENTRYPOINTは、アプリケーションの起動に使用されます

フォルダー構造は次のようになります。

.
├── run
│   └── Dockerfile
├── develop
│   └── Dockerfile
├── build
│   ├── Dockerfile
│   └── removeOldImages.sh
└── deploy
    ├── Dockerfile
    └── pushImage.sh

ビルドサーバーを設定することは、実行することを意味します:

docker build -f run -t <projName>:run
docker build -f develop -t <projName>:develop

ビルドを行うたびに、これが発生します。

# Execute the build
docker build -f build -t <projName>:build

# Install build outputs
docker build -f deploy -t <projName>:version

# If successful, Push deploy image to dockerhub
docker tag <projName>:<version> <projName>:latest
docker Push <projName>:<version>
docker Push <projName>:latest

プロジェクトをビルド/実行/インストールする方法についてのドキュメントとしてDockerfilesを参照するようにします。

ビルドが失敗し、出力が調査に不十分な場合、/bin/bash<projname>:buildを実行して、何が問題かを確認することができます。


私はこのアイデアを中心に GitHubリポジトリ をまとめました。 C++ではうまく機能しますが、おそらく何にでも使用できます。


私はこの機能を調査していませんが、@ TaylorEdmistonは私のパターンは multi-stage builds と非常に似ていることを指摘しました。これは、同じことを実現するためのよりエレガントな(そしてドキュメント化された)方法のように見えます。

26

私の推奨は、コンテナ自体で完全に開発、構築、テストすることです。これにより、開発者の環境が本番環境と同じであるというDockerの哲学が保証されます。Dockerを使用するMacOS上の最新の開発者用ワークステーションを参照してください。

特に、通常は共有ライブラリ/オブジェクトファイルとの依存関係があるC++アプリケーションの場合。

DockerでC++アプリケーションを開発、テスト、デプロイするための標準化された開発プロセスはまだ存在していないと思います。

あなたの質問に答えるために、現時点での私たちのやり方は、コンテナーを開発環境として扱い、次のような一連のプラクティスをチームに適用することです。

  1. 私たちのコードベース(設定ファイルを除く)は常に(ローカルマシン上の)共有ボリュームにあります(Gitでバージョン管理されています)
  2. 共有/依存ライブラリ、バイナリなどalwaysコンテナ内に存在
  3. コンテナでビルドしてテストし、イメージをコミットする前に、不要なオブジェクトファイル、ライブラリなどをクリーンアップして、docker diff変更は期待どおりです
  4. 共有ライブラリ、依存関係を含む環境の変更/更新は常に文書化され、チームと通信されます。
6
blueskin

更新

2017年以降にこの質問にアクセスする方は、 マルチアンサーDockerビルド の使用について the answer by fuglede を参照してください。私の回答(下記)は、それが利用可能になるずっと前の2015年からのものです。


古い答え

私が行う方法は、コンテナーの外でビルドを実行し、ビルドの出力(バイナリーと必要なライブラリー)のみをコンテナーにコピーすることです。次に、コンテナーをコンテナーレジストリにアップロードし(たとえば、ホストされているものを使用するか、独自のコンテナーを実行します)、そのレジストリから運用マシンにプルします。したがって、フローは次のようになります。

  1. バイナリを構築する
  2. binary自体をテスト/正常性チェック
  3. バイナリでコンテナイメージをビルドする
  4. バイナリでコンテナイメージをテスト/サニティチェックします
  5. コンテナーレジストリにアップロードする
  6. レジストリから取得して、staging/test/qaにデプロイします
  7. レジストリから取得して製品にデプロイする

プロダクションデプロイメントの前にテストすることが重要であるため、本番環境にデプロイするのとまったく同じものをテストしたいので、Dockerイメージをビルドした後に何らかの方法で抽出または変更したくありません。

私は、製品にデプロイする予定のコンテナーのビルドの内側を実行しません。コンテナーには、あらゆる種類の追加のアーティファクト(一時的なビルドなど)が含まれるためです。出力、ツールなど)。本番環境では不要であり、デプロイに使用しないものでコンテナイメージを不必要に拡張します。

6
Misha Brukman

他の回答で提示された解決策、特にコメントへのMisha Brukmanの提案 この回答 1つのDockerfileを開発用と1つを本番用に使用することについて-は、当時は慣用的と見なされます質問が書かれました、彼らが解決しようとしている問題-特に、開発と本番環境で同じコンテナ環境を使用しながら、イメージサイズを減らすためにビルド環境をクリーンアップする問題-に注意してくださいDocker 17.05で導入されたマルチステージビルドによって効果的に解決されました。

ここでのアイデアは、Dockerfileを2つの部分に分割することです。1つは完全なDebianベースイメージなど、お気に入りの開発環境に基づいており、最後にデプロイするバイナリの作成に関係しています。日、そしてアルパインのような最小限の環境でビルドされたバイナリを実行する別の日。

このようにして、コメントの1つでブルースキンが示唆しているように、開発環境と本番環境の間の不一致の可能性を回避しながら、プロダクションイメージが開発ツールで汚染されないようにします。

ドキュメントには、次のGoアプリケーションのマルチステージビルドの例が示されています。これは、C++開発環境に採用されます(1つは、アルパインが musl を使用しているため、注意が必要な場合があります)。開発環境でのリンク)。

FROM golang:1.7.3
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html  
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM Alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]
5
fuglede