Dockerfile を使用してソースコードをコンテナイメージにビルドし、そのイメージを配布・デプロイします。Java プロジェクトは、Golang や Python プロジェクトよりもコンテナ化が難しく、ビルドが遅くなる傾向があります。多くの企業では、Maven などの自己管理型の依存関係リポジトリに依存しており、開発者は Dockerfile のキャッシュメカニズムに不慣れなことがよくあります。このトピックでは、クラウド上の自己管理型 GitLab コードリポジトリと自己管理型 Maven リポジトリという典型的なシナリオから始めます。Dockerfile を使用して Java プロジェクトをビルドする方法と、各ビルドを高速化する方法を説明します。また、Container Registry Enterprise Edition (ACR EE) のビルドサービスを使用してイメージビルドを自動化する方法も紹介します。
前提条件
-
GitLab コードリポジトリを作成済みであること。
-
Maven リポジトリを作成済みであること。
-
Container Registry Enterprise Edition インスタンスを作成済みであること。詳細については、「Enterprise Edition インスタンスの作成」をご参照ください。
プロジェクト概要
このトピックでは、相互に依存する 2 つの Java プロジェクトを使用したビルドプロセスを例示します。プロジェクトは以下の通りです:
-
Provider:呼び出し可能なサービスを提供します。
-
Core モジュール:パブリックインターフェイスを提供します。
-
Service モジュール:サービス実装モジュールです。
-
-
Consumer:Provider サービスを呼び出します。
-
Service モジュール:Provider プロジェクトの Core モジュールに依存します。次のコードは一例です:
. ├── consumer │ ├── Dockerfile │ ├── consumer.iml │ ├── pom.xml │ └── service │ ├── pom.xml │ ├── src │ └── target └── provider ├── Dockerfile ├── core │ ├── pom.xml │ ├── src │ └── target ├── pom.xml ├── provider.iml └── service ├── pom.xml ├── src └── target
-
ビルド成果物:
-
Provider プロジェクトからビルドされたプロデューサーアプリケーションイメージ。
-
Consumer プロジェクトからビルドされたコンシューマーアプリケーションイメージ。
手順 1: 共有依存関係のデプロイ
Consumer プロジェクトをビルドする前に、それが依存する Provider プロジェクトの成果物を自己管理型 Maven リポジトリにデプロイする必要があります。Provider プロジェクトのディレクトリで次のコマンドを実行します:
mvn clean install org.apache.maven.plugins:maven-deploy-plugin:2.8:deploy -DskipTests
手順 2: カスタム Maven ベースイメージの作成
コンテナ化されたビルド環境で自己管理型 Maven リポジトリにアクセスするには、Maven リポジトリの設定をベースイメージに追加します。公式の Maven イメージを基に、企業向けのカスタムのパブリック Maven ベースイメージを作成します。これにより、アプリケーションプロジェクトはこのベースイメージを参照して Maven リポジトリにアクセスできるようになります。
-
次の内容を Dockerfile として保存し、Maven リポジトリの settings.xml ファイルと同じディレクトリに配置します。
FROM maven:3.8-openjdk-8 # プロジェクトに適合する Maven イメージを使用します。この例では Maven 3.8 を使用します。 ADD settings.xml /root/.m2/ # 自己管理型 Maven リポジトリの設定を指定されたパスに追加します。 -
次のコマンドを実行してイメージをビルドし、リモートのイメージリポジトリにプッシュします。
ls Dockerfile settings.xml docker build -t demo-registry-vpc.cn-beijing.cr.aliyuncs.com/demo/maven-base:3.8-openjdk-8 -f Dockerfile . Sending build context to Docker daemon 7.68kB Step 1/2 : FROM maven:3.8-openjdk-8 ---> a3f42bfde036 Step 2/2 : ADD settings.xml /root/.m2/ ---> db0d5a5192e3 Successfully built db0d5a5192e3 Successfully tagged demo-registry-vpc.cn-beijing.cr.aliyuncs.com/demo/maven-base:3.8-openjdk-8 docker push demo-registry-vpc.cn-beijing.cr.aliyuncs.com/demo/maven-base:3.8-openjdk-8
手順 3: Consumer アプリケーションイメージのビルド (Provider プロジェクトは対象外)
次のコマンドを実行します。(ビルドプロセス中に必要なすべてのベースイメージを Alibaba Cloud イメージリポジトリにプッシュしてください。)
FROM demo-registry-vpc.cn-beijing.cr.aliyuncs.com/demo/maven-base:3.8-openjdk-8 AS builder
# pom.xml とソースコードを追加します
ADD ./pom.xml pom.xml
ADD ./service service/
# JAR をパッケージ化します
RUN mvn clean package
# 第 2 段階:最小ランタイム環境
From demo-registry-vpc.cn-beijing.cr.aliyuncs.com/demo/openjdk:8-jre-alpine
# 第 1 段階から JAR をコピーします
COPY --from=builder service/target/service-1.0-SNAPSHOT.jar service-1.0-SNAPSHOT.jar
EXPOSE 8080
CMD ["java", "-jar", "service-1.0-SNAPSHOT.jar"]
手順 4: ビルド速度の最適化
「手順 3: Consumer アプリケーションイメージのビルド (Provider プロジェクトは対象外)」でイメージをビルドしました。しかし、コードを修正して再ビルドすると、キャッシュを使用せずに JAR パッケージを再度ダウンロードするため、ビルドプロセスが遅いことに気づくでしょう。Docker は、レイヤーのコンテンツが変更されると、そのレイヤーのキャッシュを無効にします。ソースコードを修正すると、ADD 命令内のファイルのハッシュが変更されます。この変更により、RUN 命令が強制的に再実行され、前回のビルドのキャッシュが無視されます。詳細については、「Dockerfile のベストプラクティス」をご参照ください。
ビルド速度を最適化するために、Maven の依存関係をキャッシュして再利用します:
-
まず、プロジェクトの pom.xml ファイルをコンテナにコピーして、依存関係をダウンロードします。pom.xml ファイルが変更されない限り、後続のビルドではキャッシュを使用できます。
-
プロジェクトのソースコードをコピーしてコンパイルします。
以下は改良版の Dockerfile です。最初のビルドには 43 秒かかります。ソースコードのみを変更した場合、後続のビルドは 7 秒で完了します。
FROM demo-registry-vpc.cn-beijing.cr.aliyuncs.com/demo/maven-base:3.8-openjdk-8 AS builder
# 依存関係を解決し、ソースコードの変更時に再ダウンロードしないようにします
ADD ./pom.xml pom.xml
ADD ./service/pom.xml service/pom.xml
RUN mvn dependency:go-offline
ADD ./service service/
# JAR をパッケージ化します
RUN mvn clean package
# 第 2 段階:最小ランタイム環境
From demo-registry-vpc.cn-beijing.cr.aliyuncs.com/demo/openjdk:8-jre-alpine
# 第 1 段階から JAR をコピーします
COPY --from=builder service/target/service-1.0-SNAPSHOT.jar service-1.0-SNAPSHOT.jar
EXPOSE 8080
CMD ["java", "-jar", "service-1.0-SNAPSHOT.jar"]
手順 5: Container Registry Enterprise Edition によるビルドプロセスの自動化
ACR EE はエンタープライズレベルのビルドサービスを提供し、エンタープライズのお客様に推奨されます。 詳細については、「エンタープライズ版インスタンスを使用してイメージをビルドするエンタープライズ版インスタンスを使用してイメージをビルドする」をご参照ください。
以下のセクションでは、いくつかのベストプラクティスを概説します。
-
VPC ビルドモードの使用
クラウド上のセルフマネージド GitLab インスタンスでは、セキュアな VPC ビルドモードを使用してイメージをビルドします。これにより、サービスがパブリックインターネットに公開されるのを防ぎます。詳細については、「セキュアな VPC モードでコンテナイメージをビルドするセキュアな VPC モードでコンテナイメージをビルドする」をご参照ください。
-
イミュータブルイメージバージョン機能の使用
リポジトリのイミュータブルイメージバージョン機能を有効にすると、オンラインバージョンが上書きされるのを防ぐことができます。[Create Image Repository] ページの [Repository Information] ステップで、[Image Version] の [Immutable] チェックボックスをオンにします。チェックボックスをオンにすると、リポジトリ内の
latestを除くどのイメージバージョンも上書きできなくなります。これにより、コンテナイメージのバージョンの一貫性が保たれます。 -
コミット ID に基づくビルドルールの作成
各ビルドで 2 つのイメージバージョンが生成されます。1 つのバージョンはコードのコミット ID を使用するため、イメージバージョンをコードバージョンに対応付けることができます。もう 1 つのバージョンは
latestを使用して最新バージョンを示します。[Modify Building Rule] ダイアログボックスの [Image Version] ステップで、[Commit ID] と [latest] のイメージバージョンが設定されています。コードをコミットしてビルドをトリガーします。次の例は、2 つのコードコミットによって自動的にトリガーされた 2 つのビルドを示しています。各ビルドで 2 つのイメージが生成され、2 回目のビルドはキャッシュが効くため高速になります。ビルド設定ページでは、[コード変更時のイメージ自動ビルド] スイッチが有効になっています。ビルドルールの設定では、ブランチが
branches:masterに、ビルドコンテキストディレクトリが/に、Dockerfile 名がDockerfileに設定されています。イメージバージョンには、コミット ID バージョンと最新バージョンに対応する [Configuration 1] と [Configuration 2] の 2 つのタグが含まれています。ビルドログには、両方のビルドが正常に完了し、それぞれ 106 秒と 85 秒かかったことが示されています。