第一章:Windows 11 Go开发环境配置前的系统准备与认知升级
在正式安装Go工具链之前,必须完成对Windows 11底层运行环境的系统性梳理与主动调优。这并非简单的“检查是否满足最低配置”,而是围绕开发效能、安全边界与跨平台一致性展开的认知重构——Go语言强调“一次构建、随处运行”,但其Windows体验的健壮性高度依赖宿主系统的内核行为、权限模型与开发者模式就绪状态。
系统版本与更新验证
确保运行 Windows 11 版本 22H2 或更高(推荐 23H2)。打开终端执行:
# 获取精确版本号与架构信息
Get-ComputerInfo | Select-Object WindowsVersion, OsArchitecture, WindowsBuildLabEx
若输出中 WindowsBuildLabEx 显示低于 22621(即22H2基线),请通过「设置 → Windows 更新」手动检查并安装累积更新。跳过此步可能导致WSL2集成异常或go test -race失效。
开发者模式与可选功能启用
Windows 11 的开发者模式是Go模块代理、本地Git钩子及调试器符号加载的关键前提:
- 进入「设置 → 系统 → 针对开发人员」,启用「开发者模式」;
- 同时启用「Windows Subsystem for Linux」与「Virtual Machine Platform」(需重启);
- 在PowerShell(管理员)中运行:
# 启用OpenSSH客户端(Go工具链常依赖SSH拉取私有仓库) Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
环境变量与路径语义校准
Windows传统路径分隔符(\)与Go标准库的Unix风格路径处理(/)存在隐式兼容层,但GOROOT和GOPATH必须使用纯ASCII路径且不含空格或中文。推荐统一采用:
GOROOT:C:\Go(官方安装包默认路径)GOPATH:C:\Users\YourName\go(避免OneDrive同步目录)
⚠️ 注意:若已安装旧版Go,请先卸载并手动删除残留注册表项
HKEY_LOCAL_MACHINE\SOFTWARE\Go,再清理%PATH%中所有go\bin引用——残留路径会导致go version输出混乱。
| 检查项 | 推荐值 | 验证命令 |
|---|---|---|
| PowerShell执行策略 | RemoteSigned | Get-ExecutionPolicy |
| 默认终端编码 | UTF-8 | [Console]::OutputEncoding 应返回 System.Text.UTF8Encoding |
| Git全局配置 | core.autocrlf=input |
git config --global core.autocrlf input |
完成上述准备后,系统将具备稳定承载Go 1.21+全功能集(包括go work、go install二进制管理及gopls语言服务器)的底层能力。
第二章:Go语言核心组件在Win11上的精准部署
2.1 Go SDK版本选型策略与官方二进制包校验实践
选择Go SDK需兼顾稳定性、兼容性与安全生命周期。优先采用Go官方发布的LTS支持版本(如v1.21.x),避免使用已EOL的v1.19及更早版本。
版本决策关键维度
- ✅ Go Modules兼容性(v1.16+默认启用)
- ✅ CVE修复时效性(参考Go Security Advisories)
- ❌ 避免beta/rc构建用于生产环境
官方二进制校验标准流程
# 下载SHA256校验文件与二进制包
curl -O https://go.dev/dl/go1.21.13.linux-amd64.tar.gz
curl -O https://go.dev/dl/go1.21.13.linux-amd64.tar.gz.sha256
# 验证完整性(输出应为"OK")
shasum -a 256 -c go1.21.13.linux-amd64.tar.gz.sha256
该命令调用
shasum对下载包执行SHA256哈希比对;.sha256文件由Go团队用私钥签名生成,确保未被中间人篡改。参数-c启用校验模式,严格匹配文件名与哈希值。
推荐版本矩阵(截至2024Q3)
| Go SDK 版本 | 支持状态 | 推荐场景 |
|---|---|---|
| 1.21.x | LTS | 企业级长期项目 |
| 1.22.x | Current | 新项目/尝鲜特性 |
| 1.20.x | Deprecated | 仅限紧急维护 |
graph TD
A[获取SDK下载页] --> B{是否为go.dev域名?}
B -->|是| C[下载.tar.gz + .sha256]
B -->|否| D[立即中止:非官方源]
C --> E[shasum -c 校验]
E -->|OK| F[解压并验证go version]
E -->|FAIL| D
2.2 Windows 11路径语义解析与GOROOT/GOPATH双变量科学初始化
Windows 11 对长路径(\\?\ 前缀)和符号链接的语义支持更严格,直接影响 Go 工具链对 GOROOT 和 GOPATH 的路径规范化行为。
路径语义关键差异
- 启用
LongPathsEnabled=1后,os.Stat()才能正确解析C:\Program Files\Go中含空格路径; \\?\C:\go形式路径绕过 Win32 API 路径截断,但 Go 1.21+ 默认拒绝该格式以避免跨平台不一致。
双变量初始化最佳实践
# 推荐:使用短路径 + 环境变量隔离
$env:GOROOT = "C:\Go" # 必须指向二进制根,不可含空格或 Unicode
$env:GOPATH = "$env:USERPROFILE\go" # 用户级工作区,自动启用模块感知
逻辑分析:
GOROOT必须为纯 ASCII、无空格的绝对路径,否则go env -w GOROOT=...会静默失败;GOPATH若设为C:\Users\张三\go,Windows 11 的 UTF-16 路径编码会导致go list解析错误。PowerShell 中$env:直接写入进程环境,避免 CMD 的延迟扩展陷阱。
| 变量 | 推荐值 | 模块模式影响 |
|---|---|---|
| GOROOT | C:\Go |
决定 go 命令来源 |
| GOPATH | %USERPROFILE%\go |
go get 默认下载位置 |
graph TD
A[PowerShell 启动] --> B[读取系统环境]
B --> C{GOROOT 是否合法?}
C -->|是| D[加载 go.exe 二进制]
C -->|否| E[报错:'cannot find GOROOT']
D --> F[按 GOPATH 初始化 module cache]
2.3 PowerShell 7+环境适配与Go模块默认行为深度调优
PowerShell 7+ 基于 .NET 6+,默认启用 PSNativeCommandArgumentPassing=Legacy,而 Go 模块构建时依赖 GOOS/GOARCH 环境变量的纯净传递——二者存在隐式冲突。
环境变量透传修复
# 强制启用现代参数传递并隔离 Go 构建上下文
$env:PSNativeCommandArgumentPassing = 'Standard'
$env:GOOS = 'windows'
$env:GOARCH = 'amd64'
go build -ldflags="-s -w" -o app.exe main.go
此配置禁用 PowerShell 对引号/空格的旧式转义,确保
go build接收原始环境值;-ldflags启用符号剥离与链接优化,减小二进制体积。
Go 模块代理策略对比
| 策略 | 适用场景 | 启用命令 |
|---|---|---|
GOPROXY=direct |
内网离线构建 | go env -w GOPROXY=direct |
GOPROXY=https://goproxy.cn |
国内加速 | go env -w GOPROXY=https://goproxy.cn,direct |
构建流程协同逻辑
graph TD
A[PowerShell 7+] --> B{PSNativeCommandArgumentPassing}
B -->|Standard| C[Go 进程接收原生环境]
B -->|Legacy| D[参数被双重转义 → GOOS 解析失败]
C --> E[go build 成功识别平台]
2.4 Windows Defender/SmartScreen对Go工具链的误报规避与可信签名配置
为何Go二进制常被误报
Windows Defender 和 SmartScreen 基于启发式行为分析(如无签名、高熵PE节、直接系统调用)将合法Go程序标记为“潜在不安全”。Go默认静态链接生成无调试信息、无导入表的紧凑二进制,易触发启发式规则。
可信签名实践步骤
- 获取EV代码签名证书(非OV),支持微软硬件级时间戳服务
- 使用
signtool签名并强制嵌入时间戳:signtool sign /fd SHA256 /td SHA256 /tr http://timestamp.digicert.com /a myapp.exe参数说明:
/fd SHA256指定摘要算法;/tr指向可信RFC 3161时间戳服务器;/a自动选择证书;缺失/tr将导致签名随证书过期失效。
SmartScreen信誉积累关键指标
| 指标 | 要求 |
|---|---|
| 签名持续时间 | ≥30天(EV证书需激活) |
| 下载量(Microsoft Store外) | ≥500次独立IP安装 |
| 无用户举报记录 | 连续7天零“误报”反馈 |
graph TD
A[Go构建] --> B[strip -s -w binary]
B --> C[UPX可选压缩]
C --> D[signtool签名+RFC3161时间戳]
D --> E[提交Microsoft Attestation]
2.5 Win11 WSL2协同场景下Go交叉编译环境的隔离与复用设计
在 Windows 11 + WSL2 协同开发中,需兼顾宿主系统(x64)与目标嵌入式平台(如 arm64、riscv64)的编译需求,同时避免污染全局 Go 环境。
环境隔离策略
采用 GOOS/GOARCH 显式声明 + GOCACHE 和 GOPATH 容器化路径分离:
# 在 WSL2 中为 ARM64 构建专用工作区
export GOOS=linux && export GOARCH=arm64
export GOCACHE=$HOME/.cache/go-arm64
export GOPATH=$HOME/go-arm64
此配置将构建缓存与模块下载完全隔离于
go-amd64环境;GOCACHE路径变更确保.a文件不混用,GOPATH分离防止go install冲突。
复用机制设计
| 组件 | 宿主共享 | WSL2 隔离 | 说明 |
|---|---|---|---|
| Go SDK | ✅ | ❌ | 通过 /mnt/wslg/ 挂载复用 |
| CGO 工具链 | ❌ | ✅ | WSL2 内独立安装 gcc-aarch64-linux-gnu |
| vendor 缓存 | ✅ | ✅ | Git submodule + .gitignore 精确控制 |
数据同步机制
graph TD
A[Windows VS Code] -->|sftp://wsl%3A/| B(WSL2 Ubuntu)
B --> C[go build -o bin/app-arm64]
C --> D[/mnt/wslg/workspace/bin/]
D -->|自动映射| A
第三章:VS Code + Go插件生态的工业级调试体系构建
3.1 Delve调试器在Win11上的静默安装与符号服务器直连优化
Delve(dlv)作为Go生态首选调试器,在Windows 11上需规避交互式安装与符号加载延迟问题。
静默安装脚本(PowerShell)
# 使用Chocolatey静默安装Delve(需提前安装choco)
choco install delve --force -y --no-progress
# 或直接下载二进制并注册PATH
Invoke-WebRequest -Uri "https://github.com/go-delve/delve/releases/download/v1.23.0/dlv_windows_amd64.zip" -OutFile "$env:TEMP\dlv.zip"
Expand-Archive "$env:TEMP\dlv.zip" -DestinationPath "$env:LOCALAPPDATA\Programs\Delve"
$env:PATH += ";$env:LOCALAPPDATA\Programs\Delve"
该脚本绕过UAC弹窗,--force -y禁用确认,--no-progress消除进度条输出,适配自动化部署流水线。
符号直连配置
Delve默认不主动拉取Go标准库符号;需显式启用微软符号服务器:
dlv debug --headless --continue --api-version=2 --log --log-output=debugger \
--check-go-version=false \
--only-same-user=false \
--backend=windows \
--symbol-server=https://msdl.microsoft.com/download/symbols
关键参数:--symbol-server直连MSDL,避免本地go build -gcflags="all=-N -l"冗余编译;--check-go-version=false跳过版本校验以兼容Win11新内核ABI。
| 参数 | 作用 | Win11特需性 |
|---|---|---|
--backend=windows |
强制使用native Windows backend | 避免WSL2兼容层性能损耗 |
--only-same-user=false |
允许跨用户调试(如服务进程) | 适配Win11系统服务场景 |
graph TD
A[dlv启动] --> B{符号请求}
B -->|未命中本地缓存| C[直连MSDL服务器]
C --> D[返回PDB/DBG符号流]
D --> E[注入调试会话内存映射]
3.2 Go Extension Pack配置解耦:自动补全、格式化、测试驱动的原子化开关控制
Go Extension Pack 的核心价值在于能力解耦——每项功能可独立启停,避免“全有或全无”的耦合陷阱。
原子化开关控制机制
通过 settings.json 精确控制各子功能:
{
"go.autocompleteUnimportedPackages": false,
"go.formatTool": "gofumpt",
"go.testFlags": ["-race", "-count=1"],
"go.enableCodeLens": { "test": true, "run": false }
}
autocompleteUnimportedPackages 关闭后,补全仅限已导入包,显著降低误导风险;enableCodeLens.test 启用而 run 关闭,实现测试驱动开发(TDD)的聚焦视图。
功能开关对照表
| 功能模块 | 配置项 | 推荐场景 |
|---|---|---|
| 自动补全 | go.autocompleteUnimportedPackages |
大型单体项目防污染 |
| 格式化 | go.formatTool |
统一团队代码风格 |
| 测试驱动支持 | go.enableCodeLens.test |
TDD 迭代中快速验证逻辑 |
启停逻辑流
graph TD
A[用户修改 settings.json] --> B{VS Code 重载配置}
B --> C[Go语言服务器感知变更]
C --> D[按模块粒度重建LSP能力注册]
D --> E[补全/格式化/测试Lens独立生效]
3.3 Windows Terminal集成方案:多会话终端与Go test -v实时流式输出可视化
Windows Terminal 支持通过 profiles.json 配置多标签页会话,天然适配 Go 测试的并发输出场景。
多会话配置示例
{
"guid": "{a1b2c3d4-...}",
"name": "Go Test (verbose)",
"commandline": "powershell -Command \"go test -v ./... | ForEach-Object { Write-Host $_; Start-Sleep -Milliseconds 10 }\"",
"hidden": false
}
该配置启用 PowerShell 实时逐行捕获 go test -v 输出,并添加微延迟确保 Windows Terminal 渲染不丢帧;ForEach-Object 替代原始管道缓冲,实现真正流式透传。
输出行为对比
| 行为 | 默认 cmd.exe | Windows Terminal + PowerShell |
|---|---|---|
| 行级高亮 | ❌ | ✅(支持 ANSI 转义) |
| 并发测试输出隔离 | ❌(混杂) | ✅(多标签独立会话) |
流程可视化
graph TD
A[go test -v] --> B[Stdout 流]
B --> C{PowerShell 管道}
C --> D[逐行 Write-Host]
D --> E[WT 渲染引擎]
E --> F[ANSI 着色/滚动缓冲]
第四章:企业级Go工程基础设施的Win11原生落地
4.1 Go Modules代理加速:goproxy.cn与自建反向代理的混合策略部署
在高并发构建与多团队协作场景下,单一公共代理易受网络波动与限流影响。混合策略通过分层缓存实现弹性加速:公网依赖走 goproxy.cn,私有模块与高频内部包则由自建 Nginx 反向代理(带本地磁盘缓存)承接。
架构分流逻辑
# /etc/nginx/conf.d/gomod-proxy.conf
proxy_cache_path /var/cache/go-proxy levels=1:2 keys_zone=gomod:10m max_size=5g;
server {
listen 8081;
location / {
proxy_cache gomod;
proxy_cache_valid 200 302 1h;
proxy_cache_lock on;
# 私有模块匹配:如 company.com/internal/...
if ($request_uri ~ "^/company\.com/") {
proxy_pass https://internal-go-registry;
break;
}
proxy_pass https://goproxy.cn;
}
}
该配置启用两级缓存(
levels=1:2)与原子锁(proxy_cache_lock),避免缓存击穿;max_size=5g防止磁盘溢出;proxy_cache_valid对成功响应缓存1小时,显著降低上游请求频次。
环境变量协同配置
| 环境变量 | 值 | 作用 |
|---|---|---|
GOPROXY |
http://localhost:8081,direct |
优先走本地代理,失败直连 |
GONOSUMDB |
company.com |
跳过私有模块校验 |
GOPRIVATE |
company.com |
标记私有域名不走公共代理 |
流量路由决策流程
graph TD
A[go build] --> B{GOPROXY 首节点}
B -->|匹配 GOPRIVATE| C[转发至 internal-go-registry]
B -->|不匹配| D[转发至 goproxy.cn]
C --> E[命中本地缓存?]
E -->|是| F[返回缓存响应]
E -->|否| G[拉取并缓存后返回]
4.2 Git Hooks + pre-commit校验:go fmt/go vet/go lint在Win11 PowerShell中的无感嵌入
为什么需要无感嵌入?
开发人员抗拒显式执行格式化/检查命令。将 go fmt、go vet、golint(或更现代的 golangci-lint)自动注入提交流程,可保障代码质量零遗漏。
安装与初始化
# 在项目根目录执行(PowerShell 7+ 推荐)
git init
npm install -g pre-commit
pre-commit install --hook-type pre-commit
此命令在
.git/hooks/pre-commit创建 PowerShell 脚本包装器,绕过 Windows 默认 CMD 兼容性问题;--hook-type显式指定钩子类型,避免 PowerShell 执行策略拦截。
配置 .pre-commit-config.yaml
| 工具 | 命令 | 触发时机 |
|---|---|---|
go fmt |
go fmt ./... |
修改 .go 文件 |
go vet |
go vet ./... |
提交前静态检查 |
golangci-lint |
golangci-lint run --fast |
并行多规则扫描 |
repos:
- repo: https://github.com/dnephin/pre-commit-golang
rev: v0.5.0
hooks:
- id: go-fmt
- id: go-vet
- id: golangci-lint
流程可视化
graph TD
A[git commit] --> B{pre-commit hook}
B --> C[并行执行 go fmt/vet/golangci-lint]
C --> D{全部通过?}
D -->|是| E[允许提交]
D -->|否| F[中止并输出错误行号]
4.3 Windows服务化封装:使用nssm将Go Web服务注册为系统服务并实现优雅启停
Windows原生不支持Go二进制的系统服务托管,nssm(Non-Sucking Service Manager)提供轻量、可靠的封装方案。
安装与准备
- 下载 nssm.exe(推荐 v2.24+),置于
C:\nssm\ - 确保 Go 服务已编译为控制台程序(非 GUI 子系统),并支持
SIGINT/os.Interrupt信号捕获
注册服务命令
nssm install MyGoWebSvc
执行后弹出图形界面,需配置:
- Path:
D:\myapp\server.exe - Startup directory:
D:\myapp\ - Service name:
MyGoWebSvc - Service description:
Go HTTP server with graceful shutdown
优雅启停关键逻辑
Go 主程序需监听系统关闭信号并完成 HTTP Server 的 Shutdown():
srv := &http.Server{Addr: ":8080", Handler: router}
go func() {
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
log.Fatal(err)
}
}()
// 等待中断信号
quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
<-quit
log.Println("Shutting down server...")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatal("Server forced to shutdown:", err)
}
参数说明:
WithTimeout(10s)限定清理窗口;Shutdown()阻塞至所有连接完成或超时;SIGTERM由 nssm 在“停止服务”时发送,确保资源释放。
| 配置项 | 推荐值 | 说明 |
|---|---|---|
| Service Type | Own Process |
独立进程,避免依赖 svchost |
| Stop Service | Wait for service to stop |
启用 Shutdown() 同步等待 |
| Exit Actions | Restart |
崩溃后自动恢复(可选) |
graph TD A[Windows SCM] –>|StartService| B[nssm] B –>|Spawn| C[Go server.exe] C –>|On SIGTERM| D[Graceful Shutdown] D –> E[HTTP connections drain] E –> F[Exit code 0 → SCM reports STOPPED]
4.4 Win11性能计数器对接:通过gops/gotrace采集Go Runtime指标并接入PerfMon可视化
Windows 11 的 PerfMon 原生不支持 Go 运行时指标,需构建桥接层实现标准化暴露。
数据同步机制
使用 gops 启动诊断端点,配合 gotrace 提取实时 runtime/metrics:
import "github.com/google/gops/agent"
func init() {
agent.Listen(agent.Options{ // 启用 TCP 端点与 SIGUSR1 支持
Addr: "127.0.0.1:6060", // gops 默认端口
ShutdownCleanup: true, // 进程退出时自动清理
})
}
该配置启用 /debug/pprof/ 和 /debug/metrics(Go 1.21+),为后续拉取提供 HTTP 接口基础。
指标转换管道
自定义 exporter 将 JSON 格式 runtime/metrics 映射为 Windows PDH 兼容计数器路径:
| Go Metric | PerfMon Counter Path |
|---|---|
go_goroutines |
\GoApp\Goroutines |
go_memstats_alloc_bytes |
\GoApp\HeapAllocBytes |
流程概览
graph TD
A[gops HTTP Server] --> B[Exporter轮询 /debug/metrics]
B --> C[JSON → PDH Counter Registration]
C --> D[PerfMon 实时图表渲染]
第五章:配置完成验证与长期维护黄金法则
验证清单驱动的上线前检查
在Kubernetes集群完成Istio服务网格部署后,必须执行结构化验证。以下为生产环境强制检查项:
- ✅ 所有控制平面Pod处于
Running且就绪(istiod,ingressgateway,egressgateway) - ✅
kubectl get svc -n istio-system | grep -E 'istio-ingressgateway|istio-egressgateway'返回非空且EXTERNAL-IP非<pending> - ✅ 应用命名空间已注入Sidecar(
kubectl get namespace demo --show-labels | grep istio-injection=enabled) - ✅ 通过
istioctl verify-install返回✅ Istio is installed successfully
真实流量灰度验证流程
某电商中台在2023年Q4升级至Istio 1.21后,采用三级渐进式验证:
- 内部健康探针:向
/healthz端点发送每秒5次请求,持续3分钟,错误率 - 合成事务流:使用
k6脚本模拟用户登录→商品搜索→下单链路,成功率需≥99.95% - 真实用户分流:通过
VirtualService将5%生产流量导向新版本,监控istio_requests_total{destination_service="productsvc.default.svc.cluster.local", response_code=~"5.*"}指标突增超阈值立即熔断
长期维护的四大不可妥协原则
| 原则 | 实施方式 | 违反后果 |
|---|---|---|
| 配置即代码 | 所有Gateway/VirtualService必须存于Git仓库,通过Argo CD自动同步 |
手动修改导致配置漂移,故障定位耗时增加300% |
| 指标基线化 | 每周采集istio_request_duration_seconds_bucket第95百分位值,建立动态基线(±15%波动容忍) |
未设基线时,延迟从800ms升至2200ms仍被判定为“正常” |
| 证书自动轮转 | 使用cert-manager签发Let’s Encrypt证书,Certificate资源设置renewBefore: 72h |
2022年某金融客户因证书过期导致API网关全量503,影响支付链路47分钟 |
| 变更双人复核 | 所有PeerAuthentication策略变更需经SRE+安全工程师双签名PR |
单人误删全局mTLS策略,导致跨命名空间调用全部失败 |
flowchart TD
A[配置变更提交] --> B{是否修改认证/授权策略?}
B -->|是| C[触发安全扫描流水线]
B -->|否| D[执行单元测试]
C --> E[人工安全评审]
D --> F[部署到预发集群]
E --> F
F --> G[运行自动化验证套件]
G --> H{所有检查通过?}
H -->|是| I[自动合并并发布]
H -->|否| J[阻断合并并告警]
故障自愈机制设计实例
某物流平台在Prometheus中配置以下告警规则:
- alert: IstioControlPlaneHighErrorRate
expr: sum(rate(istio_requests_total{source_workload="istiod", response_code=~"5.*"}[5m])) / sum(rate(istio_requests_total{source_workload="istiod"}[5m])) > 0.03
for: 2m
labels:
severity: critical
annotations:
summary: "istiod错误率超3%,可能影响服务发现"
该规则触发后,自动执行kubectl rollout restart deploy/istiod -n istio-system并通知值班SRE。
文档与知识沉淀规范
每次配置变更必须同步更新Confluence文档页,包含:
- 变更时间戳与操作人(如
2024-06-12T14:22:08Z @ops-wangli) - 对应Git提交哈希及Jira工单号(
GIT: a3f8b2d | JIRA: INFRA-4821) - 验证命令输出截图(含
kubectl get pods -n istio-system -o wide完整结果) - 回滚步骤(精确到
kubectl apply -f manifests/istio-1.20-backup.yaml)
监控告警分级响应SLA
对istio_requests_total指标异常实施三级响应:
- P0级(全链路中断):5分钟内电话告警,15分钟内初步定位
- P1级(核心服务降级):30分钟内企业微信响应,2小时内提供临时方案
- P2级(非关键路径延迟升高):2小时内邮件确认,下一个工作日闭环
自动化巡检脚本示例
每日凌晨2点执行的istio-health-check.sh包含:
# 检查Sidecar注入一致性
INJECTED=$(kubectl get ns --selector istio-injection=enabled -o name | wc -l)
TOTAL=$(kubectl get ns -o name | wc -l)
if [ $((INJECTED * 100 / TOTAL)) -lt 95 ]; then
echo "WARN: Only $INJECTED/$TOTAL namespaces have auto-injection enabled"
fi 