一、镜像拉取失败:你遇到的第一个拦路虎
部署OpenFaaS到Kubernetes集群时,Pod启动失败最常见的原因就是镜像拉取失败。你以为配置好一个YAML文件就能万事大吉?结果kubectl get pods一看,状态是ImagePullBackOff或者ErrImagePull,然后就开始抓狂。
这种情况多半是因为镜像仓库需要登录,或者你写的镜像标签根本不存在。比如,OpenFaaS的gateway镜像默认从Docker Hub拉取,但如果你公司内部用的是私有仓库,没有配置凭证,那K8s肯定找不到。或者你写了个latest标签,但本地已经缓存了旧版本,导致版本不匹配。
1.1 私有仓库认证:imagePullSecrets是关键
如果你的OpenFaaS镜像放在私有仓库(比如阿里云镜像仓库、AWS ECR、或者自建的Harbor),必须让K8s知道怎么登录。通常的做法是创建一个Secret,然后在Pod的Spec里引用它。
# 示例:创建私有仓库的Secret
# 技术栈:Kubernetes Secret(YAML)
apiVersion: v1
kind: Secret
metadata:
name: my-private-registry-secret
namespace: openfaas
data:
# 以下值需要base64编码
# 实际用户名: myuser,密码: mypassword,邮箱: myemail@example.com
.dockerconfigjson: eyJhdXRocyI6eyJodHRwczovL2luZGV4LmRvY2tlci5pby92MSI6eyJ1c2VybmFtZSI6Im15dXNlciIsInBhc3N3b3JkIjoibXlwYXNzd29yZCIsImVtYWlsIjoibXllbWFpbEBleGFtcGxlLmNvbSJ9fX0= # 示例值,实际需要替换
type: kubernetes.io/dockerconfigjson
然后在你使用OpenFaaS的Deployment或DaemonSet里,加上imagePullSecrets:
# 示例:在OpenFaaS gateway的Deployment中引用私有仓库凭证
# 技术栈:Kubernetes Deployment(YAML)
apiVersion: apps/v1
kind: Deployment
metadata:
name: gateway
namespace: openfaas
spec:
replicas: 1
selector:
matchLabels:
app: gateway
template:
metadata:
labels:
app: gateway
spec:
containers:
- name: gateway
image: myprivaterepo.com/openfaas/gateway:0.24.0 # 这里填写私有镜像的完整路径
ports:
- containerPort: 8080
imagePullSecrets:
- name: my-private-registry-secret # 引用上面创建的Secret
注意:如果你用的不是Docker Hub,而是AWS ECR或者别的,凭证类型可能不一样。ECR需要用AWS IAM或者临时令牌,这时候可以借助kubectl create secret docker-registry来快速创建:
# 使用kubectl命令创建ECR的Secret(需要先获取登录令牌)
# 技术栈:Shell命令
# 前提:已经通过aws ecr get-login-password获取令牌,并设置环境变量
kubectl create secret docker-registry ecr-secret \
--docker-server=123456789012.dkr.ecr.us-east-1.amazonaws.com \
--docker-username=AWS \
--docker-password=$(aws ecr get-login-password --region us-east-1) \
--namespace=openfaas
很多人在这里容易犯的错:忘记指定namespace,结果Secret创建到了default命名空间,而Pod在openfaas命名空间里,找不到对应的Secret,镜像拉取继续失败。
1.2 镜像标签陷阱:别一味用latest
有些同学为了图省事,总是写image: openfaas/gateway:latest。但latest其实是个不靠谱的东西——它会在你每次重新拉取时随时变化。而且K8s的镜像拉取策略默认是IfNotPresent,如果本地已经有同名镜像,它就不会再拉新的。如果你前一天部署了旧版,今天新版发布,pod还是用旧版。
最好明确指定版本标签,比如0.24.0。而且如果你的私有仓库里没有这个标签,Pod就会进入ImagePullBackOff循环。这时候可以用kubectl describe pod来查原因:
# 查看Pod启动失败的详细原因
# 技术栈:Shell命令
kubectl describe pod/gateway-xxx -n openfaas
# 输出里会看到类似 "Failed to pull image ...": manifest for ... not found
如果你不确定某个版本的镜像是否存在,可以先在节点上手动docker pull测试下,或者直接去Docker Hub看Tags列表。
二、权限配置陷阱:ServiceAccount与RBAC
镜像拉取成功,Pod终于变成Running了吗?不,你可能还会遇到CrashLoopBackOff。这是因为OpenFaaS的组件(比如gateway、faas-netes)需要调用Kubernetes API来创建、删除函数。默认情况下,Pod使用的ServiceAccount(叫default)没有足够的权限,导致启动核心功能报错。
2.1 创建专用的ServiceAccount
OpenFaaS官方提供了安装脚本,里面会创建ServiceAccount和RBAC绑定。但很多人图省事直接复制别人的配置,结果漏掉了这部分。你需要手动创建时,确保包含以下内容:
# 示例:为OpenFaaS创建ServiceAccount和ClusterRole
# 技术栈:Kubernetes RBAC(YAML)
apiVersion: v1
kind: ServiceAccount
metadata:
name: openfaas-controller
namespace: openfaas
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: openfaas-controller
rules:
- apiGroups: [""] # 核心API组
resources: ["services", "pods", "configmaps", "secrets", "namespaces"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: openfaas-controller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: openfaas-controller
subjects:
- kind: ServiceAccount
name: openfaas-controller
namespace: openfaas
注意:上面的权限看起来给了很多,但实际还需要考虑functions的CRD(CustomResourceDefinition)权限。OpenFaaS在较新版本里使用了自己的自定义资源(比如Function、HttpTrigger等),如果你部署了OpenFaaS Pro或者用了CRD,还需要额外授权。否则Pod日志里会有类似“Failed to list *v1.Function: the server could not find the requested resource”的错误。
2.2 如何快速诊断权限问题
当Pod不断重启时,先看看日志:
# 查看gateway Pod的日志
# 技术栈:Shell命令
kubectl logs -n openfaas deployment/gateway --tail=50
如果日志里出现“forbidden”“unauthorized”等字眼,基本就是RBAC问题。这时候可以临时创建一个具有cluster-admin权限的ServiceAccount来测试(但不推荐生产使用),确认问题后再调小权限。
三、实战案例:一步步排查并修复
假设你有一个裸K8s集群(比如用minikube或者kubeadm搭建的),你想部署OpenFaaS,但发现所有Pod都处于CrashLoopBackOff。我们来完整走一遍排查流程。
3.1 首先检查Pod状态
# 查看所有Pod
# 技术栈:Shell命令
kubectl get pods -n openfaas
# 输出可能像:
# NAME READY STATUS RESTARTS AGE
# gateway-6f8b9c9d6d-abc12 0/1 CrashLoopBackOff 5 3m
# nats-7d8f9c9d6d-def34 0/1 ImagePullBackOff 0 3m
这里看到两个问题:gateway崩溃循环,nats镜像拉取失败。我们先修镜像拉取(因为简单)。
3.2 修复NATS镜像
nats镜像通常是从Docker Hub拉取的,但如果你网络不好或者被墙了,就会ImagePullBackOff。解决方案:改用国内的镜像源,比如阿里云镜像。
# 修改openfaas部署文件中nats的镜像地址
# 技术栈:Kubernetes Deployment(YAML片段)
# 原本可能是:image: nats:2.9.9-alpine
# 修改为:
image: registry.cn-hangzhou.aliyuncs.com/google_containers/nats:2.9.9-alpine
# 注意:你需要确认该镜像确实存在,也可以自己从Docker Hub拉取后推送到私有仓库
但如果你什么镜像源都没有,最稳妥的方式是先用docker pull拉下来,然后存到私有仓库,再改YAML里的image路径。
3.3 修复gateway的崩溃问题
gateway崩溃,我们看日志:
# 查看网关日志
# 技术栈:Shell命令
kubectl logs -n openfaas deployment/gateway --tail=100
# 假如看到:Failed to watch *v1.Secret: secrets is forbidden: User "system:serviceaccount:openfaas:default" cannot watch resource "secrets" in API group "" in the namespace "openfaas"
这说明默认的ServiceAccount(default)没有权限watch secrets。我们需要把ServiceAccount换成之前创建的openfaas-controller。修改gateway的Deployment,在template.spec下增加:
spec:
serviceAccountName: openfaas-controller # 指定我们创建的SA
containers:
...
然后重新部署gateway,Pod应该能正常启动了。
3.4 验证最终状态
全部修改后,重新apply YAML文件:
# 应用修改后的部署
# 技术栈:Shell命令
kubectl apply -f gateway-deployment.yaml -n openfaas
kubectl apply -f nats-deployment.yaml -n openfaas
# 等待一会
kubectl get pods -n openfaas -w
# 应该看到所有Pod都进入Running状态
四、注意事项与最佳实践
上面说了两个大坑,实际部署中还有很多小细节要注意,我总结几条实用的:
- 镜像拉取策略:如果你的镜像标签固定不变(比如v1.0.0),可以把imagePullPolicy设为IfNotPresent,避免每次都去拉取;如果你不确定或者使用latest,最好设为Always,确保每次部署都用最新版本。具体写法:在container下加
imagePullPolicy: Always。 - 资源限制:OpenFaaS的gateway需要一定的CPU和内存。默认不设资源限制也可能导致Pod被OOM Killer干掉。建议设置requests和limits,比如cpu: 100m,memory: 128Mi。
- DNS配置:如果OpenFaaS要调用其他服务(比如NATS、Prometheus),确保集群内的DNS正常工作。可以用
kubectl exec -n openfaas <pod> -- nslookup nats.openfaas.svc.cluster.local测试。 - 命名空间隔离:把所有OpenFaaS组件都放在同一个命名空间(比如openfaas)里,管理起来方便。别东一个西一个。
- 版本匹配:OpenFaaS的各个组件(gateway、faas-netes、nats等)版本需要相互兼容。最好参考官方release notes,不要把0.18的gateway和0.24的faas-netes混用。
- ingress vs NodePort:如果你想从集群外访问OpenFaaS的UI,建议用Ingress Controller(比如nginx-ingress),而不是直接暴露NodePort,避免安全风险。
五、文章总结
部署OpenFaaS上Kubernetes,Pod启动失败多数逃不出镜像拉取和权限配置这两个坑。镜像拉取的核心是正确配置私有仓库的凭证(imagePullSecrets),并养成指定明确标签的习惯;权限配置的核心是给OpenFaaS的ServiceAccount分配足够的RBAC权限,至少包括对核心资源(pods、services、deployments)的增删改查,以及CRD的权限。通过本文的实战案例,你应该能一步步定位并修复这些问题。
记住,遇到Pod启动失败,先查kubectl describe pod看事件,再查kubectl logs看具体错误,然后对症下药。希望这篇文章能帮你在OpenFaaS的部署路上少踩几个坑,早日用上Serverless函数。
Comments