0. 写在前面:为什么你需要“神器”而非“常用命令
大家好,我是老杨,干货满满的老杨.欢迎来到互联网遥遥领先的博客. 欢迎点击原文链接或直接访问vps.top365app.com,来看老杨的全球vps信息还有各种咱们用得着的信息实时收集分析项目.
帮老杨点赞、转发、在看以及打开小星标哦
攒今世之功德,修来世之福报
Kubernetes 越来越重,维护和部署越来越累.每天都像在走钢丝。凌晨接电话,迷迷糊糊爬起来开电脑,手忙脚乱敲命令,生怕一不小心打错一个字符就把生产环境搞挂。那时候上线就像赌博,心跳总比 CPU 跑得还快。
不过这近些年我们用 GitOps 重构了整套运维流程,现在的感觉完全不一样了。今天跟大家聊聊这个过程。
以前做运维真是个手艺人,就看老师傅的手艺咋样:
# 每天都要重复这些命令
kubectl apply -f deployment.yaml
kubectl rollout status deployment/nginx
kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
nginx-7d8b49557c-2xm4k 1/1 Running 0 2m
nginx-7d8b49557c-8kw9x 1/1 Running 0 2m
nginx-7d8b49557c-qp7n2 1/1 Running 0 2m
记得有一次凌晨紧急修复,我在一堆配置文件里找来找去,最后发现是个缩进问题导致的 YAML 解析错误。那种感觉就像在黑夜里摸索电灯开关,越急越找不到。
现在用 GitOps,整个流程变得像工厂流水线一样标准化。我把所有配置都当作代码管理:
# apps/nginx/deployment.yaml
apiVersion:apps/v1
kind:Deployment
metadata:
name:nginx
namespace:production
labels:
app:nginx
version:v1.21.0
spec:
replicas:3
strategy:
type:RollingUpdate
rollingUpdate:
maxUnavailable:1
maxSurge:1
selector:
matchLabels:
app:nginx
template:
metadata:
labels:
app:nginx
spec:
containers:
-name:nginx
image:nginx:1.21.0-alpine
ports:
-containerPort:80
protocol:TCP
resources:
requests:
memory:"64Mi"
cpu:"50m"
limits:
memory:"128Mi"
cpu:"100m"
livenessProbe:
httpGet:
path:/
port:80
initialDelaySeconds:10
periodSeconds:10
readinessProbe:
httpGet:
path:/
port:80
initialDelaySeconds:5
periodSeconds: 5
改完配置直接推到 Git:
git add apps/nginx/deployment.yaml
git commit -m "nginx: 优化健康检查配置,增加就绪探针"
git push origin main
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 389 bytes | 389.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
ArgoCD 马上就检测到变更,自动开始部署:
time="2024-03-15T14:30:15Z" level=info msg="Starting sync operation" application=nginx
time="2024-03-15T14:30:16Z" level=info msg="Manifest already present in cluster" resource="Service/nginx"
time="2024-03-15T14:30:17Z" level=info msg="Updated resource" resource="Deployment/nginx"
time="2024-03-15T14:30:18Z" level=info msg="Sync operation completed in 3.2s" application=nginx
time="2024-03-15T14:30:45Z" level=info msg="Health assessment: Progressing -> Healthy" application=nginx
整个过程透明可控,就像在手机上追踪快递一样清楚。
详细聊聊 ArgoCD 的核心工作原理。很多人觉得 GitOps 就是个自动化脚本,其实远不止这么简单。
ArgoCD 采用了声明式的同步模型,这个设计非常巧妙。它不是简单地执行 kubectl apply,而是通过 Three-Way Merge 算法来精确计算需要执行的操作。
Three-Way Merge 的逻辑是这样的:
// ArgoCD 核心同步逻辑伪代码
func (ctrl *ApplicationController) Sync(app *v1alpha1.Application) error {
// 获取 Git 中的期望状态
targetManifests := ctrl.getTargetManifests(app)
// 获取集群中的实际状态
liveResources := ctrl.getLiveResources(app)
// 计算差异
diffResult := ctrl.diff(targetManifests, liveResources)
// 执行同步操作
for _, resource := range diffResult.Modified {
if resource.NeedUpdate {
ctrl.kubectl.Apply(resource.Manifest)
}
}
returnnil
}
这种机制的好处是能处理配置漂移。比如有人直接用 kubectl 修改了线上配置,ArgoCD 会检测到差异并自动修复回期望状态。
我们来看个具体例子。假设有人手动把 nginx 的副本数改成了 5:
kubectl scale deployment nginx --replicas=5
deployment.apps/nginx scaled
ArgoCD 会在下次同步时检测到差异:
time="2024-03-15T14:35:00Z" level=warn msg="Detected drift" application=nginx resource="Deployment/nginx"
time="2024-03-15T14:35:00Z" level=info msg="Live replica count: 5, Target replica count: 3"
time="2024-03-15T14:35:01Z" level=info msg="Auto-healing enabled, correcting drift"
time="2024-03-15T14:35:02Z" level=info msg="Scaled deployment nginx from 5 to 3 replicas"
这种自愈能力让系统始终保持在期望状态,不用担心手动操作导致的配置不一致。
ArgoCD 的健康检查机制也很有意思。它不仅检查资源是否存在,还会分析资源的实际运行状态:
# ArgoCD 对不同资源类型的健康检查逻辑
health_lua:|
local hs = {}
--Deployment健康检查
ifobj.kind=="Deployment"then
ifobj.status.readyReplicas==obj.spec.replicasthen
hs.status="Healthy"
hs.message="All replicas are ready"
else
hs.status="Progressing"
hs.message="Waiting for rollout to complete"
end
end
--Service健康检查
ifobj.kind=="Service"then
ifobj.spec.type=="LoadBalancer"then
ifobj.status.loadBalancer.ingressthen
hs.status="Healthy"
else
hs.status="Progressing"
hs.message="Waiting for load balancer"
end
else
hs.status="Healthy"
end
end
return hs
这种细粒度的健康检查让我能快速定位问题。比如 LoadBalancer 类型的 Service 创建失败,ArgoCD 会明确告诉我是在等待负载均衡器分配外部 IP。
举一个经典的生产故障。新版本的用户服务有个隐蔽的内存泄漏问题,运行一段时间后 Pod 就会 OOM 重启,导致服务不稳定。
以前遇到这种情况,我得找到上个稳定版本的配置,手动修改 deployment,然后重新部署。整个过程至少需要 10 分钟,而且容易出错。
现在用 GitOps 回滚简单得令人发指:
git log --oneline -n 5
a1b2c3d (HEAD -> main) feat: 用户服务升级到 v2.1.0,新增用户画像功能
e4f5g6h fix: 修复订单服务偶发性超时问题
i7j8k9l feat: 用户服务 v2.0.8,修复登录接口性能问题
m2n3o4p chore: 调整 nginx 配置,优化静态资源缓存
q5r6s7t fix: 数据库连接池配置优化
直接回滚到稳定版本:
git revert a1b2c3d --no-edit
[main f8g9h0i] Revert "feat: 用户服务升级到 v2.1.0,新增用户画像功能"
1 file changed, 1 insertion(+), 1 deletion(-)
git push origin main
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
...
To github.com:company/k8s-configs.git
a1b2c3d..f8g9h0i main -> main
ArgoCD 立即开始回滚:
time="2024-03-15T15:20:30Z" level=info msg="Detected new commit f8g9h0i"
time="2024-03-15T15:20:31Z" level=info msg="Starting rollback operation" application=user-service
time="2024-03-15T15:20:32Z" level=info msg="Rolling back user-service from v2.1.0 to v2.0.8"
time="2024-03-15T15:20:35Z" level=info msg="Deployment rollout started" deployment=user-service
time="2024-03-15T15:20:38Z" level=info msg="Old ReplicaSet user-service-7d8b49557c scaled down to 2"
time="2024-03-15T15:20:41Z" level=info msg="New ReplicaSet user-service-6c9a38446b scaled up to 2"
time="2024-03-15T15:20:44Z" level=info msg="Old ReplicaSet user-service-7d8b49557c scaled down to 1"
time="2024-03-15T15:20:47Z" level=info msg="New ReplicaSet user-service-6c9a38446b scaled up to 3"
time="2024-03-15T15:20:50Z" level=info msg="Old ReplicaSet user-service-7d8b49557c scaled down to 0"
time="2024-03-15T15:21:05Z" level=info msg="Rollback completed successfully"
从发现问题到完成回滚,总共用了不到 30 秒。而且所有操作都有审计日志,事后复盘的时候能清楚地看到整个处理过程。
以前管理权限真的头疼。开发同学要调试问题,需要生产环境的 kubectl 权限。给吧,担心误操作;不给吧,排查问题效率低下。
有次开发要查个 Pod 日志,我正在开会没法帮他。他等了半小时,最后只能让测试环境的服务凑合着用。这种情况经常发生,大家都很无奈。
现在用 GitOps + RBAC,权限管理变得井井有条。我设计了一套分层权限体系:
# ArgoCD RBAC 配置
apiVersion:v1
kind:ConfigMap
metadata:
name:argocd-rbac-cm
namespace:argocd
data:
policy.default:role:readonly
policy.csv:|
# 开发团队权限
p, role:developer, applications, get, dev/*, allow
p, role:developer, applications, sync, dev/*, allow
p, role:developer, repositories, get, *, allow
p, role:developer, logs, get, dev/*, allow
# 测试团队权限
p,role:tester,applications,get,test/*,allow
p,role:tester,applications,sync,test/*,allow
p,role:tester,applications,delete,test/*,allow
# SRE 团队权限
p,role:sre,applications,*,*/*,allow
p,role:sre,clusters,*,*,allow
p,role:sre,repositories,*,*,allow
# 团队成员映射
g,zhangsan@company.com,role:developer
g,lisi@company.com,role:developer
g,wangwu@company.com,role:tester
g,zhaoliu@company.com,role:sre
scopes: '[email,groups]'
配合 GitLab 的分支保护策略:
# .gitlab-ci.yml
stages:
-validate
-deploy-dev
-deploy-test
-deploy-prod
# 开发环境部署(开发人员可以直接触发)
deploy-dev:
stage:deploy-dev
script:
-argocdappsyncuser-service-dev
rules:
-if:'$CI_COMMIT_BRANCH == "develop"'
-if:'$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop"'
# 生产环境部署(需要 SRE 审批)
deploy-prod:
stage:deploy-prod
script:
-argocdappsyncuser-service-prod
rules:
-if:'$CI_COMMIT_BRANCH == "main"'
when:manual
allow_failure:false
environment:
name:production
action: start
现在的权限控制逻辑很清晰:
这套体系运行一年多,没出过权限相关的安全事故。而且开发效率反而提高了,因为大家不用排队等权限了。
一个实时分析对比全球多个优秀云厂商vps数据的平台
https://vps.top365app.com/zh
管理多环境配置是个技术活。同一个应用,开发环境要跑最新代码方便调试,测试环境要跑候选版本进行验收,生产环境要跑稳定版本保证可靠性。
我用 Kustomize 设计了一套分层配置体系:
k8s-configs/
├── apps/
│ └── user-service/
│ ├── base/
│ │ ├── kustomization.yaml
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ ├── configmap.yaml
│ │ └── ingress.yaml
│ ├── overlays/
│ │ ├── dev/
│ │ │ ├── kustomization.yaml
│ │ │ ├── patches/
│ │ │ │ ├── deployment-patch.yaml
│ │ │ │ └── configmap-patch.yaml
│ │ │ └── secrets/
│ │ ├── test/
│ │ │ └── ...
│ │ └── prod/
│ │ └── ...
基础配置定义通用部分:
# apps/user-service/base/deployment.yaml
apiVersion:apps/v1
kind:Deployment
metadata:
name:user-service
labels:
app:user-service
spec:
replicas:1# 默认副本数,会被 overlay 覆盖
selector:
matchLabels:
app:user-service
template:
metadata:
labels:
app:user-service
spec:
containers:
-name:app
image:user-service:latest# 默认镜像,会被 overlay 覆盖
ports:
-containerPort:8080
env:
-name:SPRING_PROFILES_ACTIVE
value:"default"
resources:
requests:
memory:"256Mi"
cpu:"100m"
limits:
memory:"512Mi"
cpu:"200m"
livenessProbe:
httpGet:
path:/actuator/health/liveness
port:8080
initialDelaySeconds:60
periodSeconds:10
readinessProbe:
httpGet:
path:/actuator/health/readiness
port:8080
initialDelaySeconds:30
periodSeconds: 5
开发环境的个性化配置:
# apps/user-service/overlays/dev/kustomization.yaml
apiVersion:kustomize.config.k8s.io/v1beta1
kind:Kustomization
namespace:dev
resources:
-../../base
images:
-name:user-service
newTag:dev-latest
replicas:
-name:user-service
count:1
patches:
-path:patches/deployment-patch.yaml
target:
kind:Deployment
name:user-service
configMapGenerator:
-name:user-service-config
files:
-application-dev.yml
behavior: merge
开发环境的补丁配置:
# apps/user-service/overlays/dev/patches/deployment-patch.yaml
-op:replace
path:/spec/template/spec/containers/0/env/0/value
value:"dev"
-op:add
path:/spec/template/spec/containers/0/env/-
value:
name:DEBUG_MODE
value:"true"
-op:replace
path:/spec/template/spec/containers/0/resources/requests/memory
value:"128Mi"
-op:replace
path:/spec/template/spec/containers/0/resources/limits/memory
value: "256Mi"
生产环境配置就更严格了:
# apps/user-service/overlays/prod/kustomization.yaml
apiVersion:kustomize.config.k8s.io/v1beta1
kind:Kustomization
namespace:production
resources:
-../../base
images:
-name:user-service
newTag:v2.0.8# 固定稳定版本
replicas:
-name:user-service
count:5
patches:
-path:patches/deployment-patch.yaml
-path:patches/security-patch.yaml
-path:patches/monitoring-patch.yaml
configMapGenerator:
-name:user-service-config
files:
-application-prod.yml
behavior:merge
secretGenerator:
-name:user-service-secrets
files:
-database-password.txt
-jwt-secret.txt
type: Opaque
生产环境的安全补丁:
# apps/user-service/overlays/prod/patches/security-patch.yaml
-op:add
path:/spec/template/spec/securityContext
value:
runAsNonRoot:true
runAsUser:1000
runAsGroup:1000
fsGroup:1000
-op:add
path:/spec/template/spec/containers/0/securityContext
value:
allowPrivilegeEscalation:false
readOnlyRootFilesystem:true
capabilities:
drop:
-ALL
seccompProfile:
type:RuntimeDefault
-op:add
path:/spec/template/spec/containers/0/volumeMounts
value:
-name:tmp-volume
mountPath:/tmp
-op:add
path:/spec/template/spec/volumes
value:
-name:tmp-volume
emptyDir: {}
这套配置体系的好处是显而易见的:
而且 Kustomize 的 patches 机制非常灵活,可以精确地修改配置的任何部分。比如我只想修改生产环境的 JVM 参数:
- op: add
path: /spec/template/spec/containers/0/env/-
value:
name: JAVA_OPTS
value: "-Xmx2g -Xms2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
这种精确控制让多环境管理变得游刃有余。
以前的监控告警就像个哑巴机器人,只会在出问题时发个短信,然后你就得自己去猜具体是什么情况。
现在的 GitOps 监控体系就像个贴心的助手,不仅告诉你出了什么问题,还会提供解决建议。
我搭建了一套分层监控体系:
# monitoring/prometheus-rules.yaml
apiVersion:monitoring.coreos.com/v1
kind:PrometheusRule
metadata:
name:gitops-monitoring
labels:
app:prometheus
spec:
groups:
-name:argocd-alerts
rules:
-alert:ArgoCDSyncFailed
expr:argocd_app_sync_total{phase="Failed"}>0
for:5m
labels:
severity:warning
team:sre
annotations:
summary:"ArgoCD 应用同步失败"
description:|
应用 {{ $labels.name }} 在命名空间 {{ $labels.dest_namespace }} 同步失败已超过 5 分钟
Git 仓库: {{ $labels.repo }}
目标分支: {{ $labels.dest_server }}
-alert:ArgoCDAppUnhealthy
expr:argocd_app_health_status{health_status!="Healthy"}==1
for:2m
labels:
severity:critical
team:sre
annotations:
summary:"ArgoCD 应用健康状态异常"
description:|
应用 {{ $labels.name }} 健康状态为 {{ $labels.health_status }}
当前同步状态: {{ $labels.sync_status }}
建议检查: kubectl describe app {{ $labels.name }} -n argocd
-name:application-alerts
rules:
-alert:PodCrashLooping
expr:rate(kube_pod_container_status_restarts_total[5m])*300>1
for:2m
labels:
severity:warning
team:dev
annotations:
summary:"Pod 频繁重启"
description:|
Pod {{ $labels.pod }} 在命名空间 {{ $labels.namespace }} 频繁重启
容器: {{ $labels.container }}
近 5 分钟重启次数: {{ $value }}
排查命令: kubectl logs {{ $labels.pod }} -n {{ $labels.namespace }} --previous
-alert:DeploymentReplicasMismatch
expr:kube_deployment_spec_replicas!=kube_deployment_status_ready_replicas
for:10m
labels:
severity:warning
team:sre
annotations:
summary:"Deployment 副本数不匹配"
description: |
Deployment {{ $labels.deployment }} 在命名空间 {{ $labels.namespace }} 副本数异常
期望副本数: {{ $labels.spec_replicas }}
就绪副本数: {{ $labels.ready_replicas }}
检查命令: kubectl describe deployment {{ $labels.deployment }} -n {{ $labels.namespace }}
告警规则设计得很实用,不仅有问题描述,还直接给出排查命令。收到告警后,我能快速定位问题。
集成钉钉机器人:
# alertmanager/config.yaml
global:
resolve_timeout:5m
route:
group_by: ['alertname']
group_wait:30s
group_interval:5m
repeat_interval:12h
receiver:'dingtalk-webhook'
routes:
-match:
severity:critical
receiver:'dingtalk-webhook-critical'
receivers:
-name:'dingtalk-webhook'
webhook_configs:
-url:'http://dingtalk-webhook:8060/dingtalk/webhook/send'
send_resolved:true
-name:'dingtalk-webhook-critical'
webhook_configs:
-url:'http://dingtalk-webhook:8060/dingtalk/webhook/send'
send_resolved:true
email_configs:
-to:'sre-team@company.com'
subject:'[CRITICAL] {{ .GroupLabels.alertname }}'
body: |
{{ range .Alerts }}
告警: {{ .Annotations.summary }}
描述: {{ .Annotations.description }}
时间: {{ .StartsAt.Format "2006-01-02 15:04:05" }}
{{ end }}
钉钉消息的格式也优化过:
{
"msgtype": "markdown",
"markdown": {
"title": "GitOps 监控告警",
"text": "## 🚨 ArgoCD 应用同步失败\n\n**应用名称**: user-service\n**命名空间**: production\n**Git 仓库**: github.com/company/k8s-configs\n**失败时间**: 2024-03-15 15:30:00\n\n**排查建议**: \n```bash\nkubectl describe app user-service -n argocd\n```\n\n**负责人**: @张三 @李四"
}
}
这种结构化的告警信息让问题处理效率大大提升。团队成员看到告警就知道该怎么处理,不用再到处找人问情况了。
用了 GitOps 之后,成本控制的效果让我意外。因为所有配置变更都在 Git 里有记录,我能很清楚地分析资源使用趋势。
我写了个脚本来分析历史变更:
#!/bin/bash
# 分析近一个月的资源配置变更
echo"=== 近 30 天资源配置变更统计 ==="
git log --since="30 days ago" \
--grep="resources\|replicas\|cpu\|memory" \
--pretty=format:"%h %an %ad %s" \
--date=short | whileread line; do
echo"$line"
done
echo -e "\n=== CPU 请求量变更趋势 ==="
git log --since="30 days ago" -p -- "*/deployment.yaml" | \
grep -E "^\+.*cpu.*:" | \
sed 's/.*cpu: "\([^"]*\)".*/\1/' | \
sort | uniq -c | sort -nr
echo -e "\n=== 内存请求量变更趋势 ==="
git log --since="30 days ago" -p -- "*/deployment.yaml" | \
grep -E "^\+.*memory.*:" | \
sed 's/.*memory: "\([^"]*\)".*/\1/' | \
sort | uniq -c | sort -nr
运行结果:
=== 近 30 天资源配置变更统计 ===
a1b2c3d 张三 2024-03-10 优化 nginx CPU 限制 100m->200m,响应延迟降低 30%
e4f5g6h 李四 2024-03-08 redis 内存增加到 2Gi,解决 OOM 问题
i7j8k9l 王五 2024-03-05 数据库副本扩容 1->3,提升高可用性
m2n3o4p 赵六 2024-03-03 开发环境自动缩容,夜间副本数 3->1
=== CPU 请求量变更趋势 ===
8 200m
5 100m
3 500m
2 1000m
=== 内存请求量变更趋
量变更趋势 ===
12 512Mi
8 256Mi
6 1Gi
4 2Gi
2 128Mi
这个分析让我发现了几个问题:
于是我设计了一套自动成本优化策略。利用 GitLab CI 的定时任务和 Prometheus 监控数据:
# .gitlab-ci.yml
cost-optimization:
stage:maintenance
image:alpine/git:latest
script:
-apkadd--no-cachecurljq
-./scripts/auto-scaling.sh
rules:
-if:$CI_PIPELINE_SOURCE=="schedule"
only:
variables:
-$SCHEDULE_TYPE=="cost_optimization"
# scripts/auto-scaling.sh
#!/bin/bash
# 获取 Prometheus 指标数据
get_cpu_usage() {
localapp=$1
localnamespace=$2
localquery="avg(rate(container_cpu_usage_seconds_total{pod=~\"$app-.*\", namespace=\"$namespace\"}[5m]))"
curl-s"http://prometheus:9090/api/v1/query?query=$query"|jq-r'.data.result[0].value[1]'
}
get_memory_usage() {
localapp=$1
localnamespace=$2
localquery="avg(container_memory_working_set_bytes{pod=~\"$app-.*\", namespace=\"$namespace\"})/1024/1024"
curl-s"http://prometheus:9090/api/v1/query?query=$query"|jq-r'.data.result[0].value[1]'
}
# 分析开发环境资源使用情况
echo"=== 开发环境资源使用分析 ==="
forappinuser-serviceorder-servicepayment-service;do
cpu_usage=$(get_cpu_usage$appdev)
memory_usage=$(get_memory_usage$appdev)
echo"应用: $app"
echo"CPU 使用率: ${cpu_usage}%"
echo"内存使用量: ${memory_usage}Mi"
# 如果是夜间且使用率低于 10%,自动缩容
current_hour=$(date+%H)
if [ $current_hour-ge22 ] || [ $current_hour-le8 ];then
if(($(echo"$cpu_usage < 0.1"|bc-l)));then
echo"检测到低使用率,执行夜间缩容"
# 修改 kustomization.yaml 文件
sed-i"s/count: [0-9]*/count: 1/"environments/dev/$app/kustomization.yaml
# 提交变更
gitaddenvironments/dev/$app/kustomization.yaml
gitcommit-m"自动优化: $app 夜间缩容,CPU 使用率仅 ${cpu_usage}%"
fi
fi
done
# 如果有变更,推送到仓库
if!gitdiff--quietHEAD~1;then
gitpushoriginmain
echo"成本优化变更已提交"
fi
这套自动化成本优化策略运行了半年,效果显著:
更重要的是,所有的成本优化操作都有 Git 记录,可以随时回滚。有次自动缩容导致早上第一个接口调用超时,我立马回滚了配置,然后调整了缩容策略的时间窗口。
现在回头看,我挺庆幸当初迈出了那一步。GitOps 并没有让 Kubernetes 变简单,但它让流程有了秩序。上线像流水线,回滚像倒带,权限像保险柜。比起熬夜抱着终端提心吊胆,这已经是巨大的进步。
这里老杨先声明一下,日常生活中大家都叫老杨波哥,跟辈分没关系,主要是岁数大了.就一个代称而已. 老杨的00后小同事老杨喊都是带哥的.张哥,李哥的. 但是这个称呼呀,在线下参加一些活动时.金主爸爸也这么叫就显的不太合适. 比如上次某集团策划总监,公司开大会来一句:“今个咱高兴!有请IT运维技术圈的波哥讲两句“ 这个氛围配这个称呼在互联网这行来讲就有点对不齐! 每次遇到这个情况老杨就想这么接话: “遇到各位是缘分,承蒙厚爱,啥也别说了,都在酒里了.老杨干了,你们随意!” 所以以后咱们改叫老杨,即市井又低调.还挺亲切,老杨觉得挺好.
运维X档案系列文章:
企业级 Kubernetes 集群安全加固全攻略( 附带一键检查脚本)
看完别走.修行在于点赞、转发、在看.攒今世之功德,修来世之福报
点击阅读原文或打开地址实时收集分析全球vps的项目 vps.top365app.com
老杨AI的号: 98dev