Subsections of ๐ชInstall Shit
AI Agent
Subsections of AI Agent
Hermes
OpenCode
๐Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link1.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"
}
EOFkubectl -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"
}
EOFkubectl -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"
}
EOFkubectl -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"
}
EOFkubectl -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"
}
EOF2.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
EOF3.sync by argocd
Details
argocd app sync argocd/opencode4.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 ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link0. (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
EOF1.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
EOF3.sync by argocd
Details
argocd app sync argocd/opencode4.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 | bash6.use bridge to manage session

๐Hugo Docs Site
The Hugo documentation site is deployed via ArgoCD on ops.docs.72602.online (formerly port.72602.online).
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link1.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
EOF2.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:
| Agent | Role | Target |
|---|---|---|
k3s-maintainer | Cluster operations | k3s cluster health, pod management, node maintenance |
doc-maintainer | Documentation updates | Hugo 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 } }
}
}
EOFDeploy 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:
| Optimization | Before | After |
|---|---|---|
| GitHub proxy for ArgoCD | Direct GitHub access | ghfast.top mirror |
| Git repo size | 117 MB | 44 MB |
| ArgoCD sync time | slow (~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.top2. 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=now3. Fast ArgoCD Sync - achieved by combining ServerSideApply, lean manifests, and cached images
Details
syncPolicy:
syncOptions:
- ServerSideApply=true๐๏ธFAQ
ClaudeCode
Ops Agent
๐Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link1.build and push Ops Agent image
Details
cd /home/aaron/Ops/docs
./manifests/ops-agent/build-and-push.shThe 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.shcreate-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=600sargocd/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=300sThe 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
| Agent | Responsibility | Operational source |
|---|---|---|
72602-k3s-maintainer | Operate the local 72602 cluster | Live cluster, then content/CSP/72602/_index.md |
zjlab-ops-maintainer | Operate ZJLAB through private SSH aliases | Live cluster, then the private inventory |
hugo-doc-maintainer | Maintain Relearn layout and runbooks | Relearn 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-keyThe 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/healththrough the configured internal cluster-local URL (SUB2API_BASE_URL), not the publictoken.72602.spaceendpoint.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_configonly 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": askOther 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:
- 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, writesapplication/sub2api-mcpkeyadmin-api-key, and exits without echoing the value. - 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 - Verify
global/healthreportshealthy: true,/mcpreports exactly{"sub2api-admin":{"status":"connected"}}, and the merged OpenCode config carries the cluster-localSUB2API_BASE_URLwithout the admin key. - Through
72602-k3s-maintainer, runsub2api-admin_readagainst/api/v1/admin/system/version; the live application must respond0.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=300sDo not patch the Deployment, delete the Ingress/PVC/Secrets, or scale the Git-owned workload as a rollback path.
OpenClaw
๐Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link1.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_KEY2.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
EOF3.sync by argocd
Details
argocd app sync argocd/openclawPreliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link1.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_KEY2.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
EOF3.sync by argocd
Details
argocd app sync argocd/openclawUsing AY ACR Image Mirror
Using DaoCloud Mirror
๐๏ธFAQ
BI
Subsections of BI
Install Superset
๐Installation
1.get helm repo
Details
helm repo add xxxxx https://xxxx
helm repo update2.install chart
Details
helm install xxxxx/chart-name --generate-name --version a.b.cUsing 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.c4. Postgresql is installed; if not, check ๐link
5. Redis is installed; if not, check ๐link1.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_PASSWORD2.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
EOFDetails
kubectl -n argocd apply -f -<< EOF
EOF3.sync by argocd
Details
argocd app sync argocd/supersetUsing 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 database2.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.yaml7.decode password
Details
kubectl -n application get secret xxxx-credentials -o jsonpath='{.data.xxx-password}' | base64 -d1.init server
Details
Using AY ACR Image Mirror
Using DaoCloud Mirror
๐๏ธFAQ
Application
Subsections of Application
N8N
๐Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link- 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
EOF3.sync by argocd
Details
argocd app sync argocd/n8nUsing AY ACR Image Mirror
Using DaoCloud Mirror
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link- 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 pvcImportant
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
EOF3.sync by argocd
Details
argocd app sync argocd/n8nUsing AY ACR Image Mirror
Using DaoCloud Mirror
๐๏ธFAQ
Wechat Markdown Editor
Official Documentation: https://github.com/doocs/md
๐Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link1.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
EOF2.sync by argocd
Details
argocd app sync argocd/wx-article-editorPreliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link1.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
EOF2.sync by argocd
Details
argocd app sync argocd/wx-article-editor1.run container
Details
docker run -d --name wx-article-editor -p 8080:80 doocs/md:latest2.access in browser
Details
open http://localhost:8080Verify
Details
kubectl -n application get pods
kubectl -n application get ingressIf deployed in ZJ environment, open https://md.dev.72602.online.
If deployed in 72602 environment, open https://md.72602.online.
๐๏ธFAQ
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 ofargocd/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)
- Install (ArgoCD)
Deploy Charge Spot Quest via 72602 GitOps ArgoCD
Subsections of Charge Spot Quest
Install (ArgoCD)
๐Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link1.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 absent2.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=120sThe 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 6004.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/nullExpected 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 300Auth
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 ็่ฏทๆฑ๏ผๆ นๆฎๅฎไน็็บฆๆๅฏน่ฏทๆฑ่ฟ่ก่ฏไผฐ๏ผๅฆๆ่ฏทๆฑ่ฟๅไบไปปไฝ็บฆๆ๏ผๅๆ็ป่ฏฅ่ฏทๆฑใ
Features
็บฆๆ็ฎก็
่ชๅฎไน็บฆๆๆจกๆฟ๏ผ็จๆทๅฏไปฅไฝฟ็จ Rego ่ฏญ่จ็ผๅ่ชๅฎไน็็บฆๆๆจกๆฟ๏ผๅฎ็ฐๅ็งๅคๆ็็ญ็ฅ้ป่พใ
ไพๅฆ๏ผๅฏไปฅๅฎไน็ญ็ฅ่ฆๆฑๆๆ็ๅฝๅ็ฉบ้ด NameSpace ๅฟ ้กป่ฎพ็ฝฎ็นๅฎ็ๆ ็ญพ๏ผๆ่ ้ๅถๆไบๅฝๅ็ฉบ้ดๅช่ฝไฝฟ็จ็นๅฎ็้ๅใ
็บฆๆๆจกๆฟๅค็จ๏ผ็บฆๆๆจกๆฟๅฏไปฅ่ขซๅคไธช็บฆๆๅฎไพๅค็จ๏ผๆ้ซไบ็ญ็ฅ็ๅฏ็ปดๆคๆงๅๅค็จๆงใ
ไพๅฆ๏ผๅฏไปฅๅๅปบไธไธช้็จ็ๆ ็ญพ็บฆๆๆจกๆฟ๏ผ็ถๅๅจไธๅ็ๅฝๅ็ฉบ้ด NameSpace ไธญๅๅปบไธๅ็็บฆๆๅฎไพ๏ผ่ฆๆฑไธๅ็ๆ ็ญพใ
็บฆๆๆดๆฐ๏ผๅฝ็บฆๆๆจกๆฟๆ็บฆๆๅ็ๆดๆฐๆถ๏ผGatekeeper ไผ่ชๅจ้ๆฐ่ฏไผฐๆๆ็ธๅ ณ็่ตๆบ๏ผ็กฎไฟ็ญ็ฅ็ๅฎๆถ็ๆใ
่ตๆบๆงๅถ
ๅๅ ฅๆฆๆช๏ผๅฝๆ่ตๆบๅๅปบๆๆดๆฐ่ฏทๆฑๆถ๏ผ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 (ๅๆญฅ้ ็ฝฎ)ๆฅๆๅฎ่ฟๆปคๅๅฟฝ็ฅ้ฃไบ่ตๆบ
ๅ่งๆงไฟ่ฏ
่กไธๆ ๅๅ่ชๅฎไน่ง่๏ผ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
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/v3.18.2/deploy/gatekeeper.yamlhelm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm install gatekeeper/gatekeeper --name-template=gatekeeper --namespace gatekeeper-system --create-namespaceMake 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_IMAGEBinary
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.gzArgoCD 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 ~/.bashrcGolang 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.gzGradle 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.gzHelm 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/helmJQ 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/jqKind 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}/binKrew 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 krewKubectl 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}/binKustomize 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}/binMaven 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 ~/.bashrcMinikube 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}/binOpen 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/*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/yqCICD
Articles
FQA
Subsections of CICD
Install Argo CD
Preliminary
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 ~/.bashrc2. install components
Choose one installation path below. Helm is recommended when you want versioned upgrades and repeatable configuration.
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
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
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.yaml4. prepare argocd-server-external.yaml
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
EOFkubectl -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
EOFkubectl -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
EOF6. [Optional] prepare argocd-server-ingress.yaml
You also need an ingress controller (for example ingress-nginx or traefik). If not installed, check ๐link.
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
EOFBefore 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
EOFapiVersion: 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-tls8. get argocd initialized password
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d9. 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_PASSif 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 -fopen https://$(minikube ip):30443if 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.crtimport cert-manager-self-signed-ca-secret.crt into your browser
open https://argocd.dev.72602.onlineManage User Info
user readonly is using for homepage website to grab some data from kubernetes.
- 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- retrieve user
readonlytoken
argocd account list
argocd account generate-token --account readonlyManage GitHub Repo
- generate github deploy key
ssh-keygen -t rsa -b 4096 -C "github-deploy-key" -f id_rsa_github -N ""- 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
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
0. create workflow related namespace
kubectl get namespace business-workflows > /dev/null 2>&1 || kubectl create namespace business-workflows1. prepare argo-workflows.yaml
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: workflowskubectl -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
EOF2. install argo workflow binary
3. [Optional] apply to k8s
kubectl -n argocd apply -f argo-workflows.yaml4. sync by argocd
argocd app sync argocd/argo-workflows5. submit a test workflow
argo -n business-workflows submit https://raw.githubusercontent.com/argoproj/argo-workflows/master/examples/hello-world.yaml --serviceaccount=argo-workflow6. 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> --watchInstall Argo Event
Preliminary
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: argocd4. apply to k8s
kubectl -n argocd apply -f argo-events.yaml5. sync by argocd
argocd app sync argocd/argo-eventsReloader
Install
Details
helm repo add stakater https://stakater.github.io/stakater-charts
helm repo update
helm install reloader stakater/reloaderDetails
kubectl apply -f https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yamlUsage
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
Subsections of Container
Install Buildah
Reference
- you can directly install docker engine from ๐ถbuildah official website.
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.
runcRequirement 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.
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 buildahOnce the installation is complete, The buildah images command will list all the images:
buildah imagessudo yum -y install buildahOnce the installation is complete, start the Docker service
sudo systemctl enable docker
sudo systemctl start docker- Set up Docker’s apt repository.
sudo apt-get -y update
sudo apt-get -y install buildah- Verify that the installation is successful by running the hello-world image:
sudo buildah run hello-worldInfo
- 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
Install Docker
Install Podman
Reference
- you can directly install docker engine from ๐ณdocker official website.
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 podmansudo yum install -y podmansudo apt-get update
sudo apt-get -y install podmanRun 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"Database
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: applicationapiVersion: 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: application3. apply to k8s
kubectl -n argocd apply -f deploy-datahub.yaml4. sync by argocd
argocd app sync argocd/datahub5. 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.onlineto/etc/hosts
- datahub frontend: https://datahub.dev.72602.online:32443
- api: https://datahub.dev.72602.online:32443/openapi/swagger-ui/index.html
[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 environmentNOTE: 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 instanceInstall Clickhouse
Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. ArgoCD is installed; if not, check ๐link3. cert-manager has installed on argocd and the clusterissuer has a named `self-signed-ca-issuer`service, , if not check ๐link1.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: database3.deploy clickhouse
Details
kubectl -n argocd apply -f deploy-clickhouse.yaml4.sync by argocd
Details
argocd app sync argocd/clickhouse5.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: NodePort6.apply to k8s
Details
kubectl -n database apply -f clickhouse-interface.yaml7.extract clickhouse admin credentials
Details
kubectl -n database get secret clickhouse-admin-credentials -o jsonpath='{.data.password}' | base64 -d8.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 ๐linkUsing 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-alpine2.check dashboard
And then you can visit ๐http://localhost:181233.use cli api
And then you can visit ๐http://localhost:19000Details
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:stablePreliminary
1. Kubernetes is installed; if not, check ๐link2. ArgoCD is installed; if not, check ๐link3. Argo Workflow is installed; if not, check ๐link1.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
EOF4.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-clickhouse6.submit to argo workflow client
Details
argo -n business-workflows submit deploy-clickhouse-flow.yaml7.extract clickhouse admin credentials
Details
kubectl -n application get secret clickhouse-admin-credentials -o jsonpath='{.data.password}' | base64 -d8.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
EOFFAQ
Install ElasticSearch
Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link1.get helm repo
Details
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update2.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=03.verify deployment
Details
kubectl -n application get pods
kubectl -n application get svcChart Reference
for more information, you can check ๐https://artifacthub.io/packages/helm/bitnami/elasticsearch
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link1.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
EOF3.sync by argocd
Details
argocd app sync argocd/elastic-search4.extract elasticsearch admin credentials
Details
kubectl -n application get secret elastic-search-elasticsearch -o jsonpath='{.data.elastic-password}' | base64 -d5.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 ๐linkUsing 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 ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link4. Argo Workflow is installed; if not, check ๐link1.prepare `argocd-login-credentials`
Details
kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database2.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
EOF4.prepare `deploy-xxxx-flow.yaml`
Details
6.submit to argo workflow client
Details
argo -n business-workflows submit deploy-xxxx-flow.yaml7.decode password
Details
kubectl -n application get secret xxxx-credentials -o jsonpath='{.data.xxx-password}' | base64 -dFAQ
Install Kafka
Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm binary is installed; if not, check ๐link1.get helm repo
Details
helm repo add bitnami oci://registry-1.docker.io/bitnamicharts/kafka
helm repo update2.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
EOF3.validate function
- list topicsDetails
kubectl -n database exec -it deployment/kafka-client-tools -- bash -c \
'kafka-topics.sh --bootstrap-server $BOOTSTRAP_SERVER --command-config $CLIENT_CONFIG_FILE --list'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'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'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'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 ๐link2. ArgoCD is installed; if not, check ๐link3. Helm binary is installed; if not, check ๐link1.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
EOFkubectl -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
EOF2.sync by argocd
Details
argocd app sync argocd/kafka3.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
EOF6.validate function
- list topicsDetails
kubectl -n database exec -it deployment/kafka-client-tools -- bash -c \
'kafka-topics.sh --bootstrap-server $BOOTSTRAP_SERVER --command-config $CLIENT_CONFIG_FILE --list'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'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'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'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 ๐linkUsing 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.22.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 --list2.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 $TOPIC2.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-beginningFAQ
Install MariaDB
Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. ArgoCD is installed; if not, check ๐link3. cert-manager has installed on argocd and the clusterissuer has a named `self-signed-ca-issuer`service, , if not check ๐link1.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: database3.deploy mariadb
Details
kubectl -n argocd apply -f deploy-mariadb.yaml4.sync by argocd
Details
argocd app sync argocd/mariadb5.check mariadb
Details
kubectl -n database get secret mariadb-credentials -o jsonpath='{.data.mariadb-root-password}' | base64 -dPreliminary
1. Kubernetes is installed; if not, check ๐link2. ArgoCD is installed; if not, check ๐link3. Argo Workflow is installed; if not, check ๐link1.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
EOF3.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/Shanghai5.submit to argo workflow client
Details
argo -n business-workflows submit deploy-mariadb-flow.yaml6.decode password
Details
kubectl -n application get secret mariadb-credentials -o jsonpath='{.data.mariadb-root-password}' | base64 -dPreliminary
1. Docker is installed; if not, check ๐linkUsing 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=ROW2.use web console
And then you can visit ๐http://localhost:8080username: `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-apache3.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
- list all bin logs
SHOW BINARY LOGS;- 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
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: database3. apply to k8s
kubectl -n argocd apply -f deploy-milvus.yaml4. sync by argocd
argocd app sync argocd/milvus5. 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 -d7. [Optional] execute sql in pod
kubectl -n database exec -it xxxx bashmariadb -h 127.0.0.1 -u root -p$MARIADB_ROOT_PASSWORDAnd then you can check connection by
show status like 'Threads%';Install Neo4j
Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link1.get helm repo
Details
helm repo add neo4j https://helm.neo4j.com/neo4j
helm repo update2.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=defaultStorageClassChart Reference
for more information, you can check ๐https://artifacthub.io/packages/helm/neo4j/neo4j
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link1.prepare `deploy-xxxxx.yaml`
Details
2.apply to k8s
Details
kubectl -n argocd apply -f xxxx.yaml3.sync by argocd
Details
argocd app sync argocd/xxxx4.prepare yaml-content.yaml
Details
5.apply to k8s
Details
kubectl apply -f xxxx.yaml6.apply xxxx.yaml directly
Details
kubectl apply -f - <<EOF
EOFPreliminary
1. Docker|Podman|Buildah is installed; if not, check ๐linkUsing 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-bullseyePreliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link4. Argo Workflow is installed; if not, check ๐link1.prepare `argocd-login-credentials`
Details
kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database2.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
EOF4.prepare `deploy-xxxx-flow.yaml`
Details
6.submit to argo workflow client
Details
argo -n business-workflows submit deploy-xxxx-flow.yaml7.decode password
Details
kubectl -n application get secret xxxx-credentials -o jsonpath='{.data.xxx-password}' | base64 -dFAQ
Install Postgresql
Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link1.get helm repo
Details
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update2.install chart
Details
helm install bitnami/postgresql --generate-name --version 18.1.8Using 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.8Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link1.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
EOF3.sync by argocd
Details
argocd app sync argocd/postgresqlPreliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link1.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
EOF3.sync by argocd
Details
argocd app sync argocd/postgresqlPreliminary
1. Docker|Podman|Buildah is installed; if not, check ๐linkUsing 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.172.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.153.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 ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link4. Argo Workflow is installed; if not, check ๐link5. Minio artifact repository has been configured, if not check ๐link- endpoint: minio.storage:90001.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
EOF3.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/hosts6.submit to argo workflow client
Details
argo -n business-workflows submit deploy-postgresql.yaml7.decode password
Details
kubectl -n application get secret postgresql-credentials -o jsonpath='{.data.postgres-password}' | base64 -d8.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
Install PgAdmin
๐Installation
1.get helm repo
Details
helm repo add runix https://helm.runix.net/
helm repo update2.install chart
Details
helm install runix/pgadmin4 --generate-name --version 1.62.0Using 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.c1.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
EOFDetails
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
EOF3.sync by argocd
Details
argocd app sync argocd/pgadminUsing 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
Install Redis
Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link1.get helm repo
Details
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update2.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=trueChart Reference
for more information, you can check ๐https://artifacthub.io/packages/helm/bitnami/redis
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link1.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
EOF3.sync by argocd
Details
argocd app sync argocd/redis4.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 pingPreliminary
1. Docker|Podman|Buildah is installed; if not, check ๐linkUsing 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-alpine2.use internal client
Details
podman run --rm \
-it docker.io/library/redis:7.2.4-alpine \
redis-cli \
-h host.containers.internal \
set mykey somevaluePreliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link4. Argo Workflow is installed; if not, check ๐link5. Minio artifact repository has been configured, if not check ๐link- endpoint: minio.storage:90001.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
EOF3.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-redis6.submit to argo workflow client
Details
argo -n business-workflows submit deploy-redis-flow.yaml7.decode password
Details
kubectl -n application get secret redis-credentials -o jsonpath='{.data.redis-password}' | base64 -dFAQ
Git
Subsections of Git
Install Act Runner
Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm binary is installed; if not, check ๐link1.get helm repo
Details
helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
helm repo update2.prepare `act-runner-secret`
Details
kubectl -n application create secret generic act-runner-secret \
--from-literal=act-runner-token=4w3Sx0Hwe6VFevl473ZZ4nFVDvFvhKcEUBvpJ09L3.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.yaml4.install chart
Details
helm upgrade --create-namespace -n application --install -f ./act-runner-values.yaml act-runner ay-helm-mirror/act-runnerPreliminary
1. Kubernetes is installed; if not, check ๐link2. ArgoCD is installed; if not, check ๐link3. Helm binary is installed; if not, check ๐link1.prepare `act-runner-secret`
Details
kubectl -n application create secret generic act-runner-secret \
--from-literal=act-runner-token=4w3Sx0Hwe6VFevl473ZZ4nFVDvFvhKcEUBvpJ09L2.prepare
act-runner.yaml
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-runner5.use action
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_runner2.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-rootlessUsing 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_runner2.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-dindUsing Mirror
you can run an addinational daocloud image to accelerate your pulling, check Daocloud Proxy
FAQ
Install Gitea
Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm binary is installed; if not, check ๐link3. CertManager is installed; if not, check ๐link4. Ingress is installed; if not, check ๐link1.get helm repo
Details
helm repo add gitea-charts https://dl.gitea.com/charts/
helm repo update2.install chart
Details
helm install gitea gitea-charts/gitea --generate-nameUsing 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.3for more information, you can check ๐https://aaronyang0628.github.io/helm-chart-mirror/
Preliminary
1. Kubernetes is installed; if not, check ๐link2. ArgoCD is installed; if not, check ๐link3. Helm binary is installed; if not, check ๐link4. Ingress is installed on ArgoCD; if not, check ๐link5. Minio is installed; if not, check ๐link1.prepare `chart-museum-credentials`
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`
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.yaml4.sync by argocd
Details
argocd app sync argocd/gitea5.decode admin password
login ๐https://gitea.dev.72602.online:32443/, using user gitea_admin and passwordDetails
kubectl -n application get secret gitea-admin-credentials -o jsonpath='{.data.password}' | base64 -dFAQ
Install GitLab
HPC
MCP Related
Subsections of MCP Related
MCP Inspector
๐Installation
1.get helm repo
Details
helm repo add xxxxx https://xxxx
helm repo update2.install chart
Details
helm install xxxxx/chart-name --generate-name --version a.b.cUsing 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.c1.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
EOF3.sync by argocd
Details
argocd app sync argocd/xxxxUsing 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 database2.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.yaml7.decode password
Details
kubectl -n application get secret xxxx-credentials -o jsonpath='{.data.xxx-password}' | base64 -d1.init server
Details
Using AY ACR Image Mirror
Using DaoCloud Mirror
๐๏ธFAQ
Monitor
Subsections of Monitor
Install Homepage
Official Documentation: https://gethomepage.dev/
Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link1.install chart directly
Details
helm install homepage oci://ghcr.io/m0nsterrr/helm-charts/homepage2.you can modify the values.yaml and re-install
Details
helm install homepage oci://ghcr.io/m0nsterrr/helm-charts/homepage -f homepage.values.yamlUsing 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.0for more information, you can check ๐https://aaronyang0628.github.io/helm-chart-mirror/
Preliminary
1. Kubernetes is installed; if not, check ๐link2. ArgoCD is installed; if not, check ๐link3. Helm binary is installed; if not, check ๐link4. Ingress is installed on ArgoCD; if not, check ๐link1.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
EOF3.sync by argocd
Details
argocd app sync argocd/homepage5.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/hostsPreliminary
1. Kubernetes is installed; if not, check ๐link2. Docker is installed; if not, check ๐linkdocker 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.0Preliminary
1. Kubernetes is installed; if not, check ๐link2. Podman is installed; if not, check ๐linkpodman 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.0FAQ
Install Langfuse
Official Documentation: https://langfuse.com/docs
๐Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. Ingress is installed; if not, check ๐link4. Cert-Manager is installed; if not, check ๐link1.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: true3.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 \
--atomic4.monitor status
Details
kubectl -n monitor get pods
kubectl -n monitor get ingress
kubectl -n monitor logs deploy/langfuse-web --tail=100Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link1.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
EOF2.sync by argocd
Details
argocd app sync argocd/langfuse3.monitor status
Details
argocd app get argocd/langfuse
kubectl -n monitor get pods
kubectl -n monitor get ingressVerify
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.onlineIf response status is 200 or 302, open https://langfuse.dev.72602.online in browser.
Install Permetheus Stack
Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link1.get helm repo
Details
helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
helm repo update2.install chart
Details
helm install ay-helm-mirror/kube-prometheus-stack --generate-nameUsing 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.2for more information, you can check ๐https://aaronyang0628.github.io/helm-chart-mirror/
Preliminary
1. Kubernetes is installed; if not, check ๐link2. ArgoCD is installed; if not, check ๐link3. Helm binary is installed; if not, check ๐link4. Ingress is installed on ArgoCD; if not, check ๐link1.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
EOF3.sync by argocd
Details
argocd app sync argocd/prometheus-stack4.extract clickhouse admin credentials
Details
kubectl -n monitor get secret prometheus-stack-credentials -o jsonpath='{.data.grafana-password}' | base64 -d5.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**install based on docker
echo "start from head is important"FAQ
UptimeKuma
Web Page
uptime-kuma (https://uptime.72602.space)
Deployment
Details
kubectl get namespace monitor > /dev/null 2>&1 || kubectl create namespace monitor
kubectl -n monitor apply -f manifests/uptimekuma/Networking
Subsections of Networking
DNS Setup
Overview
For any self-hosted service to be accessible via browser, you need:
- A domain name (e.g.
72602.online) - DNS A records pointing each subdomain to your public IP
- (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.161Add 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 โ PodTLS Certificates
With ingress-nginx + cert-manager, TLS is automatic:
- Install cert-manager (see
Installation/Networking/Cert_Manager.md) - Create a ClusterIssuer named
lets-encrypt - Each Ingress gets annotation
cert-manager.io/cluster-issuer: lets-encrypt - 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-encryptClusterIssuer - ArgoCD installed
- DNS A records added for each target subdomain
Install Cert Manager
Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm binary is installed; if not, check ๐link1.get helm repo
Details
helm repo add cert-manager-repo https://charts.jetstack.io
helm repo update2.install chart
Details
helm install cert-manager-repo/cert-manager --generate-name --version 1.20.2Using 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.2for more information, you can check ๐https://aaronyang0628.github.io/helm-chart-mirror/
Preliminary
1. Kubernetes is installed; if not, check ๐link2. ArgoCD is installed; if not, check ๐link3. Helm binary is installed; if not, check ๐link1.prepare `cert-manager.yaml`
kubectl -n argocd apply -f https://raw.githubusercontent.com/AaronYang0628/docs/main/manifests/zjlab/cert-manager.yamlkubectl -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
EOFkubectl -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
EOF2.sync by argocd
Details
argocd app sync argocd/cert-managerPreliminary
1. Docker|Podman|Buildah is installed; if not, check ๐link1.just run
Details
docker run --name cert-manager -e ALLOW_EMPTY_PASSWORD=yes bitnami/cert-manager:latestUsing 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:latestPreliminary
1. Kubernetes is installed; if not, check ๐link1.just run
Details
kubectl create -f https://github.com/jetstack/cert-manager/releases/download/v1.20.2/cert-manager.yamlPrepare 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
EOFkubectl 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
EOFkubectl -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
EOFFAQ
FAQ
Install HAProxy
๐Installation
1.prepare ECS host and backups
ssh root@47.110.67.161 hostname
sudo ss -ltnp
sudo test -e /etc/haproxy || echo absentBack 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 haproxyDo 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:10993Do not terminate TLS or configure HTTP, relay, or authentication in HAProxy. Validate before starting it:
haproxy -c -f /etc/haproxy/haproxy.cfg4.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 -ltnpThe 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
Install Ingress
Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link1.get helm repo
Details
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update2.install chart
Details
helm install ingress-nginx/ingress-nginx --generate-nameUsing 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.1for more information, you can check ๐https://aaronyang0628.github.io/helm-chart-mirror/
Preliminary
1. Kubernetes is installed; if not, check ๐link2. ArgoCD is installed; if not, check ๐link1.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.yaml3.sync by argocd
Details
argocd app sync argocd/ingress-nginxFAQ
Install Istio
Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link1.get helm repo
Details
helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
helm repo update2.install chart
Details
helm install ay-helm-mirror/kube-prometheus-stack --generate-nameUsing Proxy
for more information, you can check ๐https://artifacthub.io/packages/helm/prometheus-community/prometheus
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link1.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
EOF2.sync by argocd
Details
argocd app sync argocd/istio-base3.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
EOF4.sync by argocd
Details
argocd app sync argocd/istiod5.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
EOF6.sync by argocd
Details
argocd app sync argocd/istio-ingressgatewayPreliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link4. Argo Workflow is installed; if not, check ๐link1.prepare `argocd-login-credentials`
Details
kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database2.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
EOF4.prepare `deploy-xxxx-flow.yaml`
Details
6.submit to argo workflow client
Details
argo -n business-workflows submit deploy-xxxx-flow.yaml7.decode password
Details
kubectl -n application get secret xxxx-credentials -o jsonpath='{.data.xxx-password}' | base64 -dFAQ
Install Nginx
1. prepare server.conf
cat << EOF > default.conf
server {
listen 80;
location / {
root /usr/share/nginx/html;
autoindex on;
}
}
EOF2. 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.txtTip
you can run an addinational daocloud image to accelerate your pulling, check Daocloud Proxy
visit http://localhost:8080
Install Traefik
Proxy
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, version14.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-pathPVC
Any commands or verification steps from the former deployment procedure are historical and non-runnable. They are intentionally not reproduced here.
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 ofargocd/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.
- Install (ArgoCD)
Deploy Ollama Moderation Gateway via 72602 GitOps ArgoCD
Subsections of Ollama Moderation Gateway
Install (ArgoCD)
๐Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link1.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=120sThe 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=nameThe 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 6004.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_KEYDetails
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 300After 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, sourcehttps://github.com/AaronYang0628/docs.git, pathmanifests - 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/startand 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, andPath=/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_PROXYandHTTPS_PROXYtohttp://192.168.0.25:17890and bypasses that proxy for cluster-local ranges. sub2api.home.geekcity.tech:32443is a separate external endpoint, not the 72602 ingress. It returns404for 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/usersub2api - Git source:
manifests/sub2api-argocd.yaml, owned byargocd/ops-docs - Current release: OCI chart
0.1.15, application0.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, andapplication/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_PASSWORDThe 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 mode700, files mode600). Only the shared PostgreSQLsub2apidatabase was dumped; n8n and other databases were not touched. - The host had no
pg_restore; PostgreSQL Poddatabase/postgresql-0hadpg_restore 18.3and GNUtar 1.34. The dump was copied temporarily withkubectl cp, checked with Pod-localpg_restore --list, and the temporary Pod file was removed. The previouskubectl exec -istreaming validation was not reused. - Non-empty artifacts:
sub2api.dump(19,640,824 bytes),sub2api-data.tgz(10,616,251 bytes), andsub2api.dump.list(77,853 bytes). Git revision, manifest, and PVC metadata were also captured. sha256sum -c SHA256SUMSandpg_restore --listboth succeeded.- The captured
origin/mainrevision wasce838b424f10316fc604a4a21517c90c7b6b97ae. 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 commit5230546610c437a02ee45f5b80cd804779c9170c). The scopedsub2api.dump(47,520,105 bytes) andsub2api-data.tgz(10,192,905 bytes) were non-empty;pg_restore --listand SHA-256 checks passed. schema_migrationsadvanced from 268 to 277 records; the latest migration is233_group_free_openai_fast.sql.- ArgoCD reported
Synced/Healthy; Deployment was 1/1 on the pinnedghcr.io/wei-shaw/sub2api@sha256:271bb3b34661803681cabf54e99811ab8e248b0dd4c88b09ea1226e22dea5751image. - 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 commit21d02345de47d75454841e464756f6cf9349cc3c). The scopedsub2api.dumpandsub2api-data.tgzwere non-empty;pg_restore --listand SHA-256 checks passed. - ArgoCD reported
Synced/Healthyat2026-09-05T13:03:41Z; Deployment was 1/1, Pod ready with 0 restarts, internal/healthreturned{"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 dump46,520,009bytes,/app/dataarchive10,214,969bytes; backup artifacts andpg_restore --list, archive listing, SHA-256 all passed; GitOps commit7bd44adb5ed1b61976b507e1f32bc990738782b2; sub2api ArgoCD target/observed0.1.14Synced/Healthy operation Succeeded; runtime verification: Deployment 1/1, Pod ready 0 restarts, chartsub2api-0.1.14/app 0.2.4, actual image digest matches, Service endpoint ready/serving, internal/healthHTTP 200, Redis StatefulSet 1/1. - No rollback required.
Verified upgrade: 2026-09-16
- Backup directory:
/home/aaron/Ops/backups/sub2api/upgrade-20260916T053309Z(directory mode700, files mode600). PostgreSQL dump27,593,406bytes,/app/dataarchive4,579,406bytes; backup artifacts andpg_restore --list, archive listing, SHA-256 all passed; GitOps commite2c0e4576276f6a299bbd27e80f40af883f8e877(chore(sub2api): upgrade to chart 0.1.15); sub2api ArgoCD target/observed0.1.15Synced/Healthy operation Succeeded; runtime verification: Deployment 1/1, Podsub2api-7c9c4b95bf-r6cpgRunning/Ready, restarts 0, chartsub2api-0.1.15/app 0.2.5, actual image digest matchessha256:4c5dffab6e5ba4d3bd5382f19aad9654847b4e23de1a3d48e190146a3e6eb977, Service endpoint ready at10.42.0.198:8080, internal/healthHTTP 200 body{"status":"ok"}, Redis StatefulSet ready at10.42.0.12:6379with 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_PASSWORD2.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_PASSWORD3.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=10mDo 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-apiInstall (ArgoCD)
๐Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link- PostgreSQL is available in namespace
database, DNS resolvestoken.72602.space, and ingress-nginx with thelets-encryptClusterIssuer 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-redisSecret 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 6004.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_IDExpected 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,challengeThe 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 600Do 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:main3.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 wideThe 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_IDAdmin 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:
| Tool | Purpose |
|---|---|
sub2api-admin_describe | Capabilities and safety constraints |
sub2api-admin_health | Anonymous check of /health through the configured internal cluster-local URL (SUB2API_BASE_URL), not the public host |
sub2api-admin_read | One allowlisted authenticated GET route |
sub2api-admin_find_user | Resolve exactly one user by normalized email |
sub2api-admin_preview_recharge | Non-mutating preview of an additive credit |
sub2api-admin_recharge | Additive credit with backend idempotency |
sub2api-admin_update_user_limits | Per-user RPM and/or concurrency |
sub2api-admin_set_account_schedulable | Enable or disable scheduling for an entire upstream account |
sub2api-admin_model_control_options | Explain 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:
- Collect an exact email and a positive amount.
- Call
sub2api-admin_preview_recharge. The server fuzzy-searches but accepts only one exact normalized email match. - 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.
- Generate one stable
Idempotency-Keyof 16-128 URL-safe characters. Keep and reuse that key when the result is uncertain; never generate a fresh key for a retry. - Call
sub2api-admin_rechargewithoperation: add, the exact email and id, the audit note, and the idempotency key. - Re-read the user and balance history; record the exact
verifiedoraccepted_unverifiedoutcome. 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_multiplierchanges 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_schedulabletoggles 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_configonly 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:
- 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 reportsapplication/sub2api-mcp keys=admin-api-key. - 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 - Verify
global/healthreportshealthy: true,/mcpreports exactly{"sub2api-admin":{"status":"connected"}}, and the merged OpenCode config carries the cluster-localSUB2API_BASE_URLwithout the new key. - Through
72602-k3s-maintainer, runsub2api-admin_readagainst/api/v1/admin/system/version; the live application must respond0.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=300sAfter 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-mcpAn 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
RPC
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/.localEnsure that the directory exists:
mkdir -p $MY_INSTALL_DIRAdd 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:
sudo apt install -y cmakebrew install cmake2.2 Install basic tools required to build gRPC
sudo apt install -y build-essential autoconf libtool pkg-configbrew install autoconf automake libtool pkg-config2.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/grpc2.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
popd3. 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/helloworld3.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 43.3 run the server
./greeter_server3.4 from a different terminal, run the client and see the client output:
./greeter_clientand the result should be like this:
Greeter received: Hello worldStorage
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-artifacts4. apply artifact-repositories.yaml to k8s
kubectl -n business-workflows apply -f artifact-repositories.yamlInstall Chart Museum
Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm binary is installed; if not, check ๐link1.get helm repo
Details
helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
helm repo update2.install chart
Details
helm install ay-helm-mirror/kube-prometheus-stack --generate-nameUsing 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.2for more information, you can check ๐https://aaronyang0628.github.io/helm-chart-mirror/
Preliminary
1. Kubernetes is installed; if not, check ๐link2. ArgoCD is installed; if not, check ๐link3. Helm binary is installed; if not, check ๐link4. Ingress is installed on ArgoCD; if not, check ๐link5. Minio is installed; if not, check ๐link1.prepare `chart-museum-credentials`
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`
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-museumUploading 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/chartsIf 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/provBoth 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/chartsYou can also use the helm-push plugin:
helm cm-push mychart/ chartmuseumInstalling Charts into Kubernetes
Add the URL to your ChartMuseum installation to the local repository list:
helm repo add chartmuseum http://localhost:8080Search for charts:
helm search repo chartmuseum/Install chart:
helm install chartmuseum/mychart --generate-nameFAQ
Install Harbor
Install JuiceFS
Install Minio
Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. ArgoCD is installed; if not, check ๐link3. Ingress is installed on ArgoCD; if not, check ๐link4. Cert-manager has installed on argocd and the clusterissuer has a named `self-signed-ca-issuer`service, , if not check ๐link1.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
EOF3.sync by argocd
Details
argocd app sync argocd/minio4.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_size5.decode minio secret
Details
kubectl -n storage get secret minio-secret -o jsonpath='{.data.root-password}' | base64 -d6.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:latestPreliminary
1. Docker is installed; if not, check ๐linkUsing 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 :90012.use web console
And then you can visit ๐http://localhost:9001username: `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
Install NFS
Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. ArgoCD is installed; if not, check ๐link3. ingres has installed on argoCD, if not check ๐link1.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: storage3.deploy mariadb
Details
kubectl -n argocd apply -f nfs-provisioner.yaml4.sync by argocd
Details
argocd app sync argocd/nfs-provisionerPreliminary
1. Docker is installed; if not, check ๐linkUsing 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.1Preliminary
1. centos yum repo source has updated, if not check ๐link2.1.install nfs util
sudo apt update -y
sudo apt-get install nfs-commondnf update -y
dnf install -y nfs-utils rpcbindnsudo apt update -y
sudo apt-get install nfs-common2. create share folder
Details
mkdir /data && chmod 755 /data3.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-server5.test load on localhost
Details
showmount -e localhost6.test load on other ip
Details
showmount -e 192.168.aa.bb7.mount nfs disk
Details
mkdir -p $(pwd)/mnt/nfs
sudo mount -v 192.168.aa.bb:/data $(pwd)/mnt/nfs -o proto=tcp -o nolock8.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 -hNotes
[Optional] create new partition
fdisk /dev/vdb
# n
# p
# wparted
#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 0After updating /etc/fstab, run mount -a to validate configuration before rebooting.
FAQ
Install Rook Ceph
Install Reids
Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link1.get helm repo
Details
helm repo add ay-helm-mirror https://aaronyang0628.github.io/helm-chart-mirror/charts
helm repo update2.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 ๐link2. ArgoCD is installed; if not, check ๐link1.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
EOF3.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 ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link1.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
EOF3.sync by argocd
Details
argocd app sync argocd/redis4.decode password
Details
kubectl -n storage get secret redis-credentials -o jsonpath='{.data.redis-password}' | base64 -dPreliminary
1. Docker|Podman|Buildah is installed; if not, check ๐linkUsing 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 ๐link2. Helm is installed; if not, check ๐link3. ArgoCD is installed; if not, check ๐link4. Argo Workflow is installed; if not, check ๐link1.prepare `argocd-login-credentials`
Details
kubectl get namespaces database > /dev/null 2>&1 || kubectl create namespace database2.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
EOF4.prepare `deploy-xxxx-flow.yaml`
Details
6.submit to argo workflow client
Details
argo -n business-workflows submit deploy-xxxx-flow.yaml7.decode password
Details
kubectl -n application get secret xxxx-credentials -o jsonpath='{.data.xxx-password}' | base64 -dFAQ
tests
kubectl -n storage exec -it deployment/redis-tool -- \ redis-cli -c -h redis-master.storage pingkubectl -n storage exec -it deployment/redis-tool -- \ redis-cli -c -h redis-master.storage set mykey somevaluekubectl -n storage exec -it deployment/redis-tool -- \ redis-cli -c -h redis-master.storage get mykeykubectl -n storage exec -it deployment/redis-tool -- \ redis-cli -c -h redis-master.storage del mykeykubectl -n storage exec -it deployment/redis-tool -- \ redis-cli -c -h redis-master.storage get mykey
Streaming
Subsections of Streaming
Install Flink Operator
Installation
Preliminary
1. Kubernetes is installed; if not, check ๐link2. Helm is installed; if not, check ๐link3. Cert-manager is installed; if not, check ๐link1.get helm repo
Details
helm repo add flink-operator-repo https://downloads.apache.org/flink/flink-kubernetes-operator-1.11.0/
helm repo updatelatest 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=falseReference
for more information, you can check ๐https://nightlies.apache.org/flink/flink-kubernetes-operator-docs-main/zh/docs/try-flink-kubernetes-operator/quick-start/
Preliminary
1. Kubernetes is installed; if not, check ๐link2. ArgoCD is installed; if not, check ๐link3. Cert-manager has installed on argocd and the clusterissuer has a named self-signed-ca-issuer service , if not check ๐link4. Ingress is installed on ArgoCD; if not, check ๐link2.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
EOF3.sync by argocd
Details
argocd app sync argocd/flink-operator


