Getting Started
Kubernetes Deployment Walkthrough
Create a DigitalOcean Kubernetes environment, connect your Git repository, and deploy a first application with OPSd.
A guided path
From a new cloud project to an application running on Kubernetes
Select a stage to highlight the parts of the platform involved.
Your workstation
DigitalOcean project
Kubernetes platform
Your Git repository
Cloud foundation
GitOps delivery
Application traffic
HTTPS and secrets
This walkthrough takes a rendered OPSd configuration to a running application on DigitalOcean Kubernetes (DOKS). It covers the one-time handoff to Argo CD and a small example workload you can reach from your workstation.
The first run creates billable DigitalOcean resources. Review the resources in the OpenTofu plan and check DigitalOcean pricing for their sizes before you approve it. The basic path below does not create a public load balancer, DNS records, or certificates; you can test the application privately through a temporary port-forward.
Before you start, complete the Quickstart. You will need:
- A DigitalOcean account and an API token with permission to create the resources in the plan.
- A GitHub repository for the environment configuration. A public repository is simplest for the first run; private repository credentials are covered below.
opsd, OpenTofu,kubectl, Helm, and Git installed and available in your terminal. See OPSd Installation, the official OpenTofu installation guide, kubectl installation instructions, the Helm installation guide, and the CLI Reference.
1. Connect the GitOps repository
The repository path must be in the manifest before you render and bootstrap the environment. In demo.yaml, set the GitHub source on the existing primary compute group and enable the applications layer. Merge these values into the existing spec sections; do not add a second spec, compute_groups, or layers key:
spec:
compute_groups:
- id: primary
delivery:
mode: gitops
source:
mode: github
github:
repository_url: https://github.com/YOUR_ORG/YOUR_REPO.git
revision: main
environment_path: environments/opsd-demo
layers:
applications:
enabled: true
Replace the repository URL and choose a path for this environment. The URL must not contain a username, password, or token. environment_path is relative to the repository root. For a private repository, use the HTTPS or SSH credential steps in Connect a private GitOps repository before running opsd bootstrap.
2. Render and review the environment
Synchronize the pinned module and chart sources, then render and validate the manifest:
opsd modules sync demo.yaml
opsd render manifest demo.yaml --output live/ --include-platform
opsd validate manifest demo.yaml --platform
The live/ directory contains the cloud foundation and generated platform configuration. The foundation creates a dedicated DigitalOcean project, VPC, DOKS cluster, and default node pool. Review the region, node size and count, networking, and lifecycle settings in demo.yaml before applying. DNS, Gateway, TLS, and External Secrets components are optional; leave them disabled for the first application test.
3. Create the DigitalOcean environment
OpenTofu needs the DigitalOcean API token through the TF_VAR_digitalocean_token environment variable. Set it in your terminal using your local secret manager or secure shell input. Do not put the token in demo.yaml, tofu.tfvars, a script, or Git. Check that the variable is set without printing its value:
test -n "$TF_VAR_digitalocean_token" && echo "DigitalOcean token is set"
Review the plan, then apply it when the proposed resources and costs look right:
cd live
tofu init -backend=false -input=false
tofu plan
tofu apply
OpenTofu prompts before making changes. Read the plan and confirm it creates the environment you expect. Terraform can be used instead with the equivalent commands.
4. Connect kubectl to the new cluster
The rendered foundation exports a kubeconfig after the cluster is ready. Save it as a private local file, then point kubectl at it:
umask 077
tofu output -raw kubeconfig_raw > kubeconfig.yaml
chmod 600 kubeconfig.yaml
export KUBECONFIG="$PWD/kubeconfig.yaml"
kubectl config current-context
kubectl get nodes
The kubeconfig grants access to the cluster. Keep it out of Git and remove it from live/ when you no longer need it. kubectl get nodes should show the DOKS worker node as Ready before you continue.
5. Install Argo CD
From the project directory, install the pinned Argo CD chart and wait for the cluster nodes to become ready:
cd ..
opsd bootstrap --manifest demo.yaml
For a private GitHub repository, set its credentials as described below before this command. OPSd passes them to Kubernetes to create the repository Secret in Argo CD; credentials are not added to the manifest or rendered files. Public repositories need no credentials.
Argo CD stays private inside the cluster. You do not need to open its interface to deploy the sample application; the command above installs it for the GitOps handoff.
6. Add the generated Argo CD configuration and a sample app
OPSd generated the initial Argo CD configuration in live/layers/00-bootstrap/argocd/. Copy that argocd/ directory into the GitOps repository at:
environments/opsd-demo/layers/00-bootstrap/argocd/
From the OPSd project directory, clone the repository if you have not cloned it already, then copy the generated configuration into it. Replace the repository URL with the one from demo.yaml:
git clone https://github.com/YOUR_ORG/YOUR_REPO.git gitops
mkdir -p gitops/environments/opsd-demo/layers/00-bootstrap
cp -R live/layers/00-bootstrap/argocd gitops/environments/opsd-demo/layers/00-bootstrap/
mkdir -p gitops/environments/opsd-demo/layers/40-applications
The destination must match the environment_path in demo.yaml. In the cloned repository, create environments/opsd-demo/layers/40-applications/hello-web.yaml with this small web application:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-web
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: hello-web
template:
metadata:
labels:
app: hello-web
spec:
containers:
- name: nginx
image: nginx:stable-alpine
ports:
- name: http
containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: hello-web
namespace: default
spec:
selector:
app: hello-web
ports:
- name: http
port: 80
targetPort: http
Commit and push both paths to the branch named in revision:
cd gitops
git add environments/opsd-demo/layers/00-bootstrap/argocd environments/opsd-demo/layers/40-applications/hello-web.yaml
git commit -m "Add OPSd environment and hello-web app"
git push origin main
From the GitOps repository root, seed the bootstrap project and root Application once, using the same kubectl context you checked above:
kubectl apply -f environments/opsd-demo/layers/00-bootstrap/argocd/projects/bootstrap.yaml
kubectl apply -f environments/opsd-demo/layers/00-bootstrap/argocd/root-application.yaml
cd ..
The root Application reads the committed Argo CD configuration and creates the layer Applications. The applications layer then syncs hello-web.yaml from the same branch.
7. Confirm the application is running
Check that Argo CD sees the generated applications and that Kubernetes created the workload:
kubectl -n argocd get applications
kubectl -n default rollout status deployment/hello-web --timeout=5m
kubectl -n default get service hello-web
When the deployment is ready, forward its service to your workstation:
kubectl -n default port-forward svc/hello-web 8080:80
Open http://localhost:8080 while port-forwarding is running. Stop the command with Ctrl+C when you are done. This connection is temporary and private to your workstation; it does not expose the application publicly.
Optional: publish the application on a domain
For a public route, enable the DigitalOcean Gateway API component, configure a hostname, and provide the DNS credentials before syncing the generated infrastructure. The DOKS managed Gateway API path requires Kubernetes 1.33 or newer and non-overlapping VPC-native cluster and service subnets. It can create a public DigitalOcean load balancer, which may add to your bill. For a new environment, use a currently available Kubernetes version 1.33 or newer and set the subnets before the first apply. The CIDRs below are examples; check that they do not overlap your VPC or other network ranges. If the cluster already exists, review the OpenTofu plan carefully because networking or version changes may require replacing resources.
Add or merge the following settings into demo.yaml, keeping existing values under compute_groups and layers:
spec:
compute_groups:
- id: primary
config:
kubernetes_version: latest
cluster_subnet: 10.240.0.0/16
service_subnet: 10.241.0.0/19
layers:
infrastructure:
enabled: true
components:
gateway-api:
enabled: true
values:
acme:
email: [email protected]
server: staging
public:
enabled: true
hostname: app.example.com
tls_secret_name: app-example-com-tls
Use a domain whose authoritative DNS zone is hosted in DigitalOcean. Create a DNS API token with write access and, before syncing the generated infrastructure, create the Secret expected by cert-manager:
kubectl create namespace cert-manager
kubectl -n cert-manager create secret generic digitalocean-dns \
--from-literal=access-token="$DIGITALOCEAN_DNS_TOKEN"
Keep DIGITALOCEAN_DNS_TOKEN in a secure local environment and never commit it. Add this route to environments/opsd-demo/layers/40-applications/hello-web.yaml so requests for the hostname reach the sample Service:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: hello-web
namespace: default
spec:
parentRefs:
- name: opsd-public-gateway
namespace: default
sectionName: https
hostnames:
- app.example.com
rules:
- backendRefs:
- name: hello-web
port: 80
Render and validate the updated manifest, then review and apply any OpenTofu changes:
opsd modules sync demo.yaml
opsd render manifest demo.yaml --output live/ --include-platform
opsd validate manifest demo.yaml --platform
cd live
tofu plan
tofu apply
cd ..
From the OPSd project directory, copy the regenerated configuration into the GitOps checkout:
cp -R live/layers/00-bootstrap/argocd/. gitops/environments/opsd-demo/layers/00-bootstrap/argocd/
mkdir -p gitops/environments/opsd-demo/layers/10-infrastructure
mkdir -p gitops/environments/opsd-demo/layers/10-infrastructure/gateways
cp -R live/layers/10-infrastructure/gateways/. gitops/environments/opsd-demo/layers/10-infrastructure/gateways/
Then commit and push these generated files with the HTTPRoute:
cd gitops
git add environments/opsd-demo/layers/00-bootstrap/argocd environments/opsd-demo/layers/10-infrastructure/gateways environments/opsd-demo/layers/40-applications/hello-web.yaml
git commit -m "Add public route to hello-web"
git push origin main
cd ..
Once the Gateway has an address, read it with kubectl -n default get gateway opsd-public-gateway -o jsonpath='{.status.addresses[0].value}' and create an A record for app.example.com in the DigitalOcean DNS zone with that address. Wait for DNS and the certificate to become ready before testing https://app.example.com.
The staging ACME service is for validating DNS and certificate issuance. Switch server to production after validation. See the CLI manifest reference for ExternalDNS settings, private Gateway options, and the complete component schema.
Connect a private GitOps repository
For a private HTTPS repository, make OPSD_ARGOCD_REPO_USERNAME and OPSD_ARGOCD_REPO_PASSWORD available in the environment before running opsd bootstrap. For SSH, use an ssh:// repository URL and make OPSD_ARGOCD_REPO_SSH_PRIVATE_KEY available. Set only the credential type used by the repository. Public repositories need neither. Do not put credentials in the repository URL or demo.yaml.
What this walkthrough does not install
The monitoring layer and simpler application CI integration are planned platform work; this walkthrough does not install them. For now, review and apply infrastructure changes with OpenTofu, then commit application changes to the GitOps repository for Argo CD to sync. See Supported Paths for current availability and CLI manifest reference for all supported settings.