$linuxjunkies
>

Install Argo CD on k3s

Install Argo CD on a k3s single-node cluster using Helm, then create and auto-sync your first GitOps Application from a Git repository.

AdvancedUbuntuDebianFedoraArch12 min readUpdated June 7, 2026

Before you start

  • A machine with at least 2 vCPUs and 4 GB RAM running a supported Linux distro
  • A user account with sudo privileges and outbound internet access
  • A domain name or static IP for the Argo CD UI (port-forward works for local-only access)
  • Basic familiarity with kubectl and Kubernetes concepts (namespaces, pods, services)

Argo CD turns a Kubernetes cluster into a self-healing GitOps engine. Running it on k3s gives you a full GitOps workflow on a single VM or bare-metal node — useful for homelabs, edge sites, and staging environments that mirror production. This guide walks from a fresh machine to a working Argo CD installation with your first synced Application, using Helm for the install so upgrades stay manageable.

Prerequisites and Assumptions

You need a machine with at least 2 vCPUs and 4 GB RAM running a supported distro, a domain name or static IP (for the UI), and kubectl available after k3s installs. All commands run as a non-root user with sudo access unless noted.

Step 1: Install k3s

k3s ships a single binary that includes containerd, flannel, CoreDNS, and a built-in load balancer (ServiceLB). The installer script is the fastest path to a working cluster.

curl -sfL https://get.k3s.io | sh -s - \
  --disable traefik \
  --write-kubeconfig-mode 644

--disable traefik removes k3s's bundled ingress controller so Argo CD's own ingress or port-forward isn't blocked. --write-kubeconfig-mode 644 lets your regular user read the kubeconfig without sudo.

Wait about 30 seconds, then confirm the node is ready:

kubectl get nodes

Expected output (version will vary):

# NAME        STATUS   ROLES                  AGE   VERSION
# myhost      Ready    control-plane,master   45s   v1.29.4+k3s1

Export the kubeconfig path for tools that don't read the k3s default location:

export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
echo 'export KUBECONFIG=/etc/rancher/k3s/k3s.yaml' >> ~/.bashrc

Step 2: Install Helm

Install Helm 3 using the official script. It does not touch your cluster — it is a local client only.

curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

Verify:

helm version --short

Step 3: Install Argo CD via Helm

Add the Argo Helm repository

helm repo add argo https://argoproj.github.io/argo-helm
helm repo update

Create a values override file

A minimal argocd-values.yaml disables TLS on the server pod (termination happens at the ingress or you use port-forward) and sets resource limits appropriate for a single-node cluster:

cat > argocd-values.yaml << 'EOF'
global:
  domain: argocd.example.com   # change to your domain or remove if using port-forward

server:
  extraArgs:
    - --insecure                # disable built-in TLS; terminate at ingress layer
  resources:
    requests:
      cpu: 100m
      memory: 128Mi
    limits:
      cpu: 500m
      memory: 256Mi

repoServer:
  resources:
    requests:
      cpu: 100m
      memory: 128Mi
    limits:
      cpu: 500m
      memory: 256Mi

applicationSet:
  enabled: true

notifications:
  enabled: false               # enable later when you need alerting
EOF

Install into its own namespace

kubectl create namespace argocd

helm install argocd argo/argo-cd \
  --namespace argocd \
  --version 7.3.4 \
  --values argocd-values.yaml \
  --wait

Pin --version to a specific chart release so future helm repo update runs don't silently upgrade. Check github.com/argoproj/argo-helm/releases for the latest stable tag.

Confirm all pods reach Running:

kubectl get pods -n argocd

Step 4: Access the Argo CD UI

Retrieve the initial admin password

Helm sets a random initial password stored in a Secret:

kubectl get secret argocd-initial-admin-secret \
  -n argocd \
  -o jsonpath="{.data.password}" | base64 -d; echo

Port-forward for quick access

If you're not setting up an ingress yet, forward the server port to your workstation:

kubectl port-forward svc/argocd-server -n argocd 8080:80

Open http://localhost:8080 in your browser. Log in with username admin and the password you retrieved above.

Optional: expose via k3s ServiceLB (LoadBalancer)

If you want a stable IP on your LAN without an ingress controller, patch the service type:

kubectl patch svc argocd-server \
  -n argocd \
  -p '{"spec":{"type":"LoadBalancer"}}'

k3s's built-in ServiceLB will assign the node's IP. Retrieve it with:

kubectl get svc argocd-server -n argocd

Step 5: Install the Argo CD CLI

The CLI is optional but makes scripting and inspecting Applications much faster than the UI alone.

VERSION=$(curl -s https://api.github.com/repos/argoproj/argo-cd/releases/latest \
  | grep tag_name | cut -d '"' -f4)
curl -sSL -o argocd \
  "https://github.com/argoproj/argo-cd/releases/download/${VERSION}/argocd-linux-amd64"
chmod +x argocd
sudo mv argocd /usr/local/bin/

Log in against the port-forwarded address (run port-forward in a separate terminal first):

argocd login localhost:8080 \
  --username admin \
  --password "$(kubectl get secret argocd-initial-admin-secret \
      -n argocd -o jsonpath='{.data.password}' | base64 -d)" \
  --insecure

Change the admin password immediately:

argocd account update-password

Step 6: Create Your First Application

An Argo CD Application maps a Git repository path to a Kubernetes namespace and keeps them in sync. The cleanest way to define one is with a YAML manifest committed to Git — but for a first smoke-test, the CLI is faster.

Deploy the official guestbook example

argocd app create guestbook \
  --repo https://github.com/argoproj/argocd-example-apps.git \
  --path guestbook \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace default \
  --sync-policy automated \
  --auto-prune \
  --self-heal
  • --sync-policy automated — Argo CD syncs whenever it detects drift, no manual trigger needed.
  • --auto-prune — resources removed from Git are deleted from the cluster.
  • --self-heal — manual cluster changes that deviate from Git are reverted automatically.

Watch the sync

argocd app get guestbook
argocd app wait guestbook --health

Once health is Healthy and sync status is Synced, check the deployed resources:

kubectl get all -n default -l app=guestbook

Step 7: Define an Application in Git (the GitOps Way)

Long-term, manage Applications as YAML committed to a repository. Create apps/guestbook-app.yaml in your own repo:

cat > guestbook-app.yaml << 'EOF'
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: guestbook
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/argoproj/argocd-example-apps.git
    targetRevision: HEAD
    path: guestbook
  destination:
    server: https://kubernetes.default.svc
    namespace: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
EOF

kubectl apply -f guestbook-app.yaml

Apply this manifest once; Argo CD owns the lifecycle from that point forward. Point this pattern at your own app repo to go fully GitOps.

Verification

# All Argo CD pods healthy
kubectl get pods -n argocd

# Application sync status
argocd app list

# Cluster-wide resource count as a sanity check
kubectl get all -A | grep -v kube-system | grep -v argocd

Troubleshooting

k3s node stays NotReady

Check the service: sudo systemctl status k3s. Containerd socket issues after a reboot are usually fixed with sudo systemctl restart k3s.

Argo CD pods in CrashLoopBackOff

Inspect logs: kubectl logs -n argocd deploy/argocd-server. The most common cause on constrained nodes is OOM — raise the memory limit in argocd-values.yaml and run helm upgrade argocd argo/argo-cd -n argocd --values argocd-values.yaml.

Application stuck OutOfSync

Run argocd app diff guestbook to see exactly what the cluster has versus what Git expects. If a resource has a last-applied-configuration annotation conflict, force a hard refresh: argocd app get guestbook --hard-refresh.

Can't reach the UI after port-forward exits

The port-forward process dies with the terminal session. For persistent access on a homelab, use a systemd user service to keep it running, or set up an nginx/Caddy reverse proxy in front of the LoadBalancer IP.

tested on:Ubuntu 24.04Debian 12Fedora 40Rocky 9

Frequently asked questions

Can I run Argo CD on a k3s cluster with less than 4 GB RAM?
Technically yes — lower the resource limits in your values file and disable applicationSet and notifications. Expect slower sync cycles and possible OOM kills under load on nodes with 2 GB or less.
Why disable Traefik during k3s install?
k3s ships Traefik as a default ingress controller on port 80/443. Leaving it enabled doesn't break Argo CD, but it adds a layer you may not want and can interfere if you later install ingress-nginx or Caddy to front the Argo CD UI.
How do I upgrade Argo CD after the initial install?
Run helm repo update, then helm upgrade argocd argo/argo-cd -n argocd --version <new-version> --values argocd-values.yaml. Always check the Argo CD upgrade notes for that version before running the command.
How does Argo CD authenticate to a private Git repository?
Use argocd repo add <url> --ssh-private-key-path ~/.ssh/id_ed25519 for SSH repos, or --username / --password for HTTPS. Credentials are stored as Secrets in the argocd namespace.
What is the difference between Synced and Healthy in Argo CD?
Synced means the live cluster state matches what is defined in Git. Healthy means the deployed resources are actually running and passing their readiness checks. An app can be Synced but Degraded if pods are crash-looping after deployment.

Related guides