# 通过 Docker 运行 EMQX

本页将指导您使用官方 Docker 镜像快速安装和运行 EMQX，并使用 Docker Compose 实现集群搭建。

## 部署前准备

在 Docker 中启动 EMQX 前，请了解以下部署注意事项。

### 配置稳定的节点名

EMQX 将节点数据存储在 `data/mnesia/<节点名>` 目录中。首次启动容器前，请配置稳定的节点名，避免后续节点名发生变化导致数据丢失。

对于单节点部署，使用 `EMQX_NODE_NAME` 环境变量配置节点名，格式为 `emqx@<host>`。容器主机名应与 `<host>` 的值保持一致。

**注意：** `<host>` 部分必须是 IP 地址或完全限定域名（FQDN），例如 `node1.emqx.com`。EMQX 的 Erlang 节点以长节点名模式运行，因此不能使用不含点号的短主机名，例如 `node1`。

### 准备持久化存储

要在容器被删除后保留 EMQX 数据，请将以下容器目录挂载到宿主机：

- `/opt/emqx/data`：存储 EMQX 数据。
- `/opt/emqx/log`：存储文件日志和崩溃转储文件。

EMQX 容器默认使用控制台日志，但节点异常终止时，Erlang 虚拟机会将崩溃转储文件写入 `/opt/emqx/log`。如果未挂载该目录，删除容器后将无法保留转储文件。宿主机上的日志目录必须对容器内的 `emqx` 用户（UID 1000）可写。详情参见 [Docker 中的崩溃转储文件](../../guides/configuration/logs.md#docker-中的崩溃转储文件)。

有关 EMQX 目录结构的更多信息，参见 [EMQX 文件和目录](./install.md#文件和目录)。

### 访问宿主机服务

如果 EMQX 需要访问宿主机上运行的服务，请勿使用 `localhost` 或 `127.0.0.1` 作为服务地址。这些地址指向容器自身的网络接口。请使用宿主机 IP 地址或 [host 网络模式](https://docs.docker.com/network/host/)。在 Docker Desktop for Mac 或 Windows 中，也可以使用 `host.docker.internal`。

### 了解运行时镜像

从 EMQX Enterprise 6.3.1 开始，官方 Docker 发布镜像使用 Docker Hardened Debian 13（Trixie）。运行时镜像不包含 `apt`、`dpkg` 等软件包管理工具，因此无法在运行中的 EMQX 容器内使用这些工具安装软件包。

如果部署需要额外工具或运行时依赖，请在部署前将其加入自定义镜像并完成验证。不要依赖在运行中的官方容器内安装软件包。

发布镜像还包含构建来源信息（provenance）和软件物料清单（SBOM）的证明材料（attestations）。Docker Scout 可利用这些证明材料，应用 Docker 针对加固基础镜像提供的漏洞评估（VEX 声明）。

## 通过 Docker 运行单个 EMQX 节点

按照以下步骤运行单个 EMQX 节点。有关 EMQX 官方 Docker 镜像的更多信息，参见 [Docker Hub - emqx/emqx-enterprise](https://hub.docker.com/r/emqx/emqx-enterprise)。

1. 拉取 Docker 镜像：

   ```bash
   docker pull emqx/emqx-enterprise:6.3.1
   ```

2. 创建宿主机目录，并确保容器内的 `emqx` 用户对日志目录具有写权限：

   ```bash
   mkdir -p $PWD/data $PWD/log
   sudo chown $UID:$GID $PWD/log
   ```

3. 使用稳定的节点名和已挂载的目录启动容器：

   ```bash
   docker run -d --name emqx-enterprise \
     --hostname node1.emqx.com \
     -e "EMQX_NODE_NAME=emqx@node1.emqx.com" \
     -p 1883:1883 -p 8083:8083 \
     -p 8084:8084 -p 8883:8883 \
     -p 18083:18083 \
     -v $PWD/data:/opt/emqx/data \
     -v $PWD/log:/opt/emqx/log \
     emqx/emqx-enterprise:6.3.1
   ```

### 配置 Docker 中的默认监听地址

**Docker 镜像默认设置**

从 EMQX 6.3.0 开始，当环境变量 `EMQX_NODE__DEFAULT_LISTENER_ADDRESS` 未设置或为空时，官方镜像的入口脚本将其设置为 `all`。

该默认值使仅指定端口的 MQTT 监听器、网关监听器和 Dashboard HTTP 监听器监听所有网络接口，从而在两种[安全配置方案](../../guides/access-control/security-profile.md)下均可通过发布的容器端口访问。

监听器绑定中显式指定的 IP 地址保持不变。该配置仅控制绑定地址，不会放宽认证或授权要求。

**覆盖默认设置**

如需覆盖此默认值，可通过 `docker run -e EMQX_NODE__DEFAULT_LISTENER_ADDRESS=<value>` 传入其他支持的值，或在 Docker Compose 服务的 `environment` 部分设置该变量。

环境变量的优先级高于配置文件，因此，仅在挂载的 `emqx.conf` 中设置 `node.default_listener_address` 不会覆盖入口脚本的默认值。

支持的取值参见[默认监听地址](../../guides/access-control/security-profile.md#默认监听地址)。

::: warning 重要提示
使用 Docker 桥接网络时，将该变量设置为 `loopback` 会使受影响的监听器绑定到容器网络命名空间内的回环地址。此时，即使使用 `-p`，也无法通过发布的端口访问这些监听器。

如需控制发布端口所使用的宿主机地址，请参见 [Docker 端口发布和映射](https://docs.docker.com/engine/network/port-publishing/)。
:::

### 使用功能门控启动 EMQX

从 EMQX 6.3.0 开始，可以使用 `EMQX_FEATURES` 环境变量控制启动时可用的可选功能。例如，如需仅启动核心应用，运行：

```bash
docker run -d --name emqx-enterprise \
  -e "EMQX_FEATURES=ESSENTIAL" \
  -p 1883:1883 -p 8083:8083 \
  -p 8084:8084 -p 8883:8883 \
  emqx/emqx-enterprise:6.3.1
```

如需使用自定义功能集启动 EMQX，运行：

```bash
docker run -d --name emqx-enterprise \
  -e "EMQX_FEATURES=dashboard,metrics,plugins" \
  -p 1883:1883 -p 18083:18083 \
  emqx/emqx-enterprise:6.3.1
```

完整功能列表和依赖行为请参见[功能门控](./feature-gates.md)。

## 通过 Docker Compose 构建 EMQX 集群

Docker Compose 是一个用于编排和运行多容器的工具，下面将指导您通过 Docker Compose 创建简单的 EMQX 静态集群用于测试。

本节中的 Docker Compose 示例仅适用于本地测试，其中的卷挂载配置默认被注释。要保留数据和崩溃转储文件，请按照[部署前准备](#部署前准备)中的说明准备宿主机目录，并取消 `volumes` 配置的注释。有关生产环境中的集群部署，参见[构建集群](../../develop/cluster/introduction.md)。

:::tip

目前 Docker Compose 已经包含在 Docker 安装包中无需单独安装，如果您的 Docker 中没有包含 Compose 请参考 [Install Docker Compose](https://docs.docker.com/compose/install/) 进行安装。

:::

1. 在任意目录创建 `docker-compose.yml` 文件，内容如下：

   ```yml
   version: '3'

   services:
     emqx1:
       image: emqx/emqx-enterprise:6.3.1
       container_name: emqx1
       environment:
       - "EMQX_NODE_NAME=emqx@node1.emqx.com"
       # - "EMQX_FEATURES=dashboard,metrics,plugins"
       - "EMQX_CLUSTER__DISCOVERY_STRATEGY=static"
       - "EMQX_CLUSTER__STATIC__SEEDS=[emqx@node1.emqx.com,emqx@node2.emqx.com]"
       healthcheck:
         test: ["CMD", "/opt/emqx/bin/emqx", "ctl", "status"]
         interval: 5s
         timeout: 25s
         retries: 5
       networks:
         emqx-bridge:
           aliases:
           - node1.emqx.com
       ports:
         - 1883:1883
         - 8083:8083
         - 8084:8084
         - 8883:8883
         - 18083:18083
       # volumes:
       #   - $PWD/emqx1_data:/opt/emqx/data
       #   - $PWD/emqx1_log:/opt/emqx/log

     emqx2:
       image: emqx/emqx-enterprise:6.3.1
       container_name: emqx2
       environment:
       - "EMQX_NODE_NAME=emqx@node2.emqx.com"
       # - "EMQX_FEATURES=dashboard,metrics,plugins"
       - "EMQX_CLUSTER__DISCOVERY_STRATEGY=static"
       - "EMQX_CLUSTER__STATIC__SEEDS=[emqx@node1.emqx.com,emqx@node2.emqx.com]"
       healthcheck:
         test: ["CMD", "/opt/emqx/bin/emqx", "ctl", "status"]
         interval: 5s
         timeout: 25s
         retries: 5
       networks:
         emqx-bridge:
           aliases:
           - node2.emqx.com
       # volumes:
       #   - $PWD/emqx2_data:/opt/emqx/data
       #   - $PWD/emqx2_log:/opt/emqx/log

   networks:
     emqx-bridge:
       driver: bridge
   ```

   如果在 Docker Compose 集群中设置 `EMQX_FEATURES`，请为所有 EMQX 服务使用相同的值。

2. 通过命令行切换 `docker-compose.yml` 文件所在目录，然后输入以下命令启动 EMQX 集群：

   ```bash
   docker-compose up -d
   ```

3. 查看集群状态：

   ```bash
   $ docker exec -it emqx1 sh -c "emqx ctl cluster status"
   Cluster status: #{running_nodes => ['emqx@node1.emqx.com','emqx@node2.emqx.com'],
                     stopped_nodes => []}
   ```

## 下一步

使用客户端连接到 EMQX，进行消息收发，请参考[发布订阅操作](../messaging/publish-and-subscribe.md)。

配置 EMQX 参数及其他功能，请参考[配置文件](../../guides/configuration/configuration.md)。

将多个 EMQX 节点组建为一个集群，请参考[构建集群](../../develop/cluster/introduction.md)。
