Overview #
In this tutorial I’m using a Kubernetes K8s cluster with MetalLB deployed with Kubespray on Debian 12 servers. My GitLab instance is running on an Ubuntu 22.04 server:
192.168.30.71 deb-02 # Controller / Master Node
192.168.30.72 deb-03 # Controller / Master Node
192.168.30.73 deb-04 # Worker Node
192.168.30.74 deb-05 # Worker Node
192.168.70.4 # GitLab Server
Argo CD Deployment #
Create Namespace #
# Create a Kubernetes namespace for Argo CD deployment
kubectl create namespace argocd
Deployment #
# Deploy Argo CD
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
Verify the Resources #
# List the Argo CD resources
kubectl get all -n argocd
Shell Output:
# Shell output:
NAME READY STATUS RESTARTS AGE
pod/argocd-application-controller-0 1/1 Running 0 46s
pod/argocd-applicationset-controller-c74dfc889-r5t8z 1/1 Running 0 47s
pod/argocd-dex-server-957c97b7d-dj7hl 1/1 Running 0 46s
pod/argocd-notifications-controller-7df7749d5-zk2cs 1/1 Running 0 46s
pod/argocd-redis-cc756f67-j5cmz 1/1 Running 0 46s
pod/argocd-repo-server-6959444795-86snx 1/1 Running 0 46s
pod/argocd-server-55dcfc7c76-4g96q 1/1 Running 0 46s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/argocd-applicationset-controller ClusterIP 10.233.47.199 <none> 7000/TCP,8080/TCP 47s
service/argocd-dex-server ClusterIP 10.233.13.1 <none> 5556/TCP,5557/TCP,5558/TCP 47s
service/argocd-metrics ClusterIP 10.233.9.250 <none> 8082/TCP 47s
service/argocd-notifications-controller-metrics ClusterIP 10.233.27.228 <none> 9001/TCP 47s
service/argocd-redis ClusterIP 10.233.17.198 <none> 6379/TCP 47s
service/argocd-repo-server ClusterIP 10.233.1.6 <none> 8081/TCP,8084/TCP 47s
service/argocd-server ClusterIP 10.233.56.46 <none> 80/TCP,443/TCP 47s
service/argocd-server-metrics ClusterIP 10.233.35.44 <none> 8083/TCP 47s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/argocd-applicationset-controller 1/1 1 1 47s
deployment.apps/argocd-dex-server 1/1 1 1 47s
deployment.apps/argocd-notifications-controller 1/1 1 1 47s
deployment.apps/argocd-redis 1/1 1 1 46s
deployment.apps/argocd-repo-server 1/1 1 1 46s
deployment.apps/argocd-server 1/1 1 1 46s
NAME DESIRED CURRENT READY AGE
replicaset.apps/argocd-applicationset-controller-c74dfc889 1 1 1 47s
replicaset.apps/argocd-dex-server-957c97b7d 1 1 1 47s
replicaset.apps/argocd-notifications-controller-7df7749d5 1 1 1 46s
replicaset.apps/argocd-redis-cc756f67 1 1 1 46s
replicaset.apps/argocd-repo-server-6959444795 1 1 1 46s
replicaset.apps/argocd-server-55dcfc7c76 1 1 1 46s
NAME READY AGE
statefulset.apps/argocd-application-controller 1/1 46s
Argo CD Server Service #
Convert ClusterIP to LoadBalancer Service #
# Change the Argo CD Service service to type LoadBalancer
kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'
Verify Service Details #
# List Argo CD serivce details
kubectl describe service argocd-server -n argocd
Shell Output:
# Shell output:
Name: argocd-server
Namespace: argocd
Labels: app.kubernetes.io/component=server
app.kubernetes.io/name=argocd-server
app.kubernetes.io/part-of=argocd
Annotations: metallb.universe.tf/ip-allocated-from-pool: primary
Selector: app.kubernetes.io/name=argocd-server
Type: LoadBalancer
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.233.56.46
IPs: 10.233.56.46
LoadBalancer Ingress: 192.168.30.241
Port: http 80/TCP
TargetPort: 8080/TCP
NodePort: http 30132/TCP
Endpoints: 10.233.71.6:8080
Port: https 443/TCP
TargetPort: 8080/TCP
NodePort: https 31740/TCP
Endpoints: 10.233.71.6:8080
Session Affinity: None
External Traffic Policy: Cluster
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal IPAllocated 16s metallb-controller Assigned IP ["192.168.30.241"]
Normal nodeAssigned 16s metallb-speaker announcing from node "node4" with protocol "layer2"
DNS Entry #
To access the Argo CD webinterface, create a DNS entry that points to the external IP provided by the LoadBalancer service:
# Create a DNS entry
192.168.30.241 argocd.jklug.work
Custom TLS Certificate Secret #
Update the default self-signed TLS certificate with a custom TLS certificate:
# Update the TLS Kubernetes secret
kubectl create -n argocd secret tls argocd-server-tls \
--cert=fullchain.pem \
--key=privkey.pem
Argo CD Webinterface #
# Access the webinterface: Via LoadBalancer service
https://argocd.jklug.work
Initial Admin Password #
# Default user
admin
# Retrieve "admin" password
kubectl get secret argocd-initial-admin-secret -n argocd -o jsonpath="{.data.password}" | base64 --decode; echo
# Shell output:
ocL8NX0pPvB9V8Rn
Delete the Kubernetes secret after the password was retrieved:
# Delete the "argocd-initial-admin-secret" secret
kubectl delete secret argocd-initial-admin-secret
Argo CD CLI #
Installation #
Find the latest stable release:
https://github.com/argoproj/argo-cd/tags
# Install Argo CD CLI
curl -sSL -o argocd https://github.com/argoproj/argo-cd/releases/download/v2.11.2/argocd-linux-amd64
# Change permissions
chmod +x argocd
# Move the binary
sudo mv argocd /usr/local/bin/
# Verify the installation / check version
argocd version
# Shell output:
argocd version
argocd: v2.11.2+25f7504
BuildDate: 2024-05-23T13:58:43Z
GitCommit: 25f7504ecc198e7d7fdc055fdb83ae50eee5edd0
GitTreeState: clean
GoVersion: go1.21.10
Compiler: gc
Platform: linux/amd64
FATA[0000] Argo CD server address unspecified
Configuration #
DNS Entry #
Make sure the host where the Argo CD CLI is deploy can resolve the DNS name of the Argo CD server:
# Make sure a DNS entry for the Argo CD server is set
192.168.30.241 argocd.jklug.work
Argo CD Server Address #
# Set the the Argo CD server address
argocd login argocd.jklug.work
# Shell output:
Username: admin
Password: # Enter the admin pw
'admin:login' logged in successfully
Context 'argocd.jklug.work' updated
GitLab Repository #
DNS Entry #
Make sure the server where the Argo CD CLI is running is able to resolve the DNS name of GitLab:
# Add DNS entry
192.168.70.4 gitlab.jklug.work
Known Hosts #
GitLab Host Keys #
Scan the host keys of GitLab:
# List the GitLab host keys
ssh-keyscan gitlab.jklug.work
# Shell output:
# gitlab.jklug.work:22 SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.6
gitlab.jklug.work ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDHAQj15hmfv3OwTY3RAPwx1UlZ8p4qgtAHiZ9hngfJTSScO1kf40oL3Ek5NVKSGYZQ4w6ozBFHKO3l6tHn8nPeD7mUk/nW2U5w9yYpcRyFknn/u/Z0QreHAkI8fg6LI4n+2QYFF1rZbIemtCG33FozwrWKJ+/UsJYLnuQ2fenjcvkwPYx7NKV07RtQ3xYvkFVdWQGFJK8pLG9UcsanwZbH2nVPbv3i9KKI9xxWmJDh9JOoLhG6JipNN4Q4CoodfR9k9A2PY88dEykMInSGzFddOqbHLyISO8H1oJrofPzovPR07f+bDBK6iGIqRSW00k6mM0RFkPPo9tulLJ87DgB84jVrtYGp71wmV9PQ8jPB1uaDx5JtRNc0G+IWlIzTy8hFW9djELdTdQmfxeaCceyn1AmuXhpwZin64WTqztXj29s1olZ0+Uchh2FGpEjvlVqveeMmgAQkQezidqVHKKwinW1zdeSaBaZkS0JpLtxNpA86vBnhtYE8Z4CaQAvoQXU=
# gitlab.jklug.work:22 SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.6
gitlab.jklug.work ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPUxIo1glUPlmYJDbAOvHlRd/qjxdIEJCtBlcFLCMXECbRdp9IN/qePZdFtOnMWWVNvi8qy+7V8XbIFbzHoYwcg=
# gitlab.jklug.work:22 SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.6
gitlab.jklug.work ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH6GrjO8VqbiFMwtOfaEuKd3bV2vb7jH4r5Xl9PW1TFY
# gitlab.jklug.work:22 SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.6
# gitlab.jklug.work:22 SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.6
Add GitLab Host Keys to Argo CD #
Open the Argo CD webinterface an add the GitLab host keys:
- Go to: “Settings” > “Repository certificates and known hosts” > “ADD SSH KNOWN HOSTS”
- Paste the GitLab SSH keys in the text box, one entry per line
- Click “CREATE” to save the entry
SSH Key #
Create a SSH key on the Argo CD CLI host and add they public key to GitLab:
# Create RSA Key: 4096 bit
ssh-keygen -t rsa -b 4096
Connect GitLab Repository: #
Add the GitLab repository to Argo CD, this allows Argo CD to access and manage the repository using the specified SSH private key:
# Connect a GitLab repository via SSH
argocd repo add git@gitlab.jklug.work:root/k8s-example-project.git --ssh-private-key-path /home/debian/.ssh/id_rsa
# Connect a GitLab repository via SSH: Ignore insecure host key (For usage without GitLab host keys)
argocd repo add git@gitlab.jklug.work:root/k8s-example-project.git --ssh-private-key-path /home/debian/.ssh/id_rsa --insecure-ignore-host-key
# Shell output:
Repository 'git@gitlab.jklug.work:root/k8s-example-project.git' added
The GitLab repository should now be availble in the Argo CD webinterface under: “Settings” > “Repositories”
Create an Application in Argo CD #
Create an Argo CD application named gitlab-k8s-example-project
that points to the Kubernetes manifests in the specified GitLab repository and deploys them to the default namespace of the Kubernetes cluster.
CLI Version #
# Deploy the GitLab repository
argocd app create gitlab-k8s-example-project \
--repo git@gitlab.jklug.work:root/k8s-example-project.git \
--path . \
--dest-server https://kubernetes.default.svc \
--dest-namespace default
# Shell output:
application 'gitlab-k8s-example-project' created
-
--path .
Helm chart location in the repository: root -
--dest-server https://kubernetes.default.svc
API server URL of the Kubernetes cluster where the application should be deployed (same Kubernetes cluster where Argo CD is running). -
--dest-namespace default
Defines the Kubernetes namespace
The application should now be available in the “Applications” section of the Argo CD webinterface.
Sync / Deploy the Application #
# Deploy resources into the Kubernetes cluster
argocd app sync gitlab-k8s-example-project
Shell Output
# Shell output:
TIMESTAMP GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
2024-06-06T23:52:58+02:00 apps Deployment default gitlab-k8s-example-project-helm-guestbook OutOfSync Missing
2024-06-06T23:52:58+02:00 Service default gitlab-k8s-example-project-helm-guestbook OutOfSync Missing
2024-06-06T23:52:59+02:00 Service default gitlab-k8s-example-project-helm-guestbook OutOfSync Missing service/gitlab-k8s-example-project-helm-guestbook created
2024-06-06T23:52:59+02:00 apps Deployment default gitlab-k8s-example-project-helm-guestbook OutOfSync Missing deployment.apps/gitlab-k8s-example-project-helm-guestbook created
2024-06-06T23:52:59+02:00 Service default gitlab-k8s-example-project-helm-guestbook Synced Healthy service/gitlab-k8s-example-project-helm-guestbook created
2024-06-06T23:52:59+02:00 apps Deployment default gitlab-k8s-example-project-helm-guestbook Synced Progressing deployment.apps/gitlab-k8s-example-project-helm-guestbook created
Name: argocd/gitlab-k8s-example-project
Project: default
Server: https://kubernetes.default.svc
Namespace: default
URL: https://argocd.jklug.work/applications/gitlab-k8s-example-project
Source:
- Repo: git@gitlab.jklug.work:root/k8s-example-project.git
Target:
Path: .
SyncWindow: Sync Allowed
Sync Policy: Manual
Sync Status: Synced to (0b62635)
Health Status: Progressing
Operation: Sync
Sync Revision: 0b626353f37e785e15062ab757d8e7c96ae4bad5
Phase: Succeeded
Start: 2024-06-06 23:52:58 +0200 CEST
Finished: 2024-06-06 23:52:59 +0200 CEST
Duration: 1s
Message: successfully synced (all tasks run)
GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
Service default gitlab-k8s-example-project-helm-guestbook Synced Healthy service/gitlab-k8s-example-project-helm-guestbook created
apps Deployment default gitlab-k8s-example-project-helm-guestbook Synced Progressing deployment.apps/gitlab-k8s-example-project-helm-guestbook created
Check Application Status #
# List the application status
argocd app get gitlab-k8s-example-project
# Shell output:
Name: argocd/gitlab-k8s-example-project
Project: default
Server: https://kubernetes.default.svc
Namespace: default
URL: https://argocd.jklug.work/applications/gitlab-k8s-example-project
Source:
- Repo: git@gitlab.jklug.work:root/k8s-example-project.git
Target:
Path: .
SyncWindow: Sync Allowed
Sync Policy: Manual
Sync Status: Synced to (0b62635)
Health Status: Healthy
GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
Service default gitlab-k8s-example-project-helm-guestbook Synced Healthy service/gitlab-k8s-example-project-helm-guestbook created
apps Deployment default gitlab-k8s-example-project-helm-guestbook Synced Healthy deployment.apps/gitlab-k8s-example-project-helm-guestbook created
Verify the Kubernetes Deployment #
# Verify the deployment
kubectl get all -n default
# Shell output:
NAME READY STATUS RESTARTS AGE
pod/gitlab-k8s-example-project-helm-guestbook-867fb8b54c-tk7hh 1/1 Running 0 107s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/gitlab-k8s-example-project-helm-guestbook ClusterIP 10.233.21.63 <none> 80/TCP 107s
service/kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 6d2h
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/gitlab-k8s-example-project-helm-guestbook 1/1 1 1 107s
NAME DESIRED CURRENT READY AGE
replicaset.apps/gitlab-k8s-example-project-helm-guestbook-867fb8b54c 1 1 1 107s
Delete the Kubernetes Deployment #
# Delete the deployment
argocd app delete gitlab-k8s-example-project
# Shell output:
Are you sure you want to delete 'gitlab-k8s-example-project' and all its resources? [y/n] # y
application 'gitlab-k8s-example-project' deleted
Links #
# Official Documentation: Installation
https://argo-cd.readthedocs.io/en/stable/getting_started/
# Official Documentation: TLS Certificates
https://argo-cd.readthedocs.io/en/stable/operator-manual/tls/