diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index ce9716dc..3a5fdab5 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -4,10 +4,8 @@ name: Build & Deploy on: push: branches: + - "dev" - "main" - - "master" - tags: - - "v*.*.*" env: IMAGE_NAME: rss3/xlog @@ -47,33 +45,33 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - # deploy-dev: - # runs-on: ubuntu-latest - # needs: build - # steps: - # - name: Checkout - # uses: actions/checkout@v2 - # - name: Set K8s context - # uses: aliyun/ack-set-context@v1 - # with: - # access-key-id: "${{ secrets.ACCESS_KEY_ID }}" - # access-key-secret: "${{ secrets.ACCESS_KEY_SECRET }}" - # cluster-id: "${{ env.DEV_ACK_CLUSTER_ID }}" - # - run: | - # wget https://github.com/mikefarah/yq/releases/download/v4.25.1/yq_linux_amd64.tar.gz -O - | tar xz && mv yq_linux_amd64 /usr/local/bin/yq - # curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.22.10/bin/linux/amd64/kubectl && chmod +x kubectl && mv kubectl /usr/local/bin/kubectl - # - uses: sljeff/secrets2env@main - # with: - # secrets-json: ${{ toJson(secrets) }} - # - env: - # IMAGE_TAG_RELEASE: ${{ env.IMAGE_NAME }}:${{ needs.build.outputs.version }} - # run: | - # sh apply.sh deploy/dev/* + deploy-dev: + runs-on: ubuntu-latest + needs: build + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Set K8s context + uses: aliyun/ack-set-context@v1 + with: + access-key-id: "${{ secrets.ACCESS_KEY_ID }}" + access-key-secret: "${{ secrets.ACCESS_KEY_SECRET }}" + cluster-id: "${{ env.DEV_ACK_CLUSTER_ID }}" + - run: | + wget https://github.com/mikefarah/yq/releases/download/v4.25.1/yq_linux_amd64.tar.gz -O - | tar xz && mv yq_linux_amd64 /usr/local/bin/yq + curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.22.10/bin/linux/amd64/kubectl && chmod +x kubectl && mv kubectl /usr/local/bin/kubectl + - uses: sljeff/secrets2env@main + with: + secrets-json: ${{ toJson(secrets) }} + - env: + IMAGE_TAG_RELEASE: ${{ env.IMAGE_NAME }}:${{ needs.build.outputs.version }} + run: | + sh apply.sh deploy/dev/* deploy-prod: - # if: startsWith(github.ref, 'refs/tags/v') + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - needs: [build] + needs: [build, deploy-dev] steps: - name: Checkout uses: actions/checkout@v2 diff --git a/deploy/dev/cm.yaml b/deploy/dev/cm.yaml new file mode 100644 index 00000000..1bcb3b11 --- /dev/null +++ b/deploy/dev/cm.yaml @@ -0,0 +1,76 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: xlog-caddy + namespace: crossbell +data: + Caddyfile: | + { + storage redis { + } + + on_demand_tls { + ask http://localhost:5000/ + } + } + + xlog.page, *.xlog.page { + tls jeff@rss3.io { + dns cloudflare {env.CF_API_TOKEN} + } + + reverse_proxy 127.0.0.1:3000 + } + + :80, :443 { + tls jeff@rss3.io { + on_demand + } + + reverse_proxy 127.0.0.1:3000 + } +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: xlog-caddy-validator + namespace: crossbell +data: + app.py: | + import requests + from flask import Flask, request, Response + + app = Flask(__name__) + + + @app.route("/") + def check_domain(): + domain = request.args.get("domain") + if not domain: + return Response(status=404) + if domain.endswith('.xlog.page') or domain == "xlog.page": + return Response(status=200) + + # get TXT + res = requests.get("https://cloudflare-dns.com/dns-query", params={ + "name": f"_xlog-challenge.{domain}", + "type": "TXT", + }, headers={"Accept": "application/dns-json"}) + if res.status_code != 200: + return Response(status=res.status_code) + answer = res.json().get("Answer") or [{}] + tenant = answer[0].get("data", "").replace('"', "") + if not tenant: + return Response(status=404) + + # check crossbell + res = requests.get(f"https://indexer.crossbell.io/v1/handles/{tenant}/character") + if res.status_code != 200: + return Response(status=404) + attributes = res.json().get("metadata", {}).get("content", {}).get("attributes", []) + for d in attributes: + print(d) + if d.get("trait_type") == "xlog_custom_domain" and d.get("value") == domain: + return Response(status=200) + + return Response(status=404) diff --git a/deploy/dev/secrets.yaml b/deploy/dev/secrets.yaml new file mode 100644 index 00000000..b0e3314f --- /dev/null +++ b/deploy/dev/secrets.yaml @@ -0,0 +1,30 @@ +# Remember to add it in env.production because it is the nextjs project +apiVersion: v1 +stringData: + NEXT_PUBLIC_APP_NAME: xlog + NEXT_PUBLIC_OUR_DOMAIN: xlog.page + NEXT_PUBLIC_DISCORD_LINK: "https://discord.gg/9XscSqJEq4" + NEXT_PUBLIC_GITHUB_LINK: "https://github.com/Crossbell-Box/xlog" + NEXT_PUBLIC_CSB_IO: "" + NEXT_PUBLIC_CSB_SCAN: "https://scan.crossbell.io" + NEXT_PUBLIC_IPFS_GATEWAY: "https://cf-ipfs.com/ipfs/" + REDIS_URL: ${REDIS_URL_DEV} +kind: Secret +metadata: + name: xlog + namespace: crossbell +type: Opaque +--- +apiVersion: v1 +stringData: + CADDY_CLUSTERING_REDIS_HOST: ${CADDY_CLUSTERING_REDIS_HOST_DEV} + CADDY_CLUSTERING_REDIS_PORT: "6379" + CADDY_CLUSTERING_REDIS_USERNAME: "" + CADDY_CLUSTERING_REDIS_PASSWORD: ${CADDY_CLUSTERING_REDIS_PASSWORD_DEV} + CADDY_CLUSTERING_REDIS_DB: "6" + CF_API_TOKEN: ${CF_API_TOKEN} +kind: Secret +metadata: + name: xlog-caddy + namespace: crossbell +type: Opaque diff --git a/deploy/dev/sts.yaml b/deploy/dev/sts.yaml new file mode 100644 index 00000000..c7a01cc1 --- /dev/null +++ b/deploy/dev/sts.yaml @@ -0,0 +1,97 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: xlog + namespace: crossbell +spec: + replicas: 1 + serviceName: "xlog-lb" + selector: + matchLabels: + app: xlog + template: + metadata: + labels: + app: xlog + spec: + enableServiceLinks: false + containers: + - image: $IMAGE_TAG_RELEASE + imagePullPolicy: Always + name: xlog + envFrom: + - secretRef: + name: xlog + ports: + - containerPort: 3000 + protocol: TCP + resources: + requests: + memory: "200Mi" + cpu: "150m" + limits: + memory: "500Mi" + cpu: "500m" + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + readinessProbe: + tcpSocket: + port: 3000 + initialDelaySeconds: 40 + periodSeconds: 10 + livenessProbe: + tcpSocket: + port: 3000 + initialDelaySeconds: 40 + periodSeconds: 20 + volumeMounts: + - name: data + mountPath: "/app/.next/cache/images" + subPath: images + - name: caddy + image: kindjeff/caddy-tlsredis-docker + imagePullPolicy: Always + command: ["caddy", "run", "-config", "/app/Caddyfile"] + envFrom: + - secretRef: + name: xlog-caddy + ports: + - containerPort: 80 + name: http + - containerPort: 443 + name: https + volumeMounts: + - name: caddyfile + mountPath: /app + - name: caddy-validator + image: python + command: ["/bin/sh", "-c"] + args: ["pip install flask requests; flask --app=app run"] + ports: + - containerPort: 5000 + name: http + volumeMounts: + - name: validator + mountPath: /app.py + subPath: app.py + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: 30 + volumes: + - name: caddyfile + configMap: + name: xlog-caddy + - name: validator + configMap: + name: xlog-caddy-validator + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: ["ReadWriteOnce"] + storageClassName: "alicloud-disk-ssd" + resources: + requests: + storage: 20Gi diff --git a/deploy/dev/svc.yaml b/deploy/dev/svc.yaml new file mode 100644 index 00000000..1bd63140 --- /dev/null +++ b/deploy/dev/svc.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Service +metadata: + name: xlog-lb + namespace: crossbell + annotations: + service.beta.kubernetes.io/alibaba-cloud-loadbalancer-name: "xlog-dev" + service.beta.kubernetes.io/alibaba-cloud-loadbalancer-spec: "slb.s1.small" +spec: + type: LoadBalancer + selector: + app: xlog + ports: + - name: http + protocol: TCP + port: 80 + targetPort: 80 + - name: https + protocol: TCP + port: 443 + targetPort: 443 diff --git a/deploy/prod/deploy.yaml b/deploy/prod/deploy.yaml index f691b1d8..1918d420 100644 --- a/deploy/prod/deploy.yaml +++ b/deploy/prod/deploy.yaml @@ -40,6 +40,9 @@ spec: cpu: "500m" terminationMessagePath: /dev/termination-log terminationMessagePolicy: File + volumeMounts: + - name: xlog-image + mountPath: /app/.next/cache/images readinessProbe: tcpSocket: port: 3000 @@ -88,3 +91,6 @@ spec: - name: validator configMap: name: xlog-caddy-validator + - name: xlog-image + persistentVolumeClaim: + claimName: xlog-image # OSS PVC created manually in the ACK console