FoundersJP

NAS中 Docker Compose 的进阶玩法

· 7 分钟阅读

数字生活
Docker NAS Unraid

熟悉我的友友都知道我经常折腾NAS,而我属于也在NAS部署了很多自托管的服务,这其中Docker是必不可少的。不同的NAS系统针对Docker有不同的解决方案,而Docker Compose是目前适用性最广泛额一个。

标签说明

Docker Compose 配置文件是 YAML 格式的,通常是 docker-compose.yml 或 compose.yaml 文件。顶级标签定义了整个应用的服务、网络、存储卷等配置。以下是 Docker Compose 配置文件中常见且重要的顶级标签名称及其功能列表。这个列表是基于 Compose 规范(Compose Specification)的,它取代了旧版本的 v2 和 v3 格式,是现阶段推荐和广泛使用的标准。

version (已废弃)(在较新的 Compose 规范中已不推荐使用) 在旧的 Compose 文件格式(v2 和 v3)中用于指定配置文件版本。现在使用 Compose 规范时,此字段通常被省略或仅用于向后兼容。旧版本
services定义应用中的所有服务。 每个服务条目(如您提到的 image、container_name 等)都作为这个键下的子配置。这是 Compose 文件的核心部分。必选
volumes定义命名存储卷(Named Volumes)。 这些存储卷可以在不同的服务之间共享,并且独立于容器的生命周期。可选
networks定义自定义网络。 允许服务连接到特定的网络,以便相互通信或与外部网络通信。可选
configs定义配置数据(Config Data)。 允许服务访问敏感或非敏感的配置数据,通常用于应用配置。可选
secrets定义敏感数据(Secrets)。 允许服务安全地访问敏感信息,如密码或 API 密钥。可选
include包含其他 Compose 文件。 允许将配置拆分为多个文件,便于管理和复用。可选
name指定项目名称。 用于覆盖目录名称作为项目名称的默认行为。可选

这些顶级标签中,服务标签(services) 是构建容器必不可少的,在其下也有很多常用的子标签。

image指定构建容器所使用的镜像。 可以是 Docker Hub 上的公共镜像,也可以是私有仓库或本地镜像。
build定义如何构建镜像。 如果不使用现有的 image,则用此指定 Dockerfile 路径和构建上下文。
container_name为容器指定一个固定的名称。 默认情况下 Compose 会生成一个名称(如 projectname-servicename-1)。
ports发布容器的端口到主机。 格式通常是 主机端口:容器端口。
volumes挂载存储卷或主机路径到容器。 用于数据持久化或共享主机文件。格式可以是 主机路径:容器路径 或 卷名称:容器路径。
environment设置容器中的环境变量。 可以是键值对列表或文件引用。
env_file从文件中添加环境变量。
networks指定服务应连接到哪些网络。
depends_on定义服务之间的依赖关系。 确保依赖的服务在当前服务启动前启动。
restart定义容器退出时的重启策略。 例如 always, on-failure, unless-stopped。
command覆盖容器启动时执行的默认命令。
entrypoint覆盖容器的默认入口点。
labels添加自定义元数据(标签)到容器。
healthcheck定义一个检查容器健康状态的命令。
logging配置服务的日志驱动和选项。
deploy指定部署和运行时约束(主要用于 Swarm 模式)。

样例

为了方便理解,我用两个样例来做说明。我会在每个标签旁边使用 # 符号添加注释(说明)。

以下这个示例展示了通过单个容器配置一个独立的 Web 服务器容器(使用 Nginx 镜像)的方案。

   # Compose 文件的顶级配置键(标签)

# 推荐在新的 Compose 文件中省略 'version' 键,以遵循最新的 Compose 规范。
# 如果需要向后兼容,可以添加如下(但不再推荐):
# version: '3.8'

# 核心标签:定义应用中的所有服务
services:
  # 服务名称:可以是任何你想要的名字,它作为网络别名
  web_server:
    # 服务子标签:

    # 指定构建容器所使用的镜像
    image: nginx:latest

    # 为容器指定一个固定的名称
    container_name: my_single_nginx_container

    # 挂载存储卷或主机路径到容器
    # 格式:[主机路径或卷名称]:[容器内部路径]
    volumes:
      # 挂载本地的 ./html 目录到容器的 Nginx 默认网页目录
      - ./html:/usr/share/nginx/html:ro

    # 发布容器的端口到主机
    # 格式:[主机端口]:[容器端口]
    ports:
      # 将容器的 80 端口映射到主机的 8080 端口
      - "8080:80"

    # 设置容器中的环境变量
    environment:
      # 这是一个示例环境变量
      - TIMEZONE=Asia/Shanghai

    # 定义容器退出时的重启策略
    # 'unless-stopped' 表示除非手动停止,否则容器退出时都会重启
    restart: unless-stopped

    # 添加自定义元数据(标签)到容器
    labels:
      - "com.example.description=Single Nginx Web Server"

# 顶级标签:定义命名存储卷(如果需要)
# 在这个单容器示例中,我们使用了主机挂载,所以 volumes 标签可以省略。
# volumes:
#   my_data:

# 顶级标签:定义自定义网络(如果需要)
# 在这个单容器示例中,Compose 会使用默认的 bridge 网络。
# networks:
#   default:
#     driver: bridge

这个示例则是通过多个容器配置一个 Web 应用程序(使用 Node.js 示例)和一个数据库(使用 PostgreSQL),并配置它们之间的依赖和通信的方案。

   # Compose 文件的顶级配置键(标签)

# 核心标签:定义应用中的所有服务
services:
  # 服务一:Web 应用程序
  app_service:
    # 服务子标签:

    # 指定如何构建镜像(从 Dockerfile 构建)
    # 'context' 指定 Dockerfile 所在的目录,'dockerfile' 指定 Dockerfile 文件名
    build:
      context: .
      dockerfile: Dockerfile.app

    # 为容器指定一个固定的名称
    container_name: web_app_container

    # 发布容器的端口到主机
    # 将容器的 3000 端口映射到主机的 3000 端口
    ports:
      - "3000:3000"

    # 设置容器中的环境变量
    environment:
      # 连接数据库所需的环境变量
      - DB_HOST=db_service  # 使用服务名称作为主机名进行连接
      - DB_PORT=5432
      - DB_USER=user
      - DB_PASSWORD=secret

    # 定义服务之间的依赖关系
    # 确保 db_service 容器启动并运行后才启动 app_service
    depends_on:
      db_service:
        condition: service_started

    # 指定服务应连接到哪些网络
    networks:
      - internal_network
      - public_network

  # 服务二:数据库服务
  db_service:
    # 服务子标签:

    # 指定使用的数据库镜像
    image: postgres:14-alpine

    # 为容器指定一个固定的名称
    container_name: postgres_db_container

    # 挂载存储卷到容器
    volumes:
      # 使用命名存储卷进行数据持久化,确保数据在容器重启后不会丢失
      - postgres_data:/var/lib/postgresql/data

    # 从文件中添加环境变量(更安全的方式来管理密码)
    # 假设存在一个名为 .env.db 的文件,包含 POSTGRES_USER 等变量
    env_file:
      - .env.db

    # 定义容器退出时的重启策略
    restart: always

    # 指定服务应连接到哪些网络
    # 注意:数据库服务通常不直接暴露到公网,只连接内部网络
    networks:
      - internal_network

# 顶级标签:定义命名存储卷
volumes:
  # 定义一个名为 'postgres_data' 的卷
  postgres_data:
    # 可以指定驱动和选项,这里使用默认驱动
    driver: local

# 顶级标签:定义自定义网络
networks:
  # 定义一个内部使用的网络,供 app 和 db 通信
  internal_network:
    driver: bridge
  # 定义一个可能需要对外连接的网络
  public_network:
    driver: bridge

NAS中使用

目前来说各个主流的NAS系统都支持Docker Compose,根据自己的需要找到对应项目的Docker Compose,复制粘贴到NAS中的Docker Compose,并根据自己的具体情况编辑一下中即可。

需要特别说明的是在自己的NAS中使用时,修改Docker Compose文件中的路径。前文中提到的 挂载标签volumes 和 变量文件env_file 标签都会涉及到路径设置。大部分NAS系统在添加Docker Compose时都需要设置路径,这个路径就是容器项目在NAS中储存文件的位置。

在Docker Compose文件中,每个标签下的项目用“:”来分割,第一个冒号前的是映射的宿主机端口或地址,第一个冒号后则是容器内的端口或地址,第二个冒号后则是读写权限等设置项。

根据不同的开发者编辑代码习惯不同,映射挂载地址时,有的开发者会写绝对地址,有的则是相对地址,以上面的样例参考:

   绝对地址:/volume1/docker/Test/html

相对地址:./html

上面的例子中, html 文件夹是映射挂载的文件夹,前面的“ ./ ”则表示 html 这个文件夹是在 /docker/Test 目录下的。我个人是偏好使用相对路径的,如果容器或docker目录发生位置调整时,不会使容器因目录失联而失效。

另一个就是端口,上面的例子中,是将容器中的80端口映射到宿主机的8080端口上,如果在NAS中有多的Docker容器运行,一定要注意哪些端口已经被占用了,避免在不同的容器中映射了同样的端口,这样也会导致容器无效。

相关文章

难道失去443端口,地址就要带着数字小尾巴吗?No!Lucky+CloudFlare让你清清爽爽!

· 3 分钟阅读

熟悉的友友都知道我比较爱折腾NAS,家里的NAS中也跑了很多服务。做为宅一族的我大部分使用也是通过路由端的内网地址跳转来使用,而没有注意到公网的访问状况。然而最近突然有一天,我在外出时发现NAS上的这些服务不能通过公网访问了。 查了一下原因是IPv6的443端口被封了,以前我所在的城市IPv6是不封443的。本以为是阶…

手把手教程,在线协同Office一键全搞定,UnRiad+NextCloud-AIO

· 2 分钟阅读

最近和朋友一起做项目,要协同办公,所以打算搭建一个功能强大的自托管协同平台。选来选去选择了NextCloud。选择它的原因有二:其一,它的功能丰富多样,涵盖了任务板、Office套件以及ToDoList管理等;其二,每个功能都配备了相应的移动端应用,使我们能够随时随地推进项目进程。 以前也在UnRaid中装过Docke…

小白也不愁,软银封 IPv6 后,Lucky+Cloudflare Tunnel全搞定

· 4 分钟阅读

今天突然发现家里的NAS没法在外网访问了,存里面的笔记也同步不了。排查了半天才找到原因——软银路由升级把IPv6的入站连接给封锁了。之前我分享过“去掉非443端口小尾巴”的方法,能解决不少访问问题,但面对这次的IPv6封锁,那套办法就完全不管用了。 https://www.foundersjp.com/cn/lifes…

简单易用!Docker添加中文支持,让你轻松打造母语环境!

· 2 分钟阅读

玩NAS必然要折腾Docker,Docker可能是目前生态最广泛的应用平台了。除了大神们推荐的各种应用,在docker.com上也有很多好玩的东西,包括一些AIGC工具,一些私有云盘工具等。但是问题也来了,很多docker镜像应用不是面向中文用户开发的,所以也没有中文化。 前几天就有一位朋友跟我探讨Docker中的应用…

给 AI 做个脑科手术:用 Ollama Modelfile 本地大模型调优,让它学会影分身术的?

· 7 分钟阅读

Agent私有化的时代,Ollama是非常适合的AI模型运行基座,根据需求不同,交错加载不同的模型,以实现Agent的行为目的。不过ollama官方library的模型普遍占用空间比较大,而且不能自定义。相比较而言,从huggingface拉取是一个很好的选择。 恰好最近Qwen和Gemma都更新了新模型,号称对Age…

评论