> For the complete documentation index, see [llms.txt](https://v2.dataos.info/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://v2.dataos.info/concepts/resources/service.md).

# Service

A Service is a long-running DataOS workload that runs continuously and exposes one or more network ports. Use a Service when an application must stay available to receive traffic, serve APIs, process streams, or host a server such as Postgres, an HTTP API, or a custom containerized application.

Services are different from Workflows. A Workflow runs one or more jobs and then completes. A Service is reconciled as a running workload and remains active until it is updated, suspended, or deleted.

## Prerequisites

To create a Service, you need a tenant-specific role (**Tenant Admin** or **Data Developer**).

To use a Service, you need resource-specific permission granted by the Service owner.

## When to use

Use a Service when you need to:

* Run a long-lived process.
* Expose TCP or HTTP ports.
* Host a custom container image.
* Run a stateful application with an attached disk or Volume.
* Keep one or more replicas of the same application available.

Common examples include API servers, model-serving endpoints, webhook receivers, streaming consumers, and test databases used by other workloads.

## Manifest structure

A Service manifest uses the common Resource metadata fields and a `spec` section that defines how the service runs.

```yaml
version: v2alpha
name: ${{service-name}}
type: service
tags:
  - ${{tag}}
description: ${{description}}
spec:
  hostname: ${{service-hostname}}
  compute: ${{compute-resource}}
  replicas: ${{replica-count}}
  servicePorts:
    - name: ${{port-name}}
      port: ${{port-number}}
  stack: ${{stack-name}}
  stackSpec:
    ${{stack-specific-configuration}}
```

## Core concepts

### Ports

`servicePorts` declares the ports exposed by the Service. Each port requires a `name` and a numeric `port`.

```yaml
spec:
  servicePorts:
    - name: postgres
      port: 5432
```

For TCP services, consumers can resolve the Service endpoint from the Service runtime metadata. For HTTP services, configure the container to listen on the declared port and add any ingress configuration supported by the runtime.

### Replicas

`replicas` controls how many identical Service instances are maintained. Use more than one replica for stateless services that can handle traffic concurrently. Stateful services, such as a single Postgres instance, commonly run with `replicas: 1`.

```yaml
spec:
  replicas: 1
```

### Stateful Services

Set `stateful: true` when the Service needs stable identity or attached storage.

```yaml
spec:
  stateful: true
```

Stateful Services can use either inline disk storage or an existing Volume Resource:

* Use `disk` when storage belongs to the Service lifecycle and can be deleted with the Service.
* Use `use.volumes` when the data must persist independently of the Service.

See also: [Provision inline storage](/concepts/resources/service.md) and [Persist storage across workloads](/concepts/resources/service.md).

### Stack and stackSpec

`stack` selects the runtime stack. `stackSpec` contains stack-specific configuration. For the `container` stack, provide the container image, command, and arguments.

```yaml
spec:
  stack: container
  stackSpec:
    image: docker.io/library/postgres:18-alpine
    command:
      - docker-entrypoint.sh
    arguments:
      - postgres
```

### Projections

Use `use.projection` to project Secrets, environment variables, and files into the Service runtime. The following example reads `POSTGRES_PASSWORD` from a Secret and exposes it as an environment variable.

```yaml
spec:
  use:
    projection:
      templateType: liquid
      secrets:
        - id: ${{tenant-id}}:${{secret-name}}
          contextAlias: pgSecret
      projections:
        envVars:
          - key: POSTGRES_PASSWORD
            template: "{{ secrets['pgSecret'].POSTGRES_PASSWORD }}"
```

## Example: TCP Postgres Service with inline disk

This example runs Postgres as a stateful TCP Service. The `disk` block provisions storage mounted at `/var/lib/postgresql/data`. The disk is tied to the Service lifecycle.

{% tabs %}
{% tab title="Secret" %}

```yaml
name: ${TCP_PG_SECRET_NAME}
version: v2alpha
type: secret
description: "Password for TCP Postgres service"
layer: user
secret:
  type: key-value
  data:
    POSTGRES_PASSWORD: ${TCP_PG_PASSWORD}
```

{% endtab %}

{% tab title="Service" %}

```yaml
version: v2alpha
name: ${TCP_PG_SERVICE_NAME}
type: service
tags:
  - postgres
  - database
  - test
description: "Single replica stateful Postgres service for TCP connectivity test"
spec:
  hostname: ${TCP_PG_SERVICE_NAME}
  compute: ${COMPUTE_NAME}
  stateful: true
  replicas: 1
  servicePorts:
    - name: postgres
      port: 5432
  resources:
    requests:
      cpu: 250m
      memory: 512Mi
    limits:
      cpu: "1"
      memory: 1Gi
  disk:
    size: 10Gi
    type: disk
    mountPath: /var/lib/postgresql/data
  use:
    projection:
      templateType: liquid
      secrets:
        - id: ${ENTITY_TENANT_ID}:${TCP_PG_SECRET_NAME}
          contextAlias: pgSecret
      projections:
        envVars:
          - key: POSTGRES_PASSWORD
            template: "{{ secrets['pgSecret'].POSTGRES_PASSWORD }}"
          - key: POSTGRES_USER
            templateType: none
            template: "postgres"
          - key: POSTGRES_DB
            templateType: none
            template: "postgres"
          - key: PGDATA
            templateType: none
            template: "/var/lib/postgresql/data/pgdata"
  stack: container
  stackSpec:
    image: docker.io/library/postgres:18-alpine
    command:
      - docker-entrypoint.sh
    arguments:
      - postgres
```

{% endtab %}
{% endtabs %}

## Example: TCP Postgres Service with existing Volume

Use `use.volumes` when the database files must live in a Volume Resource whose lifecycle is managed separately from the Service.

```yaml
version: v2alpha
name: ${TCP_PG_SERVICE_NAME}vol
type: service
tags:
  - postgres
  - database
  - test
description: "Single replica stateful Postgres service for TCP connectivity test"
spec:
  hostname: ${TCP_PG_SERVICE_NAME}vol
  compute: ${COMPUTE_NAME}
  stateful: true
  replicas: 1
  servicePorts:
    - name: postgres
      port: 5432
  resources:
    requests:
      cpu: 250m
      memory: 512Mi
    limits:
      cpu: "1"
      memory: 1Gi
  use:
    volumes:
      - id: ${TCP_PG_VOLUME_ID}
        directory: /var/lib/postgresql/data
        readOnly: false
    projection:
      templateType: liquid
      secrets:
        - id: ${ENTITY_TENANT_ID}:${TCP_PG_SECRET_NAME}vol
          contextAlias: pgSecret
      projections:
        envVars:
          - key: POSTGRES_PASSWORD
            template: "{{ secrets['pgSecret'].POSTGRES_PASSWORD }}"
          - key: POSTGRES_USER
            templateType: none
            template: "postgres"
          - key: POSTGRES_DB
            templateType: none
            template: "postgres"
          - key: PGDATA
            templateType: none
            template: "/var/lib/postgresql/data/pgdata"
  stack: container
  stackSpec:
    image: docker.io/library/postgres:18-alpine
    command:
      - docker-entrypoint.sh
    arguments:
      - postgres
```

## Deploy with a Bundle

For Services that depend on Secrets, Volumes, or verification Workflows, package the resources in a Bundle so dependencies are applied in order.

```yaml
version: v2alpha
name: test-service-tcp-postgres
type: bundle
description: "Integration test: deploy stateful Postgres service, verify TCP connectivity on port 5432"
tags:
  - test
  - service
  - tcp
  - postgres
bundle:
  resources:
    - id: tcp-pg-secret
      file: tests/service/tcp-postgres/secret.yaml

    - id: tcp-pg-service
      file: tests/service/tcp-postgres/service.yaml
      dependencies:
        - tcp-pg-secret
      dependencyConditions:
        - resourceId: tcp-pg-secret
          status:
            is:
              - active

    - id: verify-tcp-pg
      file: tests/service/tcp-postgres/verify-workflow.yaml
      dependencies:
        - tcp-pg-service
      dependencyConditions:
        - resourceId: tcp-pg-service
          status:
            is:
              - active
          runtime:
            contains:
              - "running"
```

## Apply and manage

Apply the Secret before applying the Service, unless both are packaged in a Bundle.

```bash
dataos-ctl resource apply -f secret.yaml
dataos-ctl resource apply -f service.yaml
```

Apply a Bundle:

```bash
dataos-ctl resource apply -f bundle.yaml
```

Check the Service:

```bash
dataos-ctl resource get -t service -n ${{service-name}} -d
```

Delete the Service:

```bash
dataos-ctl resource delete -t service -n ${{service-name}}
```

{% hint style="warning" %}
If the Service uses an inline `disk`, deleting the Service also deletes the disk and its data. If the Service mounts an existing Volume with `use.volumes`, deleting the Service does not delete the Volume.
{% endhint %}

## Field reference

| Field           | Description                                | Required |
| --------------- | ------------------------------------------ | -------- |
| `version`       | Manifest version. Use `v2alpha`.           | Yes      |
| `name`          | Service Resource name.                     | Yes      |
| `type`          | Resource type. Use `service`.              | Yes      |
| `tags`          | Labels for grouping and discovery.         | No       |
| `description`   | Human-readable description of the Service. | No       |
| `spec`          | Service runtime specification.             | Yes      |
| `spec.hostname` | Hostname assigned to the Service.          | No       |
| `spec.compute`  | Compute Resource used to run the Service.  | Yes      |

| Field                          | Description                                                             | Required                         |
| ------------------------------ | ----------------------------------------------------------------------- | -------------------------------- |
| `version`                      | Manifest version. Use `v2alpha`.                                        | Yes                              |
| `name`                         | Service Resource name.                                                  | Yes                              |
| `type`                         | Resource type. Use `service`.                                           | Yes                              |
| `tags`                         | Labels for grouping and discovery.                                      | No                               |
| `description`                  | Human-readable description of the Service.                              | No                               |
| `spec`                         | Service runtime specification.                                          | Yes                              |
| `spec.hostname`                | Hostname assigned to the Service.                                       | No                               |
| `spec.compute`                 | Compute Resource used to run the Service.                               | Yes                              |
| `spec.stateful`                | Enables stateful runtime behavior. Required for inline Service storage. | No                               |
| `spec.replicas`                | Number of Service replicas to maintain.                                 | No                               |
| `spec.servicePorts`            | List of exposed Service ports.                                          | No                               |
| `spec.servicePorts[].name`     | Logical name for the exposed port.                                      | Yes, when `servicePorts` is used |
| `spec.servicePorts[].port`     | Numeric port exposed by the Service.                                    | Yes, when `servicePorts` is used |
| `spec.resources.requests`      | CPU and memory requested for the Service runtime.                       | No                               |
| `spec.resources.limits`        | CPU and memory limits for the Service runtime.                          | No                               |
| `spec.disk`                    | Inline disk mounted into the Service.                                   | No                               |
| `spec.disk.size`               | Requested inline disk size, such as `10Gi`.                             | Yes, when `disk` is used         |
| `spec.disk.type`               | Inline storage type. Use `disk`.                                        | Yes, when `disk` is used         |
| `spec.disk.mountPath`          | Container path where the inline disk is mounted.                        | Yes, when `disk` is used         |
| `spec.use.volumes`             | Existing Volume mounts consumed by the Service.                         | No                               |
| `spec.use.volumes[].id`        | Volume Resource identifier.                                             | Yes, when `use.volumes` is used  |
| `spec.use.volumes[].directory` | Container path where the Volume is mounted.                             | Yes, when `use.volumes` is used  |
| `spec.use.volumes[].readOnly`  | Mounts the Volume as read-only when set to `true`.                      | No                               |
| `spec.use.projection`          | Projects Secrets, environment variables, and files into the runtime.    | No                               |
| `spec.stack`                   | Runtime stack used by the Service, such as `container`.                 | Yes                              |
| `spec.stackSpec`               | Stack-specific runtime configuration.                                   | Yes                              |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://v2.dataos.info/concepts/resources/service.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
