Skip to main content

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.

DigitalOcean project DOKS cluster Argo CD Your application

Your workstation

OPSd CLI
Terraform / OpenTofu

DigitalOcean project

Dedicated project
VPC and network
DOKS cluster and node pool
Gateway and load balancer
DNS records

Kubernetes platform

Argo CD
HTTPRoute and Services
ExternalDNS
TLS certificates
External Secrets Operator
Your application
Monitoring and telemetry Planned
Application CI integration Planned

Your Git repository

Platform configuration
Application manifests or charts

Cloud foundation

OPSd Review and apply DigitalOcean project VPC DOKS

GitOps delivery

Platform and app repository Argo CD Application

Application traffic

HTTPRoute or Service Gateway ExternalDNS DNS record

HTTPS and secrets

DNS credentials cert-manager External Secrets Application
OPSd prepares Your team configures Planned

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:

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.