What production-ready means before you deploy an AI agent to cloud
Your agent works on your laptop. That is the easy 20 percent. People search for how to deploy AI agent to cloud and hope for a single command. The real work is closing the gap between "runs on my machine" and "runs unattended, survives a crash, and someone other than you can debug it at 2am." To deploy an AI agent to cloud and trust it with real traffic, treat production readiness as a checklist, not one deploy command.
The good news is that the steps are the same whether your agent is a LangChain research bot, a customer-support assistant, or an autonomous coding agent. Containerize it, pull configuration and secrets out of the code, choose a runtime, add restart and health checks, wire up logging and metrics, handle persistent state, cap its resources, and verify. Do those eight things and you have a deployment you can sleep through. Everything below is what it takes to deploy an AI agent to cloud you can actually trust.
The tempting shortcut is to skip all of this and leave the agent running in a terminal on your laptop, or in a screen session on some random VM. It works right up until your laptop sleeps, your wifi drops, or the process dies and nobody notices for a day. The steps below are the difference between a demo that impresses in a meeting and something you can leave in front of real users.
If this is your first time moving an agent off your machine, the cost tradeoffs in the cheapest way to host an AI agent 24/7 are worth reading first, so you pick a target that will not fall over the week after you launch.
Step 1: Containerize your agent with a Dockerfile
A container is the unit of deployment everywhere that matters, so this is step one. It pins your Python or Node version, your system libraries, and your dependencies into one artifact that runs the same on every host. Here is a lean, production-shaped Dockerfile for a Python agent:
FROM python:3.12-slim
# System deps first so they cache across code changes
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates curl && rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Install deps in their own layer for fast rebuilds
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Then the app code
COPY . .
# Run as a non-root user
RUN useradd --create-home appuser
USER appuser
# Config comes from the environment, never baked in
ENV PYTHONUNBUFFERED=1
EXPOSE 8080
CMD ["python", "main.py"]FROM python:3.12-slim
# System deps first so they cache across code changes
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates curl && rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Install deps in their own layer for fast rebuilds
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Then the app code
COPY . .
# Run as a non-root user
RUN useradd --create-home appuser
USER appuser
# Config comes from the environment, never baked in
ENV PYTHONUNBUFFERED=1
EXPOSE 8080
CMD ["python", "main.py"]Three details make this production-shaped rather than a toy: dependencies install in their own layer so rebuilds are fast, the container runs as a non-root appuser instead of root, and configuration comes from the environment instead of the image. The official Docker build best practices cover the rest worth following.
Step 2: Externalize config and secrets
Never bake API keys, database URLs, or model endpoints into the image. If you do, every rebuild bakes them into layers, and rotating a key means rebuilding and redeploying. Pull all of it out into the environment instead:
Non-secret config (log level, model name, feature flags) goes in environment variables or a mounted config file.
Secrets (API keys, tokens, database passwords) go in a real secret store: Kubernetes Secrets, your cloud provider's secret manager, or a managed runtime's secret storage. Never in git, never in the image.
In code, read them at startup and fail loudly if a required one is missing. An agent that boots without its model API key and only discovers this on the first user request is a worse outage than one that refuses to start at all.
Step 3: Choose where the agent runs
Where you deploy shapes how much plumbing you own. There is real spread here, so match the target to the stakes.
| Target | You manage | Best for |
|---|---|---|
| Single cloud VM | OS, restart, backups, scaling, TLS | One small agent, full control |
| Container platform (ECS, Cloud Run, Fly) | App plus config, platform handles hosts | Most single-service agents |
| Kubernetes | Cluster, manifests, networking, upgrades | Many services, teams, fine-grained control |
| Managed agent runtime | Just the agent | Skipping the ops entirely |
Kubernetes is the standard for running many long-lived services with restart policies, resource limits, secrets, and network policies built in. It is also a lot to learn and a lot to operate. If you want those guarantees (automatic restarts, resource limits, secret handling, access control) without writing manifests or babysitting the infrastructure, a managed runtime like Sokko runs your agent on secure cloud infrastructure we manage for you and hands you a terminal, so the plumbing is already done. For a fuller comparison of runtimes for continuous agents, see run any AI agent 24/7 on Sokko.
A rule of thumb for choosing: if you are deploying one or two agents and want them online this afternoon, a container platform like Cloud Run or Fly is the least effort for the most reliability. Reach for raw Kubernetes when you are running many services, need tight control over networking and scheduling, or already have a cluster and a team to run it. Reach for a managed agent runtime when you want those guarantees but not the homework that comes with them.
Step 4: Add restart, health checks, and observability
An agent will crash. A dependency times out, the model API returns a 500, or a memory spike trips the OOM killer. Production means the agent comes back on its own and tells you what happened.
Restart-on-crash. On Kubernetes this is the default pod restart policy. On a VM, use a systemd unit or
docker run --restart=always. Either way, a dead process should never stay dead silently.Health checks. Expose a small HTTP endpoint, say
/healthz, that returns 200 when the agent is alive and its dependencies are reachable. Kubernetes liveness and readiness probes hit it to decide whether to restart or route traffic. A failing liveness probe restarts the pod; a failing readiness probe just pulls it out of rotation until it recovers.Logging. Write structured logs to stdout so the platform can collect them. Include a request or trace id so you can follow one agent run across many log lines.
Metrics. Export request counts, latencies, error rates, and token usage. Prometheus is the common choice, and most platforms scrape its format natively.
Agents need one thing beyond the usual web metrics: visibility into what the agent actually did. Log every tool call, every model request with its token count, and every decision the agent took, so that when it behaves strangely you can replay the reasoning instead of guessing. Token usage in particular is both your cost line and an early warning, because a sudden spike almost always means the agent is stuck in a loop.
Put a reverse proxy (nginx, Caddy, or Traefik) in front to terminate TLS and route to the app, and external users only ever see a clean HTTPS URL.
A short note on health checks
A health check is not the same as "the process is running." A useful check confirms the agent can do its job: reach the model API and its datastore. Keep it cheap, though, because probes fire every few seconds. Split liveness from readiness:
@app.get("/healthz")
def healthz():
# liveness: the process is up and serving
return {"status": "ok"}, 200
@app.get("/readyz")
def readyz():
# readiness: dependencies are reachable
if not model_client.ping() or not db.ping():
return {"status": "degraded"}, 503
return {"status": "ready"}, 200@app.get("/healthz")
def healthz():
# liveness: the process is up and serving
return {"status": "ok"}, 200
@app.get("/readyz")
def readyz():
# readiness: dependencies are reachable
if not model_client.ping() or not db.ping():
return {"status": "degraded"}, 503
return {"status": "ready"}, 200Liveness answers "should you restart me," and it should stay green as long as the process can serve, or the platform will kill a pod that was only briefly busy. Readiness answers "should you send me traffic," and it can return a 503 while a dependency recovers without ever triggering a restart loop. A health endpoint is a handful of lines, and it pays for itself the first time a probe restarts a wedged agent before anyone files a ticket.
Step 5: Persist state and cap resources, then verify
Two things separate a demo from a deployment: state that survives a restart, and limits that stop one bad run from taking down the host.
Persistent state. Containers are ephemeral, so anything the agent must keep (conversation history, a vector index, uploaded files) has to live on a volume or an external service, not the container filesystem. Use a mounted volume, an object store, or a managed database. If your agent writes files as it works, it needs a persistent workspace that outlives any single container. A concrete case: an autonomous coding agent that edits files needs those files to still be there after a redeploy. If the workspace lives inside the container, a routine restart wipes hours of work. Mount it on a persistent volume, or pick a runtime that gives the agent a durable workspace by default.
Resource limits. Set memory and CPU limits so a runaway loop or a giant context window cannot starve everything else. On Kubernetes these are pod requests and limits; on a VM, the --memory and --cpus flags on docker run. Limits turn a vague "the box got slow" into a clean, attributable restart.
Verify. Do not trust a green deploy. Actually exercise it:
Hit the health endpoint and confirm a 200.
Send a real request and check the agent responds correctly end to end.
Kill the process and confirm it restarts on its own within seconds.
Rotate a secret and confirm the agent picks up the new value on restart.
Watch memory under a realistic load and confirm it stays under the limit you set.
Deploy AI agent to cloud: the production checklist
Print this and tick it off before you point real traffic at the agent. This is the short version of everything it takes to deploy an AI agent to cloud without regrets:
Agent runs in a container from a pinned base image, as a non-root user.
All config and secrets come from the environment or a secret store, none baked in.
A runtime is chosen and matched to how much ops you want to own.
Restart-on-crash is enabled and tested.
A
/healthzendpoint exists and probes are wired to it.Logs go to stdout as structured JSON with a trace id.
Metrics are exported and scraped.
Persistent state lives on a volume or external service, not the container.
Memory and CPU limits are set.
You verified restart, secret rotation, and behavior under load by hand.
If that list feels like a lot of infrastructure for one agent, that is the honest tradeoff: you either run the plumbing or you pay a platform to run it. For a first end-to-end run through a single agent, the deploying your first agent walkthrough is the shortest path. Sokko exists for the case where you want every item on this checklist handled for you: always-on infrastructure we manage, automatic restarts, secure secrets, resource limits, observability, and a persistent workspace, reached through a terminal at https://your-agent.sokko.ai after sokko login. Whichever target you pick, ship the checklist, not just the container.