docker 切 containerd

你想逐台将 **Kubernetes 集群从 Docker 切换为 containerd + crictl** 管理容器,并**迁移已有镜像**,这是当前主流做法,兼容未来版本的 Kubernetes(1.24+ 完全移除 dockershim)。
下面是一步步 **安全、兼容、可操作的完整替换方案**,附带镜像导入方式。

---

## ✅ 总体思路(生产环境推荐顺序)

1. ✅ 安装 containerd 和 crictl
2. ✅ 配置 containerd + systemd 服务
3. ✅ 配置 crictl 与 containerd 对接
4. ✅ 导出 Docker 镜像,导入到 containerd
5. ✅ 替换 kubelet 使用 containerd 的 CRI socket
6. ✅ 验证 kubelet、Pod 运行正常后,卸载 Docker(可选)

---

## 🧱 步骤详解

### ✅ Step 1:安装 containerd(所有节点执行)

```bash
# 如果你用的是 yum 系统(CentOS / RHEL)
yum install -y containerd

# 或使用官方版本
containerd_version="1.7.13"
wget https://github.com/containerd/containerd/releases/download/v${containerd_version}/containerd-${containerd_version}-linux-amd64.tar.gz
tar -xvf containerd-${containerd_version}-linux-amd64.tar.gz
cp bin/* /usr/bin/
```

---

### ✅ Step 2:配置 containerd 并启动

```bash
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml
```

修改 `/etc/containerd/config.toml` 中:

```toml
[plugins."io.containerd.grpc.v1.cri"]
  sandbox_image = "registry.k8s.io/pause:3.6"
```

然后启动服务:

```bash
systemctl daemon-reexec
systemctl enable --now containerd
```

---

### ✅ Step 3:安装 `crictl` 并配置使用 containerd

```bash
# 下载 crictl
version="v1.28.0"
curl -LO https://github.com/kubernetes-sigs/cri-tools/releases/download/${version}/crictl-${version}-linux-amd64.tar.gz
tar -xvf crictl-${version}-linux-amd64.tar.gz -C /usr/local/bin

# 配置 crictl 连接 containerd
cat <<EOF > /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
EOF
```

验证:

```bash
crictl info
```

---

### ✅ Step 4:迁移镜像(从 Docker → containerd)

```bash
# 1. 导出 Docker 镜像为 tar 包
docker save nginx:1.23 -o nginx.tar

# 2. 使用 ctr 或 nerdctl 导入
ctr -n k8s.io images import nginx.tar

# 或者更像 Docker 的方式
# nerdctl load -i nginx.tar
```

验证镜像是否成功导入:

```bash
crictl images | grep nginx
```

---

### ✅ Step 5:配置 kubelet 使用 containerd

编辑 `/var/lib/kubelet/kubeadm-flags.env` 或 systemd 配置中 `kubelet` 启动参数:

```bash
--container-runtime=remote \
--container-runtime-endpoint=unix:///run/containerd/containerd.sock
```

重启 kubelet:

```bash
systemctl daemon-reexec
systemctl restart kubelet
```

---

### ✅ Step 6:验证集群正常运行

```bash
kubectl get nodes
kubectl get pods -A
```

验证 Pod 的容器是否由 containerd 启动:

```bash
crictl ps
```

---

## ✅ 可选 Step 7:卸载 Docker(替换完成后)

```bash
systemctl disable --now docker
yum remove docker-ce docker-ce-cli containerd.io
rm -rf /var/lib/docker
```

---

## 🔄 一台台替换注意事项(生产级)

* ❗ **不要同时使用 Docker 和 containerd 运行 kubelet**(会冲突);
* ✅ 先在 1\~2 个节点测试替换流程;
* ✅ `crictl` 替代 `docker ps` / `docker exec` 等;
* ✅ kubeadm 集群无需重新初始化,仅 kubelet 切 socket 即可;
* ✅ 镜像迁移使用 `docker save` + `ctr import` 最稳妥;

---

## 🛠 工具对照表

| 功能     | Docker 命令         | containerd + crictl |
| ------ | ----------------- | ------------------- |
| 查看容器列表 | `docker ps`       | `crictl ps`         |
| 查看镜像   | `docker images`   | `crictl images`     |
| 进入容器   | `docker exec -it` | `crictl exec -it`   |
| 拉取镜像   | `docker pull`     | `crictl pull`       |
| 删除容器   | `docker rm`       | `crictl rm`         |
| 删除镜像   | `docker rmi`      | `crictl rmi`        |

---

## 📦 Bonus:一键迁移脚本(示意)

```bash
#!/bin/bash
set -e

# 导出镜像
docker images --format '{{.Repository}}:{{.Tag}}' | while read img; do
  fname=$(echo $img | tr '/:' '_').tar
  docker save $img -o /tmp/$fname
  ctr -n k8s.io images import /tmp/$fname
done
```

---

如果你提供你当前的系统版本、kubeadm 版本,我可以为你**生成专用的一键替换脚本**,是否需要?
正确答案是:

> ❌ **`crictl` 无法导入镜像**
> ✅ **导入镜像应使用 `ctr` 或 `nerdctl`(containerd 原生工具)**

---

## 🔍 为什么 `crictl` 不能导入镜像?

`crictl` 是 **Kubernetes 的 CRI(Container Runtime Interface)客户端**,它基于 GRPC 与 containerd 交互,用于**管理容器和镜像元数据**,但它本身不处理镜像文件导入或构建。

> 它是控制而不是构建或传输工具。

---

## ✅ 正确的镜像导入方式(containerd):

### 方法 1:使用 `ctr`(containerd 官方工具)

```bash
# 导出 Docker 镜像
docker save nginx:1.21 -o nginx.tar

# 导入到 containerd(k8s.io namespace 是 Kubelet 使用的默认)
ctr -n k8s.io images import nginx.tar

# 查看是否导入成功
crictl images | grep nginx
```

---

### 方法 2:使用 `nerdctl`(推荐,兼容 docker 命令)

```bash
nerdctl load -i nginx.tar
nerdctl images
```

> `nerdctl` 是 containerd 的 CLI 替代 `docker`,可以用 `docker-compose`,支持 build / push / load 等。

---

## 💡 crictl 的作用总结

| 能力            | 是否支持  | 工具                     |
| ------------- | ----- | ---------------------- |
| 容器管理(ps、exec) | ✅ 支持  | `crictl`               |
| 镜像查看/拉取       | ✅ 支持  | `crictl images/pull`   |
| 镜像导入 `.tar`   | ❌ 不支持 | `ctr` / `nerdctl`      |
| 镜像构建(build)   | ❌ 不支持 | `nerdctl` / `buildkit` |
| 用于 Kubernetes | ✅ 支持  | `crictl`               |

---

## ✅ 结论(你应该这样做)

* 如果你有 `.tar` 镜像文件(如从 Docker 导出),想导入给 containerd/k8s 使用:

  * ✅ 用:`ctr -n k8s.io images import`
  * 或 ✅ 用:`nerdctl load -i xxx.tar`
* **不要尝试用 `crictl` 载入镜像,它不支持。**

---

如你希望我给你一个自动从 Docker 导出并批量导入 containerd 的脚本,我可以帮你写。是否需要?
要列出 `containerd` 中的所有 **namespaces**,你可以使用 `ctr` 命令如下:

---

### ✅ 命令:

```bash
ctr namespaces list
```

---

### ✅ 示例输出:

```text
NAME        LABELS
default     -
k8s.io      -
myns        -
```

---

### ✅ 各命名空间含义说明:

| Namespace | 说明                                               |
| --------- | ------------------------------------------------ |
| `default` | containerd 默认使用的 namespace(非 Kubernetes)         |
| `k8s.io`  | **Kubelet 默认使用的 namespace**,Kubernetes 中所有容器都在这里 |
| `myns`    | 你自己运行的其他容器(例如通过 `ctr -n myns` 启动的)               |

---

### ✅ 你可以切换 namespace 执行操作:

```bash
# 查看 k8s 所在 namespace 的容器镜像
ctr -n k8s.io images list

# 查看 default namespace 的镜像
ctr -n default images list
```

---

如你需要查看某个 namespace 中的容器:

```bash
ctr -n k8s.io containers list
```

---

如你想在默认之外运行容器(建议明确指定 `-n`):

```bash
ctr -n myns run -d docker.io/library/nginx:latest mynginx
```

---

需要我给你写一个脚本自动遍历所有 namespace 并列出每个镜像吗?


这是个非常好的问题。我们来详细解释你看到的这两个 namespace —— `k8s.io` 和 `moby` —— 的区别,以及 containerd / crictl 对 namespace 的处理。

---

## 🔍 你看到的两个 namespace:

```
# ctr namespaces list
NAME     LABELS
k8s.io   -
moby     -
```

| Namespace | 来源/含义                                                      |
| --------- | ---------------------------------------------------------- |
| `k8s.io`  | **Kubernetes 的默认 namespace**,`kubelet` 使用 containerd 时指定的  |
| `moby`    | Docker 使用 containerd 时创建的 namespace("moby" 是 Docker 的项目代号) |

---

## 🤔 为什么会有 `moby`?

Docker 自 18.09 起,默认使用 containerd 作为内部 runtime,但它仍通过 Docker Engine(dockerd)管理容器。Docker 使用 containerd 时会将所有内容放在 namespace `moby` 中。

### 所以:

* 如果你 **安装过 Docker**,并且其后台默认使用 containerd,那么 containerd 中就会有 `moby` 命名空间;
* 即使你后来停止了 Docker,`moby` namespace 也会保留原来管理过的容器、镜像记录;
* 所以 `ctr -n moby images ls` 能看到 Docker 存过的镜像。

---

## ✅ containerd 工具的 namespace 支持

| 工具        | 是否支持命名空间            | 如何指定 namespace                                     |
| --------- | ------------------- | -------------------------------------------------- |
| `ctr`     | ✅ 支持                | `ctr -n <namespace>`,默认是 `default`                 |
| `crictl`  | ❌ 不支持手动指定 namespace | 固定使用 `k8s.io`,不可更改                                 |
| `nerdctl` | ✅ 支持(间接)            | 通过 `--namespace` 参数,如 `nerdctl --namespace=k8s.io` |

### 示例:

```bash
# 查看 Kubernetes 使用的镜像
ctr -n k8s.io images list

# 查看 Docker 使用 containerd 时存储的镜像
ctr -n moby images list

# 使用 nerdctl 查看指定 namespace
nerdctl --namespace=k8s.io images
```

---

## ✅ Kubernetes 强制使用 `k8s.io` namespace

在 `containerd` 的配置 `/etc/containerd/config.toml` 中,你会看到如下字段(Kubernetes 使用时必须设置):

```toml
[plugins."io.containerd.grpc.v1.cri"]
  sandbox_image = "registry.k8s.io/pause:3.6"
  ...
```

Kubelet 启动时使用参数:

```bash
--container-runtime-endpoint=unix:///run/containerd/containerd.sock
```

此时默认会访问 containerd 的 `k8s.io` namespace,因此:

> crictl 始终操作的是 `k8s.io` 命名空间,**不支持切换**。

---

## ✅ 总结

| 工具        | 默认 namespace | 是否可切换 namespace    | 典型用途             |
| --------- | ------------ | ------------------ | ---------------- |
| `ctr`     | default      | ✅ 支持               | 调试 containerd 内部 |
| `crictl`  | `k8s.io`     | ❌ 不支持              | Kubelet 专属 CLI   |
| `nerdctl` | `default`    | ✅ `--namespace` 支持 | Docker 替代品       |
| `docker`  | `moby`(内部)   | ❌ 不适配 CRI          | 非标准 runtime 已淘汰  |

---

如果你希望统一所有容器资源到 `k8s.io` namespace,也可以将 Docker 的镜像导入进去:

```bash
ctr -n moby images export all-docker.tar $(ctr -n moby images ls -q)
ctr -n k8s.io images import all-docker.tar
```

是否需要我为你写一个“跨 namespace 镜像同步”的自动脚本?

  

 

`/etc/crictl.yaml` 是 `crictl` 工具的配置文件。`crictl` 是一个用于与容器运行时(如 containerd 或 CRI-O)交互的命令行工具。它支持管理容器、镜像、网络和卷等资源。`crictl.yaml` 文件允许用户自定义与容器运行时的交互配置,如容器运行时的 API 地址、调试级别等。

### `/etc/crictl.yaml` 配置文件结构

`crictl.yaml` 文件通常包括以下几部分内容:

* **runtime-endpoint**:指定容器运行时的 API 地址。通常是 `containerd` 或 `cri-o` 的 gRPC 服务地址。
* **image-endpoint**:指定镜像服务的 gRPC 地址。
* **timeout**:容器操作的超时时间。
* **debug**:开启或关闭调试模式。

### 配置示例

```yaml
# CRI runtime endpoint
runtime-endpoint: unix:///var/run/containerd/containerd.sock
# Image service endpoint
image-endpoint: unix:///var/run/containerd/containerd.sock
# Timeout for containerd client operations
timeout: 10s
# Enable debugging mode
debug: true
```

### 配置项详解

1. **runtime-endpoint**

   * **类型**:字符串(URL)
   * **说明**:指定容器运行时(如 `containerd` 或 `cri-o`)的 API 地址。通常使用 Unix 套接字(如 `/var/run/containerd/containerd.sock`)或 TCP 地址(如 `tcp://localhost:1234`)。

   示例:

   * `unix:///var/run/containerd/containerd.sock`:指向 containerd 的 Unix 套接字。
   * `tcp://localhost:1234`:指向一个 TCP 地址,通常在 Kubernetes 集群中的远程节点上。

2. **image-endpoint**

   * **类型**:字符串(URL)
   * **说明**:指定镜像服务的 API 地址。通常与 `runtime-endpoint` 地址相同。用于管理容器镜像的操作(拉取、推送、列出等)。

3. **timeout**

   * **类型**:字符串(时间格式)
   * **说明**:指定与容器运行时通信时的超时时间。默认值为 `10s`,表示 10 秒。

4. **debug**

   * **类型**:布尔值
   * **说明**:开启或关闭调试模式。如果设置为 `true`,则在运行时会输出更多调试信息,通常用于故障排查。

### 配置文件示例:适用于 `containerd` 和 `cri-o`

1. **适用于 `containerd` 的配置:**

```yaml
runtime-endpoint: unix:///var/run/containerd/containerd.sock
image-endpoint: unix:///var/run/containerd/containerd.sock
timeout: 15s
debug: false
```

2. **适用于 `cri-o` 的配置:**

```yaml
runtime-endpoint: unix:///var/run/crio/crio.sock
image-endpoint: unix:///var/run/crio/crio.sock
timeout: 20s
debug: true
```

### 使用 `crictl` 工具时检查配置

`crictl` 工具会根据 `/etc/crictl.yaml` 配置文件中的设置与容器运行时(如 `containerd` 或 `cri-o`)进行通信。确保在配置文件中设置正确的运行时和镜像端点,以便 `crictl` 能够正常与容器运行时交互。

```bash
# 验证容器运行时状态
crictl info
```

### 常见问题排查

1. **容器运行时 API 地址错误**:如果 `runtime-endpoint` 配置不正确,`crictl` 会无法连接到容器运行时,常见错误信息如“连接失败”。

2. **镜像拉取失败**:如果 `image-endpoint` 配置有误,`crictl` 在尝试拉取镜像时会失败,检查镜像端点是否正确。

3. **超时问题**:如果容器运行时响应较慢,尝试增加 `timeout` 配置项的值,尤其是在高负载或远程节点上运行时。

### 小结

* `/etc/crictl.yaml` 是 `crictl` 配置文件,用于配置与容器运行时(如 `containerd` 或 `cri-o`)的连接信息。
* 关键配置项包括 `runtime-endpoint`、`image-endpoint`、`timeout` 和 `debug`。
* 确保配置文件中的 API 地址与运行时的实际地址一致,以便 `crictl` 能够正常工作。

如果你有多个容器运行时,确保每个运行时的配置都正确,并通过 `crictl` 验证连接和操作是否正常。

 

在 `containerd` 中,裸容器(bare container)通常指的是没有依赖于 Kubernetes 等容器编排工具的容器实例。它们是直接通过 `containerd` 管理的容器。`containerd` 提供了一个轻量级的容器管理功能,能够启动、停止、调度和管理容器,主要用于支持容器化的应用和服务。

### containerd 管理裸容器的基本步骤

#### 1. 安装 `containerd`

首先,需要确保已安装 `containerd`。在多数 Linux 发行版上,你可以通过以下命令安装:

```bash
# 对于基于 Debian 或 Ubuntu 的系统
sudo apt-get install containerd

# 对于基于 RHEL 或 CentOS 的系统
sudo yum install containerd
```

安装完成后,可以通过 `systemctl` 启动并启用 `containerd` 服务:

```bash
# 启动 containerd
sudo systemctl start containerd

# 设置 containerd 在开机时自动启动
sudo systemctl enable containerd
```

#### 2. 配置 `containerd`

`containerd` 的配置文件通常位于 `/etc/containerd/config.toml`。你可以通过编辑此配置文件来进行定制设置(如存储路径、日志配置、网络插件等)。

```bash
# 编辑配置文件
sudo nano /etc/containerd/config.toml
```

例如,配置存储路径,镜像存储等内容,之后保存文件并重启 `containerd`:

```bash
# 重启 containerd 服务
sudo systemctl restart containerd
```

#### 3. 启动和管理裸容器

容器的生命周期管理可以使用 `ctr`,`containerd` 附带的命令行工具。`ctr` 提供了一个轻量级的接口来直接管理容器和镜像。

##### a. 拉取镜像

首先需要从镜像仓库拉取镜像。`containerd` 可以使用 Docker 镜像仓库,也可以配置使用私有仓库。

```bash
# 拉取 Docker Hub 上的镜像
sudo ctr images pull docker.io/library/alpine:latest
```

##### b. 创建和启动裸容器

使用 `ctr` 工具启动裸容器。创建容器时需要指定镜像和容器配置。以下是一个基本的创建容器的命令:

```bash
# 创建并启动一个容器
sudo ctr container create \
  --name my_container \
  --runtime io.containerd.runc.v1 \
  docker.io/library/alpine:latest \
  /bin/sh
```

* `--name` 指定容器的名称。
* `--runtime` 指定容器使用的运行时,默认使用 `runc`。
* `docker.io/library/alpine:latest` 是镜像的完整名称。
* `/bin/sh` 是容器启动时执行的命令。

##### c. 启动容器

通过 `ctr` 启动已创建的容器:

```bash
# 启动容器
sudo ctr task start my_container
```

此时,容器将启动并运行。

##### d. 进入容器

如果你希望进入容器并进行交互,可以使用 `ctr` 提供的附加功能:

```bash
# 进入容器并获得 shell
sudo ctr task exec --stdin --tty my_container /bin/sh
```

##### e. 停止容器

当容器运行完成后,可以使用以下命令停止容器:

```bash
# 停止容器
sudo ctr task kill my_container
```

##### f. 删除容器

删除容器时,可以通过以下命令删除已停止的容器:

```bash
# 删除容器
sudo ctr container delete my_container
```

### 4. 使用 containerd 监控容器状态

你可以使用 `ctr` 查询当前运行的容器和任务(即容器的进程)。例如,查看容器状态:

```bash
# 查看所有正在运行的容器
sudo ctr task list

# 查看所有镜像
sudo ctr images list
```

### 5. 进一步配置和优化裸容器

裸容器的使用非常简单,但在生产环境中可能需要进行更细致的配置和优化,以下是一些常见的配置项:

* **日志管理**:可以配置容器的日志输出,确保容器的输出被正确捕获。
* **资源限制**:可以配置 CPU、内存、网络等资源限制,确保容器不会过度占用主机资源。
* **网络配置**:如果容器需要访问外部网络,确保配置正确的网络插件(例如 CNI)。

### 总结

通过 `containerd` 管理裸容器主要包括以下几个步骤:

1. 安装和配置 `containerd`。
2. 使用 `ctr` 工具拉取镜像、创建容器、启动容器、进入容器、停止容器。
3. 使用 `ctr` 查看容器和镜像的状态。

`containerd` 作为一个容器运行时,提供了非常灵活的工具来管理裸容器。如果你不依赖 Kubernetes 等编排工具,`containerd` 提供的直接控制和高效性是非常合适的选择。

  

### 检查 `containerd` 配置文件是否正确

`containerd` 使用的配置文件通常是 `/etc/containerd/config.toml`,用于配置诸如镜像拉取、运行时选项、存储驱动等。为了确保 `containerd` 配置文件正确且有效,可以通过以下几种方法进行检查:

### 1. **检查配置文件的语法是否正确**

`containerd` 配置文件是 TOML 格式,您可以通过检查文件的语法是否符合 TOML 格式,来确认配置文件没有明显的语法错误。如果配置文件存在语法错误,`containerd` 启动时会输出相关错误。

```bash
# 查看 containerd 启动日志,检查是否有配置相关的错误信息
journalctl -u containerd -f
```

如果日志中有关于 `config.toml` 文件的错误,通常会显示某些字段无效或语法错误的详细信息。

### 2. **检查配置文件的有效性**

您可以手动检查配置文件中的关键部分,确认各个配置项是否按照需要设置。例如:

* **私有仓库配置**:

  ```toml
  [plugins."io.containerd.grpc.v1.cri".registry]
    [plugins."io.containerd.grpc.v1.cri".registry.mirrors]
      [plugins."io.containerd.grpc.v1.cri".registry.mirrors."myprivateregistry.com"]
        endpoint = ["https://myprivateregistry.com"]
  ```

* **认证信息**:

  ```toml
  [plugins."io.containerd.grpc.v1.cri".registry.configs."myprivateregistry.com".auth]
    username = "my-username"
    password = "my-password"
  ```

* **存储驱动配置**:

  ```toml
  [plugins."io.containerd.snapshotter.v1.overlayfs"]
    root_path = "/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs"
  ```

* **运行时配置**:

  ```toml
  [plugins."io.containerd.grpc.v1.cri".containerd]
    snapshotter = "overlayfs"
    runtime = "io.containerd.runc.v1"
  ```

确保各个配置项的值符合您的需求,并且没有遗漏或错误的配置。

### 3. **使用 `containerd` 命令行工具检查**

`containerd` 提供了多种命令行工具来检查当前的配置及其状态。

* **检查 `containerd` 的版本:**

  ```bash
  containerd --version
  ```

* **查看正在运行的容器任务:**

  ```bash
  ctr task list
  ```

  该命令列出当前所有容器任务。您可以通过这个命令检查是否正在运行您的容器。

* **检查当前镜像:**

  ```bash
  ctr image list
  ```

  该命令会列出当前加载的所有镜像,您可以检查是否有来自私有仓库的镜像。

* **拉取镜像:**

  ```bash
  ctr image pull myprivateregistry.com/my-image:latest
  ```

  如果您配置了私有仓库,尝试拉取一个镜像,检查是否能成功拉取。如果拉取失败,查看日志中的详细错误信息。

### 4. **使用 `systemctl` 检查 `containerd` 服务状态**

您可以通过 `systemctl` 查看 `containerd` 服务的状态,以确保服务正常运行。

```bash
sudo systemctl status containerd
```

如果服务没有启动,或者有异常,使用以下命令重新启动:

```bash
sudo systemctl restart containerd
```

### 5. **查看 `containerd` 的日志**

`containerd` 启动时会输出日志,您可以查看其日志文件,以便找到可能存在的配置错误。

```bash
journalctl -u containerd -f
```

如果配置文件中的某些部分存在问题,`containerd` 会在启动时输出错误日志,帮助您定位问题所在。

---

### `citr` 配置文件作用

`citr` 是 `containerd` 的一个重要部分,用于配置和管理容器镜像仓库。`citr` 不是 `containerd` 的默认配置文件,而是一个类似于镜像的元数据存储工具。其作用如下:

* **管理镜像元数据**:`citr` 用于管理与容器镜像相关的元数据和其他配置信息。
* **镜像配置**:它可以帮助在镜像拉取、推送、存储等操作时管理镜像的元数据、认证信息等。

不过,`citr` 并不是所有 `containerd` 安装中都需要的文件,它通常是作为容器镜像存储和拉取的一部分出现,主要应用于一些特殊场景或工具集成。

### 总结

1. **检查 `containerd` 配置文件是否正确**:可以通过查看日志、检查配置项是否存在错误,或者使用命令行工具验证配置是否生效。
2. **`citr` 配置文件**:`citr` 主要用于镜像的元数据存储,它并非 `containerd` 的标准配置文件。如果您使用 `containerd` 进行容器管理,`citr` 主要用于与容器镜像相关的配置,但并不是必需的配置项。

  

 

posted on 2025-05-16 21:17  吃草的青蛙  阅读(127)  评论(0)    收藏  举报

导航