運維(15) docker-compose部署Sentinel持久化配置到MySQL

2021-12-29 鄭清

一、前言

本文將修改sentinel-dashboard源碼,集成mybatis-plus,持久化配置到mysql,然後製作docker版的sentinel鏡像,方便後期快速部署sentinel-mysql。

Docker version 20.10.8, build 3967b7d

docker-compose version 1.29.2, build 5becea4c

sentinel-dashboard:1.8.2

mybatis-plus-boot-starter:3.4.3.4

mysql5.7

二、docker-compose快速部署Sentinel - MySQL版

# 準備
git clone https://gitee.com/zhengqingya/docker-compose.git
cd docker-compose/Liunx
# 運行
docker-compose -f docker-compose-sentinel-mysql.yml -p sentinel up -d

三、訪問測試

訪問 http://127.0.0.1:8858/#/dashboard

如果sentinel日誌報錯如下

2021-10-03 13:05:47.493 ERROR 1 --- [pool-2-thread-1] c.a.c.s.dashboard.metric.MetricFetcher : Failed to fetch metric from <http://192.168.101.88:8719/metric?startTime=1633237412000&endTime=1633237418000&refetch=false> (ConnectionException: Connection timed out)

解決:讓sentinel所在機器能夠訪問sentinel客戶端ip和埠,即上面日誌中的192.168.101.88:8719

四、sentinel-dashboard源碼修改

sentinel源碼下載 https://github.com/alibaba/Sentinel 進入sentinel-dashboard模塊

1、新增如下依賴

<!-- ========================= 資料庫相關 ========================== -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<!-- mybatis-plus -->
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.4</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.9.RELEASE</version>
</dependency>

<!-- lombok插件 -->
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>

2、application.yml配置

溫馨小提示:源碼對應為application.properties文件,被我修改為application.yml了 mysql相關信息自行修改即可

auth:
# auth settings
filter:
exclude-url-suffixes: htm,html,js,css,map,ico,ttf,woff,png
exclude-urls: /,/auth/login,/auth/logout,/registry/machine,/version
# If auth.enabled=false, Sentinel console disable login
password: sentinel
username: sentinel

# logging settings
logging:
file: ${user.home}/logs/csp/sentinel-dashboard.log
level:
org:
springframework:
web: INFO
pattern:
file: '%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n'
# console: %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n

# Inject the dashboard version. It's required to enable
# filtering in pom.xml for this resource file.
sentinel:
dashboard:
version: '@project.version@'

# cookie name setting
server:
servlet:
session:
cookie:
name: sentinel_dashboard_cookie
port: 8858

# mysql setting
mysql:
host: 127.0.0.1
port: 3306
username: root
password: root
db-name: sentinel

# spring settings
spring:
http:
encoding:
charset: UTF-8
enabled: true
force: true

# 配置數據源
datasource:
url: jdbc:mysql://${mysql.host}:${mysql.port}/${mysql.db-name}?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&useSSL=false # MySQL在高版本需要指明是否進行SSL連接 解決則加上 &useSSL=false
username: ${mysql.username}
password: ${mysql.password}
driver-class-name: com.mysql.jdbc.Driver


# mybatis-plus相關配置
mybatis-plus:
# xml掃描,多個目錄用逗號或者分號分隔(告訴 Mapper 所對應的 XML 文件位置)
mapper-locations: classpath:**/*Mapper.xml
# 實體掃描,多個package用逗號或者分號分隔
typeAliasesPackage: com.alibaba.csp.sentinel.dashboard.mysql.entity
# 以下配置均有默認值,可以不設置
global-config:
# 關閉MP3.0+自帶的banner
banner: false
db-config:
# 主鍵類型 0:"資料庫ID自增", 1:"不操作", 2:"用戶輸入ID",3:"數字型snowflake", 4:"全局唯一ID UUID", 5:"字符串型snowflake";
id-type: auto
# 欄位策略
insert-strategy: not_null
update-strategy: not_null
select-strategy: not_null
# 駝峰下劃線轉換
table-underline: true
# 邏輯刪除配置
logic-delete-field: isDeleted # 全局邏輯刪除的實體欄位名
logic-delete-value: 1 # 邏輯刪除全局值(1表示已刪除,默認為 1)
logic-not-delete-value: 0 # 邏輯未刪除全局值(0表示未刪除,默認為 0)
configuration:
# 是否開啟自動駝峰命名規則映射:從資料庫列名到Java屬性駝峰命名的類似映射
map-underscore-to-camel-case: true
cache-enabled: false
# 如果查詢結果中包含空值的列,則 MyBatis 在映射的時候,不會映射這個欄位
call-setters-on-nulls: true
# 這個配置會將執行的sql列印出來,在開發或測試的時候可以用
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 解決oracle更新數據為null時無法轉換報錯,mysql不會出現此情況
jdbc-type-for-null: 'null'

3、資料庫表準備

新建資料庫sentinel-dashboard & 新建表sentinel-dashboard

CREATE TABLE `t_sentinel_metric` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id,主鍵',
`gmt_create` datetime DEFAULT NULL COMMENT '創建時間',
`gmt_modified` datetime DEFAULT NULL COMMENT '修改時間',
`app` varchar(100) DEFAULT NULL COMMENT '應用名稱',
`timestamp` datetime DEFAULT NULL COMMENT '統計時間',
`resource` varchar(500) DEFAULT NULL COMMENT '資源名稱',
`pass_qps` int(11) DEFAULT NULL COMMENT '通過qps',
`success_qps` int(11) DEFAULT NULL COMMENT '成功qps',
`block_qps` int(11) DEFAULT NULL COMMENT '限流qps',
`exception_qps` int(11) DEFAULT NULL COMMENT '發送異常的次數',
`rt` double DEFAULT NULL COMMENT '所有successQps的rt的和',
`count` int(11) DEFAULT NULL COMMENT '本次聚合的總條數',
`resource_code` int(11) DEFAULT NULL COMMENT '資源的hashCode',
PRIMARY KEY (`id`),
KEY `app_idx` (`app`) USING BTREE,
KEY `resource_idx` (`resource`) USING BTREE,
KEY `timestamp_idx` (`timestamp`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8 COMMENT='Sentinel';

4、MybatisPlus配置類

@EnableTransactionManagement
@Configuration
@MapperScan("com.alibaba.csp.sentinel.dashboard.mysql.mapper")
public class MybatisPlusConfig {

/**
* mybatis-plus分頁插件<br>
* 文檔:https://mp.baomidou.com/guide/page.html <br>
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}

}

5、SentinelMetricEntity

@Data
@EqualsAndHashCode(callSuper = true)
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_sentinel_metric")
public class SentinelMetricEntity extends Model<SentinelMetricEntity> {

@TableId(value = "id", type = IdType.AUTO)
private Long id;
private Date gmtCreate;
private Date gmtModified;
private String app;
private Date timestamp;
private String resource;
private Long passQps;
private Long successQps;
private Long blockQps;
private Long exceptionQps;
private double rt;
private int count;
private int resourceCode;

}

6、SentinelMetricMapper

@MapperScan
public interface SentinelMetricMapper extends BaseMapper<SentinelMetricEntity> {}

7、ISentinelMetricService

public interface ISentinelMetricService extends IService<SentinelMetricEntity> {}

8、SentinelMetricServiceImpl

@Slf4j
@Service
public class SentinelMetricServiceImpl extends ServiceImpl<SentinelMetricMapper, SentinelMetricEntity> implements ISentinelMetricService {}

9、Sentinel mysql持久化

可參考內存持久化類 com.alibaba.csp.sentinel.dashboard.repository.metric.InMemoryMetricsRepository

@Slf4j
@Repository("MysqlMetricsRepository")
public class MysqlMetricsRepository implements MetricsRepository<MetricEntity> {

@Autowired
private ISentinelMetricService sentinelMetricService;

@Override
@Transactional(rollbackFor = Exception.class)
public void save(MetricEntity metric) {
if (metric == null || StringUtil.isBlank(metric.getApp())) {
return;
}
// log.info("MysqlMetricsRepository save: {}", metric);
this.sentinelMetricService.save(this.copyProperties(metric, SentinelMetricEntity.class));
}

@Override
@Transactional(rollbackFor = Exception.class)
public void saveAll(Iterable<MetricEntity> metrics) {
if (metrics == null) {
return;
}
metrics.forEach(this::save);
}

@Override
public List<MetricEntity> queryByAppAndResourceBetween(String app, String resource, long startTime, long endTime) {
List<MetricEntity> resultList = new ArrayList<>();
if (StringUtil.isBlank(app)) {
return resultList;
}
if (StringUtil.isBlank(resource)) {
return resultList;
}
List<SentinelMetricEntity> sentinelMetricEntityList = this.sentinelMetricService.list(
new LambdaQueryWrapper<SentinelMetricEntity>()
.eq(SentinelMetricEntity::getApp, app)
.eq(SentinelMetricEntity::getResource, resource)
.ge(SentinelMetricEntity::getTimestamp, Date.from(Instant.ofEpochMilli(startTime)))
.le(SentinelMetricEntity::getTimestamp, Date.from(Instant.ofEpochMilli(endTime)))
);
// log.info("MysqlMetricsRepository queryByAppAndResourceBetween: {}", sentinelMetricEntityList);
return this.copyList(sentinelMetricEntityList, MetricEntity.class);
}

@Override
public List<String> listResourcesOfApp(String app) {
List<String> resultList = new ArrayList<>();
if (StringUtil.isBlank(app)) {
return resultList;
}
final long startTime = System.currentTimeMillis() - 1000 * 60;
List<SentinelMetricEntity> metricList = this.sentinelMetricService.list(
new LambdaQueryWrapper<SentinelMetricEntity>()
.eq(SentinelMetricEntity::getApp, app)
.ge(SentinelMetricEntity::getTimestamp, Date.from(Instant.ofEpochMilli(startTime)))
);
if (CollectionUtils.isEmpty(metricList)) {
return resultList;
}

Map<String, MetricEntity> resourceCount = new HashMap<>(32);
metricList.forEach(newEntity -> {
String resource = newEntity.getResource();
if (resourceCount.containsKey(resource)) {
MetricEntity oldEntity = resourceCount.get(resource);
oldEntity.addPassQps(newEntity.getPassQps());
oldEntity.addRtAndSuccessQps(newEntity.getRt(), newEntity.getSuccessQps());
oldEntity.addBlockQps(newEntity.getBlockQps());
oldEntity.addExceptionQps(newEntity.getExceptionQps());
oldEntity.addCount(1);
} else {
newEntity.setResource(newEntity.getResource());
resourceCount.put(resource, this.copyProperties(newEntity, MetricEntity.class));
}
});

// Order by last minute b_qps DESC.
return resourceCount.entrySet()
.stream()
.sorted((o1, o2) -> {
MetricEntity e1 = o1.getValue();
MetricEntity e2 = o2.getValue();
int t = e2.getBlockQps().compareTo(e1.getBlockQps());
if (t != 0) {
return t;
}
return e2.getPassQps().compareTo(e1.getPassQps());
})
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}

/**
* 對象屬性拷貝 : 將源對象的屬性拷貝到目標對象
*
* @param source 源對象
* @param clz 目標對象class
* @return 對象數據
*/
private <T> T copyProperties(Object source, Class<T> clz) {
if (source == null) {
return null;
}
T target = BeanUtils.instantiate(clz);
try {
BeanUtils.copyProperties(source, target);
} catch (BeansException e) {
log.error("BeanUtil property copy failed :BeansException", e);
} catch (Exception e) {
log.error("BeanUtil property copy failed:Exception", e);
}
return target;
}

/**
* 拷貝list
*
* @param inList 輸入list
* @param outClz 輸出目標對象class
* @return 返回集合
*/
private <E, T> List<T> copyList(List<E> inList, Class<T> outClz) {
List<T> output = new ArrayList<>();
if (!CollectionUtils.isEmpty(inList)) {
for (E source : inList) {
T target = BeanUtils.instantiate(outClz);
BeanUtils.copyProperties(source, target);
output.add(target);
}
}
return output;
}

}

10、修改內存持久方式為mysql方式

修改以下2個文件

com.alibaba.csp.sentinel.dashboard.controller.MetricController

com.alibaba.csp.sentinel.dashboard.metric.MetricFetcher

// 將之前的
@Autowired
private MetricsRepository<MetricEntity> metricStore;

// 修改為
@Autowired
@Qualifier("MysqlMetricsRepository")
private MetricsRepository<MetricEntity> metricStore;

到此,修改完成,可運行項目查看是否生效 ^_^ 小編運行、停止、再運行sentinel-dashboard發現配置是可以保存到mysql和從mysql恢復的,但sentinel客戶端所在項目如果重啟,配置是無法保留的!

11、sentinel客戶端配置

pom.xml

<!-- Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<exclusions>
<exclusion>
<artifactId>fastjson</artifactId>
<groupId>com.alibaba</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

bootstrap.yml

spring:
cloud:
sentinel:
enabled: true # 自動化配置是否生效
eager: true # 禁用控制臺懶加載
transport:
dashboard: www.zhengqingya.com:8858 # 控制臺地址
client-ip: ${spring.cloud.client.ip-address} # 獲取本機IP位址
port: 18719 # 啟動該服務,會在應用程式的相應伺服器上啟動HTTP Server,並且該伺服器將與Sentinel dashboard進行交互

五、自製sentinel-docker鏡像

Dockerfile

FROM openjdk:8-jre-alpine

MAINTAINER zhengqingya

# 解決時差8小時問題
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# 設置環境變量-運行時也可傳參進來耍哈
ENV MYSQL_SERVICE_HOST 127.0.0.1
ENV MYSQL_SERVICE_PORT 3306
ENV MYSQL_SERVICE_USER root
ENV MYSQL_SERVICE_PASSWORD root
ENV MYSQL_SERVICE_DB_NAME sentinel

# 添加jar包到容器中
ADD sentinel-dashboard.jar /app.jar

# 對外暴漏的埠號
EXPOSE 8858

# 運行🏃🏃🏃
CMD echo "****** start run ... " & \
java -Djava.security.egd=file:/dev/./urandom -Dmysql.host=${MYSQL_SERVICE_HOST} -Dmysql.port=${MYSQL_SERVICE_PORT} -Dmysql.username=${MYSQL_SERVICE_USER} -Dmysql.password=${MYSQL_SERVICE_PASSWORD} -Dmysql.db-name=${MYSQL_SERVICE_DB_NAME} -Dserver.port=8858 -Dcsp.sentinel.api.port=8719 -Dcsp.sentinel.dashboard.server=localhost:8858 -Dproject.name=sentinel-dashboard -jar /app.jar

sentinel-dashboard項目打包

mvn clean package -DskipTests

將sentinel-dashboard.jar放至Dockerfile同級路徑

製作鏡像

# 構建鏡像
docker build -t registry.cn-hangzhou.aliyuncs.com/zhengqing/sentinel-dashboard:1.8.2-mysql . --no-cache
# 推送鏡像
docker push registry.cn-hangzhou.aliyuncs.com/zhengqing/sentinel-dashboard:1.8.2-mysql

至此,鏡像製作完成 ^_^

六、docker-compose-sentinel-mysql.yml

version: '3'
services:
sentinel:
image: registry.cn-hangzhou.aliyuncs.com/zhengqing/sentinel-dashboard:1.8.2-mysql
container_name: sentinel # 容器名為'sentinel'
restart: unless-stopped # 指定容器退出後的重啟策略為始終重啟,但是不考慮在Docker守護進程啟動時就已經停止了的容器
environment: # 設置環境變量,相當於docker run命令中的-e
TZ: Asia/Shanghai
LANG: en_US.UTF-8
# TODO mysql配置信息
MYSQL_SERVICE_HOST: www.zhengqingya.com # 註:這裡不能為`127.0.0.1`或`localhost`方式!!!
MYSQL_SERVICE_DB_NAME: sentinel
MYSQL_SERVICE_PORT: 3306
MYSQL_SERVICE_USER: root
MYSQL_SERVICE_PASSWORD: root
ports: # 映射埠
- "8858:8858"

今日分享語句:如果放棄太早,你永遠都不知道自己會錯過什麼。

相關焦點

  • docker-compose 一鍵部署分布式配置中心Apollo
    、分布式日誌、分布式鏈路追蹤等在分布式部署中業務往往有很多配置比如: 應用程式在啟動和運行時需要讀取一些配置信息,配置基本上伴隨著應用程式的整個生命周期,比如:資料庫連接參數、啟動參數等,都需要去維護和配置,但不可能一臺臺伺服器登錄上去配置 今天我要跟大家分享一下分布式配置中心Apollo:Apollo(阿波羅)是攜程框架部門研發的分布式配置中心,能夠集中化管理應用不同環境
  • 使用Docker Compose部署SpringBoot應用
    使用Compose你可以用YAML文件來配置你的應用服務,然後使用一個命令,你就可以部署你配置的所有服務了。--version使用Docker Compose的步驟使用Dockerfile定義應用程式環境,一般需要修改初始鏡像行為時才需要使用;使用docker-compose.yml定義需要部署的應用程式服務,以便執行腳本一次性部署;使用docker-compose up命令將所有應用服務一次性部署起來。dock
  • Docker 入門(二):從實例來看 Dockerfile 和 Compose
    -e MYSQL_DATABASE= 可以指定運行容器時創建一個資料庫,-e MYSQL_ROOT_PASSWORD= 指定 MySQL 的密碼,MySQL 用戶名默認是 root。1$ docker run -d -p 8080:8080 myweb
  • Docker-compose 八步部署Django + Uwsgi + Nginx + MySQL + Redis升級篇
    Docker 是一個開源的應用容器引擎,讓開發者可以打包他們的應用以及依賴包到一個可移植的鏡像中,然後發布到任何流行的 Linux機器上。前/etc/redis/redis.conf # 容器啟動後啟動redis伺服器 networks: - redis_network volumes: - redis_vol:/data # 通過掛載給redis數據備份 - .
  • docker-compose安裝開發環境
    通過配置yml文件來compose 我們開發過程中所需要的服務。ps: 雖然生產上大部分用的是k8s,但是我們自己開發的時候,可以用docker-compose 來快速的起服務,用什麼起什麼,極其方便。
  • 運維(8) Harbor部署和docker推送/拉取鏡像
    一、前言本文將基於docker和docker-compose環境簡單部署Harbor,並通過docker推送/拉取鏡像操作Docker version 20.10.8, build 3967b7ddocker-compose version 1.29.2, build 5becea4c二、部署Harbor# 進入自己的安裝目錄
  • 一文精通雲服務安裝JDK11/Mysql/Nginx/Docker/Compose/Node/Git/Rocketmq容器編排
    2、安裝官方:https://docs.docker.com/compose/install/下載安裝包(比較耗時)sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/
  • Docker-compose命令大全及配置文件詳解
    使用 docker-compose 後不再需要逐一創建和啟動容器。您可以使用 YML 文件來配置應用程式需要的所有服務,然後使用一個命令,就可以從 YML 文件配置中創建並啟動所有服務。本章將介紹如何安裝Docker-compose,並對docker-compose.yml配置文件及常用命令進行詳細總結和演示。
  • Docker部署Django由淺入深系列(下): 八步部署Django+Uwsgi+Nginx+MySQL+Redis
    +Uwsgi鏡像的Dockerfile    ├── apps # 存放Django項目的各個apps    ├── manage.py    ├── myproject # Django項目配置文件    │   ├── asgi.py    │   ├── __init__.py    │   ├── settings.py
  • 教你三分鐘用docker compose搭建一個自己的個人博客網站
    準備工作開頭的準備工作還是那麼兩樣,安裝 docker 和配置鏡像加速器,如果還不會的同學可以看下我的《初識 docker》,這是預備知識。然後今天我們是用 docker compose 來實現的,所以還需要安裝下 docker compose,我們先打開官網看到上面有步驟。
  • 我選擇Docker Compose梭哈
    比如Mysql的比如:集群部署的時候,我們的應用程式需要部署到10個docker容器裡,那麼比如要想改動一個文件的內容,就要重新打包然後部署10次。我們可以將我們需要部署的應用程式掛載到宿主機上,這樣改一處就行了。
  • Sentinel規則基於Apollo(阿波羅)持久化
    上一篇我們介紹了Sentinel 無需代碼一行配置搞定限流簡單用法,但是我們發現一個問題,就是應用重啟後,規則就失效了,我們需要再創建
  • 一個網站的微服務架構實戰docker和 docker-compose
    鏡像,通過docker-compose做統一編排。主要的作用有:部署Angular項目頁面;掛載宿主機目錄作為文件伺服器;以及反向代理SpringBoot接口,解決跨域問題等等。最後三個docker容器的編排通過docker-compose來實現,三個容器之間的相互訪問都通過容器內部的別名,避免了宿主機遷移時ip無法對應的問題。為了方便開發,順便配了個自動部署。
  • Docker高級篇之DockerCompose-雲原生核心
    通過 Compose,您可以使用 YML 文件來配置應用程式需要的所有服務。然後,使用一個命令,就可以從 YML 文件配置中創建並啟動所有服務。在這裡插入圖片描述  如果要退出服務 Ctrl+c 或者 docker-compose down 4 Compose配置規則  docker-compse.yml核心  官網地址:https://docs.docker.com
  • Docker Stack使用及compose file配置
    在許多方面,Stack一直是期望的Compose——完全集成到Docker中,並能夠管理應用的整個生命周期。
  • 讓你的項目更輕鬆——docker部署django項目
    數據處理完成後,將響應結果返回給gunicorn,gunicorn拿到響應結果將其封裝(響應頭、響應行、響應體)發送給nginx,最後在由nginx返回到前端展示。因此,我們需要在linux伺服器上安裝配置gunicorn、nginx,這裡我們採用docker部署的方式。首先,我們的目標是要準備3個容器:
  • Docker Compose 1.18.0 之服務編排詳解
    在配置文件中,所有的容器通過services來定義,然後使用docker-compose腳本來啟動,停止和重啟應用,和應用中的服務以及所有依賴服務的容器 Compose 通過一個配置文件來管理多個Docker容器,非常適合組合使用多個容器進行開發的場景。服務編排工具使得Docker應用管理更為方便快捷。
  • docker-compose 快速啟動 wordpress 搭建博客
    - /var/lib/mysql ### 使用絕對路徑掛載數據卷 - /opt/data:/var/lib/mysql ### 以 Compose 配置文件為中心的相對路徑作為數據卷掛載到容器。 - .
  • 白話Docker——docker run及docker-compose
    -v:掛載目錄,這個一般是將宿主機的代碼目錄及一些配置文件,掛載到容器內部。另一種情況是在資料庫使用時,需要將容器內的數據目錄,掛載到宿主機上,讓數據在宿主機上持久保存,否則容器一旦重啟,數據就全部重置消失。        這裡並沒有演示全部的docker run參數,網上有非常多的教程,介紹都非常清楚。故不再額外介紹。
  • Docker集群管理之Docker Compose
    同時資料庫解決方案也在發生在變化,多種持久化混合方案(Polyglot Persistence)提倡將數據存放在最適合的資料庫解決方案中,而傳統的資料庫解決方案將數據存在在同一個資料庫服務中。服務數量的增加也就意味著容器數量的增多,逐漸增加的容器數量為容器部署,運行及管理帶來了挑戰。Docker Compose的出現解決多個容器部署的問題並提高了多個容器解決方案的可移植性。