问题
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.21kubectl 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:00API 触发
通过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_KEYSecret - 禁止修改:不删除头尾标记、不增减换行符
- 将
步骤 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