> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orcra.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy a container application with Orcra Run

> Write a Deployment manifest, commit it to your manifest repository, and have orun pull and run the container on your node within seconds.

orun follows a pull-based model: you declare what you want in a YAML manifest, commit it to your manifest Git repository, and every node tracking that branch reconciles the change within seconds. There is no imperative `deploy` command — pushing a commit is the deployment.

## Before you start

Make sure you have:

* A bootstrapped node tracking your manifest repository (see [Bootstrap a server as an orun node over SSH](/guides/bootstrap-a-node))
* A manifest Git repository with at least one branch the node is configured to track

<Steps>
  <Step title="Create the deployment manifest">
    Create the file `deployments/hello-world.yaml` in your manifest repository:

    ```yaml theme={null}
    apiVersion: run.orcra.dev/v0alpha
    kind: Deployment
    metadata:
      name: hello-world
    spec:
      image: traefik/whoami
      ports:
        - containerPort: 80
          port: 8080
      health:
        readiness:
          http: localhost:80/health
        liveness:
          http: localhost:80/health
      env:
        LOG_FORMAT: json
    ```

    **Key fields:**

    | Field                        | Description                                       |
    | ---------------------------- | ------------------------------------------------- |
    | `spec.image`                 | Container image to pull and run                   |
    | `spec.ports[].containerPort` | Port the container exposes internally             |
    | `spec.ports[].port`          | Host port to bind on the node                     |
    | `spec.health.readiness.http` | HTTP endpoint orun polls for readiness            |
    | `spec.health.liveness.http`  | HTTP endpoint orun polls for liveness             |
    | `spec.env`                   | Environment variables injected into the container |
  </Step>

  <Step title="Commit and push to the tracked branch">
    ```bash theme={null}
    git add deployments/hello-world.yaml
    git commit -m "Add hello-world deployment"
    git push
    ```

    Push to the branch your node is configured to track (default: `main`). Pushing to a different branch has no effect on nodes that do not track it.
  </Step>

  <Step title="Wait for the node to poll and apply">
    The node polls the manifest repository on the interval configured during bootstrap (default: `5s`). Within a few seconds of your push, orun fetches the new manifest and starts the container.

    <Note>
      If the image pull fails — for example due to a network error or a missing registry credential — orun logs the error and retries automatically on the next reconcile cycle.
    </Note>
  </Step>

  <Step title="Verify the container is running">
    From your local machine, curl the node on the host port you configured:

    ```bash theme={null}
    curl http://<node-ip>:8080
    ```

    The `traefik/whoami` image responds with the request headers and container metadata, confirming the deployment is live.
  </Step>

  <Step title="Check the deployment status via the status API">
    orun exposes a lightweight HTTP status API on port `9100` (localhost on the node). Query it over SSH or an existing tunnel:

    ```bash theme={null}
    curl -X POST http://<node-ip>:9100/status
    ```

    The response is a `NodeReport` JSON object containing the state of every deployment the node manages, including each deployment's lifecycle state (`pending`, `running`, `stopped`, or `errored`) and any error details.

    ```bash theme={null}
    # Simple liveness check
    curl -X POST http://<node-ip>:9100/healthz
    # → {"status":"ok"}
    ```
  </Step>
</Steps>

<Info>
  The poll interval defaults to `5s` and is set per-node in the node manifest via the `pollInterval` field (e.g., `pollInterval: 30s`). Shorter intervals mean faster convergence; longer intervals reduce Git API load.
</Info>

<CardGroup cols={2}>
  <Card title="Enable HTTPS ingress" icon="lock" href="/guides/ssl-and-ingress">
    Expose this deployment on a custom domain with automatic TLS via Caddy.
  </Card>

  <Card title="Build images locally" icon="wrench" href="/guides/local-image-builds">
    Build container images directly on the node from source instead of pulling from a registry.
  </Card>
</CardGroup>
