docker

docker官方文档

Docker 快速入门

Docker 安装包下载

docker是什么

Docker 是一个应用打包、分发、部署的工具

你也可以把它理解为一个轻量的虚拟机,它只虚拟你软件需要的运行环境,多余的一点都不要

而普通虚拟机则是一个完整而庞大的系统,包含各种不管你要不要的软件

跟普通虚拟机的对比

特性 普通虚拟机 Docker
跨平台 通常只能在桌面级系统运行,例如 Windows/Mac,无法在不带图形界面的服务器上运行 支持的系统非常多,各类 windows 和 Linux 都支持
性能 性能损耗大,内存占用高,因为是把整个完整系统都虚拟出来了 性能好,只虚拟软件所需运行环境,最大化减少没用的配置
自动化 需要手动安装所有东西 一个命令就可以自动部署好所需环境
稳定性 稳定性不高,不同系统差异大 稳定性好,不同系统都一样部署方式

打包、分发、部署

打包:就是把你软件运行所需的依赖、第三方库、软件打包到一起,变成一个安装包

分发:你可以把你打包好的“安装包”上传到一个镜像仓库,其他人可以非常方便的获取和安装

部署:拿着“安装包”就可以一个命令运行起来你的应用,自动模拟出一摸一样的运行环境,不管是在 Windows/Mac/Linux

docker安装

容器是由镜像实例化而来,简单来说,镜像是文件,容器是进程

容器是基于镜像创建的,即容器中的进程依赖于镜像中的文件

docker 的镜像概念类似虚拟机的镜像。是一个只读的模板,一个独立的文件系统,包括运行容器所需的数据,可以用来创建新的容器

镜像运行起来就是容器,容器服务运行的过程中,基于原始镜像做了改变,比如安装了程序,添加了文件,也可以提交回去 (commit)成为镜像

docker安装分为安装包和命令行两种

下载docker安装包,按照指示安装即可

windows需要打开启用或关闭Windows功能下的Hyper-V容器适用于Linux的Windows子系统选项

安装完要打开Docker Desktop软件,打开会启动引擎,这样才能使用docker

重要:打开Docker Desktop软件,打开Settings下的Resources,选择Advanced下的Disk image location,选择合适的文件夹存放docker的镜像和容器,注意后期容器多的话,这个文件夹很占空间的

1
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun

配置镜像加速

进入阿里云,登陆后点击左侧的镜像加速,生成自己的镜像加速地址

执行阿里云推荐的终端命令,即可更新docker的镜像源为阿里云镜像

1
2
3
4
5
6
7
8
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://xk5lrhin.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

代理配置

  1. 为docker服务创建一个内嵌的systemd目录

    1
    mkdir -p /etc/systemd/system/docker.service.d
  2. 创建/etc/systemd/system/docker.service.d/http-proxy.conf文件,并添加HTTP_PROXY环境变量,其中[proxy-addr]和[proxy-port]分别改成实际情况的代理地址和端口

    1
    2
    [Service]
    Environment="HTTP_PROXY=http://192.168.4.xx:xx" "HTTPS_PROXY=http://192.168.4.xx:xx"
  3. 如果还有内部的不需要使用代理来访问的Docker registries,那么还需要制定NO_PROXY环境变量

    1
    2
    [Service]
    Environment="HTTP_PROXY=http://192.168.4.xx:xx" "HTTPS_PROXY=http://192.168.4.xx:xx" "NO_PROXY=localhost,127.0.0.1,docker-registry.somecorporation.com"
  4. 更新配置并重启Docker服务

    1
    2
    systemctl daemon-reload
    systemctl restart docker

下载docker安装包,按照如下指令安装即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 下载 Docker 二进制文件的压缩包
wget https://download.docker.com/linux/static/stable/x86_64/docker-24.0.5.tgz

# 解压下载的 tar.gz 文件
tar -xzf docker-24.0.5.tgz

# 将解压后的二进制文件复制到 /usr/bin 目录
sudo cp ./docker/* /usr/bin/

# 假设你有一个 docker.service 文件,复制它到 systemd 的服务目录
sudo cp ./docker.service /etc/systemd/system/docker.service

# 确保 docker.service 文件具有可执行权限
sudo chmod +x /etc/systemd/system/docker.service

# 重新加载 systemd 管理器配置
sudo systemctl daemon-reload

# 启动 Docker 服务
sudo systemctl start docker

# 设置 Docker 服务开机自动启动
sudo systemctl enable docker.service

一键安装脚本(未测试,参考别人的)

创建 Docker 和 Docker-Compose 一键安装脚本 install.sh:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/bin/sh
echo 'docker开始安装...'
echo '解压tar包...'
tar -xvf ./docker-20.10.9.tgz
echo '将docker目录移到/usr/bin目录下...'
cp -f ./docker/* /usr/bin
rm -rf docker
echo '将docker.service 移到/etc/systemd/system/ 目录...'
cp -f ./docker.service /etc/systemd/system
echo '添加文件权限...'
chmod +x /etc/systemd/system/docker.service
echo '重新加载配置文件...'
systemctl daemon-reload
echo '启动docker...'
systemctl start docker
echo '设置开机自启...'
systemctl enable docker.service
if ! docker -v; then
echo "docker 安装失败..."
exit -1
fi
echo 'docker安装成功...'

echo '安装docker-compose...'
cp -f ./docker-compose-linux-x86_64 /usr/local/bin/docker-compose
echo '添加文件执行权限...'
chmod +x /usr/local/bin/docker-compose
if ! docker-compose -v; then
echo "docker-compose 安装失败..."
exit -1
fi
echo 'docker-compose 安装成功...'

一键卸载脚本

创建 Docker 和 Docker-Compose 一键安装脚本 uninstall.sh:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/sh
echo "停止所有容器服务"
docker stop $(docker ps -a -q)
echo "删除所有容器"
docker rm $(docker ps -a -q)
echo "删除docker所有镜像"
docker rmi -f $(docker images -q)
echo "停止docker服务"
systemctl stop docker
echo "删除docker.service..."
rm -rf /etc/systemd/system/docker.service
echo "删除docker文件..."
rm -rf /usr/bin/docker*
echo "重新加载配置文件"
systemctl daemon-reload
echo "卸载成功..."

echo "删除docker-compose"
rm -rf /usr/local/bin/docker-compose
echo "卸载成功"一、docker离线安装

加速格式:”registry-mirrors”: [“https://registry.docker-cn.com“]

镜像加速器 镜像加速器地址
Docker 中国官方镜像 https://registry.docker-cn.com
DaoCloud 镜像站 http://f1361db2.m.daocloud.io
Azure 中国镜像 https://dockerhub.azk8s.cn
科大镜像站 https://docker.mirrors.ustc.edu.cn
阿里云 https://ud6340vz.mirror.aliyuncs.com
七牛云 https://reg-mirror.qiniu.com
网易云 https://hub-mirror.c.163.com
腾讯云 https://mirror.ccs.tencentyun.com

命令学习

基本命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 查看版本号
docker version

# 启动docker
systemctl start docker
# 关闭docker
systemctl stop docker
# 重启docker
systemctl restart docker

# docker设置随服务启动而自启动
systemctl enable docker

# 查看docker 运行状态
systemctl status docker

# 查看volume列表
docker volume ls

# 查看网络列表
docker network ls

镜像

Docker默认拉取的架构是与主机的架构相同,当你在一个特定的架构上运行Docker命令时,Docker将自动尝试拉取与该架构匹配的镜像。例如,如果你在x86架构的主机上运行Docker命令,Docker将尝试拉取x86架构的镜像

这意味着Docker会自动适配主机的架构,并拉取相应的镜像供使用。如果需要指定架构,可以加上--platform=arm64参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 查看本地镜像
docker images

# 搜索镜像
docker search neo4j
# 拉取镜像 如果需要指定架构,可以加上`--platform=arm64`参数
docker pull 镜像名:tag

# 删除镜像 ------当前镜像没有被任何容器使用才可以删除
docker rmi -f 镜像名/镜像ID
# 删除多个 其镜像ID或镜像用用空格隔开即可
docker rmi -f 镜像名/镜像ID 镜像名/镜像ID

# 保存镜像,将我们的镜像保存为tar压缩文件,这样方便镜像转移和保存
# 然后可以在任何一台安装了docker的服务器上加载这个镜像
docker save 镜像名/镜像ID -o 镜像保存在哪个位置与名字
docker save -o my_ubuntu_v3.tar runoob/ubuntu:v3

# 加载镜像
docker load --input my_ubuntu_v3.tar

# 镜像重命名
docker tag <IMAGE_ID> <NEW_REPOSITORY>:<TAG>

容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 创建一个全新的容器,不会立即运行
docker create --name my_container nginx:latest
# 创建和启动的组合,创建了一个新容器并立即启动它,-d表示后台
docker run --name my_container -d nginx:latest

# 启动已终止容器
docker container start
# 停止容器
docker stop 容器ID或者容器名
# 重启容器
docker restart 容器ID或者容器名

# 列出所有在运行的容器信息
docker ps
# 查看本地所有容器
docker ps -a

# 删除指定容器
docker rm -f <container_id0> <container_id1>
# 删除未启动成功的容器
docker rm $(docker ps -a|grep Created|awk '{print $1}')
# 删除所有未运行的容器
docker rm $(docker ps -a|grep Created|awk '{print $1}')

# 容器重命名
docker rename CONTAINER NEW_NAME

镜像打包工具 Buildpacks、Dockerfile

Docker, Dockerfile, 和Docker Compose区别 | Baeldung

Docker Compose允许我们定义容器共享的共同对象。例如,我们可以一次性定义一个卷,然后把它挂在每个容器里,这样它们就可以共享一个共同的文件系统。或者,我们可以定义一个或多个容器用来通信的网络。

Docker Compose只是一个协调多个容器的工具。其他选择包括Kubernetes、Openshift和Apache Mesos

Docker容器迁移到其他服务器的5种方法详解_docker

目录挂载

  • 使用 Docker 运行后,我们改了项目代码不会立刻生效,需要重新buildrun,很是麻烦
  • 容器里面产生的数据,例如 log 文件,数据库备份文件,容器删除后就丢失了

目录挂载解决以上问题

  • bind mount 直接把宿主机目录映射到容器内,适合挂代码目录和配置文件。可挂到多个容器上
  • volume 由容器创建和管理,创建在宿主机,所以删除容器不会丢失,官方推荐,更高效,Linux 文件系统,适合存储数据库数据。可挂到多个容器上
  • tmpfs mount 适合存储临时文件,存宿主机内存中。不可多容器共享

演示

1
2
3
4
5
# bind mount 方式
docker run -p 8080:8080 --name test-hello -v D:/code:/app -d test:v1

# volume 方式
docker run -p 8080:8080 --name test-hello -v db-data:/app -d test:v1

Docker Compose管理

安装

1
2
3
4
5
6
7
8
9
10
11
# 下载
wget https://github.com/docker/compose/releases/download/v2.29.3/docker-compose-linux-x86_64

# 复制 Docker-Compose 到 /usr/local/bin
sudo cp -f ./docker-compose-linux-x86_64 /usr/local/bin/docker-compose

# 赋予 Docker-Compose 执行权限
sudo chmod +x /usr/local/bin/docker-compose

# 查看docker-compose版本
docker-compose -v

定义docker-compose.yaml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
version: '3.3'  # 指定 Docker Compose 文件的版本

services: # 定义服务
py311_bilu_env: # 服务名称,可以是任意的,但应具有描述性
image: py311_bilu:v0 # 指定要运行的 Docker 镜像
container_name: py311_bilu_env # 指定容器的名称
ports:
- "6007:6007" # 映射主机端口到容器端口,格式为 "主机端口:容器端口"
networks:
- bridge # 指定服务连接的网络名称,应在下面的 networks 部分定义
ulimits:
nproc: 1024 # 设置容器的最大进程数,nproc: 软限制为1024
environment: # 设置环境变量
- OMP_NUM_THREADS=4 # 设置 OMP 线程数
- OPENBLAS_NUM_THREADS=4 # 设置 OpenBLAS 线程数
- HTTP_PROXY=xxx # 设置 HTTP 代理
- HTTPS_PROXY=xx # 设置 HTTPS 代理
volumes:
- ../../ai:/app/ai # 挂载主机路径到容器路径,格式为 "主机路径:容器路径"
command: sh -c "cd /app/ai/scripts/services && python main_service_script.py" # 容器启动时执行的命令

networks:
bridge: # 定义一个名为 bridge 的网络
driver: bridge # 指定网络驱动类型为 bridge

基本指令学习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# 启动服务
docker-compose up
docker-compose up -d # 在后台运行容器

# 停止服务
docker-compose down

# 重新启动服务
docker-compose restart

# 查看服务状态
docker-compose ps

# 构建或重新构建服务
docker-compose build
docker-compose build <service_name>

# 查看服务日志
docker-compose logs
docker-compose logs <service_name>

# 进入容器的终端
docker-compose exec <service_name> /bin/bash

# 验证配置文件
docker-compose config

# 列出网络
docker-compose network ls

# 列出卷
docker-compose volume ls

# 拉取服务镜像
docker-compose pull

# 停止服务但不移除容器
docker-compose stop

# 移除停止的容器
docker-compose rm
docker-compose rm -f # 强制移除

# 扩展服务
docker-compose up --scale <service_name>=<number>

# 使用指定的 Compose 文件
docker-compose -f <compose_file> up
docker-compose -f <compose_file> down
docker-compose -f <compose_file> build
docker-compose -f <compose_file> logs

多容器通信

虚拟网络

要想多容器之间互通,从 Web 容器访问 Redis 容器,我们只需要把他们放到同个网络中就可以了

创建一个名为test-net的网络:

1
docker network create test-net

运行 Redis 在 test-net 网络中,别名redis

1
2
# network-alias指的是网络的别名
docker run -d --name redis --network redis-net --network-alias redis redis:latest

使用时url填写redis://redis:6379

运行 Web 项目,使用同个网络

1
docker run -p 8080:8080 --name test -v D:/test:/app --network redis-net -d test:v0

Docker-Compose

假设运行了两个容器:Web 项目 + Redis

如果项目依赖更多的第三方软件,我们需要管理的容器就更加多,每个都要单独配置运行,指定网络

我们可以使用 docker-compose 把项目的多个服务集合到一起,一键运行

安装 Docker Compose

  • 如果你是安装的桌面版 Docker,不需要额外安装,已经包含了
  • 如果是没图形界面的服务器版 Docker,你需要单独安装 安装文档
  • 运行docker-compose检查是否安装成功

编写脚本

要把项目依赖的多个服务集合到一起,我们需要编写一个docker-compose.yml文件,描述依赖哪些服务

容器默认时间不是北京时间,增加 TZ=Asia/Shanghai 可以改为北京时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
version: "3.7"

services:
app:
build: ./ # 或者直接使用镜像 image: narutohyc/ubuntu:v0
ports:
- 80:8080
volumes:
- ./:/app
environment:
- TZ=Asia/Shanghai
redis:
image: redis:5.0.13
volumes:
- redis:/data
environment:
- TZ=Asia/Shanghai

volumes:
redis:

docker-compose.yml 文件所在目录,执行:docker-compose up就可以跑起来了,文档在这

在后台运行只需要加一个 -d 参数docker-compose up -d

动作 命令
查看运行状态 docker-compose ps
停止运行 docker-compose stop
重启 docker-compose restart
重启单个服务 docker-compose restart service-name
进入容器命令行 docker-compose exec service-name sh
查看容器运行log docker-compose logs [service-name]

hello world

创建dockfile,新建一个Dockerfile文件

1
2
3
4
5
6
7
8
9
# 使用基础镜像,选择适合您的环境
FROM ubuntu:20.04

# 安装依赖库和工具
RUN apt update
RUN apt-get install -y wget

# 设置工作目录
WORKDIR /app

构建镜像,在Dockerfile目录下,执行以下命令,-t后面跟的是镜像名和版本,这里会构建一个fastchat镜像,版本号为v0

1
docker build -t fastchat:v0 .

如果出现网络问题,需要配置代理,可以带上--build-arg参数

1
docker build -t fastchat:v0 --build-arg http_proxy=http://192.168.0.xx:xx --build-arg https_proxy=http://192.168.0.xx:xx .

如果需要指定dockfile文件,可以使用-f参数

1
docker build -f Q:\pyCharmWS\chatgpts\dockfiles\Dockerfile-ubuntu -t ubuntu:v0 . 

除了自己写dockfile,还可以使用docker pull拉取现成的镜像

查看镜像列表

1
2
3
4
docker images

REPOSITORY TAG IMAGE ID CREATED SIZE
fastchat v0 20ee81939779 20 seconds ago 115MB

启动镜像

1
2
3
docker run -itd -p 8080:80 --name ubuntu-test fastchat:v0

>>> 918a3b2ccc42436e01c5033021ba97d5bd4c56df48b2c549bf01855d9979333c

docker run -itd表示在后台运行容器,并允许与容器进行交互,同时为容器分配一个伪终端

将容器的80端口映射到主机的8080端口

--name ubuntu-test用于指定容器的名称为`ubuntu-test,返回一个容器id

如果已执行就退出’Exit(0)’,可以加上参数--entrypoint=/bin/bash,这里会自动退出是因为Docker容器后台运行,就必须有一个前台进程。容器运行的命令如果不是那些一直挂起的命令(比如运行top,tail)就是会自动退出的

查看容器列表

1
2
3
4
docker ps

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
918a3b2ccc42 fastchat:v0 "/bin/bash" 20 seconds ago Up 19 seconds ubuntu-test

CONTAINER ID指的是容器ID

进入容器

1
docker exec -it ubuntu-test bash

输入exit退出,container是不会被关闭的

1
docker attach ubuntu-test

使用快捷键退出:按下键盘上的Ctrl + P,然后按下Ctrl + Q,container是不会被关闭的

或者输入exit退出,container是被关闭的

这个组合键可以分离终端与容器的连接,但不会停止容器的运行,将返回到宿主机的终端,而容器会继续在后台运行

停止容器

1
docker stop ubuntu-test

当您执行docker stop命令停止容器后,容器的名称可能仍然保留在Docker中。如果您尝试使用相同的容器名称再次运行容器,会出现”重名”的错误

1
2
3
Q:\pyCharmWS\chatgpts\dockfiles>docker run -itd --name ubuntu-test fastchat:v0
docker: Error response from daemon: Conflict. The container name "/ubuntu-test" is already in use by container "918a3b2ccc42436e01c5033021ba97d5bd4c56df48b2c549bf01855d9979333c". You have to remove (or rename) that container to be able to reuse that name.
See 'docker run --help'.

这是因为Docker要求容器名称在给定的命名空间中必须是唯一的。当您停止容器时,该容器的名称不会立即从Docker中删除,以便您可以查看已停止容器的状态和日志等信息

这时候可以更改原来容器的名称删除已停止的容器

  • docker rename ubuntu-old ubuntu-test

    1
    2
    3
    Q:\pyCharmWS\chatgpts\dockfiles>docker ps -a
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    918a3b2ccc42 fastchat:v0 "/bin/bash" 41 minutes ago Exited (130) 11 minutes ago ubuntu-test
  • docker rm ubuntu-test

重启容器

1
docker restart ubuntu-test

将容器保存为镜像,以便稍后再次使用或与其他人共享

要将容器保存为镜像,可以使用docker commit命令。以下是保存容器为镜像的步骤:

  1. 确保您的容器处于停止状态。如果容器正在运行,请先停止它:

    1
    docker stop <container_name_or_id>
  2. 使用docker commit命令将容器保存为镜像。在命令中指定容器的名称或ID以及要为新镜像指定的名称和标签:

    1
    docker commit <container_name_or_id> <new_image_name:tag>

    例如:

    1
    docker commit mycontainer myimage:v1

    这将创建一个名为myimage,标签为v1的新镜像

  3. 等待docker commit命令完成,它会将容器的文件系统和元数据保存为新的镜像。一旦完成,您可以使用docker images命令查看新创建的镜像

现在,您已经将容器保存为新的镜像。您可以使用该镜像创建新的容器,或将其推送到镜像仓库以供其他人使用

请注意,使用docker commit命令保存容器为镜像时,镜像将包含容器中当前的文件系统状态和配置。这意味着如果容器中有任何不必要的文件或敏感信息,它们也会包含在保存的镜像中。因此,在保存容器之前,最好确保容器中不包含不必要的文件,并遵循最佳实践来保护敏感信息

值得一提的是,docker commit 命令是将容器的状态保存为镜像,而不是推荐的方法

更好的做法是使用 Dockerfile 来定义容器的配置和状态,并使用 docker build 命令构建镜像。这样可以更好地跟踪和管理镜像的变更

dockfile

构建一个基于ubuntu的anaconda环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 使用基础镜像,选择适合您的环境
# FROM arm64v8/ubuntu:20.04
FROM ubuntu:20.04

# 安装依赖库和工具
RUN apt update
RUN apt-get install -y wget

# 下载并安装 Anaconda https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/
RUN wget -qO ~/anaconda.sh https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2023.03-0-Linux-x86_64.sh
# RUN wget -qO ~/anaconda.sh https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2023.03-0-Linux-aarch64.sh
RUN /bin/bash ~/anaconda.sh -b -p /opt/anaconda3
RUN rm ~/anaconda.sh

# 将 Anaconda 添加到环境变量
ENV PATH="/opt/anaconda3/bin:${PATH}"
RUN conda create -y -n chat38 python=3.8 anaconda

# 设置工作目录
WORKDIR /app

# 指定全局 shell 环境,这样才能用source
SHELL ["/bin/bash", "-c"]

# 切换py环境
CMD source activate chat38
RUN pip install simplejson

除了SHELL ["/bin/bash", "-c"],还可以每次指定bash环境,CMD /bin/bash -c "source activate chat38"

发布和部署

要将镜像发布到 Docker Hub 上,需要按照以下步骤进行操作:

注册 Docker Hub 账号,如果你还没有 Docker Hub 账号,首先需要在Docker Hub的官方网站上进行注册

登录 Docker Hub,使用以下命令在终端中登录到 Docker Hub

1
2
3
Q:\pyCharmWS\chatgpts\dockfiles>docker login -u narutohyc
Password:
Login Succeeded

标记镜像,在发布到 Docker Hub 之前,需要为镜像添加一个适当的标签,以便将其与你的 Docker Hub 用户名和存储库关联起来,使用以下命令为镜像添加标签

1
docker tag <IMAGE_ID> <DOCKER_HUB_USERNAME>/<REPOSITORY_NAME>:<TAG>

其中,<IMAGE_ID> 是你要发布的镜像的 ID,<DOCKER_HUB_USERNAME> 是你的 Docker Hub 用户名,<REPOSITORY_NAME> 是你想要为镜像设置的存储库名称,<TAG> 是一个可选的标签,用于标识镜像的版本号

发布镜像,使用以下命令将标记后的镜像发布到 Docker Hub

1
docker push <DOCKER_HUB_USERNAME>/<REPOSITORY_NAME>:<TAG>

这将把镜像推送到 Docker Hub 上的指定存储库中

确认发布,登录到 Docker Hub 的网站,访问你的 Docker Hub 账号,你应该能够在相应的存储库中看到已发布的镜像

请注意,发布到 Docker Hub 的镜像将成为公开可访问的,任何人都可以从 Docker Hub 上获取并使用该镜像。如果你希望限制访问权限,可以考虑使用私有仓库,或者在 Docker Hub 上创建一个私有的组织来管理镜像的访问权限

示例

安装redis

演示 Docker 安装 Redis

一个命令跑起来:docker run -d -p 6379:6379 --name redis redis:latest

命令参考:https://docs.docker.com/engine/reference/commandline/run/

安装wordpress

定义docker-compose.yml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
version: '3.1'

services:

wordpress:
image: wordpress
restart: always
ports:
- 8080:80
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
volumes:
- wordpress:/var/www/html

db:
image: mysql:5.7
restart: always
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
- db:/var/lib/mysql

volumes:
wordpress:
db:

执行docker-compose up -d

docker镜像打包部署

基于基础的python镜像,构建出符合项目的镜像,并打包上传至服务器,然后基于这个镜像,运行项目服务

版本支持(20版本不支持,会抛异常RuntimeError: can't start new thread,目前测试通过的有24.0.527.2.0)

  1. 准备dockfile文件requirements.sh文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 使用官方 Python 3.11 slim 版本镜像作为基础镜像
    FROM python:3.11-slim

    # 设置工作目录
    WORKDIR /app

    # 复制当前目录所有文件到容器的工作目录中
    COPY ./requirements.sh .

    # 更新包管理器并安装依赖
    RUN sh requirements.sh

    requirements.sh示例如下:

    1
    2
    3
    4
    5
    6
    #!/bin/bash

    pip install --progress-bar off aiohappyeyeballs==2.4.0
    pip install --progress-bar off aiohttp==3.10.5
    pip install --progress-bar off aiolimiter==1.1.0
    pip install --progress-bar off aiosignal==1.3.1
  2. 基于dockfile文件执行build命令(要在当前路径下,有Dockerfilerequirements.sh脚本)

    1
    docker build -f "D:\work\coding\Dockerfile" -t py311_bilu:v0 . 

    创建完镜像,可以用命令查看是否创建成功

    1
    2
    3
    (base) PS D:\work\coding\pycharm\bilu\新建文件夹> docker images
    REPOSITORY TAG IMAGE ID CREATED SIZE
    py311_bilu v0 de6dbadb4ea4 47 minutes ago 498MB
  3. 将镜像保存成文件

    1
    docker save -o py311_bilu.tar py311_bilu:v0
  4. 将镜像文件发送到服务器,并加载到docker

    1
    docker load -i py311_bilu.tar

    加载完镜像,可以用命令查看是否加载成功

    1
    2
    3
    docker images
    REPOSITORY TAG IMAGE ID CREATED SIZE
    py311_bilu v0 de6dbadb4ea4 47 minutes ago 498MB
  5. 运行服务(需要在docker-compose文件的路径下)

    docker-compose方式(推荐)

    1
    2
    3
    4
    5
    # 基于docker-compose.yml文件
    docker-compose up -d

    # 查看运行日志
    docker-compose logs py311_bilu_env

    旧的方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    docker ps | grep py311_bilu_env

    # 如果容器已经在运行,先关闭
    docker stop py311_bilu_env

    # 如果容器已存在,先删除
    docker rm py311_bilu_env

    # 创建并启动容器 -p为端口映射 -v为路径映射 py311_bilu_env是容器名 py311_bilu:v0是镜像名
    # sh -c 后面跟的是运行命令
    # -e HTTP_PROXY、-e HTTPS_PROXY为代理(不一定需要)
    docker run -d -p 6007:6007 --network bridge --ulimit nproc=1024:2048 -e OMP_NUM_THREADS=4 -e OPENBLAS_NUM_THREADS=4 -v /home/ai:/app/ai --name py311_bilu_env py311_bilu:v0 sh -c "cd /app/ai/scripts/services && python main_service_script.py"
  6. 重启服务(文件有更新时需要)

    1
    2
    # 重新启动服务
    docker-compose restart
  7. docker-compose文件配置有更新时,需要先关闭服务

    1
    2
    3
    4
    5
    6
    # 关闭服务
    docker-compose down
    # 启动服务
    docker-compose -f noup_docker-compose.yml up -d
    # 查看日志
    docker-compose logs py311_bilu_env
  8. 其他命令

    1
    2
    # 创建容器,并进入交互式
    docker exec -it py311_bilu_env /bin/sh

实战neo4j

docker安装部署neo4j

安装neo4j

拉取neo4j镜像

  1. docker官方镜像中找合适的镜像

    1
    docker search neo4j
  2. 拉取镜像源

    1
    docker pull neo4j(:版本号) # 缺省 ":版本号" 时默认安装latest版本的
  3. 查看本地镜像,检验是否拉取成功

    1
    docker images

图算法插件

neo4j提供了一系列常用的图算法,该算法库需要单独安装,注意版本对应关系

  1. 点击上方官网链接,下载Neo4j Graph Data Science下的文件,放到$NEO4J_HOME/plugins目录中

  2. 将以下内容添加到您的$NEO4J_HOME/conf/neo4j.conf文件中,参考这里

    1
    dbms.security.procedures.unrestricted=apoc.*,gds.*

    此配置条目是必需的,因为 GDS 库访问 Neo4j 的低级组件以最大化性能

  3. 重启 Neo4j,在docker下就是重启

为了验证您的安装,可以输入以下命令

1
RETURN gds.version()

要列出所有已安装的算法,请运行以下gds.list()过程

1
CALL gds.list()

例子: neo4j实现PageRank算法

启动neo4j

找一个目录存放docker的各镜像运行目录,比如我这里选的是/home/huangyc/docker

然后再在这个目录新建具体的镜像对应的文件夹/home/huangyc/docker/neo4j,在下面新建四个文件夹(实际上好像不需要手动建,执行命令时自动会新建)

  • data: 数据存放的文件夹
  • logs: 运行的日志文件夹
  • conf: 数据库配置文件夹(在配置文件neo4j.conf中配置包括开放远程连接、设置默认激活的数据库)
  • import: 为了大批量导入csv来构建数据库,需要导入的节点文件nodes.csv和关系文件rel.csv需要放到这个文件夹下
  • plugins: 存放jar插件

启动命令格式如下

1
2
3
4
5
6
7
8
9
docker run -d --name container_name \  //-d表示容器后台运行 --name指定容器名字
-p 7474:7474 -p 7687:7687 \ //映射容器的端口号到宿主机的端口号
-v /home/huangyc/docker/neo4j/data:/data \ //把容器内的数据目录挂载到宿主机的对应目录下
-v /home/huangyc/docker/neo4j/logs:/logs \ //挂载日志目录
-v /home/huangyc/docker/neo4j/conf:/var/lib/neo4j/conf //挂载配置目录
-v /home/huangyc/docker/neo4j/import:/var/lib/neo4j/import \ //挂载数据导入目录
-v /home/huangyc/docker/neo4j/plugins:/var/lib/neo4j/plugins \ //挂载数据导入目录
--env NEO4J_AUTH=neo4j/password \ //设定数据库的用户名和和密码
neo4j //指定使用的镜像

也可以写成单行命令

1
docker run -d --name neo4j_hyc -p 7474:7474 -p 7687:7687 -v /home/huangyc/docker/neo4j/data:/data -v /home/huangyc/docker/neo4j/logs:/logs -v /home/huangyc/docker/neo4j/conf:/var/lib/neo4j/conf -v /home/huangyc/docker/neo4j/import:/var/lib/neo4j/import -v /home/huangyc/docker/neo4j/plugins:/var/lib/neo4j/plugins --env NEO4J_AUTH=neo4j/hyc neo4j

py库

使用Python访问图数据库,主要使用的库时py2neoneo4j

  • py2neo通过操作python变量,达到操作neo4j的目的,同时也支持cypher语法
  • neo4j主要时执行CQL(cypher)语句

安装

1
pip install py2neo

使用例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# coding:utf-8
from py2neo import Graph, Node, Relationship

# 连接neo4j数据库,输入地址、用户名、密码
graph = Graph("http://192.168.1.106:7474", name="neo4j")
graph.delete_all()
# 创建结点
test_node_1 = Node('ru_yi_zhuan', name='皇帝') # 修改的部分
test_node_2 = Node('ru_yi_zhuan', name='皇后') # 修改的部分
test_node_3 = Node('ru_yi_zhuan', name='公主') # 修改的部分

graph.create(test_node_1)
graph.create(test_node_2)
graph.create(test_node_3)

# 创建关系
# 分别建立了test_node_1指向test_node_2和test_node_2指向test_node_1两条关系,关系的类型为"丈夫、妻子",两条关系都有属性count,且值为1。
node_1_zhangfu_node_1 = Relationship(test_node_1, '丈夫', test_node_2)
node_1_zhangfu_node_1['count'] = 1
node_2_qizi_node_1 = Relationship(test_node_2, '妻子', test_node_1)
node_2_munv_node_1 = Relationship(test_node_2, '母女', test_node_3)

node_2_qizi_node_1['count'] = 1

graph.create(node_1_zhangfu_node_1)
graph.create(node_2_qizi_node_1)
graph.create(node_2_munv_node_1)

print(graph)
print(test_node_1)
print(test_node_2)
print(node_1_zhangfu_node_1)
print(node_2_qizi_node_1)
print(node_2_munv_node_1)

安装

1
pip install neo4j

使用例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from neo4j import GraphDatabase

driver = GraphDatabase.driver("bolt://localhost:7687", auth=("neo4j", "password"))

def add_friend(tx, name, friend_name):
tx.run("MERGE (a:Person {name: $name}) "
"MERGE (a)-[:KNOWS]->(friend:Person {name: $friend_name})",
name=name, friend_name=friend_name)

def print_friends(tx, name):
for record in tx.run("MATCH (a:Person)-[:KNOWS]->(friend) WHERE a.name = $name "
"RETURN friend.name ORDER BY friend.name", name=name):
print(record["friend.name"])

with driver.session() as session:
session.write_transaction(add_friend, "Arthur", "Guinevere")
session.write_transaction(add_friend, "Arthur", "Lancelot")
session.write_transaction(add_friend, "Arthur", "Merlin")
session.read_transaction(print_friends, "Arthur")

实战nebula

基本介绍

NebulaGraph 由三种服务构成:Graph 服务、Meta 服务和 Storage 服务,是一种存储与计算分离的架构

Meta 服务

Meta 服务是由 nebula-metad 进程提供的,用户可以根据场景配置 nebula-metad 进程数量:

  • 测试环境中,用户可以在 NebulaGraph 集群中部署 1 个或 3 个 nebula-metad 进程。如果要部署 3 个,用户可以将它们部署在 1 台机器上,或者分别部署在不同的机器上。
  • 生产环境中,建议在 NebulaGraph 集群中部署 3 个 nebula-metad 进程。请将这些进程部署在不同的机器上以保证高可用。

所有 nebula-metad 进程构成了基于 Raft 协议的集群,其中一个进程是 leader,其他进程都是 follower。

leader 是由多数派选举出来,只有 leader 能够对客户端或其他组件提供服务,其他 follower 作为候补,如果 leader 出现故障,会在所有 follower 中选举出新的 leader。

Graph 服务

Graph 服务是由nebula-graphd 进程提供,服务主要负责处理查询请求,包括解析查询语句、校验语句、生成执行计划以及按照执行计划执行四个大步骤,查询请求发送到 Graph 服务后,会由如下模块依次处理:

  1. Parser:词法语法解析模块。
  2. Validator:语义校验模块。
  3. Planner:执行计划与优化器模块。
  4. Executor:执行引擎模块。

Storage 服务

NebulaGraph 的存储包含两个部分,一个是 Meta 相关的存储,称为 Meta 服务,在前文已有介绍。

另一个是具体数据相关的存储,称为 Storage 服务。其运行在 nebula-storaged 进程

环境搭建

nebula 3.2.1为例

下载并安装NebulaGraph

1
2
wget https://oss-cdn.nebula-graph.com.cn/package/3.2.1/nebula-graph-3.2.1.el7.x86_64.rpm
sudo rpm -ivh --prefix=/home/huangyc/nebula nebula-graph-3.2.1.el7.x86_64.rpm

--prefix为可选项,用于指定安装路径

如不设置,系统会将 NebulaGraph 安装到默认路径/usr/local/nebula/

集群配置

集群配置需要保证集群机器配置ssh免密

修改每个服务器上的 NebulaGraph 配置文件

NebulaGraph 的所有配置文件均位于安装目录的etc目录内,包括nebula-graphd.confnebula-metad.confnebula-storaged.conf,用户可以只修改所需服务的配置文件。各个机器需要修改的配置文件如下。

机器名称 待修改配置文件
A nebula-graphd.confnebula-storaged.confnebula-metad.conf
B nebula-graphd.confnebula-storaged.confnebula-metad.conf
C nebula-graphd.confnebula-storaged.confnebula-metad.conf
D nebula-graphd.confnebula-storaged.conf
E nebula-graphd.confnebula-storaged.conf
  • 机器 A 配置

    nebula-graphd.conf

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    ########## networking ##########
    # Comma separated Meta Server Addresses
    --meta_server_addrs=192.168.10.111:9559,192.168.10.112:9559,192.168.10.113:9559
    # Local IP used to identify the nebula-graphd process.
    # Change it to an address other than loopback if the service is distributed or
    # will be accessed remotely.
    --local_ip=192.168.10.111
    # Network device to listen on
    --listen_netdev=any
    # Port to listen on
    --port=9669

    nebula-storaged.conf

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ########## networking ##########
    # Comma separated Meta server addresses
    --meta_server_addrs=192.168.10.111:9559,192.168.10.112:9559,192.168.10.113:9559
    # Local IP used to identify the nebula-storaged process.
    # Change it to an address other than loopback if the service is distributed or
    # will be accessed remotely.
    --local_ip=192.168.10.111
    # Storage daemon listening port
    --port=9779

    nebula-metad.conf

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ########## networking ##########
    # Comma separated Meta Server addresses
    --meta_server_addrs=192.168.10.111:9559,192.168.10.112:9559,192.168.10.113:9559
    # Local IP used to identify the nebula-metad process.
    # Change it to an address other than loopback if the service is distributed or
    # will be accessed remotely.
    --local_ip=192.168.10.111
    # Meta daemon listening port
    --port=9559
  • 机器 D 配置

    nebula-graphd.conf

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    ########## networking ##########
    # Comma separated Meta Server Addresses
    --meta_server_addrs=192.168.10.111:9559,192.168.10.112:9559,192.168.10.113:9559
    # Local IP used to identify the nebula-graphd process.
    # Change it to an address other than loopback if the service is distributed or
    # will be accessed remotely.
    --local_ip=192.168.10.114
    # Network device to listen on
    --listen_netdev=any
    # Port to listen on
    --port=9669

    nebula-storaged.conf

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ########## networking ##########
    # Comma separated Meta server addresses
    --meta_server_addrs=192.168.10.111:9559,192.168.10.112:9559,192.168.10.113:9559
    # Local IP used to identify the nebula-storaged process.
    # Change it to an address other than loopback if the service is distributed or
    # will be accessed remotely.
    --local_ip=192.168.10.114
    # Storage daemon listening port
    --port=9779
  • ABC三台配置除了local_ip,其他都一致,DE两台配置除了local_ip,其他都一致

启动服务

命令学习

使用脚本nebula.service管理服务,包括启动、停止、重启、中止和查看

nebula.service的默认路径是/usr/local/nebula/scripts,如果修改过安装路径,请使用实际路径

语法

1
2
3
4
sudo /usr/local/nebula/scripts/nebula.service
[-v] [-c <config_file_path>]
<start | stop | restart | kill | status>
<metad | graphd | storaged | all>

比如对于非容器部署的 NebulaGraph,执行如下命令启动服务:

1
2
3
4
5
6
7
sudo /usr/local/nebula/scripts/nebula.service start all
[INFO] Starting nebula-metad...
[INFO] Done
[INFO] Starting nebula-graphd...
[INFO] Done
[INFO] Starting nebula-storaged...
[INFO] Done

执行如下命令查看 NebulaGraph 服务状态

1
sudo /usr/local/nebula/scripts/nebula.service status all

如果返回如下结果,表示 NebulaGraph 服务正常运行

1
2
3
4
5
[INFO] nebula-metad(33fd35e): Running as 29020, Listening on 9559
[INFO] nebula-graphd(33fd35e): Running as 29095, Listening on 9669
[WARN] nebula-storaged after v3.0.0 will not start service until it is added to cluster.
[WARN] See Manage Storage hosts:ADD HOSTS in https://docs.nebula-graph.io/
[INFO] nebula-storaged(33fd35e): Running as 29147, Listening on 9779

正常启动 NebulaGraph 后,nebula-storaged进程的端口显示红色。这是因为nebula-storaged在启动流程中会等待nebula-metad添加当前 Storage 服务,当前 Storage 服务收到 Ready 信号后才会正式启动服务。从 3.0.0 版本开始,在配置文件中添加的 Storage 节点无法直接读写,配置文件的作用仅仅是将 Storage 节点注册至 Meta 服务中。必须使用ADD HOSTS命令后,才能正常读写 Storage 节点。

注册

具体是通过nebula-console命令行或者studio页面执行,用 java client 也可以的, 底层逻辑都是通过客户端发送一条 add hosts xxxxx query

1
ADD HOSTS 192.168.40.39:9779, 192.168.40.40:9779, 192.168.40.41:9779;

比如使用python客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from nebula3.gclient.net import ConnectionPool
from nebula3.Config import Config

# define a config
config = Config()
config.max_connection_pool_size = 10
# init connection pool
connection_pool = ConnectionPool()
# if the given servers are ok, return true, else return false
ok = connection_pool.init([('192.168.123.xx', 9669)], config)

# option 1 control the connection release yourself
# get session from the pool
session = connection_pool.get_session('root', 'nebula')

session.execute("ADD HOSTS 192.168.123.24:9779")

等待20s后,重新查看服务状态,发现警告没有就说明成功了

1
2
3
4
5
[root@localhost nebula]# sudo scripts/nebula.service status all
[WARN] The maximum files allowed to open might be too few: 1024
[INFO] nebula-metad(bb2e684): Running as 11660, Listening on 9559
[INFO] nebula-graphd(bb2e684): Running as 11727, Listening on 9669
[INFO] nebula-storaged(bb2e684): Running as 11764, Listening on 9779

清空图

  • 数据清除后,如无备份,无法恢复。使用该功能务必谨慎

    CLEAR SPACE不是原子性操作。如果执行出错,请重新执行,避免残留数据

  • 图空间中的数据量越大,CLEAR SPACE消耗的时间越长

    如果CLEAR SPACE的执行因客户端连接超时而失败,可以增大 Graph 服务配置storage_client_timeout_ms参数的值

  • CLEAR SPACE的执行过程中,向该图空间写入数据的行为不会被自动禁止

    这样的写入行为可能导致CLEAR SPACE清除数据不完全,残留的数据也可能受到损坏

1
CLEAR SPACE [IF EXISTS] <space_name>;

保留的数据

图空间中,CLEAR SPACE不会删除的数据包括:

  • Tag 信息
  • Edge type 信息
  • 原生索引和全文索引的元数据

DROP SPACE语句用于删除指定图空间以及其中的所有信息

1
DROP SPACE [IF EXISTS] <graph_space_name>;

客户端

NebulaGraph 支持多种类型的客户端,包括命令行客户端、可视化界面客户端和流行编程语言客户端

详情参见客户端列表

前提条件

官方文档

  • NebulaGraph 服务已启动

  • 运行 NebulaGraph Console 的机器和运行 NebulaGraph 的服务器网络互通

  • NebulaGraph Console 的版本兼容 NebulaGraph 的版本

使用命令arch,查看系统结构,去官网下载安装包,重命名文件为nebula_console

  1. 为用户授予 nebula-console 文件的执行权限

    1
    chmod 111 nebula-console
  2. 在命令行界面中,切换工作目录至 nebula-console 文件所在目录,执行如下命令连接 NebulaGraph

    1
    ./nebula-console -addr <ip> -port <port> -u <username> -p <password> [-t 120] [-e "nGQL_statement" | -f filename.nGQL]

    例如,要连接到部署在 192.168.10.8 上的 Graph 服务,运行以下命令

    1
    ./nebula_console -addr 192.168.10.8 -port 9669 -u root -p nebula

已安装 Python,版本为 3.6 及以上,版本对照表

NebulaGraph 版本 NebulaGraph Python 版本
3.2.1 3.1.0
2.6.x 2.6.0

pip安装

1
$ pip install nebula3-python==<version>

初始化一些数据

  1. 执行如下语句创建名为basketballplayer的图空间

    1
    CREATE SPACE basketballplayer(partition_num=15, replica_factor=1, vid_type=fixed_string(32));
  2. 执行命令SHOW HOSTS检查分片的分布情况,确保平衡分布

    1
    2
    3
    4
    5
    6
    7
    8
    nebula> SHOW HOSTS;
    +-------------+-----------+-----------+-----------+--------------+----------------------------------+------------------------+---------+
    | Host | Port | HTTP port | Status | Leader count | Leader distribution | Partition distribution | Version |
    +-------------+-----------+-----------+-----------+--------------+----------------------------------+------------------------+---------+
    | "storaged0" | 9779 | 19669 | "ONLINE" | 5 | "basketballplayer:5" | "basketballplayer:5" | "3.1.0" |
    | "storaged1" | 9779 | 19669 | "ONLINE" | 5 | "basketballplayer:5" | "basketballplayer:5" | "3.1.0" |
    | "storaged2" | 9779 | 19669 | "ONLINE" | 5 | "basketballplayer:5" | "basketballplayer:5" | "3.1.0" |
    +-------------+-----------+-----------+-----------+--------------+----------------------------------+------------------------+---------+
  3. 选择图空间basketballplayer

    1
    nebula[(none)]> USE basketballplayer;

    用户可以执行命令SHOW SPACES查看创建的图空间

    1
    2
    3
    4
    5
    6
    nebula> SHOW SPACES;
    +--------------------+
    | Name |
    +--------------------+
    | "basketballplayer" |
    +--------------------+
  4. 创建 Tag 和 Edge type

    语法:

    1
    2
    3
    4
    5
    6
    7
    8
    CREATE {TAG | EDGE} [IF NOT EXISTS] {<tag_name> | <edge_type_name>}
    (
    <prop_name> <data_type> [NULL | NOT NULL] [DEFAULT <default_value>] [COMMENT '<comment>']
    [{, <prop_name> <data_type> [NULL | NOT NULL] [DEFAULT <default_value>] [COMMENT '<comment>']} ...]
    )
    [TTL_DURATION = <ttl_duration>]
    [TTL_COL = <prop_name>]
    [COMMENT = '<comment>'];

    创建 Tag:playerteam,以及 Edge type:followserve。说明如下表。

    | 名称 | 类型 | 属性 |
    | ——— | ————- | ———————————————— |
    | player | Tag | name (string), age (int) |
    | team | Tag | name (string) |
    | follow | Edge type | degree (int) |
    | serve | Edge type | start_year (int), end_year (int) |

    1
    2
    3
    4
    CREATE TAG player(name string, age int);
    CREATE TAG team(name string);
    CREATE EDGE follow(degree int);
    CREATE EDGE serve(start_year int, end_year int);
  5. 插入点和边

    • 插入点

      1
      2
      3
      4
      5
      6
      7
      8
      INSERT VERTEX [IF NOT EXISTS] [tag_props, [tag_props] ...]
      VALUES <vid>: ([prop_value_list])

      tag_props:
      tag_name ([prop_name_list])

      prop_name_list: [prop_name [, prop_name] ...]
      prop_value_list: [prop_value [, prop_value] ...]

      vid是 Vertex ID 的缩写,vid在一个图空间中是唯一的。参数详情请参见 INSERT VERTEX

    • 插入边

      1
      2
      3
      4
      5
      6
      INSERT EDGE [IF NOT EXISTS] <edge_type> ( <prop_name_list> ) VALUES 
      <src_vid> -> <dst_vid>[@<rank>] : ( <prop_value_list> )
      [, <src_vid> -> <dst_vid>[@<rank>] : ( <prop_value_list> ), ...];

      <prop_name_list> ::= [ <prop_name> [, <prop_name> ] ...]
      <prop_value_list> ::= [ <prop_value> [, <prop_value> ] ...]

    参数详情请参见 INSERT EDGE

    • 插入代表球员和球队的点

      1
      2
      3
      4
      nebula> INSERT VERTEX player(name, age) VALUES "player100":("Tim Duncan", 42);
      nebula> INSERT VERTEX player(name, age) VALUES "player101":("Tony Parker", 36);
      nebula> INSERT VERTEX player(name, age) VALUES "player102":("LaMarcus Aldridge", 33);
      nebula> INSERT VERTEX team(name) VALUES "team203":("Trail Blazers"), "team204":("Spurs");
    • 插入代表球员和球队之间关系的边

      1
      2
      3
      4
      nebula> INSERT EDGE follow(degree) VALUES "player101" -> "player100":(95);
      nebula> INSERT EDGE follow(degree) VALUES "player101" -> "player102":(90);
      nebula> INSERT EDGE follow(degree) VALUES "player102" -> "player100":(75);
      nebula> INSERT EDGE serve(start_year, end_year) VALUES "player101" -> "team204":(1999, 2018),"player102" -> "team203":(2006, 2015);
  6. 查询数据

    • GO 语句可以根据指定的条件遍历数据库。GO语句从一个或多个点开始,沿着一条或多条边遍历,返回YIELD子句中指定的信息。

    • FETCH 语句可以获得点或边的属性。

    • LOOKUP 语句是基于索引的,和WHERE子句一起使用,查找符合特定条件的数据。

    • MATCH 语句是查询图数据最常用的,可以灵活的描述各种图模式,但是它依赖索引去匹配 NebulaGraph 中的数据模型,性能也还需要调优。

🌶注意

无属性索引的时候,在没有指定条件的时候,可以通过数据扫描的sample下推去扫得 limit 的数据

而带有filter条件时,需要全扫才行,这个情况在nebula里是被禁止的,需要创建这个tag上的索引才能查询

1
2
3
4
5
6
7
8
9
10
11
# 在 Tag player 的 name 属性和 Edge type belong_to 上创建索引
CREATE TAG INDEX IF NOT EXISTS name ON player(name(20));
CREATE EDGE INDEX IF NOT EXISTS belong_to_index on belong_to();
# 重建索引使其生效
REBUILD EDGE INDEX name;
REBUILD EDGE INDEX belong_to_index;
# 开始查询
MATCH ()<-[e:belong_to]-()
WHERE e.industry_name=='水力发电'
RETURN e
LIMIT 3;

图模式

模式(pattern)和图模式匹配,是图查询语言的核心功能

单点模式

1
(a)

示例为一个简单的模式,描述了单个点,并使用变量a命名该点

多点关联模式

多个点通过边相连是常见的结构,模式用箭头来描述两个点之间的边。例如:

1
(a)-[]->(b)

示例为一个简单的数据结构:两个点和一条连接两个点的边,两个点分别为ab,边是有方向的,从ab

这种描述点和边的方式可以扩展到任意数量的点和边,例如:

1
(a)-[]->(b)<-[]-(c)

这样的一系列点和边称为路径(path)

只有在涉及某个点时,才需要命名这个点。如果不涉及这个点,则可以省略名称,例如:

1
(a)-[]->()<-[]-(c)

Tag模式

nGQL 中的Tag概念与 openCypher 中的Label有一些不同。例如,必须创建一个Tag之后才能使用它,而且Tag还定义了属性的类型

模式除了简单地描述图中的点之外,还可以描述点的 Tag。例如:

1
(a:User)-[]->(b)

模式也可以描述有多个 Tag 的点,例如:

1
(a:User:Admin)-[]->(b)

属性模式

点和边是图的基本结构。nGQL 在这两种结构上都可以增加属性,方便实现更丰富的模型。

在模式中,属性的表示方式为:用花括号括起一些键值对,用英文逗号分隔。例如一个点有两个属性:

1
(a {name: 'Andres', sport: 'Brazilian Ju-Jitsu'})

在这个点上可以有一条边是:

1
(a)-[{blocked: false}]->(b)

边模式

描述一条边最简单的方法是使用箭头连接两个点。

可以用以下方式描述边以及它的方向性。如果不关心边的方向,可以省略箭头,例如:

1
(a)-[]-(b)

和点一样,边也可以命名。一对方括号用于分隔箭头,变量放在两者之间。例如:

1
(a)-[r]->(b)

和点上的 Tag 一样,边也可以有类型。描述边的类型,例如:

1
(a)-[r:REL_TYPE]->(b)

和点上的 Tag 不同,一条边只能有一种 Edge type。但是如果我们想描述多个可选 Edge type,可以用管道符号(|)将可选值分开,例如:

1
(a)-[r:TYPE1|TYPE2]->(b)

和点一样,边的名称可以省略,例如:

1
(a)-[:REL_TYPE]->(b)

变长模式

在图中指定边的长度来描述多条边(以及中间的点)组成的一条长路径,不需要使用多个点和边来描述。例如:

1
(a)-[*2]->(b)

该模式描述了 3 点 2 边组成的图,它们都在一条路径上(长度为 2),等价于:

1
(a)-[]->()-[]->(b)

也可以指定长度范围,这样的边模式称为variable-length edges,例如:

1
(a)-[*3..5]->(b)

*3..5表示最小长度为 3,最大长度为 5。

该模式描述了 4 点 3 边、5 点 4 边或 6 点 5 边组成的图。

也可以忽略最小长度,只指定最大长度,例如:

1
(a)-[*..5]->(b)

必须指定最大长度,不支持仅指定最小长度((a)-[*3..]->(b))或都不指定((a)-[*]->(b))。

路径变量

一系列连接的点和边称为路径。nGQL 允许使用变量来命名路径,例如:

1
p = (a)-[*3..5]->(b)

可以在 MATCH 语句中使用路径变量

注释

支持四种注释方式:#///* */

nGQL 语句中的反斜线(\)代表换行

数据类型

字符串的表示方式为用双引号或单引号包裹,例如"Hello, Cooper"'Hello, Cooper'

日期和时间的类型,包括DATETIMEDATETIMETIMESTAMPDURATION

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
nebula> RETURN DATE({year:-123, month:12, day:3});
+------------------------------------+
| date({year:-(123),month:12,day:3}) |
+------------------------------------+
| -123-12-03 |
+------------------------------------+
nebula> RETURN DATE("23333");
+---------------+
| date("23333") |
+---------------+
| 23333-01-01 |
+---------------+

# 传入当前时间。
nebula> RETURN timestamp();
+-------------+
| timestamp() |
+-------------+
| 1625469277 |
+-------------+

# 传入指定时间。
nebula> RETURN timestamp("2022-01-05T06:18:43");
+----------------------------------+
| timestamp("2022-01-05T06:18:43") |
+----------------------------------+
| 1641363523 |
+----------------------------------+

date()支持的属性名称包括yearmonthdaydate()支持输入YYYYYYYY-MMYYYY-MM-DD,未输入的月份或日期默认为01

time()支持的属性名称包括hourminutesecond

datetime()支持的属性名称包括yearmonthdayhourminutesecond

列表(List)是复合数据类型,一个列表是一组元素的序列,可以通过元素在序列中的位置访问列表中的元素

nGQL 的下标支持从前往后查询,从 0 开始,0 表示第一个元素,1 表示第二个元素,以此类推;也支持从后往前查询,从-1 开始,-1 表示最后一个元素,-2 表示倒数第二个元素,以此类推。

  • [M]:表示下标为 M 的元素。
  • [M..N]:表示M ≤ 下标 < N的元素。N为 0 时,返回为空。
  • [M..]:表示M ≤ 下标的元素。
  • [..N]:表示下标 < N的元素。N为 0 时,返回为空。

可视化

NebulaGraph Studio(简称 Studio)是一款可以通过 Web 访问的开源图数据库可视化工具,搭配 NebulaGraph 内核使用,提供构图、数据导入、编写 nGQL 查询等一站式服务。

前提条件

在部署 RPM 版 Studio 之前,用户需要确认以下信息:

  • NebulaGraph 服务已经部署并启动。详细信息,参考 NebulaGraph 安装部署

  • 使用的 Linux 发行版为 CentOS ,已安装 lsof

  • 确保以下端口未被占用,7001是Studio 提供 web 服务使用的

从官网下载nebula-graph-studio-3.4.1.x86_64.rpm,使用以下命令安装到指定路径

1
sudo rpm -i nebula-graph-studio-3.4.1.x86_64.rpm --prefix=<path> 

安装完,自动会启动,当屏幕返回以下信息时,表示 PRM 版 Studio 已经成功启动。

1
2
3
Start installing NebulaGraph Studio now...
NebulaGraph Studio has been installed.
NebulaGraph Studio started automatically.

启动成功后,在浏览器地址栏输入 http://<ip address>:7001

注意: host处填写为 ip:port格式

用户名和密码:根据 Nebula Graph 的身份验证设置填写登录账号和密码

  • 如果未启用身份验证,可以填写默认用户名 root 和任意密码。
  • 如果已启用身份验证,但是未创建账号信息,用户只能以 GOD 角色登录,必须填写 root 及对应的密码 nebula
  • 如果已启用身份验证,同时又创建了不同的用户并分配了角色,不同角色的用户使用自己的账号和密码登录。

如果在浏览器窗口中能看到以下登录界面,表示已经成功部署并启动 Studio

异常处理

如果在安装过程中自动启动失败或是需要手动启动或停止服务,请使用以下命令:

  • 手动启动服务

    1
    bash /usr/local/nebula-graph-studio/scripts/rpm/start.sh
  • 手动停止服务

    1
    bash /usr/local/nebula-graph-studio/scripts/rpm/stop.sh

如果启动服务时遇到报错报错 ERROR: bind EADDRINUSE 0.0.0.0:7001,用户可以通过以下命令查看端口 7001 是否被占用。

1
lsof -i:7001

如果端口被占用,且无法结束该端口上进程,用户可以通过以下命令修改 Studio 服务启动端口,并重新启动服务。

1
2
3
4
5
6
//修改 studio 服务启动端口
vi etc/studio-api.yam
//修改
Port: 7001 // 修改这个端口号,改成任意一个当前可用的即可
//重启服务
systemctl restart nebula-graph-studio.service

集群监控

NebulaGraph Dashboard(简称Dashboard)是一款用于监控NebulaGraph集群中机器和服务状态的可视化工具

数据导入

Nebula Importer 数据导入实践

Nebula 目前作为较为成熟的产品,已经有着很丰富的生态。数据导入的维度而言就已经提供了多种选择。有大而全的Nebula Exchange,小而精简的Nebula Importer, 还有为 Spark / Flink 引擎提供的Nebula Spark Connector 和 Nebula Flink Connector。

使用场景介绍:

  • Nebula Exchange

    • 需要将来自 Kafka、Pulsar 平台的流式数据, 导入 Nebula Graph 数据库
    • 需要从关系型数据库(如 MySQL)或者分布式文件系统(如 HDFS)中读取批式数据
    • 需要将大批量数据生成 Nebula Graph 能识别的 SST 文件
  • Nebula Importer

    • Importer 适用于将本地 CSV 文件的内容导入至 Nebula Graph 中
  • Nebula Spark Connector:

    • 在不同的 Nebula Graph 集群之间迁移数据
    • 在同一个 Nebula Graph 集群内不同图空间之间迁移数据
    • Nebula Graph 与其他数据源之间迁移数据
    • 结合 Nebula Algorithm 进行图计算
  • Nebula Flink Connector

    • 在不同的 Nebula Graph 集群之间迁移数据
    • 在同一个 Nebula Graph 集群内不同图空间之间迁移数据
    • Nebula Graph 与其他数据源之间迁移数据

总体来说,Exchange 大而全,可以和大部分的存储引擎结合,导入到 Nebula 中,但是需要部署Spark 环境。

Importer 使用简单,所需依赖较少,但需要自己提前生成数据文件,配置好 schema 一劳永逸,但是不支持断点续传,适合数据量中等。

Spark / Flink Connector 需要和流数据结合。

不同的场景选择不同的工具,如果作为新人使用 Nebula 在导入数据时,建议使用 Nebula Importer 工具,简单快速上手。

k8s

k8s官网中文文档

Kubernetes(K8S)教程

Kubernetes Clusters-狂乱的贵公子

简介

Kubernetes (K8S) 是什么

它是一个为 容器化 应用提供集群部署和管理的开源工具,由 Google 开发

Kubernetes 这个名字源于希腊语,意为“舵手”或“飞行员”。k8s 这个缩写是因为 k 和 s 之间有八个字符的关系。 Google 在 2014 年开源了 Kubernetes 项目

主要特性:

  • 高可用,不宕机,自动灾难恢复
  • 灰度更新,不影响业务正常运转
  • 一键回滚到历史版本
  • 方便的伸缩扩展(应用伸缩,机器加减)、提供负载均衡
  • 有一个完善的生态

部署方案

  • 传统部署方式:

应用直接在物理机上部署,机器资源分配不好控制,出现Bug时,可能机器的大部分资源被某个应用占用,导致其他应用无法正常运行,无法做到应用隔离

  • 虚拟机部署

在单个物理机上运行多个虚拟机,每个虚拟机都是完整独立的系统,性能损耗大

  • 容器部署

所有容器共享主机的系统,轻量级的虚拟机,性能损耗小,资源隔离,CPU和内存可按需分配

k8s和虚拟机比较

Kubernetes 可以为你提供集中式的管理集群机器和应用,加机器、版本升级、版本回滚,那都是一个命令就搞定的事,不停机的灰度更新,确保高可用、高性能、高扩展

重要概念 Pod

豆荚,K8S 调度、管理的最小单位,一个 Pod 可以包含一个或多个容器,每个 Pod 有自己的虚拟IP。一个工作节点可以有多个 pod,主节点会考量负载自动调度 pod 到哪个节点运行

pod概念

Kubernetes 组件

Kubernetes 是一个开源的容器编排和管理平台,由多个组件组成。下面是 Kubernetes 的一些核心组件:

  1. kube-apiserver:作为 Kubernetes API 的前端组件,处理来自用户、kubectl 命令行工具以及其他组件的 API 请求,并将其存储在 etcd 中
  2. etcd:是一个高度可用且一致性的分布式键值存储,用于保存 Kubernetes 集群的配置数据、元数据和状态信息
  3. kube-scheduler:负责监视新创建的 Pod,并根据可用的计算资源、硬件和软件要求选择合适的节点进行调度
  4. kube-controller-manager:包含多个控制器,用于管理集群中的各种资源,例如节点控制器、副本控制器、服务控制器等。它负责保持期望状态和实际状态之间的一致性
  5. kubelet:在每个节点上运行的代理组件,负责管理节点上的容器,与容器运行时进行交互,接收来自 kube-apiserver 的指令,并确保容器按照期望状态运行
  6. kube-proxy:负责为 Service 对象提供网络代理和负载均衡功能,将网络流量路由到正确的容器上
  7. Container Runtime:Kubernetes 支持多种容器运行时,如 Docker、containerd、CRI-O 等,用于创建和管理容器
  8. kube-dns/coredns:提供集群内 DNS 服务,用于解析 Kubernetes 集群中的服务名称
  9. Dashboard:提供可视化的 Kubernetes 集群管理界面,用于查看和操作集群中的资源

除了这些核心组件之外,还有其他的辅助组件和插件,如Ingress Controller(用于管理入口流量)、Heapster(用于集群监控和性能分析)、Prometheus(用于指标收集和监控)、Fluentd(用于日志收集和聚合)等,这些组件可以根据具体需求选择安装和配置

k8s集群

安装和部署

占位…