技術系(Tips)
PR

Ubuntu 22.04 から openjdk-19 が消えた話 ── nginx-clojure の Docker build が壊れた原因と Java 17 への退避

saratogax
記事内に商品プロモーションを含む場合があります

ある日突然、これまで何年も通っていた docker build が、「openjdk-19-jdk-headless が見つからない」というエラーで失敗するようになりました。

ベースイメージは ubuntu:22.04、コンテナ内では nginx-clojure を組み込んだ Nginx をビルドしている、というよくある構成です。

本記事では、なぜこの問題が起きたのか、そしてなぜ nginx-clojure が非 LTS の Java 19 を要求していたのかを調べた記録をまとめます。

同じように Docker build が壊れて困っている方、あるいは「LTS じゃないバージョンを依存ライブラリが要求してくる現象」とどう向き合うか考えている方の参考になれば幸いです。

問題の現象

壊れた Dockerfile の該当箇所は以下のようなシンプルな apt-get install です。

apt-get -y install openjdk-19-jdk-headless

これがある日から、「Unable to locate package openjdk-19-jdk-headless」のような形で失敗するようになりました。

このコンテナは nginx-clojure というモジュールを Nginx に組み込んでビルドするため、Java(OpenJDK)が必須です。

ビルドが通らないとイメージを更新できず、デプロイパイプラインが止まる、というインパクトの大きい問題でした。

原因 ── openjdk-19 は Ubuntu の universe から正式に削除されている

結論から言うと、openjdk-19 系のパッケージは Ubuntu 22.04 (jammy) の universe から正式に削除されています

これは推測ではなく、Ubuntu Foundations Team による公式アナウンスがあります。

2025 年 9 月 2 日付で Ubuntu Discourse の Announcements カテゴリに「OpenJDK 19 removal from Ubuntu 22.04 LTS (Jammy Jellyfish)」というタイトルでアナウンスが掲示されました。

要旨は「OpenJDK 19 はインテリム(非 LTS)リリースで上流が EOL に達したため、jammy LTS の universe から 2025 年 10 月までに削除する」というもので、その後 Foundations Team Updates の作業ログでも実施が確認できます。

削除対象は openjdk-19 ソースから生成される全バリアント(-jdk / -jdk-headless / -jre / -jre-headless / -jre-zero / -dbg / -doc / -source)で、jammy / jammy-updates / jammy-security のすべてから消えています。

Ubuntu 22.04 の universe には、リリース当初は openjdk-8 / 11 / 17 / 18 / 19 など複数のバージョンが入っていましたが、非 LTS バージョン(OpenJDK 12, 13, …, 18, 19)はサポート期間が短いため、上流の EOL に合わせて順次削除されてきた、というのが Ubuntu 側の方針です。

OpenJDK 19 自体は Oracle のリリースモデル上、2022 年 9 月にリリースされ、2023 年 3 月には次の 20 が出てサポート終了という、わずか半年寿命のバージョンでした。

Ubuntu 側がこれを長期間維持するインセンティブはなく、今回の削除は方針どおりの正規の措置と言えます。

OpenJDK種別リリースUbuntu 22.04 universe
11LTS2018-09維持
17LTS2021-09維持
18非 LTS2022-03削除済み
19非 LTS2022-09削除済み
21LTS2023-09維持
※表は横スクロールできます

表のとおり、apt から取得し続けたいなら LTS 系(11/17/21)に揃えるのが現実的、ということになります。

そもそもなぜ nginx-clojure は Java 19 を指定していたのか

ここで気になる疑問が出てきます。

Java の LTS は 8, 11, 17, 21 と続いており、普通に考えれば 17 LTS を指定するのが自然です。

それなのに、なぜ Dockerfile では非 LTS の openjdk-19-jdk-headless を使っていたのでしょうか。

nginx-clojure の README を確認すると、サポート対象 Java バージョンとして以下のように記載されていました。

  • 「Support Java 8, 9, 10, 11, 12, 19」
  • 「Support to use jdk19 built-in coroutine viz. Continuation」

2 行目が決定的でした。

nginx-clojure はJDK 19 でビルトインで導入された Continuation API(Project Loom 由来)を使う機能をサポートしているため、機能フルセットを使うときの推奨バージョンとして 19 を挙げていたのです。

Project Loom と Continuation API ── なぜ 19 だったのか

Project Loom は、Java に軽量スレッド(Virtual Threads)と協調的な実行制御(Continuation)を導入する OpenJDK のプロジェクトです。

このうち jdk.internal.vm.Continuation という内部 API が JVM に実装として組み込まれたのが、JDK 19 です。

nginx-clojure はリクエスト処理にコルーチン的な仕組みを使っているため、JVM ネイティブの Continuation が使えると、独自実装よりもシンプルかつ効率的に処理を書けます。

これが、nginx-clojure 側で「Java 19」が前面に出ていた理由です。

バージョンProject Loom 関連の主な状況
JDK 17Continuation / Virtual Threads は未導入
JDK 19Virtual Threads がプレビュー導入。jdk.internal.vm.Continuation が利用可能に
JDK 21Virtual Threads が正式機能化(LTS)
※表は横スクロールできます

本来なら、nginx-clojure を Continuation 込みで使いたい場合の現代的な選択は JDK 21 LTS です。

ただし nginx-clojure 0.6.0 の README が更新されたタイミングでは 21 がまだリリース前後だったため、明示されているのが 19 のまま、という事情があります。

17 にダウングレードしても本当に動くのか

「19 は Continuation のために指定されている」とわかったことで、次の論点が見えてきます。

Continuation 機能を実際に使っていなければ、17 にダウングレードしても問題ないのでは?

nginx-clojure の README をさらに読むと、サポート対象として「Java 8, 9, 10, 11, 12, 19」と並んでいることがわかります。

17 が明示されていないのは「テストしていないだけ」であり、17 が動かないという意味ではないと読むのが自然です。

判断材料として、nginx-clojure を起動するときの jvm_options 設定を確認しました。

具体的には、運用中のサービスでは以下のような --add-opens しか指定していませんでした。

  • --add-opens=java.base/java.lang=ALL-UNNAMED
  • --add-opens=java.base/sun.nio.cs=ALL-UNNAMED
  • --add-opens=java.base/sun.nio.ch=ALL-UNNAMED

もし Continuation 機能を使っていれば、--add-opens=java.base/jdk.internal.vm=ALL-UNNAMED のようにJDK 内部モジュールを開く設定が必要になるはずです。

その指定がないということは、Continuation の機能を実際には使っていない、と判断できます。

この事実から、17 へのダウングレードによる機能的な影響はほぼ無い見込み、と判断できました。

対応 ── Dockerfile を 17 に書き換える

調査で方針が立ったので、Dockerfile を Java 17 に書き換えます。

変更点は 2 行のみです。

変更前

openjdk-19-jdk-headless

ln -s /usr/lib/jvm/java-19-openjdk-amd64 /usr/lib/jvm/default-jvm

変更後

openjdk-17-jdk-headless

ln -s /usr/lib/jvm/java-17-openjdk-amd64 /usr/lib/jvm/default-jvm

ローカルで docker build を実行したところ、無事に成功しました。

nginx の ./configure 段階で参照している jni.h も Java 17 のヘッダで問題なくコンパイルが通り、ビルド成果物まで作られています。

教訓 ── 非 LTS の Java を本番で使うリスク

今回の問題は、非 LTS の Java バージョンを本番イメージで使い続けるリスクを浮き彫りにしました。

OpenJDK の非 LTS バージョンは半年で次のバージョンに置き換わる前提で設計されており、ディストリビューションの apt リポジトリも、これに合わせて遅かれ早かれパッケージを削除します。

これは「いつかは壊れる」既定路線であり、今回の Docker build 失敗は時間の問題で発生していたと言えます。

同じ轍を踏まないために、依存ライブラリの README に非 LTS バージョンが明示されていた場合、以下の判断軸を持っておくと安全です。

  1. そのバージョン固有の機能を本当に使っているかjvm_options--add-opens から確認する
  2. 使っていなければ、直近の LTS(17 または 21)にピン留めして運用する
  3. 本当に必要なら、apt ではなく公式 OpenJDK バイナリ(Adoptium / Temurin など)を直接ダウンロードしてイメージに同梱する

3 の方法は apt の都合に左右されないので、非 LTS をどうしても使い続けたい場合の現実的な選択肢になります。

まとめ

  • Ubuntu 22.04 の universe からは、非 LTS の OpenJDK(18, 19 など)は上流 EOL に合わせて順次削除されている。openjdk-19 については 2025 年 9 月の Ubuntu Foundations Team の公式アナウンスで削除がアナウンスされ、同年 10 月に実施済み。apt から取得することはできない。
  • nginx-clojure が 19 を明示していた理由は、JDK 19 で導入された Continuation API を使う機能のため。19 が必須なわけではない。
  • Continuation 機能を使っていない(--add-opens=java.base/jdk.internal.vm 系の指定が無い)プロジェクトでは、Java 17 LTS にダウングレードして問題ない
  • 長期的には、依存先が非 LTS を要求してくる場合の方針(LTS にピン留め / 公式バイナリ同梱)を決めておくと、今回のような事故を未然に防げる。

「ある日突然 Docker build が壊れる」系の障害は、原因が apt 側のパッケージ削除という自分のコード以外の場所にあるため、慣れていないと特定に時間がかかります。

同じ問題に遭遇した方の参考になれば幸いです。

ABOUT ME
saratoga
saratoga
フリーランスエンジニア
仕事にも趣味にも IT を駆使するフリーランスエンジニア。技術的な TIPS や日々の生活の中で深堀りしてみたくなったことを備忘録として残していきます。
記事URLをコピーしました