文章目录

  • 1 部署需求
  • 2 软件版本
  • 3 部署过程
  • 3.1 制作镜像
  • 3.2 宿主机配置
  • 3.3 运行镜像
  • 3.4 SpringBoot项目打包部署
  • 3.5 其他常用命令
  • 4 问题解决
  • cp: omitting directory
  • Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.2:test (default-test)
  • SpringBoot项目无法正常启动,提示Java.lang.UnsatisfiedLinkError: org.gdal.gdal.gdalJNI.ALLRegistger()V
  • GDAL不支持PostgreSQL驱动?
  • SpringBoot项目无法访问与宿主机位于相同局域网中的MySQL服务?
  • 5 资源下载



环境部署是一个非常繁琐又耗时的工作,尤其是涉及更换操作系统时,其难度更是成倍的增加。本文通过构建起软件运行镜像,并将SpringBoot项目运行在容器中,以期减小软件部署工作所投入的时间与精力。

1 部署需求

在Windows环境下构建了一个SpringBoot项目,涉及对MySQL数据库、PostgreSQL+PostGIS地理空间数据库的操作,使用到了GDAL库。

软件生产环境需部署在Linux环境,将业务功能服务与数据存取服务分离,分别部署在单独的服务器上。业务功能服务器需获取数据存取服务。

2 软件版本

本文使用的软件版本如下表所示:

软件

版本

CentOS

7

Java

8.0.301

GEOS

3.6.2

PROJ

4.9.3

FileGDB_API

1.5

ANT

1.10.7

SWIG

4.0.1

GDAL

2.4.4

3 部署过程

3.1 制作镜像

此一步骤想通过Dockerfile自动构建起SpringBoot项目运行的基础环境,主要包含JavaGDAL的安装。GDAL的安装包含GDAL依赖库的安装以及GDAL的配置使用。

Dockerfile文件中的注释详细说明了各个命令的用途。

# 以centos7为基础镜像构建本镜像
FROM centos:7
LABEL maintainer="DORIC"


#------------------- 安装JAVA8 -------------------
# 使用ADD命令将与Dockerfile相同目录下的文件拷贝并解压缩至镜像指定目录下
# 非常规格式的文件复制建议使用COPY命令替代
ADD ./jdk-8u301-linux-x64.tar.gz /usr/local
# 设置工作目录为镜像中的指定路径,后续命令均在此目录下执行
WORKDIR /usr/local
# 修改文件名,以/usr/local/java为JAVA_HOME
RUN mv jdk1.8.0_301 /usr/local/java

# Dockerfile使用ENV设置环境变量
# 设置JAVA环境变量
ENV JAVA_HOME /usr/local/java
ENV JAVA_BIN /usr/local/java/bin
ENV JRE_HOME /usr/local/java/jre
# 将java中可执行文件目录添加到PATH
ENV PATH $PATH:/usr/local/java/bin:/usr/local/java/jre/bin
ENV CLASSPATH /usr/local/java/jre/bin:/usr/local/java/lib:/usr/local/java/jre/lib/charsets.jar


#------------------- 安装编译所需要的工具及库 -------------------
RUN yum -y install  \
bzip2 \ 
gcc \
make \
subversion \
gcc-c++ \
sqlite-devel \
libxml2 \ 
libxml2-devel \
python-devel \
numpy \
expat-devel \
libcurl-devel \ 
postgresql \ 
postgresql-devel


#------------------- 安装geos -------------------
# 复制文件到镜像中指定目录
COPY ./geos-3.6.2.tar.bz2 /usr/local/
WORKDIR /usr/local
# 解压缩文件到当前目录下
RUN tar -xvf geos-3.6.2.tar.bz2
WORKDIR /usr/local/geos-3.6.2
RUN ./configure
RUN make && make install
# 删除已经安装完毕的压缩包、安装包
RUN rm -rf /usr/local/geos-3.6.2.tar.bz2
RUN rm -rf /usr/local/geos-3.6.2


#------------------- 安装proj4 -------------------
COPY ./proj-4.9.3.tar.gz /usr/local/
WORKDIR /usr/local
RUN tar -xvf proj-4.9.3.tar.gz
WORKDIR /usr/local/proj-4.9.3
RUN ./configure
RUN make && make install
RUN rm -rf /usr/local/proj-4.9.3.tar.gz
RUN rm -rf /usr/local/proj-4.9.3

# ------------------- 安装filegdb api -------------------
# 用于实现GDAL操作GDB文件
COPY ./FileGDB_API_1_5_64.tar.gz /usr/local/
WORKDIR /usr/local
# 解压缩
RUN gunzip FileGDB_API_1_5_64.tar.gz
RUN tar -xvf FileGDB_API_1_5_64.tar
# 以/usr/local/FileGDB_API为安装目录
RUN mv FileGDB_API-64 /usr/local/FileGDB_API
# 将FileGDB_API的动态链接目录添加到LD_LIBRARY_PATH,否则报未定义参考错误
ENV LD_LIBRARY_PATH $LD_LIBRARY_PATH:/usr/local/FileGDB_API/lib
# 拷贝动态链接文件后需要执行ldconfig命令以刷新
RUN ldconfig

# 继续编译FileGDB_API,将生成的动态连接文件复制到/usr/local/lib/下
WORKDIR /usr/local/FileGDB_API/samples
RUN make
RUN cp ../lib/* /usr/local/lib/
RUN rm -rf /usr/local/FileGDB_API_1_5_64.tar
RUN rm -rf /usr/local/FileGDB_API_1_5_64.tar.gz

# https://gis.stackexchange.com/questions/292506/how-do-i-install-esri-file-gdb-api-in-ubuntu-16-04-so-qgis-2-8-can-see-it
# cd src/FileGDB_API-64gcc51
# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:`pwd`/lib
# cd samples
# make
# cp ../lib/* /usr/local/lib/
# ldconfig


#------------------- 安装ant -------------------
# 用于编译gdal.jar
COPY apache-ant-1.10.7-bin.tar.gz /usr/local
WORKDIR /usr/local
RUN tar -xvf apache-ant-1.10.7-bin.tar.gz
RUN mv apache-ant-1.10.7 ant
RUN rm -rf /usr/local/apache-ant-1.10.7-bin.tar.gz

#-------------------  安装swig ------------------- 
COPY swig-4.0.1.tar.gz /usr/local
WORKDIR /usr/local
RUN tar -xvf swig-4.0.1.tar.gz
WORKDIR /usr/local/swig-4.0.1
RUN ./configure \
--prefix=/usr/local/swig \ 
--without-pcre
RUN make && make install
RUN rm -rf /usr/local/swig-4.0.1
RUN rm -rf /usr/local/swig-4.0.1.tar.gz

# 配置ant/swig环境变量
ENV ANT_HOME /usr/local/ant
ENV SWIG_HOME /usr/local/swig
ENV PATH $PATH:$ANT_HOME/bin:$SWIG_HOME/bin


#------------------- 编译安装GDAL -------------------
COPY gdal-2.4.4.tar.gz /usr/local
WORKDIR /usr/local
RUN tar -xvf gdal-2.4.4.tar.gz
WORKDIR /usr/local/gdal-2.4.4
RUN ./configure \
--prefix=/usr/local/gdal \
--with-pg \ 
--with-java=/usr/local/java \ 
--with-curl=/usr/bin/curl-config \ 
--with-xml2=/usr/bin/xml2-config \ 
--with-fgdb=/usr/local/FileGDB_API
RUN make && make install

# 配置GDAL环境变量,包含了GDAL_HOME和GDAL_DATA
ENV GDAL_HOME /usr/local/gdal
ENV GDAL_DATA $GDAL_HOME/share/gdal

# 将gdal中的可执行文件和动态链接文件分别拷贝到/usr/local/bin/和/usr/local/lib/
WORKDIR /usr/local/gdal
RUN cp -r ./bin/* /usr/local/bin/
RUN cp -r ./lib/* /usr/local/lib/
RUN ldconfig

# 可执行文件和动态链接库添加到环境变量中
ENV PATH $PATH:/usr/local/bin
ENV LD_LIBRARY_PATH $LD_LIBRARY_PATH:/usr/local/lib


#------------------- 编译gdal.jar -------------------
# 在执行完编译安装的解压缩文件gdal-2.4.4目录下
WORKDIR /usr/local/gdal-2.4.4/swig/java
# 修改java.opt的java_home,在第五行插入指定内容
RUN sed -i '5aJAVA_HOME = /usr/local/java' java.opt
RUN make && make install

# 复制生成的gdal.jar和so文件到指定目录,否则报错,java.lang.UnsatisfiedLinkError:org.gdal.gdal.gdalJNI.AllRegister()V
RUN cp gdal.jar /usr/local/java/jre/lib/ext/
RUN cp *.so /usr/local/java/jre/lib/amd64/server/
ENV LD_LIBRARY_PATH $LD_LIBRARY_PATH:/usr/local/java/jre/lib/amd64/server

# RUN rm -rf /usr/local/gdal-2.4.4
RUN rm -rf /usr/local/gdal-2.4.4.tar.gz

WORKDIR /usr/local

使用上述Dockerfile文件,构建镜像:

docker build -f Dockerfile -t gdal:v1.0 .

3.2 宿主机配置

为了连接与宿主机相同局域网下其他主机的数据库服务,也为了便于外部主机访问docker中部署的业务功能,需要修改宿主机网络配置,开放指定端口。

使用firewall开放宿主机端口:

yum install -y firewalld firewall-config
systemctl start firewalld
systemctl status firewalld
systemctl enable firewalld
firewall-cmd --zone=public --add-port=3306/tcp --permanent
firewall-cmd --zone=public --add-port=5432/tcp --permanent
firewall-cmd --zone=public --add-port=8088/tcp --permanent
firewall-cmd --reload

本文docker的网络模式选择host,即docker容器与主机共享一个网络。考虑到安全,可以采用其他网络模式,其网络配置方式应发生改变,这部分内容不在本文讨论之列。

3.3 运行镜像

docker run -it --net host --name gdal gdal:v1.0

3.4 SpringBoot项目打包部署

使用IntelliJ IDEA软件打包SpringBoot项目,命名为sample.jar
需要非常注意的是,当你的SpringBoot引入第三方jar包时,需要在打包前修改pom.xml引入jar,否则运行时将提示无法找到对应jar包,其他需要打包引入的资源也是类似的操作,比如application.yaml文件。

<resources>
    <resource>
        <directory>${project.basedir}\src\main\resources\jar</directory>
        <targetPath>BOOT-INF/lib/</targetPath>
        <includes>
            <include>**/*.jar</include>
        </includes>
    </resource>
    <resource>
        <directory>${project.basedir}\src\main\resources</directory>
        <includes>
            <include>**/*.yaml</include>
        </includes>
    </resource>
</resources>

将sample.jar上传到容器中并启动:

# 复制文件到docker容器中
docker cp vlm.jar gdal:/usr/local/
# 进入已启动的容器
docker exec -it gdal /bin/bash
cd /usr/local/
java -jar sample.jar

3.5 其他常用命令

# 查看网络状态
ifconfig
# 查看开放的端口
netstat -tlnp

# 配置文件修改及执行文件
# 注意:每次系统重启后都需要 source /etc/profile
vi /etc/profile
source /etc/profile

# 远程端口连接测试
telnet 192.168.1.3 3306

# 查找java安装位置
which java
ls -lrt /usr/bin/java
ls -lrt /etc/alternatives/java

# 查看容器最后1000条日志
docker logs -f --tail=1000 gdal
# 查看所有镜像
docker images
# 查看容器
docker ps -a
# 强制删除容器
docker rm -f gdal
# 删除镜像
docker rmi gdal:v1.0

# 删除退出状态的容器
docker rm `docker ps -qf status=exited`
# 删除未构建成功的镜像
docker rmi `docker images | grep '<none>' | awk '{print $3}'`

4 问题解决

cp: omitting directory

所复制的目录下有其他文件或目录存在,需要进行递归复制。

cp -r dir ./usr

Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.2:test (default-test)

在pom.xml下增加如下配置内容:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
    <configuration>
    	<skipTests>true</skipTests>
    </configuration>
</plugin>

SpringBoot项目无法正常启动,提示Java.lang.UnsatisfiedLinkError: org.gdal.gdal.gdalJNI.ALLRegistger()V

以上错误产生的原因是程序缺少gdal引用,可能有几方面的原因:

  • 未安装GDAL
  • 未将gdal.jar以及动态链接库文件.so复制到可引用位置

归根结底是GDAL未正确安装。需要参考Dockerfile中先完成GDAL的编译安装,同时还需要继续编译GDAL,生成gdal.jar文件及动态连接so文件,并把文件分别导入
JAVA_HOME/jre/lib/ext/JAVA_HOME/jre/lib/amd64/server/目录内,并且将后一路径添加到环境变量中LD_LIBRARY_PATH中。

GDAL不支持PostgreSQL驱动?

GDAL默认不支持PostgreSQL,如程序有操作PostgreSQL的需求,则需要额外安装PostgreSQL插件。具体来说,需要完成:

  1. 在编译安装GDAL安装前先安装postgresqlpostgresql-devel两个软件包;
  2. ./configure时增加PG插件配置参数,即声明--with-pg

SpringBoot项目无法访问与宿主机位于相同局域网中的MySQL服务?

解决这个问题可以分两步解决:

  1. Docker容器运行时采用与宿主机一样的网络IP,即配置网络时选择host模式;
  2. 宿主机开放数据库访问端口,即使用firewall开放3306端口。类似的,如需访问其他数据库服务时可以打开对应端口,如PostgreSQL5432端口。