0%

docker 名词解释

下面简单解释下名词的含义,后面会详细介绍:

  • docker:docker代表这一个技术的名词,下面一个docker代表一台机器上装的一个docker服务
  • container:docker容器,相当于一个轻量的沙盒系统(可以暂时理解一个运行好的虚拟机系统)一个容器只运行一个服务
  • images:docker镜像,相当于一个安装包(可以暂时理解成一个系统iso镜像)
  • service:docker服务,多个相同的容器组成的一个服务,相当于容器的多个复制,提高了扩展性
  • swarm:docker集群,将一个docker或多个docker组成的一个资源集合,包含了网络、负载均衡、多个服务节点、服务发现、服务伸缩
  • node:docker节点,一台实际机器上的一个docker算一个节点,节点只有在docker初始化为集群才存在该概念
  • docker-compose.yml:服务编排脚本,该脚本只支持单机docker服务编排,相当于服务的启动参数,服务数量都在该脚本配置
  • stack:docker集群服务编排模式,stack.yml为集群部署模式的配置文件,文件name可以自定义,这个是多节点服务编排部署模式,在单机的基础上面多支持了容器在那个节点运行,及运行个数等
  • DockerFile:docker镜像编排脚本
  • Docker-hub:官方docker仓库
  • registry:可搭建的私有镜像仓库
  • 集群-无状态服务vs有状态服务(共享存储/NAS)
  • 分布式集群

docker swarm服务关系

6VVz11.png

docker编排部署流程

6VZP0O.png

docker简介

容器是打包代码及其所有依赖项的软件的标准单元,因此应用程序可以从一个计算环境快速可靠地运行到另一个计算环境。Docker容器映像是一个轻量级的,独立的,可执行的软件软件包,其中包含运行应用程序所需的一切:代码,运行时,系统工具,系统库和设置。

优势:

  • 标准: Docker创建了容器的行业标准,因此它们可以在任何地方移植
  • 轻巧:容器共享计算机的OS系统内核,因此不需要每个应用程序都具有OS,从而提高了服务器效率,并降低了服务器和许可成本
  • 安全:容器中的应用程序更安全,Docker提供业界最强大的默认隔离功能

虚机vs容器

容器虚化的是操作系统而不是硬件,容器更加便携和高效

6VJ3LQ.png

docker安装部署

centos安装

1
2
3
4
5
6
7
8
9
sudo yum install -y yum-utils
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io
#启动
systemctl start docker.service
# 开机启动
systemctl enable docker

docker swarm 初始化

DockerFile镜像编排

1
2
# 镜像编排命令
docker build -t image-name:tag .

dockerfile常见命令说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#基础镜像选择alpine 小巧安全流行方便
FROM exxk/tomcat:8-alpine-cst-font
#指定用户
USER patrick
#指定工作目录
WORKDIR /path/to/workdir
#编译时的环境参数
ARG DOCKER_MACHINE_VERSION
#暴露的端口
EXPOSE 80/udp
#拷贝文件到镜像的指定目录
COPY geoserver /usr/local/tomcat/webapps/geoserver
#拷贝文件,但是add功能比copy多,压缩文件会自动解压,不建议用高级的add
ADD geoserver /usr/local/tomcat/webapps/geoserver
#设置环境变量,启动时可以通过参数进行覆盖
ENV GEOSERVER_HOME=/usr/local/tomcat/webapps/geoserver/data
#运行编译时的命令
RUN chmod +x /usr/bin/gitlab-runner
#健康检查/类似心跳,前面命令执行的时间,cmd后面为心跳检测的命令
HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/ || exit 1
#设置挂在卷
VOLUME ["/etc/gitlab-runner", "/home/gitlab-runner"]
#启动时容器时,初始化容器的命令脚本
ENTRYPOINT ["/usr/bin/dumb-init", "/entrypoint"]
#入口启动命令
CMD ["catalina.sh", "run"]

Docker-hubregistry

docker-compose

官方文档

docker swarm VS k8s(Kubernetes)

6eAkhd.jpg

平台安装部署流程

6e1abd.png

6e1UDH.png

6e1NKe.png

springboot和docker 环境变量

springboot 支持系统环境变量
docker 支持容器环境变量设置

设计原理,不改变基础镜像的情况下,适应不同的环境

1
2
3
4
5
6
7
优先级由高到低
1 启动命令中指定的配置项;
2 操作系统配置项;
3 环境变量
4 配置中心中的配置文件;
5 本地的application.properties(yml)
5 本地boostrap.properties(yml)

6eGvIs.png

mac安装多个python版本

1
2
brew install python@3.10 #多个版本,多次执行,然后调整后面的版本号即可
#安装完成后,命令还是用的最早安装的,新安装的版本,可以在pycharm软件中进行切换

python pip 国内仓库代理

在改配置文件 vim ~/.pip/pip.conf添加如下内容,没有该文件创建该文件及目录

1
2
3
4
[global]
index-url = https://mirrors.aliyun.com/pypi/simple/
[install]
trusted-host = mirrors.aliyun.com

python 版本切换工具-pyenv

常用命令commands

常见问题issues

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#更新安装
brew update
brew install pyenv
#添加补齐
echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n eval "$(pyenv init -)"\nfi' >> ~/.zshrc
#重启shell
exec "$SHELL"
# 可选,但建议安装python依赖项
brew install openssl readline sqlite3 xz zlib bzip2 libiconv libzip
#查看支持的版本
pyenv install --list
#安装指定版本
pyenv install 2.7.15
#如遇安装问题,升级Xcode command line tools和配置下面的环境变量,上面可选变必选
vim ~/.zshenv

#zlib
#For compilers to find zlib you may need to set:
export LDFLAGS="-L/usr/local/opt/zlib/lib"
export CPPFLAGS="-I/usr/local/opt/zlib/include"
#For pkg-config to find zlib you may need to set:
export PKG_CONFIG_PATH="/usr/local/opt/zlib/lib/pkgconfig"

#bzip2
#If you need to have bzip2 first in your PATH, run:
export PATH="/usr/local/opt/bzip2/bin:$PATH"
#For compilers to find bzip2 you may need to set:
export LDFLAGS="-L/usr/local/opt/bzip2/lib"
export CPPFLAGS="-I/usr/local/opt/bzip2/include"

#libiconv
#If you need to have libiconv first in your PATH, run:
export PATH="/usr/local/opt/libiconv/bin:$PATH"
#For compilers to find libiconv you may need to set:
export LDFLAGS="-L/usr/local/opt/libiconv/lib"
export CPPFLAGS="-I/usr/local/opt/libiconv/include"

python包管理工具

包管理工具是指类似maven/gradle的管理工具,和maven包管理不同的是,python还要考虑虚拟环境,有了虚拟环境,才能在不同的虚拟环境安装不同版本的包,就相当于一个项目对应一个虚拟环境,一个虚拟环境安装不同的包

名词介绍

pip包管理

virtualenv虚拟环境

不同的管理工具及方案

方案一:传统模式pip+virtualenv

包依赖管理文件requirements.txt

问题:在pycharm中莫名其妙的找不到已经安装的包(eg:pandas_bokeh)

安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#安装virtualenv:
pip3 install virtualenv --break-system-packages
#创建个虚拟环境目录
mkdir pytho work_python3
➜ paddleseg_python3 ls
#Python 3创建虚拟环境
➜ paddleseg_python3 python3 -m venv .
#查看当前目录,可以发现有几个文件夹和一个pyvenv.cfg文件:
➜ paddleseg_python3 ls
bin include lib pyvenv.cfg
#继续进入bin目录
➜ paddleseg_python3 cd bin
#激活该venv环境
➜ bin source activate
#查看当前目录,里面有python3、pip3等可执行文件,实际上是链接到Python系统目录的软链接。
(paddleseg_python3) ➜ bin ls
Activate.ps1 activate.csh pip pip3.12 python3
activate activate.fish pip3 python python3.12
#下面正常安装各种第三方包

# 退出当前环境
(proj101env) bin$ deactivate
bin$

方案二:pipenv

包依赖管理文件Pipfile

问题:网上说依赖慢,依赖乱

1
2
3
brew install pipenv
#设置虚拟环境默认建立在项目目录
echo 'export PIPENV_VENV_IN_PROJECT=true' >> ~/.zshenv

参考:PyCharm+Pipenv虚拟环境作开发和依赖管理

方案三:poetry

问题:放弃有各种bug,对PyCharm兼容差,安装依赖经常失败,pycharm不能自动识别poetry

官方文档

包依赖管理文件pyproject.toml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# mac zsh安装步骤,注意后面用python3安装
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3
# 当前终端临时生效
source $HOME/.poetry/env
# 终端永久生效
echo 'export PATH="$PATH:$HOME/.poetry/bin"' >> ~/.zshrc
# 设置虚拟环境安装到项目目录,如果设置改设置,所有项目的虚拟目录都默认到了~/Library/Caches/pypoetry/virtualenvs该路径下面
poetry config virtualenvs.in-project true

brew update
brew install pyenv

#卸载
wget https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py
python3 get-poetry.py --uninstall
rm get-poetry.py

PyCharm安装插件Poetry

poetry虚拟环境目录~/Library/Caches/pypoetry/virtualenvs

1
2
3
4
#查看虚拟环境
poetry env list
#移除虚拟环境
poetry env remove python3

pyproject.toml 配置文件详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[tool.poetry]
name = "pythonleaning"
version = "0.1.0"
description = ""
authors = ["xuanleung <exxk.lx@gmail.com>"]

[tool.poetry.dependencies]
python = "^3.8"
pandas = "^1.1.4"
nupy = "^0.1.1"
pymongo = "^3.11.1"
matplotlib = "^3.3.3"

[tool.poetry.dev-dependencies]

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

#配置代理仓库
[[tool.poetry.source]]
name = "aliyun"
url = "https://mirrors.aliyun.com/pypi/simple/"

python使用数据库

python与mongodb

1
2
3
4
5
import pymongo
#连接数据库
fund = pymongo.MongoClient('mongodb://ip.cn:14011/')["db_name"]
#条件查询数据,0代表不返回该字段,1代表返回该字段,sort第二个参数1升序,-1降序
result = fund["tb_name"].find({"name": "1"}, {"_id": 0, "name": 1}).sort("name",-1)

python之pandas

DataFrame

loc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#返回为'列标'的那列数据
Series=df['col']
#给满足条件的行row和列col赋新值
df.loc['row','col']='赋新值'
#单列计算,该列全部乘以2
df['col2'] = df['col1'].map(lambda x: x*2)
#不用lambda表达式为下方写法
define square(x):
return (x * 2)
df['col2'] = df['col1'].map(square)
#多列计算用apply,例如col3 = col1 + 2 * col2:
df['col3'] = df.apply(lambda x: x['col1'] + 2 * x['col2'], axis=1)
#图表分开展示
df.plot.line(subplots=True)

# 显示所有列
pd.set_option('display.max_columns', None)
# 显示所有行
# pd.set_option('display.max_rows', None)
# 设置value的显示长度为100,默认为50
# pd.set_option('max_colwidth',100)
# 设置显示的宽度
pd.set_option('display.width', 5000)

参考

一款让Python开发效率提升50%的工具包

Python in 2020 (1) - 环境搭建

python数据可视化

Pandas支持的可视化后端:matplotlib、bokeh、plotly等

Pandas-matplotlib

老版绘图工具,不支持交互,但是资料较多,支持图表多,pandas的默认绘图后端

1
2
3
4
5
6
7
8
9
10
11
import matplotlib.pyplot as plt
x = [0, 1]
y = [0, 1]
plt.figure()
plt.plot(x, y)
plt.savefig("test.jpg")
plt.show()
#--pandas使用--
df = pd.DataFrame(result)
df.plot()
plt.show()

Pandas-Bokeh

首先安装pip install pandas-bokeh

1
2
3
4
5
6
7
import matplotlib.pyplot as plt
import pandas as pd
import pandas_bokeh
pd.set_option('plotting.backend', 'pandas_bokeh')
df = pd.DataFrame(result)
df.plot_bokeh()
plt.show()

Pandas-plotly

Pandas-hvplot

hvPlot提供了基于HoloViews和Bokeh的高级绘图API

Pyecharts

pyecharts/pyecharts

支持交互,基于Echarts,运行后会生成个html在项目目录,要在浏览器打开就可以看到图标了

1
2
3
4
5
6
7
8
9
10
import pyecharts.options as opts
from pyecharts.charts import Line
x = [0, 1]
y = [0, 1]
line = (
Line()
.add_xaxis(x)
.add_yaxis("y", y)
)
line.render()

参考

09-选择适合你的Python可视化工具

AI字幕

参考BingLingGroup/autosub

安装

1
2
3
4
5
#一定要使用http代理,不能用socke5代理,错误详细信息见常见错误1
export all_proxy=http://127.0.0.1:58591
#一定要用pip3
#(废除有bug见错误2)pip3 install git+https://github.com/BingLingGroup/autosub.git@alpha ffmpeg-normalize langcodes
pip3 install git+https://github.com/BingLingGroup/autosub.git@dev ffmpeg-normalize langcodes

使用

1
2
3
4
#dcy1.wmv视频日语(ja-jp)生成中文(zh-cn)字幕
autosub -i dcy1.wmv -S ja-jp -D zh-cn
#-o指定输出路径,不指定要卡住
autosub -i dcy1.wmv -S ja-jp -D zh-cn -o /Users/xuanleung/Downloads/worldvideo/dcy1.zh-cn.srt

常见错误

错误1:

1
ERROR: Could not install packages due to an EnvironmentError: Missing dependencies for SOCKS support.

解决:原因是安装包不支持socks代理,两种解决方法,一是让它支持,二是采用http代理,这里用第二种方法解决,执行export all_proxy=http://127.0.0.1:58591

错误2:

1
2
    return value.encode(encoding or "ascii")
AttributeError: 'NoneType' object has no attribute 'encode'

解决:原因环境变量编码的问题,执行

1
2
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8

上述还无法解决见https://github.com/BingLingGroup/autosub/issues/127上面解决是在dev分支2020.07.02提交的当时还没修复到alpha分支

1
2
#升级dev分支
pip3 install --upgrade git+https://github.com/BingLingGroup/autosub.git@dev

简介

视频转换

官方文档

FFmpeg 视频处理入门教程

常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#查看视频信息
ffprobe 1.mkv
#播放视频
ffplay 1.mkv
#将字幕封装到mkv视频容器中
ffmpeg -i 1.mkv -i 1.ass -c copy 11.mkv
#设置视频源数据里面的标题
ffmpeg -i 1.mkv -metadata title='标题' -c copy 11.mkv
#复制所有的0开头的流(各种音频字幕流)
ffmpeg -i 1.mkv -c copy -map 0 11.mkv
#复制metadata里面的数据
ffmpeg -i 1.mkv -c copy -map_metadata 0 11.mkv
#整合
ffmpeg -i 1.mkv -i 1.ass -metadata title='标题' -c copy -map 0 -map_metadata 0 11.mkv
ffmpeg -i 1.mkv -i 1.ass -metadata title='小公女セーラ 第01話「ミンチン女子学院」' -c copy -map 0 -map_metadata 0 111.mkv

基础

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#基础格式
ffmpeg {全局参数} {输入文件参数} -i {输入文件} {输出文件参数} {输出文件}
# eg:
ffmpeg \
-y \ # 全局参数
-c:a libfdk_aac -c:v libx264 \ # 输入文件参数
-i input.mp4 \ # 输入文件
-c:v libvpx-vp9 -c:a libvorbis \ # 输出文件参数
output.webm # 输出文件
ffmpeg -i input.avi output.mp4 #简写
#常用命令行参数
-c:指定编码器
-c copy:直接复制,不经过重新编码(这样比较快)
-c:v:指定视频编码器
-c:a:指定音频编码器
-i:指定输入文件
-an:去除音频流
-vn: 去除视频流
-preset:指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow。
-y:不经过确认,输出时直接覆盖同名文件。

安装

1
2
#mac
brew install ffmpeg

spring logback 简介

依赖图

可以发现logback在spring-boot-starter依赖里面,所以引入了springboot都自带logback

graph LR
logback-->spring-boot-starter-logging-->spring-boot-starter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
+--- org.springframework.boot:spring-boot-starter -> 2.2.2.RELEASE
| +--- org.springframework.boot:spring-boot:2.2.2.RELEASE
| | +--- org.springframework:spring-core:5.2.2.RELEASE
| | | \--- org.springframework:spring-jcl:5.2.2.RELEASE
| | \--- org.springframework:spring-context:5.2.2.RELEASE
| | +--- org.springframework:spring-aop:5.2.2.RELEASE
| | | +--- org.springframework:spring-beans:5.2.2.RELEASE
| | | | \--- org.springframework:spring-core:5.2.2.RELEASE (*)
| | | \--- org.springframework:spring-core:5.2.2.RELEASE (*)
| | +--- org.springframework:spring-beans:5.2.2.RELEASE (*)
| | +--- org.springframework:spring-core:5.2.2.RELEASE (*)
| | \--- org.springframework:spring-expression:5.2.2.RELEASE
| | \--- org.springframework:spring-core:5.2.2.RELEASE (*)
| +--- org.springframework.boot:spring-boot-autoconfigure:2.2.2.RELEASE
| | \--- org.springframework.boot:spring-boot:2.2.2.RELEASE (*)
| +--- org.springframework.boot:spring-boot-starter-logging:2.2.2.RELEASE
| | +--- ch.qos.logback:logback-classic:1.2.3 #可以看到在springboot里面自带
| | | +--- ch.qos.logback:logback-core:1.2.3
| | | \--- org.slf4j:slf4j-api:1.7.25 -> 1.7.29
| | +--- org.apache.logging.log4j:log4j-to-slf4j:2.12.1
| | | +--- org.slf4j:slf4j-api:1.7.25 -> 1.7.29
| | | \--- org.apache.logging.log4j:log4j-api:2.12.1
| | \--- org.slf4j:jul-to-slf4j:1.7.29
| | \--- org.slf4j:slf4j-api:1.7.29
| +--- jakarta.annotation:jakarta.annotation-api:1.3.5
| +--- org.springframework:spring-core:5.2.2.RELEASE (*)
| \--- org.yaml:snakeyaml:1.25

logback-spring.xml介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<?xml version="1.0" encoding="UTF-8"?>
<!-- Logback configuration. See http://logback.qos.ch/manual/index.html -->
<!--
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration scan="true" scanPeriod="10 seconds" debug="false">
<!--服务名称,通过读取spring配置项spring.application.name-->
<springProperty scope="context" name="APP_NAME" source="spring.application.name" />
<!--日志输出类型,可在配置文件通过spring.cloud.config.logback-profile进行设置日志输出类型 -->
<springProperty scope="context" name="LOG_TYPE" source="spring.cloud.config.logback-profile" />
<!--定义日志的目录,logs为项目根目录下logs目录 -->
<property name="LOG_PATH" value="logs" />
<!--定义日志的文件名 -->
<property value="${LOG_PATH}/${APP_NAME}.log" name="LOG_FILE_NAME" />
<!-- %d{yyyy-MM-dd}:按天进行日志滚动 %i:当文件大小超过maxFileSize时,按照i进行文件滚动 -->
<property value="${LOG_PATH}/${APP_NAME}-%d{yyyy-MM-dd}-%i.log" name="LOG_FILE_NAME_PATTERN" />
<!--定义日志的格式化标准 -->
<property name="LOG_FORMAT" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n" />

<!-- 文件输出: 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 指定日志文件的名称 -->
<file>${LOG_FILE_NAME}</file>
<!--日志文件分割机制-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE_NAME_PATTERN}</fileNamePattern>
<!--日志保留天数-->
<MaxHistory>30</MaxHistory>
<!--当天日志当大于100M进行分割-->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 日志输出格式: -->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>${LOG_FORMAT}</pattern>
</layout>
</appender>

<!--控制台输出:也就是前端显示输出 -->
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>${LOG_FORMAT}</pattern>
</layout>
</appender>

<!-- 定义不同的包,不同的日志级别(TRACE < DEBUG < INFO < WARN < ERROR),additivity生效级别true都有效(所有日志输出类型,包含默认的),false只是当前(当前配置的输出日志类型)有效 -->
<logger name="com.exxk" level="debug" />
<logger name="org.springframework" level="debug" additivity="false"></logger>

<!--选择那个日志输出类型,对应上面的appender,支持多个同时选择 -->
<root level="info">
<!--stdout设置为默认输出类型,不需要的输出类型可以直接注释-->
<appender-ref ref="stdout" />
<!--通过application配置文件的spring.cloud.config.logback-profile配置项进行指定加载那个日志输出类型,值为appender的name -->
<appender-ref ref="${LOG_TYPE}" />
</root>
</configuration>

application.properties

1
2
3
spring.application.name=testDemo
#指定那个输出类型
spring.cloud.config.logback-profile=FILE

log 日志脱敏和超长日志处理

需求:

因为日志里面含有大量的base64的图片数据,各处都有打印,导致日志过大,日志不美观排查问题不方便

参考

logback-spring.xml

一般人不敢动系列之—基于logback的日志“规范”和“脱敏”

国际化配置

spring自带,所以不需要添加任何依赖

  1. resources目录添加

    1
    2
    3
    4
    5
    6
    7
    8
    #创建message.properties文件并添加
    user.name=userName
    ----------------------------
    #创建message_en.properties文件并添加
    user.name=user name
    ---------------------------
    #创建message_zh.properties文件并添加
    user.name=用户名
  2. spring配置文件添加配置spring.messages.basename=message其中message为国际化的文件,就是上面添加的文件名,如果有文件夹包裹,从resources带上文件相对路径

  3. 添加测试类,关键类MessageSource是读取国际化文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.MessageSource;
    import org.springframework.context.i18n.LocaleContextHolder;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;

    @RestController
    @RequestMapping(value = "/test")
    public class TestControl {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    MessageSource messageSource;

    @RequestMapping(value = "/glob")
    public String glob() {
    String userNmae = messageSource.getMessage("user.name", null, LocaleContextHolder.getLocale());
    logger.info("glob :" + userNmae);
    return userNmae;
    }
    }
  4. 测试,使用postman请求该接口,然后请求headers里面添加Accept-Language:chAccept-Language:en就能返回对应的翻译了

常见问题

  1. 出现No message found under code 'user.name' for locale 'ch'.错误

    解决:在配置文件application.properties配置#spring.messages.basename=<你的国际化文件>,或者检查国际化文件是否存在和配置的文件是否匹配

需求

客户需要git自动化部署,但是又不能提供源码,所以打包成jar包,然后在套壳,依赖jar进行部署

原理

graph LR
A(springboot源项目)-->G(打包发布成jar,含main class)--做为依赖-->L[springboot套壳项目]-->E[自动部署]

利用maven仓库打包步骤

  1. 删除源项目pom.xml里面的<build></build>标签及里面的内容

  2. 如果项目里面有公共项目本地依赖(common等),都要上传,因为打包jar不会打包依赖到jar包里面,上传需要在pom.xml里面添加,然后执行mave lifecycle 里面的 deploy

    1
    2
    3
    4
    5
    6
    7
    8
    <distributionManagement>
    <repository>
    <!--这里的id要和maven里的的settings.xml的id一致-->
    <id>nexus</id>
    <name>Nexus Release Repository</name>
    <url>http://ipaddress/repository/maven-third/</url>
    </repository>
    </distributionManagement>

    注意:

    1. 上传报错的话,检查依赖包是否设置<version>0.0.1-SNAPSHOT</version>需要改成<version>0.0.1</version>因为SNAPSHOT上传需要特殊权限

    2. 上传没有权限,需要添加nexus中仓库的角色权限nx-repository-view-*-*-edit

    3. 检查maven的设置文件setting.xml

      1
      2
      3
      4
      5
      6
      7
      <servers>
      <server>
      <id>nexus</id>
      <username>read</username>
      <password>read***</password>
      </server>
      </servers>
    4. 如果是多项目结构,外面的父项目框架,不需要deploy,在pom.xml添加下面这个设置

      1
      2
      3
      <properties>
      <maven.deploy.skip>true</maven.deploy.skip>
      </properties>
  3. 新建个maven空项目,其中pom.xml如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!-- 这个千万不能添加,添加会提示找不到main class-->
    <!-- <parent>-->
    <!-- <groupId>org.springframework.boot</groupId>-->
    <!-- <artifactId>spring-boot-starter-parent</artifactId>-->
    <!-- <version>2.1.12.RELEASE</version>-->
    <!-- </parent>-->

    <groupId>com.zy</groupId>
    <!-- id不能和原项目一样,不然会提示自己依赖自己-->
    <artifactId>bpf_pf_router_zy</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>
    <name>bpf_pf_router_zy</name>

    <properties>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <skipTests>true</skipTests>
    </properties>

    <dependencies>
    <!-- 源项目打包成的jar-->
    <dependency>
    <groupId>com.nantian</groupId>
    <artifactId>bpf_pf_router</artifactId>
    <version>1.0.0</version>
    </dependency>
    </dependencies>

    <!-- 添加主类,主类在原项目,也就是第一步里面删除的那部分里面有-->
    <build>
    <plugins>
    <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <executions>
    <execution>
    <goals>
    <goal>repackage</goal>
    </goals>
    <configuration>
    <mainClass>com.nantian.bpf.router.App</mainClass>
    </configuration>
    </execution>
    </executions>
    </plugin>
    </plugins>
    </build>
    </project>

利用maven-dependency-plugin进行本地打包

  1. 在壳项目pom.xml添加如下配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    .......
    <repositories>
    <repository>
    <id>lib</id>
    <url>file:${project.basedir}/lib</url>
    </repository>
    </repositories>
    <build>
    ........
    <plugin>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
    <execution>
    <phase>compile</phase>
    <goals>
    <goal>copy-dependencies</goal>
    </goals>
    <configuration>
    <outputDirectory>${project.build.directory}/lib</outputDirectory>
    </configuration>
    </execution>
    </executions>
    </plugin>
    </plugins>
    </build>
    ......
  2. 把maven本地库里面的原项目的依赖放到壳项目的lib目录里面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    ├── README.md
    ├── lib
    │   └── com
    │   └── nantian
    │   └── bpf_pf_router
    │   ├── 1.0.0
    │   │   ├── _remote.repositories
    │   │   ├── bpf_pf_router-1.0.0.jar
    │   │   └── bpf_pf_router-1.0.0.pom
    │   ├── maven-metadata-local.xml
    │   ├── maven-metadata-nexus.xml
    │   └── resolver-status.properties
    ├── pom.xml
    ├── src
    │   └── main
    │   ├── java
    │   └── resources
    │   └── bootstrap.properties
    └── target
    └── cnpc_dj_business_facerouter-1.0.0.jar
  3. 更新时将jar更新到lib目录时,如果只更新了jar,需要注意清除maven本地库(lib 加载到 maven本地库,本地库在打包进jar),否则就更新lib里面的其他文件,这样就能识别出来lib发生了更新

       graph LR
    a[lib]-->b[maven本地库]-->c[jar]

利用lib打包步骤(废弃暂时不能解决)

  1. 改造壳项目pom.xml,修改依赖为本地依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
      <dependencies>
    <dependency>
    <groupId>com.nantian</groupId>
    <artifactId>bpf_pf_router</artifactId>
    <version>1.0.0</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/src/libs/bpf_pf_router-1.0.0.jar</systemPath>
    </dependency>
    </dependencies>
  2. 把原项目jar包放到项目src目录

  3. 改造壳项目pom.xml,修改打包参数,不修改,不会把lib打包进jar包

    1
    2
    3
    4
    5
    6
    7
    8
    <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
    <!--添加下面这句 -->
    <includeSystemScope>true</includeSystemScope>
    </configuration>
    </plugin>

问题

  1. jar包里面包含依赖,利用本地jar包打包时,依赖不自动打入(暂时未能解决)

ELK/EFK简介

E(Elasticsearch)+L(Logstash)+K(Kibana)

E(Elasticsearch)+F(Filebeat)+K(Kibana)

Redis/Mq/kafka大数据高提高弹性时候可选

graph LR
B(beats数据采集)-.->G([redis/mq/kafka])-.->L[Logstash数据管道/处理]-->E[Elasticsearch数据存储/索引]-->K[Kibana数据分析/显示]
B-->L

Logstash

输入支持:tcp,http,file,beats,kafka,rabbitmq,redis,log4j,elasticsearch,jdbc,websocket

过滤器支持:grok,ruby,mutate,json

输出支持:elasticsearch,File,Emial,http,Kafka,Redis,MongoDB,Rabbitmq,Syslog,Tcp,Websocket,Zabbix,Stdout,Csv

Filebeat vs fluent

Filebeat主要用于数据采集,轻量对应用服务器消耗较小,虽然Logstash也可以采集数据,但Logstash占用应用服务器性能比Filebeat大

fluent是Filebeat的高级版,支持很多其他日志输入模式

springboot log框架包

架构选型

方案一 EFK(docker log模式)

利用Filebeat采集docker日志,从而监控docker上所有或指定服务的日志,实现SpringCloud的日志监听

优点: 对现有服务侵入无,不需要改造现有服务

缺点:强依赖于docker,只能监听docker

graph LR
B(Filebeat收集docker日志)-->E[Elasticsearch]-->K[Kibana]

方案二 Logstash采用

优点:简洁,搭建快速

缺点:没缓冲,可能会有瓶颈

graph LR
B(Logstash收集本地log文件)-->E[Elasticsearch]-->K[Kibana]

方案三 Logstash+redis+Logstash(未验证)

参考:搭建 ELK 实时日志平台并在 Spring Boot 和 Nginx 项目中使用

优点:

  1. 直接读取日志文件,对原来的系统入侵无,
  2. 支持所有服务,例如nginx,springboot等只要能生成日志文件的

缺点:

  1. 需要在读取日志文件的服务器都安装Logstash(shipper角色)
  2. 采用docker部署的时候,springboot需要映射日志目录
graph LR
B(Logstash收集本地log文件/Shipper)--写入-->G([redis])--读取-->L[Logstash/Indexer角色]-->E[Elasticsearch]-->K[Kibana]

方案四 kafka+logstash(未验证)

参考:Spring Cloud集成ELK完成日志收集实战(elasticsearch、logstash、kibana

优点:

  1. 不需要在应用服务器安装额外的服务
  2. 支持docker部署,不需要额外映射服务目录

缺点:

  1. 需要改造springboot
  2. 不支持nginx、数据库等服务
graph LR
B(springboot)--写入-->G([kafka])--读取-->L[Logstash]-->E[Elasticsearch]-->K[Kibana]

方案五 EFK+logback-more-appenders

参考:sndyuk/logback-more-appenders

优点:直接通过jar集成logback框架,干净

缺点:只适合于springboot

graph LR
A(springboot依赖logback-more-appenders)-->B(fluent)-->E[Elasticsearch]-->K[Kibana]

步骤:

  1. Docker安装fluent,fluent镜像需要自己制作exxk/fluent-elasticsearch:latest
    参考fluentd/container-deployment/docker-compose

    1
    2
    3
    4
    5
    # fluentd/Dockerfile
    FROM fluent/fluentd:v1.6-debian-1
    USER root
    RUN ["gem", "install", "fluent-plugin-elasticsearch", "--no-document", "--version", "3.5.2"]
    USER fluent
  2. springboot引入maven依赖

    1
    2
    3
    // https://mvnrepository.com/artifact/com.sndyuk/logback-more-appenders
    compile group: 'com.sndyuk', name: 'logback-more-appenders', version: '1.4.2'
    compile group: 'org.fluentd', name: 'fluent-logger', version: '0.3.4'
  3. springboot在logback.xml添加fluentd的日志输出模式(具体见logback的配置)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
      <!--EFK ip -->
    <springProperty scope="context" name="fluentHost" source="logback.fluent.host" />
    <!--EFK 端口 -->
    <springProperty scope="context" name="fluentPort" source="logback.fluent.port" />
    <!--FLUENT输出 -->
    <appender name="FLUENT"
    class="ch.qos.logback.more.appenders.FluentLogbackAppender">
    <tag>${APP_NAME}</tag>
    <label>logback</label>
    <remoteHost>${fluentHost}</remoteHost>
    <port>${fluentPort}</port>
    <layout>
    <pattern>${LOG_FORMAT}</pattern>
    </layout>
    </appender>
  4. 动态配置application

    1
    2
    3
    spring.cloud.config.logback-profile=FLUENT
    logback.fluent.host=${LOGBACK_FLUENT_HOST:xxx.cn}
    logback.fluent.port=${LOGBACK_FLUENT_PORT:14021}
  5. 然后运行springboot触发日志

  6. 然后去页面配置见日志EFK框架中elastic的配置使用

EFK/ELK部署

参考deviantony/docker-elk

docker-stack.yml内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
version: '3.3'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.9.0
configs:
- source: elastic_config
target: /usr/share/elasticsearch/config/elasticsearch.yml
environment:
ES_JAVA_OPTS: "-Xmx256m -Xms256m"
ELASTIC_PASSWORD: changeme
discovery.type: single-node
TZ: Asia/Shanghai
deploy:
mode: replicated
replicas: 1
placement:
constraints: [node.hostname == me]
logstash:
image: docker.elastic.co/logstash/logstash:7.9.0
configs:
- source: logstash_config
target: /usr/share/logstash/config/logstash.yml
- source: logstash_pipeline
target: /usr/share/logstash/pipeline/logstash.conf
environment:
LS_JAVA_OPTS: "-Xmx256m -Xms256m"
TZ: Asia/Shanghai
deploy:
mode: replicated
replicas: 0
placement:
constraints: [node.hostname == me]
kibana:
image: docker.elastic.co/kibana/kibana:7.9.0
environment:
#无效,但是似乎不重要
TZ: Asia/Shanghai
ports:
- "14020:5601"
configs:
- source: kibana_config
target: /usr/share/kibana/config/kibana.yml
deploy:
mode: replicated
replicas: 1
placement:
constraints: [node.hostname == me]
filebeat:
image: docker.elastic.co/beats/filebeat:7.9.0
user: root
command: filebeat -e -strict.perms=false
environment:
TZ: Asia/Shanghai
configs:
- source: filebeat_config
target: /usr/share/filebeat/filebeat.yml
volumes:
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
deploy:
mode: replicated
replicas: 0
placement:
constraints: [node.hostname == me]
fluent:
image: exxk/fluent-elasticsearch:latest
environment:
TZ: Asia/Shanghai
ports:
- "14021:24224"
- "14021:24224/udp"
configs:
- source: fluent_config
target: /fluentd/etc/fluent.conf
deploy:
mode: replicated
replicas: 1
placement:
constraints: [node.hostname == me]
configs:
elastic_config:
external: true
logstash_config:
external: true
logstash_pipeline:
external: true
kibana_config:
external: true
filebeat_config:
external: true
fluent_config:
external: true

各个配置文件配置内容如下:

elastic_config

1
2
3
4
5
6
7
8
9
10
11
12
13
---
## Default Elasticsearch configuration from Elasticsearch base image.
## https://github.com/elastic/elasticsearch/blob/master/distribution/docker/src/docker/config/elasticsearch.yml
#
cluster.name: "docker-cluster"
network.host: 0.0.0.0

## X-Pack settings
## see https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-xpack.html
#
xpack.license.self_generated.type: trial
xpack.security.enabled: true
xpack.monitoring.collection.enabled: true

kibana_config

1
2
3
4
5
6
7
8
9
10
11
12
13
---
## Default Kibana configuration from Kibana base image.
## https://github.com/elastic/kibana/blob/master/src/dev/build/tasks/os_packages/docker_generator/templates/kibana_yml.template.js
#
server.name: kibana
server.host: 0.0.0.0
elasticsearch.hosts: [ "http://elasticsearch:9200" ]
monitoring.ui.container.elasticsearch.enabled: true

## X-Pack security credentials
#
elasticsearch.username: elastic
elasticsearch.password: changeme

logstash_config

1
2
3
4
5
6
7
8
9
10
11
12
---
## Default Logstash configuration from Logstash base image.
## https://github.com/elastic/logstash/blob/master/docker/data/logstash/config/logstash-full.yml
#
http.host: "0.0.0.0"
xpack.monitoring.elasticsearch.hosts: [ "http://elasticsearch:9200" ]

## X-Pack security credentials
#
xpack.monitoring.enabled: true
xpack.monitoring.elasticsearch.username: elastic
xpack.monitoring.elasticsearch.password: changeme

logstash_pipeline

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
input {
tcp {
port => 5000
}
}

## Add your filters / logstash plugins configuration here

output {
elasticsearch {
hosts => "elasticsearch:9200"
user => "elastic"
password => "changeme"
}
}

filebeat_config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
filebeat.config:
modules:
path: ${path.config}/modules.d/*.yml
reload.enabled: false

filebeat.autodiscover:
providers:
- type: docker
hints.enabled: true

processors:
- add_cloud_metadata: ~

output.elasticsearch:
hosts: 'elasticsearch:9200'
username: 'elastic'
password: 'changeme'

fluent_config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# fluentd/conf/fluent.conf

<source>
@type forward
port 24224
bind 0.0.0.0
</source>

<match *.**>
@type copy

<store>
@type elasticsearch
host elasticsearch
port 9200
logstash_format true
logstash_prefix fluentd
logstash_dateformat %Y%m%d
include_tag_key true
type_name access_log
tag_key @log_name
flush_interval 1s
user elastic
password changeme
</store>

<store>
@type stdout
</store>
</match>

springboot的配置使用很简单,也经常用,下面就是常用的AutoConfiguration入口

1
2
3
@EnableAutoConfiguration //启用自动配置
@ComponentScan
public class Application{}

但是这里主要讲下自动配置的禁用

如何禁用某些自动配置

需求场景

  1. 在公共依赖里面引入了数据库的依赖,你会发现,某些项目不需要数据库,但是由于公共依赖,也得配置数据库的连接地址
  2. 例如使用spring cloud config-bus热更新配置时,这个功能属于可选功能,因为有些环境可能不支持mq,但是不能每次打包都把依赖移除

禁用设置

启动文件的修改

主要是在启动类上面的@EnableAutoConfiguration注解添加参数exclude后面填入需要禁用的启动类,这种适合场景1,因为已经确定这个服务是不需要这个配置的了

1
2
3
@EnableAutoConfiguration(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
@EnableConfigurationProperties
public class App {}

配置文件的修改

application.properties里面添加spring.autoconfigure.exclude这个配置项,这个就很灵活了,只需要修改配置文件,就可以开启或禁用某些功能

1
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,org.springframework.boot.actuate.autoconfigure.metrics.amqp.RabbitMetricsAutoConfiguration,org.springframework.boot.actuate.autoconfigure.amqp.RabbitHealthIndicatorAutoConfiguration,org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration,org.springframework.cloud.bus.BusAutoConfiguration

常用的实战场景

禁用操作很简单,但是要找到合适的配置禁用,这就需要了解功能用到了那些自动配置项,下面介绍几个常用场景,需要禁用的自动配置类

1
2
3
4
5
6
7
8
#mongodb数据库 依赖 org.springframework.data:spring-data-mongodb
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration
#redis数据库 依赖 org.springframework.boot:spring-boot-starter-data-redis
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
#rabbitMQ 依赖 org.springframework.boot:spring-boot-starter-amqp
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration
#springCloud-Bus 依赖org.springframework.cloud:spring-cloud-starter-bus-amqp
spring.autoconfigure.exclude=org.springframework.cloud.bus.BusAutoConfiguration,org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration