镜像:将应用程序及其依赖、环境、配置打包在一起
容器:镜像运行起来就是容器,一个镜像可以运行多个容器
通常情况下,我们需要将自己的微服务项目制作成一个个的镜像,那么,如何制作镜像呢?
这自然是需要交给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能够成功访问服务