This project demonstrates a GitOps-based CI/CD pipeline using GitHub Actions and ArgoCD to deploy applications on Kubernetes.
The application is a simple Python Flask API. The main objective is not the application itself, but to learn and practice GitOps workflows in a realistic environment.
Even though the application is minimal, the architecture is designed to be easily extended to more complex and production-ready systems.
.
├── app.py # Flask application
├── Dockerfile # Container image definition
├── .github/workflows/cicd.yml # pipeline gitops cicd with argocd
├── manifests-k8s # manifest yaml k8s
│ ├── deployment.yml
│ └── service.yml
├── requirements.txt # Python dependencies
└── README.md- Kubernetes cluster: Minikube
- Container runtime: Docker
- CI/CD pipeline: GitHub Actions
- GitOps tool: ArgoCD
- Cloud provider: VirtualData (CNRS)
- Provisioning: Terraform with cloud-init
The entire environment is deployed on a virtual machine provisioned via Terraform, with automatic setup using cloud-init scripts.
The following tools are installed automatically with terraform (cloud-init) on an AlmaLinux 9.x VM:
# Docker installation
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io
systemctl enable docker
systemctl start docker
# kubectl installation
curl -LO https://dl.k8s.io/release/v1.30.0/bin/linux/amd64/kubectl
install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
rm -f kubectl
# Minikube installation
curl -LO https://github.com/kubernetes/minikube/releases/latest/download/minikube-linux-amd64
install minikube-linux-amd64 /usr/local/bin/minikube
rm -f minikube-linux-amd64
# Create non-root user for Minikube
useradd -m devops || true
usermod -aG docker devops
# Start Minikube
su - devops -c "minikube start --driver=docker"
su - devops -c "minikube addons enable ingress"
# Configure kubectl access
mkdir -p /root/.kube
cp /home/devops/.kube/config /root/.kube/config || true
export KUBECONFIG=/root/.kube/config
# Install ArgoCD
su - devops -c "kubectl create namespace argocd || true"
su - devops -c "kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml"
sleep 60
# Expose ArgoCD service via NodePort
kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "NodePort"}}'After deployment, connect to the VM:
sudo su - devops
kubectl get svc -n argocd# HTTP
kubectl port-forward --address 0.0.0.0 svc/argocd-server 8000:80 -n argocd
# HTTPS
kubectl port-forward --address 0.0.0.0 svc/argocd-server 8443:443 -n argocdAccess in browser:
http://<VM_PUBLIC_IP>:8000Important:
- The command must remain running
- Ensure the firewall allows the port
Example:
sudo firewall-cmd --add-port=8000/tcp --permanent
sudo firewall-cmd --reloadkubectl port-forward --address 0.0.0.0 svc/my-service 5000:5000 -n argocdAccess:
http://<VM_PUBLIC_IP>:5000
kubectl get secret argocd-initial-admin-secret \
-n argocd \
-o jsonpath="{.data.password}" | base64 -dCredentials:
- Username: admin
- Password: output of the command above
Required for GitHub Actions to push changes.
Create it in: Settings → Developer Settings → Personal Access Tokens
Required scopes:
- repo
- workflow
- admin:repo_hook
Go to: Repository → Settings → Secrets and variables → Actions
ARGOCD_SERVER
ARGOCD_USERNAME
ARGOCD_PASSWORD
DOCKERHUB_USERNAME
DOCKERHUB_TOKEN
PERSONAL_ACCESS_TOKEN
GIT_USERNAME
GIT_EMAIL
In the ArgoCD UI:
- Go to Settings → Repositories
- Click Connect Repo
- Method: HTTPS
- Type: Git
- Project: default
- Repository URL: your GitHub repository
Then click Connect.
kubectl delete ns argocd
minikube stop
minikube delete --allOptionally terminate the VM from your cloud provider.
