Buildpacksの紹介記事の便乗です.
Nixはパッケージマネージャの一種で,決定的なビルドを提供することを主眼としています.この記事では,Nixを使って更に小さいDockerイメージを構築することを目指します.
アプリのビルド
今回は元記事と同じくJavaアプリをビルドしてみます.
Nixはビルドの決定性を維持するために,アプリケーションの依存関係を厳密に追跡する必要があり,これにはアプリケーションの使用しているライブラリも含まれています.
そこで,Nixの世界では各プログラミング言語のパッケージマネージャの情報をNixに渡してあげるツールがよく用いられます.
今回はJavaなので,mavenixを使用します.
まずは,Nivを使ってmavenixをプロジェクトローカルにダウンロードします.
[~/buildpacks/samples/apps/java-maven]$ niv init
Initializing
Creating nix/sources.nix
Creating nix/sources.json
Importing 'niv' ...
Adding package niv
Writing new sources file
Done: Adding package niv
Importing 'nixpkgs' ...
Adding package nixpkgs
Writing new sources file
Done: Adding package nixpkgs
Done: Initializing
[~/buildpacks/samples/apps/java-maven]$ niv add nix-community/mavenix
Adding package mavenix
Writing new sources file
Done: Adding package mavenix
次のshell.nix
を使ってmavenixがインストールされた開発環境を構築します.Nixではプロジェクトごとの開発ツールをグローバルにインストールする必要が無いのです!
# shell.nix
{ sources ? import ./nix/sources.nix }:
let
pkgs = import sources.nixpkgs {};
mavenix = (import sources.mavenix { inherit pkgs; }).cli;
in
pkgs.mkShell {
buildInputs = [
mavenix
];
}
開発環境の起動にはnix-shell
を使いましょう.
[~/buildpacks/samples/apps/java-maven]$ nix-shell
これでmavenixが使えるようになりました.mvnix-init
でdefault.nix
を生成します.default.nix
はNixにアプリケーションをビルドする方法を伝えるためのファイルです.今回の場合はmavenixによってMavenアプリ用のテンプレートが出力されます.
[~/buildpacks/samples/apps/java-maven]$ mvnix-init
Creating files:
./default.nix
1. Configure by editing './default.nix'
2. Create a lock file by running 'mvnix-update "./default.nix"'
3. Build your project 'nix-build "./default.nix"
このインストラクションに従うとアプリのビルドが完了します.
[~/buildpacks/samples/apps/java-maven]$ mvnix-update
...時間がかかる...
[~/buildpacks/samples/apps/java-maven]$ nix-build --no-out-link
nix/store/ph7mw7lja1i3b8m7lwa1746r297l5bg8-sample-0.0.1-SNAPSHOT
出力されたパスにビルド結果が出力されているのを確認しましょう.
[~/buildpacks/samples/apps/java-maven]$ ls -lh /nix/store/ph7mw7lja1i3b8m7lwa1746r297l5bg8-sample-0.0.1-SNAPSHOT/share/java/
total 18M
-r--r--r-- 1 root root 18M Jan 1 1970 sample-0.0.1-SNAPSHOT.jar
-r--r--r-- 1 root root 137 Jan 1 1970 sample-0.0.1-SNAPSHOT.metadata.xml
-r-xr-xr-x 1 root root 1.4K Jan 1 1970 sample-0.0.1-SNAPSHOT.pom
-r--r--r-- 1 root root 72 Jan 1 1970 sample-0.0.1-SNAPSHOT.properties
ローカルで起動することもできます.
[~/buildpacks/samples/apps/java-maven]$ nix-shell -p jdk # OpenJDKを一時的にインストール
[~/buildpacks/samples/apps/java-maven]$ java -jar /nix/store/ph7mw7lja1i3b8m7lwa1746r297l5bg8-sample-0.0.1-SNAPSHOT/share/java/sample-0.0.1-SNAPSHOT.jar
Dockerイメージのビルド
それでは,このアプリケーション用のDockerコンテナを作成しましょう.これもNixを使うと簡単です!
コンテナ内にJavaを入れたいので,default.nix
を修正します.
# default.nix
# This file has been generated by mavenix-2.3.3. Configure the build here!
let
mavenix-src = fetchTarball { url = "https://github.com/nix-community/mavenix/tarball/v2.3.3"; sha256 = "1l653ac3ka4apm7s4qrbm4kx7ij7n2zk3b67p9l0nki8vxxi8jv7"; };
in {
# pkgs is pinned to 19.09 in mavenix-src,
# replace/invoke with <nixpkgs> or /path/to/your/nixpkgs_checkout
pkgs ? (import mavenix-src {}).pkgs,
mavenix ? import mavenix-src { inherit pkgs; },
src ? ./.,
doCheck ? false,
}: mavenix.buildMaven {
inherit src doCheck;
infoFile = ./mavenix.lock;
buildInputs = [
pkgs.jre_headless
pkgs.makeWrapper
];
postInstall = ''
# install java
makeWrapper ${pkgs.jre_headless}/bin/java $out/bin/java \
--add-flags "-jar $out/share/java/sample-0.0.1-SNAPSHOT.jar"
# create /tmp for Spring framework
mkdir $out/tmp
chmod 777 $out/tmp
'';
}
ここでは,buildInputs
のところでにJREを追加し,postInstall
フックでJavaバイナリを/bin
に配置しています.また,Springが実行時に/tmp
に書き込むのでディレクトリを作成しています.
次の内容でDockerfile.nix
を用意します.ハイ,Dockerfile
は書かなくともNixファイルが必要なのです.
{ sources ? import ./nix/sources.nix }:
let
pkgs = import sources.nixpkgs {};
app = import ./default.nix {};
in
pkgs.dockerTools.buildImage {
name = "example";
tag = "latest";
contents = app;
# エントリポイント
config.Cmd = [
"/bin/server"
];
}
標準のDockerfileではなく,Nixを使ってDockerイメージを作成しています.Dockerfileでは操作(apt install
)を記述するのに対し,Nixを使った場合は内容を記述します.
今回の場合は先程作成したアプリのパッケージ(./default.nix
)だけをコンテナ内に持つように指定しています.
ビルド方法はアプリのときと同じです.
[~/buildpacks/samples/apps/java-maven]$ nix-build Dockerfile.nix --no-out-link
/nix/store/b8l5qssgiylc8yi4f8y2ybz83l4nqbrp-docker-image-example.tar.gz
このイメージはdocker load -i
で読み込めます.
[~/buildpacks/samples/apps/java-maven]$ docker load -i /nix/store/b8l5qssgiylc8yi4f8y2ybz83l4nqbrp-docker-image-example.tar.gz
66dd4ba45ad5: Loading layer [==================================================>] 174.5MB/174.5MB
The image example:latest already exists, renaming the old one with ID sha256:76903c2f6febfd083934876f42a64e0bfd18442e80093b3c1021c97d81a35825 to empty string
Loaded image: example:latest
実行してみましょう.
[~/buildpacks/samples/apps/java-maven]$ docker run -p 8080:8080 example:latest
やりました!
サイズも173MBと上出来ですね😎
[~/buildpacks/samples/apps/java-maven]$ docker images | grep example
example latest 4c866b80b51a 50 years ago 173MB
Top comments (0)