Coolify logoCoolify

Docker Compose

如果您使用基于 Docker Compose 的部署,您需要了解 Docker Compose 如何与 Coolify 配合工作。

在所有情况下,Docker Compose(docker-compose.y[a]ml)文件都是唯一的事实来源。 这意味着您通常在 Coolify UI 中配置的各种设置(如环境变量、存储等)都需要直接在 compose 文件中定义。

使服务对外可见

当 Coolify 部署 Docker Compose 时,它会为部署中的服务创建一个网络。此外,它还会添加代理服务,以便能够从新网络中访问这些服务。

这意味着您可以通过以下几种方式使您的服务对外可用:

域名

Coolify 加载您的 compose 文件后,会列出所有服务并允许您分配域名。如果您的服务监听 80 端口,分配域名就足以让代理找到它们并将流量路由过去。如果它们监听其他端口,请将端口号添加到域名中。

例如,如果您的应用监听(容器)端口 80,并且希望运行在 example.com 上,请在域名字段输入 http://example.com(或 https://)。

然而,如果您的应用监听(容器)端口 3000,则需要在相关服务中填写 http://example.com:3000。此处的端口仅告诉 Coolify 将流量发送到容器内的哪个位置;代理仍会将此服务通过标准端口对外提供(在此例中为 http://example.com 的 80 端口)。

如果您想进一步自定义基于域名的路由,请参阅下方的 Coolify 的魔法环境变量

服务端口映射

如果您希望通过主机端口直接访问您的服务,请在 compose 文件中添加 ports 属性。例如,将容器端口 3000 直接映射到宿主机:

services:
  backend:
    image: your-backend:latest
    ports:
      - "3000:3000"

请注意,如果这样做,您的服务将在服务器的 3000 端口上直接暴露,不受任何代理配置的控制。这可能不是您想要的!如果您在开发和部署中使用同一个 Docker Compose 文件,这可能会意外暴露您本不想公开的私有服务端口。

可选地,您可以传入 IP 地址,将端口绑定到宿主机的特定网络接口:

services:
  backend:
    image: your-backend:latest
    ports:
      - "127.0.0.1:3000:3000"

这将使您的服务仅在服务器的 localhost:3000 上可用。

私有或内部服务

如果您不映射服务端口或分配域名,Coolify 将不会在私有网络之外暴露您的服务。此时,您可以按照 Docker Compose 的常规方式进行引用。

例如,如果您有两个服务,名称如下:

services:
  backend:
    image: your-backend:latest
  auth:
    image: your-auth:latest

然后,您可以从 backend 通过 http://auth:1234(或相应端口)连接到 auth。同样,auth 也可以通过 http://backend:3000(或相应端口)连接到 backend

更多详细信息,请参阅 Docker Compose 网络文档

定义环境变量

Coolify 会自动检测 compose 文件中提到的环境变量,并在 UI 中显示它们。例如:

services:
  myservice:
    environment:
      - SOME_HARDCODED_VALUE=hello # 会传递给容器,但不会显示在 Coolify 的 UI 中
      - SOME_VARIABLE=${SOME_VARIABLE_IN_COOLIFY_UI} # 会在 Coolify 的 UI 中创建一个可编辑的未初始化环境变量
      - SOME_DEFAULT_VARIABLE=${OTHER_NAME_IN_COOLIFY:-hello} # 会在 Coolify 的 UI 中创建一个值为 "hello" 的可编辑环境变量

必填环境变量

Coolify 支持使用 Docker Compose 的内置语法将环境变量标记为必填。此功能通过在启动服务前验证关键配置来改善部署体验。 您可以使用 :? 语法将环境变量标记为必填。必填变量必须在部署前设置,如果为空,将在 Coolify 的 UI 中以红色边框高亮显示。

services:
  myapp:
    environment:
      # 必填变量 - 如果未设置,部署将失败
      - DATABASE_URL=${DATABASE_URL:?}
      - API_KEY=${API_KEY:?}

      # 带默认值的必填变量 - 在 UI 中预填,但可以更改
      - PORT=${PORT:?3000}
      - LOG_LEVEL=${LOG_LEVEL:?info}

      # 可选变量 - 标准行为
      - DEBUG=${DEBUG:-false}
      - CACHE_TTL=${CACHE_TTL:-3600}

关键行为:

  • 必填变量 ({VAR:?}) 会出现在环境变量列表的顶部,若为空则显示红色边框
  • 带默认值的必填变量 ({VAR:?default}) 会预填默认值,但仍可编辑
  • 可选变量 ({VAR:-default}) 遵循标准的 Docker Compose 行为

如果在部署期间未设置必填变量:

  • Coolify 将在 UI 中高亮显示缺失的变量
  • 部署将被阻止,直到提供所有必填变量
  • 清晰的错误提示将引导用户修复配置

此验证发生在容器创建之前,可防止部分部署和运行时故障。

共享环境变量

Coolify 不会直接检测 compose 文件中的共享环境变量,但可以通过额外步骤进行引用。

  1. 按照 共享变量文档 创建您的共享变量。

  2. 在您的 Docker Compose 文件中定义变量,例如:

services:
  myservice:
    environment:
      - HARD_CODED=dev # 会传递给容器,但不会显示在 Coolify 的 UI 中。
      - SOME_OPTIONAL_VARIABLE=${SOME_VARIABLE_IN_COOLIFY_UI} # 会在 UI 中创建一个可编辑的未初始化变量。
    volumes:
      - data-persist:/var/data
  volumes:
    data-persist:
      device: /mnt/serverstorage/${SOME_VARIABLE_IN_COOLIFY_UI} # 复用该变量
  1. 在应用程序的“环境变量”中显式定义该变量,引用您在第 1 步中创建的共享变量;

如果您在开发者视图中,可以这样输入:

SOME_VARIABLE_IN_COOLIFY_UI={{environment.SOME_SHARED_VARIABLE}}

或者在普通视图中,“名称”对应 Docker Compose 文件中引用的 SOME_VARIABLE_IN_COOLIFY_UI,而“值”则是引用的环境变量 {{environment.SOME_SHARED_VARIABLE}},如下图所示。保存正确后,您会看到第三个文本框,展开它即可看到实际值,在此例中为 SOME_VALUE

Coolify 的魔法环境变量

Coolify 可以使用以下语法为您生成动态环境变量:SERVICE_<TYPE>_<IDENTIFIER>。类型可以是以下之一:

类型生成的值
URL基于您的通配符域名生成的 URL。下方示例展示了如何添加路径和端口。
FQDN基于生成的 URL 生成的完全限定域名 (FQDN)。下方示例展示了如何添加路径和端口。
USER随机字符串,16 个字符。
PASSWORD不含特殊符号的随机密码。
PASSWORD_64不含特殊符号的随机密码,64 个字符。
PASSWORDWITHSYMBOLS含特殊符号的随机密码。
PASSWORDWITHSYMBOLS_64含特殊符号的随机密码,64 个字符。
BASE64BASE64_32随机字符串,非 Base64 编码,32 个字符。
BASE64_64随机字符串,非 Base64 编码,64 个字符。
BASE64_128随机字符串,非 Base64 编码,128 个字符。
REALBASE64REALBASE64_32Base64 编码的随机字符串,32 个字符。
REALBASE64_64Base64 编码的随机字符串,64 个字符。
REALBASE64_128Base64 编码的随机字符串,128 个字符。
HEX_32十六进制随机字符串,32 个字符。
HEX_64十六进制随机字符串,64 个字符。
HEX_128十六进制随机字符串,128 个字符。

标识符命名

标识符使用下划线 (_) 时,不能在环境变量中使用端口。请改用连字符 (-) 以避免此限制。

SERVICE_URL_APPWRITE_SERVICE_3000 ❌
SERVICE_URL_APPWRITE-SERVICE_3000 ✅

每个生成的变量都可以重复使用,并且对所有服务始终保持相同的值。 所有生成的变量都会显示在 Coolify 的环境变量 UI 中,并可以在那里进行编辑(FQDN 和 URL 除外)。

例如,假设有一个 UUID 为 vgsco4o 的应用程序(由 Coolify 在创建时生成)。 它使用一个 compose 文件,在 通配符 域名 http://example.com 上部署 Appwrite 。

这将执行以下操作:

services:
  appwrite:
    environment:
      # http://appwrite-vgsco4o.example.com
      - SERVICE_URL_APPWRITE
      # http://appwrite-vgsco4o.example.com/v1/realtime
      - SERVICE_URL_APPWRITE=/v1/realtime
      # _APP_URL 将包含 FQDN,因为 SERVICE_URL_APPWRITE 只是一个普通的环境变量
      - _APP_URL=$SERVICE_URL_APPWRITE
      # http://appwrite-vgsco4o.example.com/ 将被代理到 3000 端口
      - SERVICE_URL_APPWRITE_3000
      # DOMAIN_NAME 将包含 FQDN (appwrite-vgsco4o.example.com),因为 SERVICE_FQDN_APPWRITE 会生成完整的 FQDN。无需在变量末尾添加 3000
      - DOMAIN_NAME=${SERVICE_FQDN_APPWRITE}
      # http://api-vgsco4o.example.com/api 将被代理到 2000 端口
      - SERVICE_URL_API_2000=/api
      # Coolify 生成密码并将其作为 SERVICE_SPECIFIC_PASSWORD 注入到容器中
      - SERVICE_SPECIFIC_PASSWORD=${SERVICE_PASSWORD_APPWRITE}
      # Coolify 生成一个 64 字符的不含特殊符号的密码
      - LONG_PASSWORD=${SERVICE_PASSWORD_64_APPWRITE}
      # Coolify 生成一个 64 字符的含特殊符号的密码
      - SYMBOL_PASSWORD=${SERVICE_PASSWORDWITHSYMBOLS_64_APPWRITE}
      # Coolify 生成一个 64 字符的 Base64 编码随机字符串
      - ENCRYPTION_KEY=${SERVICE_REALBASE64_64_APPWRITE}
      # Coolify 生成一个 64 字符的十六进制随机字符串
      - HEX_SECRET=${SERVICE_HEX_64_APPWRITE}
  not-appwrite:
    environment:
      # 复用 Appwrite 服务的密码。
      - APPWRITE_PASSWORD=${SERVICE_PASSWORD_APPWRITE}
      # 由于 SERVICE_URL_API 与 SERVICE_URL_APPWRITE 不同
      # Coolify 将生成一个新的 URL
      # http://not-appwrite-vgsco4o.example.com/api
      - SERVICE_URL_API=/api

基于 Git 源的 Compose 文件中的魔法环境变量支持需要 Coolify v4.0.0-beta.411 或更高版本。

存储

您可以在 compose 文件中正常预定义存储,但还有一些额外的选项可以设置,以便告诉 Coolify 如何处理这些存储。

创建空目录

# 预定义带主机绑定的目录
services:
  filebrowser:
    image: filebrowser/filebrowser:latest
    volumes:
      - type: bind
        source: ./srv
        target: /srv
        is_directory: true # 这将告诉 Coolify 创建目录(普通 docker-compose 中不可用)

创建带内容的文件

此处展示了如何添加带有内容和动态值(来自环境变量)的文件。

services:
  filebrowser:
    image: filebrowser/firebrowser:latest
    environment:
      - POSTGRES_PASSWORD=password
    volumes:
      - type: bind
        source: ./srv/99-roles.sql
        target: /docker-entrypoint-initdb.d/init-scripts/99-roles.sql
        content: |  # 这将告诉 Coolify 创建文件(普通 docker-compose 中不可用)
          -- 注意:在生产环境中请更改为您自己的密码
           \set pgpass `echo "$POSTGRES_PASSWORD"`

           ALTER USER authenticator WITH PASSWORD :'pgpass';
           ALTER USER pgbouncer WITH PASSWORD :'pgpass';

或者,您可以使用 Docker Compose 中的顶级元素 configs 来创建配置文件。

services:
  filebrowser:
    image: filebrowser/filebrowser:latest
    environment:
      - POSTGRES_PASSWORD=password
    configs:
      - source: roles
        target: /docker-entrypoint-initdb.d/init-scripts/99-roles.sql

configs:
  roles:
    content: |
      -- 注意:在生产环境中请更改为您自己的密码
        \set pgpass `echo "$POSTGRES_PASSWORD"`

        ALTER USER authenticator WITH PASSWORD :'pgpass';
        ALTER USER pgbouncer WITH PASSWORD :'pgpass';

排除健康检查

如果您有某个服务不希望包含在整体健康检查中,可以通过将 exclude_from_hc 选项设置为 true 将其排除。

提示

例如,如果您有一个仅运行一次然后容器就会停止的迁移服务,这将非常有用。

services:
  some-service:
    exclude_from_hc: true
    ...

连接到预定义网络

默认情况下,每个 compose 堆栈都会部署到一个独立的网络中,网络名称为您的资源 UUID。这将允许堆栈中的各个服务相互通信。

但在某些情况下,您可能希望与账户中的其他资源进行通信。例如,您希望将应用程序连接到部署在另一个堆栈中的数据库。

为此,您需要在 Service Stack(服务堆栈)页面上启用 Connect to Predefined Network(连接到预定义网络)选项,但这会导致内部 Docker DNS 无法按预期工作。

以下是一个示例。您有一个包含 postgres 数据库和 laravel 应用程序的堆栈。Coolify 会将您的 postgres 堆栈重命名为 postgres-<uuid>,将 laravel 堆栈重命名为 laravel-<uuid>,以防止名称冲突。

如果您在 laravel 堆栈上设置了 Connect to Predefined Network 选项,您的 laravel 应用程序将能够连接到 postgres 数据库,但您需要使用 postgres-<uuid> 作为数据库主机。

原始 Docker Compose 部署

您可以将项目配置为使用 docker compose build pack,以便直接部署您的 compose 文件,而无需使用 Coolify 的大部分自动化功能。这被称为 Raw Compose Deployment(原始 Compose 部署)。

注意

此功能面向高级用户。如果您不熟悉 Docker Compose,我们不推荐使用此方法。

标签 (Labels)

Coolify 仍会为您的应用程序添加以下标签(如果尚未设置):

labels:
  - coolify.managed=true
  - coolify.applicationId=5
  - coolify.type=application

要使用 Coolify 的代理(Traefik),您需要为应用程序设置以下标签:

labels:
  - traefik.enable=true
  - "traefik.http.routers.<unique_router_name>.rule=Host(`coolify.io`) && PathPrefix(`/`)"
  - traefik.http.routers.<unique_router_name>.entryPoints=http

On this page