In this article, we’ll explore Argo‘s features and use it to run a simple demo application.
Argo CD is “a declarative, GitOps continuous delivery tool for Kubernetes.” It can monitor your source repositories and automatically deploy changes to your cluster.
Kubernetes orchestrates container deployment and management tasks. It starts your containers, replaces them when they fail, and scales your service across the compute nodes in your cluster.
Kubernetes is best used as part of a continuous delivery workflow. Running automated deployments when new code is merged ensures changes reach your cluster quickly after passing through a consistent pipeline.
ArgoCD is a popular tool for setting up continuous delivery with Kubernetes. It automates application deployment into Kubernetes clusters by continually reconciling your repository’s state against your live workloads.
The GitOps model is integral to Argo’s design. It makes the repository the single source of truth for your application’s desired state. All the Kubernetes manifests, Kustomize templates, Helm charts, and config files your app needs should be committed to your repository. These resources “declare” what a successful deployment of your app looks like.
Argo compares the declared state to what’s actually running in your cluster, then applies the correct changes to resolve any discrepancies. This process can be configured to run automatically, preventing your cluster from drifting away from your repository. Argo resynchronizes the state whenever differences occur, such as after you manually run Kubectl commands.
Argo comes with both a CLI and web UI. It supports multi-tenant and multi-cluster environments, integrates with SSO providers, produces an audit trail, and can implement complex rollout strategies such as canary deployments and blue/green upgrades. It also offers integrated rollbacks so you can quickly recover from deployment failures.
Push vs. Pull-based CI/CD
Historically, most CI/CD implementations have relied on push-driven behavior. This requires you to connect your cluster to your CI/CD platform, then use tools like Kubectl and Helm within your pipeline to apply Kubernetes changes.
Argo is a pull-based CI/CD system. It runs inside your Kubernetes cluster and pulls source from your repositories. Argo then applies the changes for you without a manually configured pipeline.
This model is more secure than push-based workflows. You don’t have to expose your cluster’s API server or store Kubernetes credentials in your CI/CD platform. Compromising a source repository only gives an attacker access to your code instead of the code and a route to your live deployments.
Argo is easy to learn once you understand its basic concepts. Here are some terms to get familiar with.
- Argo controller – Argo’s Application Controller is the component you install in your cluster. It implements the Kubernetes controller pattern to monitor your applications and compare their state against their repositories.
- Application – An Argo application is a group of Kubernetes resources which collectively deploy your workload. Argo stores the details of applications in your cluster as instances of an included Custom Resource Definition (CRD).
- Live state – The live state is the current state of your application inside the cluster, such as the number of Pods created and the image they’re running.
- Target state – The target state is the version of the state that’s declared by your Git repository. When the repository changes, Argo will apply actions that evolve the live state into the target state.
- Refresh – A refresh occurs when Argo fetches the target state from your repository. It will compare the changes against the live state but doesn’t necessarily apply them at this stage.
- Sync – A Sync is the process of applying the changes discovered by a Refresh. Each Sync moves the cluster back towards the target state.
Now we’ve covered the core concepts, we can use Argo to deploy an example app to Kubernetes. You can read more about Argo’s terminology and the tool’s architecture in the official docs.
Let’s use Argo to run a basic NGINX web server instance in Kubernetes. We’ll assume you’ve already got access to a Kubernetes cluster, and you’ve got the Kubectl and Helm CLIs available on your machine.
Create Your App’s GitHub Repository
First, head to GitHub and create a new repository for your app. Afterward, clone your repo to your machine, ready to commit your Kubernetes manifests:
$ git clone https://github.com/<username>/<repo>.git
Copy the following YAML and save it as deployment.yaml
inside your repository:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: argo-demo
labels:
app.kubernetes.io/name: nginx
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: nginx
template:
metadata:
labels:
app.kubernetes.io/name: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- name: http
containerPort: 80
It defines a basic Kubernetes Deployment object that runs three NGINX replicas.
Next, copy this second YAML file and save it to service.yaml
. It sets up a LoadBalancer service to expose your Deployment outside your cluster:
apiVersion: v1
kind: Service
metadata:
name: nginx
namespace: argo-demo
spec:
type: LoadBalancer
selector:
app.kubernetes.io/name: nginx
ports:
- protocol: TCP
port: 80
targetPort: http
Finally, add a manifest that will create your application’s namespace:
apiVersion: v1
kind: Namespace
metadata:
name: argo-demo
Commit your changes to your repository, then push them up to GitHub:
$ git add .
$ git commit -m "Added initial Kubernetes YAML files"
$ git push
You’re ready to install Argo and start deploying your app.
Get the Argo CLI
Argo’s CLI lets you interact with your applications from your terminal. You’ll need it later to register your app with your Argo instance.
You can download the latest CLI release from GitHub. Select the right binary for your platform, then make it executable and move it to a location in your path. The following steps work for most Linux systems – substitute the latest version number instead of 2.6.1 below, first:
$ wget https://github.com/argoproj/argo-cd/releases/download/v2.6.1/argocd-linux-amd64
$ chmod +x argocd-linux-amd64
$ mv argocd-linux-amd64 /usr/bin/argocd
Check you can now run argocd
commands:
$ argocd version
argocd: v2.6.1+3f143c9
BuildDate: 2023-02-08T19:18:18Z
...
The CLI’s also distributed in Homebrew’s package list. Use the brew install
command to add argocd
to your system using this method:
$ brew install argocd
Install Argo In Your Cluster
Next, install Argo in your Kubernetes cluster. This will add the Argo CD API, controller, and Custom Resource Definitions (CRDs).
Begin by creating a namespace for Argo:
$ kubectl create namespace argocd
namespace/argocd created
Next, use Kubectl to apply Argo CD’s YAML manifest to your cluster. You can inspect the manifest before you use it to see the resources that’ll be created.
$ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
It can take several seconds for all of Argo’s components to be running in your cluster. Monitor progress by using Kubectl to list the deployments in the argocd
namespace.
You can continue once the deployments are ready:
$ kubectl get deployments -n argocd
NAME READY UP-TO-DATE AVAILABLE AGE
argocd-applicationset-controller 1/1 1 1 67s
argocd-dex-server 1/1 1 1 67s
argocd-notifications-controller 1/1 1 1 67s
argocd-redis 1/1 1 1 67s
argocd-repo-server 1/1 1 1 67s
argocd-server 1/1 1 1 67s
Connecting to Argo
Argo CD doesn’t automatically expose its API server on an external IP. You can connect to it by starting a new Kubectl port-forwarding session instead. Open another terminal window and run the following command:
$ kubectl port-forward svc/argocd-server -n argocd 8080:443
This redirects your local port 8080 to port 443 of Argo’s service. Visit localhost:8080
in your browser to access the Argo UI. You’ll be warned that the page is insecure because it uses a self-signed certificate.
You can continue with this setup while you’re experimenting, but you should follow the detailed steps in the Argo docs to configure TLS with an Ingress route before you move to production.
Before you can login, you need to retrieve the password for the default admin user. This is generated automatically during Argo’s installation process. You can access it by running the following argocd
command:
$ argocd admin initial-password -n argocd
zHKv74zvDNtVMaOB
Use these credentials to login to Argo.
Once you’re in, head straight to the User Info item in the left sidebar, then click the “Update Password” button at the top of the screen. Follow the prompts to change your password to something unique.
Now you can delete the Kubernetes secret that contains the original password for the admin account:
$ kubectl delete secret argocd-initial-admin-secret -n argocd
secret "argocd-initial-admin-secret" deleted
Login to the CLI
To login to the Argo CLI, run argocd login
and supply the API server’s URL as an argument:
$ argocd login localhost:8080
Similarly to the browser warning encountered above, you’ll be prompted to accept Argo’s built-in self-signed certificate if you haven’t configured your own TLS:
WARNING: server certificate had error: x509: certificate signed by unknown authority. Proceed insecurely (y/n)?
Accept the prompt by typing y and pressing return. You’ll then be asked to enter your username and password. The CLI should successfully authenticate to your Argo instance:
'admin:login' logged in successfully
Context 'localhost:8080' updated
Deploying Your App With Argo
Everything’s ready to start deploying apps to Argo! First, run the following CLI command to register your app:
$ argocd app create argo-demo \
--repo https://github.com/<username>/<repo>.git \
--path . \
--dest-server https://kubernetes.default.svc \
--dest-namespace argo-demo
application 'argo-demo' created
Let’s unpack what’s happening here:
- The
--repo
flag specifies the URL of your Git repository. - The
--path
flag instructs Argo to search for Kubernetes manifests, Helm charts, and other deployable assets inside this path within your repo..
is used here because the example manifests are stored in the repo’s root. - The
--dest-server
flag specifies the URL of the Kubernetes cluster to deploy to. You can usekubernetes.default.svc
when you’re deploying to the same cluster that Argo’s running in. --dest-namespace
sets the Kubernetes namespace that your app will be deployed into. This should match themetadata.namespace
fields set on your resources.
Your app will now be registered with Argo. You can retrieve its details with the argocd app list
command:
NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET
argocd/argo-demo https://kubernetes.default.svc argo-demo default OutOfSync Missing <none> <none> https://github.com/ilmiont/spacelift-argo-cd-demo.git
The app also shows up in the Argo UI:
Your First Sync
The app shows as “missing” and “out of sync.” Creating the app doesn’t automatically sync it into your cluster. Perform a sync now to have Argo apply the target state currently defined by your repo’s content:
$ argocd app sync argo-demo
...
GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
Namespace argo-demo argo-demo Running Synced namespace/argo-demo created
Service argo-demo nginx Synced Progressing service/nginx created
apps Deployment argo-demo nginx Synced Progressing deployment.apps/nginx created
Namespace argo-demo Synced
The sync results display in your terminal. You should see the Namespace, Service, and Deployment objects all get synced into your cluster, as in the command output above. The messages for all three objects confirm they were created successfully.
Repeat the apps list
command to check the app’s new status:
$ argocd app list
NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET
argocd/argo-demo https://kubernetes.default.svc argo-demo default Synced Healthy <none> <none> https://github.com/ilmiont/spacelift-argo-cd-demo.git .
Now the app is Synced and Healthy! It’s also green in the Argo UI:
As a final proof, use Kubectl to inspect the deployments in the app’s namespace. This should confirm that nginx
is up and running three replicas:
$ kubectl get deployment -n argo-demo
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 3/3 3 3 7m56s
Syncing App Updates
Now let’s make a change to our app. Modify the spec.replicas
field in your deployment.yaml
so there’s now five Pods in the Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: argo-demo
labels:
app.kubernetes.io/name: nginx
spec:
replicas: 5
...
Commit and push your changes:
$ git add .
$ git commit -m "Run 5 replicas"
$ git push
Next, repeat the argocd app sync
command to apply your changes to your cluster.
Alternatively, you can click the “Sync” button within the user interface.
$ argocd app sync argo-demo
GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
Namespace argo-demo argo-demo Running Synced namespace/argo-demo unchanged
Service argo-demo nginx Synced Healthy service/nginx unchanged
apps Deployment argo-demo nginx Synced Progressing deployment.apps/nginx configured
Namespace argo-demo Synced
Argo refreshes your app’s target state from the repo, then takes action to transition the live state. The Deployment is reconfigured and now runs five Pods:
$ kubectl get deployment -n argo-demo
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 5/5 5 5 12m
Enabling Auto-Sync
The change to five replicas didn’t apply until you repeated the sync command. Argo can automatically sync changes from your repo though, eliminating the need to issue the command each time. This fully automates your delivery workflow.
You can activate auto-sync for an app by clicking the “App Details” button within the user interface and scrolling down to the “Sync Policy” section. Click the “Enable Auto-Sync” button.
Auto-sync can also be enabled using the CLI by running the following command:
$ argocd app set argo-demo --sync-policy automated
To test auto-sync out, revert the spec.replicas
field back to three replicas:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: argo-demo
labels:
app.kubernetes.io/name: nginx
spec:
replicas: 3
...
Commit and push the change:
$ git add .
$ git commit -m "Back to 3 replicas"
$ git push
This time Argo will automatically detect the repository’s state change. You should see your Deployment scale back to 3 replicas within a few minutes of pushing the commit:
$ kubectl get deployment -n argo-demo
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 3/3 3 3 23m
Auto-sync runs every three minutes by default. You can change this value by modifying Argo’s config map, if you need more frequent deployments.
Managing Your App
Argo’s CLI and web app offer extensive options for managing and monitoring your deployments. While these are outside the scope of this beginner’s tutorial, you can start exploring the CLI commands and UI panels to take control of your app. Most features are implemented in both interfaces.
Clicking your app’s tile from the homescreen displays an overview that visualizes its components with their current sync and health states. You can view the app’s details, edit its config, and view events that describe Argo’s activity by clicking the “App Details” button in the top-left.
You can access previous deployments via the “History and Rollback” button. This lists all the syncs that Argo has performed, including an option to restore an older version. If a deployment introduces a bug, you can use this screen to rollback before you push a fix to your repo.
Argo CD is a continuous delivery tool for Kubernetes. It provides a pull-based GitOps workflow for automatically synchronizing source repositories with in-cluster deployments. While this article has only covered the basics, Argo gives you a complete toolkit for deploying your apps, inspecting their health, and quickly rolling back any failed changes.
Argo CD is an ideal solution for managing your Kubernetes workloads. It doesn’t handle how you provision and change your cluster infrastructure, though.
Try Spacelift’s CI/CD platform to collaborate on infrastructure using multiple IaC providers, including Kubernetes, Ansible, and Terraform. Spacelift lets you visualize your resources, prevent drift, and help developers ship fast within precise policy-driven guardrails.
The Most Flexible CI/CD Automation Tool
Spacelift is an alternative to using homegrown solutions on top of a generic CI. It helps overcome common state management issues and adds several must-have capabilities for infrastructure management.