DevOps 项目阶段笔记二:Docker Engine + cri-dockerd


DevOps 项目阶段笔记二:Docker Engine + cri-dockerd

项目Gitee地址

1. 本阶段目标

上一阶段已经完成 VM 基础初始化、SSH 免密、Ansible Inventory、静态 IP、Kubernetes 节点 swap/内核参数等配置。

本阶段从 Docker 开始,原计划完成:

复制代码
Ansible 自动安装 Docker Engine
        ↓
配置 Docker systemd cgroup driver
        ↓
在 Kubernetes 节点安装 cri-dockerd
        ↓
验证 Docker
        ↓
验证 cri-dockerd
        ↓
为后续 Kubernetes 安装准备 CRI


Kubernetes (K8s)
    │
    ├── 需要容器运行时(Container Runtime)来运行 Pod 里的容器
    │
    └── CRI(Container Runtime Interface)
            │  ← Kubernetes 定义的统一接口标准
            │
     ┌──────┴──────┐
     │             │
  containerd     cri-dockerd
     │             │
     │             └── 调用 Docker Engine(dockerd)
     │                         │
     │                         └── 最终管理容器
     │
  (直接通过 CRI 与 K8s 通信,效率更高)

一句话总结:

  • Docker = 底层引擎,会干活但不讲 K8s 的语言
  • CRI = K8s 规定的通用语言标准
  • cri-dockerd = 翻译官,把 K8s 的指令转成 Docker 能听懂的命令

所以你的流程本质上是:装了个只会说英语的人(Docker),再给他配个翻译(cri-dockerd),让他能跟只说中文的老板(K8s)沟通。

节点规划:

IP 主机名 角色
192.168.205.141 k8s-master Master
192.168.205.142 k8s-node1 Worker
192.168.205.143 k8s-node2 Worker
192.168.205.144 devops DevOps 工具
192.168.205.145 elk ELK 日志

Docker 计划安装到: k8s-master, k8s-node1, k8s-node2, devops

cri-dockerd 只安装到: k8s-master, k8s-node1, k8s-node2

ELK 节点本阶段不安装 Docker。


2. 本阶段架构设计

Kubernetes 不直接使用 Docker Engine 作为 CRI,因此本项目采用:

复制代码
kubelet
    ↓
cri-dockerd
    ↓
Docker Engine

后续 kubeadm 初始化时计划使用:

复制代码
unix:///run/cri-dockerd.sock

Docker cgroup driver 统一计划配置为:

复制代码
systemd

后续 kubelet 也将保持:

复制代码
systemd

目标是保证:

复制代码
Docker cgroup driver  = systemd
kubelet cgroup driver = systemd

3. 本阶段新增文件

Ansible 项目目录新增:

复制代码
~/devops-lab/ansible/
├── ansible.cfg
├── init.yml
├── network.yml
├── docker.yml          ← 新增
├── inventory/
│   └── hosts.ini
└── scripts/
    ├── init.sh
    ├── docker-install.sh          ← 新增
    └── cri-dockerd-install.sh     ← 新增

本阶段主要文件:

  • docker.yml
  • scripts/docker-install.sh
  • scripts/cri-dockerd-install.sh

4. Docker 安装方案

4.1 docker-install.sh

Docker 安装通过 scripts/docker-install.sh 统一执行。

脚本主要工作:

复制代码
检查 Ubuntu 系统
    ↓
处理可能冲突的软件包
    ↓
安装 ca-certificates / curl / gnupg
    ↓
配置 Docker APT repository

5. Docker daemon 配置

Docker 配置文件:/etc/docker/daemon.json

使用的核心配置:

json 复制代码
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  },
  "storage-driver": "overlay2"
}

其中最重要的是:

json 复制代码
"exec-opts": ["native.cgroupdriver=systemd"]

用途: 将 Docker cgroup driver 设置为 systemd,与 kubelet 保持一致。

另外 Docker 日志采用 json-file,并限制单个日志文件 max-size=100mmax-file=3,避免实验环境中容器日志无限增长。


6. cri-dockerd 安装方案

使用版本: cri-dockerd 0.4.4

下载文件: cri-dockerd-0.4.4.amd64.tgz

下载地址:

复制代码
https://github.com/Mirantis/cri-dockerd/releases/download/v0.4.4/cri-dockerd-0.4.4.amd64.tgz

SHA256:

复制代码
109b7540053a507dd85ad7b9fee9cee9caae55feedcc28365d3e7ab4fb2172d5

安装后的二进制路径: /usr/local/bin/cri-dockerd

计划生成 systemd 单元:

  • /etc/systemd/system/cri-docker.service
  • /etc/systemd/system/cri-docker.socket

最终 CRI Socket: /run/cri-dockerd.sock

Kubernetes 后续使用: unix:///run/cri-dockerd.sock


7. Ansible Playbook 设计

docker.yml 分成两个 Play。

Play 1: Docker

目标组: hosts: "k8s_nodes:devops_servers"

也就是:k8s-master, k8s-node1, k8s-node2, devops

主要任务:

  1. 运行 docker-install.sh
  2. 加入 docker group
  3. 检查 docker.service
  4. 检查 Docker cgroup driver
  5. 输出状态

由于当前使用 Ansible 2.9.6,script 模块继续使用 free-form 写法:

yaml 复制代码
script: "./scripts/docker-install.sh"

没有使用较新版本的:

yaml 复制代码
script:
  cmd: ...

Play 2: cri-dockerd

目标组: hosts: k8s_nodes

即:k8s-master, k8s-node1, k8s-node2

主要任务:

  1. 运行 cri-dockerd-install.sh
  2. 检查 cri-docker.service
  3. 检查 cri-docker.socket
  4. 检查 /run/cri-dockerd.sock
  5. 输出 CRI 状态

8. 问题一:docker.yml YAML 语法错误

问题现象

第一次运行:

bash 复制代码
ansible-playbook \
  -i inventory/hosts.ini \
  docker.yml \
  --syntax-check

报错:

复制代码
ERROR! Syntax Error while loading YAML.
mapping values are not allowed in this context

定位:docker.yml: line 25, column 47

问题行:

yaml 复制代码
-name: Check Docker cgroup driver
shell: docker info 2>/dev/null| awk -F':' '/Cgroup Driver/{print$2}'

错误位置:-F': 后面的 : 被 YAML 误解。

原因

Shell 命令本身没有问题,问题来自 YAML 解析。命令中 : 即冒号后面跟空格,YAML 会尝试将它解释成 key: value,因此一整行没有被正确识别为普通 shell 字符串。

修复

改用 YAML folded scalar:

yaml 复制代码
- name: Check Docker cgroup driver
  shell: >
    docker info 2>/dev/null | awk -F':' '/Cgroup Driver/{print$2}'
  register: docker_cgroup
  changed_when: false
  failed_when: docker_cgroup.stdout != "systemd"

之后继续执行 Playbook。

实践经验

复杂 Shell 命令中如果包含 : . " ${} 等符号,在 Ansible YAML 中最好避免直接写成长单行。优先使用 shell: >shell: | 的多行写法。简单命令仍然可以写成单行,如:

yaml 复制代码
shell: systemctl is-active docker

9. 问题二:Install cri-dockerd 阶段疑似卡住

问题现象

执行 docker.yml 时出现:

复制代码
TASK [Install cri-dockerd]
changed: [k8s-node1]
changed: [k8s-node2]

之后长时间没有新的输出。

此时可以确认:

  • k8s-node1 cri-dockerd task 已返回 changed ✓
  • k8s-node2 cri-dockerd task 已返回 changed ✓
  • k8s-master 尚未正常返回

最初怀疑:master 下载 GitHub release 太慢。


10. 对 master 的第一次排查

登录 k8s-master,检查:

bash 复制代码
ps -ef | grep -E 'curl|cri-dockerd|systemctl' | grep -v grep

结果:无输出

说明当时 master 上不存在明显的 curl、cri-dockerd、systemctl 安装进程。

进一步执行:

bash 复制代码
ps -ef | grep -E 'docker-install|cri-dockerd-install|ansible|python|bash|sh|apt|dpkg|tar|gpg' | grep -v grep

没有发现正在执行的 cri-dockerd-install.sh、curl、tar、sha256sum、apt、dpkg。

但发现 SSH/SFTP 相关进程,例如:

复制代码
sshd: master@notty
/usr/lib/openssh/sftp-server

11. 确认 master 实际没有安装成功

在 master 上检查:

bash 复制代码
/usr/local/bin/cri-dockerd --version

结果:

复制代码
-bash: /usr/local/bin/cri-dockerd: No such file or directory

检查服务:

bash 复制代码
sudo systemctl is-active cri-docker.service

结果:inactive

检查 socket:

bash 复制代码
sudo systemctl is-active cri-docker.socket

结果:inactive

检查 Unix Socket:

bash 复制代码
ls -l /run/cri-dockerd.sock

结果:

复制代码
ls: cannot access '/run/cri-dockerd.sock': No such file or directory

由此确认: k8s-master 的 cri-dockerd 当时实际上没有安装成功,而不是"已经安装成功,只是 Ansible 没返回"。


12. 排查 GitHub 下载是否存在问题

由于安装脚本需要从 GitHub 下载 cri-dockerd-0.4.4.amd64.tgz,因此在 master 上进行独立下载测试。

进入 /tmp,执行:

bash 复制代码
curl -fL \
  "https://github.com/Mirantis/cri-dockerd/releases/download/v0.4.4/cri-dockerd-0.4.4.amd64.tgz" \
  -o cri-dockerd-test.tgz

实际结果:

复制代码
100  15.5M  100  15.5M

下载大约数秒完成。

说明:

  • GitHub 可访问 ✓
  • DNS 正常 ✓
  • Release URL 正常 ✓
  • 下载速度正常 ✓

因此排除了"master 因 GitHub 下载过慢导致卡死"这一判断。


13. 校验下载文件

执行:

bash 复制代码
sha256sum /tmp/cri-dockerd-test.tgz

实际输出:

复制代码
109b7540053a507dd85ad7b9fee9cee9caae55feedcc28365d3e7ab4fb2172d5  /tmp/cri-dockerd-test.tgz

与脚本预期 SHA256 完全一致:

复制代码
109b7540053a507dd85ad7b9fee9cee9caae55feedcc28365d3e7ab4fb2172d5

因此进一步排除:

  • 下载文件损坏 ✗
  • 版本 URL 错误 ✗
  • checksum 错误 ✗

14. 对下载命令进行健壮性优化

最初脚本中的下载命令:

bash 复制代码
curl -fL \
  "${DOWNLOAD_URL}" \
  -o cri-dockerd.tgz

为了避免未来网络异常时长时间无响应,修改为:

bash 复制代码
curl -fL \
  --connect-timeout 10 \
  --max-time 300 \
  --retry 3 \
  --retry-delay 5 \
  "${DOWNLOAD_URL}" \
  -o cri-dockerd.tgz

含义:

参数 含义
--connect-timeout 10 连接建立最多等待 10 秒
--max-time 300 整个 curl 最多运行 300 秒
--retry 3 失败后最多重试 3 次
--retry-delay 5 两次重试之间等待 5 秒

这不是本次故障的最终原因,但提高了脚本在自动化环境中的可靠性。


15. 只针对 master 重新执行 cri-dockerd 安装

没有重新执行整个 Docker 阶段。而是在 Ansible Control Node devops 上单独运行:

bash 复制代码
ansible k8s-master \
  -i inventory/hosts.ini \
  -b \
  -m script \
  -a './scripts/cri-dockerd-install.sh' \
  -vv

结果:

复制代码
k8s-master | CHANGED

返回码:rc: 0

说明脚本成功执行。


16. master 最终安装输出

此次执行确认:

复制代码
=== cri-dockerd installation ===
Host: k8s-master
Version: 0.4.4

Docker 检查:
[INFO] Docker is running

下载成功:
100  15.5M  100  15.5M

SHA256:
cri-dockerd.tgz: OK
[OK] SHA256 verification passed

systemd unit 启用:
Created symlink /etc/systemd/system/multi-user.target.wants/cri-docker.service
Created symlink /etc/systemd/system/sockets.target.wants/cri-docker.socket

cri-dockerd 版本:
cri-dockerd 0.4.4 (98c4823)

Socket:
srw-rw--- 1 root docker ... /run/cri-dockerd.sock

最终输出:
[OK] cri-dockerd installation completed.

17. 关于 SSH stderr

Ansible 返回中出现:

复制代码
Shared connection to 192.168.205.141 closed.

它位于 stderr,但本次 rc: 0,并且任务状态 CHANGED,cri-dockerd 的版本、socket、systemd 启用过程也全部完成。因此这条信息本身不代表安装失败,而是 SSH 复用连接关闭时产生的信息。


18. 本次"卡住"的最终结论

可以明确排除:

  • GitHub 下载速度慢 ✗
  • DNS 故障 ✗
  • Release URL 错误 ✗
  • 下载文件损坏 ✗
  • SHA256 错误 ✗
  • cri-dockerd 0.4.4 包本身无法下载 ✗

因为 master 手动下载 15.5 MB 几秒即可完成,并且 SHA256 完全匹配。

之后使用相同 Ansible script 模块单独针对 master 重试,成功完成。

结合故障时看到的 sshd: master@notty/usr/lib/openssh/sftp-server,以及安装脚本本身没有继续运行的现象,怀疑第一次执行时 Ansible/SSH/SFTP 会话出现了临时异常。

但是: 该根因没有通过进一步日志或复现得到最终确认。因此工程笔记中不把它写成确定原因。

正确记录应是:

项目 内容
故障现象 首次通过 docker.yml 执行时,master 的 cri-dockerd task 未正常结束
已排除 GitHub/DNS/下载速度/下载文件/SHA256
处理 单独使用 Ansible script 模块针对 master 重试
结果 成功
根因 疑似首次 Ansible SSH/SFTP 会话异常,但本阶段未进一步复现,因此待确认,其实就是忘了开代理

19. 本阶段已经确认完成的内容

k8s-master

已经确认:

项目 状态
Docker 正在运行
cri-dockerd 0.4.4
SHA256 校验
cri-docker.service unit 已创建/启用
cri-docker.socket unit 已创建/启用
/run/cri-dockerd.sock 已生成

最终 socket:/run/cri-dockerd.sock

k8s-node1

Ansible 原始执行结果:

复制代码
TASK [Install cri-dockerd]
changed: [k8s-node1]

因此 cri-dockerd 安装任务成功返回。更完整的版本、service、socket 独立验收输出:本阶段未单独留存。

k8s-node2

Ansible 原始执行结果:

复制代码
TASK [Install cri-dockerd]
changed: [k8s-node2]

因此 cri-dockerd 安装任务成功返回。更完整的版本、service、socket 独立验收输出:本阶段未单独留存。

devops

本阶段设计为安装 Docker Engine。但是当前记录中没有保存 devops 节点最终 docker --versionsystemctl is-active dockerdocker info 的单独执行输出。

因此严格记录为:

  • Docker 安装任务:已纳入 docker.yml ✓
  • 最终独立验收:本阶段未留存

elk

本阶段:不安装 Docker,不安装 cri-dockerd。


20. 统一验收结果

本阶段已完成 Docker 与 cri-dockerd 的全节点统一验收,因此不再标记为"待执行"。

20.1 Docker 四节点验收

执行:

bash 复制代码
ansible 'k8s_nodes:devops_servers' \
  -i inventory/hosts.ini \
  -b \
  -m shell \
  -a 'echo "===$(hostname)==="; docker --version; systemctl is-active docker; docker info 2>/dev/null | grep "Cgroup Driver"' \
  -K

验收作用: 一次确认以下三项:

  1. docker --version --- 确认 Docker Engine 已正确安装,并记录实际版本
  2. systemctl is-active docker --- 确认 Docker daemon 正常运行,正确结果为 active
  3. docker info | grep "Cgroup Driver" --- 确认 Docker cgroup driver 已按照 Kubernetes 规划配置为 systemd

实际验收结果:

节点 Docker 版本 服务状态 Cgroup Driver
k8s-master Docker version 28.1.1, build 4eba377 active systemd
k8s-node1 Docker version 28.1.1, build 4eba377 active systemd
k8s-node2 Docker version 28.1.1, build 4eba377 active systemd
devops Docker version 28.1.1, build 4eba377 active systemd

结论:

节点 Docker 28.1.1 active systemd
k8s-master
k8s-node1
k8s-node2
devops

Docker 四节点统一验收:✓ 通过

20.2 cri-dockerd 三节点综合验收

执行:

bash 复制代码
ansible k8s_nodes \
  -i inventory/hosts.ini \
  -b \
  -m shell \
  -a 'echo "===$(hostname)==="; /usr/local/bin/cri-dockerd --version; systemctl is-active cri-docker.service; systemctl is-active cri-docker.socket; test -S /run/cri-dockerd.sock && echo "CRI socket OK"' \
  -K

验收作用: 确认三个 Kubernetes 节点上的:

  1. cri-dockerd 二进制及版本
  2. cri-docker.service
  3. cri-docker.socket
  4. /run/cri-dockerd.sock

其中:

  • /usr/local/bin/cri-dockerd --version --- 确认 cri-dockerd 已正确安装
  • systemctl is-active cri-docker.service --- 确认 cri-dockerd 服务处于运行状态
  • systemctl is-active cri-docker.socket --- 确认 systemd socket 处于运行状态
  • test -S /run/cri-dockerd.sock --- 确认该路径不仅存在,而且确实是 Unix Socket

实际验收结果:

三台节点均返回:

复制代码
cri-dockerd 0.4.4 (98c4823)
active
active
CRI socket OK

具体状态:

节点 cri-dockerd 版本 service socket CRI socket
k8s-master 0.4.4 (98c4823) active active OK
k8s-node1 0.4.4 (98c4823) active active OK
k8s-node2 0.4.4 (98c4823) active active OK

结论:

节点 cri-dockerd service active socket active CRI socket OK
k8s-master
k8s-node1
k8s-node2

cri-dockerd 三节点统一验收:✓ 通过

20.3 CRI Socket 路径与权限验收

执行:

bash 复制代码
ansible k8s_nodes \
  -i inventory/hosts.ini \
  -b \
  -m shell \
  -a 'ls -l /run/cri-dockerd.sock' \
  -K

验收作用: 进一步确认 Kubernetes 后续实际使用的 CRI Socket /run/cri-dockerd.sock 已经在三台 Kubernetes 节点正确创建,并检查其文件类型、属主和属组。

实际结果:

节点 结果
k8s-master srw-rw--- 1 root docker ... /run/cri-dockerd.sock
k8s-node1 srw-rw--- 1 root docker ... /run/cri-dockerd.sock
k8s-node2 srw-rw--- 1 root docker ... /run/cri-dockerd.sock

其中 s 表示该文件类型为 Unix Socket ,属主和属组为 root:docker

后续 kubeadm 使用的 CRI Endpoint:unix:///run/cri-dockerd.sock

CRI Socket 三节点验收:✓ 通过

20.4 最终验收结论

本阶段统一验收最终结果:

Docker 四节点:

节点 Docker 版本 状态 Cgroup Driver
k8s-master 28.1.1 active systemd ✓
k8s-node1 28.1.1 active systemd ✓
k8s-node2 28.1.1 active systemd ✓
devops 28.1.1 active systemd ✓

cri-dockerd 三节点:

节点 版本 service socket
k8s-master 0.4.4 active active ✓
k8s-node1 0.4.4 active active ✓
k8s-node2 0.4.4 active active ✓

CRI Socket:

节点 路径 状态
k8s-master /run/cri-dockerd.sock
k8s-node1 /run/cri-dockerd.sock
k8s-node2 /run/cri-dockerd.sock

因此此前"Docker/cri-dockerd 全节点批量验收待执行/待确认"正式更新为:

项目 状态
Docker 四节点批量验收
cri-dockerd 三节点批量验收
/run/cri-dockerd.sock 三节点验收

阶段 2:Docker Engine + systemd cgroup + cri-dockerd ✓ 验收完成

后续除非修改 Docker 配置、重装容器运行时,或 Kubernetes 故障排查需要重新确认 CRI,否则无需重复进行本阶段验收。

注:Ansible 使用 shell 模块执行这些检查时显示 CHANGED 属正常现象。本次验收主要依据命令 $? rc=0 以及实际输出是否符合预期判断,并不表示验收命令修改了系统配置。


21. 本阶段关键配置汇总

Docker 节点:

  • k8s-master
  • k8s-node1
  • k8s-node2
  • devops

cri-dockerd 节点:

  • k8s-master
  • k8s-node1
  • k8s-node2

Docker cgroup 目标配置: systemd

Docker storage driver 配置: overlay2

最终批量实际状态: 已统一验收 ✓

cri-dockerd:

项目
版本 0.4.4
Master 已确认版本 cri-dockerd 0.4.4 (98c4823)
binary 路径 /usr/local/bin/cri-dockerd
CRI Socket /run/cri-dockerd.sock
Kubernetes 后续 CRI Endpoint unix:///run/cri-dockerd.sock

22. 本阶段学到的内容

1. Kubernetes 使用 Docker 需要 CRI 适配层

当前项目不是:

复制代码
kubelet
    ↓
Docker

而是:

复制代码
kubelet
    ↓
cri-dockerd
    ↓
Docker Engine

因此后面 kubeadm 必须显式使用 unix:///run/cri-dockerd.sock

2. Docker 与 kubelet 的 cgroup driver 必须统一规划

本项目统一选择 systemd,显式配置。后续 Kubernetes 阶段仍需验证 kubelet 的对应配置。

3. YAML 错误不一定是 Shell 错误

这次 awk -F':' Shell 本身合法,但 YAML 对 : 有特殊语义。因此复杂 shell 命令优先使用 shell: > 可以减少 YAML 引号和转义问题。

4. Ansible script 看起来"卡住"时不能直接判断为下载慢

script 模块执行期间,控制台不会像手工终端一样持续展示脚本内部的所有实时输出。所以看到 TASK [Install...] 长时间没有变化,只能说明 task 尚未正常返回,不能直接推出 curl 下载很慢。应该通过 pssystemctl、文件是否生成、手工 curl、Ansible -vv 逐层定位。

5. 排障要先区分"服务有问题"还是"自动化执行有问题"

本次 master 排查很典型:cri-dockerd binary 不存在、service inactive、socket inactive、socket 文件不存在------说明不是"服务装好了但启动失败",而是"安装过程本身没有完成"。排障方向因此转向安装脚本/Ansible/SSH/下载,而不是继续研究 cri-docker service 日志。

6. 网络问题最好直接做最小化验证

通过 curl + sha256sum 直接确认 DNS、网络、GitHub、URL、速度、文件完整性,比反复重跑整个 Playbook 更容易缩小故障范围。

7. 故障根因没有证据时不要强行下结论

虽然第一次失败过程中出现了 sshd: master@nottysftp-server,并且后续单独重新执行成功,但没有完整日志证明 SSH/SFTP 就是根因。因此当前合理结论是"疑似 Ansible SSH/SFTP 临时会话异常,根因待确认",而不是把猜测记录成事实。

8. 自动化脚本需要主动设置网络超时

即使这次并不是下载慢导致的问题,也暴露了原脚本 curl -fL ... 缺少网络失败边界。优化后加入 connect timeout、overall timeout、retry、retry delay,可以避免未来 CI/CD 或批量 Ansible 执行时某一台机器永久等待。


23. 本阶段状态

当前可记录为:

项目 状态
Docker 自动安装脚本 ✓ 已编写并执行
Docker daemon systemd cgroup 配置 ✓ 已写入方案
cri-dockerd 0.4.4 安装脚本
k8s-master cri-dockerd ✓ 已明确验证
k8s-node1 cri-dockerd ✓ Ansible task 成功
k8s-node2 cri-dockerd ✓ Ansible task 成功
CRI socket on master ✓ 已明确验证
Docker/cri-dockerd 全节点批量验收 ✓ 已完成

因此阶段主体已经完成。


相关推荐
qq210846295339 分钟前
Ubuntu 磁盘空间清理实战:从 Docker 到 VirtualBox 的完整指南
linux·ubuntu·docker
小无名呀1 小时前
Docker的使用
运维·docker·容器
做一个AK梦1 小时前
DevOps
运维·devops
优化Henry1 小时前
关于“星链”互联网系统的几点认识
运维·服务器·网络·笔记·学习·信息与通信
九硕智慧建筑一体化厂家4 小时前
智慧建筑高效管控!楼宇自控系统赋能新能源园区智能运维
运维·人工智能·笔记·智慧城市
Wang's Blog11 小时前
PostgreSQL笔记60: 权限与角色管理——从层级体系到最佳实践
数据库·笔记·postgresql
不灭的程序员阿澄12 小时前
在飞牛 NAS 上用 Docker 运行 DeepSeek Harness
运维·docker·容器
虎王物联14 小时前
Docker Compose编排物联网平台后端:Nginx+PHP-FPM+EMQX+InfluxDB一键部署实战
物联网·nginx·docker
IZero0714 小时前
Elasticsearch 学习笔记筑基-文档操作篇
笔记·学习·elasticsearch