Docker 进阶指南:常用命令、最佳实践与资源管理
Docker 进阶指南:常用命令、最佳实践与资源管理
Docker 作为一种轻量级的容器化技术,已经成为现代软件开发和部署不可或缺的工具。本文将为您深入介绍 Docker 的常用命令、最佳实践以及如何有效管理容器资源,帮助您更好地在 Ubuntu 22.04 或其他类似环境中使用 Docker。
一、Docker 常用命令操作示例
1. 安装与配置
首先,让我们从 Docker 的安装和基本配置开始:
# 更新包索引
sudo apt update# 安装 Docker
sudo apt install docker.io# 启动 Docker 服务
sudo systemctl start docker# 设置 Docker 开机自启
sudo systemctl enable docker# 将当前用户添加到 docker 组(免 sudo 运行 docker 命令)
sudo usermod -aG docker $USER# 应用组变更(需要重新登录才能生效)
newgrp docker
2. 镜像管理
Docker 镜像是容器的基础,以下是一些常用的镜像管理命令:
# 搜索镜像
docker search ubuntu# 拉取镜像
docker pull ubuntu:22.04# 列出本地镜像
docker images# 删除镜像
docker rmi ubuntu:22.04# 构建自定义镜像
docker build -t myapp:v1 .# 推送镜像到 Docker Hub
docker push username/myapp:v1# 保存镜像到文件
docker save -o myimage.tar myimage:latest# 从文件加载镜像
docker load -i myimage.tar
3. 容器操作
容器是 Docker 的核心概念,以下是一些常用的容器操作命令:
# 创建并运行容器
docker run -it --name mycontainer ubuntu:22.04 /bin/bash# 列出运行中的容器
docker ps# 列出所有容器(包括已停止的)
docker ps -a # 启动/停止/重启容器
docker start mycontainer
docker stop mycontainer
docker restart mycontainer# 进入运行中的容器
docker exec -it mycontainer /bin/bash# 删除容器
docker rm mycontainer# 查看容器日志
docker logs mycontainer# 查看容器资源使用情况
docker stats mycontainer# 将容器保存为新镜像
docker commit mycontainer mynewimage:v1
4. 网络管理
Docker 网络允许容器之间以及容器与外部世界进行通信:
# 创建自定义网络
docker network create mynetwork# 列出所有网络
docker network ls# 将容器连接到网络
docker network connect mynetwork mycontainer# 断开容器与网络的连接
docker network disconnect mynetwork mycontainer# 检查网络
docker network inspect mynetwork
5. 数据卷管理
数据卷用于持久化数据和在容器间共享数据:
# 创建数据卷
docker volume create myvolume# 列出所有数据卷
docker volume ls# 检查数据卷
docker volume inspect myvolume# 删除数据卷
docker volume rm myvolume# 使用数据卷运行容器
docker run -v myvolume:/data myimage
二、Docker 最佳实践
遵循以下最佳实践可以帮助您更有效地使用 Docker:
1. 镜像构建最佳实践
- 使用官方基础镜像:优先选择官方维护的基础镜像,如 Alpine 或 Ubuntu。
- 指定具体的镜像版本:避免使用
latest
标签,而是使用特定的版本标签。 - 使用多阶段构建:减小最终镜像大小,提高构建效率。
- 合理使用 .dockerignore 文件:排除不必要的文件,加快构建过程。
- 最小化镜像层数:合并 RUN 命令,减少镜像层数。
示例 Dockerfile:
# 使用多阶段构建
FROM node:14 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run buildFROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
2. 容器运行最佳实践
- 一个容器一个进程:每个容器应该只运行一个主要进程。
- 使用非 root 用户:出于安全考虑,应该使用非 root 用户运行容器进程。
- 设置资源限制:为容器设置适当的 CPU 和内存限制。
- 使用健康检查:通过 HEALTHCHECK 指令确保容器中的应用正常运行。
- 正确处理信号:确保容器中的应用能够正确处理 SIGTERM 信号。
3. 安全最佳实践
- 定期更新基础镜像:及时更新基础镜像以修复已知漏洞。
- 扫描镜像漏洞:使用工具如 Trivy 或 Clair 定期扫描镜像漏洞。
- 不在镜像中存储敏感信息:使用环境变量或 Docker secrets 管理敏感信息。
- 限制容器的系统调用:使用 seccomp 或 AppArmor 限制容器的系统调用。
- 使用只读文件系统:尽可能使用只读文件系统运行容器。
4. 网络和存储最佳实践
- 使用用户定义的桥接网络:为容器间通信创建自定义网络。
- 使用命名卷:使用命名卷而不是绑定挂载来持久化数据。
- 合理使用端口映射:只暴露必要的端口,使用内部网络进行容器间通信。
5. 日志和监控最佳实践
- 集中化日志管理:使用日志驱动将容器日志发送到集中日志系统。
- 实施监控:使用 Prometheus 等工具监控容器的资源使用情况。
- 使用标签:合理使用标签来组织和管理容器。
三、Docker 容器资源限制
合理限制容器资源使用对于维护系统稳定性和优化性能至关重要。
1. 内存限制
-
设置内存硬限制:
docker run -m 512m myimage
-
设置内存软限制:
docker run -m 1g --memory-reservation=512m myimage
-
限制 Swap 使用:
docker run -m 512m --memory-swap 1g myimage
2. CPU 限制
-
设置 CPU 份额:
docker run --cpu-shares 512 myimage
-
限制 CPU 核心数:
docker run --cpus 2 myimage
-
指定 CPU 核心:
docker run --cpuset-cpus 0,1 myimage
3. I/O 限制
- 限制读写速度:
docker run --device-read-bps /dev/sda:1mb --device-write-bps /dev/sda:1mb myimage
4. 使用 Docker Compose 管理资源限制
在 docker-compose.yml
文件中可以更系统地管理资源限制:
version: '3'
services:web:image: nginxdeploy:resources:limits:cpus: '0.5'memory: 512Mreservations:cpus: '0.25'memory: 256M
5. 监控和调整资源使用
- 使用
docker stats
命令实时监控容器资源使用情况。 - 利用监控工具如 Prometheus 和 Grafana 进行更详细的资源监控。
- 根据监控结果定期调整资源限制,确保资源被有效利用。
6. 资源限制最佳实践
- 了解应用需求:在设置限制前,充分了解应用的资源需求。
- 留有余地:设置限制时留有一定余地,避免因资源不足导致应用崩溃。
- 考虑峰值:资源限制应考虑应用可能的峰值使用情况。
- 定期审核:随着应用的发展,定期审核和调整资源限制。
- 使用编排工具:对于复杂的多容器应用,考虑使用 Kubernetes 等容器编排平台进行更精细的资源管理。
通过合理设置这些资源限制,您可以有效防止单个容器过度消耗系统资源,提高整体系统的稳定性和性能。结合前面介绍的常用命令和最佳实践,您将能够更加高效和安全地使用 Docker 进行开发和部署。
相关文章:
Docker 进阶指南:常用命令、最佳实践与资源管理
Docker 进阶指南:常用命令、最佳实践与资源管理 Docker 作为一种轻量级的容器化技术,已经成为现代软件开发和部署不可或缺的工具。本文将为您深入介绍 Docker 的常用命令、最佳实践以及如何有效管理容器资源,帮助您更好地在 Ubuntu 22.04 或…...
C++编写静态库
1、新建项目创建静态库staticLib1. demoStaticLib.h #pragma once class ArrayTool { public:int Max(const int* lpHead, const int nLength);int Sum(const int* lpHead, const int nLength); }; demoStaticLib.cpp #include "pch.h" #include "demoStati…...
oracle数据库日常操作
1、执行SQL语句后不显示PL/SQL procedure successfully completed set feedback off; 2、显示实例名称 echo "set sqlprompt \"_user_connect_identifier> \"" >> $ORACLE_HOME/sqlplus/admin/glogin.sql 3、客户端尝试连接到服务器时发生超时 …...
行驶证 OCR 识别API接口的影响因素
一、影响因素 (一)证件质量与图像质量 行驶证的质量对OCR 识别 API 界面的效果有重要影响。清晰的文件可以使识别系统准确地捕获文本信息,而模糊的文本可能会导致识别错误。而且不同地区、不同年份的行驶证在字体、排版、格式等方面可能存在差异,甚至可…...
什么是TCP/IP和UDP
TCP/IP和UDP都是网络协议,用于不同计算机或设备之间的通信。它们的作用是定义数据如何在网络上传输,但它们在传输方式、可靠性和效率上有显著的区别。 1. TCP/IP TCP/IP(传输控制协议/互联网协议,Transmission Control Protocol…...
1074 Reversing Linked List (25)
Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K3, then you must output 3→2→1→6→5→4; if K4, you must output 4→3→2→1→5→6. Input Specif…...
layui table 纵向滚动条导致单元格表头表体错位问题
我用的时layui2.6.8版本 历史项目维护,bug给我让我做了,本来利用前端手段强解决,后来发现很多table 找了解决办法 打开layui-v2.6.8/lay/modules/table.js 如果打开后时压缩的代码 直接搜索 e.find(".layui-table-patch") …...
算法基础 - 求解非线性方程(牛顿法)
文章目录 1. 前言2. 牛顿迭代算法2.1. 基本思想2.2. 如何求解 x12.3. 如何求解 x22.4. 收敛性2.5. 编码实现2.5.1. 递归实现2.5.2. 非递归实现 1. 前言 前文介绍了如何使用“高斯消元法”求解线性方程组。本文秉承有始有终的态度,继续介绍“非线性方程”的求解算法。…...
[C#]C#实现数字到人民币大写金额的转换
在软件开发中,将数字转换成人民币大写形式的需求通常出现在需要生成财务报表、发票、收据、账单等正式文档的场景中。这些文档往往需要遵循一定的格式和规范,以确保信息的准确性和可读性,特别是在处理与金钱相关的数据时。 比如: …...
Base64.cv:高效安全的在线Base64转换工具详解
在日常开发中,Base64编解码是一个非常常见的需求。本文将介绍一款优秀的在线Base64转换工具:Base64.cv。 工具特点 1. 性能优势 采用浏览器原生API,转换速度快本地运算,无服务器延迟支持大容量文本处理 2. 安全性 纯客户端处…...
前端面试热门题(二)[html\css\js\node\vue)
Vue 性能优化的方法 Vue 性能优化的方法多种多样,以下是一些常用的策略: 使用v-show替换v-if:v-show是通过CSS控制元素的显示与隐藏,而v-if是通过操作DOM来控制元素的显示与隐藏,频繁操作DOM会导致性能下降。因此&am…...
施耐德电气:多维解构AI挑战,引领产业创新变革
CSDN 看到,大模型正在掀起一场智能化革命,带来计算、开发、交互三大范式全面升级和转换,其中 AI 计算范式正在从图灵、冯诺伊曼计算范式转为神经网络计算范式。AI 技术仍在快速发展,AI 算力基础设施的数据中心如果仍走“堆资源、堆…...
Unity的GPU Instancing技术
首先新建一个场景,添加一个相机,并创建一个Render Texture给相机。 然后在相机上挂载以下脚本TestBatches ,同时脚本的Inspector面板的Mesh中选择Cube,另外创建一个新的材质拖动给mat: public class TestBatches : M…...
JVM指令集概览:基础与应用
写在文章开头 在现代软件开发中,Java 语言凭借其“一次编写,到处运行”的理念成为了企业级应用的首选之一。这一理念的背后支撑技术正是 Java 虚拟机(JVM)。JVM 是一个抽象的计算机,它实现了 Java 编程语言的各种特性,并且能够执行编译后的字节码文件。了解 JVM 的工作原…...
使用 Redis Stream 结合 Redission DelayedQueue 实现延迟消息队列(已上线生产)
一、Redis Stream 介绍 Redis Stream 是 Redis 5.0 版本新增加的数据结构,作为一种轻量级的消息队列,Redis Stream 作为一种轻量级的消息队列,适合资源有限或对性能要求较高的场景。 Redis Stream 主要用于消息队列(MQÿ…...
时频转换 | Matlab基于递归图Reccurence Plots一维数据转二维图像方法
目录 基本介绍程序设计参考资料获取方式 基本介绍 时频转换 | Matlab基于递归图Reccurence Plots一维数据转二维图像方法 程序设计 clear clc close allfs 6400 ; % 数据采样频率 N 5120; % 信号的点数% 生成时间向量 t (0:N-1) / fs; % 生成正弦信号 x sin(2 * pi * 15…...
《手写Spring渐进式源码实践》实践笔记 (第二十一章 将ORM框架整合到Spring容器中)
文章目录 第二十一章 ORM框架整合Spring背景目标设计实现代码结构类图实现步骤 测试事先准备属性配置文件测试用例测试结果: 总结 第二十一章 ORM框架整合Spring 背景 MyBatis-Spring 能够实现 MyBatis 与 Spring 框架的无缝集成。它使得 MyBatis 能够参与 Spring…...
数据库管理-第267期 23ai:Oracle Data Redaction演示(20241128)
数据库管理267期 2024-11-286 数据库管理-第267期 23ai:Oracle Data Redaction演示(20241128)1 示例表及数据2 创建编校策略2.1 名字全编校2.2 电话部分编校 3 DML演示3.1 场景13.2 场景2 总结 数据库管理-第267期 23ai:Oracle Da…...
NGO-CNN-BiGRU-Attention北方苍鹰算法优化卷积双向门控循环单元时间序列预测,含优化前后对比
NGO-CNN-BiGRU-Attention北方苍鹰算法优化卷积双向门控循环单元时间序列预测,含优化前后对比 目录 NGO-CNN-BiGRU-Attention北方苍鹰算法优化卷积双向门控循环单元时间序列预测,含优化前后对比预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介…...
第六届国际科技创新学术交流会暨管理科学信息化与经济创新发展(MSIEID 2024)
重要信息 大会官网:msieid2024.iaecst.org (点击了解大会,参会等内容) 大会时间:2024年12月6-8日 大会地点:中国-广州 大会简介 随着全球化和信息化的不断深入,管理科学、信息化和经济发展…...
【计算机视觉算法与应用】模板匹配、图像配准
目录 1. 基于灰度值的模板匹配 2. 基于相关性的模板匹配 3. 基于形状的模板匹配 4. 基于组件的模板识别 5. 基于形变的模板匹配 6. 基于描述符的模板匹配 7. 基于点的模板匹配 性能比较 模板匹配的算法实现需要结合具体需求和应用场景来选择方法。以下是基于 OpenCV 的…...
HHO-CNN-BiGRU-Attention哈里斯鹰优化算法卷积神经网络结合双向门控循环单元时间序列预测,含优化前后对比
HHO-CNN-BiGRU-Attention哈里斯鹰优化算法卷积神经网络结合双向门控循环单元时间序列预测,含优化前后对比 目录 HHO-CNN-BiGRU-Attention哈里斯鹰优化算法卷积神经网络结合双向门控循环单元时间序列预测,含优化前后对比预测效果基本介绍模型描述程序设计…...
数据并行、模型并行与张量并行:深度学习中的并行计算策略(中英双语)
中文版 数据并行、模型并行与张量并行:深度学习中的并行计算策略 随着深度学习模型的不断增大,单个计算节点(例如单个 GPU)的计算和内存能力逐渐成为了限制训练效率和模型规模的瓶颈。为了应对这些挑战,深度学习社区…...
大数据-239 离线数仓 - 广告业务 测试 FlumeAgent 加载ODS、DWD层
点一下关注吧!!!非常感谢!!持续更新!!! Java篇开始了! 目前开始更新 MyBatis,一起深入浅出! 目前已经更新到了: Hadoop࿰…...
Python中的数据结构深入解析:从列表到字典的优化技巧
《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! Python是一门以易用性和可读性著称的高级编程语言,其内置的数据结构为开发者提供了强大的工具,但了解其底层实现及性能优化策略却常被忽略。本文深入探讨Python中的核心数据结构,包括列表(list)、元组…...
【JS】JS判断数据类型
typeof // typeof 后面括号有没有都可以 console.log(typeof(a)) // string console.log(typeof(123)) // number console.log(typeof(undefined)) // undefined console.log(typeof(true)) // boolean console.log(typeof(Symbol(123))) // symbolconsole.log(typeof(null)) /…...
基于jmeter+perfmon的稳定性测试记录
软件测试资料领取:[内部资源] 想拿年薪40W的软件测试人员,这份资料必须领取~ 软件测试面试刷题工具领取:软件测试面试刷题【800道面试题答案免费刷】 1. 引子 最近承接了项目中一些性能测试的任务,因此决定记录一下,…...
【0351】Postgres内核 Open WAL segment(包含 WAL 位置 ‘RecPtr’)(2 - 4)
上一篇: 文章目录 1. 打开 WAL Segment2. Standby mode 由一个 状态机(state machine)实现2.1 何处获取 WAL 文件?2.1.1 XLogSource2.1.2 从所选源(XLogSource )读取 XLOG2.1.2.1 walreceiver 运行状态 ?2.1.3 readFile(XLOG 文件句柄)1. 打开 WAL Segment 在经过前…...
Mysql基础
什么是关系型数据库? 顾名思义,关系型数据库(RDB,Relational Database)就是一种建立在关系模型的基础上的数据库。关系模型表明了数据库中所存储的数据之间的联系(一对一、一对多、多对多)。 …...
Altium Designer学习笔记 24 PCB初始布局2
基于Altium Designer 23学习版,四层板智能小车PCB 更多AD学习笔记:Altium Designer学习笔记 1-5 工程创建_元件库创建Altium Designer学习笔记 6-10 异性元件库创建_原理图绘制Altium Designer学习笔记 11-15 原理图的封装 编译 检查 _PCB封装库的创建Al…...
【从0学英语】形容词性/名词性物主代词是什么?
在英语中,物主代词是非常重要的语法概念之一,特别是对于初学者来说。理解形容词性物主代词和名词性物主代词的不同,能够帮助我们在日常对话中准确地表达拥有关系。在这篇文章中,我们将深入探讨这两个概念,并通过详细的…...
hhdb数据库介绍(10-29)
管理 数据备份 从存储节点或灾备机房数据备份 选择灾备机房类型、从库(双主备库)存储节点类型进行备份,页面根据选择类型,对应给出提示信息。发起备份时,检测从存储节点状态是否符合备份条件。 主从数据一致性检测…...
springboot(20)(删除文章分类。获取、更新、删除文章详细)(Validation分组校验)
目录 一、删除文章分类功能。 (1)接口文档。 1、请求路径、请求参数。 2、请求参数。 3、响应数据。 (2)实现思路与代码书写。 1、controller层。 2、service接口业务层。 3、serviceImpl实现类。 4、mapper层。 5、后端接口测试。…...
实战指南:理解 ThreadLocal 原理并用于Java 多线程上下文管理
目录 一、ThreadLocal基本知识回顾分析 (一)ThreadLocal原理 (二)既然ThreadLocalMap的key是弱引用,GC之后key是否为null? (三)ThreadLocal中的内存泄漏问题及JDK处理方法 &…...
Spark 内存管理机制
Spark 内存管理 堆内内存和堆外内存 作为一个 JVM 进程,Executor 的内存管理建立在 JVM(最小为六十四分之一,最大为四分之一)的内存管理之上,此外spark还引入了堆外内存(不在JVM中的内存),在spark中是指不…...
【Maven】继承和聚合
5. Maven的继承和聚合 5.1 什么是继承 Maven 的依赖传递机制可以一定程度上简化 POM 的配置,但这仅限于存在依赖关系的项目或模块中。当一个项目的多个模块都依赖于相同 jar 包的相同版本,且这些模块之间不存在依赖关系,这就导致同一个依赖…...
NViST运行笔记
文章标题: NViST: In the Wild New View Synthesis from a Single Image with Transformers 1. 环境配置 创建环境 conda create -n nvist python3.9 进入环境 conda activate nvist 安装torch torchvision torchaudio pip install torch2.1.2 torchvision0…...
性能测试工具Grafana、InfluxDB和Collectd的搭建
一、性能监控组成简介 1、监控能力分工:这个系统组合能够覆盖从数据采集、存储到可视化的整个监控流程。Collectd可以收集各种系统和应用的性能指标,InfluxDB提供高效的时序数据存储,而 Grafana 则将这些数据以直观的方式呈现出来。2,实时性能监控:对于需要实时了解系统状…...
JS中的类与对象
面向对象是使用最广泛的一种编程范式,最具代表性的面向对象语言就是Java和C,在它们的理念中,面向对象的三大特性:封装,继承,多态。类,对象,公有/私有方法/属性,各种继承就…...
域名解析系统 DNS
1.域名系统概述 用户与互联网上某台主机通信时,必须要知道对方的IP地址。然而用户很难记住长达32 位的二进制主机地址。即使是点分十进制地址也并不太容易记忆。但在应用层为了便于用户记忆各种网络应用,连接在互联网上的主机不仅有P地址,而…...
Flutter 1.1:下载Flutter环境
1、在AS中下载Flutter插件 在setting的Plugins中下载Flutter,如图所示,可以直接进行搜索查找 2、下载flutter的sdk源代码 flutter中文文档学习 通过Git下载SDK源代码 git clone -b stable https://github.com/flutter/flutter.git3、配置系统变量 3…...
HTML5系列(6)-- 拖放 API 实战指南
前端技术探索系列:HTML5 拖放 API 实战指南 🎯 致读者:探索现代交互技术 👋 前端开发者们, 今天我们将深入探讨 HTML5 中一个强大而实用的特性 —— 拖放 API。这项技术能够让我们创建更加直观和交互性强的用户界面…...
windows下kafka初体验简易demo
这里提供了windows下的java1.8和kafka3.9.0版本汇总,可直接免费下载 【免费】java1.8kafka2.13版本汇总资源-CSDN文库 解压后可以得到一个文件夹 资料汇总内有一个kafka文件资料包.tgz,解压后可得到下述文件夹kafka_2.13-3.9.0,资料汇总内还…...
算法训练(leetcode)二刷第三十三天 | *322. 零钱兑换、*279. 完全平方数、*139. 单词拆分
刷题记录 *322. 零钱兑换*279. 完全平方数*139. 单词拆分 *322. 零钱兑换 leetcode题目地址 dp[j]存储amount为j时所需要的最少硬币数。当j为0时需要0个硬币,因此dp[0]赋值为0. 因为是取最少硬币数,因此初始化需要赋值一个最大值。 状态转移方程&…...
windows的pip镜像源配置
Windows 中 pip 镜像源配置 在 Windows 系统中,为了提高 pip 包的安装速度,我们可以配置 pip 的镜像源。以下是具体的配置步骤: 创建文件夹 在 C:\Users\Administrator\pip 路径下创建一个名为 pip.ini 的文件。 编辑 pip.ini 文件 使用文本…...
Django Rest Framework中嵌套关系的JSON序列化
在 Django Rest Framework (DRF) 中,处理嵌套关系的 JSON 序列化是一个常见需求。以下是如何实现嵌套关系序列化的详细说明,包括序列化器定义、模型关系以及常见用法。 1、问题背景 假设我们有以下两个模型: class Jobdtl(models.Model):jo…...
ONVIF协议网络摄像机客户端使用gsoap获取RTSP流地址GStreamer拉流播放
什么是ONVIF协议 ONVIF(开放式网络视频接口论坛)是一个全球性的开放式行业论坛,旨在促进开发和使用基于物理IP的安全产品接口的全球开放标准。 ONVIF规范的目标是建立一个网络视频框架协议,使不同厂商生产的网络视频产品完全互通。…...
40分钟学 Go 语言高并发:Go程序性能优化方法论
Go程序性能优化方法论 一、性能指标概述 指标类型关键指标重要程度优化目标CPU相关CPU使用率、线程数、上下文切换⭐⭐⭐⭐⭐降低CPU使用率,减少上下文切换内存相关内存使用量、GC频率、对象分配⭐⭐⭐⭐⭐减少内存分配,优化GC延迟指标响应时间、处理延…...
MySQL基础(语句)知识复习 (除索引和视图)
1.客户端和数据库操作 1.登录客户端界面:mysql -uroot -p 2.查看当前的数据库版本:select version(); 3.显示所有数据库:show databases;, 4.创建数据库:create [IF NOT EXISTS] database 库名 character set 字符…...
【sqlcipher】pc端sqflite使用过程中遇到的问题
在flutter中使用sqlcipher时 Mac上如果通过flutter带的文件管理api(即File的delete()方法)删除数据库文件,再创建同名的数据文件的话,必现readonly问题, 这里需要注意的一点是 DatabaseFactory 在Mac上直接使用全局的…...