๐Ÿช€Install Shit

Aug 7, 2024

Subsections of ๐Ÿช€Install Shit

AI Agent

May 12, 2026

Subsections of AI Agent

Hermes

Mar 7, 2024

OpenCode

๐Ÿš€Installation

Install By

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


1.prepare `opencode-configuration.yaml`

Details
kubectl get namespaces opencode > /dev/null 2>&1 || kubectl create namespace opencode

kubectl -n opencode create secret generic opencode-server-secret \
  --from-literal=OPENCODE_SERVER_PASSWORD=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

1.1.choose different LLM configuration

kubectl -n opencode apply -f - <<'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
  name: opencode-config
data:
  opencode.json: |
    {
      "provider": {
        "openai": {
          "options": {
            "baseURL": "https://v2.qixuw.com/v1",
            "apiKey": "sk-ss"
          },
          "models": {
            "gpt-5.3-codex-spark": {
              "name": "GPT-5.3 Codex Spark",
              "limit": {
                "context": 128000,
                "output": 32000
              },
              "options": {
                "store": false
              },
              "variants": {
                "low": {},
                "medium": {},
                "high": {},
                "xhigh": {}
              }
            }
          }
        }
      },
      "agent": {
        "build": {
          "options": {
            "store": false
          }
        },
        "plan": {
          "options": {
            "store": false
          }
        }
      },
      "$schema": "https://opencode.ai/config.json"
    }
EOF
kubectl -n opencode apply -f - <<'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
  name: opencode-config
data:
  opencode.json: |
    {
      "provider": {
        "openai": {
          "options": {
            "baseURL": "https://v2.qixuw.com/v1",
            "apiKey": "sk-ss"
          },
          "models": {
            "gpt-5.3-codex-spark": {
              "name": "GPT-5.3 Codex Spark",
              "limit": {
                "context": 128000,
                "output": 32000
              },
              "options": {
                "store": false
              },
              "variants": {
                "low": {},
                "medium": {},
                "high": {},
                "xhigh": {}
              }
            }
          }
        }
      },
      "mcp": {
        "euclid-catalog": {
          "type": "remote",
          "url": "https://catalog.euclid.mcp.dev.72602.online:32443/sse",
          "enabled": true
        },
        "astro_k3s_mcp": {
          "type": "remote",
          "url": "http://eva24002-entrance.lab.zverse.space:30082/mcp",
          "enabled": true,
          "oauth": false,
          "timeout": 15000
        }
      },
      "agent": {
        "build": {
          "options": {
            "store": false
          }
        },
        "plan": {
          "options": {
            "store": false
          }
        }
      },
      "$schema": "https://opencode.ai/config.json"
    }
EOF
kubectl -n opencode apply -f - <<'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
  name: opencode-config
data:
  opencode.json: |
    {
      "$schema": "https://opencode.ai/config.json",
      "provider": {
        "minimax": {
          "npm": "@ai-sdk/openai-compatible",
          "name": "MiniMax M2.5",
          "options": {
            "baseURL": "http://10.200.92.41:31551/v1",
            "apiKey": "sk-sss"
          },
          "models": {
            "minimax-m2.5": {
              "name": "MiniMax M2.5",
              "id": "MiniMaxAI/MiniMax-M2.5",
              "limit": {
                "context": 196608,
                "output": 8192
              }
            }
          }
        }
      },
      "model": "minimax/minimax-m2.5"
    }
EOF
kubectl -n opencode apply -f - <<'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
  name: opencode-config
data:
  opencode.json: |
    {
      "$schema": "https://opencode.ai/config.json",
      "model": "opencode/minimax-m2.5-free",
      "small_model": "opencode/minimax-m2.5-free"
    }
EOF
kubectl -n opencode apply -f - <<'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
  name: opencode-config
data:
  opencode.json: |
    {
      "provider": {
        "qiniu": {
          "options": {
            "baseURL": "https://api.qnaigc.com/v1",
            "apiKey": "sk-sss"
          },
          "models": {
            "minimax-m2.5": {
              "name": "Minimax-M2.5",
              "limit": {
                "context": 128000,
                "output": 32000
              },
              "options": {
                "store": false
              },
              "variants": {
                "low": {},
                "medium": {},
                "high": {},
                "xhigh": {}
              }
            }
          }
        }
      },
      "agent": {
        "build": {
          "options": {
            "store": false
          }
        },
        "plan": {
          "options": {
            "store": false
          }
        }
      },
      "$schema": "https://opencode.ai/config.json"
    }
EOF

2.prepare `deploy-opencode.yaml`; change the default model when you apply a different ConfigMap

Details
kubectl -n argocd apply -f - <<'EOF'
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: opencode
  namespace: argocd
spec:
  project: default
  source:
    repoURL: oci://ghcr.io/aaronyang0628/opencode
    targetRevision: 0.20.0
    chart: opencode
    helm:
      values: |
        image:
          repository: ghcr.io/nimbleflux/opencode-docker
          tag: 1.2.26
          pullPolicy: Always
        replicaCount: 1
        command:
          - opencode
        args:
          - serve
          - --port
          - "4000"
          - --hostname
          - "0.0.0.0"
        service:
          type: ClusterIP
          port: 4000
        env:
          OPENCODE_PORT: "4000"
        extraVolumes:
          - name: opencode-config
            configMap:
              name: opencode-config
        extraVolumeMounts:
          - name: opencode-config
            mountPath: /home/opencode/.config/opencode/opencode.json
            subPath: opencode.json
            readOnly: true
        persistence:
          enabled: true
          storageClass: local-path
          config:
            enabled: false 
          data:
            enabled: true
            size: 1Gi
          workspace:
            enabled: true
            size: 5Gi
          playbook:
            enabled: true
            mountPath: /home/opencode/workspace/playbook
            example:
              enabled: true
        resources:
          requests:
            cpu: 500m
            memory: 1Gi
          limits:
            cpu: 2
            memory: 4Gi
        probes:
          liveness:
            tcpSocket:
              port: 4000
            initialDelaySeconds: 15
            periodSeconds: 30
          readiness:
            tcpSocket:
              port: 4000
            initialDelaySeconds: 10
            periodSeconds: 10
          startup:
            tcpSocket:
              port: 4000
            initialDelaySeconds: 5
            periodSeconds: 5
            failureThreshold: 30
        ingress:
          enabled: true
          className: nginx
          annotations:
            kubernetes.io/ingress.class: nginx
            cert-manager.io/cluster-issuer: self-signed-ca-issuer
            nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
            nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
            nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
            nginx.ingress.kubernetes.io/proxy-body-size: "50m"
            nginx.ingress.kubernetes.io/upstream-keepalive-connections: "50"
            nginx.ingress.kubernetes.io/upstream-keepalive-timeout: "60"
          hosts:
            - host: opencode.dev.72602.online
              paths:
                - path: /
                  pathType: Prefix
          tls:
          - hosts:
            - opencode.dev.72602.online
            secretName: opencode.dev.72602.online-tls
        globalLabels:
          app.kubernetes.io/part-of: opencode
          environment: production
        bridge:
          enabled: true
          image:
            repository: crpi-wixjy6gci86ms14e.cn-hongkong.personal.cr.aliyuncs.com/ay-dev/opencode-bridge
            tag: "v20260326r4"
          env:
            defaultModel: "opencode/minimax-m2.5-free"
            openaiStreamChunkSize: "4"
            openaiStreamChunkDelayMs: "10"
            enableLeadingEchoFilter: "false"
          resources:
            limits:
              cpu: 500m
              memory: 256Mi
            requests:
              cpu: 100m
              memory: 128Mi
          ingress:
            enabled: true
            annotations:
              kubernetes.io/ingress.class: nginx
              cert-manager.io/cluster-issuer: self-signed-ca-issuer
              nginx.ingress.kubernetes.io/proxy-buffering: "off"
              nginx.ingress.kubernetes.io/proxy-request-buffering: "off"
              nginx.ingress.kubernetes.io/proxy-connect-timeout: "300"
              nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
              nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
              nginx.ingress.kubernetes.io/proxy-body-size: "50m"
              nginx.ingress.kubernetes.io/upstream-keepalive-connections: "50"
              nginx.ingress.kubernetes.io/upstream-keepalive-timeout: "60"
            hosts:
              - host: opencode-bridge.dev.72602.online
                paths:
                  - path: /
                    pathType: Prefix
            tls:
              - secretName: opencode-bridge-tls
                hosts:
                  - opencode-bridge.dev.72602.online

  destination:
    server: https://kubernetes.default.svc
    namespace: opencode
  syncPolicy:
    syncOptions:
      - CreateNamespace=true
      - ServerSideApply=true
EOF

3.sync by argocd

Details
argocd app sync argocd/opencode

4.then you can talk with LLM with rest api

Details
curl -k -X POST https://opencode.dev.72602.online:32443/session \
-H "Content-Type: application/json" \
-d '{"model": "opencode/minimax-m2.5-free"}'

## {"id":"ses_30a879abeffe6KRC0Rmg4aPrmK","slug":"brave-eagle","version":"1.2.26","projectID":"global","directory":"/home/opencode/workspace","title":"New session - 2026-03-16T07:07:14.113Z","time":{"created":1773644834113,"updated":1773644834113}}

5.reuse the same session

Details
curl -k -X POST https://opencode.dev.72602.online:32443/session/ses_30a879abeffe6KRC0Rmg4aPrmK/message \
-H "Content-Type: application/json" \
-d '{"parts": [{"type": "text", "text": "ไฝ ๅฅฝ"}]}'

## {"info":{"role":"assistant","time":{"created":1773644844131,"completed":1773644848700},"parentID":"msg_cf5788c12001RS4wX3hwMRe0If","modelID":"minimax-m2.5","providerID":"minimax","mode":"build","agent":"build","path":{"cwd":"/home/opencode/workspace","root":"/"},"cost":0,"tokens":{"total":10628,"input":10567,"output":61,"reasoning":0,"cache":{"read":0,"write":0}},"finish":"stop","id":"msg_cf5788c63001hBrorYejcHc1tO","sessionID":"ses_30a879abeffe6KRC0Rmg4aPrmK"},"parts":[{"type":"step-start","id":"prt_cf57899120016WXp4jT4AHeTiG","sessionID":"ses_30a879abeffe6KRC0Rmg4aPrmK","messageID":"msg_cf5788c63001hBrorYejcHc1tO"},{"type":"text","text":"<think>The user said \"ไฝ ๅฅฝ\" which means \"Hello\" in Chinese. According to the instructions, I should be concise and direct. I should respond briefly without unnecessary preamble. Since this is a simple greeting, I can just respond with a greeting back.\n</think>\n\nไฝ ๅฅฝ๏ผๆœ‰ไป€ไนˆๅฏไปฅๅธฎไฝ ็š„ๅ—๏ผŸ","time":{"start":1773644848689,"end":1773644848689},"id":"prt_cf5789913001dUZnoW9w63ThkC","sessionID":"ses_30a879abeffe6KRC0Rmg4aPrmK","messageID":"msg_cf5788c63001hBrorYejcHc1tO"},{"type":"step-finish","reason":"stop","cost":0,"tokens":{"total":10628,"input":10567,"output":61,"reasoning":0,"cache":{"read":0,"write":0}},"id":"prt_cf5789e35001dLGIXJb5WHizMX","sessionID":"ses_30a879abeffe6KRC0Rmg4aPrmK","messageID":"msg_cf5788c63001hBrorYejcHc1tO"}]}

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


0. (optional) deploy `oauth2-proxy` for GitHub OAuth 2FA

Details
kubectl get namespaces oauth2-proxy > /dev/null 2>&1 || kubectl create namespace oauth2-proxy

kubectl -n oauth2-proxy create secret generic oauth2-proxy-secret \
  --from-literal=client-id=<your-github-oauth-client-id> \
  --from-literal=client-secret=<your-github-oauth-client-secret> \
  --from-literal=cookie-secret=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 32)

kubectl -n argocd apply -f - <<'EOF'
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: oauth2-proxy
  namespace: argocd
spec:
  project: default
  source:
    repoURL: oci://ghcr.io/aaronyang0628/oauth2-proxy
    targetRevision: 7.7.0
    chart: oauth2-proxy
    helm:
      values: |
        config:
          clientID: ""
          existingSecret: oauth2-proxy-secret
        extraEnv:
          - name: OAUTH2_PROXY_CLIENT_ID
            valueFrom:
              secretKeyRef:
                name: oauth2-proxy-secret
                key: client-id
          - name: OAUTH2_PROXY_CLIENT_SECRET
            valueFrom:
              secretKeyRef:
                name: oauth2-proxy-secret
                key: client-secret
          - name: OAUTH2_PROXY_COOKIE_SECRET
            valueFrom:
              secretKeyRef:
                name: oauth2-proxy-secret
                key: cookie-secret
        provider: github
        upstreams:
          - http://opencode:4000
        ingress:
          enabled: true
          className: nginx
          annotations:
            cert-manager.io/cluster-issuer: letsencrypt
          hosts:
            - host: ops.agent.72602.online
              paths:
                - /
          tls:
            - secretName: ops.agent.72602.online-tls
              hosts:
                - ops.agent.72602.online
  destination:
    server: https://kubernetes.default.svc
    namespace: oauth2-proxy
  syncPolicy:
    syncOptions:
      - CreateNamespace=true
EOF

1.prepare `opencode-configuration.yaml`

Details
kubectl get namespaces opencode > /dev/null 2>&1 || kubectl create namespace opencode

kubectl -n opencode create secret generic opencode-server-secret \
  --from-literal=OPENCODE_SERVER_PASSWORD=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

2.prepare `deploy-opencode.yaml`

Details
kubectl -n argocd apply -f - <<'EOF'
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: opencode
  namespace: argocd
spec:
  project: default
  source:
    repoURL: oci://ghcr.io/aaronyang0628/opencode
    targetRevision: 0.20.0
    chart: opencode
    helm:
      values: |
        image:
          repository: ghcr.io/nimbleflux/opencode-docker
          tag: 1.2.26
          pullPolicy: Always
        replicaCount: 1
        command:
          - opencode
        args:
          - serve
          - --port
          - "4000"
          - --hostname
          - "0.0.0.0"
        service:
          type: ClusterIP
          port: 4000
        env:
          OPENCODE_PORT: "4000"
        extraVolumes:
          - name: opencode-config
            configMap:
              name: opencode-config
        extraVolumeMounts:
          - name: opencode-config
            mountPath: /home/opencode/.config/opencode/opencode.json
            subPath: opencode.json
            readOnly: true
        persistence:
          enabled: true
          storageClass: local-path
          config:
            enabled: false 
          data:
            enabled: true
            size: 1Gi
          workspace:
            enabled: true
            size: 5Gi
          playbook:
            enabled: true
            mountPath: /home/opencode/workspace/playbook
            example:
              enabled: true
        resources:
          requests:
            cpu: 500m
            memory: 1Gi
          limits:
            cpu: 2
            memory: 4Gi
        probes:
          liveness:
            tcpSocket:
              port: 4000
            initialDelaySeconds: 15
            periodSeconds: 30
          readiness:
            tcpSocket:
              port: 4000
            initialDelaySeconds: 10
            periodSeconds: 10
          startup:
            tcpSocket:
              port: 4000
            initialDelaySeconds: 5
            periodSeconds: 5
            failureThreshold: 30
        ingress:
          enabled: true
          className: nginx
          annotations:
            kubernetes.io/ingress.class: nginx
            cert-manager.io/cluster-issuer: letsencrypt
            nginx.ingress.kubernetes.io/proxy-connect-timeout: "300"
            nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
            nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
            nginx.ingress.kubernetes.io/proxy-body-size: "50m"
            nginx.ingress.kubernetes.io/upstream-keepalive-connections: "50"
            nginx.ingress.kubernetes.io/upstream-keepalive-timeout: "60"
          hosts:
            - host: ops.agent.72602.online
              paths:
                - path: /
                  pathType: Prefix
          tls:
          - hosts:
            - ops.agent.72602.online
            secretName: ops.agent.72602.online-tls
        globalLabels:
          app.kubernetes.io/part-of: opencode
          environment: production
        bridge:
          enabled: true
          image:
            repository: crpi-wixjy6gci86ms14e.cn-hongkong.personal.cr.aliyuncs.com/ay-dev/opencode-bridge
            tag: "v20260326r4"
          env:
            defaultModel: "openai/gpt-5.3-codex-spark"
            openaiStreamChunkSize: "4"
            openaiStreamChunkDelayMs: "10"
            enableLeadingEchoFilter: "false"
          resources:
            limits:
              cpu: 500m
              memory: 256Mi
            requests:
              cpu: 100m
              memory: 128Mi
          ingress:
            enabled: true
            annotations:
              kubernetes.io/ingress.class: nginx
              cert-manager.io/cluster-issuer: letsencrypt
              nginx.ingress.kubernetes.io/proxy-buffering: "off"
              nginx.ingress.kubernetes.io/proxy-request-buffering: "off"
              nginx.ingress.kubernetes.io/proxy-connect-timeout: "300"
              nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
              nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
              nginx.ingress.kubernetes.io/proxy-body-size: "50m"
              nginx.ingress.kubernetes.io/upstream-keepalive-connections: "50"
              nginx.ingress.kubernetes.io/upstream-keepalive-timeout: "60"
            hosts:
              - host: opencode-bridge.72602.online
                paths:
                  - path: /
                    pathType: Prefix
            tls:
              - secretName: opencode-bridge-tls
                hosts:
                  - opencode-bridge.72602.online

  destination:
    server: https://kubernetes.default.svc
    namespace: opencode
  syncPolicy:
    syncOptions:
      - CreateNamespace=true
      - ServerSideApply=true
EOF

3.sync by argocd

Details
argocd app sync argocd/opencode

4.then you can talk with LLM with rest api

Details
curl -s "https://opencode-bridge.72602.online/v1/models"

## {"id":"ses_30a879abeffe6KRC0Rmg4aPrmK","slug":"brave-eagle","version":"1.2.26","projectID":"global","directory":"/home/opencode/workspace","title":"New session - 2026-03-16T07:07:14.113Z","time":{"created":1773644834113,"updated":1773644834113}}

4.then you can talk with LLM with rest api

Details
curl -k -X POST https://ops.agent.72602.online/session \
-H "Content-Type: application/json" \
-d '{"model": "MiniMaxAI/MiniMax-M2.5"}'

## {"id":"ses_30a879abeffe6KRC0Rmg4aPrmK","slug":"brave-eagle","version":"1.2.26","projectID":"global","directory":"/home/opencode/workspace","title":"New session - 2026-03-16T07:07:14.113Z","time":{"created":1773644834113,"updated":1773644834113}}

5.reuse the same session

Details
curl -k -X POST https://ops.agent.72602.online/session/ses_30a879abeffe6KRC0Rmg4aPrmK/message \
-H "Content-Type: application/json" \
-d '{"parts": [{"type": "text", "text": "ไฝ ๅฅฝ"}]}'

## {"info":{"role":"assistant","time":{"created":1773644844131,"completed":1773644848700},"parentID":"msg_cf5788c12001RS4wX3hwMRe0If","modelID":"minimax-m2.5","providerID":"minimax","mode":"build","agent":"build","path":{"cwd":"/home/opencode/workspace","root":"/"},"cost":0,"tokens":{"total":10628,"input":10567,"output":61,"reasoning":0,"cache":{"read":0,"write":0}},"finish":"stop","id":"msg_cf5788c63001hBrorYejcHc1tO","sessionID":"ses_30a879abeffe6KRC0Rmg4aPrmK"},"parts":[{"type":"step-start","id":"prt_cf57899120016WXp4jT4AHeTiG","sessionID":"ses_30a879abeffe6KRC0Rmg4aPrmK","messageID":"msg_cf5788c63001hBrorYejcHc1tO"},{"type":"text","text":"<think>The user said \"ไฝ ๅฅฝ\" which means \"Hello\" in Chinese. According to the instructions, I should be concise and direct. I should respond briefly without unnecessary preamble. Since this is a simple greeting, I can just respond with a greeting back.\n</think>\n\nไฝ ๅฅฝ๏ผๆœ‰ไป€ไนˆๅฏไปฅๅธฎไฝ ็š„ๅ—๏ผŸ","time":{"start":1773644848689,"end":1773644848689},"id":"prt_cf5789913001dUZnoW9w63ThkC","sessionID":"ses_30a879abeffe6KRC0Rmg4aPrmK","messageID":"msg_cf5788c63001hBrorYejcHc1tO"},{"type":"step-finish","reason":"stop","cost":0,"tokens":{"total":10628,"input":10567,"output":61,"reasoning":0,"cache":{"read":0,"write":0}},"id":"prt_cf5789e35001dLGIXJb5WHizMX","sessionID":"ses_30a879abeffe6KRC0Rmg4aPrmK","messageID":"msg_cf5788c63001hBrorYejcHc1tO"}]}

1. following the steps in `https://opencode.ai`

Details
curl -fsSL https://opencode.ai/install | bash

6.use bridge to manage session

bridge

๐ŸŒHugo Docs Site

The Hugo documentation site is deployed via ArgoCD on ops.docs.72602.online (formerly port.72602.online).

Deployment Environment

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


1.prepare `deploy-hugo-docs.yaml`

Details
kubectl -n argocd apply -f - <<'EOF'
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: hugo-docs
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/aaronyang0628/ops-docs.git
    targetRevision: main
    path: .
  destination:
    server: https://kubernetes.default.svc
    namespace: hugo-docs
  syncPolicy:
    syncOptions:
      - CreateNamespace=true
    automated:
      prune: true
      selfHeal: true
EOF

2.sync by argocd

Details
argocd app sync argocd/hugo-docs

๐Ÿค–Multi-Agent System

The opencode deployment includes two specialized agents for cluster and documentation maintenance:

AgentRoleTarget
k3s-maintainerCluster operationsk3s cluster health, pod management, node maintenance
doc-maintainerDocumentation updatesHugo docs site content, ArgoCD Application updates

Agent Configuration (applied as ConfigMaps)

Details
kubectl -n opencode apply -f - <<'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
  name: k3s-maintainer-config
data:
  opencode.json: |
    {
      "provider": {
        "openai": {
          "options": {
            "baseURL": "https://v2.qixuw.com/v1",
            "apiKey": "sk-ss"
          },
          "models": {
            "gpt-5.3-codex-spark": {
              "name": "GPT-5.3 Codex Spark",
              "limit": { "context": 128000, "output": 32000 }
            }
          }
        }
      },
      "mcp": {
        "k8s-mcp": {
          "type": "remote",
          "url": "http://k8s-mcp.opencode.svc.cluster.local:8080/mcp",
          "enabled": true,
          "timeout": 15000
        }
      },
      "agent": {
        "build": { "options": { "store": false } },
        "plan": { "options": { "store": false } }
      }
    }
EOF

Deploy agents via ArgoCD - each agent runs as a separate opencode server Pod with its own ConfigMap

Details
kubectl -n argocd apply -f - <<'EOF'
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: k3s-maintainer
  namespace: argocd
spec:
  project: default
  source:
    repoURL: oci://ghcr.io/aaronyang0628/opencode
    targetRevision: 0.20.0
    chart: opencode
    helm:
      values: |
        image:
          repository: ghcr.io/nimbleflux/opencode-docker
          tag: 1.2.26
        replicaCount: 1
        command: ["opencode"]
        args: ["serve", "--port", "4001", "--hostname", "0.0.0.0"]
        service:
          type: ClusterIP
          port: 4001
        env:
          OPENCODE_PORT: "4001"
        extraVolumes:
          - name: agent-config
            configMap:
              name: k3s-maintainer-config
        extraVolumeMounts:
          - name: agent-config
            mountPath: /home/opencode/.config/opencode/opencode.json
            subPath: opencode.json
        persistence:
          enabled: true
          storageClass: local-path
          config:
            enabled: false
          data:
            enabled: true
            size: 1Gi
          workspace:
            enabled: true
            size: 5Gi
        resources:
          requests:
            cpu: 500m
            memory: 1Gi
          limits:
            cpu: 2
            memory: 4Gi
  destination:
    server: https://kubernetes.default.svc
    namespace: opencode
  syncPolicy:
    syncOptions:
      - CreateNamespace=true
      - ServerSideApply=true
EOF

โšกOptimizations

Several optimizations were applied to improve the ArgoCD workflow:

OptimizationBeforeAfter
GitHub proxy for ArgoCDDirect GitHub accessghfast.top mirror
Git repo size117 MB44 MB
ArgoCD sync timeslow (~minutes)~7 seconds

1. GitHub Proxy - configure ArgoCD to use `ghfast.top` for faster OCI/Helm chart pulls

Details
# In argocd-cm ConfigMap:
data:
  repositories: |
    - url: oci://ghcr.io
      proxy: https://ghfast.top

2. Repo Size Reduction - cleaned large files and unused assets from the git repository

Details
# Remove git history and prune
git filter-repo --strip-blobs-bigger-than 1M
git gc --aggressive --prune=now

3. Fast ArgoCD Sync - achieved by combining ServerSideApply, lean manifests, and cached images

Details
syncPolicy:
  syncOptions:
    - ServerSideApply=true

๐Ÿ›Ž๏ธFAQ

Q1: OpenCode Pod runs but API returns 401/403

Symptom

  • curl to /session or bridge endpoint returns unauthorized.

Check

kubectl -n opencode get secret opencode-server-secret -o yaml
kubectl -n opencode get configmap opencode-config -o yaml
kubectl -n opencode logs deploy/opencode --tail=100

Fix

  • Confirm OPENCODE_SERVER_PASSWORD secret exists and is mounted correctly.
  • Confirm client request carries expected auth configuration.
  • Re-apply ConfigMap/Application and sync again.

Expected

  • Session creation and message requests return successful JSON responses.
Q2: Model list is empty or model invocation fails

Symptom

  • /v1/models returns empty list, or chat request returns provider/model error.

Check

kubectl -n opencode get configmap opencode-config -o jsonpath='{.data.opencode\.json}'
kubectl -n opencode logs deploy/opencode --tail=200

Fix

  • Verify provider baseURL, apiKey, and model ID in opencode.json.
  • Ensure selected default model exists in configured provider models.
  • Re-apply config and restart workload if needed.

Expected

  • /v1/models shows expected model entries and session message calls succeed.
Mar 7, 2024

ClaudeCode

Mar 7, 2024

Ops Agent

๐Ÿš€Installation

Environment
Install By

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


1.build and push Ops Agent image

Details
cd /home/aaron/Ops/docs
./manifests/ops-agent/build-and-push.sh

The image contains OpenCode, kubectl, Argo CD CLI, Git, SSH, opencode-vibeguard, DCP, and Goal Mode. The repository is not baked into the image; the Pod mounts /home/aaron/Ops/docs at /workspace.

2.prepare runtime Secrets

Details
./manifests/ops-agent/create-secrets.sh

./manifests/ops-agent/create-sub2api-mcp-secret.sh

create-secrets.sh loads the ignored repository .env by default (or the file named by OPENCODE_ENV_FILE) and requires the five model variables: OPENAI_API_KEY, GROK_API_KEY, OLLAMA_API_KEY, BACKUP_ENDPOINT, and BACKUP_API_KEY. It creates or updates model, SSH, Git credential, Registry, and Basic Auth Secrets without writing their values into Git. The Sub2API helper accepts the admin API key only through its silent interactive prompt, validates its admin-<hex64> shape, writes only application/sub2api-mcp key admin-api-key, and unsets the local variable before exit. The script refuses any other format.

3.sync by ArgoCD

Details
argocd app get ops-docs --hard-refresh
argocd app sync ops-docs --revision main
argocd app wait ops-docs --sync --health --timeout 300

argocd app get ops-agent --hard-refresh
argocd app sync ops-agent
argocd app wait ops-agent --sync --health --timeout 600
kubectl -n application rollout status deployment/ops-agent --timeout=600s

argocd/ops-docs owns manifests/ops-agent-argocd.yaml; the child argocd/ops-agent Application deploys manifests/ops-agent into namespace application. Do not apply the Kustomization directly as a second ownership path. The Deployment mounts the host workspace read-write and stores OpenCode session data in the opencode-data PVC.

Startup configuration is loaded only when OpenCode starts. After changing .opencode/opencode.json, agents, skills, or plugins, restart only the managed workload and wait for readiness:

Details
kubectl -n application rollout restart deployment/ops-agent
kubectl -n application rollout status deployment/ops-agent --timeout=300s

The live strategy is Recreate, so a restart briefly makes the web endpoint unavailable while the replacement Pod becomes Ready.

4.verify configuration and access

Details
kubectl -n application get pod,svc,ingress \
  -l app.kubernetes.io/name=ops-agent
kubectl -n application get certificate ops.agent.72602.space-tls

kubectl -n application exec deployment/ops-agent -c ops-agent -- \
  opencode debug agent hugo-doc-maintainer

kubectl -n application exec deployment/ops-agent -c ops-agent -- sh -c \
  'curl -fsS -u "$OPENCODE_SERVER_USERNAME:$OPENCODE_SERVER_PASSWORD" \
  http://127.0.0.1:4000/global/health'

kubectl -n application exec deployment/ops-agent -c ops-agent -- sh -c \
  'curl -fsS -u "$OPENCODE_SERVER_USERNAME:$OPENCODE_SERVER_PASSWORD" \
  http://127.0.0.1:4000/mcp | jq -e ". == {\"sub2api-admin\": {\"status\": \"connected\"}}"'

kubectl -n application exec deployment/ops-agent -c ops-agent -- sh -c \
  'CFG=$(curl -fsS -u "$OPENCODE_SERVER_USERNAME:$OPENCODE_SERVER_PASSWORD" \
  http://127.0.0.1:4000/config); echo "$CFG" | \
  jq -e ".mcp[\"sub2api-admin\"].environment[\"SUB2API_BASE_URL\"] == \
  \"http://sub2api.application.svc.cluster.local:8080\"" && \
  ! echo "$CFG" | grep -Eq "SUB2API_ADMIN_API_KEY|admin-api-key|x-api-key"'

kubectl -n application exec deployment/ops-agent -c ops-agent -- \
  opencode mcp list

kubectl -n application exec deployment/ops-agent -c ops-agent -- sh -c \
  'curl -fsS -u "$OPENCODE_SERVER_USERNAME:$OPENCODE_SERVER_PASSWORD" \
  http://127.0.0.1:4000/provider | \
  jq "{connected,ollama:(.all[]|select(.id==\"ollama\")|.models|keys)}"'

PASSWORD="$(kubectl -n application get secret opencode-basic-auth \
  -o jsonpath='{.data.password}' | base64 -d)"

curl -sS -o /dev/null -w '%{http_code}\n' \
  -u "aaron:$PASSWORD" https://ops.agent.72602.space/

Expected result: the Pod is Ready, the certificate is True, anonymous access returns 401, authenticated access returns 200, global/health reports healthy: true, /mcp returns exactly {"sub2api-admin":{"status":"connected"}}, the merged OpenCode config carries SUB2API_BASE_URL=http://sub2api.application.svc.cluster.local:8080 without the admin key, opencode mcp list reports sub2api-admin connected, and the connected Ollama provider lists gemma4:31b, and gpt-oss:120b. The live authenticated version read through 72602-k3s-maintainer using sub2api-admin_read against /api/v1/admin/system/version returns 0.1.168.

๐Ÿค–Agents

AgentResponsibilityOperational source
72602-k3s-maintainerOperate the local 72602 clusterLive cluster, then content/CSP/72602/_index.md
zjlab-ops-maintainerOperate ZJLAB through private SSH aliasesLive cluster, then the private inventory
hugo-doc-maintainerMaintain Relearn layout and runbooksRelearn and Installation skills

All three are subagents and inherit the model selected by the active conversation. Cluster agents verify live state before following a runbook and delegate verified documentation updates to the Hugo agent.

Aliyun operations for 72602-k3s-maintainer are documented by the public .opencode/skills/aliyun-72602-operations/SKILL.md, introduced in commit 96a9354.

๐ŸงฐMCP & Skills

Local Sub2API admin MCP

The OpenCode config registers a single local MCP server sub2api-admin under mcp.sub2api-admin:

{
  "type": "local",
  "command": ["node", ".opencode/mcp/sub2api-admin/server.mjs"],
  "cwd": "/workspace",
  "environment": {
    "SUB2API_BASE_URL": "http://sub2api.application.svc.cluster.local:8080",
    "SUB2API_ALLOWED_HOST": "sub2api.application.svc.cluster.local",
    "SUB2API_TIMEOUT_MS": "30000",
    "SUB2API_MAX_RECHARGE": "10000"
  },
  "enabled": true,
  "timeout": 40000
}

The server reads its credential from the environment variable SUB2API_ADMIN_API_KEY. The Deployment injects that variable from the dedicated runtime Secret application/sub2api-mcp key admin-api-key:

- name: SUB2API_ADMIN_API_KEY
  valueFrom:
    secretKeyRef:
      name: sub2api-mcp
      key: admin-api-key

The key is provisioned interactively by manifests/ops-agent/create-sub2api-mcp-secret.sh, which accepts the value from the operator, validates its admin-<hex64> shape, writes the Secret, and unsets the local variable. The script refuses any other format. The value never enters Git or opencode.json.

The server only accepts the configured cluster-local host; every authenticated GET runs through a reviewed route allowlist, sensitive fields are recursively redacted, and the MCP exposes only dedicated mutation tools.

Tool surface

The MCP registers nine tools:

  • describe: capabilities and safety constraints.
  • health: anonymous check of /health through the configured internal cluster-local URL (SUB2API_BASE_URL), not the public token.72602.space endpoint.
  • read: one allowlisted authenticated GET route.
  • find_user: resolve exactly one user by normalized email.
  • preview_recharge: non-mutating preview of an additive credit.
  • recharge: additive credit with backend idempotency.
  • update_user_limits: per-user RPM and/or concurrency.
  • set_account_schedulable: enable or disable scheduling for an entire upstream account.
  • model_control_options: explain the available scheduling boundaries and rate-limit scopes.

There is no generic authenticated write tool.

Sub2API 72602 operations skill

The skill .opencode/skills/sub2api-72602-operations/SKILL.md is loaded by 72602-k3s-maintainer whenever the task touches live Sub2API state. It records the boundaries, the recharge workflow, the limits and model availability constraints, and the verification loop. Recharge is additive USD-style internal credit only. The MCP accepts one exact normalized email and an immutable user id; every call must pass one stable Idempotency-Key (16-128 URL-safe characters) and re-read the user plus balance history. The MCP reports an exact verified or accepted_unverified outcome; the skill forbids rewriting an accepted_unverified response as success.

Limits and model availability are constrained in Sub2API v0.1.168:

  • User RPM and concurrency can be set through sub2api-admin_update_user_limits.
  • Group RPM exists through the admin UI; this MCP does not expose it.
  • Sub2API v0.1.168 has no configurable per-model RPM.
  • Temporary model unavailability uses the actual scheduling boundary: dedicated accounts (set_account_schedulable), restricted channel model lists, or composite routes. models_list_config only hides discovery and must never be reported as a disable. Changes affect new requests only.

The skill is documentation; the runtime stays scoped to the maintainer. No account is recharged as part of installation.

Permission scope

The global OpenCode permission set denies every sub2api-admin_* tool. The maintainer agent permits the read-only tools directly and asks before calling sub2api-admin_recharge, sub2api-admin_update_user_limits, and sub2api-admin_set_account_schedulable:

permission:
  "sub2api-admin_describe": allow
  "sub2api-admin_health": allow
  "sub2api-admin_read": allow
  "sub2api-admin_find_user": allow
  "sub2api-admin_preview_recharge": allow
  "sub2api-admin_model_control_options": allow
  "sub2api-admin_recharge": ask
  "sub2api-admin_update_user_limits": ask
  "sub2api-admin_set_account_schedulable": ask

Other agents inherit the global deny and must request the maintainer for any sub2api-admin_* mutation. The MCP does not expose credential rotation, OAuth exchange, backup restore, or application lifecycle operations.

Secret rotation

Sub2API supports only one Admin API Key. Generating or regenerating the key in the admin UI immediately invalidates the previous key, so the MCP will briefly fail to authenticate until the Ops Agent workload restarts with the new value. Plan an expected maintenance window of one to two restart cycles. Rotate in this exact order without intermediate pauses:

  1. Generate the new key in the Sub2API admin UI and immediately enter it into the silent prompt of manifests/ops-agent/create-sub2api-mcp-secret.sh; the helper runs once, validates the format, writes application/sub2api-mcp key admin-api-key, and exits without echoing the value.
  2. Restart the managed workload so the new env var is injected:
    kubectl -n application rollout restart deployment/ops-agent
    kubectl -n application rollout status deployment/ops-agent --timeout=300s
  3. Verify global/health reports healthy: true, /mcp reports exactly {"sub2api-admin":{"status":"connected"}}, and the merged OpenCode config carries the cluster-local SUB2API_BASE_URL without the admin key.
  4. Through 72602-k3s-maintainer, run sub2api-admin_read against /api/v1/admin/system/version; the live application must respond 0.1.168.

Enter the key only into the helper’s silent prompt. Never place it in shell arguments, chat, Git, OpenCode config, logs, or command output. Regenerating the key upstream is itself the invalidation step; no follow-up “disable previous key” call is needed or supported.

Test the MCP server with node --test .opencode/mcp/sub2api-admin/server.test.mjs; three tests pass and exercise the allowlist, path-traversal rejection, and recharge idempotency.

๐Ÿ”ŒPlugins

  • opencode-vibeguard@0.1.0: redacts configured credential patterns before model requests.
  • @prevalentware/opencode-goal-plugin@0.1.24: persists long-running goals and evidence-gated completion state.

Langfuse is not installed or enabled.

โ†ฉ๏ธRollback

Restore the previous reviewed configuration and Deployment through Git, then let the parent and child Applications converge:

git -C /home/aaron/Ops/docs log --oneline -- \
  .opencode/opencode.json manifests/ops-agent
git -C /home/aaron/Ops/docs revert <change-commit>
git -C /home/aaron/Ops/docs push origin HEAD:main

argocd app get ops-agent --hard-refresh
argocd app sync ops-agent
argocd app wait ops-agent --sync --health --timeout 600
kubectl -n application rollout restart deployment/ops-agent
kubectl -n application rollout status deployment/ops-agent --timeout=300s

Do not patch the Deployment, delete the Ingress/PVC/Secrets, or scale the Git-owned workload as a rollback path.

Mar 7, 2024

OpenClaw

๐Ÿš€Installation

Install By

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


1.prepare `openclaw-env-secret.yaml`

Details
kubectl get namespaces claw > /dev/null 2>&1 || kubectl create namespace claw
kubectl create secret generic openclaw-env-secret -n claw \
--from-literal=ANTHROPIC_API_KEY=REPLACE_WITH_YOUR_API_KEY \
--from-literal=OPENCLAW_GATEWAY_TOKEN=REPLACE_WITH_YOUR_TOKEN_KEY

2.prepare `deploy-openclaw.yaml`

Details
kubectl -n argocd apply -f - <<EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: openclaw
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://serhanekicii.github.io/openclaw-helm
    chart: openclaw
    targetRevision: 1.4.4
    helm:
      releaseName: openclaw
      values: |
        app-template:
          openclawVersion: "2026.2.23"
          chromiumVersion: "124"
          configMode: merge
          controllers:
            main:
              containers:
                main:
                  image:
                    repository: ghcr.io/openclaw/openclaw
                    tag: "2026.2.23"
                    pullPolicy: IfNotPresent
                  envFrom:
                    - secretRef:
                        name: openclaw-env-secret
                  args:
                    - "gateway"
                    - "--bind"
                    - "lan"
                    - "--port"
                    - "18789"
                    - "--allow-unconfigured"
                  resources:
                    requests:
                      cpu: 200m
                      memory: 512Mi
                    limits:
                      cpu: 2000m
                      memory: 2Gi
                chromium:
                  image:
                    repository: zenika/alpine-chrome
                    tag: "124"
                    pullPolicy: IfNotPresent
                  args:
                    - "--no-sandbox"
                    - "--disable-dev-shm-usage"
                    - "--remote-debugging-address=0.0.0.0"
                    - "--remote-debugging-port=9222"
                  resources:
                    requests:
                      cpu: 200m
                      memory: 512Mi
                    limits:
                      cpu: 2000m
                      memory: 2Gi
          persistence:
            data:
              enabled: true
              type: persistentVolumeClaim
              accessMode: ReadWriteOnce
              size: 10Gi
              globalMounts:
                - path: /root/.openclaw
          ingress:
            main:
              enabled: true
              className: nginx
              annotations:
                kubernetes.io/ingress.class: nginx
                cert-manager.io/cluster-issuer: lets-encrypt
                nginx.ingress.kubernetes.io/proxy-connect-timeout: "300"
                nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
                nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
                nginx.ingress.kubernetes.io/proxy-body-size: "50m"
                nginx.ingress.kubernetes.io/upstream-keepalive-connections: "50"
                nginx.ingress.kubernetes.io/upstream-keepalive-timeout: "60"
              hosts:
                - host: openclaw.dev.72602.online
                  paths:
                    - path: /
                      pathType: Prefix
                      service:
                        identifier: main
                        port: http
              tls:
                - secretName: openclaw-tls
                  hosts:
                    - openclaw.dev.72602.online
          configMaps:
            config:
              data:
                openclaw.json: |
                  {
                    gateway: {
                      controlUi: {
                        allowedOrigins: ["https://openclaw.dev.72602.online"],
                        dangerouslyAllowHostHeaderOriginFallback: true,
                      },
                    },
                    browser: {
                      gatewayToken: "${OPENCLAW_GATEWAY_TOKEN}",
                    },
                    agents: {
                      main: {
                        brain: {
                          provider: "anthropic",
                          model: "claude-sonnet-4-20250514",
                          apiKey: "${ANTHROPIC_API_KEY}",
                        },
                      },
                    },
                  }
  destination:
    server: https://kubernetes.default.svc
    namespace: claw
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
      - ApplyOutOfSyncOnly=false
EOF

3.sync by argocd

Details
argocd app sync argocd/openclaw

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


1.prepare `openclaw-env-secret.yaml`

Details
kubectl get namespaces claw > /dev/null 2>&1 || kubectl create namespace claw
kubectl create secret generic openclaw-env-secret -n claw \
--from-literal=ANTHROPIC_API_KEY=REPLACE_WITH_YOUR_API_KEY \
--from-literal=OPENCLAW_GATEWAY_TOKEN=REPLACE_WITH_YOUR_TOKEN_KEY

2.prepare `deploy-openclaw.yaml`

Details
kubectl -n argocd apply -f - <<EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: openclaw
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://serhanekicii.github.io/openclaw-helm
    chart: openclaw
    targetRevision: 1.4.4
    helm:
      releaseName: openclaw
      values: |
        app-template:
          openclawVersion: "2026.2.23"
          chromiumVersion: "124"
          configMode: merge
          controllers:
            main:
              containers:
                main:
                  image:
                    repository: ghcr.io/openclaw/openclaw
                    tag: "2026.2.23"
                    pullPolicy: IfNotPresent
                  envFrom:
                    - secretRef:
                        name: openclaw-env-secret
                  args:
                    - "gateway"
                    - "--bind"
                    - "lan"
                    - "--port"
                    - "18789"
                    - "--allow-unconfigured"
                  resources:
                    requests:
                      cpu: 200m
                      memory: 512Mi
                    limits:
                      cpu: 2000m
                      memory: 2Gi
                chromium:
                  image:
                    repository: zenika/alpine-chrome
                    tag: "124"
                    pullPolicy: IfNotPresent
                  args:
                    - "--no-sandbox"
                    - "--disable-dev-shm-usage"
                    - "--remote-debugging-address=0.0.0.0"
                    - "--remote-debugging-port=9222"
                  resources:
                    requests:
                      cpu: 200m
                      memory: 512Mi
                    limits:
                      cpu: 2000m
                      memory: 2Gi
          persistence:
            data:
              enabled: true
              type: persistentVolumeClaim
              accessMode: ReadWriteOnce
              size: 10Gi
              globalMounts:
                - path: /root/.openclaw
          ingress:
            main:
              enabled: true
              className: nginx
              annotations:
                kubernetes.io/ingress.class: nginx
                cert-manager.io/cluster-issuer: lets-encrypt
                nginx.ingress.kubernetes.io/proxy-connect-timeout: "300"
                nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
                nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
                nginx.ingress.kubernetes.io/proxy-body-size: "50m"
                nginx.ingress.kubernetes.io/upstream-keepalive-connections: "50"
                nginx.ingress.kubernetes.io/upstream-keepalive-timeout: "60"
              hosts:
                - host: openclaw.72602.online
                  paths:
                    - path: /
                      pathType: Prefix
                      service:
                        identifier: main
                        port: http
              tls:
                - secretName: openclaw-tls
                  hosts:
                    - openclaw.72602.online
          configMaps:
            config:
              data:
                openclaw.json: |
                  {
                    gateway: {
                      controlUi: {
                        allowedOrigins: ["https://openclaw.72602.online"],
                        dangerouslyAllowHostHeaderOriginFallback: true,
                      },
                    },
                    browser: {
                      gatewayToken: "${OPENCLAW_GATEWAY_TOKEN}",
                    },
                    agents: {
                      main: {
                        brain: {
                          provider: "anthropic",
                          model: "claude-sonnet-4-20250514",
                          apiKey: "${ANTHROPIC_API_KEY}",
                        },
                      },
                    },
                  }
  destination:
    server: https://kubernetes.default.svc
    namespace: claw
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
      - ApplyOutOfSyncOnly=false
EOF

3.sync by argocd

Details
argocd app sync argocd/openclaw
Using AY Helm Mirror

for more information, you can check ๐Ÿ”—https://github.com/AaronYang0628/helm-chart-mirror

helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
  helm repo update
  helm install ay-helm-mirror/chart-name --generate-name --version a.b.c
Using AY ACR Image Mirror
Using DaoCloud Mirror

๐Ÿ›Ž๏ธFAQ

Q1: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Q2: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Mar 7, 2024

Subsections of BI

Install Superset

๐Ÿš€Installation

Install By

1.get helm repo

Details
helm repo add xxxxx https://xxxx
helm repo update

2.install chart

Details
helm install xxxxx/chart-name --generate-name --version a.b.c
Using AY Helm Mirror

for more information, you can check ๐Ÿ”—https://github.com/AaronYang0628/helm-chart-mirror

helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
  helm repo update
  helm install ay-helm-mirror/chart-name --generate-name --version a.b.c

4. Postgresql is installed; if not, check ๐Ÿ”—link


5. Redis is installed; if not, check ๐Ÿ”—link


1.prepare `superset-external-env`

Details
kubectl create secret generic superset-external-env -n database \
--from-literal=DB_HOST=postgresql.database.svc.cluster.local \
--from-literal=DB_PORT=5432 \
--from-literal=DB_USER=n8n \
--from-literal=DB_PASS=REPLACE_DB_PASSWORD \
--from-literal=DB_NAME=superset \
--from-literal=REDIS_HOST=redis-master.database.svc.cluster.local \
--from-literal=REDIS_PORT=6379 \
--from-literal=REDIS_USER= \
--from-literal=REDIS_PASSWORD=REPLACE_REDIS_PASSWORD \
--from-literal=REDIS_PROTO=redis \
--from-literal=REDIS_DB=1 \
--from-literal=REDIS_CELERY_DB=0 \
--from-literal=SUPERSET_SECRET_KEY=REPLACE_SUPERSET_SECRET_KEY \
--from-literal=SUPERSET_ADMIN_PASSWORD=REPLACE_SUPERSET_ADMIN_PASSWORD

2.prepare `deploy-superset.yaml`

Details
kubectl -n argocd apply -f -<<EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: superset
spec:
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
  project: default
  source:
    repoURL: https://apache.github.io/superset
    targetRevision: 0.15.5
    helm:
      releaseName: superset
      values: |
        envFromSecret: superset-external-env
        secretEnv:
          create: false
        bootstrapScript: |
          #!/bin/bash
          uv pip install psycopg2-binary
          if [ ! -f ~/bootstrap ]; then echo "Running Superset with uid {{ .Values.runAsUser }}" > ~/bootstrap; fi
        postgresql:
          enabled: false
        redis:
          enabled: false
        supersetNode:
          connections:
            db_type: postgresql
            db_host: postgresql.database.svc.cluster.local
            db_port: "5432"
            db_user: n8n
            db_name: superset
            redis_host: redis-master.database.svc.cluster.local
            redis_port: "6379"
            redis_user: ""
            redis_cache_db: "1"
            redis_celery_db: "0"
        configOverrides:
          secret: |
            import os
            SECRET_KEY = os.getenv("SUPERSET_SECRET_KEY")
          proxy: |
            ENABLE_PROXY_FIX = True
        init:
          createAdmin: false
          initscript: |-
            #!/bin/sh
            set -eu
            echo "Upgrading DB schema..."
            superset db upgrade
            echo "Initializing roles..."
            superset init
            echo "Creating admin user..."
            superset fab create-admin \
              --username admin \
              --firstname Superset \
              --lastname Admin \
              --email admin@dev.72602.online \
              --password "${SUPERSET_ADMIN_PASSWORD}" \
              || true
        ingress:
          enabled: true
          ingressClassName: nginx
          annotations:
            cert-manager.io/cluster-issuer: lets-encrypt
          hosts:
            - superset.dev.72602.online
          path: /
          pathType: Prefix
          tls:
            - secretName: superset.dev.72602.online-tls
              hosts:
                - superset.dev.72602.online
    chart: superset
  destination:
    server: https://kubernetes.default.svc
    namespace: database
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true

EOF
Details
kubectl -n argocd apply -f -<< EOF

EOF

3.sync by argocd

Details
argocd app sync argocd/superset
Using AY Helm Mirror

for more information, you can check ๐Ÿ”—https://github.com/AaronYang0628/helm-chart-mirror

helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
  helm repo update
  helm install ay-helm-mirror/chart-name --generate-name --version a.b.c
Using AY ACR Image Mirror
Using DaoCloud Mirror

1.init server

Details
Using AY ACR Image Mirror
Using DaoCloud Mirror

1.prepare `argocd-login-credentials`

Details
kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database

2.apply rolebinding to k8s

4.prepare `deploy-xxxx-flow.yaml`

Details

5.submit to argo workflow client

Details
argo -n business-workflows submit deploy-xxxx-flow.yaml

7.decode password

Details
kubectl -n application get secret xxxx-credentials -o jsonpath='{.data.xxx-password}' | base64 -d

1.init server

Details
Using AY ACR Image Mirror
Using DaoCloud Mirror

๐Ÿ›Ž๏ธFAQ

Q1: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Q2: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

May 7, 2026

Subsections of Application

N8N

๐Ÿš€Installation

Environment
Install By

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


  1. Database postgresql has been installed, if not check ๐Ÿ”—link


1.prepare `n8n-middleware-credentials.yaml`

Details
kubectl get namespaces n8n > /dev/null 2>&1 || kubectl create namespace n8n
N8N_PASSWORD=$(kubectl -n database get secret postgresql-credentials -o jsonpath='{.data.password}' | base64 -d)
kubectl -n n8n create secret generic n8n-middleware-credential \
--from-literal=postgres-password="${N8N_PASSWORD}"

2.prepare `deploy-n8n.yaml`

Details
kubectl -n argocd apply -f - <<EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: n8n
spec:
  project: default
  source:
    repoURL: https://community-charts.github.io/helm-charts
    targetRevision: 1.16.36
    helm:
      releaseName: n8n
      values: |
        global:
          security:
            allowInsecureImages: true
        image:
          repository: n8nio/n8n
        log:
          level: info
        encryptionKey: "ay-dev-n8n"
        timezone: Asia/Shanghai
        db:
          type: postgresdb
        externalPostgresql:
          host: postgresql-hl.database.svc.cluster.local
          port: 5432
          username: "n8n"
          database: "n8n"
          existingSecret: "n8n-middleware-credential"
        main:
          count: 1
          extraEnvVars:
            "N8N_BLOCK_ENV_ACCESS_IN_NODE": "false"
            "N8N_FILE_SYSTEM_ALLOWED_PATHS": "/home/node/.n8n-files"
            "EXECUTIONS_TIMEOUT": "300"
            "EXECUTIONS_TIMEOUT_MAX": "600"
            "DB_POSTGRESDB_POOL_SIZE": "10"
            "CACHE_ENABLED": "true"
            "N8N_CONCURRENCY_PRODUCTION_LIMIT": "5"
            "NODE_TLS_REJECT_UNAUTHORIZED": "0"
            "N8N_SECURE_COOKIE": "false"
            "WEBHOOK_URL": "https://webhook.n8n.dev.72602.online"
            "QUEUE_BULL_REDIS_TIMEOUT_THRESHOLD": "60000"
            "N8N_COMMUNITY_PACKAGES_ENABLED": "true"
            "N8N_GIT_NODE_DISABLE_BARE_REPOS": "true"
            "N8N_LICENSE_AUTO_RENEW_ENABLED": "true"
            "N8N_LICENSE_RENEW_ON_INIT": "true"
          persistence:
            enabled: true
            accessMode: ReadWriteOnce
            storageClass: "local-path"
            size: 50Gi
          volumes:
            - name: downloads-volume
              hostPath:
                path: /home/aaron/Downloads
                type: DirectoryOrCreate
          volumeMounts:
            - name: downloads-volume
              mountPath: /home/node/.n8n-files
          resources:
            requests:
              cpu: 1000m
              memory: 1024Mi
            limits:
              cpu: 2000m
              memory: 2048Mi
        worker:
          mode: queue
          count: 2
          waitMainNodeReady:
            enabled: false
          extraEnvVars:
            "N8N_FILE_SYSTEM_ALLOWED_PATHS": "/home/node/.n8n-files"
            "EXECUTIONS_TIMEOUT": "300"
            "EXECUTIONS_TIMEOUT_MAX": "600"
            "DB_POSTGRESDB_POOL_SIZE": "5"
            "QUEUE_BULL_REDIS_TIMEOUT_THRESHOLD": "60000"
            "N8N_COMMUNITY_PACKAGES_ENABLED": "true"
            "N8N_GIT_NODE_DISABLE_BARE_REPOS": "true"
            "N8N_LICENSE_AUTO_RENEW_ENABLED": "true"
            "N8N_LICENSE_RENEW_ON_INIT": "true"
          persistence:
            enabled: true
            accessMode: ReadWriteOnce
            storageClass: "local-path"
            size: 50Gi
          volumes:
            - name: downloads-volume
              hostPath:
                path: /home/aaron/Downloads
                type: DirectoryOrCreate
          volumeMounts:
            - name: downloads-volume
              mountPath: /home/node/.n8n-files
          resources:
            requests:
              cpu: 500m
              memory: 1024Mi
            limits:
              cpu: 1000m
              memory: 2048Mi
        nodes:
          builtin:
            enabled: true
            modules:
              - crypto
              - fs
          external:
            allowAll: true
            packages:
              - n8n-nodes-globals
        npmRegistry:
          enabled: true
          url: http://mirrors.cloud.tencent.com/npm/
        redis:
          enabled: true
          image:
            registry: m.daocloud.io/docker.io
            repository: bitnamilegacy/redis
          master:
            resourcesPreset: "small"
            persistence:
              enabled: true
              accessMode: ReadWriteOnce
              storageClass: "local-path"
              size: 10Gi
        ingress:
          enabled: true
          className: nginx
          annotations:
            kubernetes.io/ingress.class: nginx
            cert-manager.io/cluster-issuer: self-signed-ca-issuer
            nginx.ingress.kubernetes.io/proxy-connect-timeout: "300"
            nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
            nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
            nginx.ingress.kubernetes.io/proxy-body-size: "50m"
            nginx.ingress.kubernetes.io/upstream-keepalive-connections: "50"
            nginx.ingress.kubernetes.io/upstream-keepalive-timeout: "60"
            nginx.ingress.kubernetes.io/enable-cors: "true"
            nginx.ingress.kubernetes.io/cors-allow-origin: "https://webhook.n8n.dev.72602.online:32443"
            nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, OPTIONS, PUT, DELETE"
            nginx.ingress.kubernetes.io/cors-allow-headers: "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization"
            nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
          hosts:
            - host: n8n.dev.72602.online
              paths:
                - path: /
                  pathType: Prefix
            - host: webhook.n8n.dev.72602.online
              paths:
                - path: /
                  pathType: Prefix
          tls:
          - hosts:
            - n8n.dev.72602.online
            - webhook.n8n.dev.72602.online
            secretName: n8n.dev.72602.online-tls
        webhook:
          mode: queue
          url: "https://webhook.n8n.dev.72602.online"
          autoscaling:
            enabled: false
          waitMainNodeReady:
            enabled: true
          resources:
            requests:
              cpu: 200m
              memory: 256Mi
            limits:
              cpu: 512m
              memory: 512Mi
    chart: n8n
  destination:
    server: https://kubernetes.default.svc
    namespace: n8n
  syncPolicy:
    syncOptions:
      - CreateNamespace=true
      - ApplyOutOfSyncOnly=false

EOF

3.sync by argocd

Details
argocd app sync argocd/n8n
Using AY Helm Mirror

for more information, you can check ๐Ÿ”—https://github.com/AaronYang0628/helm-chart-mirror

helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
  helm repo update
  helm install ay-helm-mirror/chart-name --generate-name --version a.b.c
Using AY ACR Image Mirror
Using DaoCloud Mirror
Install By

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


  1. Database postgresql has been installed, if not check ๐Ÿ”—link


1.verify retained credentials and storage

Details
kubectl get namespace n8n
kubectl -n n8n get secret n8n-middleware-credential n8n-encryption-key-existing
kubectl -n n8n get pvc
Important

The live credentials and PVCs are retained state. Do not delete, recreate, or replace them when updating the Argo CD Application.

2.prepare `deploy-n8n.yaml`

Details
kubectl -n argocd apply -f - <<'EOF'
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: n8n
  namespace: argocd
spec:
  project: default
  ignoreDifferences:
    - group: ""
      kind: Secret
      name: n8n-redis
      namespace: n8n
      jsonPointers:
        - /data/redis-password
    - group: apps
      kind: StatefulSet
      name: n8n-redis-master
      namespace: n8n
      jqPathExpressions:
        - .spec.template.metadata.annotations."checksum/secret"
  source:
    repoURL: https://community-charts.github.io/helm-charts
    targetRevision: 1.16.36
    chart: n8n
    helm:
      releaseName: n8n
      values: |
        global:
          security:
            allowInsecureImages: true
        image:
          repository: m.daocloud.io/docker.io/n8nio/n8n
        log:
          level: info
        existingEncryptionKeySecret: n8n-encryption-key-existing
        timezone: Asia/Shanghai
        db:
          type: postgresdb
        externalPostgresql:
          host: postgresql-hl.database.svc.cluster.local
          port: 5432
          username: "n8n"
          database: "n8n"
          existingSecret: "n8n-middleware-credential"
        main:
          count: 1
          editorBaseUrl: "https://n8n.72602.space"
          extraEnvVars:
            HTTP_PROXY: "http://192.168.0.25:17890"
            HTTPS_PROXY: "http://192.168.0.25:17890"
            NO_PROXY: "registry.npmjs.org,npmjs.org,npmmirror.com,registry.npmmirror.com"
            no_proxy: "registry.npmjs.org,npmjs.org,npmmirror.com,registry.npmmirror.com"
            NPM_CONFIG_REGISTRY: "https://registry.npmmirror.com"
            N8N_BLOCK_ENV_ACCESS_IN_NODE: "false"
            N8N_FILE_SYSTEM_ALLOWED_PATHS: "/data"
            EXECUTIONS_TIMEOUT: "300"
            EXECUTIONS_TIMEOUT_MAX: "600"
            DB_POSTGRESDB_POOL_SIZE: "10"
            CACHE_ENABLED: "true"
            N8N_CONCURRENCY_PRODUCTION_LIMIT: "5"
            NODE_TLS_REJECT_UNAUTHORIZED: "0"
            N8N_SECURE_COOKIE: "false"
            QUEUE_BULL_REDIS_TIMEOUT_THRESHOLD: "60000"
            N8N_COMMUNITY_PACKAGES_ENABLED: "true"
            N8N_GIT_NODE_DISABLE_BARE_REPOS: "true"
            N8N_LICENSE_AUTO_RENEW_ENABLED: "true"
            N8N_LICENSE_RENEW_ON_INIT: "true"
          persistence:
            enabled: true
            accessMode: ReadWriteOnce
            storageClass: "local-path"
            size: 5Gi
          volumes:
            - name: downloads-volume
              hostPath:
                path: /run/media/aaron/DATA
                type: DirectoryOrCreate
          volumeMounts:
            - name: downloads-volume
              mountPath: /data
          resources:
            requests:
              cpu: 1000m
              memory: 1024Mi
            limits:
              cpu: 2000m
              memory: 2048Mi
        worker:
          mode: queue
          count: 2
          waitMainNodeReady:
            enabled: false
          extraEnvVars:
            HTTP_PROXY: "http://192.168.0.25:17890"
            HTTPS_PROXY: "http://192.168.0.25:17890"
            NO_PROXY: "registry.npmjs.org,npmjs.org,npmmirror.com,registry.npmmirror.com"
            no_proxy: "registry.npmjs.org,npmjs.org,npmmirror.com,registry.npmmirror.com"
            NPM_CONFIG_REGISTRY: "https://registry.npmmirror.com"
            N8N_FILE_SYSTEM_ALLOWED_PATHS: "/data"
            EXECUTIONS_TIMEOUT: "300"
            EXECUTIONS_TIMEOUT_MAX: "600"
            DB_POSTGRESDB_POOL_SIZE: "5"
            QUEUE_BULL_REDIS_TIMEOUT_THRESHOLD: "60000"
            N8N_COMMUNITY_PACKAGES_ENABLED: "true"
            N8N_GIT_NODE_DISABLE_BARE_REPOS: "true"
            N8N_LICENSE_AUTO_RENEW_ENABLED: "true"
            N8N_LICENSE_RENEW_ON_INIT: "true"
          persistence:
            enabled: true
            accessMode: ReadWriteOnce
            storageClass: "local-path"
            size: 50Gi
          volumes:
            - name: downloads-volume
              hostPath:
                path: /run/media/aaron/DATA
                type: DirectoryOrCreate
          volumeMounts:
            - name: downloads-volume
              mountPath: /data
          resources:
            requests:
              cpu: 500m
              memory: 1024Mi
            limits:
              cpu: 1000m
              memory: 2048Mi
        nodes:
          builtin:
            enabled: true
            modules:
              - crypto
              - fs
          external:
            allowAll: true
            packages:
              - n8n-nodes-globals
              - n8n-nodes-wechat-formatter
        npmRegistry:
          enabled: true
          url: https://registry.npmmirror.com
        redis:
          enabled: true
          image:
            registry: m.daocloud.io/docker.io
            repository: bitnamilegacy/redis
          master:
            resourcesPreset: "small"
            persistence:
              enabled: true
              accessMode: ReadWriteOnce
              storageClass: "local-path"
              size: 50Gi
        ingress:
          enabled: true
          className: nginx
          annotations:
            kubernetes.io/ingress.class: nginx
            cert-manager.io/cluster-issuer: lets-encrypt
            nginx.ingress.kubernetes.io/proxy-connect-timeout: "300"
            nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
            nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
            nginx.ingress.kubernetes.io/proxy-body-size: "50m"
            nginx.ingress.kubernetes.io/upstream-keepalive-connections: "50"
            nginx.ingress.kubernetes.io/upstream-keepalive-timeout: "60"
          hosts:
            - host: n8n.72602.space
              paths:
                - path: /
                  pathType: Prefix
            - host: webhook.n8n.72602.space
              paths:
                - path: /
                  pathType: Prefix
          tls:
            - hosts:
                - n8n.72602.space
                - webhook.n8n.72602.space
              secretName: n8n.72602.space-tls
        webhook:
          mode: queue
          url: "https://webhook.n8n.72602.space"
          autoscaling:
            enabled: false
          waitMainNodeReady:
            enabled: true
          resources:
            requests:
              cpu: 200m
              memory: 256Mi
            limits:
              cpu: 512m
              memory: 512Mi
  destination:
    server: https://kubernetes.default.svc
    namespace: n8n
  syncPolicy:
    syncOptions:
      - CreateNamespace=true
      - ApplyOutOfSyncOnly=false
      - RespectIgnoreDifferences=true
EOF

3.sync by argocd

Details
argocd app sync argocd/n8n
Using AY Helm Mirror

for more information, you can check ๐Ÿ”—https://github.com/AaronYang0628/helm-chart-mirror

helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
  helm repo update
  helm install ay-helm-mirror/chart-name --generate-name --version a.b.c
Using AY ACR Image Mirror
Using DaoCloud Mirror

๐Ÿ›Ž๏ธFAQ

Q1: n8n cannot connect to PostgreSQL

Symptom

  • n8n Pod starts but keeps retrying DB connection.

Check

kubectl -n n8n get pods
kubectl -n n8n logs deploy/n8n -c n8n --tail=100
kubectl -n n8n get secret n8n-middleware-credential -o yaml
kubectl -n database get svc postgresql-hl

Fix

  • Confirm secret key name matches chart expectation (postgres-password).
  • Confirm DB host/port/user/database in values are correct.
  • Ensure PostgreSQL is healthy before syncing n8n.

Expected

  • n8n Pod reaches Running and UI becomes accessible.
Q2: 72602 Argo CD reports Redis Secret and checksum drift

Symptom

  • Secret/n8n-redis and StatefulSet/n8n-redis-master repeatedly report drift even though Redis is healthy.

Root cause

  • The Redis subchart renders a generated password when no fixed password is supplied. A new desired render changes /data/redis-password and the derived pod-template checksum/secret without indicating live credential corruption.

Fix

  • Preserve all live n8n credentials and PVCs. Do not delete, recreate, or replace them to resolve this drift.
  • Keep ignoreDifferences limited to /data/redis-password and the Redis StatefulSet’s checksum/secret, with RespectIgnoreDifferences=true.
  • Review the remaining diff, then sync the Application only when it contains the intended values change.
argocd app diff argocd/n8n --insecure --grpc-web --refresh
argocd app sync argocd/n8n --insecure --grpc-web
argocd app get argocd/n8n --insecure --grpc-web
kubectl -n n8n rollout status deployment/n8n --timeout=300s
kubectl -n n8n rollout status statefulset/n8n-redis-master --timeout=300s

Rollback

  • Remove only the two ignoreDifferences entries and RespectIgnoreDifferences=true, then reapply the Application. This restores drift reporting without changing the Secret or PVC.

Expected

  • Argo CD reports Synced and Healthy; n8n and Redis remain Ready, and the existing PVCs remain Bound.
Q3: Community nodes fail โ€” “Unrecognized node type” after pod restart

Symptom

  • Webhook ๆˆ– workflow ๆŠฅ Unrecognized node type: n8n-nodes-xxx
  • ็คพๅŒบๅŒ…ๅœจ Pod ้‡ๅฏๅŽๆถˆๅคฑ

Root cause

  • Helm chart ๅ†…็ฝฎ initContainer ไฝฟ็”จ node:20-alpine๏ผŒ็ผบๅฐ‘ Python
  • ๅซ native ไพ่ต–็š„ๅŒ…๏ผˆๅฆ‚ isolated-vm๏ผ‰npm install ๅคฑ่ดฅ๏ผŒๅฏผ่‡ดๆ‰€ๆœ‰็คพๅŒบๅŒ…ๆœชๅฎ‰่ฃ…
  • ๅฏน webhook pod๏ผŒchart ้ป˜่ฎคไธๆไพ›็คพๅŒบ่Š‚็‚น volume/initContainer

Fix (permanent, survives ArgoCD sync)

ๆ ธๅฟƒๆ€่ทฏ๏ผšchart ๅ†…็ฝฎ initContainer ็ฉบ่ท‘๏ผŒ่‡ชๅฎšไน‰ initContainer ๆณจๅ…ฅๅˆฐ `main/worker/webhook.initContainers`ใ€‚

nodes:
  external:
    packages: []   # ๆธ…็ฉบ chart ๅ†…็ฝฎๅŒ…ๅˆ—่กจ๏ผŒ้ฟๅ… native build ๅคฑ่ดฅ
main:
  volumes:
    - name: community-node-modules
      emptyDir: {}
  volumeMounts:
    - name: community-node-modules
      mountPath: /home/node/.n8n/nodes
  initContainers:
    - name: npm-install-community
      image: node:20-alpine
      command: ['/bin/sh', '-c']
      args:
        - |
          export COMMUNITY_PACKAGES="n8n-nodes-globals n8n-nodes-wechat-formatter n8n-nodes-browserless-api"
          mkdir -p /nodesdata/nodes
          echo "$COMMUNITY_PACKAGES" | sha256sum > /nodesdata/nodes/packages.hash.new
          if [ ! -f /nodesdata/nodes/packages.hash ] || ! cmp /nodesdata/nodes/packages.hash /nodesdata/nodes/packages.hash.new; then
            npm install --loglevel info --no-save --ignore-scripts $COMMUNITY_PACKAGES --prefix /nodesdata/nodes
            mv /nodesdata/nodes/packages.hash.new /nodesdata/nodes/packages.hash
          fi
      env:
        - name: HTTP_PROXY
          value: http://192.168.0.25:17890
        - name: HTTPS_PROXY
          value: http://192.168.0.25:17890
      volumeMounts:
        - name: community-node-modules
          mountPath: /nodesdata/nodes
      securityContext:
        runAsUser: 1000
        runAsGroup: 1000
        runAsNonRoot: true
# worker ๅ’Œ webhook ๅŒๆ ทๆทปๅŠ ไธŠ่ฟฐ volumes/volumeMounts/initContainers
worker:
  volumes: ...
  volumeMounts: ...
  initContainers: ...
webhook:
  volumes: ...
  volumeMounts: ...
  initContainers: ...

--ignore-scripts ๆ˜ฏๅ…ณ้”ฎ๏ผš่ทณ่ฟ‡ isolated-vm ็ญ‰ native ไพ่ต–็ผ–่ฏ‘๏ผŒnode:20-alpine ไธๅซ Python ไนŸ่ƒฝ่ฃ…ใ€‚

ๅŒไธŠ๏ผŒๅช้œ€ไฟฎๆ”น๏ผš - `HTTP_PROXY`/`HTTPS_PROXY` ๆŒ‰ ZJ ้›†็พคไปฃ็†ๅœฐๅ€ๅกซๅ†™ - `COMMUNITY_PACKAGES` ๆŒ‰้œ€่ฐƒๆ•ด

Manual emergency fix (quick)

# ๅœจๆฏไธช Pod ๅ†…ๆ‰‹ๅŠจๅฎ‰่ฃ…
kubectl exec -n n8n deploy/n8n -- sh -c \
  "cd /home/node/.n8n/nodes && npm install --ignore-scripts n8n-nodes-globals n8n-nodes-wechat-formatter n8n-nodes-browserless-api"
kubectl exec -n n8n statefulset/n8n-worker -- sh -c \
  "cd /home/node/.n8n/nodes && npm install --ignore-scripts n8n-nodes-globals n8n-nodes-wechat-formatter n8n-nodes-browserless-api"
# ้‡ๅฏ n8n ๅŠ ่ฝฝๆ–ฐ่Š‚็‚น
kubectl delete pods -n n8n -l app.kubernetes.io/component=main
kubectl delete pods -n n8n -l app.kubernetes.io/component=worker

Expected

  • kubectl exec -n n8n deploy/n8n -- ls /home/node/.n8n/nodes/node_modules/ | grep n8n ๆœ‰่พ“ๅ‡บ
  • Webhook ่ฟ”ๅ›žๆญฃๅธธๅ“ๅบ”๏ผˆ้ž Unrecognized node type๏ผ‰
Mar 7, 2024

Wechat Markdown Editor

Official Documentation: https://github.com/doocs/md

๐Ÿš€Installation

Install By

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


1.prepare `deploy-wx-article-editor.yaml`

Details
kubectl -n argocd apply -f - <<'EOF'
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: wx-article-editor
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://bjw-s-labs.github.io/helm-charts
    chart: app-template
    targetRevision: 4.4.0
    helm:
      values: |
        controllers:
          main:
            containers:
              app:
                image:
                  repository: m.daocloud.io/docker.io/doocs/md
                  tag: latest
                  pullPolicy: IfNotPresent
                probes:
                  liveness:
                    enabled: true
                  readiness:
                    enabled: true
                  startup:
                    enabled: true

        service:
          app:
            controller: main
            ports:
              http:
                port: 80

        ingress:
          app:
            enabled: true
            className: nginx
            annotations:
              kubernetes.io/ingress.class: nginx
              cert-manager.io/cluster-issuer: self-signed-ca-issuer
            hosts:
              - host: md.dev.72602.online
                paths:
                  - path: /
                    pathType: Prefix
                    service:
                      identifier: app
                      port: http
            tls:
              - secretName: md.dev.72602.online-tls
                hosts:
                  - md.dev.72602.online
  destination:
    server: https://kubernetes.default.svc
    namespace: application
  syncPolicy:
    syncOptions:
      - CreateNamespace=true
      - ServerSideApply=true
EOF

2.sync by argocd

Details
argocd app sync argocd/wx-article-editor

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


1.prepare `deploy-wx-article-editor.yaml`

Details
kubectl -n argocd apply -f - <<'EOF'
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: wx-article-editor
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://bjw-s-labs.github.io/helm-charts
    chart: app-template
    targetRevision: 4.4.0
    helm:
      values: |
        controllers:
          main:
            containers:
              app:
                image:
                  repository: m.daocloud.io/docker.io/doocs/md
                  tag: latest
                  pullPolicy: IfNotPresent
                probes:
                  liveness:
                    enabled: true
                  readiness:
                    enabled: true
                  startup:
                    enabled: true

        service:
          app:
            controller: main
            ports:
              http:
                port: 80

        ingress:
          app:
            enabled: true
            className: nginx
            annotations:
              kubernetes.io/ingress.class: nginx
              cert-manager.io/cluster-issuer: letsencrypt
            hosts:
              - host: md.72602.online
                paths:
                  - path: /
                    pathType: Prefix
                    service:
                      identifier: app
                      port: http
            tls:
              - secretName: md.72602.online-tls
                hosts:
                  - md.72602.online
  destination:
    server: https://kubernetes.default.svc
    namespace: application
  syncPolicy:
    syncOptions:
      - CreateNamespace=true
      - ServerSideApply=true
EOF

2.sync by argocd

Details
argocd app sync argocd/wx-article-editor

1.run container

Details
docker run -d --name wx-article-editor -p 8080:80 doocs/md:latest

2.access in browser

Details
open http://localhost:8080

Verify

Details
kubectl -n application get pods
kubectl -n application get ingress

If deployed in ZJ environment, open https://md.dev.72602.online.

If deployed in 72602 environment, open https://md.72602.online.

๐Ÿ›Ž๏ธFAQ

Q1: Page is blank after opening domain

Check Pod and Ingress first:

kubectl -n application get pods
kubectl -n application logs deploy/wx-article-editor --tail=100
kubectl -n application describe ingress

Then verify the domain resolves to your ingress entry node.

Q2: Browser does not trust HTTPS certificate

If you use self-signed issuer in ZJ, export CA cert and import into browser:

kubectl -n basic-components get secret root-secret -o jsonpath='{.data.tls\.crt}' | base64 -d > cert-manager-self-signed-ca-secret.crt
Mar 7, 2024

Charge Spot Quest

Overview

Charge Spot Quest is the ้‚ป้‡Œไบ’ๅŠฉยทๅ…ฑไบซๅ……็”ต UI + booking API. It is deployed via the 72602 ArgoCD GitOps pipeline using Helm chart charge-spot-quest (version 0.1.3) with in-cluster SQLite.

  • ArgoCD Application: argocd/charge-spot-quest (child of argocd/ops-docs)
  • Namespace: charge-spot
  • Service: charge-spot-quest (port 8080)
  • Ingress: charge.72602.space (TLS via cert-manager)
  • Database: SQLite PVC charge-spot-quest-sqlite (1Gi, local-path)

Subsections of Charge Spot Quest

Install (ArgoCD)

๐Ÿš€Installation

Environment
Install By

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


1.prepare `charge` DNS A record

Details
# zone 72602.space, RR charge, type A, value 47.110.67.161, TTL 600
# create only when the matching enabled record is absent

2.prepare `charge-spot-quest-argocd.yaml`

Details
git -C /home/aaron/Ops/docs fetch origin main
git -C /home/aaron/Ops/docs \
  show origin/main:manifests/charge-spot-quest-argocd.yaml >/dev/null

argocd app get ops-docs --hard-refresh
argocd app sync ops-docs --revision main
argocd app wait ops-docs --sync --timeout 300

kubectl wait --for=jsonpath='{.status.phase}'=Active \
  namespace/charge-spot --timeout=120s

The parent ops-docs Application reads the manifests path and creates the child Application. The child creates namespace charge-spot through CreateNamespace=true. SQLite is enabled; bundled and external PostgreSQL stay off.

3.sync by argocd

Details
argocd app get charge-spot-quest --hard-refresh
argocd app sync charge-spot-quest
argocd app wait charge-spot-quest --sync --health --timeout 600

4.verify

Details
kubectl -n argocd get application charge-spot-quest \
  -o jsonpath='{.spec.source.repoURL}{"\n"}{.spec.source.path}{"\n"}{.spec.source.targetRevision}{"\n"}'

kubectl -n charge-spot get deployment charge-spot-quest \
  -o jsonpath='{range .spec.template.spec.containers[*]}{.name}{"="}{.image}{"\n"}{end}'

kubectl -n charge-spot rollout status deployment/charge-spot-quest --timeout=600s
kubectl -n charge-spot get pods,svc,ingress,pvc
kubectl -n charge-spot get certificate
kubectl -n charge-spot get pods -l app.kubernetes.io/component=postgresql

curl -fsS https://charge.72602.space/health
curl -fsS https://charge.72602.space/readyz
curl -fsS -o /dev/null -w '%{content_type}\n' https://charge.72602.space/
curl -fsS https://charge.72602.space/api/spots >/dev/null

Expected release values: chart charge-spot-quest version 0.1.3 and image ghcr.io/aaronyang0628/charge-spot-quest@sha256:c5e5b853b783b435f6bb0c369c5fb05ff79757f457714c6de11f4f7720e4aa35. Ingress / returns text/html. PVC charge-spot-quest-sqlite is Bound at 1Gi. TLS certificate charge.72602.space-tls should be Ready with expiry 2026-12-14T06:20:17Z.

๐Ÿ“ฆRollback Guidance

If a deployment must be reverted, create a reviewed Git revert for manifests/charge-spot-quest-argocd.yaml, push it, and sync the parent application. The SQLite PVC and TLS certificate are not deleted by rollback.

cd /home/aaron/Ops/docs
git fetch origin main
git revert --no-edit fdcbdca
git push origin main
argocd app sync ops-docs --revision main
argocd app wait ops-docs --sync --health --timeout 300

Subsections of Auth

Deploy GateKeeper Server

Official Website: https://open-policy-agent.github.io/gatekeeper/website/

Preliminary

  • Kubernetes ็‰ˆๆœฌๅฟ…้กปๅคงไบŽ v1.16

Components

Gatekeeper ๆ˜ฏๅŸบไบŽ Open Policy Agent๏ผˆOPA๏ผ‰ ๆž„ๅปบ็š„ Kubernetes ๅ‡†ๅ…ฅๆŽงๅˆถๅ™จ๏ผŒๅฎƒๅ…่ฎธ็”จๆˆทๅฎšไน‰ๅ’Œๅฎžๆ–ฝ่‡ชๅฎšไน‰็ญ–็•ฅ๏ผŒไปฅๆŽงๅˆถ Kubernetes ้›†็พคไธญ่ต„ๆบ็š„ๅˆ›ๅปบใ€ๆ›ดๆ–ฐๅ’Œๅˆ ้™คๆ“ไฝœ

  • ๆ ธๅฟƒ็ป„ไปถ
    • ็บฆๆŸๆจกๆฟ๏ผˆConstraint Templates๏ผ‰๏ผšๅฎšไน‰็ญ–็•ฅ็š„่ง„ๅˆ™้€ป่พ‘๏ผŒไฝฟ็”จ Rego ่ฏญ่จ€็ผ–ๅ†™ใ€‚ๅฎƒๆ˜ฏ็ญ–็•ฅ็š„ๆŠฝ่ฑกๆจกๆฟ๏ผŒๅฏไปฅ่ขซๅคšไธช็บฆๆŸๅฎžไพ‹(Constraint Instance)ๅค็”จใ€‚
    • ็บฆๆŸๅฎžไพ‹๏ผˆConstraints Instance๏ผ‰๏ผšๅŸบไบŽ็บฆๆŸๆจกๆฟๅˆ›ๅปบ็š„ๅ…ทไฝ“็ญ–็•ฅๅฎžไพ‹๏ผŒๆŒ‡ๅฎšไบ†ๅ…ทไฝ“็š„ๅ‚ๆ•ฐๅ’ŒๅŒน้…่ง„ๅˆ™๏ผŒ็”จไบŽๅฎšไน‰ๅ“ชไบ›่ต„ๆบ้œ€่ฆๅบ”็”จ่ฏฅ็ญ–็•ฅใ€‚
    • ๅ‡†ๅ…ฅๆŽงๅˆถๅ™จ๏ผˆAdmission Controller๏ผ‰(ๆ— ้œ€ไฟฎๆ”น)๏ผšๆ‹ฆๆˆช Kubernetes API Server ็š„่ฏทๆฑ‚๏ผŒๆ นๆฎๅฎšไน‰็š„็บฆๆŸๅฏน่ฏทๆฑ‚่ฟ›่กŒ่ฏ„ไผฐ๏ผŒๅฆ‚ๆžœ่ฏทๆฑ‚่ฟๅไบ†ไปปไฝ•็บฆๆŸ๏ผŒๅˆ™ๆ‹’็ป่ฏฅ่ฏทๆฑ‚ใ€‚
      ๆ ธๅฟƒPod่ง’่‰ฒ

      mvc mvc

      • gatekeeper-audit
        • ๅฎšๆœŸๅˆ่ง„ๆฃ€ๆŸฅ๏ผš่ฏฅ็ป„ไปถไผšๆŒ‰็…ง้ข„่ฎพ็š„ๆ—ถ้—ด้—ด้š”๏ผŒๅฏน้›†็พคไธญๅทฒๅญ˜ๅœจ็š„ๆ‰€ๆœ‰่ต„ๆบ่ฟ›่กŒๅ…จ้ขๆ‰ซๆ๏ผŒไปฅๆฃ€ๆŸฅๅฎƒไปฌๆ˜ฏๅฆ็ฌฆๅˆๆ‰€ๅฎšไน‰็š„็บฆๆŸ่ง„ๅˆ™ใ€‚(ๅ‘จๆœŸๆ€ง๏ผŒๆ‰น้‡ๆฃ€ๆŸฅ)
        • ็”Ÿๆˆๅฎก่ฎกๆŠฅๅ‘Š๏ผšๅœจๅฎŒๆˆ่ต„ๆบๆ‰ซๆๅŽ๏ผŒgatekeeper-audit ไผš็”Ÿๆˆ่ฏฆ็ป†็š„ๅฎก่ฎกๆŠฅๅ‘Š๏ผŒๅ…ถไธญไผšๆ˜Ž็กฎๆŒ‡ๅ‡บๅ“ชไบ›่ต„ๆบ่ฟๅไบ†ๅ“ชไบ›็บฆๆŸ่ง„ๅˆ™๏ผŒๆ–นไพฟ็ฎก็†ๅ‘˜ๅŠๆ—ถไบ†่งฃ้›†็พค็š„ๅˆ่ง„็Šถๆ€ใ€‚
      • gatekeeper-controller-manager
        • ๅฎžๆ—ถๅ‡†ๅ…ฅๆŽงๅˆถ๏ผšไฝœไธบๅ‡†ๅ…ฅๆŽงๅˆถๅ™จ๏ผŒgatekeeper-controller-manager ๅœจ่ต„ๆบๅˆ›ๅปบใ€ๆ›ดๆ–ฐๆˆ–ๅˆ ้™คๆ“ไฝœๅ‘่ตทๆ—ถ๏ผŒไผšๅฎžๆ—ถๆ‹ฆๆˆช่ฟ™ไบ›่ฏทๆฑ‚ใ€‚ๅฎƒไผšไพๆฎ้ข„ๅฎšไน‰็š„็บฆๆŸๆจกๆฟๅ’Œ็บฆๆŸ่ง„ๅˆ™๏ผŒๅฏน่ฏทๆฑ‚ไธญ็š„่ต„ๆบ่ฟ›่กŒๅณๆ—ถ่ฏ„ไผฐใ€‚๏ผˆๅฎžๆ—ถๆ€ง๏ผŒไบ‹ไปถ้ฉฑๅŠจ๏ผ‰
        • ๅค„็†ๅ†ณ็ญ–่ฏทๆฑ‚๏ผšๆ นๆฎ่ฏ„ไผฐ็ป“ๆžœ๏ผŒๅฆ‚ๆžœ่ฏทๆฑ‚ไธญ็š„่ต„ๆบ็ฌฆๅˆๆ‰€ๆœ‰็บฆๆŸ่ง„ๅˆ™๏ผŒgatekeeper-controller-manager ไผšๅ…่ฎธ่ฏฅ่ฏทๆฑ‚็ปง็ปญๆ‰ง่กŒ;่‹ฅ่ฟๅไบ†ไปปไฝ•่ง„ๅˆ™๏ผŒๅฎƒไผšๆ‹’็ป่ฏฅ่ฏทๆฑ‚๏ผŒ้ฟๅ…่ฟ่ง„่ต„ๆบ่ฟ›ๅ…ฅ้›†็พคใ€‚

Features

  1. ็บฆๆŸ็ฎก็†

    • ่‡ชๅฎšไน‰็บฆๆŸๆจกๆฟ๏ผš็”จๆˆทๅฏไปฅไฝฟ็”จ Rego ่ฏญ่จ€็ผ–ๅ†™่‡ชๅฎšไน‰็š„็บฆๆŸๆจกๆฟ๏ผŒๅฎž็Žฐๅ„็งๅคๆ‚็š„็ญ–็•ฅ้€ป่พ‘ใ€‚

      ไพ‹ๅฆ‚๏ผŒๅฏไปฅๅฎšไน‰็ญ–็•ฅ่ฆๆฑ‚ๆ‰€ๆœ‰็š„ๅ‘ฝๅ็ฉบ้—ด NameSpace ๅฟ…้กป่ฎพ็ฝฎ็‰นๅฎš็š„ๆ ‡็ญพ๏ผŒๆˆ–่€…้™ๅˆถๆŸไบ›ๅ‘ฝๅ็ฉบ้—ดๅช่ƒฝไฝฟ็”จ็‰นๅฎš็š„้•œๅƒใ€‚

      ๆŸฅ็œ‹ๅทฒๅญ˜ๅœจ็š„็บฆๆŸๆจกๆฟๅ’Œๅฎžไพ‹
          ```shell
          kubectl get constrainttemplates
          kubectl get constraints
          ```
      
          ```shell
          kubectl apply -f - <<EOF
          apiVersion: templates.gatekeeper.sh/v1
          kind: ConstraintTemplate
          metadata:
          name: k8srequiredlabels
          spec:
              crd:
                  spec:
                  names:
                      kind: K8sRequiredLabels
                  validation:
                      openAPIV3Schema:
                          type: object
                          properties:
                              labels:
                                  type: array
                                  items:
                                      type: string
          targets:
              - target: admission.k8s.gatekeeper.sh
              rego: |
                  package k8srequiredlabels
      
                  violation[{"msg": msg, "details": {"missing_labels": missing}}] {
                      provided := {label | input.review.object.metadata.labels[label]}
                      required := {label | label := input.parameters.labels[_]}
                      missing := required - provided
                      count(missing) > 0
                      msg := sprintf("you must provide labels: %v", [missing])
                  }
          EOF
          ```
      

    • ็บฆๆŸๆจกๆฟๅค็”จ๏ผš็บฆๆŸๆจกๆฟๅฏไปฅ่ขซๅคšไธช็บฆๆŸๅฎžไพ‹ๅค็”จ๏ผŒๆ้ซ˜ไบ†็ญ–็•ฅ็š„ๅฏ็ปดๆŠคๆ€งๅ’Œๅค็”จๆ€งใ€‚

      ไพ‹ๅฆ‚๏ผŒๅฏไปฅๅˆ›ๅปบไธ€ไธช้€š็”จ็š„ๆ ‡็ญพ็บฆๆŸๆจกๆฟ๏ผŒ็„ถๅŽๅœจไธๅŒ็š„ๅ‘ฝๅ็ฉบ้—ด NameSpace ไธญๅˆ›ๅปบไธๅŒ็š„็บฆๆŸๅฎžไพ‹๏ผŒ่ฆๆฑ‚ไธๅŒ็š„ๆ ‡็ญพใ€‚

      ไธ€ไธช็บฆๆŸๅฎžไพ‹็š„yaml
          ่ฆๆฑ‚ๆ‰€ๆœ‰็š„ๅ‘ฝๅ็ฉบ้—ด NameSpace ๅฟ…้กปๅญ˜ๅœจๆ ‡็ญพโ€œgatekeeperโ€
      
          ```yaml
          apiVersion: constraints.gatekeeper.sh/v1beta1
          kind: K8sRequiredLabels
          metadata:
          name: ns-must-have-gk-label
          spec:
              enforcementAction: dryrun
              match:
                  kinds:
                  - apiGroups: [""]
                      kinds: ["Namespace"]
              parameters:
                  labels: ["gatekeeper"]
          ```
      

    • ็บฆๆŸๆ›ดๆ–ฐ๏ผšๅฝ“็บฆๆŸๆจกๆฟๆˆ–็บฆๆŸๅ‘็”Ÿๆ›ดๆ–ฐๆ—ถ๏ผŒGatekeeper ไผš่‡ชๅŠจ้‡ๆ–ฐ่ฏ„ไผฐๆ‰€ๆœ‰็›ธๅ…ณ็š„่ต„ๆบ๏ผŒ็กฎไฟ็ญ–็•ฅ็š„ๅฎžๆ—ถ็”Ÿๆ•ˆใ€‚

  2. ่ต„ๆบๆŽงๅˆถ

    • ๅ‡†ๅ…ฅๆ‹ฆๆˆช๏ผšๅฝ“ๆœ‰่ต„ๆบๅˆ›ๅปบๆˆ–ๆ›ดๆ–ฐ่ฏทๆฑ‚ๆ—ถ๏ผŒGatekeeper ไผšๅฎžๆ—ถๆ‹ฆๆˆช่ฏทๆฑ‚๏ผŒๅนถๆ นๆฎ็ญ–็•ฅ่ฟ›่กŒ่ฏ„ไผฐใ€‚ๅฆ‚ๆžœ่ฏทๆฑ‚่ฟๅไบ†็ญ–็•ฅ๏ผŒไผš็ซ‹ๅณๆ‹’็ป่ฏทๆฑ‚๏ผŒๅนถ่ฟ”ๅ›ž่ฏฆ็ป†็š„้”™่ฏฏไฟกๆฏ๏ผŒๅธฎๅŠฉ็”จๆˆทๅฟซ้€Ÿๅฎšไฝ้—ฎ้ข˜ใ€‚

    • ่ต„ๆบๅˆ›ๅปบๅ’Œๆ›ดๆ–ฐ้™ๅˆถ๏ผšGatekeeper ๅฏไปฅ้˜ปๆญขไธ็ฌฆๅˆ็ญ–็•ฅ็š„่ต„ๆบๅˆ›ๅปบๅ’Œๆ›ดๆ–ฐ่ฏทๆฑ‚ใ€‚

      ไพ‹ๅฆ‚๏ผŒๅฆ‚ๆžœๅฎšไน‰ไบ†ไธ€ไธช็ญ–็•ฅ่ฆๆฑ‚ๆ‰€ๆœ‰็š„ Deployment ๅฟ…้กป่ฎพ็ฝฎ่ต„ๆบ้™ๅˆถ๏ผˆrequests ๅ’Œ limits๏ผ‰๏ผŒ้‚ฃไนˆๅฝ“็”จๆˆทๅฐ่ฏ•ๅˆ›ๅปบๆˆ–ๆ›ดๆ–ฐไธ€ไธชๆฒกๆœ‰่ฎพ็ฝฎ่ต„ๆบ้™ๅˆถ็š„ Deployment ๆ—ถ๏ผŒ่ฏทๆฑ‚ๅฐ†่ขซๆ‹’็ปใ€‚

      ้€š่ฟ‡enforcementActionๆฅๆŽงๅˆถ๏ผŒๅฏ้€‰๏ผšdryrun | deny | warn

      check https://open-policy-agent.github.io/gatekeeper-library/website/validation/containerlimits

    • ่ต„ๆบ็ฑปๅž‹่ฟ‡ๆปค๏ผšๅฏไปฅ้€š่ฟ‡็บฆๆŸ็š„ match ๅญ—ๆฎตๆŒ‡ๅฎš้œ€่ฆๅบ”็”จ็ญ–็•ฅ็š„่ต„ๆบ็ฑปๅž‹ๅ’Œๅ‘ฝๅ็ฉบ้—ดใ€‚

      ไพ‹ๅฆ‚๏ผŒๅฏไปฅๅชๅฏน็‰นๅฎšๅ‘ฝๅ็ฉบ้—ดไธญ็š„ Pod ๅบ”็”จ็ญ–็•ฅ๏ผŒๆˆ–่€…ๅชๅฏน็‰นๅฎš API ็ป„ๅ’Œ็‰ˆๆœฌ็š„่ต„ๆบๅบ”็”จ็ญ–็•ฅใ€‚

      ๅฏไปฅ้€š่ฟ‡syncSet (ๅŒๆญฅ้…็ฝฎ)ๆฅๆŒ‡ๅฎš่ฟ‡ๆปคๅ’Œๅฟฝ็•ฅ้‚ฃไบ›่ต„ๆบ

      ๆ‰ซๆๅ…จ้ƒจns,pod,ๅฟฝ็•ฅkubeๅผ€ๅคด็š„ๅ‘ฝๅ็ฉบ้—ด
          ```yaml
          apiVersion: config.gatekeeper.sh/v1alpha1
          kind: Config
          metadata:
          name: config
          namespace: "gatekeeper-system"
          spec:
          sync:
              syncOnly:
              - group: ""
                  version: "v1"
                  kind: "Namespace"
              - group: ""
                  version: "v1"
                  kind: "Pod"
          match:
              - excludedNamespaces: ["kube-*"]
              processes: ["*"]
          ```
      

  3. ๅˆ่ง„ๆ€งไฟ่ฏ

    • ่กŒไธšๆ ‡ๅ‡†ๅ’Œ่‡ชๅฎšไน‰่ง„่Œƒ๏ผšGatekeeper ๅฏไปฅ็กฎไฟ Kubernetes ้›†็พคไธญ็š„่ต„ๆบ็ฌฆๅˆ่กŒไธšๆ ‡ๅ‡†ๅ’Œ็ฎก็†ๅ‘˜่ฆๆฑ‚็š„ๅ†…้ƒจ็š„ๅฎ‰ๅ…จ่ง„่Œƒใ€‚

      ไพ‹ๅฆ‚๏ผŒๅฏไปฅๅฎšไน‰็ญ–็•ฅ่ฆๆฑ‚ๆ‰€ๆœ‰็š„ๅฎนๅ™จๅฟ…้กปไฝฟ็”จๆœ€ๆ–ฐ็š„ๅฎ‰ๅ…จ่กฅไธ๏ผŒๆˆ–่€…่ฆๆฑ‚ๆ‰€ๆœ‰็š„ๅญ˜ๅ‚จๅทๅฟ…้กป่ฟ›่กŒๅŠ ๅฏ†ใ€‚

      Gatekeeper ๅทฒ็ปๆไพ›่ฟ‘50็งๅ„็ฑป่ต„ๆบ้™ๅˆถ็š„็บฆๆŸ็ญ–็•ฅ๏ผŒๅฏไปฅ้€š่ฟ‡่ฎฟ้—ฎhttps://open-policy-agent.github.io/gatekeeper-library/website/ ๆŸฅ็œ‹ๅนถ่Žทๅพ—

    • ๅฎก่ฎกๅ’ŒๆŠฅๅ‘Š๏ผšGatekeeper ๅฏไปฅ่ฎฐๅฝ•ๆ‰€ๆœ‰็š„็ญ–็•ฅ่ฏ„ไผฐ็ป“ๆžœ๏ผŒๆ–นไพฟ็ฎก็†ๅ‘˜่ฟ›่กŒๅฎก่ฎกๅ’ŒๆŠฅๅ‘Šใ€‚้€š่ฟ‡ๆŸฅ็œ‹ๅฎก่ฎกๆ—ฅๅฟ—๏ผŒ็ฎก็†ๅ‘˜ๅฏไปฅไบ†่งฃๅ“ชไบ›่ต„ๆบ่ฟๅไบ†็ญ–็•ฅ๏ผŒไปฅๅŠ่ฟๅไบ†ๅ“ชไบ›็ญ–็•ฅใ€‚

    • ๅฎก่ฎกๅฏผๅ‡บ๏ผšๅฎก่ฎกๆ—ฅๅฟ—ๅฏไปฅๅฏผๅ‡บๅนถๆŽฅๅ…ฅไธ‹ๆธธใ€‚

      ่ฏฆ็ป†ไฟกๆฏๅฏไปฅๆŸฅ็œ‹https://open-policy-agent.github.io/gatekeeper/website/docs/pubsub/

Installation

install from
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/v3.18.2/deploy/gatekeeper.yaml
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm install gatekeeper/gatekeeper --name-template=gatekeeper --namespace gatekeeper-system --create-namespace

Make sure that:

  • You have Docker version 20.10 or later installed.
  • Your kubectl context is set to the desired installation cluster.
  • You have a container registry you can write to that is readable by the target cluster.
git clone https://github.com/open-policy-agent/gatekeeper.git \
&& cd gatekeeper 
  • Build and push Gatekeeper image:
export DESTINATION_GATEKEEPER_IMAGE=<add registry like "myregistry.docker.io/gatekeeper">
make docker-buildx REPOSITORY=$DESTINATION_GATEKEEPER_IMAGE OUTPUT_TYPE=type=registry
  • And the deploy
make deploy REPOSITORY=$DESTINATION_GATEKEEPER_IMAGE
Mar 12, 2024

Subsections of Binary

Argo Workflow Binary

MIRROR="files.m.daocloud.io/"
VERSION=v3.5.4
curl -sSLo argo-linux-amd64.gz "https://${MIRROR}github.com/argoproj/argo-workflows/releases/download/${VERSION}/argo-linux-amd64.gz"
gunzip argo-linux-amd64.gz
chmod u+x argo-linux-amd64
mkdir -p ${HOME}/bin
mv -f argo-linux-amd64 ${HOME}/bin/argo
rm -f argo-linux-amd64.gz
Apr 7, 2024

ArgoCD Binary

MIRROR="files.m.daocloud.io/"
VERSION=v3.1.8
[ $(uname -m) = x86_64 ] && curl -sSLo argocd "https://${MIRROR}github.com/argoproj/argo-cd/releases/download/${VERSION}/argocd-linux-amd64"
[ $(uname -m) = aarch64 ] && curl -sSLo argocd "https://${MIRROR}github.com/argoproj/argo-cd/releases/download/${VERSION}/argocd-linux-arm64"
chmod u+x argocd
mkdir -p ${HOME}/bin
mv -f argocd ${HOME}/bin

[Optional] add to PATH

cat >> ~/.bashrc  << EOF
export PATH=$PATH:/root/bin
EOF
source ~/.bashrc
Apr 7, 2024

Golang Binary

# sudo rm -rf /usr/local/go  # ๅˆ ้™คๆ—ง็‰ˆๆœฌ
wget https://go.dev/dl/go1.24.4.linux-amd64.tar.gz
tar -C /usr/local -xzf go1.24.4.linux-amd64.tar.gz
vim ~/.bashrc
export PATH=$PATH:/usr/local/go/bin
source ~/.bashrc
rm -rf ./go1.24.4.linux-amd64.tar.gz
Apr 7, 2024

Gradle Binary

MIRROR="files.m.daocloud.io/"
VERSION=v3.5.4
curl -sSLo argo-linux-amd64.gz "https://${MIRROR}github.com/argoproj/argo-workflows/releases/download/${VERSION}/argo-linux-amd64.gz"
gunzip argo-linux-amd64.gz
chmod u+x argo-linux-amd64
mkdir -p ${HOME}/bin
mv -f argo-linux-amd64 ${HOME}/bin/argo
rm -f argo-linux-amd64.gz
Apr 7, 2024

Helm Binary

ARCH_IN_FILE_NAME=linux-amd64
FILE_NAME=helm-v3.18.3-${ARCH_IN_FILE_NAME}.tar.gz
curl -sSLo ${FILE_NAME} "https://files.m.daocloud.io/get.helm.sh/${FILE_NAME}"
tar zxf ${FILE_NAME}
mkdir -p ${HOME}/bin
mv -f ${ARCH_IN_FILE_NAME}/helm ${HOME}/bin
rm -rf ./${FILE_NAME}
rm -rf ./${ARCH_IN_FILE_NAME}
chmod u+x ${HOME}/bin/helm
Apr 7, 2024

JQ Binary

JQ_VERSION=1.7
JQ_BINARY=jq-linux64
wget https://github.com/stedolan/jq/releases/download/jq-${JQ_VERSION}/${JQ_BINARY}.tar.gz -O - | tar xz && mv ${JQ_BINARY} /usr/bin/jq
Apr 7, 2024

Kind Binary

MIRROR="files.m.daocloud.io/"
VERSION=v0.29.0
[ $(uname -m) = x86_64 ] && curl -sSLo kind "https://${MIRROR}github.com/kubernetes-sigs/kind/releases/download/${VERSION}/kind-linux-amd64"
[ $(uname -m) = aarch64 ] && curl -sSLo kind "https://${MIRROR}github.com/kubernetes-sigs/kind/releases/download/${VERSION}/kind-linux-arm64"
chmod u+x kind
mkdir -p ${HOME}/bin
mv -f kind ${HOME}/bin
Apr 7, 2025

Krew Binary

cd "$(mktemp -d)" &&
OS="$(uname | tr '[:upper:]' '[:lower:]')" &&
ARCH="$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')" &&
KREW="krew-${OS}_${ARCH}" &&
curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/latest/download/${KREW}.tar.gz" &&
tar zxvf "${KREW}.tar.gz" &&
./"${KREW}" install krew
Apr 7, 2024

Kubectl Binary

MIRROR="files.m.daocloud.io/"
VERSION=$(curl -L -s https://${MIRROR}dl.k8s.io/release/stable.txt)
[ $(uname -m) = x86_64 ] && curl -sSLo kubectl "https://${MIRROR}dl.k8s.io/release/${VERSION}/bin/linux/amd64/kubectl"
[ $(uname -m) = aarch64 ] && curl -sSLo kubectl "https://${MIRROR}dl.k8s.io/release/${VERSION}/bin/linux/arm64/kubectl"
chmod u+x kubectl
mkdir -p ${HOME}/bin
mv -f kubectl ${HOME}/bin
Apr 7, 2024

Kustomize Binary

MIRROR="github.com"
VERSION="v5.7.1"
[ $(uname -m) = x86_64 ] && curl -sSLo kustomize "https:///${MIRROR}/kubernetes-sigs/kustomize/releases/download/kustomize/${VERSION}/kustomize_${VERSION}_linux_amd64.tar.gz"
[ $(uname -m) = aarch64 ] && curl -sSLo kustomize "https:///${MIRROR}/kubernetes-sigs/kustomize/releases/download/kustomize/${VERSION}/kustomize_${VERSION}_linux_arm64.tar.gz"
chmod u+x kustomize
mkdir -p ${HOME}/bin
mv -f kustomize ${HOME}/bin
Apr 7, 2024

Maven Binary

wget https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz
tar xzf apache-maven-3.9.6-bin.tar.gz -C /usr/local
ln -sfn /usr/local/apache-maven-3.9.6/bin/mvn /root/bin/mvn  
export PATH=$PATH:/usr/local/apache-maven-3.9.6/bin
source ~/.bashrc
Apr 7, 2024

Minikube Binary

MIRROR="files.m.daocloud.io/"
[ $(uname -m) = x86_64 ] && curl -sSLo minikube "https://${MIRROR}storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64"
[ $(uname -m) = aarch64 ] && curl -sSLo minikube "https://${MIRROR}storage.googleapis.com/minikube/releases/latest/minikube-linux-arm64"
chmod u+x minikube
mkdir -p ${HOME}/bin
mv -f minikube ${HOME}/bin
Apr 7, 2024

Open Java

mkdir -p /etc/apt/keyrings && \
wget -qO - https://packages.adoptium.net/artifactory/api/gpg/key/public | gpg --dearmor -o /etc/apt/keyrings/adoptium.gpg && \
echo "deb [signed-by=/etc/apt/keyrings/adoptium.gpg arch=amd64] https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main" | tee /etc/apt/sources.list.d/adoptium.list > /dev/null && \
apt-get update && \
apt-get install -y temurin-21-jdk && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
Apr 7, 2025

YQ Binary

YQ_VERSION=v4.40.5
YQ_BINARY=yq_linux_amd64
wget https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/${YQ_BINARY}.tar.gz -O - | tar xz && mv ${YQ_BINARY} /usr/bin/yq
Apr 7, 2024

CICD

Articles

FQA

Q1: difference between docker\podmn\buildah

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Mar 7, 2025

Subsections of CICD

Install Argo CD

Preliminary

  • Kubernetes is installed; if not, check ๐Ÿ”—link
  • Helm binary is installed; if not, check ๐Ÿ”—link

1. install argoCD binary

Install the argocd CLI first so you can authenticate, sync applications, and verify deployment status from your terminal.

MIRROR="files.m.daocloud.io/"
VERSION=v3.1.8
[ $(uname -m) = x86_64 ] && curl -sSLo argocd "https://${MIRROR}github.com/argoproj/argo-cd/releases/download/${VERSION}/argocd-linux-amd64"
[ $(uname -m) = aarch64 ] && curl -sSLo argocd "https://${MIRROR}github.com/argoproj/argo-cd/releases/download/${VERSION}/argocd-linux-arm64"
chmod u+x argocd
mkdir -p ${HOME}/bin
mv -f argocd ${HOME}/bin

[Optional] add to PATH

cat >> ~/.bashrc  << EOF
export PATH=$PATH:/root/bin
EOF
source ~/.bashrc

2. install components

Choose one installation path below. Helm is recommended when you want versioned upgrades and repeatable configuration.

Install By
1. Prepare argocd.values.yaml
cat <<EOF > argocd.zj.values.yaml
crds:
  install: true
  keep: false
global:
  domain: argocd.dev.72602.online
  revisionHistoryLimit: 3
  image:
    repository: m.daocloud.io/quay.io/argoproj/argocd
    imagePullPolicy: IfNotPresent
redis:
  enabled: true
  image:
    repository: m.daocloud.io/docker.io/library/redis
  exporter:
    enabled: false
    image:
      repository: m.daocloud.io/bitnami/redis-exporter
  metrics:
    enabled: false
redis-ha:
  enabled: false
  image:
    repository: m.daocloud.io/docker.io/library/redis
  configmapTest:
    repository: m.daocloud.io/docker.io/koalaman/shellcheck
  haproxy:
    enabled: false
    image:
      repository: m.daocloud.io/docker.io/library/haproxy
  exporter:
    enabled: false
    image: m.daocloud.io/docker.io/oliver006/redis_exporter
dex:
  enabled: true
  image:
    repository: m.daocloud.io/ghcr.io/dexidp/dex
server:
  ingress:
    enabled: true
    ingressClassName: nginx
    annotations:
      nginx.ingress.kubernetes.io/ssl-passthrough: "true"
      cert-manager.io/cluster-issuer: self-signed-ca-issuer
      nginx.ingress.kubernetes.io/backend-protocol: HTTPS
    hostname: argocd.dev.72602.online
    path: /
    pathType: Prefix
    tls: true
EOF
cat <<EOF > argocd.72602.values.yaml
crds:
  install: true
  keep: false
global:
  domain: argocd.72602.online
  revisionHistoryLimit: 3
  image:
    repository: m.daocloud.io/quay.io/argoproj/argocd
    imagePullPolicy: IfNotPresent
redis:
  enabled: true
  image:
    repository: m.daocloud.io/docker.io/library/redis
  exporter:
    enabled: false
    image:
      repository: m.daocloud.io/bitnami/redis-exporter
  metrics:
    enabled: false
redis-ha:
  enabled: false
  image:
    repository: m.daocloud.io/docker.io/library/redis
  configmapTest:
    repository: m.daocloud.io/docker.io/koalaman/shellcheck
  haproxy:
    enabled: false
    image:
      repository: m.daocloud.io/docker.io/library/haproxy
  exporter:
    enabled: false
    image: m.daocloud.io/docker.io/oliver006/redis_exporter
dex:
  enabled: true
  image:
    repository: m.daocloud.io/ghcr.io/dexidp/dex
server:
  ingress:
    enabled: true
    ingressClassName: nginx
    annotations:
      nginx.ingress.kubernetes.io/ssl-passthrough: "true"
      cert-manager.io/cluster-issuer: lets-encrypt
      nginx.ingress.kubernetes.io/backend-protocol: HTTPS
    hostname: argocd.72602.online
    path: /
    pathType: Prefix
    tls: true
EOF
2. Install argoCD From Mirror
helm upgrade --install argo-cd argo-cd \
  --namespace argocd \
  --create-namespace \
  --version 9.5.4 \
  --repo https://aaronyang0628.github.io/helm-chart-mirror/charts \
  --values argocd.zj.values.yaml \
  --atomic
helm install argo-cd argo-cd \
  --namespace argocd \
  --create-namespace \
  --version 9.5.4 \
  --repo https://aaronyang0628.github.io/helm-chart-mirror/charts \
  --values argocd.72602.values.yaml \
  --atomic
[Optional]() 4. Install argoCD From Original
helm upgrade --install argo-cd argo-cd \
  --namespace argocd \
  --create-namespace \
  --version 9.5.4 \
  --repo https://argoproj.github.io/argo-helm \
  --values argocd.zj.values.yaml \
  --atomic
helm install argo-cd argo-cd \
  --namespace argocd \
  --create-namespace \
  --version 9.5.4 \
  --repo https://argoproj.github.io/argo-helm \
  --values argocd.72602.values.yaml \
  --atomic

By default, you can install ArgoCD from this link.

kubectl create namespace argocd \
&& kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

Or, you can use your own manifest file URL.

4. prepare argocd-server-external.yaml

Install By
kubectl -n argocd apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/component: server
    app.kubernetes.io/instance: argo-cd
    app.kubernetes.io/name: argocd-server-external
    app.kubernetes.io/part-of: argocd
  name: argocd-server-external
spec:
  ports:
  - name: https
    port: 443
    protocol: TCP
    targetPort: 8080
    nodePort: 30443
  selector:
    app.kubernetes.io/instance: argo-cd
    app.kubernetes.io/name: argocd-server
  type: NodePort
EOF
kubectl -n argocd apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/component: server
    app.kubernetes.io/instance: argo-cd
    app.kubernetes.io/name: argocd-server-external
    app.kubernetes.io/part-of: argocd
  name: argocd-server-external
spec:
  ports:
  - name: https
    port: 443
    protocol: TCP
    targetPort: 8080
    nodePort: 30443
  selector:
    app.kubernetes.io/instance: argo-cd
    app.kubernetes.io/name: argocd-server
  type: NodePort
EOF
kubectl -n argocd apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/component: server
    app.kubernetes.io/instance: argo-cd
    app.kubernetes.io/name: argocd-server-external
    app.kubernetes.io/part-of: argocd
    app.kubernetes.io/version: v3.3.8
  name: argocd-server-external
spec:
  ports:
  - name: https
    port: 443
    protocol: TCP
    targetPort: 8080
    nodePort: 30443
  selector:
    app.kubernetes.io/instance: argo-cd
    app.kubernetes.io/name: argocd-server
  type: NodePort
EOF

6. [Optional] prepare argocd-server-ingress.yaml

You also need an ingress controller (for example ingress-nginx or traefik). If not installed, check ๐Ÿ”—link.

Install By

Before creating the ingress, install cert-manager and create the self-signed-ca-issuer issuer. If not ready, check ๐Ÿ”—link.

kubectl -n argocd apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: self-signed-ca-issuer
    nginx.ingress.kubernetes.io/backend-protocol: HTTPS
  name: argo-cd-argocd-server
  namespace: argocd
spec:
  ingressClassName: nginx
  rules:
  - host: argocd.dev.72602.online
    http:
      paths:
      - backend:
          service:
            name: argo-cd-argocd-server
            port:
              number: 443
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - argocd.dev.72602.online
    secretName: argocd.dev.72602.online-tls
EOF

Before you create ingress, you need to create cert-manager and cert-issuer lets-encrypt, if not, please check ๐Ÿ”—link

kubectl -n argocd apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: lets-encrypt
    nginx.ingress.kubernetes.io/backend-protocol: HTTPS
    nginx.ingress.kubernetes.io/ssl-passthrough: "true"
  name: argo-cd-argocd-server
  namespace: argocd
spec:
  ingressClassName: nginx
  rules:
  - host: argocd.72602.online
    http:
      paths:
      - backend:
          service:
            name: argo-cd-argocd-server
            port:
              number: 443
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - argocd.72602.online
    secretName: argocd.72602.online-tls
EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: self-signed-ca-issuer
    nginx.ingress.kubernetes.io/backend-protocol: HTTPS
    nginx.ingress.kubernetes.io/ssl-passthrough: "true"
  name: argo-cd-argocd-server
  namespace: argocd
spec:
  ingressClassName: nginx
  rules:
  - host: argocd.dev.72602.online
    http:
      paths:
      - backend:
          service:
            name: argo-cd-argocd-server
            port:
              number: 443
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - argocd.dev.72602.online
    secretName: argocd.dev.72602.online-tls

8. get argocd initialized password

kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d

9. login argocd

ARGOCD_PASS=$(kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d)
MASTER_IP=$(kubectl get nodes --selector=node-role.kubernetes.io/control-plane -o jsonpath='{$.items[0].status.addresses[?(@.type=="InternalIP")].address}')
argocd login --insecure --username admin $MASTER_IP:30443 --password $ARGOCD_PASS

if you deploy argocd in minikube, you might need to forward this port

ssh -i ~/.minikube/machines/minikube/id_rsa docker@$(minikube ip) -L '*:30443:0.0.0.0:30443' -N -f
open https://$(minikube ip):30443

if you use ingress, you might need to configure your browser to allow insecure connection

kubectl -n basic-components get secret root-secret -o jsonpath='{.data.tls\.crt}' | base64 -d > cert-manager-self-signed-ca-secret.crt

import cert-manager-self-signed-ca-secret.crt into your browser

open https://argocd.dev.72602.online

Manage User Info

user readonly is using for homepage website to grab some data from kubernetes.

  1. create local user readonly (no password, apiKey only)
kubectl -n argocd patch configmap argocd-cm --type merge -p '{"data":{"accounts.readonly":"apiKey","accounts.readonly.enabled":"true"}}'

kubectl -n argocd patch configmap argocd-rbac-cm --type merge -p '{"data":{"policy.csv":"p, role:readonly, applications, get, */*, allow\np, role:readonly, projects, get, *, allow\np, role:readonly, repositories, get, *, allow\np, role:readonly, clusters, get, *, allow\ng, readonly, role:readonly","policy.default":""}}'

kubectl -n argocd rollout restart deploy argo-cd-argocd-server
  1. retrieve user readonly token
argocd account list
argocd account generate-token --account readonly

Manage GitHub Repo

  1. generate github deploy key
ssh-keygen -t rsa -b 4096 -C "github-deploy-key" -f id_rsa_github -N ""
  1. create kubernetes secret
kubectl create secret generic github-ssh-key \
  --from-file=id_rsa=./id_rsa_github \
  --from-file=id_rsa.pub=./id_rsa_github.pub \
  --from-file=known_hosts=<(ssh-keyscan github.com)

FAQ

Q1: The browser doesnโ€™t trust this self-signed certificate

Basically, you need to import the certificate into your browser.

kubectl -n basic-components get secret root-secret -o jsonpath='{.data.tls\.crt}' | base64 -d > cert-manager-self-signed-ca-secret.crt

And then import it into your browser.

Mar 7, 2024

Install Argo WorkFlow

โš ๏ธ ZJ Lab Only โ€” Argo Workflow is only deployed in the ZJ Lab environment (ay.dev). It is not deployed in the 72602 cluster.

Preliminary

  • Kubernetes is installed; if not, check ๐Ÿ”—link
  • Argo CD is installed; if not, check ๐Ÿ”—link
  • cert-manager has installed on argocd and the clusterissuer has a named self-signed-ca-issuer, if not check ๐Ÿ”—link
kubectl get namespace business-workflows > /dev/null 2>&1 || kubectl create namespace business-workflows

1. prepare argo-workflows.yaml

content
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: argo-workflows
spec:
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
  project: default
  source:
    repoURL: https://argoproj.github.io/argo-helm
    chart: argo-workflows
    targetRevision: 0.45.27
    helm:
      releaseName: argo-workflows
      values: |
        crds:
          install: true
          keep: false
        singleNamespace: false
        controller:
          image:
            registry: m.daocloud.io/quay.io
          workflowNamespaces:
            - business-workflows
        executor:
          image:
            registry: m.daocloud.io/quay.io
        workflow:
          serviceAccount:
            create: true
          rbac:
            create: true
        server:
          enabled: true
          image:
            registry: m.daocloud.io/quay.io
          ingress:
            enabled: true
            ingressClassName: nginx
            annotations:
              cert-manager.io/cluster-issuer: self-signed-ca-issuer
              nginx.ingress.kubernetes.io/rewrite-target: /$1
              nginx.ingress.kubernetes.io/use-regex: "true"
            hosts:
              - argo-workflows.dev.72602.online
            paths:
              - /?(.*)
            pathType: ImplementationSpecific
            tls:
              - secretName: argo-workflows.dev.72602.online-tls
                hosts:
                  - argo-workflows.dev.72602.online
          authModes:
            - server
            - client
          sso:
            enabled: false
  destination:
    server: https://kubernetes.default.svc
    namespace: workflows
kubectl -n argocd apply -f - << EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: argo-workflows
spec:
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
  project: default
  source:
    repoURL: https://argoproj.github.io/argo-helm
    chart: argo-workflows
    targetRevision: 0.45.27
    helm:
      releaseName: argo-workflows
      values: |
        crds:
          install: true
          keep: false
        singleNamespace: false
        controller:
          image:
            registry: m.daocloud.io/quay.io
          workflowNamespaces:
            - business-workflows
        executor:
          image:
            registry: m.daocloud.io/quay.io
        workflow:
          serviceAccount:
            create: true
          rbac:
            create: true
        server:
          enabled: true
          image:
            registry: m.daocloud.io/quay.io
          ingress:
            enabled: true
            ingressClassName: nginx
            annotations:
              cert-manager.io/cluster-issuer: self-signed-ca-issuer
              nginx.ingress.kubernetes.io/rewrite-target: /$1
              nginx.ingress.kubernetes.io/use-regex: "true"
            hosts:
              - argo-workflows.dev.72602.online
            paths:
              - /?(.*)
            pathType: ImplementationSpecific
            tls:
              - secretName: argo-workflows.dev.72602.online-tls
                hosts:
                  - argo-workflows.dev.72602.online
          authModes:
            - server
            - client
          sso:
            enabled: false
  destination:
    server: https://kubernetes.default.svc
    namespace: workflows
EOF

2. install argo workflow binary

3. [Optional] apply to k8s

kubectl -n argocd apply -f argo-workflows.yaml

4. sync by argocd

argocd app sync argocd/argo-workflows

5. submit a test workflow

argo -n business-workflows submit https://raw.githubusercontent.com/argoproj/argo-workflows/master/examples/hello-world.yaml --serviceaccount=argo-workflow

6. check workflow status

# list all flows
argo -n business-workflows list
# get specific flow status
argo -n business-workflows get <$flow_name>
# get specific flow log
argo -n business-workflows logs <$flow_name>
# get specific flow log continuously
argo -n business-workflows logs <$flow_name> --watch
Mar 7, 2024

Install Argo Event

Preliminary

  • Kubernetes is installed; if not, check ๐Ÿ”—link
  • Argo CD is installed; if not, check ๐Ÿ”—link

1. prepare argo-events.yaml

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: argo-events
spec:
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
  project: default
  source:
    repoURL: https://argoproj.github.io/argo-helm
    chart: argo-events
    targetRevision: 2.4.2
    helm:
      releaseName: argo-events
      values: |
        openshift: false
        createAggregateRoles: true
        crds:
          install: true
          keep: true
        global:
          image:
            repository: m.daocloud.io/quay.io/argoproj/argo-events
        controller:
          replicas: 1
          resources: {}
        webhook:
          enabled: true
          replicas: 1
          port: 12000
          resources: {}
        extraObjects:
          - apiVersion: networking.k8s.io/v1
            kind: Ingress
            metadata:
              annotations:
                cert-manager.io/cluster-issuer: self-signed-ca-issuer
                nginx.ingress.kubernetes.io/rewrite-target: /$1
              labels:
                app.kubernetes.io/instance: argo-events
                app.kubernetes.io/managed-by: Helm
                app.kubernetes.io/name: argo-events-events-webhook
                app.kubernetes.io/part-of: argo-events
                argocd.argoproj.io/instance: argo-events
              name: argo-events-webhook
            spec:
              ingressClassName: nginx
              rules:
              - host: argo-events.webhook.dev.72602.online
                http:
                  paths:
                  - backend:
                      service:
                        name: events-webhook
                        port:
                          number: 12000
                    path: /?(.*)
                    pathType: ImplementationSpecific
              tls:
              - hosts:
                - argo-events.webhook.dev.72602.online
                secretName: argo-events-webhook-tls
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd

4. apply to k8s

kubectl -n argocd apply -f argo-events.yaml

5. sync by argocd

argocd app sync argocd/argo-events
Mar 7, 2024

Reloader

Install

Details
helm repo add stakater https://stakater.github.io/stakater-charts
helm repo update
helm install reloader stakater/reloader
Using AY Helm Mirror

for more information, you can check ๐Ÿ”—https://aaronyang0628.github.io/helm-chart-mirror/

helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
helm repo update
helm -n basic-components install reloader stakater/reloader
Details
kubectl apply -f https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml
Using AY Gitee Mirror
kubectl apply -f https://gitee.com/aaron2333/aaaa/raw/main/bbbb.yaml
Using AY ACR Mirror
docker pull crpi-wixjy6gci86ms14e.cn-hongkong.personal.cr.aliyuncs.com/ay-mirror/xxxx
Using DaoCloud Mirror
docker pull m.daocloud.io/docker.io/library/xxxx

Usage

  • For a Deployment called foo have a ConfigMap called foo-configmap. Then add this annotation to main metadata of your Deployment configmap.reloader.stakater.com/reload: "foo-configmap"

  • For a Deployment called foo have a Secret called foo-secret. Then add this annotation to main metadata of your Deployment secret.reloader.stakater.com/reload: "foo-secret"

  • After successful installation, your pods will get rolling updates when a change in data of configmap or secret will happen.

Reference

For more information about reloader, please refer to https://github.com/stakater/Reloader

Container

Articles

FQA

Q1: difference between docker\podmn\buildah

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Mar 7, 2025

Subsections of Container

Install Buildah

Reference

Prerequisites

  • Kernel Version Requirements To run Buildah on Red Hat Enterprise Linux or CentOS, version 7.4 or higher is required. On other Linux distributions Buildah requires a kernel version that supports the OverlayFS and/or fuse-overlayfs filesystem – you’ll need to consult your distribution’s documentation to determine a minimum version number.

  • runc Requirement Buildah uses runc to run commands when buildah run is used, or when buildah build encounters a RUN instruction, so you’ll also need to build and install a compatible version of runc for Buildah to call for those cases. If Buildah is installed via a package manager such as yum, dnf or apt-get, runc will be installed as part of that process.

  • CNI Requirement When Buildah uses runc to run commands, it defaults to running those commands in the host’s network namespace. If the command is being run in a separate user namespace, though, for example when ID mapping is used, then the command will also be run in a separate network namespace.

A newly-created network namespace starts with no network interfaces, so commands which are run in that namespace are effectively disconnected from the network unless additional setup is done. Buildah relies on the CNI library and plugins to set up interfaces and routing for network namespaces.

something wrong with CNI

If Buildah is installed via a package manager such as yum, dnf or apt-get, a package containing CNI plugins may be available (in Fedora, the package is named containernetworking-cni). If not, they will need to be installed, for example using:

git clone https://github.com/containernetworking/plugins
( cd ./plugins; ./build_linux.sh )
sudo mkdir -p /opt/cni/bin
sudo install -v ./plugins/bin/* /opt/cni/bin

The CNI library needs to be configured so that it will know which plugins to call to set up namespaces. Usually, this configuration takes the form of one or more configuration files in the /etc/cni/net.d directory. A set of example configuration files is included in the docs/cni-examples directory of this source tree.

Installation

Caution

If you already have something wrong with apt update, please check the following ๐Ÿ”—link, adding docker source won’t help solve that problem.

sudo dnf update -y 
sudo dnf -y install buildah

Once the installation is complete, The buildah images command will list all the images:

buildah images
sudo yum -y install buildah

Once the installation is complete, start the Docker service

sudo systemctl enable docker
sudo systemctl start docker
  1. Set up Docker’s apt repository.
sudo apt-get -y update
sudo apt-get -y install buildah
  1. Verify that the installation is successful by running the hello-world image:
sudo buildah run hello-world

Info

  • Docker Image saved in /var/lib/docker

Mirror

You can modify /etc/docker/daemon.json

{
  "registry-mirrors": ["<$mirror_url>"]
}

for example:

  • https://docker.mirrors.ustc.edu.cn
Mar 7, 2025

Install Docker

Mar 7, 2025

Install Podman

Reference

Installation

Caution

If you already have something wrong with apt update, please check the following ๐Ÿ”—link, adding docker source won’t help solve that problem.

sudo dnf update -y 
sudo dnf -y install podman
sudo yum install -y podman
sudo apt-get update
sudo apt-get -y install podman

Run Params

start an container

podman run [params]

-rm: delete if failed

-v: load a volume

Example

podman run --rm\
      -v /root/kserve/iris-input.json:/tmp/iris-input.json \
      --privileged \
     -e MODEL_NAME=sklearn-iris \
     -e INPUT_PATH=/tmp/iris-input.json \
     -e SERVICE_HOSTNAME=sklearn-iris.kserve-test.example.com \
      -it m.daocloud.io/docker.io/library/golang:1.22  sh -c "command A; command B; exec bash"
Mar 7, 2025

Subsections of Database

Datahub

Preliminary

  • Kubernetes is installed; if not, check ๐Ÿ”—link
  • ArgoCD is installed; if not, check ๐Ÿ”—link
  • Elasticsearch is installed; if not, check ๐Ÿ”—link
  • MariaDB is installed; if not, check ๐Ÿ”—link
  • Kafka is installed; if not, check ๐Ÿ”—link

Steps

1. prepare datahub credentials secret

kubectl -n application \
    create secret generic datahub-credentials \
    --from-literal=mysql-root-password="$(kubectl get secret mariadb-credentials --namespace database -o jsonpath='{.data.mariadb-root-password}' | base64 -d)"
kubectl -n application \
    create secret generic datahub-credentials \
    --from-literal=mysql-root-password="$(kubectl get secret mariadb-credentials --namespace database -o jsonpath='{.data.mariadb-root-password}' | base64 -d)" \
    --from-literal=security.protocol="SASL_PLAINTEXT" \
    --from-literal=sasl.mechanism="SCRAM-SHA-256" \
    --from-literal=sasl.jaas.config="org.apache.kafka.common.security.scram.ScramLoginModule required username=\"user1\" password=\"$(kubectl get secret kafka-user-passwords --namespace database -o jsonpath='{.data.client-passwords}' | base64 -d | cut -d , -f 1)\";"

5. prepare deploy-datahub.yaml

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: datahub
spec:
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
  project: default
  source:
    repoURL: https://helm.datahubproject.io
    chart: datahub
    targetRevision: 0.4.8
    helm:
      releaseName: datahub
      values: |
        global:
          elasticsearch:
            host: elastic-search-elasticsearch.application.svc.cluster.local
            port: 9200
            skipcheck: "false"
            insecure: "false"
            useSSL: "false"
          kafka:
            bootstrap:
              server: kafka.database.svc.cluster.local:9092
            zookeeper:
              server: kafka-zookeeper.database.svc.cluster.local:2181
          sql:
            datasource:
              host: mariadb.database.svc.cluster.local:3306
              hostForMysqlClient: mariadb.database.svc.cluster.local
              port: 3306
              url: jdbc:mysql://mariadb.database.svc.cluster.local:3306/datahub?verifyServerCertificate=false&useSSL=true&useUnicode=yes&characterEncoding=UTF-8&enabledTLSProtocols=TLSv1.2
              driver: com.mysql.cj.jdbc.Driver
              username: root
              password:
                secretRef: datahub-credentials
                secretKey: mysql-root-password
        datahub-gms:
          enabled: true
          replicaCount: 1
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-gms
          service:
            type: ClusterIP
          ingress:
            enabled: false
        datahub-frontend:
          enabled: true
          replicaCount: 1
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-frontend-react
          defaultUserCredentials:
            randomAdminPassword: true
          service:
            type: ClusterIP
          ingress:
            enabled: true
            className: nginx
            annotations:
              cert-manager.io/cluster-issuer: self-signed-ca-issuer
            hosts:
            - host: datahub.dev.72602.online
              paths:
              - /
            tls:
            - secretName: "datahub.dev.72602.online-tls"
              hosts:
              - datahub.dev.72602.online
        acryl-datahub-actions:
          enabled: true
          replicaCount: 1
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-actions
        datahub-mae-consumer:
          replicaCount: 1
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-mae-consumer
          ingress:
            enabled: false
        datahub-mce-consumer:
          replicaCount: 1
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-mce-consumer
          ingress:
            enabled: false
        datahub-ingestion-cron:
          enabled: false
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-ingestion
        elasticsearchSetupJob:
          enabled: true
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-elasticsearch-setup
        kafkaSetupJob:
          enabled: true
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-kafka-setup
        mysqlSetupJob:
          enabled: true
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-mysql-setup
        postgresqlSetupJob:
          enabled: false
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-postgres-setup
        datahubUpgrade:
          enabled: true
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-upgrade
        datahubSystemUpdate:
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-upgrade
  destination:
    server: https://kubernetes.default.svc
    namespace: application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: datahub
spec:
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
  project: default
  source:
    repoURL: https://helm.datahubproject.io
    chart: datahub
    targetRevision: 0.4.8
    helm:
      releaseName: datahub
      values: |
        global:
          springKafkaConfigurationOverrides:
            security.protocol: SASL_PLAINTEXT
            sasl.mechanism: SCRAM-SHA-256
          credentialsAndCertsSecrets:
            name: datahub-credentials
            secureEnv:
              sasl.jaas.config: sasl.jaas.config
          elasticsearch:
            host: elastic-search-elasticsearch.application.svc.cluster.local
            port: 9200
            skipcheck: "false"
            insecure: "false"
            useSSL: "false"
          kafka:
            bootstrap:
              server: kafka.database.svc.cluster.local:9092
            zookeeper:
              server: kafka-zookeeper.database.svc.cluster.local:2181
          neo4j:
            host: neo4j.database.svc.cluster.local:7474
            uri: bolt://neo4j.database.svc.cluster.local
            username: neo4j
            password:
              secretRef: datahub-credentials
              secretKey: neo4j-password
          sql:
            datasource:
              host: mariadb.database.svc.cluster.local:3306
              hostForMysqlClient: mariadb.database.svc.cluster.local
              port: 3306
              url: jdbc:mysql://mariadb.database.svc.cluster.local:3306/datahub?verifyServerCertificate=false&useSSL=true&useUnicode=yes&characterEncoding=UTF-8&enabledTLSProtocols=TLSv1.2
              driver: com.mysql.cj.jdbc.Driver
              username: root
              password:
                secretRef: datahub-credentials
                secretKey: mysql-root-password
        datahub-gms:
          enabled: true
          replicaCount: 1
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-gms
          service:
            type: ClusterIP
          ingress:
            enabled: false
        datahub-frontend:
          enabled: true
          replicaCount: 1
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-frontend-react
          defaultUserCredentials:
            randomAdminPassword: true
          service:
            type: ClusterIP
          ingress:
            enabled: true
            className: nginx
            annotations:
              cert-manager.io/cluster-issuer: self-signed-ca-issuer
            hosts:
            - host: datahub.dev.72602.online
              paths:
              - /
            tls:
            - secretName: "datahub.dev.72602.online-tls"
              hosts:
              - datahub.dev.72602.online
        acryl-datahub-actions:
          enabled: true
          replicaCount: 1
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-actions
        datahub-mae-consumer:
          replicaCount: 1
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-mae-consumer
          ingress:
            enabled: false
        datahub-mce-consumer:
          replicaCount: 1
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-mce-consumer
          ingress:
            enabled: false
        datahub-ingestion-cron:
          enabled: false
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-ingestion
        elasticsearchSetupJob:
          enabled: true
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-elasticsearch-setup
        kafkaSetupJob:
          enabled: true
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-kafka-setup
        mysqlSetupJob:
          enabled: true
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-mysql-setup
        postgresqlSetupJob:
          enabled: false
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-postgres-setup
        datahubUpgrade:
          enabled: true
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-upgrade
        datahubSystemUpdate:
          image:
            repository: m.daocloud.io/docker.io/acryldata/datahub-upgrade
  destination:
    server: https://kubernetes.default.svc
    namespace: application
if you wannna start one more gms

add this under global, if you wanna start one more gms

  datahub_standalone_consumers_enabled: true

3. apply to k8s

kubectl -n argocd apply -f deploy-datahub.yaml

4. sync by argocd

argocd app sync argocd/datahub

5. extract credentials

kubectl -n application get secret datahub-user-secret -o jsonpath='{.data.user\.props}' | base64 -d

[Optional] Visit through browser

After DNS or hosts mapping is configured, open the URLs below to verify UI and API reachability.

add $K8S_MASTER_IP datahub.dev.72602.online to /etc/hosts

[Optional] Visit through DatahubCLI

Use DatahubCLI for metadata ingestion and management from scripts or CI pipelines.

We recommend Python virtual environments (venv-s) to namespace pip modules. Here’s an example setup:

python3 -m venv venv             # create the environment
source venv/bin/activate         # activate the environment

NOTE: If you install datahub in a virtual environment, that same virtual environment must be re-activated each time a shell window or session is created.

Once inside the virtual environment, install datahub using the following commands

# Requires Python 3.8+
python3 -m pip install --upgrade pip wheel setuptools
python3 -m pip install --upgrade acryl-datahub
# validate that the install was successful
datahub version
# If you see "command not found", try running this instead: python3 -m datahub version
datahub init
# authenticate your datahub CLI with your datahub instance
Mar 7, 2024

Install Clickhouse

Installation

Install By

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. ArgoCD is installed; if not, check ๐Ÿ”—link


3. cert-manager has installed on argocd and the clusterissuer has a named `self-signed-ca-issuer`service, , if not check ๐Ÿ”—link


1.prepare admin credentials secret

Details
kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database
kubectl -n database create secret generic clickhouse-admin-credentials \
    --from-literal=password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

2.prepare `deploy-clickhouse.yaml`

Details
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: clickhouse
spec:
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
  project: default
  source:
    repoURL: https://charts.bitnami.com/bitnami
    chart: clickhouse
    targetRevision: 4.5.1
    helm:
      releaseName: clickhouse
      values: |
        serviceAccount:
          name: clickhouse
        image:
          registry: m.daocloud.io/docker.io
          pullPolicy: IfNotPresent
        volumePermissions:
          enabled: false
          image:
            registry: m.daocloud.io/docker.io
            pullPolicy: IfNotPresent
        zookeeper:
          enabled: true
          image:
            registry: m.daocloud.io/docker.io
            pullPolicy: IfNotPresent
          replicaCount: 3
          persistence:
            enabled: true
            storageClass: nfs-external
            size: 8Gi
          volumePermissions:
            enabled: false
            image:
              registry: m.daocloud.io/docker.io
              pullPolicy: IfNotPresent
        shards: 2
        replicaCount: 3
        ingress:
          enabled: true
          annotations:
            cert-manager.io/cluster-issuer: self-signed-ca-issuer
            nginx.ingress.kubernetes.io/rewrite-target: /$1
          hostname: clickhouse.dev.72602.online
          ingressClassName: nginx
          path: /?(.*)
          tls: true
        persistence:
          enabled: false
        resources:
          requests:
            cpu: 2
            memory: 512Mi
          limits:
            cpu: 3
            memory: 1024Mi
        auth:
          username: admin
          existingSecret: clickhouse-admin-credentials
          existingSecretKey: password
        metrics:
          enabled: true
          image:
            registry: m.daocloud.io/docker.io
            pullPolicy: IfNotPresent
          serviceMonitor:
            enabled: true
            namespace: monitor
            jobLabel: clickhouse
            selector:
              app.kubernetes.io/name: clickhouse
              app.kubernetes.io/instance: clickhouse
            labels:
              release: prometheus-stack
        extraDeploy:
          - |
            apiVersion: apps/v1
            kind: Deployment
            metadata:
              name: clickhouse-tool
              namespace: database
              labels:
                app.kubernetes.io/name: clickhouse-tool
            spec:
              replicas: 1
              selector:
                matchLabels:
                  app.kubernetes.io/name: clickhouse-tool
              template:
                metadata:
                  labels:
                    app.kubernetes.io/name: clickhouse-tool
                spec:
                  containers:
                    - name: clickhouse-tool
                      image: m.daocloud.io/docker.io/clickhouse/clickhouse-server:23.11.5.29-alpine
                      imagePullPolicy: IfNotPresent
                      env:
                        - name: CLICKHOUSE_USER
                          value: admin
                        - name: CLICKHOUSE_PASSWORD
                          valueFrom:
                            secretKeyRef:
                              key: password
                              name: clickhouse-admin-credentials
                        - name: CLICKHOUSE_HOST
                          value: csst-clickhouse.csst
                        - name: CLICKHOUSE_PORT
                          value: "9000"
                        - name: TZ
                          value: Asia/Shanghai
                      command:
                        - tail
                      args:
                        - -f
                        - /etc/hosts
  destination:
    server: https://kubernetes.default.svc
    namespace: database

3.deploy clickhouse

Details
kubectl -n argocd apply -f deploy-clickhouse.yaml

4.sync by argocd

Details
argocd app sync argocd/clickhouse

5.prepare `clickhouse-interface.yaml`

Details
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/component: clickhouse
    app.kubernetes.io/instance: clickhouse
  name: clickhouse-interface
spec:
  ports:
  - name: http
    port: 8123
    protocol: TCP
    targetPort: http
    nodePort: 31567
  - name: tcp
    port: 9000
    protocol: TCP
    targetPort: tcp
    nodePort: 32005
  selector:
    app.kubernetes.io/component: clickhouse
    app.kubernetes.io/instance: clickhouse
    app.kubernetes.io/name: clickhouse
  type: NodePort

6.apply to k8s

Details
kubectl -n database apply -f clickhouse-interface.yaml

7.extract clickhouse admin credentials

Details
kubectl -n database get secret clickhouse-admin-credentials -o jsonpath='{.data.password}' | base64 -d

8.invoke http api

Details
add `$K8S_MASTER_IP clickhouse.dev.72602.online` to **/etc/hosts**
CK_PASS=$(kubectl -n database get secret clickhouse-admin-credentials -o jsonpath='{.data.password}' | base64 -d)
echo 'SELECT version()' | curl -k "https://admin:${CK_PASS}@clickhouse.dev.72602.online:32443/" --data-binary @-

Preliminary

1. Docker is installed; if not, check ๐Ÿ”—link


Using Proxy

you can run an addinational daocloud image to accelerate your pulling, check Daocloud Proxy

1.init server

Details
mkdir -p clickhouse/{data,logs}
podman run --rm \
    --ulimit nofile=262144:262144 \
    --name clickhouse-server \
    -p 18123:8123 \
    -p 19000:9000 \
    -v $(pwd)/clickhouse/data:/var/lib/clickhouse \
    -v $(pwd)/clickhouse/logs:/var/log/clickhouse-server \
    -e CLICKHOUSE_DB=my_database \
    -e CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT=1 \
    -e CLICKHOUSE_USER=ayayay \
    -e CLICKHOUSE_PASSWORD=123456 \
    -d m.daocloud.io/docker.io/clickhouse/clickhouse-server:23.11.5.29-alpine

2.check dashboard

And then you can visit ๐Ÿ”—http://localhost:18123

3.use cli api

And then you can visit ๐Ÿ”—http://localhost:19000
Details
podman run --rm \
  --entrypoint clickhouse-client \
  -it m.daocloud.io/docker.io/clickhouse/clickhouse-server:23.11.5.29-alpine \
  --host host.containers.internal \
  --port 19000 \
  --user ayayay \
  --password 123456 \
  --query "select version()"

4.use visual client

Details
podman run --rm -p 8080:80 -d m.daocloud.io/docker.io/spoonest/clickhouse-tabix-web-client:stable

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. ArgoCD is installed; if not, check ๐Ÿ”—link


3. Argo Workflow is installed; if not, check ๐Ÿ”—link


1.prepare `argocd-login-credentials`

Details
kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database
kubectl -n database create secret generic mariadb-credentials \
    --from-literal=mariadb-root-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16) \
    --from-literal=mariadb-replication-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16) \
    --from-literal=mariadb-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

2.apply rolebinding to k8s

Details
kubectl apply -f - <<EOF
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: application-administrator
rules:
  - apiGroups:
      - argoproj.io
    resources:
      - applications
    verbs:
      - '*'
  - apiGroups:
      - apps
    resources:
      - deployments
    verbs:
      - '*'

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: application-administration
  namespace: argocd
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: application-administrator
subjects:
  - kind: ServiceAccount
    name: argo-workflow
    namespace: business-workflows

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: application-administration
  namespace: application
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: application-administrator
subjects:
  - kind: ServiceAccount
    name: argo-workflow
    namespace: business-workflows
EOF

4.prepare clickhouse admin credentials secret

Details
kubectl get namespace application > /dev/null 2>&1 || kubectl create namespace application
kubectl -n application create secret generic clickhouse-admin-credentials \
  --from-literal=password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

5.prepare deploy-clickhouse-flow.yaml

Details
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: deploy-argocd-app-ck-
spec:
  entrypoint: entry
  artifactRepositoryRef:
    configmap: artifact-repositories
    key: default-artifact-repository
  serviceAccountName: argo-workflow
  templates:
  - name: entry
    inputs:
      parameters:
      - name: argocd-server
        value: argo-cd-argocd-server.argocd:443
      - name: insecure-option
        value: --insecure
    dag:
      tasks:
      - name: apply
        template: apply
      - name: prepare-argocd-binary
        template: prepare-argocd-binary
        dependencies:
        - apply
      - name: sync
        dependencies:
        - prepare-argocd-binary
        template: sync
        arguments:
          artifacts:
          - name: argocd-binary
            from: "{{tasks.prepare-argocd-binary.outputs.artifacts.argocd-binary}}"
          parameters:
          - name: argocd-server
            value: "{{inputs.parameters.argocd-server}}"
          - name: insecure-option
            value: "{{inputs.parameters.insecure-option}}"
      - name: wait
        dependencies:
        - sync
        template: wait
        arguments:
          artifacts:
          - name: argocd-binary
            from: "{{tasks.prepare-argocd-binary.outputs.artifacts.argocd-binary}}"
          parameters:
          - name: argocd-server
            value: "{{inputs.parameters.argocd-server}}"
          - name: insecure-option
            value: "{{inputs.parameters.insecure-option}}"
  - name: apply
    resource:
      action: apply
      manifest: |
        apiVersion: argoproj.io/v1alpha1
        kind: Application
        metadata:
          name: app-clickhouse
          namespace: argocd
        spec:
          syncPolicy:
            syncOptions:
            - CreateNamespace=true
          project: default
          source:
            repoURL: https://charts.bitnami.com/bitnami
            chart: clickhouse
            targetRevision: 4.5.3
            helm:
              releaseName: app-clickhouse
              values: |
                image:
                  registry: docker.io
                  repository: bitnami/clickhouse
                  tag: 23.12.3-debian-11-r0
                  pullPolicy: IfNotPresent
                service:
                  type: ClusterIP
                volumePermissions:
                  enabled: false
                  image:
                    registry: m.daocloud.io/docker.io
                    pullPolicy: IfNotPresent
                ingress:
                  enabled: true
                  ingressClassName: nginx
                  annotations:
                    cert-manager.io/cluster-issuer: self-signed-ca-issuer
                    nginx.ingress.kubernetes.io/rewrite-target: /$1
                  path: /?(.*)
                  hostname: clickhouse.dev.72602.online
                  tls: true
                shards: 2
                replicaCount: 3
                persistence:
                  enabled: false
                auth:
                  username: admin
                  existingSecret: clickhouse-admin-credentials
                  existingSecretKey: password
                zookeeper:
                  enabled: true
                  image:
                    registry: m.daocloud.io/docker.io
                    repository: bitnami/zookeeper
                    tag: 3.8.3-debian-11-r8
                    pullPolicy: IfNotPresent
                  replicaCount: 3
                  persistence:
                    enabled: false
                  volumePermissions:
                    enabled: false
                    image:
                      registry: m.daocloud.io/docker.io
                      pullPolicy: IfNotPresent
          destination:
            server: https://kubernetes.default.svc
            namespace: application
  - name: prepare-argocd-binary
    inputs:
      artifacts:
      - name: argocd-binary
        path: /tmp/argocd
        mode: 755
        http:
          url: https://files.m.daocloud.io/github.com/argoproj/argo-cd/releases/download/v2.9.3/argocd-linux-amd64
    outputs:
      artifacts:
      - name: argocd-binary
        path: "{{inputs.artifacts.argocd-binary.path}}"
    container:
      image: m.daocloud.io/docker.io/library/fedora:39
      command:
      - sh
      - -c
      args:
      - |
        ls -l {{inputs.artifacts.argocd-binary.path}}
  - name: sync
    inputs:
      artifacts:
      - name: argocd-binary
        path: /usr/local/bin/argocd
      parameters:
      - name: argocd-server
      - name: insecure-option
        value: ""
    container:
      image: m.daocloud.io/docker.io/library/fedora:39
      env:
      - name: ARGOCD_USERNAME
        valueFrom:
          secretKeyRef:
            name: argocd-login-credentials
            key: username
      - name: ARGOCD_PASSWORD
        valueFrom:
          secretKeyRef:
            name: argocd-login-credentials
            key: password
      - name: WITH_PRUNE_OPTION
        value: --prune
      command:
      - sh
      - -c
      args:
      - |
        set -e
        export ARGOCD_SERVER={{inputs.parameters.argocd-server}}
        export INSECURE_OPTION={{inputs.parameters.insecure-option}}
        export ARGOCD_USERNAME=${ARGOCD_USERNAME:-admin}
        argocd login ${INSECURE_OPTION} --username ${ARGOCD_USERNAME} --password ${ARGOCD_PASSWORD} ${ARGOCD_SERVER}
        argocd app sync argocd/app-clickhouse ${WITH_PRUNE_OPTION} --timeout 300
  - name: wait
    inputs:
      artifacts:
      - name: argocd-binary
        path: /usr/local/bin/argocd
      parameters:
      - name: argocd-server
      - name: insecure-option
        value: ""
    container:
      image: m.daocloud.io/docker.io/library/fedora:39
      env:
      - name: ARGOCD_USERNAME
        valueFrom:
          secretKeyRef:
            name: argocd-login-credentials
            key: username
      - name: ARGOCD_PASSWORD
        valueFrom:
          secretKeyRef:
            name: argocd-login-credentials
            key: password
      command:
      - sh
      - -c
      args:
      - |
        set -e
        export ARGOCD_SERVER={{inputs.parameters.argocd-server}}
        export INSECURE_OPTION={{inputs.parameters.insecure-option}}
        export ARGOCD_USERNAME=${ARGOCD_USERNAME:-admin}
        argocd login ${INSECURE_OPTION} --username ${ARGOCD_USERNAME} --password ${ARGOCD_PASSWORD} ${ARGOCD_SERVER}
        argocd app wait argocd/app-clickhouse

6.submit to argo workflow client

Details
argo -n business-workflows submit deploy-clickhouse-flow.yaml

7.extract clickhouse admin credentials

Details
kubectl -n application get secret clickhouse-admin-credentials -o jsonpath='{.data.password}' | base64 -d

8.invoke http api

Details
add `$K8S_MASTER_IP clickhouse.dev.72602.online` to **/etc/hosts**
CK_PASSWORD=$(kubectl -n application get secret clickhouse-admin-credentials -o jsonpath='{.data.password}' | base64 -d) && echo 'SELECT version()' | curl -k "https://admin:${CK_PASSWORD}@clickhouse.dev.72602.online/" --data-binary @-

9.create external interface

Details
kubectl -n application apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/component: clickhouse
    app.kubernetes.io/instance: app-clickhouse
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: clickhouse
    app.kubernetes.io/version: 23.12.2
    argocd.argoproj.io/instance: app-clickhouse
    helm.sh/chart: clickhouse-4.5.3
  name: app-clickhouse-service-external
spec:
  ports:
  - name: tcp
    port: 9000
    protocol: TCP
    targetPort: tcp
    nodePort: 30900
  selector:
    app.kubernetes.io/component: clickhouse
    app.kubernetes.io/instance: app-clickhouse
    app.kubernetes.io/name: clickhouse
  type: NodePort
EOF

FAQ

Q1: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Q2: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Mar 7, 2024

Install ElasticSearch

Installation

Install By

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


1.get helm repo

Details
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update

2.install chart

Details
kubectl get namespaces application > /dev/null 2>&1 || kubectl create namespace application

helm upgrade --install elastic-search bitnami/elasticsearch \
  --namespace application \
  --version 19.11.3 \
  --set global.kibanaEnabled=true \
  --set security.enabled=false \
  --set master.masterOnly=false \
  --set master.replicaCount=1 \
  --set master.persistence.enabled=false \
  --set data.replicaCount=0 \
  --set data.persistence.enabled=false \
  --set coordinating.replicaCount=0 \
  --set ingest.replicaCount=0

3.verify deployment

Details
kubectl -n application get pods
kubectl -n application get svc
Chart Reference

for more information, you can check ๐Ÿ”—https://artifacthub.io/packages/helm/bitnami/elasticsearch

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


1.prepare `deploy-elasticsearch.yaml`

Details
kubectl apply -f - << EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: elastic-search
spec:
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
  project: default
  source:
    repoURL: https://charts.bitnami.com/bitnami
    chart: elasticsearch
    targetRevision: 19.11.3
    helm:
      releaseName: elastic-search
      values: |
        global:
          kibanaEnabled: true
        clusterName: elastic
        image:
          registry: m.zjvis.net/docker.io
          pullPolicy: IfNotPresent
        security:
          enabled: false
        service:
          type: ClusterIP
        ingress:
          enabled: true
          annotations:
            cert-manager.io/cluster-issuer: self-signed-ca-issuer
            nginx.ingress.kubernetes.io/rewrite-target: /$1
          hostname: elastic-search.dev.72602.online
          ingressClassName: nginx
          path: /?(.*)
          tls: true
        master:
          masterOnly: false
          replicaCount: 1
          persistence:
            enabled: false
          resources:
            requests:
              cpu: 2
              memory: 1024Mi
            limits:
              cpu: 4
              memory: 4096Mi
          heapSize: 2g
        data:
          replicaCount: 0
          persistence:
            enabled: false
        coordinating:
          replicaCount: 0
        ingest:
          enabled: true
          replicaCount: 0
          service:
            enabled: false
            type: ClusterIP
          ingress:
            enabled: false
        metrics:
          enabled: false
          image:
            registry: m.zjvis.net/docker.io
            pullPolicy: IfNotPresent
        volumePermissions:
          enabled: false
          image:
            registry: m.zjvis.net/docker.io
            pullPolicy: IfNotPresent
        sysctlImage:
          enabled: true
          registry: m.zjvis.net/docker.io
          pullPolicy: IfNotPresent
        kibana:
          elasticsearch:
            hosts:
              - '{{ include "elasticsearch.service.name" . }}'
            port: '{{ include "elasticsearch.service.ports.restAPI" . }}'
        esJavaOpts: "-Xmx2g -Xms2g"        
  destination:
    server: https://kubernetes.default.svc
    namespace: application
EOF

3.sync by argocd

Details
argocd app sync argocd/elastic-search

4.extract elasticsearch admin credentials

Details
kubectl -n application get secret elastic-search-elasticsearch -o jsonpath='{.data.elastic-password}' | base64 -d

5.invoke http api

Details
add `$K8S_MASTER_IP elastic-search.dev.72602.online` to `/etc/hosts`
curl -k -H "Content-Type: application/json" \
    -X POST "https://elastic-search.dev.72602.online:32443/books/_doc?pretty" \
    -d '{"name": "Snow Crash", "author": "Neal Stephenson", "release_date": "1992-06-01", "page_count": 470}'

Preliminary

1. Docker|Podman|Buildah is installed; if not, check ๐Ÿ”—link


Using Mirror

you can run an addinational daocloud image to accelerate your pulling, check Daocloud Proxy

1.init server

Details

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


4. Argo Workflow is installed; if not, check ๐Ÿ”—link


1.prepare `argocd-login-credentials`

Details
kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database

2.apply rolebinding to k8s

Details
kubectl apply -f - <<EOF
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: application-administrator
rules:
  - apiGroups:
      - argoproj.io
    resources:
      - applications
    verbs:
      - '*'
  - apiGroups:
      - apps
    resources:
      - deployments
    verbs:
      - '*'

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: application-administration
  namespace: argocd
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: application-administrator
subjects:
  - kind: ServiceAccount
    name: argo-workflow
    namespace: business-workflows

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: application-administration
  namespace: application
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: application-administrator
subjects:
  - kind: ServiceAccount
    name: argo-workflow
    namespace: business-workflows
EOF

4.prepare `deploy-xxxx-flow.yaml`

Details

6.submit to argo workflow client

Details
argo -n business-workflows submit deploy-xxxx-flow.yaml

7.decode password

Details
kubectl -n application get secret xxxx-credentials -o jsonpath='{.data.xxx-password}' | base64 -d

FAQ

Q1: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Q2: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Apr 12, 2024

Install Kafka

Installation

Install By

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm binary is installed; if not, check ๐Ÿ”—link


1.get helm repo

Details
helm repo add bitnami oci://registry-1.docker.io/bitnamicharts/kafka
helm repo update

2.install chart

helm upgrade --create-namespace -n database kafka --install bitnami/kafka \
  --set global.imageRegistry=m.daocloud.io/docker.io \
  --set zookeeper.enabled=false \
  --set controller.replicaCount=1 \
  --set broker.replicaCount=1 \
  --set persistance.enabled=false  \
  --version 28.0.3
helm upgrade --create-namespace -n database kafka --install bitnami/kafka \
  --set global.imageRegistry=m.daocloud.io/docker.io \
  --set zookeeper.enabled=false \
  --set controller.replicaCount=1 \
  --set broker.replicaCount=1 \
  --set persistance.enabled=false  \
  --version 28.0.3
Details
kubectl -n database \
  create secret generic client-properties \
  --from-literal=client.properties="$(printf "security.protocol=SASL_PLAINTEXT\nsasl.mechanism=SCRAM-SHA-256\nsasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required username=\"user1\" password=\"$(kubectl get secret kafka-user-passwords --namespace database -o jsonpath='{.data.client-passwords}' | base64 -d | cut -d , -f 1)\";\n")"
Details
kubectl -n database apply -f - << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kafka-client-tools
  labels:
    app: kafka-client-tools
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kafka-client-tools
  template:
    metadata:
      labels:
        app: kafka-client-tools
    spec:
      volumes:
      - name: client-properties
        secret:
          secretName: client-properties
      containers:
      - name: kafka-client-tools
        image: m.daocloud.io/docker.io/bitnami/kafka:3.6.2
        volumeMounts:
        - name: client-properties
          mountPath: /bitnami/custom/client.properties
          subPath: client.properties
          readOnly: true
        env:
        - name: BOOTSTRAP_SERVER
          value: kafka.database.svc.cluster.local:9092
        - name: CLIENT_CONFIG_FILE
          value: /bitnami/custom/client.properties
        command:
        - tail
        - -f
        - /etc/hosts
        imagePullPolicy: IfNotPresent
EOF

3.validate function

- list topics
Details
kubectl -n database exec -it deployment/kafka-client-tools -- bash -c \
    'kafka-topics.sh --bootstrap-server $BOOTSTRAP_SERVER --command-config $CLIENT_CONFIG_FILE --list'
- create topic
Details
kubectl -n database exec -it deployment/kafka-client-tools -- bash -c \
  'kafka-topics.sh --bootstrap-server $BOOTSTRAP_SERVER --command-config $CLIENT_CONFIG_FILE --create --if-not-exists --topic test-topic'
- describe topic
Details
kubectl -n database exec -it deployment/kafka-client-tools -- bash -c \
  'kafka-topics.sh --bootstrap-server $BOOTSTRAP_SERVER --command-config $CLIENT_CONFIG_FILE --describe --topic test-topic'
- produce message
Details
kubectl -n database exec -it deployment/kafka-client-tools -- bash -c \
  'for message in $(seq 0 10); do echo $message | kafka-console-producer.sh --bootstrap-server $BOOTSTRAP_SERVER --producer.config $CLIENT_CONFIG_FILE --topic test-topic; done'
- consume message
Details
kubectl -n database exec -it deployment/kafka-client-tools -- bash -c \
  'kafka-console-consumer.sh --bootstrap-server $BOOTSTRAP_SERVER --consumer.config $CLIENT_CONFIG_FILE --topic test-topic --from-beginning'

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. ArgoCD is installed; if not, check ๐Ÿ”—link


3. Helm binary is installed; if not, check ๐Ÿ”—link


1.prepare `deploy-kafka.yaml`

kubectl -n argocd apply -f - << EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: kafka
spec:
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
  project: default
  source:
    repoURL: https://charts.bitnami.com/bitnami
    chart: kafka
    targetRevision: 28.0.3
    helm:
      releaseName: kafka
      values: |
        image:
          registry: m.daocloud.io/docker.io
        controller:
          replicaCount: 1
          persistence:
            enabled: false
          logPersistence:
            enabled: false
          extraConfig: |
            message.max.bytes=5242880
            default.replication.factor=1
            offsets.topic.replication.factor=1
            transaction.state.log.replication.factor=1
        broker:
          replicaCount: 1
          persistence:
            enabled: false
          logPersistence:
            enabled: false
          extraConfig: |
            message.max.bytes=5242880
            default.replication.factor=1
            offsets.topic.replication.factor=1
            transaction.state.log.replication.factor=1
        externalAccess:
          enabled: false
          autoDiscovery:
            enabled: false
            image:
              registry: m.daocloud.io/docker.io
        volumePermissions:
          enabled: false
          image:
            registry: m.daocloud.io/docker.io
        metrics:
          kafka:
            enabled: false
            image:
              registry: m.daocloud.io/docker.io
          jmx:
            enabled: false
            image:
              registry: m.daocloud.io/docker.io
        provisioning:
          enabled: false
        kraft:
          enabled: true
        zookeeper:
          enabled: false
  destination:
    server: https://kubernetes.default.svc
    namespace: database
EOF
kubectl -n argocd apply -f - << EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: kafka
spec:
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
  project: default
  source:
    repoURL: https://charts.bitnami.com/bitnami
    chart: kafka
    targetRevision: 28.0.3
    helm:
      releaseName: kafka
      values: |
        image:
          registry: m.daocloud.io/docker.io
        listeners:
          client:
            protocol: PLAINTEXT
          interbroker:
            protocol: PLAINTEXT
        controller:
          replicaCount: 0
          persistence:
            enabled: false
          logPersistence:
            enabled: false
          extraConfig: |
            message.max.bytes=5242880
            default.replication.factor=1
            offsets.topic.replication.factor=1
            transaction.state.log.replication.factor=1
        broker:
          replicaCount: 1
          minId: 0
          persistence:
            enabled: false
          logPersistence:
            enabled: false
          extraConfig: |
            message.max.bytes=5242880
            default.replication.factor=1
            offsets.topic.replication.factor=1
            transaction.state.log.replication.factor=1
        externalAccess:
          enabled: false
          autoDiscovery:
            enabled: false
            image:
              registry: m.daocloud.io/docker.io
        volumePermissions:
          enabled: false
          image:
            registry: m.daocloud.io/docker.io
        metrics:
          kafka:
            enabled: false
            image:
              registry: m.daocloud.io/docker.io
          jmx:
            enabled: false
            image:
              registry: m.daocloud.io/docker.io
        provisioning:
          enabled: false
        kraft:
          enabled: false
        zookeeper:
          enabled: true
          image:
            registry: m.daocloud.io/docker.io
          replicaCount: 1
          auth:
            client:
              enabled: false
            quorum:
              enabled: false
          persistence:
            enabled: false
          volumePermissions:
            enabled: false
            image:
              registry: m.daocloud.io/docker.io
            metrics:
              enabled: false
          tls:
            client:
              enabled: false
            quorum:
              enabled: false
  destination:
    server: https://kubernetes.default.svc
    namespace: database
EOF

2.sync by argocd

Details
argocd app sync argocd/kafka

3.set up client tool

kubectl -n database \
    create secret generic client-properties \
    --from-literal=client.properties="$(printf "security.protocol=SASL_PLAINTEXT\nsasl.mechanism=SCRAM-SHA-256\nsasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required username=\"user1\" password=\"$(kubectl get secret kafka-user-passwords --namespace database -o jsonpath='{.data.client-passwords}' | base64 -d | cut -d , -f 1)\";\n")"
kubectl -n database \
    create secret generic client-properties \
    --from-literal=client.properties="security.protocol=PLAINTEXT"

5.prepare `kafka-client-tools.yaml`

Details
kubectl -n database apply -f - << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kafka-client-tools
  labels:
    app: kafka-client-tools
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kafka-client-tools
  template:
    metadata:
      labels:
        app: kafka-client-tools
    spec:
      volumes:
      - name: client-properties
        secret:
          secretName: client-properties
      containers:
      - name: kafka-client-tools
        image: m.daocloud.io/docker.io/bitnami/kafka:3.6.2
        volumeMounts:
        - name: client-properties
          mountPath: /bitnami/custom/client.properties
          subPath: client.properties
          readOnly: true
        env:
        - name: BOOTSTRAP_SERVER
          value: kafka.database.svc.cluster.local:9092
        - name: CLIENT_CONFIG_FILE
          value: /bitnami/custom/client.properties
        - name: ZOOKEEPER_CONNECT
          value: kafka-zookeeper.database.svc.cluster.local:2181
        command:
        - tail
        - -f
        - /etc/hosts
        imagePullPolicy: IfNotPresent
EOF

6.validate function

- list topics
Details
kubectl -n database exec -it deployment/kafka-client-tools -- bash -c \
    'kafka-topics.sh --bootstrap-server $BOOTSTRAP_SERVER --command-config $CLIENT_CONFIG_FILE --list'
- create topic
Details
kubectl -n database exec -it deployment/kafka-client-tools -- bash -c \
  'kafka-topics.sh --bootstrap-server $BOOTSTRAP_SERVER --command-config $CLIENT_CONFIG_FILE --create --if-not-exists --topic test-topic'
- describe topic
Details
kubectl -n database exec -it deployment/kafka-client-tools -- bash -c \
  'kafka-topics.sh --bootstrap-server $BOOTSTRAP_SERVER --command-config $CLIENT_CONFIG_FILE --describe --topic test-topic'
- produce message
Details
kubectl -n database exec -it deployment/kafka-client-tools -- bash -c \
  'for message in $(seq 0 10); do echo $message | kafka-console-producer.sh --bootstrap-server $BOOTSTRAP_SERVER --producer.config $CLIENT_CONFIG_FILE --topic test-topic; done'
- consume message
Details
kubectl -n database exec -it deployment/kafka-client-tools -- bash -c \
  'kafka-console-consumer.sh --bootstrap-server $BOOTSTRAP_SERVER --consumer.config $CLIENT_CONFIG_FILE --topic test-topic --from-beginning'

Preliminary

1. Docker is installed; if not, check ๐Ÿ”—link


Using Proxy

you can run an addinational daocloud image to accelerate your pulling, check Daocloud Proxy

1.init server

Details
mkdir -p kafka/data
chmod -R 777 kafka/data
podman run --rm \
    --name kafka-server \
    --hostname kafka-server \
    -p 9092:9092 \
    -p 9094:9094 \
    -v $(pwd)/kafka/data:/bitnami/kafka/data \
    -e KAFKA_CFG_NODE_ID=0 \
    -e KAFKA_CFG_PROCESS_ROLES=controller,broker \
    -e KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@kafka-server:9093 \
    -e KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094 \
    -e KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,EXTERNAL://host.containers.internal:9094 \
    -e KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT \
    -e KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER \
    -d m.daocloud.io/docker.io/bitnami/kafka:3.6.2

2.list topic

Details
BOOTSTRAP_SERVER=host.containers.internal:9094
podman run --rm \
    -it m.daocloud.io/docker.io/bitnami/kafka:3.6.2 kafka-topics.sh \
        --bootstrap-server $BOOTSTRAP_SERVER --list

2.create topic

Details
BOOTSTRAP_SERVER=host.containers.internal:9094
# BOOTSTRAP_SERVER=10.200.60.64:9094
TOPIC=test-topic
podman run --rm \
    -it m.daocloud.io/docker.io/bitnami/kafka:3.6.2 kafka-topics.sh \
        --bootstrap-server $BOOTSTRAP_SERVER \
        --create \
        --if-not-exists \
        --topic $TOPIC

2.consume record

Details
BOOTSTRAP_SERVER=host.containers.internal:9094
# BOOTSTRAP_SERVER=10.200.60.64:9094
TOPIC=test-topic
podman run --rm \
    -it m.daocloud.io/docker.io/bitnami/kafka:3.6.2 kafka-console-consumer.sh \
        --bootstrap-server $BOOTSTRAP_SERVER \
        --topic $TOPIC \
        --from-beginning

FAQ

Q1: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Q2: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Mar 7, 2024

Install MariaDB

Installation

Install By

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. ArgoCD is installed; if not, check ๐Ÿ”—link


3. cert-manager has installed on argocd and the clusterissuer has a named `self-signed-ca-issuer`service, , if not check ๐Ÿ”—link


1.prepare mariadb credentials secret

Details
kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database
kubectl -n database create secret generic mariadb-credentials \
    --from-literal=mariadb-root-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16) \
    --from-literal=mariadb-replication-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16) \
    --from-literal=mariadb-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

2.prepare `deploy-mariadb.yaml`

Details
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: mariadb
spec:
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
  project: default
  source:
    repoURL: https://charts.bitnami.com/bitnami
    chart: mariadb
    targetRevision: 16.3.2
    helm:
      releaseName: mariadb
      values: |
        architecture: standalone
        auth:
          database: test-mariadb
          username: aaron.yang
          existingSecret: mariadb-credentials
        primary:
          extraFlags: "--character-set-server=utf8mb4 --collation-server=utf8mb4_bin"
          persistence:
            enabled: false
        secondary:
          replicaCount: 1
          persistence:
            enabled: false
        image:
          registry: m.daocloud.io/docker.io
          pullPolicy: IfNotPresent
        volumePermissions:
          enabled: false
          image:
            registry: m.daocloud.io/docker.io
            pullPolicy: IfNotPresent
        metrics:
          enabled: false
          image:
            registry: m.daocloud.io/docker.io
            pullPolicy: IfNotPresent
  destination:
    server: https://kubernetes.default.svc
    namespace: database

3.deploy mariadb

Details
kubectl -n argocd apply -f deploy-mariadb.yaml

4.sync by argocd

Details
argocd app sync argocd/mariadb

5.check mariadb

Details
kubectl -n database get secret mariadb-credentials -o jsonpath='{.data.mariadb-root-password}' | base64 -d

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. ArgoCD is installed; if not, check ๐Ÿ”—link


3. Argo Workflow is installed; if not, check ๐Ÿ”—link


1.prepare `argocd-login-credentials`

Details
kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database
kubectl -n database create secret generic mariadb-credentials \
    --from-literal=mariadb-root-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16) \
    --from-literal=mariadb-replication-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16) \
    --from-literal=mariadb-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

2.apply rolebinding to k8s

Details
kubectl -n argocd apply -f - <<EOF
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: application-administrator
rules:
  - apiGroups:
      - argoproj.io
    resources:
      - applications
    verbs:
      - '*'
  - apiGroups:
      - apps
    resources:
      - deployments
    verbs:
      - '*'

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: application-administration
  namespace: argocd
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: application-administrator
subjects:
  - kind: ServiceAccount
    name: argo-workflow
    namespace: business-workflows

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: application-administration
  namespace: application
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: application-administrator
subjects:
  - kind: ServiceAccount
    name: argo-workflow
    namespace: business-workflows
EOF

3.prepare mariadb credentials secret

Details
kubectl -n application create secret generic mariadb-credentials \
  --from-literal=mariadb-root-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16) \
  --from-literal=mariadb-replication-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16) \
  --from-literal=mariadb-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

4.prepare `deploy-mariadb-flow.yaml`

Details
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: deploy-argocd-app-mariadb-
spec:
  entrypoint: entry
  artifactRepositoryRef:
    configmap: artifact-repositories
    key: default-artifact-repository
  serviceAccountName: argo-workflow
  templates:
  - name: entry
    inputs:
      parameters:
      - name: argocd-server
        value: argo-cd-argocd-server.argocd:443
      - name: insecure-option
        value: --insecure
    dag:
      tasks:
      - name: apply
        template: apply
      - name: prepare-argocd-binary
        template: prepare-argocd-binary
        dependencies:
        - apply
      - name: sync
        dependencies:
        - prepare-argocd-binary
        template: sync
        arguments:
          artifacts:
          - name: argocd-binary
            from: "{{tasks.prepare-argocd-binary.outputs.artifacts.argocd-binary}}"
          parameters:
          - name: argocd-server
            value: "{{inputs.parameters.argocd-server}}"
          - name: insecure-option
            value: "{{inputs.parameters.insecure-option}}"
      - name: wait
        dependencies:
        - sync
        template: wait
        arguments:
          artifacts:
          - name: argocd-binary
            from: "{{tasks.prepare-argocd-binary.outputs.artifacts.argocd-binary}}"
          parameters:
          - name: argocd-server
            value: "{{inputs.parameters.argocd-server}}"
          - name: insecure-option
            value: "{{inputs.parameters.insecure-option}}"
      - name: init-db-tool
        template: init-db-tool
        dependencies:
        - wait
  - name: apply
    resource:
      action: apply
      manifest: |
        apiVersion: argoproj.io/v1alpha1
        kind: Application
        metadata:
          name: app-mariadb
          namespace: argocd
        spec:
          syncPolicy:
            syncOptions:
            - CreateNamespace=true
          project: default
          source:
            repoURL: https://charts.bitnami.com/bitnami
            chart: mariadb
            targetRevision: 16.5.0
            helm:
              releaseName: app-mariadb
              values: |
                architecture: standalone
                auth:
                  database: geekcity
                  username: aaron.yang
                  existingSecret: mariadb-credentials
                primary:
                  persistence:
                    enabled: false
                secondary:
                  replicaCount: 1
                  persistence:
                    enabled: false
                image:
                  registry: m.daocloud.io/docker.io
                  pullPolicy: IfNotPresent
                volumePermissions:
                  enabled: false
                  image:
                    registry: m.daocloud.io/docker.io
                    pullPolicy: IfNotPresent
                metrics:
                  enabled: false
                  image:
                    registry: m.daocloud.io/docker.io
                    pullPolicy: IfNotPresent
          destination:
            server: https://kubernetes.default.svc
            namespace: application
  - name: prepare-argocd-binary
    inputs:
      artifacts:
      - name: argocd-binary
        path: /tmp/argocd
        mode: 755
        http:
          url: https://files.m.daocloud.io/github.com/argoproj/argo-cd/releases/download/v2.9.3/argocd-linux-amd64
    outputs:
      artifacts:
      - name: argocd-binary
        path: "{{inputs.artifacts.argocd-binary.path}}"
    container:
      image: m.daocloud.io/docker.io/library/fedora:39
      command:
      - sh
      - -c
      args:
      - |
        ls -l {{inputs.artifacts.argocd-binary.path}}
  - name: sync
    inputs:
      artifacts:
      - name: argocd-binary
        path: /usr/local/bin/argocd
      parameters:
      - name: argocd-server
      - name: insecure-option
        value: ""
    container:
      image: m.daocloud.io/docker.io/library/fedora:39
      env:
      - name: ARGOCD_USERNAME
        valueFrom:
          secretKeyRef:
            name: argocd-login-credentials
            key: username
      - name: ARGOCD_PASSWORD
        valueFrom:
          secretKeyRef:
            name: argocd-login-credentials
            key: password
      - name: WITH_PRUNE_OPTION
        value: --prune
      command:
      - sh
      - -c
      args:
      - |
        set -e
        export ARGOCD_SERVER={{inputs.parameters.argocd-server}}
        export INSECURE_OPTION={{inputs.parameters.insecure-option}}
        export ARGOCD_USERNAME=${ARGOCD_USERNAME:-admin}
        argocd login ${INSECURE_OPTION} --username ${ARGOCD_USERNAME} --password ${ARGOCD_PASSWORD} ${ARGOCD_SERVER}
        argocd app sync argocd/app-mariadb ${WITH_PRUNE_OPTION} --timeout 300
  - name: wait
    inputs:
      artifacts:
      - name: argocd-binary
        path: /usr/local/bin/argocd
      parameters:
      - name: argocd-server
      - name: insecure-option
        value: ""
    container:
      image: m.daocloud.io/docker.io/library/fedora:39
      env:
      - name: ARGOCD_USERNAME
        valueFrom:
          secretKeyRef:
            name: argocd-login-credentials
            key: username
      - name: ARGOCD_PASSWORD
        valueFrom:
          secretKeyRef:
            name: argocd-login-credentials
            key: password
      command:
      - sh
      - -c
      args:
      - |
        set -e
        export ARGOCD_SERVER={{inputs.parameters.argocd-server}}
        export INSECURE_OPTION={{inputs.parameters.insecure-option}}
        export ARGOCD_USERNAME=${ARGOCD_USERNAME:-admin}
        argocd login ${INSECURE_OPTION} --username ${ARGOCD_USERNAME} --password ${ARGOCD_PASSWORD} ${ARGOCD_SERVER}
        argocd app wait argocd/app-mariadb
  - name: init-db-tool
    resource:
      action: apply
      manifest: |
        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: app-mariadb-tool
          namespace: application
          labels:
            app.kubernetes.io/name: mariadb-tool
        spec:
          replicas: 1
          selector:
            matchLabels:
              app.kubernetes.io/name: mariadb-tool
          template:
            metadata:
              labels:
                app.kubernetes.io/name: mariadb-tool
            spec:
              containers:
                - name: mariadb-tool
                  image:  m.daocloud.io/docker.io/bitnami/mariadb:10.5.12-debian-10-r0
                  imagePullPolicy: IfNotPresent
                  env:
                    - name: MARIADB_ROOT_PASSWORD
                      valueFrom:
                        secretKeyRef:
                          key: mariadb-root-password
                          name: mariadb-credentials
                    - name: TZ
                      value: Asia/Shanghai

5.submit to argo workflow client

Details
argo -n business-workflows submit deploy-mariadb-flow.yaml

6.decode password

Details
kubectl -n application get secret mariadb-credentials -o jsonpath='{.data.mariadb-root-password}' | base64 -d

Preliminary

1. Docker is installed; if not, check ๐Ÿ”—link


Using Proxy

you can run an addinational daocloud image to accelerate your pulling, check Daocloud Proxy

1.init server

Details
mkdir -p mariadb/data
podman run  \
    -p 3306:3306 \
    -e MARIADB_ROOT_PASSWORD=mysql \
    -d m.daocloud.io/docker.io/library/mariadb:11.2.2-jammy \
    --log-bin \
    --binlog-format=ROW

2.use web console

And then you can visit ๐Ÿ”—http://localhost:8080

username: `root`

password: `mysql`

Details
podman run --rm -p 8080:80 \
    -e PMA_ARBITRARY=1 \
    -d m.daocloud.io/docker.io/library/phpmyadmin:5.1.1-apache

3.use internal client

Details
podman run --rm \
    -e MYSQL_PWD=mysql \
    -it m.daocloud.io/docker.io/library/mariadb:11.2.2-jammy \
    mariadb \
    --host host.containers.internal \
    --port 3306 \
    --user root \
    --database mysql \
    --execute 'select version()'

Useful SQL

  1. list all bin logs
SHOW BINARY LOGS;
  1. delete previous bin logs
PURGE BINARY LOGS TO 'mysqld-bin.0000003'; # delete mysqld-bin.0000001 and mysqld-bin.0000002
PURGE BINARY LOGS BEFORE 'yyyy-MM-dd HH:mm:ss';
PURGE BINARY LOGS DATE_SUB(NOW(), INTERVAL 3 DAYS); # delete last three days bin log file.
Details

If you using master-slave mode, you can change all BINARY to MASTER

FAQ

Q1: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Q2: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Mar 7, 2024

Install Milvus

Preliminary

  • Kubernetes is installed; if not, check link
  • ArgoCD is installed; if not, check link
  • cert-manager has installed on argocd and the clusterissuer has a named self-signed-ca-issuerservice, , if not check link
  • minio is installed; if not, check link

Steps

1. copy minio credentials secret

kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database
kubectl -n storage get secret minio-secret -o json \
    | jq 'del(.metadata["namespace","creationTimestamp","resourceVersion","selfLink","uid"])' \
    | kubectl -n database apply -f -

2. prepare deploy-milvus.yaml

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: milvus
spec:
  syncPolicy:
    syncOptions:
      - CreateNamespace=true
  project: default
  source:
    repoURL: registry-1.docker.io/bitnamicharts
    chart: milvus
    targetRevision: 11.2.4
    helm:
      releaseName: milvus
      values: |
        global:
          security:
            allowInsecureImages: true
        milvus:
          image:
            registry: m.lab.zverse.space/docker.io
            repository: bitnami/milvus
            tag: 2.5.7-debian-12-r0
            pullPolicy: IfNotPresent
          auth:
            enabled: false
        initJob:
          forceRun: false
          image:
            registry: m.lab.zverse.space/docker.io
            repository: bitnami/pymilvus
            tag: 2.5.6-debian-12-r0
            pullPolicy: IfNotPresent
          resources:
            requests:
              cpu: 2
              memory: 512Mi
            limits:
              cpu: 2
              memory: 2Gi
        dataCoord:
          replicaCount: 1
          resources:
            requests:
              cpu: 500m
              memory: 512Mi
            limits:
              cpu: 2
              memory: 2Gi
          metrics:
            enabled: true
            
        rootCoord:
          replicaCount: 1
          resources:
            requests:
              cpu: 500m
              memory: 1Gi
            limits:
              cpu: 2
              memory: 4Gi
        queryCoord:
          replicaCount: 1
          resources:
            requests:
              cpu: 500m
              memory: 1Gi
            limits:
              cpu: 2
              memory: 4Gi
        indexCoord:
          replicaCount: 1
          resources:
            requests:
              cpu: 500m
              memory: 1Gi
            limits:
              cpu: 2
              memory: 4Gi
        dataNode:
          replicaCount: 1
          resources:
            requests:
              cpu: 500m
              memory: 1Gi
            limits:
              cpu: 2
              memory: 4Gi
        queryNode:
          replicaCount: 1
          resources:
            requests:
              cpu: 500m
              memory: 1Gi
            limits:
              cpu: 2
              memory: 2Gi
        indexNode:
          resources:
            requests:
              cpu: 500m
              memory: 1Gi
            limits:
              cpu: 2
              memory: 2Gi
        proxy:
          replicaCount: 1
          service:
            type: ClusterIP
          resources:
            requests:
              cpu: 500m
              memory: 1Gi
            limits:
              cpu: 2
              memory: 2Gi
        attu:
          image:
            registry: m.lab.zverse.space/docker.io
            repository: bitnami/attu
            tag: 2.5.5-debian-12-r1
          resources:
            requests:
              cpu: 500m
              memory: 1Gi
            limits:
              cpu: 2
              memory: 4Gi
          service:
            type: ClusterIP
          ingress:
            enabled: true
            ingressClassName: "nginx"
            annotations:
              cert-manager.io/cluster-issuer: alidns-webhook-zverse-letsencrypt
            hostname: milvus.dev.72602.online
            path: /
            pathType: ImplementationSpecific
            tls: true
        waitContainer:
          image:
            registry: m.lab.zverse.space/docker.io
            repository: bitnami/os-shell
            tag: 12-debian-12-r40
            pullPolicy: IfNotPresent
          resources:
            requests:
              cpu: 500m
              memory: 1Gi
            limits:
              cpu: 2
              memory: 4Gi
        externalS3:
          host: "minio.storage"
          port: 9000
          existingSecret: "minio-secret"
          existingSecretAccessKeyIDKey: "root-user"
          existingSecretKeySecretKey: "root-password"
          bucket: "milvus"
          rootPath: "file"
        etcd:
          enabled: true
          image:
            registry: m.lab.zverse.space/docker.io
          replicaCount: 1
          auth:
            rbac:
              create: false
            client:
              secureTransport: false
          resources:
            requests:
              cpu: 500m
              memory: 1Gi
            limits:
              cpu: 2
              memory: 2Gi
          persistence:
            enabled: true
            storageClass: ""
            size: 2Gi
          preUpgradeJob:
            enabled: false
        minio:
          enabled: false
        kafka:
          enabled: true
          image:
            registry: m.lab.zverse.space/docker.io
          controller:
            replicaCount: 1
            livenessProbe:
              failureThreshold: 8
            resources:
              requests:
                cpu: 500m
                memory: 1Gi
              limits:
                cpu: 2
                memory: 2Gi
            persistence:
              enabled: true
              storageClass: ""
              size: 2Gi
          service:
            ports:
              client: 9092
          extraConfig: |-
            offsets.topic.replication.factor=3
          listeners:
            client:
              protocol: PLAINTEXT
            interbroker:
              protocol: PLAINTEXT
            external:
              protocol: PLAINTEXT
          sasl:
            enabledMechanisms: "PLAIN"
            client:
              users:
                - user
          broker:
            replicaCount: 0
  destination:
    server: https://kubernetes.default.svc
    namespace: database

3. apply to k8s

kubectl -n argocd apply -f deploy-milvus.yaml

4. sync by argocd

argocd app sync argocd/milvus

5. check Attu WebUI

milvus address: milvus-proxy:19530

milvus database: default

https://milvus.dev.72602.online:32443/#/

5. [Optional] import data

import data by using sql file

MARIADB_ROOT_PASSWORD=$(kubectl -n database get secret mariadb-credentials -o jsonpath='{.data.mariadb-root-password}' | base64 -d)
POD_NAME=$(kubectl get pod -n database -l "app.kubernetes.io/name=mariadb-tool" -o jsonpath="{.items[0].metadata.name}") \
&& export SQL_FILENAME="Dump20240301.sql" \
&& kubectl -n database cp ${SQL_FILENAME} ${POD_NAME}:/tmp/${SQL_FILENAME} \
&& kubectl -n database exec -it deployment/app-mariadb-tool -- bash -c \
    'echo "create database ccds;" | mysql -h mariadb.database -uroot -p$MARIADB_ROOT_PASSWORD' \
&& kubectl -n database exec -it ${POD_NAME} -- bash -c \
    "mysql -h mariadb.database -uroot -p\${MARIADB_ROOT_PASSWORD} \
    ccds < /tmp/Dump20240301.sql"

6. [Optional] decode password

kubectl -n database get secret mariadb-credentials -o jsonpath='{.data.mariadb-root-password}' | base64 -d

7. [Optional] execute sql in pod

kubectl -n database exec -it xxxx bash
mariadb -h 127.0.0.1 -u root -p$MARIADB_ROOT_PASSWORD

And then you can check connection by

show status like  'Threads%';
May 26, 2025

Install Neo4j

Installation

Install By

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


1.get helm repo

Details
helm repo add neo4j https://helm.neo4j.com/neo4j
helm repo update

2.install chart

Details
kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database

helm upgrade --install neo4j neo4j/neo4j \
  --namespace database \
  --set neo4j.password=changeMe123 \
  --set volumes.data.mode=defaultStorageClass
Chart Reference

for more information, you can check ๐Ÿ”—https://artifacthub.io/packages/helm/neo4j/neo4j

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


1.prepare `deploy-xxxxx.yaml`

Details

2.apply to k8s

Details
kubectl -n argocd apply -f xxxx.yaml

3.sync by argocd

Details
argocd app sync argocd/xxxx

4.prepare yaml-content.yaml

Details

5.apply to k8s

Details
kubectl apply -f xxxx.yaml

6.apply xxxx.yaml directly

Details
kubectl apply -f - <<EOF

EOF

Preliminary

1. Docker|Podman|Buildah is installed; if not, check ๐Ÿ”—link


Using Proxy

you can run an addinational daocloud image to accelerate your pulling, check Daocloud Proxy

1.init server

Details
mkdir -p neo4j/data
podman run --rm \
    --name neo4j \
    -p 7474:7474 \
    -p 7687:7687 \
    -e neo4j_ROOT_PASSWORD=mysql \
    -v $(pwd)/neo4j/data:/data \
    -d docker.io/library/neo4j:5.18.0-community-bullseye
and then you can visit ๐Ÿ”—[http://localhost:7474]


username: `root`
password: `mysql`

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


4. Argo Workflow is installed; if not, check ๐Ÿ”—link


1.prepare `argocd-login-credentials`

Details
kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database

2.apply rolebinding to k8s

Details
kubectl apply -f - <<EOF
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: application-administrator
rules:
  - apiGroups:
      - argoproj.io
    resources:
      - applications
    verbs:
      - '*'
  - apiGroups:
      - apps
    resources:
      - deployments
    verbs:
      - '*'

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: application-administration
  namespace: argocd
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: application-administrator
subjects:
  - kind: ServiceAccount
    name: argo-workflow
    namespace: business-workflows

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: application-administration
  namespace: application
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: application-administrator
subjects:
  - kind: ServiceAccount
    name: argo-workflow
    namespace: business-workflows
EOF

4.prepare `deploy-xxxx-flow.yaml`

Details

6.submit to argo workflow client

Details
argo -n business-workflows submit deploy-xxxx-flow.yaml

7.decode password

Details
kubectl -n application get secret xxxx-credentials -o jsonpath='{.data.xxx-password}' | base64 -d

FAQ

Q1: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Q2: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Mar 7, 2024

Install Postgresql

Installation

Install By

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


1.get helm repo

Details
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update

2.install chart

Details
helm install bitnami/postgresql --generate-name --version 18.1.8
Using Proxy

for more information, you can check ๐Ÿ”—https://artifacthub.io/packages/helm/prometheus-community/prometheus

helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
helm repo update
helm install my-postgresql ay-helm-mirror/postgresql --version 18.1.8

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


1.prepare `postgresql-credentials`

Details
kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database
kubectl -n database create secret generic postgresql-credentials \
    --from-literal=postgres-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16) \
    --from-literal=password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16) \
    --from-literal=replication-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

2.prepare `deploy-postgresql.yaml`

Details
kubectl -n argocd apply -f - <<EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: postgresql
spec:
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
  project: default
  source:
    repoURL: https://aaronyang0628.github.io/helm-chart-mirror/charts
    chart: postgresql
    targetRevision: 18.1.8
    helm:
      releaseName: postgresql
      values: |
        global:
          security:
            allowInsecureImages: true
        architecture: standalone
        auth:
          database: n8n
          username: n8n
          existingSecret: postgresql-credentials
        primary:
          resources:
            requests:
              cpu: 1
              memory: 512Mi
            limits:
              cpu: 2
              memory: 1024Mi
          persistence:
            enabled: true
            storageClass: local-path
            size: 8Gi
        readReplicas:
          replicaCount: 1
          persistence:
            enabled: true
            storageClass: local-path
            size: 8Gi
        backup:
          enabled: false
        image:
          registry: m.daocloud.io/registry-1.docker.io
          pullPolicy: IfNotPresent
        volumePermissions:
          enabled: false
          image:
            registry: m.daocloud.io/registry-1.docker.io
            pullPolicy: IfNotPresent
        metrics:
          enabled: false
          image:
            registry: m.daocloud.io/registry-1.docker.io
            pullPolicy: IfNotPresent
    extraDeploy:
    - apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: postgres-tcp-ingress
        annotations:
          kubernetes.io/ingress.class: nginx
          cert-manager.io/cluster-issuer: lets-encrypt
      spec:
        rules:
        - host: postgres.dev.72602.online
          http:
            paths:
            - path: /
              pathType: Prefix
              backend:
                service:
                  name: postgresql
                  port:
                    number: 5342
  destination:
    server: https://kubernetes.default.svc
    namespace: database
EOF

3.sync by argocd

Details
argocd app sync argocd/postgresql

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


1.prepare `postgresql-credentials`

Details
kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database
kubectl -n database create secret generic postgresql-credentials \
    --from-literal=postgres-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16) \
    --from-literal=password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16) \
    --from-literal=replication-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

2.prepare `deploy-postgresql.yaml`

Details
kubectl -n argocd apply -f - <<EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: postgresql
spec:
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
  project: default
  source:
    repoURL: https://charts.bitnami.com/bitnami
    chart: postgresql
    targetRevision: 18.6.2
    helm:
      releaseName: postgresql
      values: |
        global:
          security:
            allowInsecureImages: true
        architecture: standalone
        auth:
          database: n8n
          username: n8n
          existingSecret: postgresql-credentials
        primary:
          resources:
            requests:
              cpu: 1
              memory: 512Mi
            limits:
              cpu: 2
              memory: 1024Mi
          persistence:
            enabled: true
            storageClass: local-path
            size: 8Gi
        readReplicas:
          replicaCount: 1
          persistence:
            enabled: true
            storageClass: local-path
            size: 8Gi
        backup:
          enabled: false
        image:
          registry: m.daocloud.io/registry-1.docker.io
          pullPolicy: IfNotPresent
        volumePermissions:
          enabled: false
          image:
            registry: m.daocloud.io/registry-1.docker.io
            pullPolicy: IfNotPresent
        metrics:
          enabled: false
          image:
            registry: m.daocloud.io/registry-1.docker.io
            pullPolicy: IfNotPresent
  destination:
    server: https://kubernetes.default.svc
    namespace: database
EOF

3.sync by argocd

Details
argocd app sync argocd/postgresql

Preliminary

1. Docker|Podman|Buildah is installed; if not, check ๐Ÿ”—link


Using Proxy

you can run an addinational daocloud image to accelerate your pulling, check Daocloud Proxy

1.init server

Details
mkdir -p $(pwd)/postgresql/data
podman run --rm \
    --name postgresql \
    -p 5432:5432 \
    -e POSTGRES_PASSWORD=postgresql \
    -e PGDATA=/var/lib/postgresql/data/pgdata \
    -v $(pwd)/postgresql/data:/var/lib/postgresql/data \
    -d docker.io/library/postgres:15.2-alpine3.17

2.use web console

Details
podman run --rm \
  -p 8080:80 \
  -e 'PGADMIN_DEFAULT_EMAIL=ben.wangz@foxmail.com' \
  -e 'PGADMIN_DEFAULT_PASSWORD=123456' \
  -d docker.io/dpage/pgadmin4:6.15
And then you can visit ๐Ÿ”—[http://localhost:8080]


3.use internal client

Details
podman run --rm \
    --env PGPASSWORD=postgresql \
    --entrypoint psql \
    -it docker.io/library/postgres:15.2-alpine3.17 \
    --host host.containers.internal \
    --port 5432 \
    --username postgres \
    --dbname postgres \
    --command 'select version()'

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


4. Argo Workflow is installed; if not, check ๐Ÿ”—link


5. Minio artifact repository has been configured, if not check ๐Ÿ”—link


- endpoint: minio.storage:9000

1.prepare `argocd-login-credentials`

Details
kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database
ARGOCD_USERNAME=admin
ARGOCD_PASSWORD=$(kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d)
kubectl -n business-workflows create secret generic argocd-login-credentials \
    --from-literal=username=${ARGOCD_USERNAME} \
    --from-literal=password=${ARGOCD_PASSWORD}

2.apply rolebinding to k8s

Details
kubectl apply -f - <<EOF
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: application-administrator
rules:
  - apiGroups:
      - argoproj.io
    resources:
      - applications
    verbs:
      - '*'
  - apiGroups:
      - apps
    resources:
      - deployments
    verbs:
      - '*'

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: application-administration
  namespace: argocd
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: application-administrator
subjects:
  - kind: ServiceAccount
    name: argo-workflow
    namespace: business-workflows

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: application-administration
  namespace: application
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: application-administrator
subjects:
  - kind: ServiceAccount
    name: argo-workflow
    namespace: business-workflows
EOF

3.prepare postgresql admin credentials secret

Details
kubectl -n application create secret generic postgresql-credentials \
  --from-literal=postgres-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16) \
  --from-literal=password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16) \
  --from-literal=replication-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

4.prepare `deploy-postgresql-flow.yaml`

Details
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: deploy-argocd-app-pg-
spec:
  entrypoint: entry
  artifactRepositoryRef:
    configmap: artifact-repositories
    key: default-artifact-repository
  serviceAccountName: argo-workflow
  templates:
  - name: entry
    inputs:
      parameters:
      - name: argocd-server
        value: argo-cd-argocd-server.argocd:443
      - name: insecure-option
        value: --insecure
    dag:
      tasks:
      - name: apply
        template: apply
      - name: prepare-argocd-binary
        template: prepare-argocd-binary
        dependencies:
        - apply
      - name: sync
        dependencies:
        - prepare-argocd-binary
        template: sync
        arguments:
          artifacts:
          - name: argocd-binary
            from: "{{tasks.prepare-argocd-binary.outputs.artifacts.argocd-binary}}"
          parameters:
          - name: argocd-server
            value: "{{inputs.parameters.argocd-server}}"
          - name: insecure-option
            value: "{{inputs.parameters.insecure-option}}"
      - name: wait
        dependencies:
        - sync
        template: wait
        arguments:
          artifacts:
          - name: argocd-binary
            from: "{{tasks.prepare-argocd-binary.outputs.artifacts.argocd-binary}}"
          parameters:
          - name: argocd-server
            value: "{{inputs.parameters.argocd-server}}"
          - name: insecure-option
            value: "{{inputs.parameters.insecure-option}}"
      - name: init-db-tool
        template: init-db-tool
        dependencies:
        - wait
  - name: apply
    resource:
      action: apply
      manifest: |
        apiVersion: argoproj.io/v1alpha1
        kind: Application
        metadata:
          name: app-postgresql
          namespace: argocd
        spec:
          syncPolicy:
            syncOptions:
            - CreateNamespace=true
          project: default
          source:
            repoURL: https://charts.bitnami.com/bitnami
            chart: postgresql
            targetRevision: 14.2.2
            helm:
              releaseName: app-postgresql
              values: |
                architecture: standalone
                auth:
                  database: geekcity
                  username: aaron.yang
                  existingSecret: postgresql-credentials
                primary:
                  persistence:
                    enabled: false
                readReplicas:
                  replicaCount: 1
                  persistence:
                    enabled: false
                backup:
                  enabled: false
                image:
                  registry: m.daocloud.io/docker.io
                  pullPolicy: IfNotPresent
                volumePermissions:
                  enabled: false
                  image:
                    registry: m.daocloud.io/docker.io
                    pullPolicy: IfNotPresent
                metrics:
                  enabled: false
                  image:
                    registry: m.daocloud.io/docker.io
                    pullPolicy: IfNotPresent
          destination:
            server: https://kubernetes.default.svc
            namespace: application
  - name: prepare-argocd-binary
    inputs:
      artifacts:
      - name: argocd-binary
        path: /tmp/argocd
        mode: 755
        http:
          url: https://files.m.daocloud.io/github.com/argoproj/argo-cd/releases/download/v2.9.3/argocd-linux-amd64
    outputs:
      artifacts:
      - name: argocd-binary
        path: "{{inputs.artifacts.argocd-binary.path}}"
    container:
      image: m.daocloud.io/docker.io/library/fedora:39
      command:
      - sh
      - -c
      args:
      - |
        ls -l {{inputs.artifacts.argocd-binary.path}}
  - name: sync
    inputs:
      artifacts:
      - name: argocd-binary
        path: /usr/local/bin/argocd
      parameters:
      - name: argocd-server
      - name: insecure-option
        value: ""
    container:
      image: m.daocloud.io/docker.io/library/fedora:39
      env:
      - name: ARGOCD_USERNAME
        valueFrom:
          secretKeyRef:
            name: argocd-login-credentials
            key: username
      - name: ARGOCD_PASSWORD
        valueFrom:
          secretKeyRef:
            name: argocd-login-credentials
            key: password
      - name: WITH_PRUNE_OPTION
        value: --prune
      command:
      - sh
      - -c
      args:
      - |
        set -e
        export ARGOCD_SERVER={{inputs.parameters.argocd-server}}
        export INSECURE_OPTION={{inputs.parameters.insecure-option}}
        export ARGOCD_USERNAME=${ARGOCD_USERNAME:-admin}
        argocd login ${INSECURE_OPTION} --username ${ARGOCD_USERNAME} --password ${ARGOCD_PASSWORD} ${ARGOCD_SERVER}
        argocd app sync argocd/app-postgresql ${WITH_PRUNE_OPTION} --timeout 300
  - name: wait
    inputs:
      artifacts:
      - name: argocd-binary
        path: /usr/local/bin/argocd
      parameters:
      - name: argocd-server
      - name: insecure-option
        value: ""
    container:
      image: m.daocloud.io/docker.io/library/fedora:39
      env:
      - name: ARGOCD_USERNAME
        valueFrom:
          secretKeyRef:
            name: argocd-login-credentials
            key: username
      - name: ARGOCD_PASSWORD
        valueFrom:
          secretKeyRef:
            name: argocd-login-credentials
            key: password
      command:
      - sh
      - -c
      args:
      - |
        set -e
        export ARGOCD_SERVER={{inputs.parameters.argocd-server}}
        export INSECURE_OPTION={{inputs.parameters.insecure-option}}
        export ARGOCD_USERNAME=${ARGOCD_USERNAME:-admin}
        argocd login ${INSECURE_OPTION} --username ${ARGOCD_USERNAME} --password ${ARGOCD_PASSWORD} ${ARGOCD_SERVER}
        argocd app wait argocd/app-postgresql
  - name: init-db-tool
    resource:
      action: apply
      manifest: |
        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: app-postgresql-tool
          namespace: application
          labels:
            app.kubernetes.io/name: postgresql-tool
        spec:
          replicas: 1
          selector:
            matchLabels:
              app.kubernetes.io/name: postgresql-tool
          template:
            metadata:
              labels:
                app.kubernetes.io/name: postgresql-tool
            spec:
              containers:
                - name: postgresql-tool
                  image: m.daocloud.io/docker.io/bitnami/postgresql:14.4.0-debian-11-r9
                  imagePullPolicy: IfNotPresent
                  env:
                    - name: POSTGRES_PASSWORD
                      valueFrom:
                        secretKeyRef:
                          key: postgres-password
                          name: postgresql-credentials
                    - name: TZ
                      value: Asia/Shanghai
                  command:
                    - tail
                  args:
                    - -f
                    - /etc/hosts

6.submit to argo workflow client

Details
argo -n business-workflows submit deploy-postgresql.yaml

7.decode password

Details
kubectl -n application get secret postgresql-credentials -o jsonpath='{.data.postgres-password}' | base64 -d

8.import data

Details
POSTGRES_PASSWORD=$(kubectl -n application get secret postgresql-credentials -o jsonpath='{.data.postgres-password}' | base64 -d) \
POD_NAME=$(kubectl get pod -n application -l "app.kubernetes.io/name=postgresql-tool" -o jsonpath="{.items[0].metadata.name}") \
&& export SQL_FILENAME="init_dfs_table_data.sql" \
&& kubectl -n application cp ${SQL_FILENAME} ${POD_NAME}:/tmp/${SQL_FILENAME} \
&& kubectl -n application exec -it deployment/app-postgresql-tool -- bash -c \
    'echo "CREATE DATABASE csst;" | PGPASSWORD="$POSTGRES_PASSWORD" \
    psql --host app-postgresql.application -U postgres -d postgres -p 5432' \
&& kubectl -n application exec -it deployment/app-postgresql-tool -- bash -c \
    'PGPASSWORD="$POSTGRES_PASSWORD" psql --host app-postgresql.application \
    -U postgres -d csst -p 5432 < /tmp/init_dfs_table_data.sql'

FAQ

Q1: How to connect to the postgres
POSTGRES_PASSWORD=$(kubectl -n database get secret postgresql-credentials -o jsonpath='{.data.postgres-password}' | base64 -d)
podman run --rm \
    --env PGPASSWORD=${POSTGRES_PASSWORD} \
    --entrypoint psql \
    -it m.daocloud.io/docker.io/library/postgres:15.2-alpine3.17 \
    --host host.containers.internal \
    --port 32543 \
    --username postgres  \
    --dbname postgres  \
    --command 'SELECT datname FROM pg_database;'
Q2: Argo Workflow submitted but app-postgresql is not ready

Symptom

  • Workflow step succeeds, but PostgreSQL app or tool Deployment is not ready.

Check

argo -n business-workflows list
argo -n business-workflows logs @latest
kubectl -n application get pods
kubectl -n application describe deploy app-postgresql
kubectl -n application describe deploy app-postgresql-tool

Fix

  • Ensure argocd-login-credentials secret exists and has valid username/password.
  • Ensure postgresql-credentials secret exists in application namespace.
  • Re-run workflow after fixing missing secret/permission issues.

Expected

  • app-postgresql and app-postgresql-tool Deployments become available.
Mar 7, 2024

Install PgAdmin

๐Ÿš€Installation

Install By

1.get helm repo

Details
helm repo add runix https://helm.runix.net/
helm repo update

2.install chart

Details
helm install runix/pgadmin4 --generate-name --version 1.62.0
Using AY Helm Mirror

for more information, you can check ๐Ÿ”—https://github.com/AaronYang0628/helm-chart-mirror

helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
  helm repo update
  helm install ay-helm-mirror/chart-name --generate-name --version a.b.c

1.prepare `pgadmin-credentials.yaml`

Details
kubectl -n database create secret generic pgadmin-credentials \
  --from-literal=password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

2.prepare `deploy-pgadmin.yaml`

Details
kubectl -n argocd apply -f -<< EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: pgadmin
spec:
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
  project: default
  source:
    repoURL: https://helm.runix.net
    targetRevision: 1.62.0
    helm:
      releaseName: pgadmin
      values: |
        image:
          registry: docker.io
          repository: dpage/pgadmin4
          tag: latest
        replicaCount: 1
        persistentVolume:
          enabled: false
        env:
          email: pgadmin@mail.dev.72602.online
          passwordExistingSecret: pgadmin-credentials
          variables:
            - name: PGADMIN_CONFIG_WTF_CSRF_ENABLED
              value: "False"
            - name: PGADMIN_CONFIG_PROXY_X_FOR_COUNT
              value: "1"
            - name: PGADMIN_CONFIG_PROXY_X_PROTO_COUNT
              value: "1"
            - name: PGADMIN_CONFIG_PROXY_X_HOST_COUNT
              value: "1"
            - name: PGADMIN_CONFIG_PROXY_X_PORT_COUNT
              value: "1"
        resources:
          requests:
            cpu: 500m
            memory: 512Mi
          limits:
            cpu: 1000m
            memory: 1024Mi
        ingress:
          enabled: true
          ingressClassName: nginx
          annotations:
            cert-manager.io/cluster-issuer: lets-encrypt
          hosts:
            - host: pgadmin.dev.72602.online
              paths:
                - path: /
                  pathType: ImplementationSpecific
          tls:
            - secretName: pgadmin.dev.72602.online-tls
              hosts:
                - pgadmin.dev.72602.online
    chart: pgadmin4
  destination:
    server: https://kubernetes.default.svc
    namespace: database
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
EOF
Details
kubectl -n argocd apply -f -<< EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: pgadmin
spec:
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
  project: default
  source:
    repoURL: https://helm.runix.net/
    chart: pgadmin4
    targetRevision: 1.23.3
    helm:
      releaseName: pgadmin4
      values: |
        replicaCount: 1
        persistentVolume:
          enabled: false
        env:
          email: pgadmin@mail.72602.online
          variables:
            - name: PGADMIN_CONFIG_WTF_CSRF_ENABLED
              value: "False"
        existingSecret: pgadmin-credentials
        resources:
          requests:
            memory: 512Mi
            cpu: 500m
          limits:
            memory: 1024Mi
            cpu: 1000m
        image:
          registry: m.daocloud.io/docker.io
          pullPolicy: IfNotPresent
        ingress:
          enabled: true
          ingressClassName: nginx
          annotations:
            cert-manager.io/cluster-issuer: letsencrypt
          hosts:
            - host: pgadmin.72602.online
              paths:
                - path: /
                  pathType: ImplementationSpecific
          tls:
            - secretName: pgadmin.72602.online-tls
              hosts:
                - pgadmin.72602.online
  destination:
    server: https://kubernetes.default.svc
    namespace: database
EOF

3.sync by argocd

Details
argocd app sync argocd/pgadmin
Using AY Helm Mirror

for more information, you can check ๐Ÿ”—https://github.com/AaronYang0628/helm-chart-mirror

helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
  helm repo update
  helm install ay-helm-mirror/chart-name --generate-name --version a.b.c
Using AY ACR Image Mirror
Using DaoCloud Mirror

1.init server

Details
Using AY ACR Image Mirror
Using DaoCloud Mirror

1.init server

Details
Using AY ACR Image Mirror
Using DaoCloud Mirror

๐Ÿ›Ž๏ธFAQ

Q1: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Q2: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Mar 7, 2025

Install Redis

Installation

Install By

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


1.get helm repo

Details
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update

2.install chart

Details
kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database

helm upgrade --install redis m.daocloud.io/docker.io/bitnamilegacy/redis \
  --namespace database \
  --version 18.16.0 \
  --set architecture=replication \
  --set auth.enabled=true
Chart Reference

for more information, you can check ๐Ÿ”—https://artifacthub.io/packages/helm/bitnami/redis

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


1.prepare `redis-credentials`

Details
kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database
kubectl -n database create secret generic redis-credentials \
--from-literal=redis-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

2.apply `deploy-redis.yaml`

```shell kubectl -n argocd apply -f https://raw.githubusercontent.com/AaronYang0628/docs/main/manifests/zjlab/redis.yaml ```

Details
kubectl -n argocd apply -f - << 'EOF'
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: redis
spec:
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
  project: default
  source:
    repoURL: https://charts.bitnami.com/bitnami
    chart: redis
    targetRevision: 18.16.0
    helm:
      releaseName: redis
      values: |
        architecture: replication
        auth:
          enabled: true
          sentinel: false
          existingSecret: redis-credentials
        master:
          count: 1
          resources:
            requests:
              memory: 512Mi
              cpu: 512m
            limits:
              memory: 1024Mi
              cpu: 1024m
          disableCommands:
            - FLUSHDB
            - FLUSHALL
          persistence:
            enabled: true
            storageClass: "local-path"
            accessModes:
            - ReadWriteOnce
            size: 8Gi
        replica:
          replicaCount: 1
          resources:
            requests:
              memory: 512Mi
              cpu: 512m
            limits:
              memory: 1024Mi
              cpu: 1024m
          disableCommands:
            - FLUSHDB
            - FLUSHALL
          persistence:
            enabled: true
            storageClass: "local-path"
            accessModes:
            - ReadWriteOnce
            size: 8Gi
        image:
          registry: m.daocloud.io/docker.io
          pullPolicy: IfNotPresent
        sentinel:
          enabled: false
        metrics:
          enabled: false
        volumePermissions:
          enabled: false
        sysctl:
          enabled: false
        extraDeploy:
        - apiVersion: traefik.io/v1alpha1
          kind: IngressRouteTCP
          metadata:
            name: redis-tcp
            namespace: storage
          spec:
            entryPoints:
              - redis
            routes:
            - match: HostSNI(`*`)
              services:
              - name: redis-master
                port: 6379
  destination:
    server: https://kubernetes.default.svc
    namespace: storage
EOF

3.sync by argocd

Details
argocd app sync argocd/redis

4.test redis connection

Details
kubectl -n storage run test --rm -it --image=m.daocloud.io/docker.io/library/redis:7 -- \
redis-cli -h redis-master -p 6379 -a uItmVGpX5PShHc8j ping

Preliminary

1. Docker|Podman|Buildah is installed; if not, check ๐Ÿ”—link


Using Proxy

you can run an addinational daocloud image to accelerate your pulling, check Daocloud Proxy

1.init server

Details
mkdir -p $(pwd)/redis/data
podman run --rm \
    --name redis \
    -p 6379:6379 \
    -v $(pwd)/redis/data:/data \
    -d docker.io/library/redis:7.2.4-alpine

2.use internal client

Details
podman run --rm \
    -it docker.io/library/redis:7.2.4-alpine \
    redis-cli \
    -h host.containers.internal \
    set mykey somevalue

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm is installed; if not, check ๐Ÿ”—link


3. ArgoCD is installed; if not, check ๐Ÿ”—link


4. Argo Workflow is installed; if not, check ๐Ÿ”—link


5. Minio artifact repository has been configured, if not check ๐Ÿ”—link


- endpoint: minio.storage:9000

1.prepare `argocd-login-credentials`

Details
ARGOCD_USERNAME=admin
ARGOCD_PASSWORD=$(kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d)
kubectl -n business-workflows create secret generic argocd-login-credentials \
    --from-literal=username=${ARGOCD_USERNAME} \
    --from-literal=password=${ARGOCD_PASSWORD}

2.apply rolebinding to k8s

Details
kubectl apply -f - <<EOF
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: application-administrator
rules:
  - apiGroups:
      - argoproj.io
    resources:
      - applications
    verbs:
      - '*'
  - apiGroups:
      - apps
    resources:
      - deployments
    verbs:
      - '*'

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: application-administration
  namespace: argocd
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: application-administrator
subjects:
  - kind: ServiceAccount
    name: argo-workflow
    namespace: business-workflows

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: application-administration
  namespace: application
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: application-administrator
subjects:
  - kind: ServiceAccount
    name: argo-workflow
    namespace: business-workflows
EOF

3.prepare redis credentials secret

Details
kubectl -n application create secret generic redis-credentials \
  --from-literal=redis-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

4.prepare `deploy-redis-flow.yaml`

Details
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: deploy-argocd-app-redis-
spec:
  entrypoint: entry
  artifactRepositoryRef:
    configmap: artifact-repositories
    key: default-artifact-repository
  serviceAccountName: argo-workflow
  templates:
  - name: entry
    inputs:
      parameters:
      - name: argocd-server
        value: argocd-server.argocd:443
      - name: insecure-option
        value: --insecure
    dag:
      tasks:
      - name: apply
        template: apply
      - name: prepare-argocd-binary
        template: prepare-argocd-binary
        dependencies:
        - apply
      - name: sync
        dependencies:
        - prepare-argocd-binary
        template: sync
        arguments:
          artifacts:
          - name: argocd-binary
            from: "{{tasks.prepare-argocd-binary.outputs.artifacts.argocd-binary}}"
          parameters:
          - name: argocd-server
            value: "{{inputs.parameters.argocd-server}}"
          - name: insecure-option
            value: "{{inputs.parameters.insecure-option}}"
      - name: wait
        dependencies:
        - sync
        template: wait
        arguments:
          artifacts:
          - name: argocd-binary
            from: "{{tasks.prepare-argocd-binary.outputs.artifacts.argocd-binary}}"
          parameters:
          - name: argocd-server
            value: "{{inputs.parameters.argocd-server}}"
          - name: insecure-option
            value: "{{inputs.parameters.insecure-option}}"
  - name: apply
    resource:
      action: apply
      manifest: |
        apiVersion: argoproj.io/v1alpha1
        kind: Application
        metadata:
          name: app-redis
          namespace: argocd
        spec:
          syncPolicy:
            syncOptions:
            - CreateNamespace=true
          project: default
          source:
            repoURL: https://charts.bitnami.com/bitnami
            chart: redis
            targetRevision: 18.16.0
            helm:
              releaseName: app-redis
              values: |
                architecture: replication
                auth:
                  enabled: true
                  sentinel: true
                  existingSecret: redis-credentials
                master:
                  count: 1
                  disableCommands:
                    - FLUSHDB
                    - FLUSHALL
                  persistence:
                    enabled: false
                replica:
                  replicaCount: 3
                  disableCommands:
                    - FLUSHDB
                    - FLUSHALL
                  persistence:
                    enabled: false
                image:
                  registry: m.daocloud.io/docker.io
                  pullPolicy: IfNotPresent
                sentinel:
                  enabled: false
                  persistence:
                    enabled: false
                  image:
                    registry: m.daocloud.io/docker.io
                    pullPolicy: IfNotPresent
                metrics:
                  enabled: false
                  image:
                    registry: m.daocloud.io/docker.io
                    pullPolicy: IfNotPresent
                volumePermissions:
                  enabled: false
                  image:
                    registry: m.daocloud.io/docker.io
                    pullPolicy: IfNotPresent
                sysctl:
                  enabled: false
                  image:
                    registry: m.daocloud.io/docker.io
                    pullPolicy: IfNotPresent
          destination:
            server: https://kubernetes.default.svc
            namespace: application
  - name: prepare-argocd-binary
    inputs:
      artifacts:
      - name: argocd-binary
        path: /tmp/argocd
        mode: 755
        http:
          url: https://files.m.daocloud.io/github.com/argoproj/argo-cd/releases/download/v2.9.3/argocd-linux-amd64
    outputs:
      artifacts:
      - name: argocd-binary
        path: "{{inputs.artifacts.argocd-binary.path}}"
    container:
      image: m.daocloud.io/docker.io/library/fedora:39
      command:
      - sh
      - -c
      args:
      - |
        ls -l {{inputs.artifacts.argocd-binary.path}}
  - name: sync
    inputs:
      artifacts:
      - name: argocd-binary
        path: /usr/local/bin/argocd
      parameters:
      - name: argocd-server
      - name: insecure-option
        value: ""
    container:
      image: m.daocloud.io/docker.io/library/fedora:39
      env:
      - name: ARGOCD_USERNAME
        valueFrom:
          secretKeyRef:
            name: argocd-login-credentials
            key: username
      - name: ARGOCD_PASSWORD
        valueFrom:
          secretKeyRef:
            name: argocd-login-credentials
            key: password
      - name: WITH_PRUNE_OPTION
        value: --prune
      command:
      - sh
      - -c
      args:
      - |
        set -e
        export ARGOCD_SERVER={{inputs.parameters.argocd-server}}
        export INSECURE_OPTION={{inputs.parameters.insecure-option}}
        export ARGOCD_USERNAME=${ARGOCD_USERNAME:-admin}
        argocd login ${INSECURE_OPTION} --username ${ARGOCD_USERNAME} --password ${ARGOCD_PASSWORD} ${ARGOCD_SERVER}
        argocd app sync argocd/app-redis ${WITH_PRUNE_OPTION} --timeout 300
  - name: wait
    inputs:
      artifacts:
      - name: argocd-binary
        path: /usr/local/bin/argocd
      parameters:
      - name: argocd-server
      - name: insecure-option
        value: ""
    container:
      image: m.daocloud.io/docker.io/library/fedora:39
      env:
      - name: ARGOCD_USERNAME
        valueFrom:
          secretKeyRef:
            name: argocd-login-credentials
            key: username
      - name: ARGOCD_PASSWORD
        valueFrom:
          secretKeyRef:
            name: argocd-login-credentials
            key: password
      command:
      - sh
      - -c
      args:
      - |
        set -e
        export ARGOCD_SERVER={{inputs.parameters.argocd-server}}
        export INSECURE_OPTION={{inputs.parameters.insecure-option}}
        export ARGOCD_USERNAME=${ARGOCD_USERNAME:-admin}
        argocd login ${INSECURE_OPTION} --username ${ARGOCD_USERNAME} --password ${ARGOCD_PASSWORD} ${ARGOCD_SERVER}
        argocd app wait argocd/app-redis

6.submit to argo workflow client

Details
argo -n business-workflows submit deploy-redis-flow.yaml

7.decode password

Details
kubectl -n application get secret redis-credentials -o jsonpath='{.data.redis-password}' | base64 -d

FAQ

Q1: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Q2: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Mar 7, 2024

Subsections of Git

Install Act Runner

Installation

Install By

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm binary is installed; if not, check ๐Ÿ”—link


1.get helm repo

Details
helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
helm repo update

2.prepare `act-runner-secret`

Details
kubectl -n application create secret generic act-runner-secret \
  --from-literal=act-runner-token=4w3Sx0Hwe6VFevl473ZZ4nFVDvFvhKcEUBvpJ09L

3.prepare values

Details
echo "
replicas: 1
runner:
  instanceURL: http://192.168.100.125:30300
  token:
    fromSecret:
      name: "act-runner-secret"
      key: "act-runner-token"" > act-runner-values.yaml

4.install chart

Details
helm upgrade  --create-namespace -n application --install -f ./act-runner-values.yaml act-runner ay-helm-mirror/act-runner

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. ArgoCD is installed; if not, check ๐Ÿ”—link


3. Helm binary is installed; if not, check ๐Ÿ”—link


1.prepare `act-runner-secret`

Details
kubectl -n application create secret generic act-runner-secret \
  --from-literal=act-runner-token=4w3Sx0Hwe6VFevl473ZZ4nFVDvFvhKcEUBvpJ09L
act-runner-token could be get from here

token is used for authentication and identification, such as P2U1U0oB4XaRCi8azcngmPCLbRpUGapalhmddh23. Each token can be used to create multiple runners, until it is replaced with a new token using the reset link. You can obtain different levels of ’tokens’ from the following places to create the corresponding level of ‘runners’:

Instance level: The admin settings page, like <your_gitea.com>/-/admin/actions/runners.

act_runner_token act_runner_token

2.prepare act-runner.yaml

Storage In
kubectl -n argocd apply -f - <<EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: act-runner
spec:
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
  project: default
  source:
    repoURL: https://aaronyang0628.github.io/helm-chart-mirror/charts
    chart: act-runner
    targetRevision: 0.2.2
    helm:
      releaseName: act-runner
      values: |
        image:
          name: vegardit/gitea-act-runner
          tag: "dind-0.2.13"
          repository: m.daocloud.io/docker.io
        runner:
          instanceURL: https://192.168.100.125:30300
          token:
            fromSecret:
              name: "act-runner-secret"
              key: "act-runner-token"
          config:
            enabled: true
            data: |
              log:
                level: info
              runner:
                labels:
                  - ubuntu-latest:docker://m.daocloud.io/docker.gitea.com/runner-images:ubuntu-latest
              container:
                force_pull: true
        persistence:
          enabled: true
          storageClassName: ""
          accessModes: ReadWriteOnce
          size: 10Gi
        autoscaling:
          enabled: true
          minReplicas: 1
          maxReplicas: 3
        replicas: 1  
        securityContext:
          privileged: true
          runAsUser: 0
          runAsGroup: 0
          fsGroup: 0
          capabilities:
            add: ["NET_ADMIN", "SYS_ADMIN"]
        podSecurityContext:
          runAsUser: 0
          runAsGroup: 0
          fsGroup: 0
        resources: 
          requests:
            cpu: 200m
            memory: 512Mi
          limits:
            cpu: 1000m
            memory: 2048Mi
  destination:
    server: https://kubernetes.default.svc
    namespace: application
EOF

4.sync by argocd

Details
argocd app sync argocd/act-runner

5.use action

Details

Even if Actions is enabled for the Gitea instance, repositories still disable Actions by default.

To enable it, go to the settings page of your repository like your_gitea.com/<owner>/repo/settings and enable Enable Repository Actions.

act_runner_token act_runner_token

Preliminary

1. Podman has installed, and the `podman` command is available in your PATH.


1.prepare data and config dir

Details
mkdir -p /opt/gitea_act_runner/{data,config} \
&& chown -R 1000:1000 /opt/gitea_act_runner \
&& chmod -R 755 /opt/gitea_act_runner

2.run container

Details
podman run -it \
  --name gitea_act_runner \
  --rm \
  --privileged \
  --network=host \
  -v /opt/gitea_act_runner/data:/data \
  -v /opt/gitea_act_runner/config:/config \
  -v /var/run/podman/podman.sock:/var/run/docker.sock \
  -e GITEA_INSTANCE_URL="http://10.200.60.64:30300" \
  -e GITEA_RUNNER_REGISTRATION_TOKEN="5lgsrOzfKz3RiqeMWxxUb9RmUPEWNnZ6hTTZV0DL" \
  m.daocloud.io/docker.io/gitea/act_runner:latest-dind-rootless
Using Mirror

you can run an addinational daocloud image to accelerate your pulling, check Daocloud Proxy

Preliminary

1. Docker 2. Podman has installed, and the `podman` command is available in your PATH.

1.prepare data and config dir

Details
mkdir -p /opt/gitea_act_runner/{data,config} \
&& chown -R 1000:1000 /opt/gitea_act_runner \
&& chmod -R 755 /opt/gitea_act_runner

2.run container

Details
docker run -it \
  --name gitea_act_runner \
  --rm \
  --privileged \
  --network=host \
  -v /opt/gitea_act_runner/data:/data \
  -v /opt/gitea_act_runner/config:/config \
  -e GITEA_INSTANCE_URL="http://192.168.100.125:30300" \
  -e GITEA_RUNNER_REGISTRATION_TOKEN="5lgsrOzfKz3RiqeMWxxUb9RmUPEWNnZ6hTTZV0DL" \
  m.daocloud.io/docker.io/gitea/act_runner:latest-dind
Using Mirror

you can run an addinational daocloud image to accelerate your pulling, check Daocloud Proxy

FAQ

Q1: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Q2: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Jun 7, 2025

Install Gitea

Installation

Install By

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. Helm binary is installed; if not, check ๐Ÿ”—link


3. CertManager is installed; if not, check ๐Ÿ”—link


4. Ingress is installed; if not, check ๐Ÿ”—link


1.get helm repo

Details
helm repo add gitea-charts https://dl.gitea.com/charts/
helm repo update

2.install chart

Details
helm install gitea gitea-charts/gitea --generate-name
Using Mirror
helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts \
  && helm install ay-helm-mirror/gitea --generate-name --version 12.1.3

for more information, you can check ๐Ÿ”—https://aaronyang0628.github.io/helm-chart-mirror/

Preliminary

1. Kubernetes is installed; if not, check ๐Ÿ”—link


2. ArgoCD is installed; if not, check ๐Ÿ”—link


3. Helm binary is installed; if not, check ๐Ÿ”—link


4. Ingress is installed on ArgoCD; if not, check ๐Ÿ”—link


5. Minio is installed; if not, check ๐Ÿ”—link


1.prepare `chart-museum-credentials`

Storage In
kubectl get namespaces application > /dev/null 2>&1 || kubectl create namespace application
kubectl -n application create secret generic gitea-admin-credentials \
    --from-literal=username=gitea_admin \
    --from-literal=password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)
kubectl get namespaces application > /dev/null 2>&1 || kubectl create namespace application
kubectl -n application create secret generic gitea-admin-credentials \
    --from-literal=username=gitea_admin \
    --from-literal=password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

2.prepare `gitea.yaml`

Storage In
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: gitea
spec:
  syncPolicy:
    syncOptions:
    - CreateNamespace=true
  project: default
  source:
    repoURL: https://dl.gitea.com/charts/
    chart: gitea
    targetRevision: 10.1.4
    helm:
      releaseName: gitea
      values: |
        image:
          registry: m.daocloud.io/docker.io
        service:
          http:
            type: NodePort
            port: 3000
            nodePort: 30300
          ssh:
            type: NodePort
            port: 22
            nodePort: 32022
        ingress:
          enabled: true
          ingressClassName: nginx
          annotations:
            kubernetes.io/ingress.class: nginx
            nginx.ingress.kubernetes.io/rewrite-target: /$1
            cert-manager.io/cluster-issuer: self-signed-ca-issuer
          hosts:
          - host: gitea.dev.72602.online
            paths:
            - path: /?(.*)
              pathType: ImplementationSpecific
          tls:
          - secretName: gitea.dev.72602.online-tls
            hosts:
            - gitea.dev.72602.online
        persistence:
          enabled: true
          size: 8Gi
          storageClass: ""
        redis-cluster:
          enabled: false
        postgresql-ha:
          enabled: false
        postgresql:
          enabled: true
          architecture: standalone
          image:
            registry: m.daocloud.io/docker.io
          primary:
            persistence:
              enabled: false
              storageClass: ""
              size: 8Gi
          readReplicas:
            replicaCount: 1
            persistence:
              enabled: true
              storageClass: ""
              size: 8Gi
          backup:
            enabled: false
          volumePermissions:
            enabled: false
            image:
              registry: m.daocloud.io/docker.io
          metrics:
            enabled: false
            image:
              registry: m.daocloud.io/docker.io
        gitea:
          admin:
            existingSecret: gitea-admin-credentials
            email: aaron19940628@gmail.com
          config:
            database:
              DB_TYPE: postgres
            session:
              PROVIDER: db
            cache:
              ADAPTER: memory
            queue:
              TYPE: level
            indexer:
              ISSUE_INDEXER_TYPE: bleve
              REPO_INDEXER_ENABLED: true
            repository:
              MAX_CREATION_LIMIT: 10
              DISABLED_REPO_UNITS: "repo.wiki,repo.ext_wiki,repo.projects"
              DEFAULT_REPO_UNITS: "repo.code,repo.releases,repo.issues,repo.pulls"
            server:
              PROTOCOL: http
              LANDING_PAGE: login
              DOMAIN: gitea.dev.72602.online
              ROOT_URL: https://gitea.dev.72602.online:32443/
              SSH_DOMAIN: ssh.gitea.dev.72602.online
              SSH_PORT: 32022
              SSH_AUTHORIZED_PRINCIPALS_ALLOW: email
            admin:
              DISABLE_REGULAR_ORG_CREATION: true
            security:
              INSTALL_LOCK: true
            service:
              REGISTER_EMAIL_CONFIRM: true
              DISABLE_REGISTRATION: true
              ENABLE_NOTIFY_MAIL: false
              DEFAULT_ALLOW_CREATE_ORGANIZATION: false
              SHOW_MILESTONES_DASHBOARD_PAGE: false
            migrations:
              ALLOW_LOCALNETWORKS: true
            mailer:
              ENABLED: false
            i18n:
              LANGS: "en-US,zh-CN"
              NAMES: "English,็ฎ€ไฝ“ไธญๆ–‡"
            oauth2:
              ENABLE: false
  destination:
    server: https://kubernetes.default.svc
    namespace: application
sssss

3.apply to k8s

Details
kubectl -n argocd apply -f gitea.yaml

4.sync by argocd

Details
argocd app sync argocd/gitea

5.decode admin password

login ๐Ÿ”—https://gitea.dev.72602.online:32443/

, using user gitea_admin and password
Details
kubectl -n application get secret gitea-admin-credentials -o jsonpath='{.data.password}' | base64 -d

FAQ

Q1: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Q2: Show me almost endless possibilities

You can add standard markdown syntax:

  • multiple paragraphs
  • bullet point lists
  • emphasized, bold and even bold emphasized text
  • links
  • etc.
...and even source code

the possibilities are endless (almost - including other shortcodes may or may not work)

Jun 7, 2025

HPC

    Mar 7, 2024

    Subsections of MCP Related

    MCP Inspector

    ๐Ÿš€Installation

    Install By

    1.get helm repo

    Details
    helm repo add xxxxx https://xxxx
    helm repo update

    2.install chart

    Details
    helm install xxxxx/chart-name --generate-name --version a.b.c
    Using AY Helm Mirror

    for more information, you can check ๐Ÿ”—https://github.com/AaronYang0628/helm-chart-mirror

    helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
      helm repo update
      helm install ay-helm-mirror/chart-name --generate-name --version a.b.c

    1.prepare `xxxxx-credentials.yaml`

    Details

    2.prepare `deploy-xxxxx.yaml`

    Details
    kubectl -n argocd apply -f -<< EOF
    apiVersion: argoproj.io/v1alpha1
    kind: Application
    metadata:
      name: xxxx
    spec:
      project: default
      source:
        repoURL: https://xxxxx
        chart: xxxx
        targetRevision: a.b.c
    EOF

    3.sync by argocd

    Details
    argocd app sync argocd/xxxx
    Using AY Helm Mirror

    for more information, you can check ๐Ÿ”—https://github.com/AaronYang0628/helm-chart-mirror

    helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
      helm repo update
      helm install ay-helm-mirror/chart-name --generate-name --version a.b.c
    Using AY ACR Image Mirror
    Using DaoCloud Mirror

    1.init server

    Details
    Using AY ACR Image Mirror
    Using DaoCloud Mirror

    1.prepare `argocd-login-credentials`

    Details
    kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database

    2.apply rolebinding to k8s

    4.prepare `deploy-xxxx-flow.yaml`

    Details

    5.submit to argo workflow client

    Details
    argo -n business-workflows submit deploy-xxxx-flow.yaml

    7.decode password

    Details
    kubectl -n application get secret xxxx-credentials -o jsonpath='{.data.xxx-password}' | base64 -d

    1.init server

    Details
    Using AY ACR Image Mirror
    Using DaoCloud Mirror

    ๐Ÿ›Ž๏ธFAQ

    Q1: Show me almost endless possibilities

    You can add standard markdown syntax:

    • multiple paragraphs
    • bullet point lists
    • emphasized, bold and even bold emphasized text
    • links
    • etc.
    ...and even source code

    the possibilities are endless (almost - including other shortcodes may or may not work)

    Q2: Show me almost endless possibilities

    You can add standard markdown syntax:

    • multiple paragraphs
    • bullet point lists
    • emphasized, bold and even bold emphasized text
    • links
    • etc.
    ...and even source code

    the possibilities are endless (almost - including other shortcodes may or may not work)

    Jun 7, 2024

    Subsections of Monitor

    Install Homepage

    Official Documentation: https://gethomepage.dev/

    Installation

    Install By

    Preliminary

    1. Kubernetes is installed; if not, check ๐Ÿ”—link


    2. Helm is installed; if not, check ๐Ÿ”—link


    1.install chart directly

    Details
    helm install homepage oci://ghcr.io/m0nsterrr/helm-charts/homepage

    2.you can modify the values.yaml and re-install

    Related values files
    Details
    helm install homepage oci://ghcr.io/m0nsterrr/helm-charts/homepage -f homepage.values.yaml
    Using Mirror
    helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts \
      && helm install ay-helm-mirror/homepage  --generate-name --version 4.2.0

    for more information, you can check ๐Ÿ”—https://aaronyang0628.github.io/helm-chart-mirror/

    Preliminary

    1. Kubernetes is installed; if not, check ๐Ÿ”—link


    2. ArgoCD is installed; if not, check ๐Ÿ”—link


    3. Helm binary is installed; if not, check ๐Ÿ”—link


    4. Ingress is installed on ArgoCD; if not, check ๐Ÿ”—link


    1.prepare `homepage.yaml`

    Details
    kubectl -n argocd apply -f - << EOF
      apiVersion: argoproj.io/v1alpha1
      kind: Application
      metadata:
        name: homepage
      spec:
        syncPolicy:
          syncOptions:
            - CreateNamespace=true
            - ServerSideApply=true
        project: default
        source:
          repoURL: oci://ghcr.io/m0nsterrr/helm-charts/homepage
          chart: homepage
          targetRevision: 4.2.0
          helm:
            releaseName: homepage
            values: |
              image:
                registry: m.daocloud.io/ghcr.io
                repository: gethomepage/homepage
                pullPolicy: IfNotPresent
                tag: "v1.5.0"
              config:
                allowedHosts: 
                - "home.72602.online"
              ingress:
                enabled: true
                ingressClassName: "nginx"
                annotations:
                  kubernetes.io/ingress.class: nginx
                hosts:
                  - host: home.72602.online
                    paths:
                      - path: /
                        pathType: ImplementationSpecific
              resources:
                limits:
                  cpu: 500m
                  memory: 512Mi
                requests:
                  cpu: 100m
                  memory: 128Mi
        destination:
          server: https://kubernetes.default.svc
          namespace: monitor
    EOF

    3.sync by argocd

    Details
    argocd app sync argocd/homepage

    5.check the web browser

    Details
    K8S_MASTER_IP=$(kubectl get nodes --selector=node-role.kubernetes.io/control-plane -o jsonpath='{$.items[0].status.addresses[?(@.type=="InternalIP")].address}')
    echo "$K8S_MASTER_IP home.72602.online" >> /etc/hosts

    Preliminary

    1. Kubernetes is installed; if not, check ๐Ÿ”—link


    2. Docker is installed; if not, check ๐Ÿ”—link


    docker run -d \
    --name homepage \
    -e HOMEPAGE_ALLOWED_HOSTS=47.110.67.161:3000 \
    -e PUID=1000 \
    -e PGID=1000 \
    -p 3000:3000 \
    -v /root/home-site/static/icons:/app/public/icons  \
    -v /root/home-site/content/Ops/HomePage/config:/app/config \
    -v /var/run/docker.sock:/var/run/docker.sock:ro \
    --restart unless-stopped \
    ghcr.io/gethomepage/homepage:v1.5.0

    Preliminary

    1. Kubernetes is installed; if not, check ๐Ÿ”—link


    2. Podman is installed; if not, check ๐Ÿ”—link


    podman run -d \
    --name homepage \
    -e HOMEPAGE_ALLOWED_HOSTS=127.0.0.1:3000 \
    -e PUID=1000 \
    -e PGID=1000 \
    -p 3000:3000 \
    -v /root/home-site/static/icons:/app/public/icons \
    -v /root/home-site/content/Ops/HomePage/config:/app/config \
    --restart unless-stopped \
    ghcr.io/gethomepage/homepage:v1.5.0

    FAQ

    Q1: Show me almost endless possibilities

    You can add standard markdown syntax:

    • multiple paragraphs
    • bullet point lists
    • emphasized, bold and even bold emphasized text
    • links
    • etc.
    ...and even source code

    the possibilities are endless (almost - including other shortcodes may or may not work)

    Q2: Show me almost endless possibilities

    You can add standard markdown syntax:

    • multiple paragraphs
    • bullet point lists
    • emphasized, bold and even bold emphasized text
    • links
    • etc.
    ...and even source code

    the possibilities are endless (almost - including other shortcodes may or may not work)

    Oct 7, 2025

    Install Langfuse

    Official Documentation: https://langfuse.com/docs

    ๐Ÿš€Installation

    Install By

    Preliminary

    1. Kubernetes is installed; if not, check ๐Ÿ”—link


    2. Helm is installed; if not, check ๐Ÿ”—link


    3. Ingress is installed; if not, check ๐Ÿ”—link


    4. Cert-Manager is installed; if not, check ๐Ÿ”—link


    1.prepare namespace and secrets

    Details
    kubectl get namespaces monitor > /dev/null 2>&1 || kubectl create namespace monitor
    
    kubectl -n monitor create secret generic langfuse-secret \
      --from-literal=NEXTAUTH_SECRET=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 32) \
      --from-literal=SALT=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 32)

    2.prepare `langfuse.values.yaml`

    Details
    # Minimal example. Adjust storage classes, resource limits, and domain before production use.
    ingress:
      enabled: true
      className: nginx
      annotations:
        cert-manager.io/cluster-issuer: self-signed-ca-issuer
      hosts:
        - host: langfuse.dev.72602.online
          paths:
            - path: /
              pathType: Prefix
      tls:
        - secretName: langfuse.dev.72602.online-tls
          hosts:
            - langfuse.dev.72602.online
    
    env:
      NEXTAUTH_URL: https://langfuse.dev.72602.online
      TELEMETRY_ENABLED: "false"
    
    # Use external databases in production.
    postgresql:
      enabled: true
    redis:
      enabled: true
    clickhouse:
      enabled: true

    3.install chart

    Details
    helm repo add langfuse https://langfuse.github.io/langfuse-k8s
    helm repo update
    
    helm upgrade --install langfuse langfuse/langfuse \
      -n monitor \
      -f langfuse.values.yaml \
      --atomic

    4.monitor status

    Details
    kubectl -n monitor get pods
    kubectl -n monitor get ingress
    kubectl -n monitor logs deploy/langfuse-web --tail=100

    Preliminary

    1. Kubernetes is installed; if not, check ๐Ÿ”—link


    2. Helm is installed; if not, check ๐Ÿ”—link


    3. ArgoCD is installed; if not, check ๐Ÿ”—link


    1.prepare `langfuse-app.yaml`

    Details
    kubectl -n argocd apply -f - <<'EOF'
    apiVersion: argoproj.io/v1alpha1
    kind: Application
    metadata:
      name: langfuse
      namespace: argocd
    spec:
      project: default
      source:
        repoURL: https://langfuse.github.io/langfuse-k8s
        chart: langfuse
        targetRevision: 1.0.0
        helm:
          values: |
            ingress:
              enabled: true
              className: nginx
              annotations:
                cert-manager.io/cluster-issuer: self-signed-ca-issuer
              hosts:
                - host: langfuse.dev.72602.online
                  paths:
                    - path: /
                      pathType: Prefix
              tls:
                - secretName: langfuse.dev.72602.online-tls
                  hosts:
                    - langfuse.dev.72602.online
            env:
              NEXTAUTH_URL: https://langfuse.dev.72602.online
              TELEMETRY_ENABLED: "false"
            postgresql:
              enabled: true
            redis:
              enabled: true
            clickhouse:
              enabled: true
      destination:
        server: https://kubernetes.default.svc
        namespace: monitor
      syncPolicy:
        syncOptions:
          - CreateNamespace=true
          - ServerSideApply=true
    EOF

    2.sync by argocd

    Details
    argocd app sync argocd/langfuse

    3.monitor status

    Details
    argocd app get argocd/langfuse
    kubectl -n monitor get pods
    kubectl -n monitor get ingress

    Verify

    Details
    K8S_MASTER_IP=$(kubectl get nodes --selector=node-role.kubernetes.io/control-plane -o jsonpath='{$.items[0].status.addresses[?(@.type=="InternalIP")].address}')
    echo "$K8S_MASTER_IP langfuse.dev.72602.online" | sudo tee -a /etc/hosts
    
    curl -kI https://langfuse.dev.72602.online

    If response status is 200 or 302, open https://langfuse.dev.72602.online in browser.

    May 8, 2026

    Install Permetheus Stack

    Installation

    Install By

    Preliminary

    1. Kubernetes is installed; if not, check ๐Ÿ”—link


    2. Helm is installed; if not, check ๐Ÿ”—link


    1.get helm repo

    Details
    helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
    helm repo update

    2.install chart

    Details
    helm install ay-helm-mirror/kube-prometheus-stack --generate-name
    Using Mirror
    helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts \
      && helm install ay-helm-mirror/kube-prometheus-stack  --generate-name --version 1.17.2

    for more information, you can check ๐Ÿ”—https://aaronyang0628.github.io/helm-chart-mirror/

    Preliminary

    1. Kubernetes is installed; if not, check ๐Ÿ”—link


    2. ArgoCD is installed; if not, check ๐Ÿ”—link


    3. Helm binary is installed; if not, check ๐Ÿ”—link


    4. Ingress is installed on ArgoCD; if not, check ๐Ÿ”—link


    1.prepare `chart-museum-credentials`

    Details
    kubectl get namespaces monitor > /dev/null 2>&1 || kubectl create namespace monitor
    kubectl -n monitor create secret generic prometheus-stack-credentials \
      --from-literal=grafana-username=admin \
      --from-literal=grafana-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

    2.prepare `prometheus-stack.yaml`

    Details
    kubectl -n argocd apply -f - << EOF
      apiVersion: argoproj.io/v1alpha1
      kind: Application
      metadata:
        name: prometheus-stack
      spec:
        syncPolicy:
          syncOptions:
            - CreateNamespace=true
            - ServerSideApply=true
        project: default
        source:
          repoURL: https://aaronyang0628.github.io/helm-chart-mirror/charts
          chart: kube-prometheus-stack
          targetRevision: 72.9.1
          helm:
            releaseName: prometheus-stack
            values: |
              crds:
                enabled: true
              global:
                rbac:
                  create: true
                imageRegistry: ""
                imagePullSecrets: []
              alertmanager:
                enabled: true
                ingress:
                  enabled: false
                serviceMonitor:
                  selfMonitor: true
                  interval: ""
                alertmanagerSpec:
                  image:
                    registry: m.daocloud.io/quay.io
                    repository: prometheus/alertmanager
                    tag: v0.28.1
                  replicas: 1
                  resources: {}
                  storage:
                    volumeClaimTemplate:
                      spec:
                        storageClassName: ""
                        accessModes: ["ReadWriteOnce"]
                        resources:
                          requests:
                            storage: 2Gi
              grafana:
                enabled: true
                ingress:
                  enabled: true
                  annotations:
                    cert-manager.io/clusterissuer: self-signed-issuer
                    kubernetes.io/ingress.class: nginx
                  hosts:
                    - grafana.dev.72602.online
                  path: /
                  pathtype: ImplementationSpecific
                  tls:
                  - secretName: grafana.dev.72602.online-tls
                    hosts:
                    - grafana.dev.72602.online
              prometheusOperator:
                admissionWebhooks:
                  patch:
                    resources: {}
                    image:
                      registry: m.daocloud.io/registry.k8s.io
                      repository: ingress-nginx/kube-webhook-certgen
                      tag: v1.5.3  
                image:
                  registry: m.daocloud.io/quay.io
                  repository: prometheus-operator/prometheus-operator
                prometheusConfigReloader:
                  image:
                    registry: m.daocloud.io/quay.io
                    repository: prometheus-operator/prometheus-config-reloader
                  resources: {}
                thanosImage:
                  registry: m.daocloud.io/quay.io
                  repository: thanos/thanos
                  tag: v0.38.0
              prometheus:
                enabled: true
                ingress:
                  enabled: true
                  annotations:
                    cert-manager.io/clusterissuer: self-signed-issuer
                    kubernetes.io/ingress.class: nginx
                  hosts:
                    - prometheus.dev.72602.online
                  path: /
                  pathtype: ImplementationSpecific
                  tls:
                  - secretName: prometheus.dev.72602.online-tls
                    hosts:
                    - prometheus.dev.72602.online
                prometheusSpec:
                  image:
                    registry: m.daocloud.io/quay.io
                    repository: prometheus/prometheus
                    tag: v3.4.0
                  replicas: 1
                  shards: 1
                  resources: {}
                  storageSpec: 
                    volumeClaimTemplate:
                      spec:
                        storageClassName: ""
                        accessModes: ["ReadWriteOnce"]
                        resources:
                          requests:
                            storage: 2Gi
              thanosRuler:
                enabled: false
                ingress:
                  enabled: false
                thanosRulerSpec:
                  replicas: 1
                  storage: {}
                  resources: {}
                  image:
                    registry: m.daocloud.io/quay.io
                    repository: thanos/thanos
                    tag: v0.38.0
        destination:
          server: https://kubernetes.default.svc
          namespace: monitor
    EOF

    3.sync by argocd

    Details
    argocd app sync argocd/prometheus-stack

    4.extract clickhouse admin credentials

    Details
      kubectl -n monitor get secret prometheus-stack-credentials -o jsonpath='{.data.grafana-password}' | base64 -d

    5.check the web browser

    Details
      > add `$K8S_MASTER_IP grafana.dev.72602.online` to **/etc/hosts**
    
      > add `$K8S_MASTER_IP prometheus.dev.72602.online` to **/etc/hosts**
    prometheus-server: https://prometheus.dev.72602.online:32443/


    grafana-console: https://grafana.dev.72602.online:32443/


    install based on docker

    echo  "start from head is important"

    FAQ

    Q1: Show me almost endless possibilities

    You can add standard markdown syntax:

    • multiple paragraphs
    • bullet point lists
    • emphasized, bold and even bold emphasized text
    • links
    • etc.
    ...and even source code

    the possibilities are endless (almost - including other shortcodes may or may not work)

    Q2: Show me almost endless possibilities

    You can add standard markdown syntax:

    • multiple paragraphs
    • bullet point lists
    • emphasized, bold and even bold emphasized text
    • links
    • etc.
    ...and even source code

    the possibilities are endless (almost - including other shortcodes may or may not work)

    Jun 7, 2024

    UptimeKuma

    Web Page

    uptime-kuma (https://uptime.72602.space)

    Deployment

    Depoly For
    Details
    kubectl get namespace monitor > /dev/null 2>&1 || kubectl create namespace monitor
    kubectl -n monitor apply -f manifests/uptimekuma/
    Notes: - Uptime Kuma is exposed only through k8s ingress (`uptime.72602.space`). - Do not bind ECS host ports 80/443 for local reverse proxies, they are reserved for forwarding to miniPC ingress. ### ZJLAB Tunnel Push Monitors ZJLAB's `primary` and `backup` tunnel listeners are loopback-only on the relay. Uptime Kuma cannot reach them directly from the Kubernetes Pod, so do not create TCP monitors that target those private listeners. Use one Push monitor per tunnel instead. Create these monitors in the Uptime Kuma UI: | Field | `ZJLAB primary` | `ZJLAB backup` | | --- | --- | --- | | Monitor type | `Push` | `Push` | | Heartbeat interval | Match the ECS check-only monitor interval | Match the ECS check-only monitor interval | | Monitor timeout | Longer than one normal check interval and its network timeout | Longer than one normal check interval and its network timeout | | Notifications | Use the existing notification policy | Use the existing notification policy | Save each monitor and keep its generated Push URL secret. Store the URLs only in the private SOPS inventory used by the ECS check-only monitor. The monitor must send `status=up` after a successful tunnel check and `status=down` with a fixed reason after a failed check. Do not put Push URLs in this repository, tunnel unit files, public pages, or ordinary logs. After the Push monitors are created: 1. Pause the old TCP monitors for the private ZJLAB listeners. They cannot reach relay loopback addresses from the Kuma Pod and will remain in timeout. 2. Add the two Push URLs to the ECS monitor's secret-backed configuration. 3. Send one controlled heartbeat for each label and confirm both monitors show `Up` with a recent heartbeat. 4. Confirm a failed check changes only the matching monitor to `Down`, then restore the heartbeat and confirm it returns to `Up`. The private inventory owns the exact check interval, Push URLs, monitor unit, and rollback procedure. The public runbook intentionally omits those values. ### ZJLAB Relay HTTP Monitors The two important ZJLAB `dev` relay Deployments are monitored through their public business paths. Do not target their ECS loopback listeners from Kuma; those listeners are intentionally private. Create these monitors in the Uptime Kuma UI and attach the existing notification policy: | Name | Type | URL | Accepted status code | |---|---|---|---| | `ZJLAB MaaS Relay` | HTTP(s) | `https://llm.72602.space/` | `404` | | `ZJLAB NewAPI Relay` | HTTP(s) | `https://newapi.zjlab.72602.space/v1/models` | `401` | Use a 60-second interval, 15-second timeout, and three retries. The NewAPI probe is deliberately unauthenticated, so `401` is the expected healthy response. Accept only the exact status listed for each monitor; `502`, timeout, TLS failure, or another status must remain a failure. The completed ECS integration maps listener `10023` to the ZJLAB `primary` check and listener `10024` to `backup`. These are independent of the 72602 public tunnel listeners `10021` and `10022`. The ECS checker sends `up` after a healthy check and `down` with a fixed reason after a failed check. Push request failures are best-effort and do not alter checker judgment, DingTalk debounce, or tunnel lifecycle. Existing query parameters are preserved without adding a second `?`. Verification recorded healthy dry-run and service results for both labels over more than two complete 60-second cycles. Monitoring rollback restores the root-only ECS backup and encrypted private inventory backup, then restarts only the ZJLAB healthcheck service.

    Subsections of Networking

    DNS Setup

    Overview

    For any self-hosted service to be accessible via browser, you need:

    1. A domain name (e.g. 72602.online)
    2. DNS A records pointing each subdomain to your public IP
    3. (Optional) cert-manager for automatic TLS certificates

    72602 Cluster DNS

    All subdomains use A records โ†’ 47.110.67.161 (ECS public IP):

    72602.online                  A  47.110.67.161
    argocd.72602.online           A  47.110.67.161
    ops.docs.72602.online         A  47.110.67.161
    token.72602.space             A  47.110.67.161
    home.72602.online             A  47.110.67.161
    n8n.72602.online              A  47.110.67.161
    webhook.n8n.72602.online      A  47.110.67.161
    ops.agent.72602.online        A  47.110.67.161
    uptime.72602.space            A  47.110.67.161
    clash.72602.online            A  47.110.67.161
    api.minio.72602.online        A  47.110.67.161
    console.minio.72602.online    A  47.110.67.161

    Add these records in your DNS provider (Cloudflare / Aliyun DNS / etc.).

    Traffic Flow

    Browser โ†’ A record โ†’ 47.110.67.161:443
                             โ†“ ECS sshd (reverse tunnel from minipc)
                           127.0.0.1:32443 (minipc ingress-nginx NodePort via SSH -R)
                             โ†“ ingress-nginx NodePort
                          k3s ingress controller
                             โ†“ Ingress rules
                          Service โ†’ Pod

    TLS Certificates

    With ingress-nginx + cert-manager, TLS is automatic:

    1. Install cert-manager (see Installation/Networking/Cert_Manager.md)
    2. Create a ClusterIssuer named lets-encrypt
    3. Each Ingress gets annotation cert-manager.io/cluster-issuer: lets-encrypt
    4. cert-manager automatically provisions TLS certificates via HTTP-01 challenge

    โš ๏ธ For clusters behind NAT/SSH reverse tunnel (like 72602), HTTP-01 validation requires the domain to resolve to the public IP and port 80/443 to reach the cluster. This works because ECS forwards 80/443 โ†’ minipc NodePort via SSH reverse tunnel (managed by autossh systemd services).

    Prerequisites

    Before deploying any app, ensure:

    • Domain registered and DNS manageable
    • k3s cluster running
    • ingress-nginx installed (NodePort mode)
    • cert-manager installed with lets-encrypt ClusterIssuer
    • ArgoCD installed
    • DNS A records added for each target subdomain
    May 12, 2026

    Install Cert Manager

    Installation

    Install By

    Preliminary

    1. Kubernetes is installed; if not, check ๐Ÿ”—link


    2. Helm binary is installed; if not, check ๐Ÿ”—link


    1.get helm repo

    Details
    helm repo add cert-manager-repo https://charts.jetstack.io
    helm repo update

    2.install chart

    Details
    helm install cert-manager-repo/cert-manager --generate-name --version 1.20.2
    Using Mirror
    helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts \
      && helm install ay-helm-mirror/cert-manager --generate-name --version 1.20.2

    for more information, you can check ๐Ÿ”—https://aaronyang0628.github.io/helm-chart-mirror/

    Preliminary

    1. Kubernetes is installed; if not, check ๐Ÿ”—link


    2. ArgoCD is installed; if not, check ๐Ÿ”—link


    3. Helm binary is installed; if not, check ๐Ÿ”—link


    1.prepare `cert-manager.yaml`

    kubectl -n argocd apply -f https://raw.githubusercontent.com/AaronYang0628/docs/main/manifests/zjlab/cert-manager.yaml
    kubectl -n argocd apply -f - << EOF
    apiVersion: argoproj.io/v1alpha1
    kind: Application
    metadata:
      name: cert-manager
    spec:
      syncPolicy:
        syncOptions:
        - CreateNamespace=true
      project: default
      source:
        repoURL: https://aaronyang0628.github.io/helm-chart-mirror/charts
        chart: cert-manager
        targetRevision: 1.20.2
        helm:
          releaseName: cert-manager
          values: |
            installCRDs: true
            image:
              repository: m.daocloud.io/quay.io/jetstack/cert-manager-controller
              tag: v1.20.2
            webhook:
              image:
                repository: m.daocloud.io/quay.io/jetstack/cert-manager-webhook
                tag: v1.20.2
            cainjector:
              image:
                repository: m.daocloud.io/quay.io/jetstack/cert-manager-cainjector
                tag: v1.20.2
            acmesolver:
              image:
                repository: m.daocloud.io/quay.io/jetstack/cert-manager-acmesolver
                tag: v1.20.2
            startupapicheck:
              image:
                repository: m.daocloud.io/quay.io/jetstack/cert-manager-startupapicheck
                tag: v1.20.2
      destination:
        server: https://kubernetes.default.svc
        namespace: basic-components
    EOF
    kubectl -n argocd apply -f - << EOF
    apiVersion: argoproj.io/v1alpha1
    kind: Application
    metadata:
      name: cert-manager
    spec:
      syncPolicy:
        syncOptions:
        - CreateNamespace=true
      project: default
      source:
        repoURL: https://charts.jetstack.io
        chart: cert-manager
        targetRevision: 1.20.2
        helm:
          releaseName: cert-manager
          values: |
            installCRDs: true
            image:
              repository: m.daocloud.io/quay.io/jetstack/cert-manager-controller
              tag: v1.20.2
            webhook:
              image:
                repository: m.daocloud.io/quay.io/jetstack/cert-manager-webhook
                tag: v1.20.2
            cainjector:
              image:
                repository: m.daocloud.io/quay.io/jetstack/cert-manager-cainjector
                tag: v1.20.2
            acmesolver:
              image:
                repository: m.daocloud.io/quay.io/jetstack/cert-manager-acmesolver
                tag: v1.20.2
            startupapicheck:
              image:
                repository: m.daocloud.io/quay.io/jetstack/cert-manager-startupapicheck
                tag: v1.20.2        
      destination:
        server: https://kubernetes.default.svc
        namespace: basic-components
    EOF

    2.sync by argocd

    Details
    argocd app sync argocd/cert-manager

    Preliminary

    1. Docker|Podman|Buildah is installed; if not, check ๐Ÿ”—link


    1.just run

    Details
    docker run --name cert-manager -e ALLOW_EMPTY_PASSWORD=yes bitnami/cert-manager:latest
    Using Proxy

    you can run an addinational daocloud image to accelerate your pulling, check Daocloud Proxy

    docker run --name cert-manager \
      -e ALLOW_EMPTY_PASSWORD=yes 
      m.daocloud.io/docker.io/bitnami/cert-manager:latest

    Preliminary

    1. Kubernetes is installed; if not, check ๐Ÿ”—link


    1.just run

    Details
    kubectl create -f https://github.com/jetstack/cert-manager/releases/download/v1.20.2/cert-manager.yaml

    Prepare Certificate Issuer

    kubectl apply  -f - <<EOF
    ---
    apiVersion: cert-manager.io/v1
    kind: Issuer
    metadata:
      namespace: basic-components
      name: self-signed-issuer
    spec:
      selfSigned: {}
    
    ---
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      namespace: basic-components
      name: my-self-signed-ca
    spec:
      isCA: true
      commonName: my-self-signed-ca
      secretName: root-secret
      privateKey:
        algorithm: ECDSA
        size: 256
      issuerRef:
        name: self-signed-issuer
        kind: Issuer
        group: cert-manager.io
    
    ---
    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: self-signed-ca-issuer
    spec:
      ca:
        secretName: root-secret
    EOF
    kubectl apply -f - << EOF
    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: lets-encrypt
    spec:
      acme:
        email: byang628@zhejianglab.org
        server: https://acme-v02.api.letsencrypt.org/directory
        privateKeySecretRef:
          name: letsencrypt-account-key
        solvers:
        - http01:
            ingress:
              class: nginx
    EOF
    kubectl -n kube-system apply -f - << EOF
    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: lets-encrypt
    spec:
      acme:
        email: aaron19940628@gmail.com
        server: https://acme-v02.api.letsencrypt.org/directory
        privateKeySecretRef:
          name: letsencrypt-account-key
        solvers:
        - http01:
            ingress:
              class: nginx
    EOF

    FAQ

    Q1: cert-manager Pods are not ready

    Symptom

    • cert-manager, cert-manager-webhook, or cert-manager-cainjector Pods keep restarting.

    Check

    kubectl -n basic-components get pods | grep cert-manager
    kubectl -n basic-components describe pod -l app.kubernetes.io/name=cert-manager
    kubectl -n basic-components logs deploy/cert-manager --tail=100

    Fix

    • Ensure CRDs are installed (installCRDs: true in Helm values).
    • Re-sync app: argocd app sync argocd/cert-manager.
    • If image pull fails, switch to mirror image settings shown above.

    Expected

    • All cert-manager Pods become Running and READY 1/1.
    Q2: Certificate stays in Pending or Ingress has no TLS secret

    Symptom

    • Ingress TLS secret is not created, or Certificate status does not become Ready.

    Check

    kubectl get clusterissuer
    kubectl -n basic-components get certificate
    kubectl -n basic-components describe certificate <certificate-name>
    kubectl -n basic-components get secret root-secret

    Fix

    • Confirm ClusterIssuer exists (self-signed-ca-issuer or lets-encrypt).
    • Ensure Ingress annotation matches issuer name: cert-manager.io/cluster-issuer.
    • Re-apply issuer manifest and then re-apply ingress.

    Expected

    • Target certificate shows Ready=True and TLS secret exists.

    FAQ

    Q1: The browser doesn’t trust this self-signed certificate

    Basically, you need to import the certificate into your browser.

    kubectl -n basic-components get secret root-secret -o jsonpath='{.data.tls\.crt}' | base64 -d > cert-manager-self-signed-ca-secret.crt

    And then import it into your browser.

    Q2: Show me almost endless possibilities

    You can add standard markdown syntax:

    • multiple paragraphs
    • bullet point lists
    • emphasized, bold and even bold emphasized text
    • links
    • etc.
    ...and even source code

    the possibilities are endless (almost - including other shortcodes may or may not work)

    Jun 7, 2024

    Install HAProxy

    ๐Ÿš€Installation

    Environment
    Install By

    1.prepare ECS host and backups

    ssh root@47.110.67.161 hostname
    sudo ss -ltnp
    sudo test -e /etc/haproxy || echo absent

    Back up /etc/haproxy before installing. Keep the backup outside tracked source. The 72602 mail change also keeps the reverse-tunnel unit backup on the minipc.

    2.install Ubuntu package

    sudo apt-get install --no-install-recommends haproxy

    Do not run upgrade, full-upgrade, or dist-upgrade. Ubuntu may start the package service during installation; stop it before replacing the default configuration and before the tunnel backends are ready.

    3.configure TCP passthrough

    /etc/haproxy/haproxy.cfg must use mode tcp, bind public IPv4 and IPv6 25, 465, 587, and 993, and send PROXY v2 to:

    127.0.0.1:10225
    127.0.0.1:10465
    127.0.0.1:10587
    127.0.0.1:10993

    Do not terminate TLS or configure HTTP, relay, or authentication in HAProxy. Validate before starting it:

    haproxy -c -f /etc/haproxy/haproxy.cfg

    4.start after tunnel verification

    # Confirm the four ECS loopback backends are sshd listeners first.
    sudo ss -ltnp
    sudo systemctl enable --now haproxy
    sudo systemctl is-active haproxy
    sudo systemctl is-enabled haproxy
    sudo ss -ltnp

    The public mail ports must belong to haproxy; only the four high ports on 127.0.0.1 may belong to the tunnel sshd.

    5.rollback

    sudo systemctl stop haproxy
    # Restore the saved 10022 unit on 72602-minipc, daemon-reload, restart only 10022.

    Do not restore an old HAProxy configuration or uninstall the package as part of this rollback. Preserve Mailu Secrets and PVCs.

    ๐Ÿ›Ž๏ธFAQ

    Mailu does not accept PROXY protocol

    Check the transport source that reaches the Mailu front Pod. The current 72602 hostPort path is observed as 10.42.0.1, while the current Git values use realIpFrom=127.0.0.1/32. Dovecot logs Client not trusted when these do not match, and TLS/STARTTLS can close before negotiation. Correct the source or trust boundary in Git, wait for automatic ArgoCD reconciliation, and repeat the protocol and no-DATA relay checks. Do not manually patch or restart Mailu.

    Mar 7, 2024

    Install Ingress

    Installation

    Install By

    Preliminary

    1. Kubernetes is installed; if not, check ๐Ÿ”—link


    2. Helm is installed; if not, check ๐Ÿ”—link


    1.get helm repo

    Details
    helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
    helm repo update

    2.install chart

    Details
    helm install ingress-nginx/ingress-nginx --generate-name
    Using Mirror
    helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts &&
      helm install ay-helm-mirror/ingress-nginx --generate-name --version 4.15.1

    for more information, you can check ๐Ÿ”—https://aaronyang0628.github.io/helm-chart-mirror/

    Preliminary

    1. Kubernetes is installed; if not, check ๐Ÿ”—link


    2. ArgoCD is installed; if not, check ๐Ÿ”—link


    1.prepare `ingress-nginx.yaml`

    ```shell kubectl -n argocd apply -f https://raw.githubusercontent.com/AaronYang0628/docs/main/manifests/zjlab/ingress-nginx.yaml ```

    Details
    kubectl -n argocd apply -f - <<EOF
    apiVersion: argoproj.io/v1alpha1
    kind: Application
    metadata:
      name: ingress-nginx
    spec:
      syncPolicy:
        syncOptions:
        - CreateNamespace=true
      project: default
      source:
        repoURL: https://kubernetes.github.io/ingress-nginx
        chart: ingress-nginx
        targetRevision: 4.15.1
        helm:
          releaseName: ingress-nginx
          values: |
            controller:
              image:
                registry: m.daocloud.io/registry.k8s.io
              service:
                enabled: true
                type: NodePort
                nodePorts:
                  http: 32080
                  https: 32443
                  tcp:
                    8080: 32808
                    5324: 33224 #pg
              resources:
                requests:
                  cpu: 100m
                  memory: 128Mi
              admissionWebhooks:
                enabled: true
                patch:
                  enabled: true
                  image:
                    registry: m.daocloud.io/registry.k8s.io
            metrics:
              enabled: false
            defaultBackend:
              enabled: false
              image:
                registry: m.daocloud.io/registry.k8s.io
      destination:
        server: https://kubernetes.default.svc
        namespace: basic-components
    EOF

    [Optional] 2.apply to k8s

    Details
    kubectl -n argocd apply -f ingress-nginx.yaml

    3.sync by argocd

    Details
    argocd app sync argocd/ingress-nginx

    FAQ

    Q1: Ingress created but cannot access the domain

    Symptom

    • curl -k https://<your-domain> fails or times out.

    Check

    kubectl -n basic-components get svc
    kubectl -n basic-components get pod -l app.kubernetes.io/component=controller
    kubectl -n basic-components get ingress

    Fix

    • Confirm your domain resolves to the node IP (or add /etc/hosts entry).
    • Ensure ingress-nginx Service exposes NodePort 32443 for HTTPS.
    • Re-sync app: argocd app sync argocd/ingress-nginx.

    Expected

    • Ingress controller Pods are Running and HTTPS endpoint is reachable.
    Q2: Using minikube and NodePort is unreachable

    Symptom

    • Browser cannot open https://$(minikube ip):32443.

    Check and fix

    kubectl -n basic-components get svc
    ssh -i ~/.minikube/machines/minikube/id_rsa docker@$(minikube ip) -L '*:30443:0.0.0.0:30443' -N -f
    ssh -i ~/.minikube/machines/minikube/id_rsa docker@$(minikube ip) -L '*:32443:0.0.0.0:32443' -N -f
    ssh -i ~/.minikube/machines/minikube/id_rsa docker@$(minikube ip) -L '*:32080:0.0.0.0:32080' -N -f

    Expected

    • You can access the ingress endpoint through forwarded ports.
    Jun 7, 2024

    Install Istio

    Installation

    Install By

    Preliminary

    1. Kubernetes is installed; if not, check ๐Ÿ”—link


    2. Helm is installed; if not, check ๐Ÿ”—link


    1.get helm repo

    Details
    helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
    helm repo update

    2.install chart

    Details
    helm install ay-helm-mirror/kube-prometheus-stack --generate-name
    Using Proxy

    Preliminary

    1. Kubernetes is installed; if not, check ๐Ÿ”—link


    2. Helm is installed; if not, check ๐Ÿ”—link


    3. ArgoCD is installed; if not, check ๐Ÿ”—link


    1.prepare `deploy-istio-base.yaml`

    Details
    kubectl -n argocd apply -f - << EOF
    apiVersion: argoproj.io/v1alpha1
    kind: Application
    metadata:
      name: istio-base
    spec:
      syncPolicy:
        syncOptions:
        - CreateNamespace=true
      project: default
      source:
        repoURL: https://istio-release.storage.googleapis.com/charts
        chart: base
        targetRevision: 1.23.2
        helm:
          releaseName: istio-base
          values: |
            defaults:
              global:
                istioNamespace: istio-system
              base:
                enableCRDTemplates: false
                enableIstioConfigCRDs: true
              defaultRevision: "default"
      destination:
        server: https://kubernetes.default.svc
        namespace: istio-system
    EOF

    2.sync by argocd

    Details
    argocd app sync argocd/istio-base

    3.prepare `deploy-istiod.yaml`

    Details
    kubectl -n argocd apply -f - << EOF
    apiVersion: argoproj.io/v1alpha1
    kind: Application
    metadata:
      name: istiod
    spec:
      syncPolicy:
        syncOptions:
        - CreateNamespace=true
      project: default
      source:
        repoURL: https://istio-release.storage.googleapis.com/charts
        chart: istiod
        targetRevision: 1.23.2
        helm:
          releaseName: istiod
          values: |
            defaults:
              global:
                istioNamespace: istio-system
                defaultResources:
                  requests:
                    cpu: 10m
                    memory: 128Mi
                  limits:
                    cpu: 100m
                    memory: 128Mi
                hub: m.daocloud.io/docker.io/istio
                proxy:
                  autoInject: disabled
                  resources:
                    requests:
                      cpu: 100m
                      memory: 128Mi
                    limits:
                      cpu: 2000m
                      memory: 1024Mi
              pilot:
                autoscaleEnabled: true
                resources:
                  requests:
                    cpu: 500m
                    memory: 2048Mi
                cpu:
                  targetAverageUtilization: 80
                podAnnotations:
                  cluster-autoscaler.kubernetes.io/safe-to-evict: "true"
      destination:
        server: https://kubernetes.default.svc
        namespace: istio-system
    EOF

    4.sync by argocd

    Details
    argocd app sync argocd/istiod

    5.prepare `deploy-istio-ingressgateway.yaml`

    Details
    kubectl -n argocd apply -f - << EOF
    apiVersion: argoproj.io/v1alpha1
    kind: Application
    metadata:
      name: istio-ingressgateway
    spec:
      syncPolicy:
        syncOptions:
        - CreateNamespace=true
      project: default
      source:
        repoURL: https://istio-release.storage.googleapis.com/charts
        chart: gateway
        targetRevision: 1.23.2
        helm:
          releaseName: istio-ingressgateway
          values: |
            defaults:
              replicaCount: 1
              podAnnotations:
                inject.istio.io/templates: "gateway"
                sidecar.istio.io/inject: "true"
                cluster-autoscaler.kubernetes.io/safe-to-evict: "true"
              resources:
                requests:
                  cpu: 100m
                  memory: 128Mi
                limits:
                  cpu: 2000m
                  memory: 1024Mi
              service:
                type: LoadBalancer
                ports:
                - name: status-port
                  port: 15021
                  protocol: TCP
                  targetPort: 15021
                - name: http2
                  port: 80
                  protocol: TCP
                  targetPort: 80
                - name: https
                  port: 443
                  protocol: TCP
                  targetPort: 443
              autoscaling:
                enabled: true
                minReplicas: 1
                maxReplicas: 5
      destination:
        server: https://kubernetes.default.svc
        namespace: istio-system
    EOF

    6.sync by argocd

    Details
    argocd app sync argocd/istio-ingressgateway

    Preliminary

    1. Kubernetes is installed; if not, check ๐Ÿ”—link


    2. Helm is installed; if not, check ๐Ÿ”—link


    3. ArgoCD is installed; if not, check ๐Ÿ”—link


    4. Argo Workflow is installed; if not, check ๐Ÿ”—link


    1.prepare `argocd-login-credentials`

    Details
    kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database

    2.apply rolebinding to k8s

    Details
    kubectl apply -f - <<EOF
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: application-administrator
    rules:
      - apiGroups:
          - argoproj.io
        resources:
          - applications
        verbs:
          - '*'
      - apiGroups:
          - apps
        resources:
          - deployments
        verbs:
          - '*'
    
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: application-administration
      namespace: argocd
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: application-administrator
    subjects:
      - kind: ServiceAccount
        name: argo-workflow
        namespace: business-workflows
    
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: application-administration
      namespace: application
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: application-administrator
    subjects:
      - kind: ServiceAccount
        name: argo-workflow
        namespace: business-workflows
    EOF

    4.prepare `deploy-xxxx-flow.yaml`

    Details

    6.submit to argo workflow client

    Details
    argo -n business-workflows submit deploy-xxxx-flow.yaml

    7.decode password

    Details
    kubectl -n application get secret xxxx-credentials -o jsonpath='{.data.xxx-password}' | base64 -d

    FAQ

    Q1: Show me almost endless possibilities

    You can add standard markdown syntax:

    • multiple paragraphs
    • bullet point lists
    • emphasized, bold and even bold emphasized text
    • links
    • etc.
    ...and even source code

    the possibilities are endless (almost - including other shortcodes may or may not work)

    Q2: Show me almost endless possibilities

    You can add standard markdown syntax:

    • multiple paragraphs
    • bullet point lists
    • emphasized, bold and even bold emphasized text
    • links
    • etc.
    ...and even source code

    the possibilities are endless (almost - including other shortcodes may or may not work)

    Jun 7, 2024

    Install Nginx

    1. prepare server.conf

    cat << EOF > default.conf
    server {
      listen 80;
      location / {
          root   /usr/share/nginx/html;
          autoindex on;
      }
    }
    EOF

    2. install

    mkdir $(pwd)/data
    podman run --rm -p 8080:80 \
        -v $(pwd)/data:/usr/share/nginx/html:ro \
        -v $(pwd)/default.conf:/etc/nginx/conf.d/default.conf:ro \
        -d docker.io/library/nginx:1.19.9-alpine
    echo 'this is a test' > $(pwd)/data/some-data.txt
    Tip

    you can run an addinational daocloud image to accelerate your pulling, check Daocloud Proxy

    visit http://localhost:8080

    Mar 7, 2024

    Install Traefik

    Mar 7, 2024

    Subsections of Proxy

    Open WebUI

    Archived

    The 72602 OpenWebUI deployment is retired and has no current installation route. argocd/open-webui does not exist, and the ai namespace has no OpenWebUI resources. txt2img.agent.72602.online is retired and has no working endpoint; its DNS record, certificate, TLS Secret, and unreferenced data claims were removed.

    The repository file manifests/application/open-webui.yaml is a historical, non-deployed manifest. It is not consumed by the current GitOps setup and still points to the retired route. Do not use it as an installation source.

    Historical Record (2026-05)

    The service was previously deployed in the 72602 cluster through an ArgoCD Helm Application in namespace ai:

    • Route: txt2img.agent.72602.online (now retired)
    • Helm chart: open-webui, version 14.5.0
    • Image: m.daocloud.io/ghcr.io/open-webui/open-webui:0.9.5
    • AI backend: sub2api.application.svc:8080/v1 (OpenAI-compatible)
    • WebSocket manager: shared Redis in namespace storage
    • Persistence: SQLite on a 2Gi local-path PVC

    Any commands or verification steps from the former deployment procedure are historical and non-runnable. They are intentionally not reproduced here.

    May 12, 2026

    Ollama Moderation Gateway

    Overview

    The Ollama Moderation Gateway provides an OpenAI-compatible moderation endpoint backed by Ollama models. It is deployed via the 72602 ArgoCD GitOps pipeline using the Helm chart ollama-moderation-gateway (version 0.1.0).

    • ArgoCD Application: argocd/ollama-moderation-gateway (child of argocd/ops-docs)
    • Namespace: moderation
    • Service: ollama-moderation-gateway (port 8000)
    • Ingress: moderation.llm.72602.space (TLS via cert-manager)

    Current Operational State: Deployment ollama-moderation-gateway desired replicas: 3, available replicas: 3. Service reports three Ready endpoints. Single-node resource metrics are healthy. The image, runtime configuration and Ingress remain unchanged; only replicaCount was changed.

    Subsections of Ollama Moderation Gateway

    Install (ArgoCD)

    ๐Ÿš€Installation

    Environment
    Install By

    Preliminary

    1. Kubernetes is installed; if not, check ๐Ÿ”—link


    2. Helm is installed; if not, check ๐Ÿ”—link


    3. ArgoCD is installed; if not, check ๐Ÿ”—link


    1.verify source and create namespace

    Details
    git -C /home/aaron/Ops/docs fetch origin main
    git -C /home/aaron/Ops/docs \
      show origin/main:manifests/ollama-moderation-gateway-argocd.yaml >/dev/null
    
    argocd app get ops-docs --hard-refresh
    argocd app sync ops-docs --revision main
    argocd app wait ops-docs --sync --timeout 300
    
    kubectl wait --for=jsonpath='{.status.phase}'=Active \
      namespace/moderation --timeout=120s

    The parent ops-docs Application reads the manifests path and creates the child Application. The child creates namespace moderation through CreateNamespace=true.

    2.prepare runtime secret

    Details
    test -s /home/aaron/Ops/docs/.moderation.env
    test "$(stat -c %a /home/aaron/Ops/docs/.moderation.env)" = 600
    
    kubectl -n moderation create secret generic ollama-moderation-gateway \
      --from-env-file=/home/aaron/Ops/docs/.moderation.env \
      --dry-run=client -o yaml | kubectl apply -f -
    
    kubectl -n moderation get secret ollama-moderation-gateway --output=name

    The ignored .moderation.env file must contain OLLAMA_API_KEYS and MODERATION_API_KEYS. Secret values remain outside Git and terminal output.

    3.verify GitOps source and sync child

    Details
    # confirm parent application source
    kubectl -n argocd get application ops-docs \
      -o jsonpath='{.spec.source.repoURL}{"\n"}{.spec.source.path}'
    
    # refresh and sync the child (ollama-moderation-gateway)
    argocd app get ollama-moderation-gateway --hard-refresh
    argocd app sync ollama-moderation-gateway
    argocd app wait ollama-moderation-gateway --sync --health --timeout 600

    4.verify deployment, service, ingress and certificate

    Details
    # chart source details
    kubectl -n argocd get application ollama-moderation-gateway \
      -o jsonpath='{.spec.source.repoURL}{"\n"}{.spec.source.path}{"\n"}{.spec.source.targetRevision}{"\n"}'
    
    # image and release verification
    kubectl -n moderation get deployment ollama-moderation-gateway \
      -o jsonpath='{range .spec.template.spec.containers[*]}{.name}{"="}{.image}{"\n"}{end}'
    
    # rollout status
    kubectl -n moderation rollout status deployment/ollama-moderation-gateway --timeout=600s
    kubectl -n moderation get pods,svc,ingress
    kubectl -n moderation get certificate,certificaterequest,order,challenge
    kubectl -n moderation get endpointslice -l kubernetes.io/service-name=ollama-moderation-gateway
    
    # health checks
    curl -fsS https://moderation.llm.72602.space/health
    curl -fsS https://moderation.llm.72602.space/readyz
    
    # authenticated moderation request; do not echo the key or response body
    set +x
    read -rsp 'Gateway API key: ' GATEWAY_KEY; printf '\n'
    curl -fsS -X POST https://moderation.llm.72602.space/v1/moderations \
      -H "Authorization: Bearer ${GATEWAY_KEY}" \
      -H "Content-Type: application/json" \
      --json '{"model":"moderation-fast","input":"hello"}' \
      | jq -e '.results | length == 1' >/dev/null
    unset GATEWAY_KEY
    Details

    Current Operational State: Deployment ollama-moderation-gateway desired replicas: 3, available replicas: 3. Service reports three Ready endpoints. Single-node resource metrics are healthy. The image, runtime configuration and Ingress remain unchanged; only replicaCount was changed.

    Expected release values: chart ollama-moderation-gateway version 0.1.0 and image ghcr.io/aaronyang0628/ollama-moderation-gateway@sha256:6957f8a32ad93577500c6952d7dd0b9ae970672b82570144852c5fe5766773c5. The TLS certificate moderation.llm.72602.space-tls should be Ready with expiry 2026-12-13T00:55:24Z.

    ๐Ÿ“ฆRollback Guidance

    If a deployment must be reverted, create a reviewed Git revert for the deployment source commit, push it, and sync the parent application. Runtime secrets and TLS certificates are external resources and are not modified by the rollback.

    # create a reviewed revert in the docs repository
    cd /home/aaron/Ops/docs
    git fetch origin main
    git revert --no-edit 39c48b3
    git push origin main
    argocd app sync ops-docs --revision main
    argocd app wait ops-docs --sync --health --timeout 300

    After rollback, re-run the verification steps above to ensure the service is healthy.

    Sub2API

    Web Page

    sub2api web page (https://token.72602.space)

    Current State

    • Git owner: argocd/ops-docs, source https://github.com/AaronYang0628/docs.git, path manifests
    • ArgoCD Application: argocd/sub2api
    • Namespace: application
    • OCI chart: ghcr.io/aaronyang0628/helm-chart-mirror/sub2api (0.1.15)
    • Application image: ghcr.io/wei-shaw/sub2api@sha256:4c5dffab6e5ba4d3bd5382f19aad9654847b4e23de1a3d48e190146a3e6eb977
    • Public API and OAuth host: token.72602.space
    • Ingress class: nginx
    • TLS certificate: token.72602.space-tls (Ready)
    • External PostgreSQL: postgresql.database.svc.cluster.local:5432 (database/user: sub2api)
    • Application PVC: sub2api-data, 10Gi, local-path, RWO
    • Redis PVC: 8Gi, local-path, RWO; AOF is enabled
    • RollingUpdate: maxUnavailable: 0, maxSurge: 1

    Google OAuth Route

    • Use the 72602 public URL: https://token.72602.space.
    • Google OAuth is enabled in the live application. The start endpoint is /api/v1/auth/oauth/google/start and the callback URI generated by the running application is: https://token.72602.space/api/v1/auth/oauth/google/callback.
    • The application sets the OAuth state, redirect, and provider cookies with HttpOnly, Secure, SameSite=Lax, and Path=/api/v1/auth/oauth. The frontend callback page is /auth/oauth/callback.
    • The Pod requires the cluster egress proxy for Google token exchange. The GitOps source sets HTTP_PROXY and HTTPS_PROXY to http://192.168.0.25:17890 and bypasses that proxy for cluster-local ranges.
    • sub2api.home.geekcity.tech:32443 is a separate external endpoint, not the 72602 ingress. It returns 404 for the 72602 OAuth start path and must not be used for this login flow.
    • If Google reports a redirect URI mismatch, register only the exact callback URI above in the Google OAuth client. Google Cloud Console changes are not managed by this Kubernetes repository.

    Docs

    • Backup & Restore

      Sub2API pre-upgrade backup and recovery runbook

      • Install (ArgoCD)

        Deploy Sub2API through the 72602 GitOps parent and OCI Helm child Application

        • Ops

          GitOps upgrades and daily operations for Sub2API

          Subsections of Sub2API

          Backup & Restore

          Scope

          • Database: PostgreSQL (database/postgresql-0), DB/user sub2api
          • Git source: manifests/sub2api-argocd.yaml, owned by argocd/ops-docs
          • Current release: OCI chart 0.1.15, application 0.2.5
          • Application image: ghcr.io/wei-shaw/sub2api@sha256:4c5dffab6e5ba4d3bd5382f19aad9654847b4e23de1a3d48e190146a3e6eb977
          • Runtime data: application/sub2api-data, 10Gi, local-path, RWO
          • Redis data: 8Gi, local-path, RWO; AOF is enabled
          • Runtime Secrets: application/sub2api-auth, application/sub2api-external-postgresql, and application/sub2api-redis

          Sub2API executes PostgreSQL migrations automatically on startup. Migrations are forward-only, so every chart or image upgrade requires a verified pg_dump before the Git version change.

          Pre-Upgrade Backup

          1.create a protected operation directory

          BACKUP_ROOT=/home/aaron/Ops/backups/sub2api
          BACKUP_DIR="${BACKUP_ROOT}/upgrade-$(date -u +%Y%m%dT%H%M%SZ)"
          mkdir -p "$BACKUP_DIR"
          chmod 700 "$BACKUP_DIR"
          printf '%s\n' "$BACKUP_DIR"

          Use the generated UTC directory for the entire operation. Do not hard-code a previous operation timestamp into future commands.

          2.dump PostgreSQL without printing its password

          set +x
          PG_PASSWORD="$(kubectl -n application get secret \
            sub2api-external-postgresql \
            -o jsonpath='{.data.postgres-password}' | base64 -d)"
          test -n "$PG_PASSWORD"
          
          printf '%s\n' "$PG_PASSWORD" | \
            kubectl -n database exec -i postgresql-0 -- \
            sh -c 'IFS= read -r PGPASSWORD; export PGPASSWORD; exec pg_dump -U sub2api -d sub2api -Fc' \
            > "$BACKUP_DIR/sub2api.dump"
          
          unset PG_PASSWORD

          The password is passed on stdin and is not written into the backup directory.

          3.capture application data and non-secret metadata

          kubectl -n application exec deployment/sub2api -- \
            tar -C /app/data -czf - . > "$BACKUP_DIR/sub2api-data.tgz"
          
          git -C /home/aaron/Ops/docs fetch origin main
          git -C /home/aaron/Ops/docs rev-parse origin/main \
            > "$BACKUP_DIR/git-revision.txt"
          git -C /home/aaron/Ops/docs show origin/main:manifests/sub2api-argocd.yaml \
            > "$BACKUP_DIR/sub2api-argocd.yaml"
          
          kubectl -n application get pvc \
            -l app.kubernetes.io/instance=sub2api -o yaml \
            > "$BACKUP_DIR/pvc-metadata.yaml"

          Do not export Kubernetes Secret objects into this directory. Back up Secret values only through the approved secret-management process. Redis AOF supports restart recovery on its PVC, but it is not a substitute for the PostgreSQL dump. Do not copy live AOF files as if they were a consistent database backup.

          4.verify artifacts before upgrading

          test -s "$BACKUP_DIR/sub2api.dump"
          test -s "$BACKUP_DIR/sub2api-data.tgz"
          
          kubectl -n database exec -i postgresql-0 -- pg_restore --list \
            < "$BACKUP_DIR/sub2api.dump" \
            > "$BACKUP_DIR/sub2api.dump.list"
          test -s "$BACKUP_DIR/sub2api.dump.list"
          
          sha256sum \
            "$BACKUP_DIR/sub2api.dump" \
            "$BACKUP_DIR/sub2api-data.tgz" \
            "$BACKUP_DIR/sub2api-argocd.yaml" \
            "$BACKUP_DIR/pvc-metadata.yaml" \
            "$BACKUP_DIR/git-revision.txt" \
            > "$BACKUP_DIR/SHA256SUMS"
          sha256sum -c "$BACKUP_DIR/SHA256SUMS"

          Verified backup: 2026-08-14

          • Backup directory: /home/aaron/Ops/backups/sub2api/upgrade-20260814T063611Z (directory mode 700, files mode 600). Only the shared PostgreSQL sub2api database was dumped; n8n and other databases were not touched.
          • The host had no pg_restore; PostgreSQL Pod database/postgresql-0 had pg_restore 18.3 and GNU tar 1.34. The dump was copied temporarily with kubectl cp, checked with Pod-local pg_restore --list, and the temporary Pod file was removed. The previous kubectl exec -i streaming validation was not reused.
          • Non-empty artifacts: sub2api.dump (19,640,824 bytes), sub2api-data.tgz (10,616,251 bytes), and sub2api.dump.list (77,853 bytes). Git revision, manifest, and PVC metadata were also captured.
          • sha256sum -c SHA256SUMS and pg_restore --list both succeeded.
          • The captured origin/main revision was ce838b424f10316fc604a4a21517c90c7b6b97ae. No failure occurred; no upgrade, Argo CD sync, or GitOps/cluster change was performed.

          Verified upgrade: 2026-09-05 (application 0.2.0)

          • Backup directory: /home/aaron/Ops/backups/sub2api/upgrade-20260905T000035Z (upgrade commit 5230546610c437a02ee45f5b80cd804779c9170c). The scoped sub2api.dump (47,520,105 bytes) and sub2api-data.tgz (10,192,905 bytes) were non-empty; pg_restore --list and SHA-256 checks passed.
          • schema_migrations advanced from 268 to 277 records; the latest migration is 233_group_free_openai_fast.sql.
          • ArgoCD reported Synced/Healthy; Deployment was 1/1 on the pinned ghcr.io/wei-shaw/sub2api@sha256:271bb3b34661803681cabf54e99811ab8e248b0dd4c88b09ea1226e22dea5751 image.
          • Existing application and Redis PVCs remained Bound, Service endpoints were Ready, and public health/settings checks succeeded.
          • No rollback was required.

          Verified upgrade: 2026-09-05 (application 0.2.1)

          • Backup directory: /home/aaron/Ops/backups/sub2api/upgrade-20260905T115349Z-178860 (upgrade commit 21d02345de47d75454841e464756f6cf9349cc3c). The scoped sub2api.dump and sub2api-data.tgz were non-empty; pg_restore --list and SHA-256 checks passed.
          • ArgoCD reported Synced/Healthy at 2026-09-05T13:03:41Z; Deployment was 1/1, Pod ready with 0 restarts, internal /health returned {"status":"ok"}, Service endpoint ready, and Redis StatefulSet 1/1.
          • Existing application and Redis PVCs remained Bound; health and settings checks succeeded.
          • No rollback was required.

          Verified upgrade: 2026-09-10

          • Backup directory: /home/aaron/Ops/backups/sub2api/upgrade-20260910T061248Z; PostgreSQL dump 46,520,009 bytes, /app/data archive 10,214,969 bytes; backup artifacts and pg_restore --list, archive listing, SHA-256 all passed; GitOps commit 7bd44adb5ed1b61976b507e1f32bc990738782b2; sub2api ArgoCD target/observed 0.1.14 Synced/Healthy operation Succeeded; runtime verification: Deployment 1/1, Pod ready 0 restarts, chart sub2api-0.1.14/app 0.2.4, actual image digest matches, Service endpoint ready/serving, internal /health HTTP 200, Redis StatefulSet 1/1.
          • No rollback required.

          Verified upgrade: 2026-09-16

          • Backup directory: /home/aaron/Ops/backups/sub2api/upgrade-20260916T053309Z (directory mode 700, files mode 600). PostgreSQL dump 27,593,406 bytes, /app/data archive 4,579,406 bytes; backup artifacts and pg_restore --list, archive listing, SHA-256 all passed; GitOps commit e2c0e4576276f6a299bbd27e80f40af883f8e877 (chore(sub2api): upgrade to chart 0.1.15); sub2api ArgoCD target/observed 0.1.15 Synced/Healthy operation Succeeded; runtime verification: Deployment 1/1, Pod sub2api-7c9c4b95bf-r6cpg Running/Ready, restarts 0, chart sub2api-0.1.15/app 0.2.5, actual image digest matches sha256:4c5dffab6e5ba4d3bd5382f19aad9654847b4e23de1a3d48e190146a3e6eb977, Service endpoint ready at 10.42.0.198:8080, internal /health HTTP 200 body {"status":"ok"}, Redis StatefulSet ready at 10.42.0.12:6379 with 1 historical restart.
          • No rollback required.

          Restore PostgreSQL Safely

          Restore into a separate database first. Do not overwrite the live sub2api database during an upgrade rollback.

          1.create the restore database

          BACKUP_DIR=/home/aaron/Ops/backups/sub2api/<approved-backup-directory>
          test -s "$BACKUP_DIR/sub2api.dump"
          
          set +x
          read -rsp 'PostgreSQL admin password: ' POSTGRES_ADMIN_PASSWORD; printf '\n'
          test -n "$POSTGRES_ADMIN_PASSWORD"
          
          printf '%s\n' "$POSTGRES_ADMIN_PASSWORD" | \
            kubectl -n database exec -i postgresql-0 -- \
            sh -c 'IFS= read -r PGPASSWORD; export PGPASSWORD; exec createdb -U postgres -O sub2api sub2api_restore'
          
          unset POSTGRES_ADMIN_PASSWORD

          2.restore and verify with the application database user

          set +x
          PG_PASSWORD="$(kubectl -n application get secret \
            sub2api-external-postgresql \
            -o jsonpath='{.data.postgres-password}' | base64 -d)"
          test -n "$PG_PASSWORD"
          
          { printf '%s\n' "$PG_PASSWORD"; cat "$BACKUP_DIR/sub2api.dump"; } | \
            kubectl -n database exec -i postgresql-0 -- \
            sh -c 'IFS= read -r PGPASSWORD; export PGPASSWORD; exec pg_restore -U sub2api -d sub2api_restore --exit-on-error --no-owner --no-privileges'
          
          printf '%s\n' "$PG_PASSWORD" | \
            kubectl -n database exec -i postgresql-0 -- \
            sh -c 'IFS= read -r PGPASSWORD; export PGPASSWORD; exec psql -U sub2api -d sub2api_restore -c "\\dt"'
          
          unset PG_PASSWORD

          3.switch only through a reviewed Git recovery change

          Change externalPostgresql.database to sub2api_restore in manifests/sub2api-argocd.yaml, commit and push the reviewed recovery change, then reconcile ops-docs and sub2api. Restore sub2api-data only during a planned maintenance window with the workload quiesced; never extract the archive over a running Pod.

          argocd app get ops-docs --hard-refresh
          argocd app sync ops-docs --revision main
          argocd app wait ops-docs --sync --health --timeout 300
          argocd app sync sub2api
          argocd app wait sub2api --sync --health --timeout 600
          
          curl -fsS https://token.72602.space/health
          curl -fsS https://token.72602.space/api/v1/settings/public
          kubectl -n application logs deployment/sub2api --since=10m

          Do not use kubectl rollout undo, delete PVCs, or delete Secrets as restore or rollback steps.

          App-Level S3 Backup Check

          The live S3 endpoint is https://api.minio.72602.space, and Sub2API uses the sub2api bucket. The MinIO API Ingress source keeps nginx.ingress.kubernetes.io/proxy-body-size: "0" scoped to that API host so backup uploads are not rejected by the default 1 MiB ingress limit. Verify a scheduled or manual backup from logs without printing credentials, tokens, object names, or backup content:

          kubectl -n application logs deployment/sub2api --since=30m
          kubectl -n basic-components logs deployment/ingress-nginx-controller --since=30m
          kubectl -n storage get ingress minio-api

          Install (ArgoCD)

          ๐Ÿš€Installation

          Environment
          Install By

          Preliminary

          1. Kubernetes is installed; if not, check ๐Ÿ”—link


          2. Helm is installed; if not, check ๐Ÿ”—link


          3. ArgoCD is installed; if not, check ๐Ÿ”—link


          1. PostgreSQL is available in namespace database, DNS resolves token.72602.space, and ingress-nginx with the lets-encrypt ClusterIssuer is ready.

          1.prepare runtime Secrets

          Details
          kubectl get namespace application >/dev/null 2>&1 || \
            kubectl create namespace application
          
          set +x
          read -rsp 'Sub2API admin password: ' ADMIN_PASSWORD; printf '\n'
          read -rsp 'Sub2API PostgreSQL password: ' POSTGRES_PASSWORD; printf '\n'
          read -rsp 'Sub2API Redis password: ' REDIS_PASSWORD; printf '\n'
          JWT_SECRET="$(openssl rand -hex 32)"
          TOTP_KEY="$(openssl rand -hex 32)"
          
          test -n "$ADMIN_PASSWORD"
          test -n "$POSTGRES_PASSWORD"
          test -n "$REDIS_PASSWORD"
          
          kubectl -n application create secret generic sub2api-auth \
            --from-literal=admin-password="$ADMIN_PASSWORD" \
            --from-literal=jwt-secret="$JWT_SECRET" \
            --from-literal=totp-encryption-key="$TOTP_KEY" \
            --dry-run=client -o yaml | kubectl apply -f -
          
          kubectl -n application create secret generic sub2api-external-postgresql \
            --from-literal=postgres-password="$POSTGRES_PASSWORD" \
            --dry-run=client -o yaml | kubectl apply -f -
          
          kubectl -n application create secret generic sub2api-redis \
            --from-literal=redis-password="$REDIS_PASSWORD" \
            --dry-run=client -o yaml | kubectl apply -f -
          
          unset ADMIN_PASSWORD POSTGRES_PASSWORD REDIS_PASSWORD JWT_SECRET TOTP_KEY
          kubectl -n application get secret \
            sub2api-auth sub2api-external-postgresql sub2api-redis

          Secret values must stay outside Git, terminal output, and this handbook.

          2.verify the GitOps source

          The parent argocd/ops-docs Application reads https://github.com/AaronYang0628/docs.git at path manifests. The canonical child declaration is manifests/sub2api-argocd.yaml; it configures the OCI chart source and must not be applied as an independent deployment route.

          Details
          git -C /home/aaron/Ops/docs fetch origin main
          git -C /home/aaron/Ops/docs \
            show origin/main:manifests/sub2api-argocd.yaml >/dev/null
          
          kubectl -n argocd get application ops-docs \
            -o jsonpath='{.spec.source.repoURL}{"\n"}{.spec.source.path}{"\n"}'

          Expected source values are https://github.com/AaronYang0628/docs.git and manifests.

          3.sync parent and child Applications

          Details
          argocd app get ops-docs --hard-refresh
          argocd app sync ops-docs --revision main
          argocd app wait ops-docs --sync --health --timeout 300
          
          argocd app get sub2api --hard-refresh
          argocd app sync sub2api
          argocd app wait sub2api --sync --health --timeout 600

          4.verify release, storage, ingress, and API path

          Details
          kubectl -n argocd get application sub2api \
            -o jsonpath='{.spec.source.repoURL}{"\n"}{.spec.source.chart}{" "}{.spec.source.targetRevision}{"\n"}'
          
          kubectl -n application get deployment sub2api \
            -o jsonpath='{range .spec.template.spec.containers[*]}{.name}{"="}{.image}{"\n"}{end}'
          
          kubectl -n application rollout status deployment/sub2api --timeout=600s
          kubectl -n application get pods,svc,ingress,pvc
          kubectl -n application get certificate,certificaterequest,order,challenge
          kubectl -n application get endpointslice \
            -l kubernetes.io/service-name=sub2api
          
          curl -fsS https://token.72602.space/health
          curl -fsS https://token.72602.space/api/v1/settings/public
          
          set +x
          read -rsp 'Sub2API API token: ' SUB2API_API_TOKEN; printf '\n'
          curl -fsS \
            -H "Authorization: Bearer ${SUB2API_API_TOKEN}" \
            https://token.72602.space/v1/models
          
          read -rp 'Model ID for smoke generation: ' MODEL_ID
          curl -fsS https://token.72602.space/v1/chat/completions \
            -H "Authorization: Bearer ${SUB2API_API_TOKEN}" \
            --json "{\"model\":\"${MODEL_ID}\",\"messages\":[{\"role\":\"user\",\"content\":\"Reply with OK.\"}],\"max_tokens\":8}"
          unset SUB2API_API_TOKEN MODEL_ID

          Expected release values are chart 0.1.14 and application image ghcr.io/wei-shaw/sub2api@sha256:4a9620931fbb966b04375c34fe3edd01b640e7e6fbbba02537a9a64d9555a59e. The TLS certificate is Ready; the sub2api-data PVC is 10Gi and the Redis PVC is 8Gi, both local-path RWO.

          Ops

          Web Page

          sub2api web page (https://token.72602.space)

          Current Release

          argocd app get ops-docs --hard-refresh
          argocd app get sub2api --hard-refresh
          
          kubectl -n argocd get application sub2api \
            -o jsonpath='{.spec.source.repoURL}{"\nchart="}{.spec.source.chart}{" "}{.spec.source.targetRevision}{"\nimage.tag="}{.spec.source.helm.parameters[?(@.name=="image.tag")].value}{"\n"}'
          
          kubectl -n application get deployment sub2api \
            -o jsonpath='{range .spec.template.spec.containers[*]}{.name}{"="}{.image}{"\n"}{end}'
          
          kubectl -n application get pods,svc,ingress,pvc
          kubectl -n application get certificate,certificaterequest,order,challenge

          The expected values are OCI chart 0.1.15, image ghcr.io/wei-shaw/sub2api@sha256:4c5dffab6e5ba4d3bd5382f19aad9654847b4e23de1a3d48e190146a3e6eb977, namespace application, and host token.72602.space. The application PVC is 10Gi; the Redis PVC is 8Gi with AOF enabled. Both use local-path and RWO.

          Sync From Git

          argocd/ops-docs owns manifests/sub2api-argocd.yaml from https://github.com/AaronYang0628/docs.git. Reconcile the Git parent before the OCI Helm child:

          git -C /home/aaron/Ops/docs fetch origin main
          argocd app get ops-docs --hard-refresh
          argocd app sync ops-docs --revision main
          argocd app wait ops-docs --sync --health --timeout 300
          
          argocd app get sub2api --hard-refresh
          argocd app sync sub2api
          argocd app wait sub2api --sync --health --timeout 600

          Do not apply manifests/sub2api-argocd.yaml directly as a second ownership path.

          Rolling Upgrade

          1.back up PostgreSQL before changing chart or image values

          Use the Backup & Restore runbook. Sub2API executes PostgreSQL migrations automatically at startup, and migrations are forward-only. Verify the dump before continuing.

          2.update the Git source

          Edit only the reviewed targetRevision, image.tag, or required values in manifests/sub2api-argocd.yaml, then inspect and publish the change:

          git -C /home/aaron/Ops/docs diff --check -- manifests/sub2api-argocd.yaml
          git -C /home/aaron/Ops/docs diff -- manifests/sub2api-argocd.yaml
          git -C /home/aaron/Ops/docs add manifests/sub2api-argocd.yaml
          git -C /home/aaron/Ops/docs commit -m "chore: upgrade sub2api"
          git -C /home/aaron/Ops/docs push origin HEAD:main

          3.reconcile parent and child Applications

          argocd app get ops-docs --hard-refresh
          argocd app sync ops-docs --revision main
          argocd app wait ops-docs --sync --health --timeout 300
          
          argocd app get sub2api --hard-refresh
          argocd app sync sub2api
          argocd app wait sub2api --sync --health --timeout 600
          kubectl -n application rollout status deployment/sub2api --timeout=600s
          kubectl -n application get endpointslice \
            -l kubernetes.io/service-name=sub2api -o wide

          The Deployment explicitly uses maxUnavailable: 0 and maxSurge: 1. Kubernetes adds the new Ready Pod to the EndpointSlice before terminating the old Pod, and the Service selects only Ready endpoints. This protects new requests during rollout, but it does not guarantee completion of requests that are already attached to the terminating Pod. Long generations still require the application to handle graceful termination and draining correctly.

          4.verify the public and authenticated model path

          curl -fsS https://token.72602.space/health
          curl -fsS https://token.72602.space/api/v1/settings/public
          
          set +x
          read -rsp 'Sub2API API token: ' SUB2API_API_TOKEN; printf '\n'
          curl -fsS \
            -H "Authorization: Bearer ${SUB2API_API_TOKEN}" \
            https://token.72602.space/v1/models
          
          read -rp 'Model ID for smoke generation: ' MODEL_ID
          curl -fsS https://token.72602.space/v1/chat/completions \
            -H "Authorization: Bearer ${SUB2API_API_TOKEN}" \
            --json "{\"model\":\"${MODEL_ID}\",\"messages\":[{\"role\":\"user\",\"content\":\"Reply with OK.\"}],\"max_tokens\":8}"
          unset SUB2API_API_TOKEN MODEL_ID

          Admin MCP

          The Ops Agent Pod runs a local MCP server sub2api-admin against the cluster-local endpoint http://sub2api.application.svc.cluster.local:8080. The Deployment injects the API key from the dedicated runtime Secret application/sub2api-mcp key admin-api-key. Provision the Secret through manifests/ops-agent/create-sub2api-mcp-secret.sh; the value never enters Git or opencode.json. The MCP only accepts the configured cluster-local host, every authenticated GET runs through a reviewed route allowlist, sensitive fields are recursively redacted, and no generic authenticated write tool is exposed.

          Enter the key only into the helper’s silent interactive prompt. Never place the key in shell arguments, chat, Git, OpenCode config, logs, or command output.

          Tools

          Nine tools are registered:

          ToolPurpose
          sub2api-admin_describeCapabilities and safety constraints
          sub2api-admin_healthAnonymous check of /health through the configured internal cluster-local URL (SUB2API_BASE_URL), not the public host
          sub2api-admin_readOne allowlisted authenticated GET route
          sub2api-admin_find_userResolve exactly one user by normalized email
          sub2api-admin_preview_rechargeNon-mutating preview of an additive credit
          sub2api-admin_rechargeAdditive credit with backend idempotency
          sub2api-admin_update_user_limitsPer-user RPM and/or concurrency
          sub2api-admin_set_account_schedulableEnable or disable scheduling for an entire upstream account
          sub2api-admin_model_control_optionsExplain the available scheduling boundaries and rate-limit scopes

          The global OpenCode permission set denies every sub2api-admin_* tool. The 72602-k3s-maintainer agent allows the six read-only tools directly and asks before recharge, update_user_limits, or set_account_schedulable. Use the maintainer for any authenticated mutation.

          Recharge protocol

          Recharge is additive USD-style internal credit only; set and subtract operations are not exposed. Before every charge:

          1. Collect an exact email and a positive amount.
          2. Call sub2api-admin_preview_recharge. The server fuzzy-searches but accepts only one exact normalized email match.
          3. Read back the matched email, the immutable user id, status, the current balance, the amount, and the expected balance; obtain explicit confirmation for that exact tuple.
          4. Generate one stable Idempotency-Key of 16-128 URL-safe characters. Keep and reuse that key when the result is uncertain; never generate a fresh key for a retry.
          5. Call sub2api-admin_recharge with operation: add, the exact email and id, the audit note, and the idempotency key.
          6. Re-read the user and balance history; record the exact verified or accepted_unverified outcome. Never rewrite an unverified accepted response as success.

          No account is recharged as part of installation. Do not recharge inactive users unless the operator explicitly confirms the inactive status.

          Limits and model availability

          Sub2API v0.1.176 has no configurable per-model RPM. Operator scope:

          • User RPM and concurrency via sub2api-admin_update_user_limits.
          • Group RPM is set through the admin UI; this MCP does not expose it.
          • rate_multiplier changes billing, not request rate.

          For temporary model unavailability, call sub2api-admin_model_control_options first and identify the model’s actual scheduling boundary:

          • Dedicated account: sub2api-admin_set_account_schedulable toggles every model served by that account; roll back with the inverse value.
          • Restricted channel: remove the exact model from the channel pricing/model list while restrict_models=true; preserve the previous payload for rollback. This MCP does not mutate channels, use the admin UI.
          • Composite model: disable the exact composite route; preserve prior state. Use the admin UI.
          • models_list_config only hides discovery. It does not block direct requests and must never be reported as a disable.

          Scheduling changes affect new requests only. They do not cancel requests or streams already in progress. If the model spans multiple accounts, channels, or routes, enumerate and confirm every affected target before mutation.

          Secret rotation

          Sub2API supports only one Admin API Key. Generating or regenerating the key in the admin UI immediately invalidates the previous key, so the MCP will briefly fail to authenticate until the Ops Agent workload restarts with the new value. Plan an expected maintenance window of one to two restart cycles. Rotate in this exact order without intermediate pauses:

          1. Generate the new key in the Sub2API admin UI and immediately enter it into the silent prompt of manifests/ops-agent/create-sub2api-mcp-secret.sh. Confirm the helper reports application/sub2api-mcp keys=admin-api-key.
          2. Restart the managed workload so the new env var is injected:
            kubectl -n application rollout restart deployment/ops-agent
            kubectl -n application rollout status deployment/ops-agent --timeout=300s
          3. Verify global/health reports healthy: true, /mcp reports exactly {"sub2api-admin":{"status":"connected"}}, and the merged OpenCode config carries the cluster-local SUB2API_BASE_URL without the new key.
          4. Through 72602-k3s-maintainer, run sub2api-admin_read against /api/v1/admin/system/version; the live application must respond 0.1.176.

          The upstream “generate key” action is itself the invalidation step; no follow-up disable of the previous key is needed or supported.

          Tests: node --test .opencode/mcp/sub2api-admin/server.test.mjs passes three tests covering the allowlist, path-traversal rejection, and the recharge idempotency path.

          GitOps Rollback

          Restore the previous reviewed chart and image values, and any reviewed OpenCode configuration, with git revert or a new commit, then let ArgoCD converge:

          git -C /home/aaron/Ops/docs log --oneline -- manifests/sub2api-argocd.yaml .opencode/opencode.json
          git -C /home/aaron/Ops/docs revert <change-commit>
          git -C /home/aaron/Ops/docs push origin HEAD:main
          # Record rollback as a new Git revert commit (upgrade commit f6bf8df86d40d07493dafbc713ca37b31f80dd4e); backup artifacts are in `/home/aaron/Ops/backups/sub2api/upgrade-20260908T032857Z` for isolated DB restore.
          
          argocd app get ops-docs --hard-refresh
          argocd app sync ops-docs --revision main
          argocd app wait ops-docs --sync --health --timeout 300
          argocd app sync sub2api
          argocd app wait sub2api --sync --health --timeout 600
          
          kubectl -n application rollout restart deployment/ops-agent
          kubectl -n application rollout status deployment/ops-agent --timeout=300s

          After the Ops Agent Pod rolls back and no Deployment references the helper Secret, remove it:

          test -z "$(kubectl -n application get deployment -o json \
            | jq -r '.items[].spec.template.spec.containers[]
                    | select(.env[]?.valueFrom.secretKeyRef.name=="sub2api-mcp")
                    | .name')" && \
            kubectl -n application delete secret sub2api-mcp

          An image/chart rollback does not reverse a forward-only PostgreSQL migration. Confirm compatibility with the migrated schema; when database recovery is required, restore the pre-upgrade dump into a separate database and switch via a reviewed Git change. Do not use kubectl rollout undo, and do not delete PVCs or Secrets as a rollback step until the Git revert and ops-agent restart are Healthy.

          Troubleshooting

          kubectl -n application logs deployment/sub2api --since=10m
          kubectl -n application get events --sort-by=.lastTimestamp
          kubectl -n application get endpointslice \
            -l kubernetes.io/service-name=sub2api -o yaml
          argocd app get sub2api --hard-refresh

          ๐Ÿ›Ž๏ธFAQ

          Settings API reports column settings.id does not exist

          If /api/v1/settings/public or the admin settings API returns HTTP 500 and the logs contain pq: column settings.id does not exist, Sub2API is connected to a shared or legacy database with an incompatible settings table.

          Confirm that the live Application and Secret reference the dedicated sub2api database and user without printing the password:

          kubectl -n argocd get application sub2api \
            -o jsonpath='{.spec.source.helm.values}'
          kubectl -n application get secret sub2api-external-postgresql
          kubectl -n application logs deployment/sub2api --since=10m

          Keep externalPostgresql.username and externalPostgresql.database set to sub2api in manifests/sub2api-argocd.yaml. Create or recover the dedicated database first, then update the Secret through the approved secret-management process and reconcile through ArgoCD. Do not point Sub2API at the n8n database or patch the Deployment directly.

          Redis reports WRONGPASS

          WRONGPASS invalid username-password pair means the password used by the Sub2API Pod no longer matches the Redis Secret. The chart must continue to pin the stable Secret and key:

          redis:
            auth:
              existingSecret: sub2api-redis
              existingSecretPasswordKey: redis-password

          Verify references and workload state without reading the Secret value:

          kubectl -n application get secret sub2api-redis
          kubectl -n application get deployment sub2api \
            -o jsonpath='{range .spec.template.spec.containers[0].env[*]}{.name}{" <- "}{.valueFrom.secretKeyRef.name}{"/"}{.valueFrom.secretKeyRef.key}{"\n"}{end}'
          kubectl -n application logs deployment/sub2api --since=10m

          If rotation is required, update Redis and application/sub2api-redis as one planned operation, then reconcile the Git-owned Application. Do not generate a new password during a routine restart.

          Subsections of RPC

          gRpc

          This guide gets you started with gRPC in C++ with a simple working example.

          In the C++ world, thereโ€™s no universally accepted standard for managing project dependencies. You need to build and install gRPC before building and running this quick startโ€™s Hello World example.

          Build and locally install gRPC and Protocol Buffers. The steps in the section explain how to build and locally install gRPC and Protocol Buffers using cmake. If youโ€™d rather use bazel, see Building from source.

          1. Setup

          Choose a directory to hold locally installed packages. This page assumes that the environment variable MY_INSTALL_DIR holds this directory path. For example:

          export MY_INSTALL_DIR=$HOME/.local

          Ensure that the directory exists:

          mkdir -p $MY_INSTALL_DIR

          Add the local bin folder to your path variable, for example:

          export PATH="$MY_INSTALL_DIR/bin:$PATH"
          Important

          We strongly encourage you to install gRPC locally โ€” using an appropriately set CMAKE_INSTALL_PREFIX โ€” because there is no easy way to uninstall gRPC after youโ€™ve installed it globally.

          2. Install Essentials

          2.1 Install Cmake

          You need version 3.13 or later of cmake. Install it by following these instructions:

          Install on
          sudo apt install -y cmake
          brew install cmake
          Check the version of cmake
          cmake --version
          2.2 Install basic tools required to build gRPC
          Install on
          sudo apt install -y build-essential autoconf libtool pkg-config
          brew install autoconf automake libtool pkg-config
          2.3 Clone the grpc repo

          Clone the grpc repo and its submodules:

          git clone --recurse-submodules -b v1.62.0 --depth 1 --shallow-submodules https://github.com/grpc/grpc
          2.4 Build and install gRPC and Protocol Buffers

          While not mandatory, gRPC applications usually leverage Protocol Buffers for service definitions and data serialization, and the example code uses proto3.

          The following commands build and locally install gRPC and Protocol Buffers:

          cd grpc
          mkdir -p cmake/build
          pushd cmake/build
          cmake -DgRPC_INSTALL=ON \
                -DgRPC_BUILD_TESTS=OFF \
                -DCMAKE_INSTALL_PREFIX=$MY_INSTALL_DIR \
                ../..
          make -j 4
          make install
          popd

          3. Run the example

          The example code is part of the grpc repo source, which you cloned as part of the steps of the previous section.

          3.1 change the example’s directory:
          cd examples/cpp/helloworld
          3.2 build the example project by using cmake

          make sure you still can echo $MY_INSTALL_DIR, and return a valid result

          mkdir -p cmake/build
          pushd cmake/build
          cmake -DCMAKE_PREFIX_PATH=$MY_INSTALL_DIR ../..
          make -j 4

          3.3 run the server

          ./greeter_server

          3.4 from a different terminal, run the client and see the client output:

          ./greeter_client

          and the result should be like this:

          Greeter received: Hello world
          Apr 7, 2024

          Subsections of Storage

          Deploy Artifict Repository

          Preliminary

          • Kubernetes is installed; if not, check link
          • minio is ready for artifact repository

            endpoint: minio.storage:9000

          Steps

          1. prepare bucket for s3 artifact repository

          # K8S_MASTER_IP could be you master ip or loadbalancer external ip
          K8S_MASTER_IP=172.27.253.27
          MINIO_ACCESS_SECRET=$(kubectl -n storage get secret minio-secret -o jsonpath='{.data.rootPassword}' | base64 -d)
          podman run --rm \
          --entrypoint bash \
          --add-host=minio-api.dev.72602.online:${K8S_MASTER_IP} \
          -it docker.io/minio/mc:latest \
          -c "mc alias set minio http://minio-api.dev.72602.online admin ${MINIO_ACCESS_SECRET} \
              && mc ls minio \
              && mc mb --ignore-existing minio/argo-workflows-artifacts"

          2. prepare secret s3-artifact-repository-credentials

          will create business-workflows namespace

          MINIO_ACCESS_KEY=$(kubectl -n storage get secret minio-secret -o jsonpath='{.data.rootUser}' | base64 -d)
          kubectl -n business-workflows create secret generic s3-artifact-repository-credentials \
              --from-literal=accessKey=${MINIO_ACCESS_KEY} \
              --from-literal=secretKey=${MINIO_ACCESS_SECRET}

          3. prepare configMap artifact-repositories.yaml

          apiVersion: v1
          kind: ConfigMap
          metadata:
            name: artifact-repositories
            annotations:
              workflows.argoproj.io/default-artifact-repository: default-artifact-repository
          data:
            default-artifact-repository: |
              s3:
                endpoint: minio.storage:9000
                insecure: true
                accessKeySecret:
                  name: s3-artifact-repository-credentials
                  key: accessKey
                secretKeySecret:
                  name: s3-artifact-repository-credentials
                  key: secretKey
                bucket: argo-workflows-artifacts

          4. apply artifact-repositories.yaml to k8s

          kubectl -n business-workflows apply -f artifact-repositories.yaml
          Mar 7, 2024

          Install Chart Museum

          Installation

          Install By

          Preliminary

          1. Kubernetes is installed; if not, check ๐Ÿ”—link


          2. Helm binary is installed; if not, check ๐Ÿ”—link


          1.get helm repo

          Details
          helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
          helm repo update

          2.install chart

          Details
          helm install ay-helm-mirror/kube-prometheus-stack --generate-name
          Using Mirror
          helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts \
            && helm install ay-helm-mirror/cert-manager --generate-name --version 1.17.2

          for more information, you can check ๐Ÿ”—https://aaronyang0628.github.io/helm-chart-mirror/

          Preliminary

          1. Kubernetes is installed; if not, check ๐Ÿ”—link


          2. ArgoCD is installed; if not, check ๐Ÿ”—link


          3. Helm binary is installed; if not, check ๐Ÿ”—link


          4. Ingress is installed on ArgoCD; if not, check ๐Ÿ”—link


          5. Minio is installed; if not, check ๐Ÿ”—link


          1.prepare `chart-museum-credentials`

          Storage In
          kubectl get namespaces basic-components > /dev/null 2>&1 || kubectl create namespace basic-components
          kubectl -n basic-components create secret generic chart-museum-credentials \
              --from-literal=username=admin \
              --from-literal=password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)
          
          kubectl get namespaces basic-components > /dev/null 2>&1 || kubectl create namespace basic-components
          kubectl -n basic-components create secret generic chart-museum-credentials \
              --from-literal=username=admin \
              --from-literal=password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16) \
              --from-literal=aws_access_key_id=$(kubectl -n storage get secret minio-credentials -o jsonpath='{.data.rootUser}' | base64 -d) \
              --from-literal=aws_secret_access_key=$(kubectl -n storage get secret minio-credentials -o jsonpath='{.data.rootPassword}' | base64 -d)
          

          2.prepare `chart-museum.yaml`

          Storage In
          kubectl apply -f - << EOF
          apiVersion: argoproj.io/v1alpha1
          kind: Application
          metadata:
            name: chart-museum
          spec:
            syncPolicy:
              syncOptions:
                - CreateNamespace=true
            project: default
            source:
              repoURL: https://chartmuseum.github.io/charts
              chart: chartmuseum
              targetRevision: 3.10.3
              helm:
                releaseName: chart-museum
                values: |
                  replicaCount: 1
                  image:
                    repository: m.daocloud.io/ghcr.io/helm/chartmuseum
                  env:
                    open:
                      DISABLE_API: false
                      STORAGE: local
                      AUTH_ANONYMOUS_GET: true
                    existingSecret: "chart-museum-credentials"
                    existingSecretMappings:
                      BASIC_AUTH_USER: "username"
                      BASIC_AUTH_PASS: "password"
                  persistence:
                    enabled: false
                    storageClass: ""
                  volumePermissions:
                    image:
                      registry: m.daocloud.io/docker.io
                  ingress:
                    enabled: true
                    ingressClassName: nginx
                    annotations:
                      cert-manager.io/cluster-issuer: self-signed-ca-issuer
                      nginx.ingress.kubernetes.io/rewrite-target: /$1
                    hosts:
                      - name: chartmuseum.dev.72602.online
                        path: /?(.*)
                        tls: true
                        tlsSecret: chartmuseum.dev.72602.online-tls
            destination:
              server: https://kubernetes.default.svc
              namespace: basic-components
          EOF
          
          kubectl apply -f - << EOF
          apiVersion: argoproj.io/v1alpha1
          kind: Application
          metadata:
            name: chart-museum
          spec:
            syncPolicy:
              syncOptions:
                - CreateNamespace=true
            project: default
            source:
              repoURL: https://chartmuseum.github.io/charts
              chart: chartmuseum
              targetRevision: 3.10.3
              helm:
                releaseName: chart-museum
                values: |
                  replicaCount: 1
                  image:
                    repository: m.daocloud.io/ghcr.io/helm/chartmuseum
                  env:
                    open:
                      DISABLE_API: false
                      STORAGE: amazon
                      STORAGE_AMAZON_ENDPOINT: http://minio-api.dev.72602.online:32080
                      STORAGE_AMAZON_BUCKET: chart-museum
                      STORAGE_AMAZON_PREFIX: charts
                      STORAGE_AMAZON_REGION: us-east-1
                      AUTH_ANONYMOUS_GET: true
                    existingSecret: "chart-museum-credentials"
                    existingSecretMappings:
                      BASIC_AUTH_USER: "username"
                      BASIC_AUTH_PASS: "password"
                      AWS_ACCESS_KEY_ID: "aws_access_key_id"
                      AWS_SECRET_ACCESS_KEY: "aws_secret_access_key"
                  persistence:
                    enabled: false
                    storageClass: ""
                  volumePermissions:
                    image:
                      registry: m.daocloud.io/docker.io
                  ingress:
                    enabled: true
                    ingressClassName: nginx
                    annotations:
                      cert-manager.io/cluster-issuer: self-signed-ca-issuer
                      nginx.ingress.kubernetes.io/rewrite-target: /$1
                    hosts:
                      - name: chartmuseum.dev.72602.online
                        path: /?(.*)
                        tls: true
                        tlsSecret: chartmuseum.dev.72602.online-tls
            destination:
              server: https://kubernetes.default.svc
              namespace: basic-components
          EOF
          
          apiVersion: argoproj.io/v1alpha1
          kind: Application
          metadata:
            name: chart-museum
          spec:
            syncPolicy:
              syncOptions:
                - CreateNamespace=true
            project: default
            source:
              repoURL: https://chartmuseum.github.io/charts
              chart: chartmuseum
              targetRevision: 3.10.3
              helm:
                releaseName: chart-museum
                values: |
                  replicaCount: 1
                  image:
                    repository: m.daocloud.io/ghcr.io/helm/chartmuseum
                  env:
                    open:
                      DISABLE_API: false
                      STORAGE: local
                      AUTH_ANONYMOUS_GET: true
                    existingSecret: "chart-museum-credentials"
                    existingSecretMappings:
                      BASIC_AUTH_USER: "username"
                      BASIC_AUTH_PASS: "password"
                  persistence:
                    enabled: false
                    storageClass: ""
                  volumePermissions:
                    image:
                      registry: m.daocloud.io/docker.io
                  ingress:
                    enabled: true
                    ingressClassName: nginx
                    annotations:
                      cert-manager.io/cluster-issuer: self-signed-ca-issuer
                      nginx.ingress.kubernetes.io/rewrite-target: /$1
                    hosts:
                      - name: chartmuseum.dev.72602.online
                        path: /?(.*)
                        tls: true
                        tlsSecret: chartmuseum.dev.72602.online-tls
            destination:
              server: https://kubernetes.default.svc
              namespace: basic-components
          

          3.sync by argocd

          Details
          argocd app sync argocd/chart-museum

          Uploading a Chart Package

          Follow “How to Run” section below to get ChartMuseum up and running at http://localhost:8080

          First create mychart-0.1.0.tgz using the Helm CLI:

          cd mychart/
          helm package .

          Upload mychart-0.1.0.tgz:

          curl --data-binary "@mychart-0.1.0.tgz" http://localhost:8080/api/charts

          If you’ve signed your package and generated a provenance file, upload it with:

          curl --data-binary "@mychart-0.1.0.tgz.prov" http://localhost:8080/api/prov

          Both files can also be uploaded at once (or one at a time) on the /api/charts route using the multipart/form-data format:

          curl -F "chart=@mychart-0.1.0.tgz" -F "prov=@mychart-0.1.0.tgz.prov" http://localhost:8080/api/charts

          You can also use the helm-push plugin:

          helm cm-push mychart/ chartmuseum

          Installing Charts into Kubernetes

          Add the URL to your ChartMuseum installation to the local repository list:

          helm repo add chartmuseum http://localhost:8080

          Search for charts:

          helm search repo chartmuseum/

          Install chart:

          helm install chartmuseum/mychart --generate-name

          FAQ

          Q1: Show me almost endless possibilities

          You can add standard markdown syntax:

          • multiple paragraphs
          • bullet point lists
          • emphasized, bold and even bold emphasized text
          • links
          • etc.
          ...and even source code

          the possibilities are endless (almost - including other shortcodes may or may not work)

          Q2: Show me almost endless possibilities

          You can add standard markdown syntax:

          • multiple paragraphs
          • bullet point lists
          • emphasized, bold and even bold emphasized text
          • links
          • etc.
          ...and even source code

          the possibilities are endless (almost - including other shortcodes may or may not work)

          Jun 7, 2024

          Install Harbor

          Mar 7, 2025

          Install Minio

          Installation

          Install By

          Preliminary

          1. Kubernetes is installed; if not, check ๐Ÿ”—link


          2. Helm binary is installed; if not, check ๐Ÿ”—link


          Preliminary

          1. Kubernetes is installed; if not, check ๐Ÿ”—link


          2. ArgoCD is installed; if not, check ๐Ÿ”—link


          3. Ingress is installed on ArgoCD; if not, check ๐Ÿ”—link


          4. Cert-manager has installed on argocd and the clusterissuer has a named `self-signed-ca-issuer`service, , if not check ๐Ÿ”—link


          1.prepare minio credentials secret

          Details
          kubectl get namespaces storage > /dev/null 2>&1 || kubectl create namespace storage
          kubectl -n storage create secret generic minio-secret \
              --from-literal=root-user=admin \
              --from-literal=root-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

          2.prepare `deploy-minio.yaml`

          ```shell kubectl -n argocd apply -f https://raw.githubusercontent.com/AaronYang0628/docs/main/manifests/zjlab/minio.yaml ```

          Details
          kubectl -n argocd apply -f - << EOF
          apiVersion: argoproj.io/v1alpha1
          kind: Application
          metadata:
            name: minio
          spec:
            syncPolicy:
              syncOptions:
              - CreateNamespace=true
            project: default
            source:
              repoURL: https://aaronyang0628.github.io/helm-chart-mirror/charts
              chart: minio
              targetRevision: 16.0.10
              helm:
                releaseName: minio
                values: |
                  global:
                    imageRegistry: "m.daocloud.io/docker.io"
                    imagePullSecrets: []
                    storageClass: ""
                    security:
                      allowInsecureImages: true
                    compatibility:
                      openshift:
                        adaptSecurityContext: auto
                  image:
                    registry: m.daocloud.io/docker.io
                    repository: bitnami/minio
                  clientImage:
                    registry: m.daocloud.io/docker.io
                    repository: bitnami/minio-client
                  mode: standalone
                  defaultBuckets: ""
                  auth:
                    # rootUser: admin
                    # rootPassword: ""
                    existingSecret: "minio-secret"
                  statefulset:
                    updateStrategy:
                      type: RollingUpdate
                    podManagementPolicy: Parallel
                    replicaCount: 1
                    zones: 1
                    drivesPerNode: 1
                  resourcesPreset: "micro"
                  resources: 
                    requests:
                      memory: 512Mi
                      cpu: 250m
                    limits:
                      memory: 512Mi
                      cpu: 250m
                  ingress:
                    enabled: true
                    ingressClassName: "nginx"
                    hostname: console.minio.72602.space
                    path: /?(.*)
                    pathType: ImplementationSpecific
                    annotations:
                      kubernetes.io/ingress.class: nginx
                      nginx.ingress.kubernetes.io/rewrite-target: /$1
                      cert-manager.io/cluster-issuer: lets-encrypt
                    tls: true
                    selfSigned: true
                    extraHosts: []
                  apiIngress:
                    enabled: true
                    ingressClassName: "nginx"
                    hostname: api.minio.72602.space
                    path: /?(.*)
                    pathType: ImplementationSpecific
                    annotations:
                      kubernetes.io/ingress.class: nginx
                      nginx.ingress.kubernetes.io/rewrite-target: /$1
                      cert-manager.io/cluster-issuer: lets-encrypt
                      nginx.ingress.kubernetes.io/proxy-body-size: "0"
                    tls: true
                    selfSigned: true
                    extraHosts: []
                  persistence:
                    enabled: false
                    storageClass: ""
                    mountPath: /bitnami/minio/data
                    accessModes:
                      - ReadWriteOnce
                    size: 8Gi
                    annotations: {}
                    existingClaim: ""
                  metrics:
                    prometheusAuthType: public
                    enabled: false
                    serviceMonitor:
                      enabled: false
                      namespace: ""
                      labels: {}
                      jobLabel: ""
                      paths:
                        - /minio/v2/metrics/cluster
                        - /minio/v2/metrics/node
                      interval: 30s
                      scrapeTimeout: ""
                      honorLabels: false
                    prometheusRule:
                      enabled: false
                      namespace: ""
                      additionalLabels: {}
                      rules: []
            destination:
              server: https://kubernetes.default.svc
              namespace: storage
          EOF

          3.sync by argocd

          Details
          argocd app sync argocd/minio

          4.verify GitOps and API ingress

          Details
          argocd app get argocd/minio --refresh --insecure --grpc-web
          kubectl -n storage get ingress minio-api \
            -o jsonpath='{.metadata.annotations.nginx\.ingress\.kubernetes\.io/proxy-body-size}{"\n"}'
          kubectl -n basic-components exec deploy/ingress-nginx-controller -- \
            nginx -T 2>/dev/null | grep -A20 'server_name api.minio.72602.space' | \
            grep client_max_body_size
          The ArgoCD application and MinIO resources must be `Synced`/`Healthy`, the annotation must be `0`, and generated nginx must show `client_max_body_size 0`. Run an authenticated S3 `PutObject`/`Stat`/`Delete` smoke test against `https://api.minio.72602.space` and remove the temporary object afterward. This annotation applies only to the MinIO API Ingress; do not disable body limits globally without review.

          5.decode minio secret

          Details
          kubectl -n storage get secret minio-secret -o jsonpath='{.data.root-password}' | base64 -d

          6.visit web console

          Login Credentials

          add $K8S_MASTER_IP console.minio.72602.space to /etc/hosts

          address: ๐Ÿ”—https://console.minio.72602.space/login

          access key: admin

          secret key: ``

          7.using mc

          Details
          K8S_MASTER_IP=$(kubectl get node -l node-role.kubernetes.io/control-plane -o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}')
          MINIO_ACCESS_SECRET=$(kubectl -n storage get secret minio-secret -o jsonpath='{.data.root-password}' | base64 -d)
          podman run --rm \
              --entrypoint bash \
               --add-host=api.minio.72602.space:${K8S_MASTER_IP} \
              -it m.daocloud.io/docker.io/minio/mc:latest \
              -c "mc alias set minio https://api.minio.72602.space admin ${MINIO_ACCESS_SECRET} \
                  && mc ls minio \
                  && mc mb --ignore-existing minio/test \
                  && mc cp /etc/hosts minio/test/etc/hosts \
                  && mc ls --recursive minio"
          Details
          K8S_MASTER_IP=$(kubectl get node -l node-role.kubernetes.io/control-plane -o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}')
          MINIO_ACCESS_SECRET=$(kubectl -n storage get secret minio-secret -o jsonpath='{.data.root-password}' | base64 -d)
          podman run --rm \
              --entrypoint bash \
               --add-host=api.minio.72602.space:${K8S_MASTER_IP} \
              -it m.daocloud.io/docker.io/minio/mc:latest

          Preliminary

          1. Docker is installed; if not, check ๐Ÿ”—link


          Using Proxy

          you can run an addinational daocloud image to accelerate your pulling, check Daocloud Proxy

          1.init server

          Details
          mkdir -p $(pwd)/minio/data
          podman run --rm \
              --name minio-server \
              -p 9000:9000 \
              -p 9001:9001 \
              -v $(pwd)/minio/data:/data \
              -d docker.io/minio/minio:latest server /data --console-address :9001

          2.use web console

          And then you can visit ๐Ÿ”—http://localhost:9001

          username: `minioadmin`

          password: `minioadmin`

          3.use internal client

          Details
          podman run --rm \
              --entrypoint bash \
              -it docker.io/minio/mc:latest \
              -c "mc alias set minio http://host.docker.internal:9000 minioadmin minioadmin \
                  && mc ls minio \
                  && mc mb --ignore-existing minio/test \
                  && mc cp /etc/hosts minio/test/etc/hosts \
                  && mc ls --recursive minio"

          FAQ

          Q1: Show me almost endless possibilities

          You can add standard markdown syntax:

          • multiple paragraphs
          • bullet point lists
          • emphasized, bold and even bold emphasized text
          • links
          • etc.
          ...and even source code

          the possibilities are endless (almost - including other shortcodes may or may not work)

          Q2: Show me almost endless possibilities

          You can add standard markdown syntax:

          • multiple paragraphs
          • bullet point lists
          • emphasized, bold and even bold emphasized text
          • links
          • etc.
          ...and even source code

          the possibilities are endless (almost - including other shortcodes may or may not work)

          Mar 7, 2024

          Install NFS

          Installation

          Install By

          Preliminary

          1. Kubernetes is installed; if not, check ๐Ÿ”—link


          2. Helm is installed; if not, check ๐Ÿ”—link


          Preliminary

          1. Kubernetes is installed; if not, check ๐Ÿ”—link


          2. ArgoCD is installed; if not, check ๐Ÿ”—link


          3. ingres has installed on argoCD, if not check ๐Ÿ”—link


          1.prepare `nfs-provisioner.yaml`

          Details
          apiVersion: argoproj.io/v1alpha1
          kind: Application
          metadata:
            name: nfs-provisioner
          spec:
            syncPolicy:
              syncOptions:
              - CreateNamespace=true
            project: default
            source:
              repoURL: https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner
              chart: nfs-subdir-external-provisioner
              targetRevision: 4.0.18
              helm:
                releaseName: nfs-provisioner
                values: |
                  image:
                    repository: m.daocloud.io/registry.k8s.io/sig-storage/nfs-subdir-external-provisioner
                    pullPolicy: IfNotPresent
                  nfs:
                    server: nfs.services.test
                    path: /
                    mountOptions:
                      - vers=4
                      - minorversion=0
                      - rsize=1048576
                      - wsize=1048576
                      - hard
                      - timeo=600
                      - retrans=2
                      - noresvport
                    volumeName: nfs-subdir-external-provisioner-nas
                    reclaimPolicy: Retain
                  storageClass:
                    create: true
                    defaultClass: true
                    name: nfs-external-nas
            destination:
              server: https://kubernetes.default.svc
              namespace: storage

          3.deploy mariadb

          Details
          kubectl -n argocd apply -f nfs-provisioner.yaml

          4.sync by argocd

          Details
          argocd app sync argocd/nfs-provisioner

          Preliminary

          1. Docker is installed; if not, check ๐Ÿ”—link


          Using Proxy

          you can run an addinational daocloud image to accelerate your pulling, check Daocloud Proxy

          1.init server

          Details
          echo -e "nfs\nnfsd" > /etc/modules-load.d/nfs4.conf
          modprobe nfs && modprobe nfsd
          mkdir -p $(pwd)/data/nfs/data
          echo '/data *(rw,fsid=0,no_subtree_check,insecure,no_root_squash)' > $(pwd)/data/nfs/exports
          podman run \
              --name nfs4 \
              --rm \
              --privileged \
              -p 2049:2049 \
              -v $(pwd)/data/nfs/data:/data \
              -v $(pwd)/data/nfs/exports:/etc/exports:ro \
              -d docker.io/erichough/nfs-server:2.2.1

          Preliminary

          1. centos yum repo source has updated, if not check ๐Ÿ”—link


          2.

          1.install nfs util

          sudo apt update -y
          sudo apt-get install nfs-common
          dnf update -y
          dnf install -y nfs-utils rpcbindn
          sudo apt update -y
          sudo apt-get install nfs-common

          2. create share folder

          Details
          mkdir /data && chmod 755 /data

          3.edit `/etc/exports`

          Details
          /data *(rw,sync,insecure,no_root_squash,no_subtree_check)

          4.start nfs server

          Details
          systemctl enable rpcbind
          systemctl enable nfs-server
          systemctl start rpcbind
          systemctl start nfs-server

          5.test load on localhost

          Details
          showmount -e localhost
          Expectd Output
          Export list for localhost:
          /data *

          6.test load on other ip

          Details
          showmount -e 192.168.aa.bb
          Expectd Output
          Export list for localhost:
          /data *

          7.mount nfs disk

          Details
          mkdir -p $(pwd)/mnt/nfs
          sudo mount -v 192.168.aa.bb:/data $(pwd)/mnt/nfs  -o proto=tcp -o nolock

          8.set nfs auto mount

          Details
          echo "192.168.aa.bb:/data /data nfs rw,auto,nofail,noatime,nolock,intr,tcp,actimeo=1800 0 0" >> /etc/fstab
          df -h

          Notes

          [Optional] create new partition
          disk size:
          fdisk /dev/vdb
          
          # n
          # p
          # w
          parted
          
          #select /dev/vdb 
          #mklabel gpt 
          #mkpart primary 0 -1
          #Cancel
          #mkpart primary 0% 100%
          #print
          [Optional] Format disk
          mkfs.xfs /dev/vdb1 -f
          [Optional] mount disk to folder
          mount /dev/vdb1 /data
          [Optional] mount when restart
          #vim `/etc/fstab` 
          /dev/vdb1     /data  xfs   defaults   0 0

          After updating /etc/fstab, run mount -a to validate configuration before rebooting.

          fstab fstab

          FAQ

          Q1: Show me almost endless possibilities

          You can add standard markdown syntax:

          • multiple paragraphs
          • bullet point lists
          • emphasized, bold and even bold emphasized text
          • links
          • etc.
          ...and even source code

          the possibilities are endless (almost - including other shortcodes may or may not work)

          Q2: Show me almost endless possibilities

          You can add standard markdown syntax:

          • multiple paragraphs
          • bullet point lists
          • emphasized, bold and even bold emphasized text
          • links
          • etc.
          ...and even source code

          the possibilities are endless (almost - including other shortcodes may or may not work)

          Mar 7, 2025

          Install Rook Ceph

          Mar 7, 2025

          Install Reids

          Installation

          Install By

          Preliminary

          1. Kubernetes is installed; if not, check ๐Ÿ”—link


          2. Helm is installed; if not, check ๐Ÿ”—link


          1.get helm repo

          Details
          helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
          helm repo update

          2.install chart

          Details
          helm install redis bitnami/redis \
            --namespace storage --create-namespace \
            --set architecture=standalone \
            --set auth.password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

          Preliminary

          1. Kubernetes is installed; if not, check ๐Ÿ”—link


          2. ArgoCD is installed; if not, check ๐Ÿ”—link


          1.prepare redis secret

          Details
          kubectl get namespaces storage > /dev/null 2>&1 || kubectl create namespace storage
          kubectl -n storage create secret generic redis-shared-credentials \
            --from-literal=redis-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

          2.prepare `deploy-redis.yaml`

          Details
          kubectl -n argocd apply -f - << EOF
          apiVersion: argoproj.io/v1alpha1
          kind: Application
          metadata:
            name: redis-shared
          spec:
            project: default
            syncPolicy:
              automated:
                prune: true
                selfHeal: true
              syncOptions:
              - CreateNamespace=true
            source:
              repoURL: https://charts.bitnami.com/bitnami
              chart: redis
              targetRevision: 18.16.0
              helm:
                releaseName: redis-shared
                values: |
                  architecture: standalone
                  auth:
                    enabled: true
                    existingSecret: redis-shared-credentials
                  master:
                    disableCommands:
                      - FLUSHDB
                      - FLUSHALL
                    persistence:
                      enabled: true
                      storageClass: local-path
                      size: 2Gi
                  image:
                    registry: m.daocloud.io/docker.io
                    repository: bitnamilegacy/redis
                    tag: latest
                    pullPolicy: IfNotPresent
                  metrics:
                    enabled: false
                  volumePermissions:
                    enabled: false
                  sysctl:
                    enabled: false
            destination:
              server: https://kubernetes.default.svc
              namespace: storage
          EOF

          3.sync by argocd

          ```bash argocd app sync redis-shared ```

          4.verify

          ```bash kubectl -n storage get pods -l app.kubernetes.io/instance=redis-shared kubectl -n storage exec redis-shared-master-0 -- redis-cli -a \ "\$(kubectl -n storage get secret redis-shared-credentials -o jsonpath='{.data.redis-password}' | base64 -d)" ping ```

          5.connection info

          ``` Host: redis-shared-master.storage.svc.cluster.local Port: 6379 Password: (stored in secret redis-shared-credentials) ```

          Preliminary

          1. Kubernetes is installed; if not, check ๐Ÿ”—link


          2. Helm is installed; if not, check ๐Ÿ”—link


          3. ArgoCD is installed; if not, check ๐Ÿ”—link


          1.prepare redis secret

          Details
          kubectl get namespaces storage > /dev/null 2>&1 || kubectl create namespace storage
          kubectl -n storage create secret generic redis-credentials \
            --from-literal=redis-password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)

          2.prepare `deploy-redis.yaml`

          Details
          kubectl -n argocd apply -f - << EOF
          apiVersion: argoproj.io/v1alpha1
          kind: Application
          metadata:
            name: redis
          spec:
            syncPolicy:
              syncOptions:
              - CreateNamespace=true
            project: default
            source:
              repoURL: https://charts.bitnami.com/bitnami
              chart: redis
              targetRevision: 18.16.0
              helm:
                releaseName: redis
                values: |
                  architecture: replication
                  auth:
                    enabled: true
                    sentinel: true
                    existingSecret: redis-credentials
                  master:
                    count: 1
                    disableCommands:
                      - FLUSHDB
                      - FLUSHALL
                    persistence:
                      enabled: true
                      storageClass: nfs-external
                      size: 8Gi
                  replica:
                    replicaCount: 3
                    disableCommands:
                      - FLUSHDB
                      - FLUSHALL
                    persistence:
                      enabled: true
                      storageClass: nfs-external
                      size: 8Gi
                  image:
                    registry: m.daocloud.io/docker.io
                    pullPolicy: IfNotPresent
                  sentinel:
                    enabled: false
                    persistence:
                      enabled: false
                    image:
                      registry: m.daocloud.io/docker.io
                      pullPolicy: IfNotPresent
                  metrics:
                    enabled: false
                    image:
                      registry: m.daocloud.io/docker.io
                      pullPolicy: IfNotPresent
                  volumePermissions:
                    enabled: false
                    image:
                      registry: m.daocloud.io/docker.io
                      pullPolicy: IfNotPresent
                  sysctl:
                    enabled: false
                    image:
                      registry: m.daocloud.io/docker.io
                      pullPolicy: IfNotPresent
                  extraDeploy:
                    - |
                      apiVersion: apps/v1
                      kind: Deployment
                      metadata:
                        name: redis-tool
                        namespace: csst
                        labels:
                          app.kubernetes.io/name: redis-tool
                      spec:
                        replicas: 1
                        selector:
                          matchLabels:
                            app.kubernetes.io/name: redis-tool
                        template:
                          metadata:
                            labels:
                              app.kubernetes.io/name: redis-tool
                          spec:
                            containers:
                            - name: redis-tool
                              image: m.daocloud.io/docker.io/bitnami/redis:7.2.4-debian-12-r8
                              imagePullPolicy: IfNotPresent
                              env:
                              - name: REDISCLI_AUTH
                                valueFrom:
                                  secretKeyRef:
                                    key: redis-password
                                    name: redis-credentials
                              - name: TZ
                                value: Asia/Shanghai
                              command:
                              - tail
                              - -f
                              - /etc/hosts
            destination:
              server: https://kubernetes.default.svc
              namespace: storage
          EOF

          3.sync by argocd

          Details
          argocd app sync argocd/redis

          4.decode password

          Details
          kubectl -n storage get secret redis-credentials -o jsonpath='{.data.redis-password}' | base64 -d

          Preliminary

          1. Docker|Podman|Buildah is installed; if not, check ๐Ÿ”—link


          Using Proxy

          you can run an addinational daocloud image to accelerate your pulling, check Daocloud Proxy

          1.init server

          Details

          Preliminary

          1. Kubernetes is installed; if not, check ๐Ÿ”—link


          2. Helm is installed; if not, check ๐Ÿ”—link


          3. ArgoCD is installed; if not, check ๐Ÿ”—link


          4. Argo Workflow is installed; if not, check ๐Ÿ”—link


          1.prepare `argocd-login-credentials`

          Details
          kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database

          2.apply rolebinding to k8s

          Details
          kubectl apply -f - <<EOF
          ---
          apiVersion: rbac.authorization.k8s.io/v1
          kind: ClusterRole
          metadata:
            name: application-administrator
          rules:
            - apiGroups:
                - argoproj.io
              resources:
                - applications
              verbs:
                - '*'
            - apiGroups:
                - apps
              resources:
                - deployments
              verbs:
                - '*'
          
          ---
          apiVersion: rbac.authorization.k8s.io/v1
          kind: RoleBinding
          metadata:
            name: application-administration
            namespace: argocd
          roleRef:
            apiGroup: rbac.authorization.k8s.io
            kind: ClusterRole
            name: application-administrator
          subjects:
            - kind: ServiceAccount
              name: argo-workflow
              namespace: business-workflows
          
          ---
          apiVersion: rbac.authorization.k8s.io/v1
          kind: RoleBinding
          metadata:
            name: application-administration
            namespace: application
          roleRef:
            apiGroup: rbac.authorization.k8s.io
            kind: ClusterRole
            name: application-administrator
          subjects:
            - kind: ServiceAccount
              name: argo-workflow
              namespace: business-workflows
          EOF

          4.prepare `deploy-xxxx-flow.yaml`

          Details

          6.submit to argo workflow client

          Details
          argo -n business-workflows submit deploy-xxxx-flow.yaml

          7.decode password

          Details
          kubectl -n application get secret xxxx-credentials -o jsonpath='{.data.xxx-password}' | base64 -d

          FAQ

          Q1: Show me almost endless possibilities

          You can add standard markdown syntax:

          • multiple paragraphs
          • bullet point lists
          • emphasized, bold and even bold emphasized text
          • links
          • etc.
          ...and even source code

          the possibilities are endless (almost - including other shortcodes may or may not work)

          Q2: Show me almost endless possibilities

          You can add standard markdown syntax:

          • multiple paragraphs
          • bullet point lists
          • emphasized, bold and even bold emphasized text
          • links
          • etc.
          ...and even source code

          the possibilities are endless (almost - including other shortcodes may or may not work)

          tests

          • kubectl -n storage exec -it deployment/redis-tool -- \
                redis-cli -c -h redis-master.storage ping
          • kubectl -n storage exec -it deployment/redis-tool -- \
                redis-cli -c -h redis-master.storage set mykey somevalue
          • kubectl -n storage exec -it deployment/redis-tool -- \
                redis-cli -c -h redis-master.storage get mykey
          • kubectl -n storage exec -it deployment/redis-tool -- \
                redis-cli -c -h redis-master.storage del mykey
          • kubectl -n storage exec -it deployment/redis-tool -- \
                redis-cli -c -h redis-master.storage get mykey
          May 7, 2024

          Subsections of Streaming

          Install Flink Operator

          Installation

          Install By

          Preliminary

          1. Kubernetes is installed; if not, check ๐Ÿ”—link


          2. Helm is installed; if not, check ๐Ÿ”—link


          3. Cert-manager is installed; if not, check ๐Ÿ”—link


          1.get helm repo

          Details
          helm repo add flink-operator-repo https://downloads.apache.org/flink/flink-kubernetes-operator-1.11.0/
          helm repo update

          latest version : ๐Ÿ”—https://flink.apache.org/downloads/#apache-flink-kubernetes-operator

          2.install chart

          Details
          helm install --create-namespace -n flink flink-kubernetes-operator flink-operator-repo/flink-kubernetes-operator --set image.repository=m.lab.zverse.space/ghcr.io/apache/flink-kubernetes-operator --set image.tag=1.11.0 --set webhook.create=false
          Reference

          Preliminary

          1. Kubernetes is installed; if not, check ๐Ÿ”—link


          2. ArgoCD is installed; if not, check ๐Ÿ”—link


          3. Cert-manager has installed on argocd and the clusterissuer has a named self-signed-ca-issuer service , if not check ๐Ÿ”—link


          4. Ingress is installed on ArgoCD; if not, check ๐Ÿ”—link


          2.prepare `flink-operator.yaml`

          Details
          kubectl -n argocd apply -f - << EOF
          apiVersion: argoproj.io/v1alpha1
          kind: Application
          metadata:
            name: flink-operator
          spec:
            syncPolicy:
              syncOptions:
              - CreateNamespace=true
            project: default
            source:
              repoURL: https://downloads.apache.org/flink/flink-kubernetes-operator-1.11.0
              chart: flink-kubernetes-operator
              targetRevision: 1.11.0
              helm:
                releaseName: flink-operator
                values: |
                  image:
                    repository: m.daocloud.io/ghcr.io/apache/flink-kubernetes-operator
                    pullPolicy: IfNotPresent
                    tag: "1.11.0"
                version: v3
            destination:
              server: https://kubernetes.default.svc
              namespace: flink
          EOF

          3.sync by argocd

          Details
          argocd app sync argocd/flink-operator

          FAQ

          Q1: Show me almost endless possibilities

          You can add standard markdown syntax:

          • multiple paragraphs
          • bullet point lists
          • emphasized, bold and even bold emphasized text
          • links
          • etc.
          ...and even source code

          the possibilities are endless (almost - including other shortcodes may or may not work)

          Q2: Show me almost endless possibilities

          You can add standard markdown syntax:

          • multiple paragraphs
          • bullet point lists
          • emphasized, bold and even bold emphasized text
          • links
          • etc.
          ...and even source code

          the possibilities are endless (almost - including other shortcodes may or may not work)