From 2f850d18aa326554eb346626d2a2668f1a6b98ad Mon Sep 17 00:00:00 2001 From: Jun-te Kim Date: Thu, 12 Mar 2026 20:36:34 +0000 Subject: [PATCH] moved all workflows: --- .../disabled/basic-system-information.yml | 40 ++ .github/workflows/disabled/ha.yml | 46 +++ .github/workflows/disabled/juntekim.yml | 97 +++++ .../disabled/k8s_traefik_init_setup.yml | 131 +++++++ .github/workflows/disabled/n8n.yml | 53 +++ .github/workflows/disabled/pihole.yml | 47 +++ .github/workflows/disabled/ses-juntekim.yml | 71 ++++ .../workflows/disabled/stripe-to-invoice.yml | 347 ++++++++++++++++++ .../workflows/disabled/terraform-apply.yml | 128 +++++++ .github/workflows/disabled/terraform-plan.yml | 89 +++++ 10 files changed, 1049 insertions(+) create mode 100644 .github/workflows/disabled/basic-system-information.yml create mode 100644 .github/workflows/disabled/ha.yml create mode 100644 .github/workflows/disabled/juntekim.yml create mode 100644 .github/workflows/disabled/k8s_traefik_init_setup.yml create mode 100644 .github/workflows/disabled/n8n.yml create mode 100644 .github/workflows/disabled/pihole.yml create mode 100644 .github/workflows/disabled/ses-juntekim.yml create mode 100644 .github/workflows/disabled/stripe-to-invoice.yml create mode 100644 .github/workflows/disabled/terraform-apply.yml create mode 100644 .github/workflows/disabled/terraform-plan.yml diff --git a/.github/workflows/disabled/basic-system-information.yml b/.github/workflows/disabled/basic-system-information.yml new file mode 100644 index 0000000..3881e1f --- /dev/null +++ b/.github/workflows/disabled/basic-system-information.yml @@ -0,0 +1,40 @@ +name: Basic System Information +on: + workflow_dispatch: + +jobs: + Basic-system-information: + runs-on: mealcraft-runners + container: ubuntu:22.04 + steps: + - uses: actions/checkout@v4 + - name: hi + run: echo "hi" + - name: user + run: echo $USER + - name: home + run: echo $HOME + - name: pwd + run: pwd + - name: ls -la + run: ls -la + - name: Install kubectl + run: | + apt-get update + apt-get install -y ca-certificates curl + curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + install -m 0755 kubectl /usr/local/bin/kubectl + - name: Configure kubeconfig from runner SA + run: | + KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT" + SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) + CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt + NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace) + + kubectl config set-cluster k8s --server="$KUBE_HOST" --certificate-authority="$CA_CERT" + kubectl config set-credentials sa --token="$SA_TOKEN" + kubectl config set-context sa-context --cluster=k8s --user=sa --namespace="$NAMESPACE" + kubectl config use-context sa-context + + - name: kubectl test + run: kubectl get pods -A \ No newline at end of file diff --git a/.github/workflows/disabled/ha.yml b/.github/workflows/disabled/ha.yml new file mode 100644 index 0000000..440535b --- /dev/null +++ b/.github/workflows/disabled/ha.yml @@ -0,0 +1,46 @@ +name: Deploy Home Assistant + +on: + push: + branches: + - main + +env: + MANIFEST_PATH: "homeassistant/homeassistant.yml" + +jobs: + deploy: + runs-on: mealcraft-runners + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Install kubectl + run: | + sudo apt-get update + sudo apt-get install -y curl ca-certificates + curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + sudo install -m 0755 kubectl /usr/local/bin/kubectl + + - name: Install envsubst + run: | + sudo apt-get update + sudo apt-get install -y gettext + + - name: Configure kubeconfig + run: | + KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT" + SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) + CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt + NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace) + + kubectl config set-cluster microk8s --server="$KUBE_HOST" --certificate-authority="$CA_CERT" + kubectl config set-credentials runner --token="$SA_TOKEN" + kubectl config set-context runner-context --cluster=microk8s --user=runner --namespace="$NAMESPACE" + kubectl config use-context runner-context + + - name: Deploy Home Assistant + run: | + echo "Deploying Home Assistant from $MANIFEST_PATH" + kubectl apply -f $MANIFEST_PATH diff --git a/.github/workflows/disabled/juntekim.yml b/.github/workflows/disabled/juntekim.yml new file mode 100644 index 0000000..4401602 --- /dev/null +++ b/.github/workflows/disabled/juntekim.yml @@ -0,0 +1,97 @@ +name: Build juntekim.com + +on: + push: + tags: + - "*" + branches: + - "**" + +jobs: + Push-to-juntekim-to-docker-hub: + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v3 + + - name: Inject slug/short variables + uses: rlespinasse/github-slug-action@v4 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} + + - name: Build Docker Image + run: | + docker build \ + -f juntekim_frontend/deployment/Dockerfile \ + -t docker.io/kimjunte/portfolio_page:$GITHUB_REF_SLUG \ + juntekim_frontend + + - name: Push to Docker Hub + run: | + docker push docker.io/kimjunte/portfolio_page:$GITHUB_REF_SLUG + + + run-on-k8s: + runs-on: mealcraft-runners # <-- your ARC scale set label + needs: Push-to-juntekim-to-docker-hub + steps: + - uses: actions/checkout@v4 + + # Install kubectl inside containerMode's default Ubuntu + - name: Install kubectl + run: | + sudo apt-get update + sudo apt-get install -y curl ca-certificates + curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + sudo install -m 0755 kubectl /usr/local/bin/kubectl + + - name: Install envsubst + run: | + sudo apt-get update + sudo apt-get install -y gettext # <---- envsubst lives here + + # Configure kubeconfig from ARC's service account + - name: Configure kubeconfig + run: | + KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT" + SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) + CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt + NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace) + + kubectl config set-cluster microk8s --server="$KUBE_HOST" --certificate-authority="$CA_CERT" + kubectl config set-credentials runner --token="$SA_TOKEN" + kubectl config set-context runner-context --cluster=microk8s --user=runner --namespace="$NAMESPACE" + kubectl config use-context runner-context + + - name: Inject slug variables + uses: rlespinasse/github-slug-action@v4 + + - name: Set namespace + id: ns + run: | + if [[ $GITHUB_REF == refs/tags/* ]]; then + echo "NAMESPACE=default" >> $GITHUB_ENV + else + echo "NAMESPACE=staging" >> $GITHUB_ENV + fi + + - name: Set hostname + run: | + if [ "$NAMESPACE" = "staging" ]; then + echo "HOSTNAME=staging.juntekim.com" >> $GITHUB_ENV + else + echo "HOSTNAME=juntekim.com" >> $GITHUB_ENV + fi + + - name: Deploy to Kubernetes + run: | + export IMAGE="docker.io/kimjunte/portfolio_page:$GITHUB_REF_SLUG" + export NAMESPACE HOSTNAME + + envsubst < juntekim_frontend/deployment/deployment.yml | kubectl apply -f - + envsubst < juntekim_frontend/deployment/service.yml | kubectl apply -f - + envsubst < juntekim_frontend/deployment/ingressroute.yml | kubectl apply -f - diff --git a/.github/workflows/disabled/k8s_traefik_init_setup.yml b/.github/workflows/disabled/k8s_traefik_init_setup.yml new file mode 100644 index 0000000..ba713cd --- /dev/null +++ b/.github/workflows/disabled/k8s_traefik_init_setup.yml @@ -0,0 +1,131 @@ +name: K8s Bootstrap Setup + +on: + workflow_dispatch: + +jobs: + + # ----------------------------------------------------- + # Job 1: Build and push image using GitHub-hosted runner + # ----------------------------------------------------- + build-image: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + # Docker login on GitHub-hosted runner (has Docker) + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} + + # Build and push using real Docker daemon + - name: Build & Push Traefik Image + uses: docker/build-push-action@v5 + with: + context: ./traefik + file: ./traefik/Dockerfile + push: true + tags: | + docker.io/kimjunte/edge_router:${{ github.sha }} + docker.io/kimjunte/edge_router:latest + + # ----------------------------------------------------- + # Job 2: Deploy to MicroK8s using ARC self-hosted runner + # ----------------------------------------------------- + deploy: + runs-on: mealcraft-runners + needs: build-image + + steps: + - uses: actions/checkout@v4 + + # Install kubectl inside containerMode's default Ubuntu + - name: Install kubectl + run: | + sudo apt-get update + sudo apt-get install -y curl ca-certificates + curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + sudo install -m 0755 kubectl /usr/local/bin/kubectl + + # Configure kubeconfig from ARC's service account + - name: Configure kubeconfig + run: | + KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT" + SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) + CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt + NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace) + + kubectl config set-cluster microk8s --server="$KUBE_HOST" --certificate-authority="$CA_CERT" + kubectl config set-credentials runner --token="$SA_TOKEN" + kubectl config set-context runner-context --cluster=microk8s --user=runner --namespace="$NAMESPACE" + kubectl config use-context runner-context + + # ----------------------------------------------------- + # ⭐ Inject AWS secrets needed for Traefik Route53 DNS + # ----------------------------------------------------- + - name: Apply AWS Secrets + run: | + kubectl create secret generic aws-secrets \ + --namespace=default \ + --from-literal=AWS_ACCESS_KEY_ID='${{ secrets.AWS_ACCESS_KEY_ID }}' \ + --from-literal=AWS_SECRET_ACCESS_KEY='${{ secrets.AWS_SECRET_ACCESS_KEY }}' \ + --from-literal=AWS_REGION='${{ secrets.AWS_REGION }}' \ + --dry-run=client -o yaml | kubectl apply -f - + + - name: Apply AWS Secrets + run: | + kubectl create namespace arc-systems \ + --dry-run=client -o yaml | kubectl apply -f - + + kubectl create secret generic aws-secrets \ + --namespace=arc-systems \ + --from-literal=AWS_ACCESS_KEY_ID='${{ secrets.AWS_ACCESS_KEY_ID }}' \ + --from-literal=AWS_SECRET_ACCESS_KEY='${{ secrets.AWS_SECRET_ACCESS_KEY }}' \ + --from-literal=AWS_REGION='${{ secrets.AWS_REGION }}' \ + --dry-run=client -o yaml | kubectl apply -f - + + # Apply storage classes + PVs + - name: Apply StorageClass + PV + run: | + kubectl apply -f traefik/storageclass/storageclass.yaml + kubectl apply -f traefik/storageclass/certs-pv.yaml + + # # Install Traefik CRDs (idempotent) + # - name: Install Traefik CRDs + # run: | + # kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v2.11/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml + # kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v2.11/docs/content/reference/dynamic-configuration/kubernetes-crd-rbac.yml + + # Deploy Traefik + - name: Deploy Traefik + run: | + kubectl apply -f traefik/edge-router/pvc.yaml + kubectl apply -f traefik/edge-router/traefik-deployment.yml + kubectl apply -f traefik/edge-router/traefik-services.yml + kubectl apply -f traefik/edge-router/middleware.yaml + kubectl apply -f traefik/edge-router/secret-dashboard.yml + kubectl apply -f traefik/edge-router/traefik-ingressroute.yml + + # Deploy whoami test app + - name: Deploy whoami + run: | + kubectl apply -f traefik/who-am-i/whoami-deployment.yml + kubectl apply -f traefik/who-am-i/whoami-service.yml + kubectl apply -f traefik/who-am-i/whoami-ingressroute.yml + + # Registry secret + - name: Create registry secret (default) + run: kubectl apply -f traefik/docker-registry-credentials/docker-credentials.yml + + # Staging namespace + - name: Create staging namespace + run: kubectl get ns staging >/dev/null 2>&1 || kubectl create namespace staging + + - name: Registry secret to staging + run: | + sed 's/namespace: default/namespace: staging/' \ + traefik/docker-registry-credentials/docker-credentials.yml \ + | kubectl apply -f - diff --git a/.github/workflows/disabled/n8n.yml b/.github/workflows/disabled/n8n.yml new file mode 100644 index 0000000..b86b69d --- /dev/null +++ b/.github/workflows/disabled/n8n.yml @@ -0,0 +1,53 @@ +name: Deploy n8n + +on: + push: + branches: + - main + tags: + - "*" + +env: + IMAGE: "docker.io/n8nio/n8n:latest" + MANIFEST_PATH: "n8n/n8n.yml" + +jobs: + deploy: + runs-on: mealcraft-runners + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + # Install kubectl + - name: Install kubectl + run: | + sudo apt-get update + sudo apt-get install -y curl ca-certificates + curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + sudo install -m 0755 kubectl /usr/local/bin/kubectl + + # Install envsubst + - name: Install envsubst + run: | + sudo apt-get update + sudo apt-get install -y gettext + + # Configure kubeconfig from ARC pod service account + - name: Configure kubeconfig + run: | + KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT" + SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) + CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt + NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace) + + kubectl config set-cluster microk8s --server="$KUBE_HOST" --certificate-authority="$CA_CERT" + kubectl config set-credentials runner --token="$SA_TOKEN" + kubectl config set-context runner-context --cluster=microk8s --user=runner --namespace="$NAMESPACE" + kubectl config use-context runner-context + + - name: Deploy n8n to Kubernetes + run: | + echo "Deploying n8n with IMAGE=$IMAGE" + export IMAGE + envsubst < $MANIFEST_PATH | kubectl apply -f - diff --git a/.github/workflows/disabled/pihole.yml b/.github/workflows/disabled/pihole.yml new file mode 100644 index 0000000..9f1c8ba --- /dev/null +++ b/.github/workflows/disabled/pihole.yml @@ -0,0 +1,47 @@ +name: Deploy pihole + +on: + workflow_dispatch: + +env: + MANIFEST_PATH: "pihole/pihole.yml" + +jobs: + deploy: + runs-on: mealcraft-runners + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + # Install kubectl + - name: Install kubectl + run: | + sudo apt-get update + sudo apt-get install -y curl ca-certificates + curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + sudo install -m 0755 kubectl /usr/local/bin/kubectl + + # Install envsubst + - name: Install envsubst + run: | + sudo apt-get update + sudo apt-get install -y gettext + + # Configure kubeconfig (ARC service account) + - name: Configure kubeconfig + run: | + KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT" + SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) + CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt + NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace) + + kubectl config set-cluster microk8s --server="$KUBE_HOST" --certificate-authority="$CA_CERT" + kubectl config set-credentials runner --token="$SA_TOKEN" + kubectl config set-context runner-context --cluster=microk8s --user=runner --namespace="$NAMESPACE" + kubectl config use-context runner-context + + - name: Deploy Pi-hole to Kubernetes + run: | + echo "Deploying Pi-hole" + envsubst < $MANIFEST_PATH | kubectl apply -f - diff --git a/.github/workflows/disabled/ses-juntekim.yml b/.github/workflows/disabled/ses-juntekim.yml new file mode 100644 index 0000000..5318295 --- /dev/null +++ b/.github/workflows/disabled/ses-juntekim.yml @@ -0,0 +1,71 @@ +name: SES - juntekim.com [Simple Email Service] + +on: + pull_request: + paths: + - "aws_environment/ses-juntekim/**" + +env: + TF_VERSION: "1.6.6" + WORKING_DIR: "aws_environment/ses-juntekim" + +jobs: + terraform-plan: + name: Terraform Plan - SES + runs-on: mealcraft-runners + + permissions: + contents: read + pull-requests: write + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v3 + with: + terraform_version: ${{ env.TF_VERSION }} + + - name: Install AWS CLI v2 + run: | + sudo apt-get update + sudo apt-get install -y unzip curl + + curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" + unzip awscliv2.zip + sudo ./aws/install + + aws --version + + - name: Verify AWS identity + run: aws sts get-caller-identity + + - name: Terraform Init + working-directory: ${{ env.WORKING_DIR }} + run: terraform init + + - name: Terraform Validate + working-directory: ${{ env.WORKING_DIR }} + run: terraform validate + + - name: Terraform Plan + id: plan + working-directory: ${{ env.WORKING_DIR }} + run: terraform plan -input=false -out=tfplan + + - name: Comment Plan on PR + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + const planOutput = `${{ steps.plan.outputs.stdout }}`; + + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `## Terraform Plan - SES\n\n\`\`\`\n${planOutput}\n\`\`\`` + }); + continue-on-error: true diff --git a/.github/workflows/disabled/stripe-to-invoice.yml b/.github/workflows/disabled/stripe-to-invoice.yml new file mode 100644 index 0000000..7551991 --- /dev/null +++ b/.github/workflows/disabled/stripe-to-invoice.yml @@ -0,0 +1,347 @@ +name: Build & Deploy stripe-to-invoice (with DB secrets + migrations) + +on: + push: + branches: + - "**" + tags: + - "*" + workflow_dispatch: + +jobs: + # -------------------------------------------------- + # BUILD IMAGE + # -------------------------------------------------- + build: + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v4 + + - name: Inject slug variables + uses: rlespinasse/github-slug-action@v4 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build & push image + uses: docker/build-push-action@v6 + with: + context: . + file: stripe_to_invoice/deployment/Dockerfile + push: true + tags: docker.io/kimjunte/stripe_to_invoice:${{ env.GITHUB_REF_SLUG }} + + # -------------------------------------------------- + # DEPLOY POSTGRES (DEV / PROD) + # -------------------------------------------------- + deploy-db: + name: Deploy Postgres (PV + PVC + Deployment) + runs-on: mealcraft-runners + needs: build + + steps: + - uses: actions/checkout@v4 + + - name: Install kubectl + run: | + sudo apt-get update + sudo apt-get install -y curl ca-certificates gettext + curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + sudo install -m 0755 kubectl /usr/local/bin/kubectl + + - name: Configure kubeconfig (in-cluster) + run: | + KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT" + SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) + CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt + + kubectl config set-cluster microk8s --server="$KUBE_HOST" --certificate-authority="$CA_CERT" + kubectl config set-credentials runner --token="$SA_TOKEN" + kubectl config set-context runner-context --cluster=microk8s --user=runner + kubectl config use-context runner-context + + - name: Decide environment + run: | + if [[ "$GITHUB_REF" == refs/heads/release/* || "$GITHUB_REF" == refs/tags/* ]]; then + echo "ENV=prod" >> $GITHUB_ENV + echo "NAMESPACE=default" >> $GITHUB_ENV + echo "PG_VOLUME=stripe_invoice_prod" >> $GITHUB_ENV + else + echo "ENV=dev" >> $GITHUB_ENV + echo "NAMESPACE=dev" >> $GITHUB_ENV + echo "PG_VOLUME=stripe_invoice_dev" >> $GITHUB_ENV + fi + + - name: Apply Postgres manifests + run: | + export ENV NAMESPACE PG_VOLUME + envsubst < db/k8s/postgres/stripe-to-invoice-db.yaml | kubectl apply -f - + + # -------------------------------------------------- + # APPLY DB + APP SECRETS + # -------------------------------------------------- + secrets: + name: Apply runtime secrets + runs-on: mealcraft-runners + needs: deploy-db + + steps: + - uses: actions/checkout@v4 + + # 🔧 MINIMAL FIX (ENV bootstrap) + - name: Decide environment (from ref) + run: | + if [[ "$GITHUB_REF" == refs/heads/release/* || "$GITHUB_REF" == refs/tags/* ]]; then + echo "ENV=prod" >> $GITHUB_ENV + else + echo "ENV=dev" >> $GITHUB_ENV + fi + + - name: Install kubectl + run: | + sudo apt-get update + sudo apt-get install -y curl ca-certificates gettext + curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + sudo install -m 0755 kubectl /usr/local/bin/kubectl + + - name: Configure kubeconfig (in-cluster) + run: | + KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT" + SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) + CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt + + kubectl config set-cluster microk8s --server="$KUBE_HOST" --certificate-authority="$CA_CERT" + kubectl config set-credentials runner --token="$SA_TOKEN" + kubectl config set-context runner-context --cluster=microk8s --user=runner + kubectl config use-context runner-context + + - name: Decide environment + run: | + if [[ "$ENV" == "prod" ]]; then + echo "POSTGRES_HOST=postgres-prod.default.svc.cluster.local" >> $GITHUB_ENV + echo "POSTGRES_DB=stripe_invoice" >> $GITHUB_ENV + echo "RUNTIME_SECRET=postgres-prod" >> $GITHUB_ENV + echo "NAMESPACE=default" >> $GITHUB_ENV + else + echo "POSTGRES_HOST=postgres-dev.dev.svc.cluster.local" >> $GITHUB_ENV + echo "POSTGRES_DB=stripe_invoice" >> $GITHUB_ENV + echo "RUNTIME_SECRET=postgres-dev" >> $GITHUB_ENV + echo "NAMESPACE=dev" >> $GITHUB_ENV + fi + + - name: Apply DB secret + run: | + set -a + source db/.env + set +a + + if [[ "$ENV" == "prod" ]]; then + USER="$PROD_POSTGRES_USER" + PASS="$PROD_POSTGRES_PASSWORD" + else + USER="$DEV_POSTGRES_USER" + PASS="$DEV_POSTGRES_PASSWORD" + fi + + DATABASE_URL="postgres://${USER}:${PASS}@${POSTGRES_HOST}:5432/${POSTGRES_DB}?sslmode=disable" + + kubectl create secret generic "$RUNTIME_SECRET" \ + --namespace "$NAMESPACE" \ + --from-literal=POSTGRES_USER="$USER" \ + --from-literal=POSTGRES_PASSWORD="$PASS" \ + --from-literal=POSTGRES_DB="$POSTGRES_DB" \ + --from-literal=DATABASE_URL="$DATABASE_URL" \ + --dry-run=client -o yaml | kubectl apply -f - + + - name: Apply app secrets + run: | + set -e + set -a + source stripe_to_invoice/deployment/secrets/.env + set +a + + if [[ "$ENV" == "prod" ]]; then + STRIPE_SECRET_KEY="$PROD_STRIPE_SECRET_KEY" + STRIPE_CLIENT_ID="$PROD_STRIPE_CLIENT_ID" + STRIPE_REDIRECT_URI="$PROD_STRIPE_REDIRECT_URI" + APP_URL="$PROD_APP_URL" + XERO_CLIENT_ID="$PROD_XERO_CLIENT_ID" + XERO_CLIENT_SECRET="$PROD_XERO_SECRET_KEY" + XERO_REDIRECT_URI="$PROD_XERO_REDIRECT_URI" + AWS_REGION="$PROD_AWS_REGION" + AWS_ACCESS_KEY_ID="$PROD_AWS_ACCESS_KEY_ID" + AWS_SECRET_ACCESS_KEY="$PROD_AWS_SECRET_ACCESS_KEY" + STRIPE_WEBHOOK_SECRET="$PROD_STRIPE_WEBHOOK_SECRET" + SES_FROM_EMAIL="$PROD_SES_FROM_EMAIL" + STRIPE_BILLING_SECRET_KEY="$PROD_STRIPE_BILLING_SECRET_KEY" + STRIPE_BILLING_WEBHOOK_SECRET="$PROD_STRIPE_BILLING_WEBHOOK_SECRET" + STRIPE_SUBSCRIPTION_PRICE_ID="$PROD_STRIPE_SUBSCRIPTION_PRICE_ID" + else + STRIPE_SECRET_KEY="$DEV_STRIPE_SECRET_KEY" + STRIPE_CLIENT_ID="$DEV_STRIPE_CLIENT_ID" + STRIPE_REDIRECT_URI="$DEV_STRIPE_REDIRECT_URI" + APP_URL="$DEV_APP_URL" + XERO_CLIENT_ID="$DEV_XERO_CLIENT_ID" + XERO_CLIENT_SECRET="$DEV_XERO_SECRET_KEY" + XERO_REDIRECT_URI="$DEV_XERO_REDIRECT_URI" + AWS_REGION="$DEV_AWS_REGION" + AWS_ACCESS_KEY_ID="$DEV_AWS_ACCESS_KEY_ID" + AWS_SECRET_ACCESS_KEY="$DEV_AWS_SECRET_ACCESS_KEY" + STRIPE_WEBHOOK_SECRET="$DEV_STRIPE_WEBHOOK_SECRET" + SES_FROM_EMAIL="$DEV_SES_FROM_EMAIL" + STRIPE_BILLING_SECRET_KEY="$DEV_STRIPE_BILLING_SECRET_KEY" + STRIPE_BILLING_WEBHOOK_SECRET="$DEV_STRIPE_BILLING_WEBHOOK_SECRET" + STRIPE_SUBSCRIPTION_PRICE_ID="$DEV_STRIPE_SUBSCRIPTION_PRICE_ID" + fi + + export \ + STRIPE_SECRET_KEY \ + STRIPE_CLIENT_ID \ + STRIPE_REDIRECT_URI \ + APP_URL \ + XERO_CLIENT_ID \ + XERO_CLIENT_SECRET \ + XERO_REDIRECT_URI \ + AWS_REGION \ + AWS_ACCESS_KEY_ID \ + AWS_SECRET_ACCESS_KEY \ + STRIPE_WEBHOOK_SECRET \ + SES_FROM_EMAIL \ + STRIPE_BILLING_SECRET_KEY \ + STRIPE_BILLING_WEBHOOK_SECRET \ + STRIPE_SUBSCRIPTION_PRICE_ID \ + NAMESPACE + + envsubst < stripe_to_invoice/deployment/secrets/stripe-secrets.yaml | kubectl apply -f - + + # -------------------------------------------------- + # RUN ATLAS MIGRATIONS + # -------------------------------------------------- + migrate: + name: Run DB migrations (Atlas) + runs-on: mealcraft-runners + needs: secrets + + steps: + - uses: actions/checkout@v4 + + # 🔧 MINIMAL FIX (ENV bootstrap) + - name: Decide environment (from ref) + run: | + if [[ "$GITHUB_REF" == refs/heads/release/* || "$GITHUB_REF" == refs/tags/* ]]; then + echo "ENV=prod" >> $GITHUB_ENV + else + echo "ENV=dev" >> $GITHUB_ENV + fi + + - name: Install Atlas + uses: ariga/setup-atlas@v0 + + - name: Install kubectl + run: | + sudo apt-get update + sudo apt-get install -y curl ca-certificates gettext + curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + sudo install -m 0755 kubectl /usr/local/bin/kubectl + + - name: Configure kubeconfig (in-cluster) + run: | + KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT" + SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) + CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt + + kubectl config set-cluster microk8s --server="$KUBE_HOST" --certificate-authority="$CA_CERT" + kubectl config set-credentials runner --token="$SA_TOKEN" + kubectl config set-context runner-context --cluster=microk8s --user=runner + kubectl config use-context runner-context + + - name: Decide environment + run: | + if [[ "$ENV" == "prod" ]]; then + echo "SECRET=postgres-prod" >> $GITHUB_ENV + echo "NAMESPACE=default" >> $GITHUB_ENV + else + echo "SECRET=postgres-dev" >> $GITHUB_ENV + echo "NAMESPACE=dev" >> $GITHUB_ENV + fi + + - name: Run migrations (DEBUG – FULL DATABASE_URL) + run: | + DATABASE_URL=$(kubectl get secret "$SECRET" \ + -n "$NAMESPACE" \ + -o jsonpath='{.data.DATABASE_URL}' | base64 -d) + + echo "DATABASE_URL (FULL DEBUG — REMOVE AFTER):" + echo "$DATABASE_URL" + + atlas migrate apply \ + --dir file://db/atlas/stripe_invoice/migrations \ + --url "$DATABASE_URL" + + # -------------------------------------------------- + # DEPLOY APPLICATION + # -------------------------------------------------- + deploy: + runs-on: mealcraft-runners + needs: + - build + - secrets + - migrate + + steps: + - uses: actions/checkout@v4 + + # 🔧 MINIMAL FIX (ENV bootstrap) + - name: Decide environment (from ref) + run: | + if [[ "$GITHUB_REF" == refs/heads/release/* || "$GITHUB_REF" == refs/tags/* ]]; then + echo "ENV=prod" >> $GITHUB_ENV + else + echo "ENV=dev" >> $GITHUB_ENV + fi + + - name: Install kubectl + run: | + sudo apt-get update + sudo apt-get install -y curl ca-certificates gettext + curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + sudo install -m 0755 kubectl /usr/local/bin/kubectl + + - name: Configure kubeconfig (in-cluster) + run: | + KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT" + SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) + CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt + + kubectl config set-cluster microk8s --server="$KUBE_HOST" --certificate-authority="$CA_CERT" + kubectl config set-credentials runner --token="$SA_TOKEN" + kubectl config set-context runner-context --cluster=microk8s --user=runner + kubectl config use-context runner-context + + - name: Inject slug variables + uses: rlespinasse/github-slug-action@v4 + + - name: Decide environment + run: | + if [[ "$ENV" == "prod" ]]; then + echo "NAMESPACE=default" >> $GITHUB_ENV + echo "DB_ENV=prod" >> $GITHUB_ENV + echo "HOSTNAME=stripetoinvoice.com" >> $GITHUB_ENV + else + echo "NAMESPACE=dev" >> $GITHUB_ENV + echo "DB_ENV=dev" >> $GITHUB_ENV + echo "HOSTNAME=stripe-to-invoice.dev.juntekim.com" >> $GITHUB_ENV + fi + + - name: Deploy application + run: | + export IMAGE="docker.io/kimjunte/stripe_to_invoice:$GITHUB_REF_SLUG" + export NAMESPACE DB_ENV HOSTNAME + envsubst < stripe_to_invoice/deployment/deployment.yaml | kubectl apply -f - diff --git a/.github/workflows/disabled/terraform-apply.yml b/.github/workflows/disabled/terraform-apply.yml new file mode 100644 index 0000000..43680fa --- /dev/null +++ b/.github/workflows/disabled/terraform-apply.yml @@ -0,0 +1,128 @@ +name: "Terraform Apply" + +on: + push: + branches: + - main + +env: + TF_CLOUD_ORGANIZATION: "MealCraft" + TF_API_TOKEN: "${{ secrets.TF_API_TOKEN }}" + TF_WORKSPACE: "production" + CONFIG_DIRECTORY: aws_environment + TF_VAR_public_ip: "${{ secrets.PUBLIC_IP }}" + +jobs: + terraform: + if: github.repository != 'hashicorp-education/learn-terraform-github-actions' + name: "Terraform Apply" + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Debug Paths + run: | + echo "Workspace: $GITHUB_WORKSPACE" + ls -R . + echo "CONFIG_DIRECTORY: $CONFIG_DIRECTORY" + ls -R "$CONFIG_DIRECTORY" + + - name: Upload Configuration + uses: hashicorp/tfc-workflows-github/actions/upload-configuration@v1.0.0 + id: apply-upload + with: + workspace: ${{ env.TF_WORKSPACE }} + directory: ${{ env.CONFIG_DIRECTORY }} + + - name: Create Apply Run + uses: hashicorp/tfc-workflows-github/actions/create-run@v1.0.0 + id: apply-run + with: + workspace: ${{ env.TF_WORKSPACE }} + configuration_version: ${{ steps.apply-upload.outputs.configuration_version_id }} + + # Terraform marks the run as "confirmable" using lowercase attribute + - name: Apply + if: fromJSON(steps.apply-run.outputs.payload).data.attributes.actions.is_confirmable + uses: hashicorp/tfc-workflows-github/actions/apply-run@v1.0.0 + id: apply + with: + comment: "Apply from GitHub Actions CI ${{ github.sha }}" + run: ${{ steps.apply-run.outputs.run_id }} + + - name: Print TF_VAR_public_ip + run: 'echo "📡 Public IP used by Terraform: $TF_VAR_public_ip"' + + terraform-ses: + if: github.repository != 'hashicorp-education/learn-terraform-github-actions' + name: "Terraform Apply - SES" + runs-on: mealcraft-runners + needs: terraform + permissions: + contents: read + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + # - name: Install modern Node.js + # run: | + # curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - + # sudo apt-get install -y nodejs + # node --version + + # - name: Setup Terraform + # uses: hashicorp/setup-terraform@v3 + # with: + # terraform_version: "1.6.6" + + # - name: Install AWS CLI v2 + # run: | + # sudo apt-get update + # sudo apt-get install -y unzip curl + + # curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" + # unzip awscliv2.zip + # sudo ./aws/install + + # aws --version + + # - name: Verify AWS identity + # run: aws sts get-caller-identity + + # - name: Terraform Init + # working-directory: aws_environment/ses-juntekim + # run: terraform init + + # - name: Terraform Validate + # working-directory: aws_environment/ses-juntekim + # run: terraform validate + + # - name: Terraform Plan + # id: plan + # working-directory: aws_environment/ses-juntekim + # run: terraform plan -input=false + + # - name: Terraform Apply + # working-directory: aws_environment/ses-juntekim + # run: terraform apply -auto-approve -input=false + + - name: Future Improvement Reminder + run: | + echo "" + echo "⚠️ REMINDER: Future maintenance required for SES Terraform" + echo "" + echo "This SES configuration currently uses a separate S3 backend for state management." + echo "Plan to consolidate and migrate away from Hashicorp Terraform Cloud:" + echo "" + echo "TODO:" + echo " - [ ] Consolidate SES terraform into main Terraform Cloud workspace" + echo " - [ ] Move away from Hashicorp Terraform Cloud entirely" + echo " - [ ] Use alternative state management solution for all infrastructure" + echo "" + echo "See: aws_environment/ses-juntekim/README.md for details" + echo "" diff --git a/.github/workflows/disabled/terraform-plan.yml b/.github/workflows/disabled/terraform-plan.yml new file mode 100644 index 0000000..f3f8d61 --- /dev/null +++ b/.github/workflows/disabled/terraform-plan.yml @@ -0,0 +1,89 @@ +name: "Terraform Plan" + +on: + pull_request: + +env: + TF_CLOUD_ORGANIZATION: "MealCraft" + TF_API_TOKEN: "${{ secrets.TF_API_TOKEN }}" + TF_WORKSPACE: "production" + CONFIG_DIRECTORY: aws_environment + TF_VAR_public_ip: "${{ secrets.PUBLIC_IP }}" + +jobs: + terraform: + if: github.repository != 'hashicorp-education/learn-terraform-github-actions' + name: "Terraform Plan" + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Debug Paths + run: | + echo "Workspace: $GITHUB_WORKSPACE" + ls -R . + echo "CONFIG_DIRECTORY: $CONFIG_DIRECTORY" + ls -R "$CONFIG_DIRECTORY" + - name: Upload Configuration + uses: hashicorp/tfc-workflows-github/actions/upload-configuration@v1.0.0 + id: plan-upload + with: + workspace: ${{ env.TF_WORKSPACE }} + directory: ${{ env.CONFIG_DIRECTORY }} + speculative: true + + - name: Create Plan Run + uses: hashicorp/tfc-workflows-github/actions/create-run@v1.0.0 + id: plan-run + with: + workspace: ${{ env.TF_WORKSPACE }} + configuration_version: ${{ steps.plan-upload.outputs.configuration_version_id }} + plan_only: true + + - name: Get Plan Output + uses: hashicorp/tfc-workflows-github/actions/plan-output@v1.0.0 + id: plan-output + with: + plan: ${{ fromJSON(steps.plan-run.outputs.payload).data.relationships.plan.data.id }} + + - name: Update PR + uses: actions/github-script@v6 + id: plan-comment + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + // 1. Retrieve existing bot comments for the PR + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }); + const botComment = comments.find(comment => { + return comment.user.type === 'Bot' && comment.body.includes('Terraform Cloud Plan Output') + }); + const output = `#### Terraform Cloud Plan Output + \`\`\` + Plan: ${{ steps.plan-output.outputs.add }} to add, ${{ steps.plan-output.outputs.change }} to change, ${{ steps.plan-output.outputs.destroy }} to destroy. + \`\`\` + [Terraform Cloud Plan](${{ steps.plan-run.outputs.run_link }}) + `; + if (botComment) { + github.rest.issues.deleteComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: botComment.id, + }); + } + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: output + }) + + - name: Print TF_VAR_public_ip + run: 'echo "📡 Public IP used by Terraform: $TF_VAR_public_ip"' +