NebulaGraph使用docker-compose部署方式如何备份还原

一、前言

之前的备份管理参考官网文档只实现了单机的备份,未能实现 Docker-Compose 部署方式的备份还原操作,实在睡不着啊,有道是垂死病中惊坐起,今天晚必须搞定它。。。。

二、备份 and 还原

2.1、Agent 部署问题以及解决

由于 Agent 部署需要在每个节点安装,但是 Docker-Compose 方式部署,只有一台机器,我们先尝试部署一个 Agent 测试是否可行。

# 下载 Agent
wget https://github.com/vesoft-inc/nebula-agent/releases/download/v3.6.1/agent-3.6.1-linux-amd64

# 重命名并放入系统 PATH,放入系统 PATH 后可以直接执行命令,不用./
sudo mv agent-3.6.1-linux-amd64 /usr/local/bin/agent

# 赋权 755,使用 br 命令可以正常使用
sudo chmod 755 /usr/local/bin/agent

# 查看 meta 服务启动后转发出来的端口,我这边是 49161、49159、49158 三个端口
docker-compose ps 

由于之前踩过坑了,详见上一篇文章,所以我们要知道 Agent 注册的 host 要和 meta 服务的 host 一致,否则无法进行备份会报错提示没有 Agent,那么我们先去看一下 meta 服务注册后的 host 是什么。

# 连接服务
sudo nebula-console -addr 127.0.0.1 -port 9669 -u root -p password
​
# 我们可以看到,有三个 meta 服务,host 分别是metad0 metad1 metad2

所以我们注册 Agent 的时候要使用主机 metad0 这个名称,有一些 Linux 基础的朋友就知道了,我们要去修改 /etc/hosts 这个文件了

# 修改 hosts 文件
sudo vim /etc/hosts

# 内容如下
127.0.0.1 localhost metad0 metad1 metad2

image-20231205203916533

# 启动 Agent
sudo nohup agent --agent="metad0:8888" --meta="metad0:49161" > nebula_agent.log 2>&1 &
​
# 查看 agent 的进程是否正常

# 连接服务,查看 Agent 是否正常注册
sudo nebula-console -addr 127.0.0.1 -port 9669 -u root -p password
show hosts agent;

image-20231205205002982

坑一:翻车了啊,兄弟们,Agent 没有成功注册

不要慌,有坑填坑就完事了,我们去查看一下agent的日志

通过日志我们可以发现以下几点线索

  1. 第一次连接端口 49161 成功了
  2. 尝试去连接 metad1 的 9559 端口失败
  3. 没有尝试连接 metad2 节点的 9559 端口

通过以往的各种被坑经验,我判断存报错存在以下两种可能性

  1. Agent 需要连接所有 meta 节点,连接 meta0 后读取到了其他 meta 节点的信息,尝试连接,失败了
  2. Agent 需要连接 meta 集群节点中的 leader,我链接的 metad0 不是 leader

由于报错只连接了 meta1 失败,没有尝试连接 metad2,所以第 2 种的可能性大一点,我们修改agent的启动参数,连接 metad1 去启动 Agent,端口号 49159,记得先杀掉之前的Agent:

# 启动 Agent
sudo nohup agent --agent="metad1:8888" --meta="metad1:49159" > nebula_agent.log 2>&1 &
​
# 连接服务,查看 Agent 是否正常注册
sudo nebula-console -addr 127.0.0.1 -port 9669 -u root -p password
show hosts agent;

ok,搞定了,Agent 服务正常注册了,注册名称也是我们所期望的 metad1

2.2、备份

安装 br 工具,尝试进行备份

# 下载 br
wget https://github.com/vesoft-inc/nebula-br/releases/download/v3.5.0/br-3.5.0-linux-amd64
​
# 重命名并放入系统 PATH,放入系统 PATH 后可以直接执行命令,不用./
sudo mv br-3.5.0-linux-amd64 /usr/local/bin/br
​
# 赋权 755,使用 br 命令可以正常使用
sudo chmod 755 /usr/local/bin/br
​
# 查看版本
br version

安装完毕

image-20231205091939766

# 备份
sudo br backup full --meta "metad1:49159" --storage "local:///opt/NebulaGraph"

坑二:兄弟们双翻车,报错 Error: parse cluster response failed: response is not successful, code is E_LIST_CLUSTER_NO_AGENT_FAILURE

多么熟悉的报错,应该是缺少两个 Agent 导致的,现在问题卡在哪呢,9559 是容器端口,转发出来以后就不是了,正因如此才能实现在一台服务器启动 3 个 Agent 而没有端口冲突的问题,我们如果要启动三个 Agent 会导致第 2、3 两个 Agent 无法正常连接 meta 集群的 leader(从坑一可以发现,所有 Agent 想要正常启动都要连接 leader 才行,但是我们要模拟注册 metad0 和 metad2,只能链接这两个节点才能正常给三个 meta 注册 agent 进行备份操作)

在死了无数脑细胞后,发现一个思路我们可以用四层代理,将服务器 9559 端口转发到 leader 节点的 49159

NginX 安装就不写了,不水内容,浪费大家时间,NginX 配置文件如下:

server {
listen 9559;
proxy_pass 127.0.0.1:49159;
}

配置文件主要含义就是有三个服务 metad0,metad1,metad2 都监听同一个端口 9559,分别转发后边的 meta 服务,由于服务名不一样,所以并不会存在端口冲突。

我们启动 agent0 和 agent2:

# 启动 agent0
# 注意修改 8888 端口为 8887
sudo nohup agent --agent="metad0:8887" --meta="metad0:49161" > nebula_agent0.log 2>&1 &
​
# 启动 agent2
# 注意修改 8888 端口为 8889
sudo nohup agent --agent="metad2:8889" --meta="metad2:49158" > nebula_agent2.log 2>&1 &
​
# 连接服务,查看 agent 是否正常注册
sudo nebula-console -addr 127.0.0.1 -port 9669 -u root -p password
show hosts agent;

再次尝试备份:

# 备份
sudo br backup full --meta "metad1:49159" --storage "local:///opt/NebulaGraph"

坑3:。。。叒报错了,还是熟悉的报错

这次痛定思痛,仔细翻看官方文档,最终确定 Agent 不是每个 meta 节点要部署,是所有节点,查看 storaged 和 graphd 节点的 host,启动对应节点的 agent:

#启动 agent
sudo nohup agent --agent="storaged0:8890" --meta="metad1:49159" > nebula_agent3.log 2>&1 &
sudo nohup agent --agent="storaged1:8891" --meta="metad1:49159" > nebula_agent4.log 2>&1 &
sudo nohup agent --agent="storaged2:8892" --meta="metad1:49159" > nebula_agent5.log 2>&1 &
sudo nohup agent --agent="graphd:8893" --meta="metad1:49159" > nebula_agent6.log 2>&1 &
sudo nohup agent --agent="graphd1:8894" --meta="metad1:49159" > nebula_agent7.log 2>&1 &
sudo nohup agent --agent="graphd2:8895" --meta="metad1:49159" > nebula_agent8.log 2>&1 &
​```

查看节点注册:

![image-20231205220417973|690x303](upload://vWslEr9o9BFyXMoGkQjybIlmxF2.png)


再次备份:

```shell
# 备份
sudo br backup full --meta "metad1:49159" --storage "local:///opt/NebulaGraph"

坑四:坏消息继续报错,好消息报错变了

继续分析报错,service metad1:49159 not found,这个报错应该是集群内其他服务连接 metad1:49159 失败,由于集群是容器启动,会将 metad1 解析到对应的容器 IP,而容器 IP 又没监听 49159 这个端口,所以失败,我们已经通过 NginX 转发了这个端口到 9559,所以我们使用 9559 端口进行备份:

# 备份
sudo br backup full --meta "metad1:9559" --storage "local:///opt/NebulaGraph"

坑五:报错继续中,报错有一次发生了变化

分析:报错中的路径应该是容器中存储数据的路径,容器外无非访问导致,但是容器化部署单机多节点又无法将所有文件通过挂载的方式挂到物理主机,因为重名文件。

没办法了,直接将容器中放入 Agent,使 Agent 在容器中运行,就可以读到文件了。删除现有集群以及 Agent 然后重新安装集群(此部分内容不写了,没意义)

需要注意的是新集群启动之前,要修改 docker-compose.yaml 将备份路径挂载到容器内,同时增加 hostname 配置(一处小坑,不单独再写了)

# 每个容器添加一下内容
volumes:
- /opt/NebulaGraph:/opt/NebulaGraph
​
# hostname 配置
services:
metad0:
hostname: metad0
​
# 注意,以上配置是所有服务都需要加,只列举一个

集群启动以后复制 Agent 到容器内:

# 复制 agent
sudo docker cp /usr/local/bin/agent nebula-docker-compose-release-36-graphd-1:/usr/local/bin/agent
sudo docker cp /usr/local/bin/agent nebula-docker-compose-release-36-graphd1-1:/usr/local/bin/agent
sudo docker cp /usr/local/bin/agent nebula-docker-compose-release-36-graphd2-1:/usr/local/bin/agent
sudo docker cp /usr/local/bin/agent nebula-docker-compose-release-36-storaged0-1:/usr/local/bin/agent
sudo docker cp /usr/local/bin/agent nebula-docker-compose-release-36-storaged1-1:/usr/local/bin/agent
sudo docker cp /usr/local/bin/agent nebula-docker-compose-release-36-storaged2-1:/usr/local/bin/agent
sudo docker cp /usr/local/bin/agent nebula-docker-compose-release-36-metad0-1:/usr/local/bin/agent
sudo docker cp /usr/local/bin/agent nebula-docker-compose-release-36-metad1-1:/usr/local/bin/agent
sudo docker cp /usr/local/bin/agent nebula-docker-compose-release-36-metad2-1:/usr/local/bin/agent
​
# 启动 agent
# 流程说明,进入容器,启动 agent,退出容器
# 重复此操作,保证每个容器都启动了 agent,注意修改参数
docker exec -it nebula-docker-compose-release-36-graphd-1 bash
nohup agent --agent="graphd:8888" --meta="metad1:9559" > nebula_agent.log 2>&1 &
exit
​
# 全部启动完成后,查看 agent 注册情况

需要注意,重新部署后 leader 节点发生变化,通过 Agent 日志确认 leader 节点,修改 NginX 配置指向 leader 节点

再再再再次备份

# 备份
# 直接使用 NginX 代理后的 9559 端口
sudo br backup full --meta "metad1:9559" --storage "local:///opt/NebulaGraph"

坑6:无语。。。不过看报错,很简单,宿主机 br 工具,无法连接 Agent 导致,一不做二不休,我们把 br 工具也放到容器内。。。然后再容器内进行备份:

# 复制 br 工具
sudo docker cp /usr/local/bin/br nebula-docker-compose-release-36-metad0-1:/usr/local/bin/br
​
# 进入容器内
docker exec -it nebula-docker-compose-release-36-metad0-1 bash
​
# 备份
br backup full --meta "metad1:9559" --storage "local:///opt/NebulaGraph"

终于成了,由于我们已经将 /opt/NebulaGraph 在容器中做了挂载,所以我们宿主机也是有这个备份的。

查看备份:

2.3、还原

这个就比较简单了,基于以上遇到过的坑,我们要进入容器内进行还原操作,同时我们备份目录 /opt/NebulaGraph 是挂载到所有容器内的,避免了复制备份文件的麻烦:

# 进入容器内
docker exec -it nebula-docker-compose-release-36-metad0-1 bash

# 恢复数据
br restore full --meta "127.0.0.1:9559" --storage "local:///opt/NebulaGraph" --name BACKUP_2023_12_05_14_59_41

正常还原,成功,睡觉,呃呃呃我先写个总结。。。。

三、总结

整体来说不顺利,意料之外的坑很多,最终解决的办法也不理想(太晚了,时间不够了,只能临时解决)。

所有遇到的坑,都在正文中写了,不在最后重复写了,一些特殊的地方单独和大家说一下。

重点 1:为什么用 NginX 代理,而不是直接修改 docker-compose.yaml 的配置,把端口映射出来?

因为无法确定那个 meta 会是主节点,NginX 可以在服务启动后确定那个是主节点后调整配置。

重点 2:解决问题的思路。

通过查看官方文档,分析备份恢复的逻辑;通过各种日志报错信息,分析报错原因;通过不断尝试,找出解决办法。

重点 3:为什么这么备份我觉得不理想,理想的解决办法应该是什么?

不理想的原因:1、我直接往容器中复制了 Agent 和 BR,容器删除后重建,这一切都没有了,不符合容器化部署的理念。

理想的方式:写 dockerfile,重做镜像来实现上面的效果。

想做,但是不做的事:K8s 部署的备份还原方式,想做因为没做过。不做的原因,已经分析出了备份的逻辑,只需要给每个 pod 注入一个 Agent 容器就可以实现,但是太累了,所以就不再写 K8s 的备份恢复了,有兴趣的小伙伴自行尝试,有问题可以联系我。

建议:官方给出了这种部署方式,就顺便提供一下备份的方式吧,自己研究太累了。

最后一句话:你不做你怎么知道你不行,Do it!

本文正在参加 NebulaGraph 技术社区年度征文活动,征文详情:https://discuss.nebula-graph.com.cn/t/topic/13970

如果你觉得本文对你有所启发,记得给我点个 :heart: ,谢谢你的鼓励

18 个赞

哇,非常非常赞哈!(这种 hacking 的感觉超级共鸣、喜欢!)

ps. 我之前利用 docker 自身 sidecar 的能力,试过 hack 把 agent 放在另一个容器,但是和每一个服务 sidecar,起来,你可以结合参考,这样,就不用手动 copy binary 了。

可惜那时候 br 还是完全假设主进程是二进制包,所以 restore 会失败,因为有一些 rpc 没法完成,但是备份是可以跑通的:

现在 br 支持容器了之后,我还没有来得及更新、让 br 能走通呢。

要不要试试用 compose/swarm 的方式把 agent 用类似 nebula-up 的方式容器启动哈(好像在引诱你的下一篇文章)?如果有需要 nebula-up 更新得欢迎来 PR!不过 docker 原生的 network_mode 抽象就是方便这种 sidecar 的模式的,好像 k8s 中 sidecar 最初也是类似的实现。

  metad0-agent:
    image: weygu/nebula-br:${BR_VERSION}
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./scripts:/usr/local/nebula/scripts
      - ./data/meta0:/data/meta
    command: --agent="metad0:8888" --meta="metad0:9559" --debug
    network_mode: 'container:nebula-docker-compose_metad0_1'