commit ca6e6b35d607798a2435a806c1387016673e1a37 Author: guipguia Date: Fri Jan 16 16:31:15 2026 +0000 feat: 🎸 initial commit diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..51f17ea --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,5 @@ +[defaults] +inventory = ./inventory.ini +host_key_checking = False +nocows = 1 +deprecation_warnings = False diff --git a/inventory.ini b/inventory.ini new file mode 100644 index 0000000..5d4555f --- /dev/null +++ b/inventory.ini @@ -0,0 +1,3 @@ +[microk8s_nodes] +; Replace with your actual IP address +target_host ansible_host=192.168.50.118 ansible_user=guipguia diff --git a/playbook.yml b/playbook.yml new file mode 100644 index 0000000..e3e3e01 --- /dev/null +++ b/playbook.yml @@ -0,0 +1,19 @@ +--- +- name: Setup Single Node MicroK8s Cluster + hosts: microk8s_nodes + become: true + vars_prompt: + - name: cloudflare_token + prompt: "Enter your Cloudflare API Token" + private: yes + - name: acme_email + prompt: "Enter your Email for Let's Encrypt" + private: no + roles: + - common + - microk8s + - helm + - argocd + - traefik_gateway + - cert_manager + - gitea diff --git a/roles/argocd/tasks/main.yml b/roles/argocd/tasks/main.yml new file mode 100644 index 0000000..db362b9 --- /dev/null +++ b/roles/argocd/tasks/main.yml @@ -0,0 +1,21 @@ +--- +- name: Add ArgoCD Helm repository + command: /snap/bin/helm repo add argo https://argoproj.github.io/argo-helm + become: false + changed_when: false + +- name: Update Helm repositories + command: /snap/bin/helm repo update + become: false + changed_when: false + +- name: Install/Upgrade ArgoCD + command: > + /snap/bin/helm upgrade --install argocd argo/argo-cd + --namespace argocd + --create-namespace + --set server.service.type=NodePort + --wait + become: false + register: argocd_install + changed_when: "'Release \"argocd\" does not exist' in argocd_install.stdout or 'Happy Helming' in argocd_install.stdout" diff --git a/roles/cert_manager/tasks/main.yml b/roles/cert_manager/tasks/main.yml new file mode 100644 index 0000000..696770e --- /dev/null +++ b/roles/cert_manager/tasks/main.yml @@ -0,0 +1,66 @@ +--- +- name: Add Jetstack Helm Repo + kubernetes.core.helm_repository: + name: jetstack + repo_url: https://charts.jetstack.io + +- name: Install Cert Manager + kubernetes.core.helm: + name: cert-manager + chart_ref: jetstack/cert-manager + release_namespace: cert-manager + create_namespace: true + values: + installCRDs: true + extraArgs: + - --feature-gates=ExperimentalGatewayAPISupport=true + wait: true + +- name: Create Cloudflare Secret + kubernetes.core.k8s: + definition: + apiVersion: v1 + kind: Secret + metadata: + name: cloudflare-api-token + namespace: cert-manager + type: Opaque + stringData: + api-token: "{{ cloudflare_token }}" + +- name: Create Cloudflare ClusterIssuer + kubernetes.core.k8s: + definition: + apiVersion: cert-manager.io/v1 + kind: ClusterIssuer + metadata: + name: letsencrypt-prod + spec: + acme: + email: "{{ acme_email }}" + server: https://acme-v02.api.letsencrypt.org/directory + privateKeySecretRef: + name: letsencrypt-prod-account-key + solvers: + - dns01: + cloudflare: + email: "{{ acme_email }}" + apiTokenSecretRef: + name: cloudflare-api-token + key: api-token + +- name: Create Certificate for Gitea + kubernetes.core.k8s: + definition: + apiVersion: cert-manager.io/v1 + kind: Certificate + metadata: + name: git-svc-pguia-com-tls + namespace: traefik + spec: + secretName: git-svc-pguia-com-tls + issuerRef: + name: letsencrypt-prod + kind: ClusterIssuer + dnsNames: + - git.svc.pguia.com diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml new file mode 100644 index 0000000..e789c40 --- /dev/null +++ b/roles/common/tasks/main.yml @@ -0,0 +1,31 @@ +--- +- name: Update apt cache and upgrade all packages + apt: + update_cache: yes + upgrade: dist + cache_valid_time: 3600 + +- name: Install required packages + apt: + name: + - curl + - git + - htop + - snapd + - python3-kubernetes + - python3-pip + state: present + +- name: Ensure snapd service is running + service: + name: snapd + state: started + enabled: yes + +- name: Enable IPv4 forwarding + sysctl: + name: net.ipv4.ip_forward + value: '1' + sysctl_set: yes + state: present + reload: yes diff --git a/roles/gitea/tasks/main.yml b/roles/gitea/tasks/main.yml new file mode 100644 index 0000000..4f98e85 --- /dev/null +++ b/roles/gitea/tasks/main.yml @@ -0,0 +1,79 @@ +--- +- name: Add Gitea Helm Repo + kubernetes.core.helm_repository: + name: gitea + repo_url: https://dl.gitea.com/charts/ + +- name: Install Gitea + kubernetes.core.helm: + name: gitea + chart_ref: gitea/gitea + release_namespace: gitea + create_namespace: true + values: + gitea: + config: + server: + ROOT_URL: "https://git.svc.pguia.com/" + DOMAIN: "git.svc.pguia.com" + SSH_DOMAIN: "git.svc.pguia.com" + SSH_PORT: "2222" + SSH_LISTEN_PORT: "22" + ingress: + enabled: false + postgresql: + enabled: true + postgresql-ha: + enabled: false + persistence: + enabled: true + storageClass: microk8s-hostpath + size: 150Gi + postgresql: + enabled: true + persistence: + enabled: true + storageClass: microk8s-hostpath + size: 50Gi + wait: true + +- name: Create HTTPRoute for Gitea + kubernetes.core.k8s: + definition: + apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: gitea-route + namespace: gitea + spec: + parentRefs: + - name: main-gateway + namespace: traefik + hostnames: + - "git.svc.pguia.com" + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: gitea-http + port: 3000 + +- name: Create TCPRoute for Gitea SSH + kubernetes.core.k8s: + definition: + apiVersion: gateway.networking.k8s.io/v1alpha2 + kind: TCPRoute + metadata: + name: gitea-ssh-route + namespace: gitea + spec: + parentRefs: + - name: main-gateway + namespace: traefik + sectionName: ssh + rules: + - backendRefs: + - name: gitea-ssh + port: 22 diff --git a/roles/helm/tasks/main.yml b/roles/helm/tasks/main.yml new file mode 100644 index 0000000..5ac1563 --- /dev/null +++ b/roles/helm/tasks/main.yml @@ -0,0 +1,5 @@ +--- +- name: Install Helm snap + command: snap install helm --classic + args: + creates: /snap/bin/helm diff --git a/roles/microk8s/tasks/main.yml b/roles/microk8s/tasks/main.yml new file mode 100644 index 0000000..44977f3 --- /dev/null +++ b/roles/microk8s/tasks/main.yml @@ -0,0 +1,77 @@ +--- +- name: Install MicroK8s snap + command: snap install microk8s --classic --channel=1.35/stable + args: + creates: /snap/bin/microk8s + +- name: Wait for MicroK8s to be ready + command: microk8s status --wait-ready + changed_when: false + register: mk8s_status + until: mk8s_status.rc == 0 + retries: 10 + delay: 10 + +- name: Add user to microk8s group + user: + name: "{{ ansible_user }}" + groups: microk8s + append: yes + +- name: Create .kube directory + file: + path: "/home/{{ ansible_user }}/.kube" + state: directory + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" + mode: '0755' + +- name: Generate kubeconfig + shell: microk8s config > /home/{{ ansible_user }}/.kube/config + changed_when: false + # We might want to make this idempotent by checking file existence or content, + # but regenerating it is usually fine/safe. + +- name: Set ownership of kubeconfig + file: + path: "/home/{{ ansible_user }}/.kube/config" + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" + mode: '0600' + +- name: Create .kube directory for root + file: + path: /root/.kube + state: directory + mode: '0700' + owner: root + group: root + +- name: Generate kubeconfig for root + shell: microk8s config > /root/.kube/config + changed_when: false + +- name: Add kubectl alias to .bashrc + lineinfile: + path: "/home/{{ ansible_user }}/.bashrc" + line: "alias kubectl='microk8s kubectl'" + regexp: "^alias kubectl='microk8s kubectl'$" + state: present + +- name: Enable MicroK8s addons + command: microk8s enable dns hostpath-storage metallb:192.168.50.240-192.168.50.250 + register: enable_addons + changed_when: "'already enabled' not in enable_addons.stdout" + failed_when: + - enable_addons.rc != 0 + - "'already enabled' not in enable_addons.stdout" + +- name: Patch hostpath-provisioner to use /data + shell: | + microk8s kubectl patch deployment hostpath-provisioner -n kube-system --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/volumes/0/hostPath/path", "value": "/data/microk8s-storage"}]' + register: patch_hostpath + changed_when: "'patched' in patch_hostpath.stdout" + retries: 5 + delay: 10 + until: patch_hostpath.rc == 0 + diff --git a/roles/traefik_gateway/tasks/main.yml b/roles/traefik_gateway/tasks/main.yml new file mode 100644 index 0000000..24989f8 --- /dev/null +++ b/roles/traefik_gateway/tasks/main.yml @@ -0,0 +1,101 @@ +--- +- name: Install Gateway API CRDs + shell: | + microk8s kubectl apply --server-side -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.1/experimental-install.yaml + register: install_crds + changed_when: "'configured' in install_crds.stdout or 'created' in install_crds.stdout" + +- name: Install Traefik CRDs + shell: | + microk8s kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.4/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml + register: install_traefik_crds + changed_when: "'configured' in install_traefik_crds.stdout or 'created' in install_traefik_crds.stdout" + +- name: Add Traefik Helm Repo + kubernetes.core.helm_repository: + name: traefik + repo_url: https://traefik.github.io/charts + +- name: Install Traefik with Gateway API support + kubernetes.core.helm: + name: traefik + chart_ref: traefik/traefik + release_namespace: traefik + create_namespace: true + values: + providers: + kubernetesGateway: + enabled: true + ports: + web: + port: 80 + websecure: + port: 443 + ssh: + port: 2222 + expose: + default: true + exposedPort: 2222 + protocol: TCP + service: + type: LoadBalancer + gateway: + enabled: false + gatewayClass: + enabled: false + securityContext: + capabilities: + drop: [ALL] + add: [NET_BIND_SERVICE] + runAsNonRoot: true + runAsUser: 65532 + runAsGroup: 65532 + skip_crds: true + wait: true + +- name: Create Gateway Class + kubernetes.core.k8s: + definition: + apiVersion: gateway.networking.k8s.io/v1 + kind: GatewayClass + metadata: + name: traefik + spec: + controllerName: traefik.io/gateway-controller + +- name: Create Gateway + kubernetes.core.k8s: + definition: + apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: main-gateway + namespace: traefik + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + spec: + gatewayClassName: traefik + listeners: + - name: web + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: All + - name: websecure + port: 443 + protocol: HTTPS + hostname: git.svc.pguia.com + tls: + mode: Terminate + certificateRefs: + - name: git-svc-pguia-com-tls + allowedRoutes: + namespaces: + from: All + - name: ssh + port: 2222 + protocol: TCP + allowedRoutes: + namespaces: + from: All