需求背景
将已有的,maven管理的多模块微服务springboot项目,用docker进行项目部署
项目打包部署
参考:使用Docker部署Spring boot项目_funtaster的博客
springboot项目(docker打包插件,docker配置文件)
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- Docker maven plugin -->
<plugin>
<!--插件依赖-->
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.0.0</version>
<!--配置-->
<configuration>
<!--项目镜像命名-->
<imageName>${docker.image.prefix}.${project.artifactId}</imageName>
<!--Dockerfile文件所在目录-->
<dockerDirectory>src/main/docker</dockerDirectory>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
<!-- Docker maven plugin -->
</plugins>
</build>
Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ADD love-master-0.0.1-SNAPSHOT.jar love-master.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/love-master.jar"]
安装docker
#所需包
yum install -y yum-utils device-mapper-persistent-data lvm2
#设置稳定存储库
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
#安装最新版本的Docker Engine - 社区和容器
yum install docker-ce docker-ce-cli containerd.io
#要安装特定版本的Docker Engine - Community,请列出repo中的可用版本,然后选择并安装
yum list docker-ce --showduplicates | sort -r
#返回的列表取决于启用的存储库,并且特定于您的CentOS版本
yum install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io
(yum install docker-ce-19.03.1 docker-ce-cli-19.03.1 containerd.io)
#启动Docker
systemctl start docker
##允许远程
vi /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375
使用maven命令生成docker镜像(整个工程都是maven管理的)
#找到项目所在目录
cd /home/program/parentProject/
#根目录下进行 install
mvn clean install package -Dmaven.test.skip=true
#进入web模块下
cd moduleProject/
#执行maven命令生成jar包和镜像
mvn package docker:build -Dmaven.test.skip=true
#查看镜像是否存在
docker images
#运行镜像(参考日志下的运行)
docker run -p 8080:8080 --name containerName -d imageName
Doker日志
参考:理解docker部署springboot-容器日志处理(四)_txxs的博客
1.实时查看输出层日志
#docker logs -f -t --since="2017-05-31" --tail=10 edu_web_1
docker logs -f -t --tail 行数 容器名
--since : 此参数指定了输出日志开始日期,即只输出指定日期之后的日志。
-f : 查看实时日志
-t : 查看日志产生的日期
-tail=10 : 查看最后的10条日志。
edu_web_1 : 容器名称
2.数据卷的方式
docker run -v /home/docker_logs/:/home/logs/love/all -v /home/docker_logs/:/home/logs/love/info -v /home/docker_logs/:/home/logs/love/err/ -p 8888:8888 --name love-master -d springboot.love-master
-v docker日志输出目录:宿主机输出日志 (有多个日志文件,则按上述格式多加几个就好了)
-d 后台运行 springboot.love-master 镜像名称
-p 容器端口:宿主机端口 (端口映射,当使用nginx代理时[负载均衡],要配置成制定的容器端口)
-name 容器名称
这里我写了多个,是因为我在springboot日志框架logback下写了对应配置,将日志进行了级别分类
查看日志,发现已经有了,但是日志时间不对,差了8个小时,猜测时区不对
在docker容器和系统时间不一致(日志打印时间不对)
参考:Docker中部署springboot时间不对的问题
1.检查系统时间和容器时间
#系统
date
#容器
#进入容器
docker exec -it containerId sh
date
2.在启动容器时,把系统时间挂载到容器内,添加如下参数
-v /etc/localtime:/etc/localtime
3.这时系统和容器时间一致了,日志时间还是不对
JVM是通过/etc/timezone文件获取时区的,需要在容器中映射或者写入时区文件
在Dockfile中新增命令
RUN echo "Asia/Shanghai" > /etc/timezone
其他
logback-boot.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
scan 自动重新加载 配置文件发生变化后进行重新配置
scanPeriod 属性控制扫描周期,其值可以带时间单位,包括:milliseconds、seconds、minutes 和 hours.没写明时间单位,则默认为毫秒
默认情况下,每隔一分钟扫描一次
-->
<configuration scan="true" scanPeriod="30 minutes">
<!--
引用资源文件,引用变量,用法同spring资源文件的加载
<property resource="resource1.properties" />
直接指定变量
<property name="LOG_HOME" value="" />
-->
<property resource="logback.properties" />
<!-- 设置上下文名称后,可以方便地区分来自不同应用程序的记录 -->
<contextName>${logback.appName}</contextName>
<!-- 彩色日志 -->
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN:-%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%15.15t] %-40.40logger{39} : %m%n}"/>
<!-- <encoder>元素class 属性是必要的,表示将被实例化的 encoder 类的全限定名.
因为太常用了,所以当 encoder 是 PatternLayoutEncoder 时,可以省略 class 属性 -->
<!--
%date{yyyy-MM-dd HH:mm:ss} 时间
[%thread] 线程名称
%-5level 级别
%logger 类名
%msg%n信息
-->
<!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,%i索引【从数字0开始递增】,,, -->
<!-- name 属性指定 appender 的名称,class 属性指定 appender 类的全限定名 -->
<!-- appender是configuration的子节点,是负责写日志的组件。 -->
<!-- ConsoleAppender:把日志输出到控制台 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
<encoder>
<!--<pattern>%d %p (%file:%line\)- %m%n</pattern>-->
<!--<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName %-5level --- [%thread] %logger{36} [%file:%line]:%msg%n</pattern>-->
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<!-- 控制台也要使用UTF-8,不要使用GBK,否则会中文乱码 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
<!-- 以下的大概意思是:1.先按日期存日志,日期变了,将前一天的日志文件名重命名为XXX%日期%索引,新的日志仍然是sys.log -->
<!-- 2.如果日期没有发生变化,但是当前日志的文件大小超过2MB时,对当前日志进行分割 重命名-->
<appender name="love_all" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logback.home}/${logback.all}/${logback.allFileName}.log</file>
<!-- rollingPolicy:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。 -->
<!-- TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 活动文件的名字会根据fileNamePattern的值,每隔一段时间改变一次 -->
<!-- 文件名:log/sys.2017-12-05.0.log -->
<fileNamePattern>${logback.home}/${logback.all}/${logback.allFileName}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 每产生一个日志文件,该日志文件的保存期限为30天 -->
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- maxFileSize:这是活动文件的大小,默认值是10MB,本篇设置为2MB,只是为了演示 -->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<!-- pattern节点,用来设置日志的输入格式 -->
<!--<pattern>%d %p (%file:%line\)- %m%n</pattern>-->
<!--<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName %-5level --- [%thread] %logger{36} [%file:%line]:%msg%n</pattern>-->
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<appender name="love_debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logback.home}/${logback.debug}/${logback.debugFileName}.log</file>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logback.home}/${logback.debug}/${logback.debugFileName}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- or whenever the file size reaches 100MB -->
<maxFileSize>2MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<!--<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName %-5level --- [%thread] %logger{36} [%file:%line]:%msg%n</pattern>-->
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<appender name="love_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logback.home}/${logback.info}/${logback.infoFileName}.log</file>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logback.home}/${logback.info}/${logback.infoFileName}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- or whenever the file size reaches 100MB -->
<maxFileSize>2MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<!--<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName %-5level --- [%thread] %logger{36} [%file:%line]:%msg%n</pattern>-->
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<appender name="love_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logback.home}/${logback.err}/${logback.errFileName}.log</file>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logback.home}/${logback.err}/${logback.errFileName}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- or whenever the file size reaches 100MB -->
<maxFileSize>2MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<!--<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName %-5level --- [%thread] %logger{36} [%file:%line]:%msg%n</pattern>-->
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- 指定项目中某个包,当有日志操作行为时的日志记录级别 -->
<!-- 也就是只要是发生在这个根包下面的所有日志操作行为的权限都是xxxx -->
<!-- 级别依次为【从高到低】:FATAL > ERROR > WARN > INFO > DEBUG > TRACE -->
<logger name="org.springframework.web" level="INFO" />
<logger name="org.springframework.web.servlet.mvc.method.annotation" level="INFO" />
<logger name="org.mybatis.spring" level="DEBUG" />
<logger name="org.mybatis" level="DEBUG" />
<!--<logger name="cn.penghf" level="INFO"/>-->
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="love_info"/>
<appender-ref ref="love_all"/>
<appender-ref ref="love_error"/>
<appender-ref ref="love_debug"/>
</root>
</configuration>
logback.properties
logback.appName=love
#logback.home=/home/logs/love
logback.home=D:/dev/logs
logback.debug=debug
logback.info=info
logback.err=err
logback.all=all
#包含所有的日志信息
logback.allFileName=love_all
#debug等级的日志文件
logback.debugFileName=love_debug
#info等级的日志文件
logback.infoFileName=love_info
#error等级的日志文件
logback.errFileName=love_err