本文记录了一套Windows + VirtualBox 环境下的OpenClaw部署流程,核心用到K8s、Helm、local-static-provisioner、nginx-ingress,所有组件镜像均使用私有仓库 ,同时解决了私有镜像拉取卡住、本地静态存储、Windows访问虚拟机K8s集群、OpenClaw HTTPS配置等关键问题,仅供测试学习使用。
一、环境前置说明
- 底层环境:Windows 10/11 + VirtualBox 虚拟机
- K8s集群:已部署完成(本文不赘述K8s/Helm基础部署)
- 虚拟机网卡:Host-Only 网卡(网段:192.168.56.x)
- 私有镜像仓库:192.168.56.102(Harbor)
- 核心组件私有镜像地址:
- Nginx-Ingress Controller:
192.168.56.102/library/registry.k8s.io/ingress-nginx/controller:v1.15.1 - Nginx Webhook:
192.168.56.102/library/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.6.9 - Local Static Provisioner:
192.168.56.102/library/registry.k8s.io/sig-storage/local-volume-provisioner:v2.8.0 - OpenClaw:
192.168.56.102/library/ghcr.io/openclaw/openclaw:2026.3.13-1
- Nginx-Ingress Controller:
二、local-static-provisioner 部署(本地静态存储)
2.1 本地目录创建(含子目录,完整步骤)
在所有K8s节点执行:
bash
# 1. 创建根目录
mkdir -p /mnt/fast-disks
# 2. 批量创建子目录 vol-0000 ~ vol-0009
for i in $(seq -w 0 9); do
mkdir -p /mnt/fast-disks/vol-00$i
chmod 777 /mnt/fast-disks/vol-00$i
done
# 3. 查看目录是否创建成功
ls -l /mnt/fast-disks/
2.2 目录绑定挂载(必须执行)
bash
for i in $(seq -w 0 9); do
DIR="/mnt/fast-disks/vol-00$i";
if [ -d "$DIR" ]; then
echo "Mounting $DIR ...";
mount --bind "$DIR" "$DIR";
# 永久挂载(重启不失效)
echo "$DIR $DIR none bind 0 0" >> /etc/fstab
fi;
done
# 验证挂载
mount | grep fast-disks
2.3 创建 StorageClass
fast-disks.yaml
yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-disks
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
bash
kubectl apply -f fast-disks.yaml
2.4 Helm 部署 local-static-provisioner(私有镜像)
provisioner-values.yaml
yaml
image: "192.168.56.102/library/registry.k8s.io/sig-storage/local-volume-provisioner:v2.8.0"
nameOverride: local-static-provisioner
storageClassName: fast-disks
discovery:
useMountPoint: false
volumes:
- name: local-disks
hostPath: /mnt/disks
mountPath: /mnt/disks
blockCleanerCommand:
- "/scripts/shred.sh"
- "2"
volumeMode: Filesystem
fsType: ext4
namePattern: "*"
部署:
bash
helm repo add sig-storage https://kubernetes-sigs.github.io/sig-storage-local-static-provisioner/
helm repo update
helm install local-provisioner sig-storage/local-static-provisioner -f provisioner-values.yaml
三、Nginx-Ingress 部署(私有镜像)
3.1 下载官方YAML并替换镜像
bash
curl -O https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/baremetal/deploy.yaml
替换为私有仓库镜像:
registry.k8s.io/ingress-nginx/controller:v1.15.1
→192.168.56.102/library/registry.k8s.io/ingress-nginx/controller:v1.15.1registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.6.9
→192.168.56.102/library/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.6.9
3.2 部署
bash
kubectl apply -f deploy.yaml
四、私有镜像同步(全组件)
在能访问外网的机器/虚拟机执行:
bash
# 1. OpenClaw
docker pull ghcr.io/openclaw/openclaw:2026.3.13-1
docker tag ghcr.io/openclaw/openclaw:2026.3.13-1 192.168.56.102/library/ghcr.io/openclaw/openclaw:2026.3.13-1
docker push 192.168.56.102/library/ghcr.io/openclaw/openclaw:2026.3.13-1
# 2. local-static-provisioner
docker pull registry.k8s.io/sig-storage/local-volume-provisioner:v2.8.0
docker tag registry.k8s.io/sig-storage/local-volume-provisioner:v2.8.0 192.168.56.102/library/registry.k8s.io/sig-storage/local-volume-provisioner:v2.8.0
docker push 192.168.56.102/library/registry.k8s.io/sig-storage/local-volume-provisioner:v2.8.0
# 3. nginx-ingress controller
docker pull registry.k8s.io/ingress-nginx/controller:v1.15.1
docker tag registry.k8s.io/ingress-nginx/controller:v1.15.1 192.168.56.102/library/registry.k8s.io/ingress-nginx/controller:v1.15.1
docker push 192.168.56.102/library/registry.k8s.io/ingress-nginx/controller:v1.15.1
# 4. nginx-ingress webhook
docker pull registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.6.9
docker tag registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.6.9 192.168.56.102/library/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.6.9
docker push 192.168.56.102/library/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.6.9
五、私有镜像拉取卡住问题(根因+解决方案)
问题现象
- 普通镜像:配置
certs.d/hosts.toml就能拉取 - 嵌套路径镜像(如
192.168.56.102/library/ghcr.io/openclaw/openclaw):一直卡住
必须配置两处
/etc/containerd/certs.d/192.168.56.102/hosts.toml
toml
server = "http://192.168.56.102"
[host."http://192.168.56.102"]
capabilities = ["pull", "resolve", "push"]
skip_verify = true
allow_insecure = true
[host."http://192.168.56.102".auth]
username = "admin"
password = "Harbor12345"
/etc/containerd/config.toml(解决嵌套镜像拉取关键)
toml
[plugins."io.containerd.grpc.v1.cri".registry.configs]
[plugins."io.containerd.grpc.v1.cri".registry.configs."192.168.56.102"]
[plugins."io.containerd.grpc.v1.cri".registry.configs."192.168.56.102".auth]
username = "admin"
password = "Harbor12345"
根因
containerd 对包含多层级/嵌套域名路径的镜像解析逻辑不同:
- 普通镜像:走
certs.d - 嵌套路径镜像:必须读取
config.toml里的全局认证才能正确鉴权
生效
bash
systemctl daemon-reload
systemctl restart containerd
六、OpenClaw 部署(核心配置完整版)
6.1 生成 HTTPS 证书(openclaw.local)
bash
cat > openssl.cnf <<EOF
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
x509_extensions = v3_req
[dn]
CN = openclaw.local
[v3_req]
subjectAltName = @alt_names
[alt_names]
DNS.1 = openclaw.local
EOF
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout tls.key \
-out tls.crt \
-config openssl.cnf
kubectl create secret tls openclaw-tls --cert=tls.crt --key=tls.key
6.2 openclaw-values.yaml(最关键正确配置)
yaml
app-template:
# ====================== 1. 私有镜像仓库 ======================
imageRegistry: "192.168.56.102/library"
controllers:
main:
initContainers:
init-config:
image:
repository: "{{ .Values.imageRegistry }}/ghcr.io/openclaw/openclaw"
tag: 2026.3.13-1
containers:
main:
image:
repository: "{{ .Values.imageRegistry }}/ghcr.io/openclaw/openclaw"
tag: 2026.3.13-1
#.....还有其他地方的镜像要修改,这里忽略...........................
# ====================== 2. Ingress + TLS ======================
ingress:
main:
enabled: true
className: nginx
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-body-size: "0"
tls:
- secretName: openclaw-tls
hosts:
- host: openclaw.local
paths:
- path: /
pathType: Prefix
backend:
service:
number: 18789
# ====================== 3. OpenClaw 配置文件 ======================
configMaps:
config:
enabled: true
data:
bash_aliases: |
alias openclaw='node /app/dist/index.js'
openclaw.json: |
{
// Gateway configuration
"gateway": {
"port": 18789,
"mode": "local",
"controlUi": {
"dangerouslyAllowHostHeaderOriginFallback": true
},
"auth": {
"mode": "token",
"token": "xxxxxxxx"
},
.....................
}
# ====================== 4. 持久化存储 ======================
persistence:
enabled: true
storageClass: fast-disks
size: 10Gi
mountPath: /data
6.3 部署 OpenClaw
bash
helm repo add openclaw-helm https://openclaw-helm.github.io/helm-charts
helm repo update
helm install my-openclaw openclaw-helm/openclaw -f openclaw-values.yaml
七、Windows 访问 openclaw.local(关键!Host-Only 虚拟机环境)
因为你是 Windows + VirtualBox K8s ,必须同时配置 hosts + 静态路由 才能访问。
7.1 配置 Windows hosts
路径:
C:\Windows\System32\drivers\etc\hosts
添加:
192.168.56.111 openclaw.local
(192.168.56.111 为你的 K8s 节点IP)
7.2 配置 Windows 静态路由(必须!)
以管理员身份 打开 CMD 执行:
cmd
route add 192.156.48.0 mask 255.255.255.0 192.168.56.111 -p
说明:
192.156.48.0/24:你的 K8s 服务网段(Service CIDR)192.168.56.111:虚拟机网关/节点IP-p:永久路由(重启不失效)
7.3 验证路由
cmd
route print | findstr 192.156.48.0
八、最终访问
浏览器直接打开:
https://openclaw.local
(自签名证书选择继续访问即可)
九、注意事项
- 所有配置均为测试环境,不可直接用于生产
- Local PV 绑定单节点,节点宕机数据不可用
- 自签名证书仅用于测试
- Windows 必须配置 hosts + 静态路由 才能正常访问虚拟机内 Ingress
- 嵌套路径镜像必须配置
config.toml认证,否则拉取失败