diff --git a/Dockerfile b/Dockerfile index 87f9b787..8c627aaa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,6 +18,29 @@ ARG DEBIAN_VERSION=trixie-20260316-slim ARG BUILDER_IMAGE="docker.io/hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}" ARG RUNNER_IMAGE="docker.io/debian:${DEBIAN_VERSION}" +# ---- wgrib2 build stage (cached independently) ---- +FROM ${RUNNER_IMAGE} AS wgrib2-builder + +ARG WGRIB2_VERSION=3.6.1 + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + build-essential gfortran wget ca-certificates \ + zlib1g-dev libaec-dev libpng-dev \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /tmp/wgrib2 + +RUN wget -q "https://www.ftp.cpc.ncep.noaa.gov/wd51we/wgrib2/wgrib2.tgz.v${WGRIB2_VERSION}" \ + -O wgrib2.tgz \ + && tar xzf wgrib2.tgz \ + && cd grib2 \ + && export CC=gcc FC=gfortran \ + && make \ + && cp wgrib2/wgrib2 /usr/local/bin/wgrib2 \ + && strip /usr/local/bin/wgrib2 + +# ---- Elixir build stage ---- FROM ${BUILDER_IMAGE} AS builder # install build dependencies @@ -66,12 +89,13 @@ COPY config/runtime.exs config/ COPY rel rel RUN mix release -# start a new build stage so that the final image will only contain -# the compiled release and other runtime necessities +# ---- Final runtime stage ---- FROM ${RUNNER_IMAGE} AS final RUN apt-get update \ - && apt-get install -y --no-install-recommends libstdc++6 openssl libncurses6 locales ca-certificates snmp \ + && apt-get install -y --no-install-recommends \ + libstdc++6 openssl libncurses6 locales ca-certificates snmp \ + libgfortran5 libaec0 zlib1g libpng16-16t64 \ && rm -rf /var/lib/apt/lists/* # Set the locale @@ -88,6 +112,9 @@ RUN chown nobody /app # set runner ENV ENV MIX_ENV="prod" +# Copy wgrib2 binary from the build stage +COPY --from=wgrib2-builder /usr/local/bin/wgrib2 /usr/local/bin/wgrib2 + # Only copy the final release from the build stage COPY --from=builder --chown=nobody:root /app/_build/${MIX_ENV}/rel/microwaveprop ./ diff --git a/lib/microwaveprop/weather/grib2/wgrib2.ex b/lib/microwaveprop/weather/grib2/wgrib2.ex index 67e43b0d..63e457e9 100644 --- a/lib/microwaveprop/weather/grib2/wgrib2.ex +++ b/lib/microwaveprop/weather/grib2/wgrib2.ex @@ -9,7 +9,6 @@ defmodule Microwaveprop.Weather.Grib2.Wgrib2 do require Logger - @wgrib2_path System.find_executable("wgrib2") @undefined_value 9.999e20 @doc """ @@ -29,9 +28,9 @@ defmodule Microwaveprop.Weather.Grib2.Wgrib2 do end @doc "Check if wgrib2 is available on the system." - def available? do - @wgrib2_path != nil - end + def available?, do: wgrib2_path() != nil + + defp wgrib2_path, do: System.find_executable("wgrib2") defp extract_with_wgrib2(grib_binary, match_pattern, grid_spec) do %{ @@ -68,7 +67,7 @@ defmodule Microwaveprop.Weather.Grib2.Wgrib2 do "bin" ] - case System.cmd(@wgrib2_path, args, stderr_to_stdout: true) do + case System.cmd(wgrib2_path(), args, stderr_to_stdout: true) do {output, 0} -> # Parse message inventory from stdout to know which vars were extracted messages = parse_wgrib2_inventory(output)