How an AI Agent Deployed This Blog
This blog was deployed to Kubernetes by an AI agent using Claude Code. Here is the full workflow — from the first prompt to a live, TLS-secured Ghost blog in ten steps.
This blog — the one you're reading right now — was deployed to Kubernetes by an AI agent. Not generated from a template. Not copied from a tutorial. An agentic workflow that explored a live cluster, planned the deployment, wrote the manifests, hit a real error, fixed it, and brought the site online.
Here's exactly how that happened.
The Setup
I use Claude Code, Anthropic's CLI tool for Claude, as part of my development workflow. It has direct access to my terminal, can run shell commands, read and write files, and — critically — it can use kubectl against my live Kubernetes cluster.
The cluster is a 3-node Civo K3s setup that already runs several apps. I wanted to add a Ghost blog.
The First Prompt
I started with a single, open-ended request:
"I want to deploy ghost blogging platform to civo k8s. Can you use kubectl to plan this please? Also, is it possible to have multiple blogs on the same instance?"
I used Claude Code's plan mode, which tells the agent to research and plan before making any changes. This is important — I didn't want it jumping straight into applying manifests against a live cluster without understanding the landscape first.
The Agent Explores
Before proposing anything, Claude ran several kubectl commands in parallel to understand the cluster:
kubectl config current-contextandkubectl get nodes— to confirm which cluster it was working withkubectl get namespacesandkubectl get storageclass— to understand the existing structurekubectl get ingress --all-namespaces— to learn the ingress pattern already in usekubectl get clusterissuer— to check TLS certificate setup
It discovered the cluster uses Traefik for ingress, cert-manager with a Let's Encrypt ClusterIssuer, and the civo-volume storage class. It also noticed the one-namespace-per-app convention from existing deployments.
This is the part that separates an agentic workflow from a chatbot conversation. The agent didn't ask me what ingress controller I use or whether I had cert-manager installed — it looked.
Answering the Multi-Blog Question
Claude answered the Ghost question directly: no, Ghost doesn't support multiple blogs per instance. Each Ghost process serves one site. It noted that multiple blogs would need separate deployments, but could share a MariaDB server with separate databases.
This kind of domain knowledge combined with infrastructure awareness is where the workflow starts to feel genuinely useful.
Interactive Planning
The agent then asked me focused questions rather than making assumptions:
- What domain? — It offered suggestions based on my existing domains but let me specify. I chose
agenticadventures.blog. - How many blogs? — Just one to start.
These weren't open-ended questions. They were multiple choice with sensible defaults, which kept the planning moving quickly.
Course Corrections
During planning, I made three corrections that shaped the final result:
"Don't store secrets in chat"
The initial plan mentioned generating passwords and storing them in secrets. I flagged that I didn't want any credentials appearing in the conversation history. Claude immediately adjusted — the deploy script now generates passwords inline with openssl rand directly inside the kubectl create secret command. No secrets ever appear in files, plans, or chat.
"Can we use MariaDB?"
The original plan used MySQL 8.0. I prefer MariaDB. A quick correction and the plan was updated — image changed to mariadb:11, environment variables updated to MARIADB_*, and the health check switched to MariaDB's native healthcheck.sh.
"What do I point the A record to?"
The plan initially suggested a CNAME to Civo's load balancer hostname. But for an apex domain like agenticadventures.blog, you need an A record. Claude ran dig to resolve the load balancer hostname to its IP address and updated the plan with the specific A record to create.
Each correction took seconds. The agent didn't start over — it made targeted updates to the plan and moved on.
Capacity Check
I asked Claude to check whether the cluster had room for the new workloads. It ran kubectl top nodes and presented a capacity table:
| Node | CPU Actual | CPU Requests | Memory Actual | Memory Requests |
|---|---|---|---|---|
| Node 1 | 109% | 63% | 83% | 52% |
| Node 2 | 7% | 65% | 50% | 54% |
| Node 3 | 11% | 52% | 28% | 28% |
Ghost + MariaDB would need 500m CPU and 512Mi memory in requests — easily fitting on Node 3 with 48% CPU and 72% memory headroom. This gave me confidence to proceed without worrying about resource pressure.
Project Structure
Rather than applying manifests inline, I asked Claude to create a proper project folder with documentation. It created:
~/Projects/blogs/agenticadventures/
├── README.md
├── deploy.sh
└── k8s/
├── namespace.yaml
├── mariadb-statefulset.yaml
├── mariadb-service.yaml
├── ghost-pvc.yaml
├── ghost-deployment.yaml
├── ghost-service.yaml
├── middleware.yaml
└── ingress.yaml
Each manifest is a separate file. The deploy script applies them in the correct order and generates database passwords inline.
The Deploy
With DNS records already pointed at the cluster, I told Claude to deploy:
"yes deploy, i have updated the dns records"
It ran ./deploy.sh. Namespace created. Secret generated. MariaDB came up. Ghost started. And then — an error.
The Error
error: resource mapping not found for name: "redirect-https"
namespace: "ghost-blog" from "middleware.yaml":
no matches for kind "Middleware" in version "traefik.io/v1alpha1"
The Traefik middleware CRD on this cluster uses the older traefik.containo.us/v1alpha1 API version, not the newer traefik.io/v1alpha1. Claude didn't panic. It ran kubectl api-resources | grep middleware to check the correct version, updated the manifest, and re-applied. Middleware and ingress created successfully.
This is the kind of thing that makes an agentic workflow valuable. The agent encountered a real-world version mismatch, diagnosed it with a targeted command, fixed the manifest, and continued — all without me intervening.
Verification
Claude then checked everything:
NAME READY STATUS RESTARTS AGE
ghost-96b564b49-z4cqh 1/1 Running 0 2m48s
mariadb-0 1/1 Running 0 4m47s
Both PVCs bound. Ingress assigned. TLS certificate issued. And:
HTTP/2 200
content-type: text/html; charset=utf-8
x-powered-by: Express
The blog was live.
What Made This Work
Looking back at the session, a few things stand out about why this agentic workflow was effective:
Exploration before action. The agent examined the live cluster state before proposing anything. It didn't ask me what I had installed — it checked. This meant the plan matched reality from the start.
Focused questions. Instead of asking open-ended questions or making assumptions, the agent asked specific, multiple-choice questions at decision points. This kept the planning fast and precise.
Graceful corrections. When I changed requirements (MariaDB over MySQL, no secrets in chat, project folder instead of inline), the agent made targeted updates without restarting the process.
Real error handling. The Traefik API version mismatch was a genuine production issue. The agent diagnosed it, fixed it, and moved on — the same debugging loop a human engineer would follow, just faster.
Appropriate caution. The agent used plan mode to research before acting, checked capacity before deploying, and generated secrets inline instead of exposing them. It treated the production cluster with respect.
The Full Prompt Sequence
For those interested in reproducing this workflow, here are the prompts I used, in order:
I want to deploy ghost blogging platform to civo k8s. Can you use kubectl to plan this please? Also, is it possible to have multiple blogs on the same instance?- Selected
agenticadventures.blogas the custom domain - Selected "Just one" blog
Do not store any secrets in the chat. If generating secrets inject directly into commandCan we use mariadbWhat do I point the A record to?Can you check the cluster capacity alsoI want you to document this including the used manifests in a new project folder- Selected
~/Projects/blogs/agenticadventuresas the project location yes deploy, i have updated the dns records
Ten prompts. From zero to a live, TLS-secured Ghost blog on Kubernetes.
What's Next
This is the first post on Agentic Adventures — a blog about building with AI agents, exploring agentic workflows, and documenting what works (and what doesn't) in practice. The fact that the blog itself was deployed by an agent felt like the right place to start.