Docker 中离线/半离线安装 GDAL 完整指南(ARM64 + Debian 11 bullseye 基础镜像)

适用场景:需要在 Docker 容器(尤其是 ARM64 架构、基于 Debian 11 的 openjdk:8 镜像)中安装 GDAL,用于栅格图像格式转换(如 ERDAS Imagine .img → GeoTIFF .tif),且服务器环境网络受限或希望尽量减少依赖网络。

背景

在某个在线评价平台项目中,Java 服务容器需要使用 GDAL 命令行工具 ​​gdal_translate​​ 来实现遥感图像格式转换(IMG → TIF)。

最初尝试通过宿主机预编译 GDAL 二进制 + 卷挂载方式,但由于架构不匹配(宿主机 x86_64 vs 容器 aarch64)导致完全失败。

最终采用构建自定义 Docker 镜像的方式,成功将 GDAL 3.2.2 完整集成到容器中,支持 HFA 驱动(ERDAS Imagine 格式)。

整个过程历经多次迭代,主要难点在于GDAL 依赖链极长,需要补齐几十个 deb 包。本文把所有坑、报错、解决方法详细记录下来,希望帮到同样遇到这个问题的朋友。

目标镜像信息(最终成功版)
  • 镜像名称:​my-openjdk8-with-gdal:v1
  • 大小:约 1.37GB
  • GDAL 版本:3.2.2
  • 支持功能:​gdal_translate -of GTiff input.img output.tif​ 正常工作,HFA 驱动可用
完整步骤(一步一步)
1. 前期诊断:确认为什么挂载失败

进入容器:

复制代码
docker exec -it container bash

检查:

复制代码
uname -m                  # aarch64
cat /etc/os-release       # Debian GNU/Linux 11 (bullseye)
gdalinfo --version        # command not found 或 not found
file /usr/local/gdal_bin/gdalinfo  # 如果存在,通常显示 x86-64 → 架构不匹配

结论 :手动挂载的 GDAL 二进制是 x86 版,ARM64 容器无法执行。放弃挂载方案,转向自定义镜像

2. 准备 GDAL 核心 + 依赖 deb 包(在有网络的机器上)

推荐方式(最省事): 找一台 Debian 11 arm64 系统(或虚拟机/云服务器):

复制代码
mkdir ~/gdal-debs && cd ~/gdal-debs
apt update
apt install --download-only gdal-bin libgdal-dev gdal-data python3-numpy libarmadillo-dev libcfitsio-dev libhdf5-dev libnetcdf-dev libopenjp2-7-dev libpoppler-dev
cp /var/cache/apt/archives/*.deb .

手动下载方式 (如果没有 Debian 环境): 去 ​​https://packages.debian.org/bullseye/arm64/​​ 或 ​​ftp.jp.debian.org/debian/pool/main/​​ 搜索下载(优先亚洲镜像):

核心包(必须):

  • gdal-bin_3.2.2+dfsg-2+deb11u2_arm64.deb
  • libgdal28_3.2.2+dfsg-2+deb11u2_arm64.deb
  • gdal-data_3.2.2+dfsg-2+deb11u2_all.deb
  • libgdal-dev_3.2.2+dfsg-2+deb11u2_arm64.deb

常见依赖(至少补这些,否则 dpkg 会失败):

  • libproj19_7.2.1-1_arm64.deb
  • libwebp6_0.6.1-2.1+deb11u2_arm64.deb(注意是 6,不是 7)
  • libcurl4_7.74.0-1.3+deb11u16_arm64.deb(注意安全更新版)
  • python3-numpy_1.19.5-1_arm64.deb(非常关键!)
  • libarmadillo10_10.1.2+dfsg-6_arm64.deb
  • libcfitsio9_3.48-3_arm64.deb
  • libcharls2_2.2.0+dfsg-1_arm64.deb
  • libgeos-c1v5_3.9.0-1_arm64.deb
  • libhdf5-103-1 + libhdf5-hl-100
  • libnetcdf18_4.7.4-1_arm64.deb
  • libopenjp2-7_2.4.0-3_arm64.deb
  • libpoppler118_20.09.0-3.1_arm64.deb
  • proj-data_7.2.1-1_all.deb

把所有 deb 文件传到生产宿主机,统一放在:

复制代码
/home/user/offline-debs/
3. 准备构建目录(生产宿主机)
复制代码
cd /home/user/build-context   # 建议用一个固定目录
mkdir -p debs
cp /home/user/offline-debs/*.deb ./debs/
ls -l debs/   # 必须看到所有 deb 文件(物理复制!不要用软链接)

最常见报错 :COPY failed: stat debs: file does not exist
原因 :用了符号链接(ln -s),Docker 不支持上下文外的 symlink
解决 :必须用 ​​cp​​ 物理复制文件到当前目录的 debs 子文件夹

4. 创建 Dockerfile

用 vi/vim 编辑 ​​Dockerfile.gdal​​(不要用 cat << EOF,容易出隐藏问题):

复制代码
# syntax=docker/dockerfile:1

FROM docker-registry.example.com/openjdk:8

# 复制 deb 文件夹(现在在构建上下文内)
COPY debs /tmp/debs/

# 安装:先强制 dpkg,如果依赖问题则联网修复(最关键一步)
RUN dpkg -i /tmp/debs/*.deb || ( \
    apt-get update && \
    apt-get install -f -y && \
    dpkg -i /tmp/debs/*.deb \
) && \
rm -rf /tmp/debs /var/lib/apt/lists/* /var/cache/apt/archives/*

# GDAL 环境变量设置
ENV GDAL_DATA=/usr/share/gdal \
    LD_LIBRARY_PATH=/usr/lib/aarch64-linux-gnu:/usr/lib:/lib64 \
    PATH=/usr/bin:/usr/local/openjdk-8/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
    CLASSPATH=/usr/share/java/gdal.jar:${CLASSPATH:-}

WORKDIR /app/jars
CMD ["java", "-jar", "demo-0.0.1-SNAPSHOT.jar", "--spring.config.location=file:/app/jars/application-prod.yml"]

常见语法坑

  • 第一行必须是 ​# syntax=docker/dockerfile:1​ 或空/FROM,否则报 parser error
  • RUN 续行用 ​\​,每个命令后 ​\​,最后一行不加
5. 构建镜像(迭代过程)
复制代码
docker build -f Dockerfile.gdal -t my-openjdk8-with-gdal:v1 --no-cache .

最痛苦阶段:依赖缺失循环

常见缺失(按出现频率排序):

  • python3-numpy → 必须补
  • libarmadillo10
  • libgeos-c1v5
  • libhdf5-103-1 / libhdf5-hl-100
  • libcfitsio9 / libcharls2
  • libnetcdf18 / libopenjp2-7
  • proj-data

解决策略

  1. 构建 → 看日志报哪个包缺失
  2. 下载对应 arm64 deb 加到 debs/
  3. 改 tag 为 v2、v3... 重新 build
  4. 最佳方案 :容器有网络时,让 ​apt-get install -f -y​ 自动下载补齐(日志会显示 Get:1~200+,下载 145MB+,占用 711MB 空间)
  • 这是实际成功的关键!有网就别死磕手动补包

成功标志:日志出现

复制代码
Setting up gdal-bin ...
Setting up libgdal28 ...
Processing triggers for libc-bin ...
6. 部署到生产

修改 docker-compose.yml:

复制代码
demo-service:
  image: my-openjdk8-with-gdal:v4
  #注意:这里要换成打好的包含gdald的镜像名称
  container_name: container
  ports:
    - "12322:8032"
  volumes:
    - ./services/demo/:/app/jars
    - /mnt/nfs/general:/var/nfs/general
    - /etc/localtime:/etc/localtime:ro
  environment:
    - TZ=Asia/Shanghai
  restart: always

重启:

复制代码
docker-compose down demo-service
docker-compose up -d demo-service
7. 最终验证

进入容器:

复制代码
docker exec -it evaluation-container bash

测试:

复制代码
gdalinfo --version
gdalinfo --formats | grep -i HFA   # 必须看到 HFA - Erdas Imagine .img: read/write

# 实际文件转换(文件已在 NFS 挂载路径)
cd /var/nfs/general/data/file-data/533151845376409600/
gdal_translate -of GTiff -co COMPRESS=LZW -co TILED=YES Texas_DEM_90m_8bit.img Texas_DEM_90m_8bit.tif

gdalinfo Texas_DEM_90m_8bit.tif

成功!tif 文件生成且包含地理信息。

总结经验教训
  • GDAL 是依赖地狱:完整安装可能需要 150+ 个 deb 包,手动补非常痛苦。
  • 有网络就别硬扛离线 :让 ​apt install -f​ 自动补齐是最省力方式。
  • 符号链接大坑:Docker build 上下文不支持外部 symlink,必须物理复制文件。
  • Dockerfile 语法敏感 :第一行加 ​# syntax=docker/dockerfile:1​,用 vi 编辑避免隐藏字符。
  • 时间消耗:诊断 + 补包迭代 ≈ 1-2 天;一旦成功,一劳永逸。

希望这篇详细记录能帮到同样在 ARM64 Docker 上折腾 GDAL 的朋友。如果你在某个步骤卡住,欢迎留言,我可以进一步解答。

相关推荐
charlee442 天前
从Shapefile到GeoJSON:用GDAL实现GIS矢量数据读写与空间分析
空间分析·gis开发·矢量数据·gdal·ogr
charlee443 天前
GIS开发必知:WKT 与 EPSG 如何表达空间参考坐标系?附 GDAL 实现
gis·gdal·epsg·空间参考系统·wkt
椰汁菠萝4 天前
spring boot下使用gdal解析tif文件
java·native·gdal·0
你们瞎搞14 天前
Cesium加载20GB航测影像.tif
前端·cesium·gdal·地图切片
汪宁宇1 个月前
如何在QT5+MinGW环境中编译使用QGIS开发地图应用
c++·qt·qgis·mingw·地图库
枝上棉蛮1 个月前
2025年GIS软件深度解析:商业旗舰、开源先锋与国产新锐的选型指南
arcgis·gis·qgis·gisbox·gis服务器·global mapper·grass gis
GIS阵地1 个月前
Qt实现简易仪表盘
开发语言·c++·qt·pyqt·qgis·qt5·地理信息系统
GDAL1 个月前
QGIS Open Sans字体安装失败解决方案
qgis·字体
GDAL1 个月前
QGISQT6-OSGeo4W-3.44.5-1.msi 与 QGIS-OSGeo4W-3.44.5-1.msi 核心区别
qgis