
适用场景:需要在 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
解决策略:
- 构建 → 看日志报哪个包缺失
- 下载对应 arm64 deb 加到 debs/
- 改 tag 为 v2、v3... 重新 build
- 最佳方案 :容器有网络时,让
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 的朋友。如果你在某个步骤卡住,欢迎留言,我可以进一步解答。