首页 > 技术文章 > Docker自定义Java项目镜像

changtong1819 2021-12-09 19:01 原文

镜像:将应用程序及其依赖、环境、配置打包在一起
容器:镜像运行起来就是容器,一个镜像可以运行多个容器

通常情况下,我们需要将自己的微服务项目制作成一个个的镜像,那么,如何制作镜像呢?

这自然是需要交给docker来处理,我们要做的,仅仅只是在项目中添加好DockerFile这样一个描述文件,告诉Docker我们需要使用哪个操作系统的基本镜像、要拷贝什么文件、需要安装什么依赖、启动脚本是什么,后面Docker会帮助我们构建镜像。

DockerFIle文件中的常用指令如下:

在公司的项目中就一直有这么一个Dockerfile文件,之前一直看不懂,现在算是能理解了:

FROM xxx/javabase:0.8.0
COPY app.jar /hzero-xxx.jar
ENV JAVA_TOOL_OPTIONS -Dfile.encoding=UTF8 -Duser.language=zh -Duser.region=zh_CN -Duser.country=zh_CN
ENTRYPOINT exec java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap $JAVA_OPTS $SKYWALKING_OPTS  -jar /hzero-esign.jar

解析上面的文件内容,可以得知,首先我们就是要引入我们的基础镜像 FROM

注意这里你可能会疑问为什么不直接用那些centos之类的系统镜像?
一 是我们并不需要那么完整的系统镜像,毕竟我们是在Docker里面的,只需要一些核心的函数库啥的就行了,所以都会选择尽可能精简的基础镜像
二 是我们想要运行我们的Java项目,那JDK你要不要装?环境变量要不要配?这些工作不可能每次都重复做,干脆就弄一个公司自用的专门运行Java项目的基础镜像,里面环境都搭好了

然后就是把我们项目的Jar包拷贝进镜像里面 COPY

接着就是一些系统环境变量啥的 ENV

最后自然是执行脚本了,运行Java项目嘛,基本命令就是Java -jar xxx ,想要高级点还能加上一些Jvm相关的配置参数 ENTRYPOINT ,注意,这个命令就是我们容器运行时自动执行的

至于最后的制作镜像操作,你就可以把DockerFile和一些需要的文件例如你的Jar包放一块,然后在当前路径下执行 docker build -t xxx:x . 就行了,一个镜像就制作完成(注意,这里后面要跟路径的,所所以最后面有一个 . 用来表示当前路径)

当然,在你镜像打包好之后,你需要启动这个微服务,启动过程可能会出现各种问题

  • 首先可能是你的Jar并没有打包好,也就是说,你可能没有把依赖一块打包,导致这个Jar包只有几十几百k,那么你就要看看项目的pom文件是否有什么特殊设置了

    例如我们项目里有这么个藏了这么个属性,这个skip一看名字就不对劲,肯定是不能跳过的

  <properties>
      <plugin.version>0.0.0-SNAPSHOT</plugin.version>
      <maven.springboot.skip>true</maven.springboot.skip>
  </properties>

赶紧给注掉上面的skip,再加上spring-boot-maven-plugin插件

  <build>
      <plugins>
          <plugin>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-maven-plugin</artifactId>
              <version>${spring-boot-maven-plugin.version}</version>
              <executions>
                  <execution>
                      <goals>
                          <goal>repackage</goal>
                      </goals>
                  </execution>
              </executions>
          </plugin>
      </plugins>
  </build>

接下来就能将依赖一起打包了

  • 在你的微服务项目里可能使用了spring-boot-starter-actuator来进行服务监控,而你的注册中心又是另外一个微服务,那么很明显,注册中心是要向你的服务发送请求的,首先,你肯定要配置端口映射

    docker run -dit —name xx -p xx:xx xxxx /bin/bash -d是为了后台运行,后面的 /bin/bash是为了让容器能有一个一直执行的命令从而保持后台运行,-p是为了宿主和容器进行端口映射

    映射了端口不代表就外部就能直接访问到容器了

    因为默认配置下,docker容器内部是独立的IP,如果是直接以容器IP注册到eureka,eureka回访的时候肯定是访问你注册信息里的IP,那自然是访问不到的,我们应该让它访问我们的宿主IP

eureka:
  instance:
    # 以IP注册到注册中心
    preferIpAddress: true
    leaseRenewalIntervalInSeconds: 10
    leaseExpirationDurationInSeconds: 30
    # 服务的一些元数据信息
    metadata-map:
      VERSION: 1.6
    ip-address: 宿主IP #以此处设置的宿主IP来注册到eureka
  client:
    serviceUrl:
      # 注册中心地址
      defaultZone: 注册中心地址
    registryFetchIntervalSeconds: 10
    disable-delta: true

这样eureka访问我们服务的xx端口时会访问我们的宿主IP:xx,而我们宿主的xx端口又与容器的xx端口进行了映射,最终实现效果就是eureka能够成功访问服务

推荐阅读