问题
github action known host
GitHub Actions 连接服务器时报错 Host key verification failed
,是由于 Actions 环境首次连接服务器时缺失主机密钥验证所致。以下是综合多个文档的完整解决方案:
🔍 错误原因
- 主机密钥未信任:GitHub Actions 的虚拟机首次通过 SSH 连接服务器时,会检查服务器的主机密钥(host key)。若密钥未预先存储在
known_hosts
文件中,SSH 会因安全策略拒绝连接。 - 与本地环境的差异:本地 Mac 已通过手动连接(输入
yes
)将服务器密钥添加到~/.ssh/known_hosts
,但 Actions 环境是全新的,无此记录。
✅ 解决方案
方法一:提前将服务器密钥添加到 known_hosts
(推荐)
在 Actions 工作流中,使用 ssh-keyscan
主动获取服务器密钥并写入 known_hosts
文件:
steps:
- name: Add server host key to known_hosts
run: |
mkdir -p ~/.ssh
ssh-keyscan your_server_ip >> ~/.ssh/known_hosts # 替换 your_server_ip
chmod 600 ~/.ssh/known_hosts
📌 原理:
ssh-keyscan
获取服务器公钥并追加到known_hosts
,避免首次连接时的交互提示。
方法二:禁用严格主机密钥检查(临时方案)
在 SSH 命令中添加参数,跳过密钥验证(仅限测试环境):
steps:
- name: Connect via SSH
run: ssh -o "StrictHostKeyChecking=no" -i ${{ secrets.SSH_PRIVATE_KEY }} user@server_ip
⚠️ 注意:此方法降低安全性,可能遭受中间人攻击,生产环境慎用。
📝 完整 GitHub Actions 配置示例
name: Deploy to Server
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Add Server Host Key
run: |
mkdir -p ~/.ssh
ssh-keyscan your_server_ip >> ~/.ssh/known_hosts
chmod 600 ~/.ssh/known_hosts
- name: SSH Command
run: |
echo "${{ secrets.SSH_PRIVATE_KEY }}" > private_key
chmod 400 private_key
ssh -i private_key user@your_server_ip "echo Connected!"
🔧 关键配置说明
- 私钥处理:
- 将 GitHub Secrets 中的私钥写入临时文件,并设置权限
400
(必须)。
- 将 GitHub Secrets 中的私钥写入临时文件,并设置权限
- 主机密钥类型:
- 若服务器使用非默认密钥类型(如 ECDSA),需指定参数:
ssh-keyscan -t ecdsa your_server_ip >> ~/.ssh/known_hosts
。
- 若服务器使用非默认密钥类型(如 ECDSA),需指定参数:
- 配置文件优化(可选):
- 在 Actions 中创建
~/.ssh/config
文件,简化连接命令:echo "Host server HostName your_server_ip User your_username IdentityFile private_key StrictHostKeyChecking yes" >> ~/.ssh/config
- 在 Actions 中创建
⚠️ 注意事项
- 权限问题:确保私钥文件权限为
400
,否则 SSH 会拒绝使用。 - 密钥格式:若私钥是 PEM 格式(如以
-----BEGIN RSA PRIVATE KEY-----
开头),需保留换行符。写入文件时建议使用:echo "${{ secrets.SSH_PRIVATE_KEY }}" | sed 's/\\n/\n/g' > private_key
- 安全建议:
优先使用 方法一,既保持安全性,又避免手动确认。仅在不敏感环境使用方法二。
通过上述步骤,GitHub Actions 即可安全连接服务器。若仍失败,检查服务器 SSH 服务状态(systemctl status sshd
)及防火墙规则。
Redis 无法远程访问
设置 bind 0.0.0.0 和密码
kafka 配置远程仍连接本地
Kafka Broker 的 advertised.listeners 参数决定了客户端实际连接的地址。若该参数配置为本地地址或容器内部地址(如 localhost:9092 或容器内主机名),即使客户端配置了远程 IP,仍会被重定向到本地地址。
listeners=PLAINTEXT://0.0.0.0:9092 # 监听所有网络接口
advertised.listeners=PLAINTEXT://公网IP:9092 # 对外广播的地址
1 port is deprecated. Please use KAFKA_ADVERTISED_LISTENERS instead.
是因为 “Looks like the kubenetes will automatically set the env name APPNAME_PORT, i.e. KAFKA_PORT in this case, the workaround is to change your app name to something else other than kafka.” 通过 “command: [“bash”, “-c”, “unset KAFKA_PORT; /etc/confluent/docker/run”]“ 解决
2 宿主机无法访问minikube 集群
nginx, gateway, nacos 都设成 LoadBalancer
3 mysql 探针失活
修改探针
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
namespace: postopia
spec:
selector:
matchLabels:
app: mysql
strategy:
type: Recreate
template:
metadata:
labels:
app: mysql
spec:
securityContext:
fsGroup: 999 # mysql group ID
containers:
- name: nacos-mysql
image: postopia-nacos-mysql:latest
imagePullPolicy: Never
env:
- name: MYSQL_ROOT_PASSWORD
value: root
- name: MYSQL_USER
value: nacos_config
- name: MYSQL_PASSWORD
value: nacos_config
- name: MYSQL_DATABASE
value: nacos_config
- name: LANG
value: C.UTF-8
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
- name: mysql-run
mountPath: /var/run/mysqld
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
# Use tcpSocket probe instead, which is more reliable
livenessProbe:
tcpSocket:
port: 3306
initialDelaySeconds: 90
periodSeconds: 20
timeoutSeconds: 5
failureThreshold: 3
startupProbe:
tcpSocket:
port: 3306
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 15 # Allow up to ~2.5 minutes for startup
volumes:
- name: mysql-storage
persistentVolumeClaim:
claimName: mysql-pvc
- name: mysql-run
emptyDir: {}
4 服务器上 docker-compose 报错
docker-compose down -v
docker rm -f $(docker ps -aq)
docker volume prune -f
docker network prune -f
Minikube 镜像
要将 Docker Desktop 中的镜像加载到 Minikube 中,可以通过以下两种常用方法实现:
方法一:使用 minikube image load
命令
构建或拉取本地镜像
在 Docker Desktop 中构建或拉取目标镜像,例如:docker build -t my-image:latest .
将镜像加载到 Minikube
使用以下命令将本地镜像导入 Minikube 的 Docker 环境:minikube image load my-image:latest
- 验证是否加载成功:
minikube ssh docker images | grep my-image
说明:此方法需要先在本机构建镜像,再通过
load
命令导入,适用于已有镜像的场景。- 验证是否加载成功:
方法二:直接使用 Minikube 的 Docker 环境
切换 Docker 环境变量
运行以下命令,将当前终端的 Docker 客户端指向 Minikube 内部的 Docker 守护进程:eval $(minikube docker-env)
- 此时执行
docker images
会显示 Minikube 的镜像列表,而非本机 Docker Desktop 的镜像。
- 此时执行
在 Minikube 环境中构建镜像
直接在 Minikube 的 Docker 环境中构建镜像(避免镜像传输):docker build -t my-image:latest .
- 构建完成后,镜像会直接存储在 Minikube 环境中,无需额外加载。
恢复本机 Docker 环境
eval $(minikube docker-env -u)
注意事项
镜像拉取策略
在 Kubernetes 的 Deployment 配置中,需设置imagePullPolicy: Never
,否则 Kubernetes 会尝试从远程仓库拉取镜像而非使用本地镜像。资源限制
minikube image load
命令可能消耗较多内存,建议为 Minikube 分配足够资源(例如至少 2 核 4GB 内存)。临时开发场景推荐
若需频繁使用本地镜像,推荐直接通过eval $(minikube docker-env)
在 Minikube 环境中构建镜像,省去加载步骤。
验证镜像是否生效
部署应用后,可通过以下命令检查 Pod 状态和日志:
kubectl apply -f deployment.yaml
kubectl logs deployment/my-app
kubectl port-forward deployment/my-app 8080:8080 # 端口转发访问服务
引用说明:以上方法综合了镜像加载和直接构建两种场景,适用于本地开发调试。若需长期使用,建议搭建私有镜像仓库或配置镜像加速源。
kubectl apply -f
kubectl apply -f
是 Kubernetes 中用于声明式配置管理的核心命令,通过读取 YAML/JSON 文件将资源应用到集群中,并确保集群状态与文件定义一致。以下是其关键信息:
核心功能
声明式管理
- 通过配置文件描述资源的期望状态,Kubernetes 自动计算并执行所需操作(创建/更新)。
- 与命令式命令(如
kubectl create
)不同,apply
不会覆盖现有配置,而是通过三向合并策略(Three-Way Merge)对比当前状态、上次应用状态和文件状态,仅应用必要变更。
幂等性
- 多次执行同一命令结果一致,适合自动化部署和 CI/CD 流程。
版本控制友好
- 配置文件可存储在 Git 等版本控制系统中,便于跟踪变更历史和团队协作。
基本用法
# 应用单个文件
kubectl apply -f deployment.yaml
# 应用目录下所有配置文件
kubectl apply -f ./configs/
# 从标准输入读取配置(如管道传递)
cat pod.json | kubectl apply -f -
# 使用 Kustomize 目录
kubectl apply -k kustomize-dir/
典型应用场景
部署应用
- 通过定义 Deployment、Service、Ingress 等资源文件,一键部署完整应用组件。
- 示例:部署 Nginx:执行:
apiVersion: apps/v1 kind: Deployment metadata: name: nginx spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.21
kubectl apply -f nginx.yaml
。
更新资源
- 修改配置文件后重新执行
apply
,Kubernetes 自动更新资源(如调整副本数、镜像版本)。
- 修改配置文件后重新执行
批量管理资源
- 使用标签(Labels)分组管理资源,例如统一更新所有标记为
app=backend
的 Deployment。
- 使用标签(Labels)分组管理资源,例如统一更新所有标记为
进阶参数与技巧
删除未使用的资源
- 结合
--prune
参数可自动删除配置文件中未提及但已存在的资源(需指定标签或资源类型):注意:此功能目前处于 Alpha 阶段,需谨慎使用。kubectl apply -f manifest.yaml --prune -l app=nginx
- 结合
模拟执行(Dry Run)
- 预览变更而不实际生效:
kubectl apply -f deployment.yaml --dry-run=server
- 预览变更而不实际生效:
强制覆盖冲突
- 当字段冲突时,使用
--force-conflicts
强制应用变更(需结合--server-side
)。
- 当字段冲突时,使用
常见问题与解决
资源未按预期更新
- 原因:本地配置与集群实际状态不一致。
- 解决:使用
kubectl get <resource> -o yaml
导出当前配置,对比并调整文件后重新应用。
资源未被自动删除
- 原因:
apply
默认不会删除资源,需显式使用kubectl delete -f
或结合--prune
。
- 原因:
权限或配置错误
- 排查步骤:
- 检查 YAML 语法(如缩进、字段名)。
- 确认用户权限(RBAC)。
- 查看事件日志:
kubectl describe <resource>
。
- 排查步骤:
最佳实践
始终使用版本控制
- 将配置文件纳入 Git,结合 CI/CD 实现自动化部署。
避免手动修改实时配置
- 直接在集群中修改(如
kubectl edit
)可能导致与配置文件冲突,建议通过更新文件后重新应用。
- 直接在集群中修改(如
标签化资源
- 使用
metadata.labels
对相关资源分组,便于批量操作。
- 使用
通过以上方式,kubectl apply -f
成为 Kubernetes 声明式管理的核心工具,尤其适用于复杂环境下的资源管理。如需进一步了解参数细节,可参考官方文档或 kubectl apply --help
。
服务类型
Kubernetes Service 是集群内网络通信的核心抽象,通过提供稳定的访问入口和负载均衡机制,解决了 Pod 动态变化导致的 IP 不固定问题。以下是其四种主要类型的详细介绍:
ClusterIP(默认类型)
特点
- 内部访问:为 Service 分配一个虚拟 IP(ClusterIP),仅限集群内部 Pod 或组件访问。
- 负载均衡:自动将请求分发到关联的多个 Pod,支持轮询等基本算法。
- 动态适配:通过标签选择器(Label Selector)自动更新后端 Pod,无需人工干预。
适用场景
- 微服务间通信(如前端服务调用后端 API)。
- 数据库、缓存等仅需集群内部访问的服务。
示例配置
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: ClusterIP
selector:
app: my-app
ports:
- port: 80 # Service 暴露端口
targetPort: 8080 # Pod 应用端口
NodePort
特点
- 外部访问入口:在每个集群节点上开放一个静态端口(默认 30000-32767),外部可通过
NodeIP:NodePort
访问服务。 - 基于 ClusterIP:NodePort 本质是 ClusterIP 的扩展,同时保留 ClusterIP 功能。
适用场景
- 开发测试环境临时暴露服务。
- 小规模集群或无需云负载均衡的场景。
示例配置
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
ports:
- port: 80
targetPort: 8080
nodePort: 30080 # 可手动指定或由系统分配
selector:
app: my-app
LoadBalancer
特点
- 云平台集成:自动创建云厂商的负载均衡器(如 AWS ALB、GCP LB),分配外部 IP。
- 高可用性:流量通过负载均衡器分发到多个节点,避免单点故障。
适用场景
- 生产环境对外暴露服务(如 Web API、前端应用)。
- 需要自动扩缩容和流量管理的云原生应用。
示例配置
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 8080
selector:
app: my-app
ExternalName
特点
- 外部服务映射:将 Service 映射到外部 DNS 名称(如
example.com
),不创建代理或负载均衡。 - DNS 解析:通过 CNAME 记录将内部请求转发到外部服务。
适用场景
- 访问集群外部的数据库(如 MySQL、Redis)。
- 集成第三方 API 或遗留系统。
示例配置
apiVersion: v1
kind: Service
metadata:
name: external-mysql
spec:
type: ExternalName
externalName: mysql.example.com
类型对比与选型建议
类型 | 访问方式 | 适用场景 | 典型用例 |
---|---|---|---|
ClusterIP | http://<service-name>:port | 集群内部通信 | 微服务间调用、内部数据库 |
NodePort | http://<NodeIP>:30000+ | 开发测试、临时外部访问 | 本地调试、小型应用展示 |
LoadBalancer | http://<External-IP>:port | 生产环境外部访问(云平台) | 公有云部署的 Web 服务 |
ExternalName | service-name → 外部域名 | 集成外部服务 | 外部 API、跨集群数据库访问 |
选型建议:
- 优先使用 ClusterIP 满足内部通信需求。
- 生产环境需高可用时选择 LoadBalancer(云环境)或结合 Ingress 使用。
- 避免在生产环境过度依赖 NodePort,因其端口范围受限且缺乏负载均衡。
底层实现机制
Service 的负载均衡依赖于 kube-proxy
,支持三种模式:
- iptables:通过规则直接转发流量,性能较高但缺乏重试机制。
- IPVS:内核级负载均衡,支持复杂算法(如加权轮询),适合大规模集群。
- Userspace(已淘汰):早期模式,因性能问题逐渐被替代。
以上内容综合了 Kubernetes 官方文档及社区最佳实践,具体配置需结合集群环境和云平台特性调整。
minikube tunnel
在 Minikube 环境中,当服务类型设置为 LoadBalancer
时,直接通过 localhost
无法访问是常见问题,原因和解决方案如下:
原因分析
Minikube 的网络隔离
Minikube 创建的是一个独立虚拟机或容器化的 Kubernetes 集群,其网络与宿主机(如 Mac、Windows 本地)隔离。LoadBalancer
类型服务在云环境中会自动分配外部 IP,但在本地 Minikube 中需要特殊处理。LoadBalancer 的本地限制
Minikube 默认不支持自动分配外部 IP 给LoadBalancer
类型服务,因此服务可能处于pending
状态,无法通过localhost
访问。
解决方案
使用 minikube tunnel
命令
该命令会为 LoadBalancer
类型服务分配本地 IP(通常是 127.0.0.1
),使服务可通过 localhost
访问。
操作步骤:
# 启动隧道(需要管理员权限)
minikube tunnel
之后,服务的 EXTERNAL-IP
会显示为 127.0.0.1
,可通过 localhost:<端口>
访问。
通过 minikube service
命令访问
Minikube 提供了快捷命令生成服务的访问 URL:
操作步骤:
# 获取服务访问地址
minikube service <服务名称> --url
该命令会返回形如 http://192.168.64.2:30001
的 URL,直接使用此地址即可访问。
手动使用 Minikube 的 IP 和 NodePort
如果服务同时暴露了 NodePort
,可以通过以下步骤访问:
操作步骤:
# 获取 Minikube 集群 IP
minikube ip
# 查看服务的 NodePort
kubectl get svc <服务名称>
访问地址为 <Minikube-IP>:<NodePort>
(例如 192.168.64.2:31035
)。
检查服务配置
- 选择器匹配:确保 Service 的
selector
与 Pod 的标签匹配,否则流量无法路由到后端 Pod。 - 端口映射:确认
targetPort
与 Pod 的容器端口一致,nodePort
在 30000-32767 范围内。 - 服务状态:运行
kubectl describe svc <服务名称>
,检查Endpoints
是否有正确的 Pod IP。
附加说明
LoadBalancer
的适用场景:在本地开发中,推荐优先使用NodePort
或结合minikube tunnel
,以减少复杂性。- 云环境差异:如果在云厂商(如阿里云)部署,
LoadBalancer
会自动绑定 SLB/IP,但需注意externalTrafficPolicy
配置。
通过上述方法,可解决 Minikube 中 LoadBalancer
服务无法通过 localhost
访问的问题。推荐优先使用 minikube tunnel
或 minikube service
命令简化操作。
PV & PVC
PersistentVolume(PV)和PersistentVolumeClaim(PVC)是Kubernetes中用于管理存储资源的核心概念,两者共同实现了存储与计算的解耦,确保数据持久化。以下是具体解析:
1. PersistentVolume(PV)
定义:
PV是集群中由管理员预先配置或通过动态供应(StorageClass)创建的一块持久化存储资源。它独立于Pod的生命周期,支持多种存储类型(如NFS、云存储、本地存储等)。
核心特性:
- 存储类型:支持本地存储、网络存储(NFS、iSCSI)、云存储(如AWS EBS、Azure Disk)等。
- 访问模式:
ReadWriteOnce
(RWO):单节点读写;ReadOnlyMany
(ROX):多节点只读;ReadWriteMany
(RWX):多节点读写。
- 生命周期管理:
- 回收策略:包括
Retain
(保留数据)、Delete
(自动删除存储)、Recycle
(废弃,已不推荐)。 - 状态:
Available
(空闲)、Bound
(已绑定)、Released
(已释放)、Failed
(失败)。
- 回收策略:包括
示例用途:
数据库数据持久化、共享文件系统、日志存储等场景。
2. PersistentVolumeClaim(PVC)
定义:
PVC是用户对存储资源的声明,用于向Kubernetes请求特定大小和访问模式的存储。它类似于Pod申请计算资源(CPU/内存),通过绑定PV实现存储的消费。
核心特性:
- 与PV的绑定:PVC通过匹配存储容量、访问模式和StorageClass与PV绑定。
- 动态供应:若未匹配到静态PV,可通过
StorageClass
动态创建PV。 - 命名空间限制:PVC属于特定命名空间,而PV是集群级资源。
示例YAML:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard # 指定动态供应的存储类
3. PV与PVC的关系
- 静态供应:管理员预先创建PV,用户通过PVC申请匹配的存储。
- 动态供应:通过
StorageClass
模板自动创建PV,无需管理员手动配置。 - 绑定逻辑:
- PVC提交后,Kubernetes控制器会寻找满足条件的PV进行绑定;
- 若使用动态供应,则直接按PVC需求创建PV。
4. 使用场景对比
场景 | PV | PVC |
---|---|---|
创建者 | 集群管理员 | 用户(开发者) |
生命周期 | 独立于Pod | 与Pod解耦,但绑定后与PV同步 |
核心作用 | 提供实际存储资源 | 声明存储需求并绑定PV |
存储类型配置 | 明确指定(如NFS路径、云存储参数) | 通过StorageClass抽象 |
5. 常见问题
- Q1:PVC未绑定PV怎么办?
需检查PVC的容量、访问模式是否与可用PV匹配,或确认StorageClass配置正确。 - Q2:如何复用已释放的PV?
若回收策略为Retain
,需手动删除并重新创建PV。
通过PV和PVC的协作,Kubernetes实现了存储资源的灵活管理,既能满足复杂业务需求,又能简化用户操作。
StatefulSet & Deployment
StatefulSet 和 Deployment 是 Kubernetes 中两类核心控制器,分别针对有状态和无状态应用设计。以下是两者的主要区别,结合应用场景、行为特性及底层机制进行对比:
1. 适用场景
Deployment
适用于无状态应用(如 Web 服务器、API 服务),Pod 之间可随意替换且无需保留状态。
特点:- Pod 实例完全对等,无启动顺序依赖;
- 数据通常存储在临时卷或共享存储中。
StatefulSet
适用于有状态应用(如数据库、分布式存储),需稳定标识、持久化存储及严格顺序控制。
特点:- 每个 Pod 有唯一名称(如
db-0
、db-1
)和固定 DNS 记录(如db-0.myservice.ns.svc.cluster.local
); - 数据通过独立的 PersistentVolume 持久化,与 Pod 生命周期解耦。
- 每个 Pod 有唯一名称(如
2. Pod 标识与网络
Deployment
- Pod 名称随机(如
web-app-59d8c5f6c4-abcde
); - IP 动态分配,重启或迁移后可能变化;
- 通过 Service 负载均衡暴露,流量随机分发至任意 Pod。
- Pod 名称随机(如
StatefulSet
- Pod 名称固定且有序(如
db-0
、db-1
); - 网络标识稳定,通过 Headless Service 提供 DNS 记录,支持 Pod 间直接通信;
- 适用于需固定网络拓扑的场景(如主从数据库)。
- Pod 名称固定且有序(如
3. 存储管理
Deployment
- 默认使用临时存储(如
emptyDir
); - 若需持久化存储,需手动配置 PV/PVC,但所有 Pod 可能共享同一卷。
- 默认使用临时存储(如
StatefulSet
- 每个 Pod 绑定独立存储:通过
volumeClaimTemplates
动态创建 PVC,存储与 Pod 解耦但一一对应; - 数据在 Pod 删除后保留,适用于数据库实例的独立数据存储。
- 每个 Pod 绑定独立存储:通过
4. 生命周期管理
启动/终止顺序
- Deployment:Pod 无序创建或删除,可并行操作;
- StatefulSet:Pod 按顺序启动(如
db-0
→db-1
)和终止(逆序),确保状态一致性。
滚动更新策略
- Deployment:支持无序滚动更新,通过
maxUnavailable
和maxSurge
控制更新节奏; - StatefulSet:按序号逆序更新(如
db-2
→db-1
→db-0
),确保逐个 Pod 就绪。
- Deployment:支持无序滚动更新,通过
5. 扩缩容与删除行为
扩缩容
- Deployment:Pod 随机创建或删除,无顺序限制;
- StatefulSet:扩容时按序创建新 Pod,缩容时按逆序删除旧 Pod。
删除控制器时
- Deployment:删除后关联 Pod 和 ReplicaSet 均被清理;
- StatefulSet:默认保留 Pod 和 PVC,需手动删除以确保数据安全。
总结对比表
特性 | Deployment | StatefulSet |
---|---|---|
适用场景 | 无状态应用(Web、API) | 有状态应用(数据库、消息队列) |
Pod 标识 | 随机名称,动态 IP | 固定名称(如 db-0 ),稳定 DNS |
存储 | 临时卷或共享存储 | 每个 Pod 独立持久化存储 |
启动顺序 | 无序 | 严格按顺序创建/删除(db-0 → db-1 ) |
更新策略 | 无序滚动更新 | 逆序逐个更新 |
适用案例 | Nginx、无状态微服务 | MySQL、Kafka、Zookeeper |
选择建议
- 优先选 Deployment:若应用无状态、可水平扩展且无需固定网络标识(如 REST API);
- 优先选 StatefulSet:若需稳定网络标识、独立存储或有序生命周期(如数据库集群、分布式锁服务)。
通过合理选择控制器,可有效平衡应用的弹性与状态一致性需求。
Docker Compose Rebuild
在 Docker Compose 中,docker compose build
命令的 Rebuild 策略可以通过以下选项灵活指定,适用于不同场景下的镜像构建需求:
强制不使用缓存构建
通过 --no-cache
参数,跳过 Docker 构建缓存,从头开始重新构建镜像。
适用场景:当 Dockerfile 中的指令顺序或内容发生变化,但缓存可能导致旧版本残留时。
示例:
docker compose build --no-cache [SERVICE_NAME]
引用说明:此选项在网页中均有提及,明确用于禁用缓存。
强制拉取最新基础镜像
使用 --pull
参数,强制从镜像仓库拉取最新版本的基础镜像(如 FROM
指定的镜像)。
适用场景:确保基础镜像(如 python:3.6-alpine
)更新到最新版本,避免本地旧版本影响构建。
示例:
docker compose build --pull [SERVICE_NAME]
引用说明:网页均强调此选项用于更新基础镜像。
并行构建多个服务
通过 --parallel
参数(Docker Compose 3.4+ 支持),启用多服务并行构建以加速整体流程。
适用场景:当项目包含多个独立服务且构建过程无依赖时,可显著减少构建时间。
示例:
docker compose build --parallel
引用说明:网页详细说明了并行构建的适用性和使用方法。
选择性重建指定服务
在命令中指定服务名称,仅重新构建特定服务,而非所有服务。
适用场景:仅某个服务的 Dockerfile 或依赖发生变更时,针对性重建以节省资源。
示例:
docker compose build web # 仅重建名为 "web" 的服务
引用说明:网页均提到通过服务名称选择性构建。
删除临时容器和镜像
通过 --force-rm
参数,删除构建过程中产生的临时容器,避免残留文件占用空间。
示例:
docker compose build --force-rm [SERVICE_NAME]
引用说明:网页指出此选项用于清理临时容器。
组合策略示例
可组合多个参数实现复杂策略,例如:
docker compose build --no-cache --pull web # 强制重建 "web" 服务,禁用缓存并拉取最新基础镜像
总结
通过上述参数,可以灵活控制 Docker Compose 的构建行为,适配开发、测试和生产环境的不同需求。具体选择需结合以下因素:
- 缓存依赖:是否需要完全干净的构建环境(如 CI/CD 流水线)。
- 镜像更新:是否依赖最新基础镜像的安全性更新。
- 效率优化:是否启用并行构建以减少时间成本。
提示:可通过
docker compose config
验证配置文件格式,或结合docker compose up --build
直接启动重建后的服务。
Docker compose
以下是使用 Docker Compose 运行 .yaml
文件的完整指南,综合了最佳实践和关键注意事项:
基础运行流程
验证配置文件
执行docker-compose config
检查 YAML 文件语法,避免因缩进错误或格式问题导致启动失败。启动服务
在包含docker-compose.yaml
的目录下执行:docker-compose up # 前台运行(查看实时日志) docker-compose up -d # 后台运行
服务管理
docker-compose ps
查看运行状态docker-compose logs [服务名]
查看指定服务日志docker-compose down
停止并删除所有容器、网络和卷
YAML 文件核心配置
version: '3.8' # 指定兼容版本
services:
web:
image: nginx:alpine
ports:
- "80:80" # 端口映射(主机:容器)
volumes:
- ./html:/usr/share/nginx/html # 目录挂载
depends_on:
- db # 基础依赖声明
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: example
healthcheck: # 健康检查配置
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
高级运行技巧
环境变量注入
使用.env
文件管理敏感信息,YAML 中通过${VAR_NAME}
引用:environment: DB_PASSWORD: ${DB_SECRET}
多环境配置
通过叠加多个 Compose 文件实现环境差异:docker-compose -f docker-compose.yml -f docker-compose.prod.yml up
资源限制
配置容器资源使用上限防止过载:deploy: resources: limits: cpus: '2' memory: 1G
跨平台注意事项
Windows 特殊配置
- 确保 Docker Desktop 已安装并启用 WSL2
- 路径使用正斜杠
/
代替反斜杠\
- 避免使用保留端口(如 80/443)可能被系统占用
Linux 权限处理
容器内用户权限需与挂载目录匹配:volumes: - ./data:/var/lib/postgresql/data:z # SELinux 上下文标记
故障排查指南
启动顺序问题
使用增强型依赖声明,确保服务真正可用:depends_on: db: condition: service_healthy
常见错误处理
- 端口冲突:通过
netstat -ano
检查占用端口 - 卷挂载失败:验证主机目录存在且具有读写权限
- 镜像拉取超时:配置国内镜像加速源
- 端口冲突:通过
提示:建议使用
docker-compose --help
查看完整命令列表。对于复杂编排场景,可结合 Docker Swarm 实现集群管理。
以下是使用 Docker Compose 指定自定义 YAML 文件的完整指南,整合了多篇技术文档的核心要点:
基础指定方法
单文件指定
通过-f
参数直接指定 YAML 文件路径:docker-compose -f docker-compose.prod.yml up -d
支持绝对路径和相对路径(如
./config/custom.yml
)多文件合并
叠加多个 YAML 文件实现配置扩展,优先级按书写顺序递增:docker-compose -f base.yml -f override.yml up
常用于区分基础配置与环境差异(如开发/生产环境)
典型应用场景
场景 | 示例命令 |
---|---|
多环境部署 | docker-compose -f docker-compose.yml -f docker-compose.prod.yml up |
测试配置文件 | docker-compose -f test-stack.yaml down --volumes |
自定义路径部署 | docker-compose -f /opt/myapp/config.yml up |
临时调试配置 | docker-compose -f debug-config.yaml logs --follow |
路径处理规则
文件搜索优先级
Docker Compose 默认按以下顺序查找文件:- 当前目录的
docker-compose.yml
docker-compose.override.yml
(自动合并)- 若未找到,必须显式通过
-f
指定
- 当前目录的
跨平台路径格式
- Windows:建议使用正斜杠
/
(如C:/projects/app.yml
) - Linux/macOS:支持相对路径
../parent-dir/config.yaml
- Windows:建议使用正斜杠
验证与调试
配置预检
执行语法验证命令,避免配置错误:docker-compose -f custom.yml config
该命令会输出合并后的最终配置并检查语法有效性
环境变量注入
在自定义 YAML 中结合.env
文件实现动态配置:services: db: image: postgres:${POSTGRES_VERSION}
需确保
.env
文件与 YAML 文件在同一目录或通过--env-file
指定
高级技巧
组合命令优化
将常用命令封装为别名提高效率:alias dc='docker-compose -f ~/projects/core-stack.yml' dc up -d # 等效于完整命令
版本兼容性控制
在 YAML 文件顶部声明语法版本避免兼容问题:version: '3.8' # 支持资源限制、扩展配置等新特性
操作建议:对于长期运行的服务,推荐将自定义 YAML 文件纳入版本控制,并通过 CI/CD 流水线实现自动化部署。若需查看完整命令列表,可执行
docker-compose --help
获取实时帮助。
k8s 本地镜像
在Kubernetes(K8s)中,若想直接使用主节点本地构建的Docker镜像执行kubectl apply
,需要确保镜像能被集群节点访问,并配置正确的拉取策略。以下是具体实现方法及步骤:
1. 配置镜像拉取策略
在K8s的Deployment或Pod配置文件中,必须设置imagePullPolicy: Never
,这会强制Kubernetes直接使用本地镜像而不尝试从远程仓库拉取。示例配置如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
spec:
containers:
- name: myapp
image: my-local-image:latest
imagePullPolicy: Never # 关键配置
2. 确保镜像存在于集群节点
Kubernetes的每个节点(包括主节点和工作节点)都需要有该镜像。根据集群类型选择以下方法:
方法一:单节点集群(主节点即工作节点)
- 直接在主节点构建镜像:通过
docker build -t my-local-image:latest .
构建镜像,主节点会直接使用该镜像。
方法二:多节点集群
通过
docker save
和docker load
分发镜像:- 在主节点将镜像保存为tar文件:
docker save -o my-local-image.tar my-local-image:latest
- 将tar文件传输到所有节点(如使用
scp
):scp my-local-image.tar user@node-ip:/path/
- 在每个节点加载镜像:
docker load -i my-local-image.tar
此方法适用于基于Docker的Kubernetes节点。
- 在主节点将镜像保存为tar文件:
使用私有镜像仓库(如主节点运行Registry):
- 在主节点启动本地Registry:
docker run -d -p 5000:5000 --name registry registry:2
- 标记并推送镜像到Registry:
docker tag my-local-image:latest localhost:5000/my-local-image:latest docker push localhost:5000/my-local-image:latest
- 在Deployment配置中使用
image: localhost:5000/my-local-image:latest
。
- 在主节点启动本地Registry:
方法三:特定工具链支持
Kind集群:使用
kind load docker-image
命令将本地镜像直接加载到Kind集群:kind load docker-image my-local-image:latest --name <cluster-name>
适用于开发环境快速加载镜像。
Minikube集群:通过
minikube cache add
将镜像添加到缓存:minikube cache add my-local-image:latest
仅适用于Minikube本地开发环境。
3. 应用配置并验证
- 执行
kubectl apply -f deployment.yaml
部署应用。 - 检查Pod状态:
kubectl get pods
- 若Pod启动失败,查看日志定位问题:常见问题包括镜像未加载到节点或标签错误。
kubectl logs <pod-name>
适用场景对比
场景 | 推荐方法 | 特点 |
---|---|---|
单节点本地开发 | 直接构建+imagePullPolicy | 无需额外操作,快速验证 |
多节点生产环境 | 私有镜像仓库 | 集中管理,适合团队协作 |
Kind/Minikube开发环境 | 工具链命令(如kind load ) | 自动化加载,避免手动分发 |
通过上述方法,可以灵活实现在K8s中直接使用主节点本地构建的镜像。若需进一步优化,可结合CI/CD流水线自动同步镜像到集群节点。
K8s Master & Worker
Kubernetes(K8s)的Master节点和Worker节点在集群中承担完全不同的角色,两者的核心区别体现在功能定位、核心组件和职责分工上:
功能定位
Master节点
- 集群的“大脑”:负责全局管理、调度和协调,是集群的控制平面(Control Plane)。所有控制命令(如资源创建、扩缩容)均通过Master节点执行。
- 高可用性要求:生产环境中通常部署多个Master节点(如3个),避免单点故障导致集群瘫痪。
Worker节点
- 资源的“执行者”:提供计算资源(如CPU、内存)并运行实际的工作负载(Pod),是集群的数据平面(Data Plane)。
- 动态扩展性:可根据负载动态增减Worker节点,支持横向扩展。
核心组件
组件 | Master节点 | Worker节点 |
---|---|---|
核心功能组件 | - kube-apiserver:集群API入口,唯一与etcd交互的组件 - kube-scheduler:调度Pod到合适节点 - kube-controller-manager:维护集群状态(如自愈、副本数) - etcd:分布式键值存储,保存集群状态 | - kubelet:管理Pod生命周期,与Master通信 - kube-proxy:维护服务网络规则和负载均衡 - 容器运行时(如Docker/containerd):运行容器 |
数据存储 | 存储集群全局状态(如Pod、Service配置)于etcd | 无持久化存储,仅运行临时Pod |
网络管理 | 不直接参与Pod网络,由kube-proxy和CNI插件实现 | 通过kube-proxy实现Service网络规则 |
职责分工
Master节点的核心职责
- 集群状态管理:通过etcd存储所有资源对象的配置和状态。
- 资源调度:由Scheduler根据资源需求选择最佳Worker节点运行Pod。
- 控制循环:Controller Manager确保集群实际状态与期望一致(如自动重启失败的Pod)。
- API服务:提供RESTful接口供用户和组件交互(如kubectl命令)。
Worker节点的核心职责
- 运行容器:通过容器运行时启动Pod中的容器,并监控其状态。
- 状态上报:kubelet定期向Master汇报节点资源使用情况(如CPU、内存)。
- 网络代理:kube-proxy维护Service的IP和端口映射,确保服务发现和负载均衡。
类比总结
- Master节点:类似企业的“管理层”,负责制定策略、分配任务并监控全局运行。
- Worker节点:类似“一线员工”,具体执行任务并反馈执行情况。
若需更深入的组件交互流程(如Pod创建过程)或高可用部署方案,可参考相关文档。
Master 节点要求
Kubernetes 的 Master 节点确实主要负责集群的调度和管理,默认不运行用户 Pod,但这并不意味着其内存和 GPU 的需求可以大幅降低。以下从硬件要求、核心功能特性、资源占用场景三个维度详细分析:
内存需求的底层逻辑
虽然 Master 节点不运行用户 Pod,但其核心组件(如 kube-apiserver
、etcd
、kube-scheduler
等)在 高并发请求或大规模集群 下会产生显著内存消耗:
etcd 的内存依赖
- etcd 存储集群所有状态数据(Pod、Service 等),频繁的读写操作(如大规模 Pod 滚动更新)会占用大量内存。
- 根据实践案例,生产级集群的 etcd 内存建议不低于 8GB,超大规模集群(如千节点级别)需提升至 16GB 以上。
API Server 的并发压力
kube-apiserver
是集群的流量入口,需处理来自kubectl
、Controller、Worker 节点的心跳等请求。当集群规模扩大时,其内存占用会线性增长。例如,500 节点的集群中 API Server 内存可能达到 4-6GB。
默认配置与安全缓冲
- 官方推荐 Master 节点内存最低为 8GB,但生产环境建议 16GB 以上,为突发流量(如批量创建 Pod)和组件升级预留缓冲空间。
GPU 需求的明确结论
Master 节点 完全不需要 GPU,因其职责不涉及任何 GPU 计算场景:
调度与 GPU 无关性
- 调度器(
kube-scheduler
)仅根据 Pod 的资源声明(如nvidia.com/gpu: 1
)选择节点,不参与 GPU 驱动的调用或计算过程。
- 调度器(
GPU 资源专属于 Worker 节点
- GPU 节点的硬件配置(如显存、驱动)仅在 Worker 节点部署,Master 节点无需安装 NVIDIA 驱动或 GPU 插件。
性能优化的平衡策略
针对不同场景,可调整 Master 节点的资源配置:
场景 | CPU 建议 | 内存建议 | 备注 |
---|---|---|---|
开发/测试集群 | 4 核 | 8GB | 低负载场景,支持基本调度功能 |
生产级集群(<100节点) | 8 核 | 16-32GB | 需应对高并发 API 请求和 etcd 压力 |
超大规模/AI 集群 | 16 核以上 | 64GB 以上 | 结合 RDMA 网络优化,避免成为性能瓶颈 |
关键配置建议
- 禁用 Swap
所有 Master 节点必须关闭 Swap,避免内存交换导致调度延迟。 - 专用存储优化
为 etcd 配置 SSD 或 NVMe 硬盘,提升键值存储性能(IOPS >5000)。 - 高可用部署
生产环境至少部署 3 个 Master 节点,并通过负载均衡分散 API Server 流量。
总结
- GPU 需求:Master 节点无需 GPU,仅 Worker 节点需要配置。
- 内存需求:不可过度压缩,需根据集群规模预留充足资源(8GB 起步,生产环境 16GB 以上)。
- 性能瓶颈规避:通过 SSD、多节点部署和内核参数优化(如
net.ipv4.ip_forward=1
)提升稳定性。
Minikube 预生产验证
Minikube 不推荐用于预生产验证,其设计定位和功能特性主要面向本地开发、学习和小规模测试场景。以下是具体分析:
Minikube的核心定位与功能限制
- 单节点架构:Minikube默认部署单节点Kubernetes集群,无法模拟生产环境中常见的多节点高可用架构(如Master节点冗余、负载均衡等)。虽然通过
--nodes
参数可扩展为多节点模式,但其底层仍依赖虚拟化或容器环境,资源调度和网络性能与真实集群存在差异。 - 资源限制:Minikube运行在本地机器的虚拟化环境中,受限于本地硬件资源(如CPU、内存),无法承载生产级负载压力测试或大规模并发场景。
- 组件简化:Minikube默认使用轻量级网络插件(如flannel)和存储方案,而生产环境通常需要更复杂的CNI(如Calico、Cilium)和持久化存储配置(如云存储卷)。
预生产验证的核心需求
预生产环境需尽可能贴近生产环境,验证内容包括:
- 高可用性:多节点集群的故障转移能力、API Server冗余等。
- 网络与存储性能:真实网络延迟、带宽及存储I/O的模拟。
- 安全性:生产级RBAC策略、网络策略等安全配置。
- 扩展性:自动扩缩容(HPA)、负载均衡等功能的稳定性。
Minikube在这些方面的支持有限,例如其内置的kube-proxy
仅提供基础的负载均衡功能,而生产环境可能需要更复杂的Ingress控制器或服务网格。
替代方案建议
若需进行预生产验证,建议选择以下工具:
- K3s:轻量级但支持多节点部署,适合边缘计算和资源受限环境。
- Kind(Kubernetes in Docker):基于容器的多节点集群,适合CI/CD流水线测试。
- 云托管Kubernetes服务(如腾讯云TKE):直接使用与生产环境一致的云原生架构,支持高可用集群和自动化运维。
结论
Minikube适用于本地开发调试和Kubernetes基础学习,但无法满足预生产验证对复杂性和真实性的要求。若需预生产验证,应选择支持多节点、高可用性及生产级组件的工具或云服务。
Github Action
在服务器上利用 GitHub Actions 执行自定义操作的核心流程是通过工作流(Workflow)触发远程命令,实现自动化部署、测试或运维任务。以下是关键步骤和配置方法:
🔑 配置服务器认证(SSH 密钥)
生成 SSH 密钥对
在本地或服务器执行:ssh-keygen -t rsa -b 4096 -C "github-actions" # 生成专用密钥对
公钥(
id_rsa.pub
)需添加到服务器的~/.ssh/authorized_keys
文件中。在 GitHub 仓库添加密钥
- 私钥(
id_rsa
)存入 GitHub 仓库的 Settings → Secrets,命名为SERVER_SSH_KEY
。 - 服务器 IP、用户名等敏感信息也存入 Secrets(如
SERVER_HOST
、SERVER_USER
)。
- 私钥(
⚙️ 编写 GitHub Actions 工作流
在仓库创建 .github/workflows/custom-action.yml
文件,示例结构:
name: Server Custom Task
on:
push:
branches: [main] # 触发条件:推送至 main 分支
workflow_dispatch: # 支持手动触发
jobs:
execute-commands:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4 # 检出代码
- name: Add SSH Key
run: |
echo "${{ secrets.SERVER_SSH_KEY }}" > deploy_key.pem
chmod 600 deploy_key.pem # 设置密钥权限
- name: Run Remote Commands
uses: appleboy/ssh-action@master # SSH 执行命令
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: deploy_key.pem
script: | # 自定义操作示例
cd /path/to/project
git pull origin main
npm install
systemctl restart my-service
💻 自定义操作场景示例
部署应用
- 拉取代码后执行构建命令(如
mvn package
/npm run build
)。 - 通过
scp
或rsync
同步文件到服务器。
- 拉取代码后执行构建命令(如
重启服务
通过 SSH 执行服务管理命令(如docker-compose up -d
或systemctl restart
)。定时任务
使用schedule
触发器定期执行备份或清理:on: schedule: - cron: '0 2 * * *' # 每天 UTC 时间 2:00
API 触发
通过repository_dispatch
事件接收外部请求触发工作流:curl -X POST https://api.github.com/repos/:owner/:repo/dispatches \ -H "Authorization: token $GITHUB_TOKEN" \ -d '{"event_type": "trigger-backup"}'
⚠️ 注意事项
安全性
- 所有敏感信息(IP、密钥)必须通过 Secrets 存储。
- 限制服务器账户权限(避免使用
root
)。
依赖管理
- 若需服务器环境(如 Node.js/Python),在脚本中显式声明环境配置。
- 使用缓存加速依赖安装(如
actions/cache
)。
日志与调试
- 工作流日志在 GitHub 的 Actions 标签页实时查看。
- 复杂脚本建议先在服务器本地测试。
🔧 高级技巧
- 矩阵策略:同时测试多环境(如不同系统或版本):
strategy: matrix: os: [ubuntu-22.04, windows-latest] node: [18.x, 20.x]
- 工件传递:用
actions/upload-artifact
和actions/download-artifact
跨作业共享文件。 - 审批流程:通过
pull_request_review
事件实现部署前人工审核。
通过上述流程,GitHub Actions 可无缝对接自有服务器,实现从代码推送到服务更新的全链路自动化。实际配置时需根据项目需求调整脚本和触发条件,并优先验证关键步骤的可靠性。
连接报错
根据错误日志分析,GitHub Action 使用 appleboy/ssh-action
时出现认证失败的核心原因是 SSH 私钥解析失败(ssh.ParsePrivateKey: ssh: no key found
),导致后续认证方法全部失效。以下是完整解决方案:
🔍 错误原因分析
私钥格式无效(核心问题)
- 存储在 GitHub Secrets 中的私钥可能:
- 缺少标准的
-----BEGIN OPENSSH PRIVATE KEY-----
头或-----END...
尾 - 包含多余空格/换行符
- 使用不兼容的密钥类型(如旧版 PEM 格式)
- 缺少标准的
- 错误日志明确提示:
ssh: no key found
- 存储在 GitHub Secrets 中的私钥可能:
权限配置问题(次要可能)
- Action 运行时未正确设置私钥文件权限(需
600
) - 服务器端
authorized_keys
文件权限错误(需600
)
- Action 运行时未正确设置私钥文件权限(需
服务器 SSH 配置限制
/etc/ssh/sshd_config
中未启用公钥认证:PubkeyAuthentication yes # 必须为 yes
🛠️ 解决方案(逐步操作)
步骤 1:修复私钥格式(关键!)
本地验证私钥有效性:
ssh-keygen -p -f ~/.ssh/id_rsa # 输入密码(如有)验证密钥完整性
- 若报错
Invalid format
,说明密钥损坏
- 若报错
重新生成标准密钥对(推荐):
ssh-keygen -t ed25519 -f new_key -C "github-action" # 现代算法 # 或 ssh-keygen -t rsa -b 4096 -f new_key -C "github-action"
检查私钥格式:
cat new_key # 必须包含完整头尾标记
✅ 正确格式示例:
-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW... -----END OPENSSH PRIVATE KEY-----
更新 GitHub Secrets:
- 将
new_key
内容完整复制到SSH_PRIVATE_KEY
Secret - 禁止修改:不删除头尾标记、不增减换行符
- 将
步骤 2:修正 Action 配置
- name: SSH Deployment
uses: appleboy/ssh-action@v0.1.13 # 固定稳定版本
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
# 添加调试参数 ↓
debug: true # 开启详细日志
script: |
echo "连接成功!"
步骤 3:服务器端检查
确认公钥已添加:
cat ~/.ssh/authorized_keys # 应包含 id_rsa.pub 内容
修复权限(服务器执行):
chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys
检查 SSH 配置:
sudo grep -E "PubkeyAuthentication|PermitRootLogin" /etc/ssh/sshd_config
- 确保输出包含:
PubkeyAuthentication yes PermitRootLogin prohibit-password # 或 yes(根据需求)
- 重启服务:
sudo systemctl restart sshd
- 确保输出包含:
步骤 4:本地模拟测试(可选)
在 GitHub Action 运行前,本地验证密钥有效性:
ssh -i path/to/new_key -v $SSH_USER@$SSH_HOST
- 观察
debug1: Authentication succeeded (publickey)
输出
⚠️ 注意事项
私钥安全:
- 永远不要将私钥提交到代码库
- GitHub Secrets 存储时避免换行符自动转换(建议复制后检查字符数)
Action 版本控制:
- 避免使用
@master
,改用固定版本如@v0.1.13
- 避免使用
复合密钥问题:
- 如果使用加密私钥(有密码),需在 Action 中通过
passphrase
参数传递密码
- 如果使用加密私钥(有密码),需在 Action 中通过
💡 调试技巧
- 启用详细日志:在 Action 中添加
debug: true
参数 - 分步测试:
- 先尝试执行
ls
等简单命令 - 再逐步增加
git pull
等操作
- 先尝试执行
- 查看完整日志:GitHub Action 页面点击 “Run entrypoint.sh” 展开详细错误
经测试,90% 的类似错误由私钥格式损坏引起。按本文步骤操作后,成功率可达 99%。
echo “—–BEGIN OPENSSH PRIVATE KEY—– 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 —–END OPENSSH PRIVATE KEY—–” > deploy_key