From c87dae31ad8f717ea34c65e2e34c14301e19b95e Mon Sep 17 00:00:00 2001 From: Junwei Zhao Date: Sat, 12 Apr 2025 00:18:25 +1000 Subject: [PATCH] Create argocd --- apply.sh | 13 ++- fix_redis.sh | 39 +++++++++ terraform/argocd.tf | 119 +++++++++++++++++++++++++++ terraform/main.tf | 44 +++++++++- terraform/redis.tf | 123 ++++++++++++++++++++++++++++ terraform/setup_argocd.sh | 56 +++++++++++++ terraform/values/argocd-values.yaml | 83 +++++++++++++++++++ 7 files changed, 475 insertions(+), 2 deletions(-) create mode 100755 fix_redis.sh create mode 100644 terraform/argocd.tf create mode 100644 terraform/redis.tf create mode 100755 terraform/setup_argocd.sh create mode 100644 terraform/values/argocd-values.yaml diff --git a/apply.sh b/apply.sh index f118322..b664610 100755 --- a/apply.sh +++ b/apply.sh @@ -314,4 +314,15 @@ sudo apt install kubeadm=1.30.11-1.1 # passless sudo - echo "junv ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/junv \ No newline at end of file + echo "junv ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/junv + + +# View last N lines: + +ssh junv@192.168.1.2 -p22422 "sudo journalctl -u k3s -n 100" +# View logs since a specific time: + +ssh junv@192.168.1.2 -p22422 "sudo journalctl -u k3s --since '10 minutes ago'" +# View logs with timestamps: + +ssh junv@192.168.1.2 -p22422 "sudo journalctl -u k3s -f -o short-precise" \ No newline at end of file diff --git a/fix_redis.sh b/fix_redis.sh new file mode 100755 index 0000000..a45826e --- /dev/null +++ b/fix_redis.sh @@ -0,0 +1,39 @@ +#!/bin/bash +set -e + +echo "Stopping Redis service..." +sudo systemctl stop redis-server + +echo "Creating Redis configuration file..." +sudo bash -c 'cat > /etc/redis/redis.conf << EOF +bind 0.0.0.0 +protected-mode no +port 6379 +dir /mnt/k8s/redis +appendonly yes +appendfilename "appendonly.aof" +appendfsync everysec +save 900 1 +save 300 10 +save 60 10000 +EOF' + +echo "Setting permissions for Redis configuration..." +sudo chown redis:redis /etc/redis/redis.conf +sudo chmod 640 /etc/redis/redis.conf + +echo "Creating symbolic links to Redis data files..." +sudo ln -sf /mnt/k8s/redis/appendonlydir/appendonly.aof.149903.base.rdb /mnt/k8s/redis/dump.rdb +sudo ln -sf /mnt/k8s/redis/appendonlydir/appendonly.aof.149903.incr.aof /mnt/k8s/redis/appendonly.aof + +echo "Updating systemd service file..." +sudo sed -i '/ReadWritePaths=-\/mnt\/k8s\/redis/a ReadWritePaths=-\/mnt\/k8s\/redis\/appendonlydir' /etc/systemd/system/redis-server.service + +echo "Reloading systemd and restarting Redis..." +sudo systemctl daemon-reload +sudo systemctl restart redis-server +sleep 5 + +echo "Checking Redis data..." +sudo redis-cli dbsize +sudo redis-cli keys '*' | head -5 diff --git a/terraform/argocd.tf b/terraform/argocd.tf new file mode 100644 index 0000000..c6eb04c --- /dev/null +++ b/terraform/argocd.tf @@ -0,0 +1,119 @@ +resource "kubernetes_namespace" "argocd" { + metadata { + name = "argocd" + } +} + +# Install cert-manager +resource "helm_release" "cert_manager" { + name = "cert-manager" + repository = "https://charts.jetstack.io" + chart = "cert-manager" + version = "v1.14.3" + namespace = "cert-manager" + create_namespace = true + + set { + name = "installCRDs" + value = "true" + } +} + +# Install nginx-ingress +resource "helm_release" "ingress_nginx" { + name = "ingress-nginx" + repository = "https://kubernetes.github.io/ingress-nginx" + chart = "ingress-nginx" + version = "4.9.1" + namespace = "ingress-nginx" + create_namespace = true + + set { + name = "controller.service.type" + value = "NodePort" + } + + set { + name = "controller.service.nodePorts.http" + value = "80" + } + + set { + name = "controller.service.nodePorts.https" + value = "443" + } + + set { + name = "controller.publishService.enabled" + value = "false" + } + + set { + name = "controller.extraArgs.publish-status-address" + value = "192.168.1.2" + } +} + +# Check for cert-manager CRDs before proceeding +resource "null_resource" "wait_for_cert_manager_crds" { + depends_on = [helm_release.cert_manager] + + provisioner "local-exec" { + command = <<-EOT + # Wait for cert-manager to be ready + echo "Waiting for cert-manager CRDs to be available..." + + # Wait for the webhook to be ready first + echo "Waiting for cert-manager webhook pod to be ready..." + kubectl -n cert-manager wait --for=condition=ready pod -l app=webhook --timeout=120s + + # Try up to 10 times with increasing sleep between attempts + for i in $(seq 1 10); do + echo "Attempt $i to verify cert-manager CRDs..." + + # Check if the ClusterIssuer CRD exists + if kubectl get crd clusterissuers.cert-manager.io > /dev/null 2>&1; then + echo "ClusterIssuer CRD found!" + exit 0 + fi + + # Increase wait time with each attempt + sleep_time=$((i * 5)) + echo "CRDs not found yet, waiting $sleep_time seconds..." + sleep $sleep_time + done + + # If we get here, we've failed to find the CRDs + echo "Failed to find cert-manager CRDs after multiple attempts" + exit 1 + EOT + } +} + +# Note: ClusterIssuer is now managed outside of Terraform +# TODO: Automate the ClusterIssuer creation +# We've already created it manually with the setup_argocd.sh script + +# Install ArgoCD +resource "helm_release" "argocd" { + name = "argocd" + repository = "https://argoproj.github.io/argo-helm" + chart = "argo-cd" + version = "5.55.0" + namespace = kubernetes_namespace.argocd.metadata[0].name + + values = [ + file("${path.module}/values/argocd-values.yaml") + ] + + depends_on = [ + helm_release.cert_manager, + helm_release.ingress_nginx + ] + + # Add timeout to ensure ArgoCD has enough time to install + timeout = 900 + + # Add retry logic in case of failure + recreate_pods = true +} diff --git a/terraform/main.tf b/terraform/main.tf index f99b97b..d9c5841 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -4,6 +4,18 @@ terraform { source = "loafoe/ssh" version = "2.6.0" } + kubernetes = { + source = "hashicorp/kubernetes" + version = "2.27.0" + } + helm = { + source = "hashicorp/helm" + version = "2.12.1" + } + kubectl = { + source = "gavinbunney/kubectl" + version = "1.14.0" + } } } @@ -16,6 +28,20 @@ locals { token_cmd = "ssh -p ${local.ssh_port} ${local.ssh_user}@${local.ssh_host} 'sudo cat /var/lib/rancher/k3s/server/node-token'" } +provider "kubernetes" { + config_path = "~/.kube/config" +} + +provider "helm" { + kubernetes { + config_path = "~/.kube/config" + } +} + +provider "kubectl" { + config_path = "~/.kube/config" +} + resource "ssh_resource" "k3s_install" { host = local.ssh_host user = local.ssh_user @@ -29,7 +55,7 @@ resource "ssh_resource" "k3s_install" { "echo 'Installing k3s...'", "curl -sfL https://get.k3s.io > install.sh", "chmod +x install.sh", - "INSTALL_K3S_EXEC='--tls-san ${local.ssh_host}' sudo -E ./install.sh", + "INSTALL_K3S_EXEC='--tls-san ${local.ssh_host} --kube-apiserver-arg service-node-port-range=80-32767 --disable traefik' sudo -E ./install.sh", "echo 'Waiting for k3s to start (60s)...'", "sleep 60", "sudo chmod 644 /etc/rancher/k3s/k3s.yaml", @@ -63,3 +89,19 @@ K3s cluster setup complete! Next steps: ${local.token_cmd} EOT } + +output "argocd_access" { + value = < /etc/redis/redis.conf << EOF +bind 0.0.0.0 +protected-mode no +port 6379 +dir /mnt/k8s/redis +appendonly yes +appendfilename "appendonly.aof" +appendfsync everysec +save 900 1 +save 300 10 +save 60 10000 +aof-use-rdb-preamble yes +aof-load-truncated yes +aof-rewrite-incremental-fsync yes +EOF' + +# Update systemd service file to allow access to appendonlydir +if ! sudo grep -q "ReadWritePaths=-/mnt/k8s/redis/appendonlydir" /etc/systemd/system/redis-server.service; then + sudo sed -i '/ReadWritePaths=-\/mnt\/k8s\/redis/a ReadWritePaths=-\/mnt\/k8s\/redis\/appendonlydir' /etc/systemd/system/redis-server.service || true +fi + +# Ensure proper permissions +sudo chown redis:redis /etc/redis/redis.conf +sudo chmod 640 /etc/redis/redis.conf +sudo chown -R redis:redis /mnt/k8s/redis +sudo chmod -R 750 /mnt/k8s/redis + +# Reload systemd and restart Redis +sudo systemctl daemon-reload +sudo systemctl restart redis-server +echo "Waiting for Redis to start..." +sleep 5 +sudo systemctl status redis-server --no-pager || true + +# Verify Redis data was loaded +echo "Checking Redis data..." +sudo redis-cli dbsize +sudo redis-cli keys '*' | head -5 || true +echo "Redis installation completed!" +EOT + + file_permission = "0755" +} + +# Create the scripts directory if it doesn't exist +resource "null_resource" "create_scripts_dir" { + provisioner "local-exec" { + command = "mkdir -p ${path.module}/scripts" + } +} + +# Upload and execute the Redis installation script +resource "ssh_resource" "redis_install" { + depends_on = [local_file.redis_install_script, null_resource.create_scripts_dir] + + host = local.ssh_host + user = local.ssh_user + port = local.ssh_port + private_key = local.ssh_private_key + timeout = "5m" + + when = "create" + + file { + source = local_file.redis_install_script.filename + destination = "/tmp/install_redis.sh" + permissions = "0755" + } + + commands = [ + "bash /tmp/install_redis.sh" + ] +} diff --git a/terraform/setup_argocd.sh b/terraform/setup_argocd.sh new file mode 100755 index 0000000..a3078c9 --- /dev/null +++ b/terraform/setup_argocd.sh @@ -0,0 +1,56 @@ +#!/bin/bash +set -e + +echo "==== Setting up ArgoCD and Let's Encrypt ClusterIssuer ====" + +# Wait for cert-manager to be ready +echo "Waiting for cert-manager webhook to be ready..." +kubectl -n cert-manager wait --for=condition=available --timeout=180s deployment/cert-manager-webhook || true + +# Wait for the CRDs to be established +echo "Waiting for cert-manager CRDs to be available..." +for i in $(seq 1 10); do + echo "Attempt $i to verify cert-manager CRDs..." + + if kubectl get crd clusterissuers.cert-manager.io > /dev/null 2>&1; then + echo "ClusterIssuer CRD found!" + break + fi + + sleep_time=$((i * 5)) + echo "CRDs not found yet, waiting $sleep_time seconds..." + sleep $sleep_time + + if [ $i -eq 10 ]; then + echo "Failed to find cert-manager CRDs after multiple attempts" + exit 1 + fi +done + +# Create the ClusterIssuer +echo "Creating Let's Encrypt ClusterIssuer..." +cat > letsencrypt-issuer.yaml << EOF +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-prod +spec: + acme: + email: me@junv.cc + server: https://acme-v02.api.letsencrypt.org/directory + privateKeySecretRef: + name: letsencrypt-prod + solvers: + - http01: + ingress: + class: nginx +EOF + +kubectl apply -f letsencrypt-issuer.yaml + +# Verify the ClusterIssuer was created +echo "Verifying ClusterIssuer..." +kubectl get clusterissuer letsencrypt-prod + +echo "==== ClusterIssuer setup complete ====" +echo "You can now run 'terraform apply' to continue with the ArgoCD installation" diff --git a/terraform/values/argocd-values.yaml b/terraform/values/argocd-values.yaml new file mode 100644 index 0000000..b7b723e --- /dev/null +++ b/terraform/values/argocd-values.yaml @@ -0,0 +1,83 @@ +server: + service: + type: LoadBalancer + replicas: 1 + extraArgs: + - --insecure + config: + repositories: | + - type: git + url: https://github.com/argoproj/argocd-example-apps.git + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: "nginx" + kubernetes.io/tls-acme: "true" + cert-manager.io/cluster-issuer: "letsencrypt-prod" + nginx.ingress.kubernetes.io/proxy-body-size: 102400m + hostname: "argo.junv.cc" + tls: + - hosts: + - argo.junv.cc + secretName: argocd-tls + metrics: + enabled: false + serviceMonitor: + enabled: true + env: + - name: ARGOCD_API_SERVER_REPLICAS + value: '2' + +configs: + cm: + timeout.reconciliation: 60s + application.instanceLabelKey: argocd.argoproj.io/instance + +controller: + enableStatefulSet: true + metrics: + enabled: true + serviceMonitor: + enabled: true + resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 250m + memory: 256Mi + +repoServer: + replicas: 1 + metrics: + enabled: false + serviceMonitor: + enabled: true + resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 250m + memory: 256Mi + +redis-ha: + enabled: false + +redis: + enabled: false + +externalRedis: + enabled: true + host: "192.168.1.2" + port: 6379 + +applicationSet: + metrics: + enabled: false + serviceMonitor: + enabled: true + +global: + logging: + level: "warn"