2021-08-31
- 容器container是一个进程,容器运行于属于自己的独立的命名空间,因此容器可以拥有自己的root文件系统、网络配置、进程空间等。容器内的应用进程直接运行于宿主机的内核。
- 镜像image包含了容器的文件系统,也包含了很多其他的配置。(镜像运行起来就是容器)。docker镜像是分层的结构,镜像构建时会一层层的构建,前一层是后一层的基础,每一层构建完就不会再发生改变,后一层的任何改变只会发生在自己的这一层。如删除前一层的文件,实际上不是真的删除前一层的文件,而是仅在当前层标记该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是该文件实际上会一直跟随镜像。
- Dockerfile用来创建镜像,docker-compose指定如何运行镜像。
docker ps #获取已运行的容器
docker ps -a #获取所有的容器
docker images #获取所有镜像
#从仓库下载一个镜像
docker pull nginx:latest
#将镜像保存到本地
docker save -o docker-nginx.tar nginx
#从本地导入镜像
docker load -i docker-nginx.tar
#运行一个镜像,-d后台运行。-p将主机的端口映射到容器的端口。
docker run -d -p 80:80 image_name:image_version
#启动一个shell,执行了两个命令,第一个命令随机挑选了一个数并写到了txt文件中,第二个命令让容器保持运行
docker run -d ubuntu bash -c "shuf -i 1-10000 -n 1 -o /data.txt && tail -f /dev/null"
#启动镜像,并执行后面的命令
docker run -it ubuntu ls /
#--name 指定容器的名称
docker run -d -p 17106:3306 --name 171-mysql mysql8:171-uam
#进入容器中,-i保持stdin打开,-t分配一个终端
docker exec -i -t <container-id> /bin/bash
#查看容器内此txt文件内容
docker exec <container-id> cat /data.txt
#停止容器运行
docker stop <container-id>
#移除容器
docker rm <container-id>
#停止并移除容器运行
docker rm -f <container-id>
#根据当前路径的dockerfile构建一个镜像。-t给镜像起个名字。
# . 表示在当前路径下,可以使用一个.dockerignore文件来忽略某些文件。
docker build -f Dockerfile -t image_name:image_version .
#创建一个named volume
docker volume create todo-db
#将volumn挂载到/etc/todos路径下
docker run -dp 3000:3000 -v todo_db:/etc/todos image_name:image_version
#查看此named volume的信息
docker volume inspect todo-db
#使用了一个bind mounts,将主机的当前路径挂载到容器内的/app路径
#-w表示当前的工作路径,-d表示后台运行,-c表示执行后面的命令,-p表示端口映射
docker run -dp 3000:3000 -w /app -v "$(pwd):/app" node:12-alpine sh -c "yarn install && yarn run dev"
#查看logs,-f表示跟随日志输出
docker logs -f <container-id>
#创建了一个network
docker network create todo-app
#启动了一个mysql容器,并接入到network,使用-e定义了初始化数据库用的环境变量,
#mysql还支持MYSQL_HOST(mysql server的主机名),MYSQL_USER。docker自动创建了一个todo-mysql-data的volume。
docker run -d --network todo-app --network-alias mysql \
-v todo-mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=todos \
mysql:5.7
#输入密码后就能进入到mysql中
docker exec -it <mysql-container-id> mysql -p
#加入到这个网络,并进入到bash
docker run -it --network todo-app image_name:image_version /bin/sh
#扫描一个镜像
docker scan image_name:image_version
#查看创建历史,--no-trunc获取全部输出
docker image history [--no-trunc] mysql:5.7
restart策略
#
- 当使用
docker run
命令时可以使用--restart
来配置容器的重启策略。可选的标志如下:
flag |
description |
no |
任何情况下不会自动重启容器(默认) |
on-failure[:max-retries] |
当容器由于错误(退出代码为非0)而退出时会重启容器。使用:max-retries 来限制容器尝试重启的次数。 |
always |
始终在容器停止时重启,除非容器是被手动停止的。在docker重新启动时容器也会重启。 |
unless-stopped |
类似于always,但是当容器停止后,重启docker容器并不会启动。 |
参考链接:
use-a-restart-policy
docker-compose
#
docker-compose version
获取版本信息。
- 创建一个叫
docker-compose.yml
的文件,如将下面这个命令转化为docker-compose。
#转换前
docker run -dp 3000:3000 -w /app -v "$(pwd):/app" --network todo-app \
-e MYSQL_HOST=mysql -e MYSQL_USER=root \
-e MYSQL_PASSWORD=secret -e MYSQL_DB=todos \
node:12-alpine sh -c "yarn install && yarn run dev"
#转换前
docker run -d \
--network todo-app --network-alias mysql \
-v todo-mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret -e MYSQL_DATABASE=todos \
mysql:5.7
#转换后
version: "3.7"
services:
app:
image: node:12-alpine
ports:
- 3000:3000
working_dir: /app
#docker compose中volume定义可以使用相对路径。
volumes:
- ./:/app
command: sh -c "yarn install && yarn run dev"
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASSWORD: secret
MYSQL_DB: todos
mysql:
image: mysql:5.7
volumes:
- todo-mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: todos
volumes:
todo-mysql-data:
- 使用
docker-compose up -d
命令执行,-d参数使得在后台运行,这个命令会自动在应用间创建network。
- 使用
docker-compose logs -f
来查看日志。-f表示follow,会将日志的变化输出到控制台。
- 使用
docker-compose logs -f app
来查看特定服务的日志。
docker-compose down [--volumes]
关闭并移除,–volumes指定是否删除volumes。
dockerfile
#
- 一个Dockerfile大部分情况下以FROM指令开始,FROM指令指定了构建的父镜像。
ENV
用来设置环境变量,通过${xxx}
的方式使用。
- CMD在docker run时运行,RUN在docker build时运行。
- RUN会在新的一层执行命令。
多阶段构建
#
FROM maven AS build
WORKDIR /app
COPY . .
RUN mvn package
FROM tomcat
COPY --from=build /app/target/file.war /usr/local/tomcat/webapps
参考链接:
Orientation and setup | Docker Documentation
2021-08-30
settings.gradle
#
rootProject.name = 'demo'
include('app')
- rootProject指定了构建的名称,默认以上级目录命名。
- include(’…’)定义了一个叫app的子项目,子项目包含自己的代码和构建逻辑。
gradle.properties
#
最终的配置组合了所有的命令行提供的属性和gradle.properties文件。
配置优先级:
#
- 命令行使用-P/–project-prop传递的参数;
- GRADLE_USER_HOME目录的gradle.properties;
- 项目根目录的gradle.properties;
- gradle安装目录的gradle.properties.
#指定构建时jvm参数。
org.gradle.jvmargs=-Xms2g
#并行编译,会使用org.gradle.workers.max参数
org.gradle.parallel=(true,false)
#默认为CPU的数量
org.gradle.workers.max=
#使用systemProp.前缀可在gradle.properties中配置系统属性,或者命令行中使用-D(不加systemProp,有多个project时,只有根路径下的以systemProp开头的属性会被使用,其他的都会被忽略。
参考链接:
Build Environment (gradle.org)
构建
#
tasks
#
- 每个gradle build由多个projects组成,一个project又由多个tasks组成。
tasks.register('upper') {
doLast {
String someString = 'mY_nAmE'
println "Original: $someString"
println "Upper case: ${someString.toUpperCase()}"
}
}
tasks.register('hello') {
dependsOn tasks.upper
doLast {
print 'hello world'
}
}
#执行gradle -q hello,-q表示抑制日志消息
tasks.register('hello') {
doLast {
println 'Hello Earth'
}
}
tasks.named('hello') {
doFirst {
println 'Hello Venus'
}
}
tasks.named('hello') {
doLast {
println 'Hello Mars'
}
}
tasks.named('hello') {
doLast {
println 'Hello Jupiter'
}
}
#执行gradle -q hello
#doFirst和doLast可以被执行多次,他们被添加到task的actions list的开始或结束位置,当task执行时,在action list中的action会被按顺序执行。
默认task
#
defaultTasks 'clean', 'run'
tasks.register('clean') {
doLast {
println 'Default Cleaning!'
}
}
tasks.register('run') {
doLast {
println 'Default Running!'
}
}
#通过gradle -q执行
为构建脚本添加外部依赖
#
- 如果构建脚本需要使用外部的库,可以使用buildscript,buildscript中添加的依赖只对构建脚本有效。
//使用库中的某个类
import org.apache.commons.codec.binary.Base64
buildscript {
repositories {
mavenCentral()
}
//将库添加到classpath路径下
dependencies {
classpath group: 'commons-codec', name: 'commons-codec', version: '1.2'
}
}
tasks.register('encode') {
doLast {
def byte[] encodedString = new Base64().encode('hello world\n'.getBytes())
println new String(encodedString)
}
}
#gradle -q encode
2021-08-30
SLF4J:the simple logging facade for java。
2021-08-23
例:
#
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>testFile.log</file>
<!-- 将 immediateFlush 设置为 false 可以获得更高的日志吞吐量 -->
<immediateFlush>false</immediateFlush>
<!-- 默认为 ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<appender name="SYSLOG" class="ch.qos.logback.classic.net.SyslogAppender">
<syslogHost>remote_home</syslogHost>
<port>5140</port>
<facility>AUTH</facility>
<suffixPattern>[%thread] %logger %msg</suffixPattern>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
<logger name="space.xiaoxiang" level="debug" additivity="true"/>
</configuration>
appender
#
AppenderBase
#
- 是一个抽象类,实现了Appender接口,提供了基本方法供appender使用。
OutputStreamAppender
#
- 是ConsoleAppender、FileAppender以及 RollingFileAppender的父类。
ConsoleAppender
#
- 将日志输出到控制台,ConsoleAppender通过用户指定的encoder格式化日志事件。
FileAppender
#
RollingFileAppender
#
- 具有轮转日志文件的功能。比如在满足特定的条件后,将日志输出到另一个文件。
SocketAppender 和 SSLSocketAppender
#
SMTPAppender
#
- 收集日志到缓冲区中,当用户指定的事件发生时,将从缓冲区中取出适当的内容进行发送。
DBAppender
#
- 将日志插到三张数据库表中,三张表分别是logging_event, logging_event_property 与 logging_event_exception。
SyslogAppender
#
- 可以将日志发送给远程的syslog守护线程。
- 日志事件的严重程度是根据日志事件的级别转换来的,DEBUG被转换为7,INFO被转换为6,WARN为4,ERROR为3。
SiftingAppender
#
AsyncAppender
#
- 作为一个事件调度器存在,必须调用其他appender来完成操作。
encoder
#
- encoder将日志事件转换为字节数组,同时将字节数组写入到一个OutputStream中。
- PatternLayoutEncoder是目前唯一真正有用的encoder,它仅包裹了一个PatternLayout就完成了大部分的工作。
layout
#
PatternLayout
#
-
可以通过调整PatternLayout的转换模式来进行定制,PatternLayout的转换模式由字面量和转换说明符组成,每一个转换说明符由一个百分号开始%
,后面跟随格式修改器,以及可用大括号括起来的转换字符和可选的参数。格式修改器可以对字段进行对齐,修改最大最小宽度等。
-
括号用于对转换模式进行分组,(
和)
都有特殊的含义。
-
名为com.foo
的logger是名为com.foo.bar
的logger的父级。(命名层次结构)
-
root logger的默认层级为DEBUG。
-
层级的排序:TRACE < DEBUG < INFO < WARN < ERROR。
-
appender具有叠加性:logger L的日志输出会遍历L和它父级中所有的appender,如果L的某个上级P,P设置了additivity=false,那么L的日志输出会遍历从L到P(不包括P)的所有appender。additivity默认为true。
logback初始化步骤
#
- 在类路径下寻找名为logback-test.xml。
- 如果没找到,找名为logback.groovy的文件。
- 如果没找到,找名为logback.xml的文件。
- 如果没找到,会用ServiceLoader工具去解析
META-INF\services\ch.qos.logback.classic.spi.Configutator
路径下实现了Configurator接口的类
- 如果还没找到,logback会通过BasicConfigurator为自己进行配置,日志将会全部打印在控制台。
2021-08-20
- oAuth是一种授权机制,数据所有者告诉授权系统,允许第三方应用获取这些数据,授权系统从而产生一个短期的进入令牌(token),第三方应用通过令牌获取数据。
授权码方式
#
第三方应用(记为a)访问CALLBACK_URL这个网站,会重定向到授权系统(记为b),url如1所示
1. 请求授权码
#
https://b.com/oauth/authorize?
response_type=code& #表示参数要求返回授权码
client_id=CLIENT_ID& #客户端id,b就知道是谁在请求
redirect_uri=CALLBACK_URL& #b接收请求后跳转的网站
scope=read #授权范围
2. 返回授权码
#
在授权系统登录成功后,会重定向到CALLBACK_URL?code=AUTHORIZATION_CODE
,code就是授权码。
3. 请求令牌
#
CALLBACK_URL这个网站会重定向到授权系统,url如下:
https://b.com/oauth/token?
client_id=CLIENT_ID& #客户端id,b就知道是谁在请求
client_secret=CLIENT_SECRET&
grant_type=authorization_code& #授权类型,表明是授权码
code=AUTHORIZATION_CODE& #上一步拿到的授权码
redirect_uri=CALLBACK_URL #b之后跳转的网站
4. 返回令牌
#
授权系统会重定向到CALLBACK_URL,并发送一段JSON数据
{
"access_token":"ACCESS_TOKEN(令牌)",
"token_type":"bearer",
"expires_in":2592000,
"refresh_token":"REFRESH_TOKEN",
"scope":"read",
"uid":100101,
"info":{...}
}
参考链接:
OAuth 2.0 的四种方式 - 阮一峰的网络日志 (ruanyifeng.com)