生产环境:为运行中Elasticsearch容器挂载卷且避免数据丢失
生产环境Elasticsearch容器挂载卷的低停机迁移方案
问题背景
通过docker-compose部署的Elasticsearch+Kibana,ES容器已运行许久,存储约600GB数据,但未挂载数据卷。重启容器或修改配置会导致数据丢失,需在仅允许极短停机时间的生产环境下,完成数据到卷的迁移,且避免数据丢失。
之前尝试的两种方法均不满足要求:
- docker commit:创建镜像耗时极长(600GB需400-600分钟),操作期间新写入的数据无法同步
- docker cp:复制过程耗时久,且复制期间产生的增量数据会丢失,停机窗口过长
核心痛点:操作全程的增量数据无法留存,整体耗时不符合生产环境要求。
最优方案:ES集群滚动迁移+容器卷挂载
利用Elasticsearch原生的集群分片同步特性,实现几乎无停机的数据迁移,同时保证数据完整性。
前置条件
- 有额外服务器资源可临时启动同版本ES容器
- 新旧ES节点版本、集群配置(集群名、网络)完全一致
- 已做好全量数据备份(如使用
elasticsearch-snapshot)
具体操作步骤
1. 启动挂载数据卷的新ES节点
修改现有docker-compose.yml,新增一个配置好数据卷的ES服务:
services: # 原ES节点(保留,后续停用) es-old: image: elasticsearch:<你的ES版本> environment: - cluster.name=your-cluster-name - node.name=es-old - bootstrap.memory_lock=true - "ES_JAVA_OPTS=-Xms4g -Xmx4g" networks: - es-network ulimits: memlock: soft: -1 hard: -1 # 新增挂载数据卷的ES节点 es-new: image: elasticsearch:<你的ES版本> volumes: - es-data:/usr/share/elasticsearch/data # 挂载持久化卷 environment: - cluster.name=your-cluster-name - discovery.seed_hosts=es-old # 指向原节点服务名/IP - node.name=es-new - bootstrap.memory_lock=true - "ES_JAVA_OPTS=-Xms4g -Xmx4g" networks: - es-network ulimits: memlock: soft: -1 hard: -1 volumes: es-data: driver: local networks: es-network: external: false
启动新节点:
docker-compose up -d es-new
2. 等待集群数据同步完成
通过Kibana Dev Tools执行命令,查看分片同步状态:
GET _cat/shards?v
当所有分片的STATE显示为STARTED,且新节点拥有对应分片副本时,同步完成。
3. 锁定原节点写入,处理最后增量
为确保同步完成后无新数据写入原节点,将原ES设置为只读:
PUT /_all/_settings { "index.blocks.write": true }
等待1-2分钟,确认所有正在处理的写入请求完成,此时新节点已同步所有数据(含最后增量)。
4. 切换流量到新节点(极短停机)
停止原ES节点:
docker-compose stop es-old
修改docker-compose.yml,将新节点的服务名改为原ES的服务名(如es),确保Kibana等依赖服务指向正确,然后重启相关服务:
# 修改后启动新节点(替换原服务名) docker-compose up -d es # 重启Kibana以更新ES地址 docker-compose restart kibana
5. 恢复ES可写状态
执行命令解除只读限制:
PUT /_all/_settings { "index.blocks.write": null }
6. 清理临时资源(可选)
确认新节点运行正常、数据完整后,删除原ES容器及临时配置。
方案优势
- 停机窗口极小:仅切换流量的1-2分钟内不可写,远低于传统方法的数小时
- 数据零丢失:通过ES集群同步保证全量+增量数据完整
- 操作可控:依赖ES原生特性,无需Docker层面的慢复制操作
备选方案(无额外资源时)
如果无法新增节点,可采用直接迁移容器数据目录到卷的方式,停机窗口等于数据复制时间:
- 查找原ES容器的主机数据目录:
docker inspect <原ES容器ID> | grep -A 5 "Source" | grep "/var/lib/docker/volumes/" | awk '{print $2}' | sed 's/\"//g'
- 停止ES容器(开始停机):
docker-compose stop es
- 创建新卷并复制数据:
docker volume create es-data docker run --rm -v <步骤1得到的目录>:/old-data -v es-data:/new-data busybox cp -a /old-data/. /new-data/
- 修改docker-compose.yml挂载新卷,启动ES:
docker-compose up -d es
内容的提问来源于stack exchange,提问作者KKI
相关产品推荐
相关产品推荐

