Nomad 系列-快速上手

系列文章

Nomad 重要术语

Nomad 安装设置相关术语

  • agent - 代理。Agent 是在 Server(服务器) 或 Client(客户端) 模式下运行的 Nomad 进程。
  • client - 客户端。Nomad 客户端负责运行分配给它的任务。它还向服务器注册自己,并监视要分配的任何工作。当运行代理时,客户端可以被称为节点 (Node)。
  • server - 服务器端。Nomad 服务器管理所有作业和客户端,监视任务,并控制哪些任务被放置在哪些客户端节点上。服务器之间相互复制数据以确保高可用性。
  • dev_agent - 开发(模式)代理是一种代理配置,它为运行 Nomad 的单节点集群提供了有用的默认值。它在服务器和客户端模式下运行,并且不会将其群集状态持久化到磁盘,这允许代理从可重复的干净状态启动,而不必在运行之间删除基于磁盘的状态。

Nomad 集群通常由三到五个服务器代理和许多客户端代理组成。

Nomad 使用的相关术语

在 Nomad 调度和运行工作负载的过程中,您将遇到以下术语。

  • task - 任务是 Nomad 中最小的工作单元(类似 K8s 中的 Pod)。任务由 task drivers 执行,drivers 包括 docker 和 exec 等,这使得 Nomad 可以灵活地支持任务类型。任务指定其所需的任务驱动程序、驱动程序的配置、约束 (constraints) 和所需的资源。
  • group - 组是在同一 Nomad 客户端上运行的一系列任务。(我个人认为类似于 K8s 中的 Deployment/Statefulset/Daemonset/Job)
  • job - 作业是 Nomad 的核心控制单元,它定义了应用程序及其配置。它可以包含一个或多个任务。(我个人认为 job 类似于 K8s 中的多个资源 yaml manifest 集合。包括:SVC/Ingress/ConfigMap/Deploy/PVC...)
  • job specification - 作业规范,也称为 jobspec,定义了 Nomad 作业的模式。它描述了作业的类型、作业运行所需的任务和资源、作业信息(如作业可以在哪些客户端上运行)等。
  • allocation - 分配是作业中的任务组与客户端节点之间的映射。当运行作业时,Nomad 将选择能够运行它的客户端,并在机器上为作业中定义的任务组中的任务分配资源。(我认为类似于 K8s 中已经在运行的 pod.)

应用程序在 jobspec 中定义为具有 jobspec 的任务组 (groups of tasks),并且一旦提交给 Nomad,就会创建一个作业 (job) 沿着该 jobspec 中定义的每个组的分配 (allocation)。

Nomad 上的应用工作流

典型的应用程序工作流程涉及几个步骤,并从 Nomad 外部开始。

在 Nomad 上运行的任何应用程序的先决条件是具有工作负载工件。Nomad 支持各种工件,包括 Docker 镜像原始二进制文件 raw binariesJava 应用程序 和使用 QEMU 的虚拟机映像。

Nomad 不会创建这些应用程序工件,但可以使用 CircleCI,GitHub Actions 或本地构建等 CI 工具来创建工件,然后将其推送到存储库,Nomad 可以在调度作业时从中检索它们。

创建应用程序后,工作流将继续使用 Nomad。

  • 创建 job spec - 作业规范包含应用程序所需的任务,包括工件驻留的位置、网络配置(如端口和服务定义)、所需实例数量等等。
  • 部署 job - 作业规范将提交给 Nomad,并根据作业配置在一个或多个客户端上为作业安排分配。
  • 更新和重新部署 job - 更新应用程序代码或作业规范,然后重新提交给 Nomad 进行调度。

快速入门

接下来我们快速上手 Nomad, 主要展示如何部署示例应用程序。

前提

  • Docker 已安装
  • Nomad 二进制(包括 CLI) 已安装
  • (可选)CNI 插件已安装
  • Nomad 集群已创建并运行(至少包括 1 个 Server 和 1 个 Client)

部署示例应用程序 Job

这里我们直接使用 git clone Nomad 官方提供的 Demo:

bash 复制代码
git clone https://github.com/hashicorp-education/learn-nomad-getting-started.git
cd learn-nomad-getting-started
git checkout -b nomad-getting-started v1.1

示例应用程序在 Docker 容器中运行,由一个数据库和一个从数据库读取数据的 Web 前端组成。您将使用 参数化批处理作业 parameterized batch job 设置数据库,然后使用 定期批处理作业 periodic batch job 启动其他将数据写入数据库的短期作业。

Job 类型

Service(服务) 作业用于长期运行的服务(类似于 K8s 中的 Deployment),这些服务一直运行到显式停止。

Batch 作业是指在成功退出之前一直运行的短期作业(类似于 K8s 中的 JobCronJob)。

  • 参数化 (parameterized) 块允许您配置批处理作业以接受必需或可选的输入。您可以使用 nomad job dispatch 命令触发作业。
  • 周期性 (periodic) 块允许您安排 Nomad 作业在设置的时间运行。这些也被称为 Nomad cron jobs(类似于 K8s 中的 CronJob)。

示例应用程序 Pytechco 概述

示例应用程序 pytechco 模拟在一家技术公司工作的员工。他们联机,完成任务,然后注销。

跳转到本地计算机上示例 repo 的 jobs 目录:

bash 复制代码
cd jobs

下面每个组成应用程序的 jobspec 文件都将 driver 属性设置为 docker ,并使用 image 属性指定存储在 GHCR 中 config 块中的镜像。而 Redis 作业使用了 Docker Hub 上托管的官方 Redis 镜像。

Redis 服务

jobs/pytechco-redis.nomad.hcl 内容如下:

hcl 复制代码
task "redis-task" {
  driver = "docker"
  config {
    image = "redis:7.0.7-alpine"
  }
}

pytechco-redis.nomad.hcl -此服务作业运行并将 Redis 数据库暴露为 Nomad 服务,以供其他应用程序组件连接。jobspec 将类型设置为 service ,配置 Nomad service 块(类似于 K8s 中的 Service) 以使用 Nomad 原生服务发现 (Nomad native service discovery),并创建名为 redis-svc 的服务。具体如下:

HCL 复制代码
job "pytechco-redis" {
  type = "service"

  group "ptc-redis" {
    count = 1
    network {
      port "redis" {
        to = 6379
      }
    }

    service {
      name     = "redis-svc"
      port     = "redis"
      provider = "nomad"
    }

    task "redis-task" {
      driver = "docker"

      config {
        image = "redis:7.0.7-alpine"
        ports = ["redis"]
      }
    }
  }
}

以上代码说明如下:

  • type = "service": service type 的 job, 类似于 K8s 中的 Deployment
  • group "ptc-redis": group 块 ptc-redis
  • count = 1: 副本数为 1
  • to = 6379: 位于 network 块中,指示连接到 (to) 容器中的 6379 端口 (host 或 bridge 端口随机分派)
  • service {: service 块,类似于 K8s 中的 Service
  • provider = "nomad": Nomad 从 1.3 版本及以后,新增 Nomad native service. 🐾注意:如果不指定,默认使用 consul service.(前提是需要安装 consul)
  • task "redis-task" {: task 块,类似于 K8s 中的 Pod.
  • driver = "docker": Nomad 不同于 K8s. K8s 默认只支持一种运行时,即容器运行时;Nomad 默认就支持多种运行时 (nomad 的术语是driver), 典型如:docker, java, raw binarier, QEMU 等,这里指定使用 docker driver.
  • config {: 这里是特定于 docker 的 driver 的配置,包括:imageports
  • image = "redis:7.0.7-alpine": Docker Hub 的 redis:7.0.7-alpine" 镜像
  • ports = ["redis"]: 对外暴露的端口列表,这里是 redis, 即在 network 中定义的 to = 6379
Web 服务

pytechco-web.nomad.hcl -此服务作业运行 Web 应用程序前端,显示存储在数据库中的值和活动员工。jobspec 将类型设置为 service ,并为应用程序使用静态 端口 5000 。它还使用 nomadService 内置函数来获取 Redis 数据库服务的地址和端口信息。

HCL 复制代码
job "pytechco-web" {
  type = "service"

  group "ptc-web" {
    count = 1
    network {
      port "web" {
        static = 5000
      }
    }

    service {
      name     = "ptc-web-svc"
      port     = "web"
      provider = "nomad"
    }

    task "ptc-web-task" {
      template {
        data        = <<EOH
{{ range nomadService "redis-svc" }}
REDIS_HOST={{ .Address }}
REDIS_PORT={{ .Port }}
FLASK_HOST=0.0.0.0
REFRESH_INTERVAL=500
{{ end }}
EOH
        destination = "local/env.txt"
        env         = true
      }

      driver = "docker"

      config {
        image = "ghcr.io/hashicorp-education/learn-nomad-getting-started/ptc-web:1.0"
        ports = ["web"]
      }
    }
  }
}

详细说明如下(大部分和 redis 类似,这里不重复介绍了):

  • static = 5000: 位于 network 块中,指定静态 端口为 5000. 与to 不一样在于,to 指定内部端口,外部端口随机分派;static 内外部端口都相同,这里是 5000 端口。
  • template {: template 块。作用类似于 K8s 中的 ConfigMap.
  • data = <<EOH: 具体配置内容,这里是引用 nomadService 内置函数来获取 Redis 数据库服务的地址和端口信息。配置内容为 EOH 包裹的内容。
    • REDIS_HOST={{ .Address }}: 即运行后的分派 (alloc) 的外部(通常是 host) 地址
    • REDIS_PORT={{ .Port }}: 即运行后分派的外部端口(不是 6379), 是一个 20000-30000 之间的随机端口。
  • destination = "local/env.txt: 配置文件在分派后的位置。
  • env = true: 同时也将REDIS_HOST REDIS_PORT 等设置为分配 (alloc) 容器中的环境变量。
Setup Parameterized Batch

pytechco-setup.nomad.hcl -此参数化批处理作业 (parameterized batch job) 使用默认值设置数据库。您可以多次调度它来重置数据库。jobspec 将类型设置为 batch ,并有一个带有 meta_required 属性的 parameterized 块,在分派时需要 budget 的值。

HCL 复制代码
job "pytechco-setup" {
  type = "batch"

  parameterized {
    meta_required = ["budget"]
  }

  group "ptc-setup" {
    count = 1

    task "ptc-setup-task" {

      template {
        data        = <<EOH
{{ range nomadService "redis-svc" }}
REDIS_HOST={{ .Address }}
REDIS_PORT={{ .Port }}
{{ end }}
PTC_BUDGET={{ env "NOMAD_META_budget" }}
EOH
        destination = "local/env.txt"
        env         = true
      }
      driver = "docker"

      config {
        image = "ghcr.io/hashicorp-education/learn-nomad-getting-started/ptc-setup:1.0"
      }
    }
  }
}

具体说明如下:

  • type = "batch" Job 类型为 batch, 类似于 K8s 中的 JobCronJob
  • parameterized {: 该 Job 有一个带有 meta_required 属性的 parameterized 块,在分派时需要 budget 的值
  • PTC_BUDGET={{ env "NOMAD_META_budget }} 获取环境变量 NOMAD_META_budget 的值并赋给 PTC_BUDGET
Employee Periodic Batch

pytechco-employee.nomad.hcl -此定期批处理作业使员工联机。它随机化了员工的工作类型和其他变量,如他们工作的时间和他们完成任务的速度。jobspec 将类型设置为 batch ,并有一个 periodic 块将 cron 属性设置为允许它每 3 秒启动一个新作业的值。

HCL 复制代码
job "pytechco-employee" {
  type = "batch"

  periodic {
    cron             = "0/3 * * * * * *"
    prohibit_overlap = false
  }

  group "ptc-employee" {
    count = 1

    task "ptc-employee-task" {

      restart {
        attempts = 2
        delay    = "15s"
        interval = "10s"
        mode     = "fail"
      }

      template {
        data        = <<EOH
{{ range nomadService "redis-svc" }}
REDIS_HOST={{ .Address }}
REDIS_PORT={{ .Port }}
PTC_EMPLOYEE_ID={{ env "NOMAD_SHORT_ALLOC_ID"}}
{{ end }}
EOH
        destination = "local/env.txt"
        env         = true
      }
      driver = "docker"

      config {
        image = "ghcr.io/hashicorp-education/learn-nomad-getting-started/ptc-employee:1.0"
        // args = [
        //     "--employee-type", "sales_engineer"
        // ]
      }
    }
  }
}

具体说明如下:

  • periodic {: type = "batch" 再加上 periodic, 就类似于 K8s 中的 CronJob
  • restart {: Batch 执行过程中的异常重启机制配置。
  • PTC_EMPLOYEE_ID={{ env "NOMAD_SHORT_ALLOC_ID"}}: 将环境变量 NOMAD_SHORT_ALLOC_ID(该环境变量由 Nomad 生成,类似于 K8s 的 pod name) 赋值给 PTC_EMPLOYEE_ID
  • // args = [: // HCL 中的注释,此行不起作用。argsdocker driver config 中的 args 配置。

从 Nomad 1.5.0 开始, datacenter 属性默认为集群中所有可用的数据中心( "*" )。因此,本教程的作业规范将省略该属性,因为默认值已足够。如果您运行的是较早版本的 Nomad CLI 和集群二进制文件,则需要包含并设置该属性。

部署应用程序

具体命令如下:

提交数据库 Job:

shell 复制代码
$ nomad job run pytechco-redis.nomad.hcl
==> 2023-03-10T12:16:09-05:00: Monitoring evaluation "d44af37b"
    2023-03-10T12:16:09-05:00: Evaluation triggered by job "pytechco-redis"
    2023-03-10T12:16:10-05:00: Evaluation within deployment: "0ea05651"
    2023-03-10T12:16:10-05:00: Allocation "be0bda79" created: node "2c9f4b7e", group "ptc-redis"
    2023-03-10T12:16:10-05:00: Evaluation status changed: "pending" -> "complete"
==> 2023-03-10T12:16:10-05:00: Evaluation "d44af37b" finished with status "complete"
==> 2023-03-10T12:16:10-05:00: Monitoring deployment "0ea05651"
  ✓ Deployment "0ea05651" successful
    
    2023-03-10T12:16:24-05:00
    ID          = 0ea05651
    Job ID      = pytechco-redis
    Job Version = 0
    Status      = successful
    Description = Deployment completed successfully
    
    Deployed
    Task Group  Desired  Placed  Healthy  Unhealthy  Progress Deadline
    ptc-redis   1        1       1        0          2023-03-10T17:26:23Z

提交 web Job:

bash 复制代码
nomad job run pytechco-web.nomad.hcl

获取 webapp 的 IP 地址。以下命令获取 Web 作业的分配 ID,并使用该 ID 获取分配的状态。然后,它在分配状态输出中搜索 IP 地址,并将 IP 地址格式化为与 webapp 端口的链接。在浏览器中打开输出中的 URL 以查看 webapp 前端。

bash 复制代码
nomad node status -verbose \
    $(nomad job allocs pytechco-web | grep -i running | awk '{print $2}') | \
    grep -i ip-address | awk -F "=" '{print $2}' | xargs | \
    awk '{print "http://"$1":5000"}'

提交 Setup Job:

bash 复制代码
nomad job run pytechco-setup.nomad.hcl

通过提供 budget 值分派该 setup job:

shell 复制代码
$ nomad job dispatch -meta budget="200" pytechco-setup
Dispatched Job ID = pytechco-setup/dispatch-1678468734-396cfa83
Evaluation ID     = 53a77034

==> 2023-03-10T12:18:54-05:00: Monitoring evaluation "53a77034"
    2023-03-10T12:18:54-05:00: Evaluation triggered by job "pytechco-setup/dispatch-1678468734-396cfa83"
    2023-03-10T12:18:54-05:00: Allocation "d6c60ffd" created: node "2c9f4b7e", group "ptc-setup"
    2023-03-10T12:18:54-05:00: Evaluation status changed: "pending" -> "complete"
==> 2023-03-10T12:18:54-05:00: Evaluation "53a77034" finished with status "complete"

提交 Employee Job:

bash 复制代码
nomad job run pytechco-employee.nomad.hcl

跳转到 Nomad UI,单击 "Jobs " 页面,然后单击 pytechco-employee job。由于这是一个 cron batch job,您可以看到它每 3 秒创建一个新作业。

跳转回 webapp URL。效果如下:

更新应用程序

首先,停止 employee job:

bash 复制代码
nomad job stop -purge pytechco-employee

通过使用新 budget 500 再次分派 setup job 来重置数据库:

shell 复制代码
$ nomad job dispatch -meta budget="500" pytechco-setup
Dispatched Job ID = pytechco-setup/dispatch-1678469008-6ffe1c0c
Evaluation ID     = e8e420f0

==> 2023-03-10T12:23:28-05:00: Monitoring evaluation "e8e420f0"
    2023-03-10T12:23:28-05:00: Evaluation triggered by job "pytechco-setup/dispatch-1678469008-6ffe1c0c"
    2023-03-10T12:23:28-05:00: Allocation "74acf63e" created: node "2c9f4b7e", group "ptc-setup"
    2023-03-10T12:23:28-05:00: Evaluation status changed: "pending" -> "complete"
==> 2023-03-10T12:23:28-05:00: Evaluation "e8e420f0" finished with status "complete"

打开 pytechco-employee.nomad.hcl 文件并取消注释任务配置的 args 块,使作业仅创建类型为 sales_engineer 的员工。然后将cron更新为 0/1 * * * * * * ,使作业每秒运行一次。保存文件。

HCL 复制代码
...
        cron = "0/1 * * * * * *"
...

        args = [
            "--employee-type", "sales_engineer"
        ]
...

再次提交 employee job 并跳转到 Web 应用程序。请注意,所有在线员工现在都只是销售工程师 (sales_enginee)(之前是有多个不同的员工类型),而且他们中的更多人在任何给定时间都在线。

shell 复制代码
$ nomad job run pytechco-employee.nomad.hcl
Job registration successful
Approximate next launch time: 2023-03-10T17:24:18Z (1s from now)

清理应用程序

停止并清理所有 Jobs:

bash 复制代码
nomad job stop -purge pytechco-employee
nomad job stop -purge pytechco-web
nomad job stop -purge pytechco-redis
nomad job stop -purge pytechco-setup

总结

本文中,我们一起了解了 Nomad 的术语,并根据官方 Demo, 部署和更新了 Nomad Job。同时穿插了解了 Nomad 和 K8s 的一些类比和对比。

后面就正式进入具体实战环节,包括:Nomad 与 Traefik 和 Tailscale 的集成等独家内容。敬请期待。💪💪💪

📚️参考文档

三人行, 必有我师; 知识共享, 天下为公. 本文由东风微鸣技术博客 EWhisper.cn 编写.

相关推荐
众人皆醒我独醉6 小时前
Pod 一直 Terminating,死活删不掉?三个凶手,每一个你都意想不到
面试·kubernetes
飞翔沫沫情8 小时前
K8s Alloy 采集 Pod 控制台日志
云原生·容器·kubernetes
潮起鲸落入海13 小时前
Kubernetes Metric Server, Quota and Limits
容器·kubernetes
摇滚侠14 小时前
云原生 Java 架构师的第一课 K8s+Docker+KubeSphere+DevOps 19-25
java·云原生·kubernetes
咕噜咕噜的猪大侠16 小时前
《K8s 核心知识梳理:Deployment 滚动更新、JobCronJob、DaemonSet 和 Service》
云原生·容器·kubernetes
摇滚侠16 小时前
云原生 Java 架构师的第一课 K8s+Docker+KubeSphere+DevOps 26-40
java·云原生·kubernetes
AOwhisky1 天前
kubernetes(K8s)学习笔记:第十期与第十一期核心知识点自测与详解
运维·笔记·云原生·kubernetes·云计算·k8s·hpa
Waay2 天前
面试口述版:个人对 Prometheus 完整理解
运维·学习·云原生·面试·职场和发展·kubernetes·prometheus
云烟成雨TD2 天前
Kubernetes 系列【4】基础概念
云原生·容器·kubernetes