跳到主要内容

国内 Docker 配置 atomhub 镜像仓库

· 阅读需 1 分钟
素明诚
Full stack development

Docker Hub 镜像被禁,在国内可以使用下面这个镜像源,目前只有一些基础镜像

编辑 Docker 配置文件: 打开或创建 /etc/docker/daemon.json 文件

{
"registry-mirrors": [
"https://atomhub.openatom.cn"
]
}

重启 Docker 服务: 为使配置生效,请执行以下命令:

sudo systemctl daemon-reload
sudo systemctl restart docker

官网地址

https://atomhub.openatom.cn/

试过这个源目前是可以使用的,因为里面有华为,所以相信未来也一定可以继续使用!

Linux 命令 nvidia-smi 参数

· 阅读需 2 分钟
素明诚
Full stack development

命令 nvidia-smi 输出的信息

06e4d05b11403eb3a9f8943902ac0e8f### 表格标题和版本信息

NVIDIA-SMI:显示 nvidia-smi 工具的版本号

Driver Version:当前安装的 NVIDIA 驱动版本

CUDA Version:系统支持的 CUDA 版本,这对开发者来说很重要,因为它决定了可以使用的 CUDA 工具和功能

GPU 列表

对于每块 GPU,表格都会显示以下信息,从左到右介绍

GPU:GPU 的编号,从 0 开始

Name:GPU 的型号,例如“NVIDIA GeForce RTX 3090”

Persistence-M:持久性模式的开关状态,通常在服务器和需长时间运行的环境中启用

Bus-Id:GPU 在系统中的 PCI 总线 ID

Disp.A:显示活动状态,显示是否有显示器连接到这块 GPU

Volatile Uncorr. ECC:显示是否启用了易失性未校正的错误校正码(ECC),通常用于计算密集型任务的可靠性

性能指标

Fan:风扇速度的百分比

Temp:GPU 的当前温度

Perf:性能状态,从 P0(最高性能)到 P12(最低性能)

**Pwr/Cap:**当前功率使用量和功率上限

Memory-Usage:GPU 内存的使用情况,显示已使用和总计的内存(例如,“2MiB / 24576MiB”)

GPU-Util:GPU 利用率的百分比,显示 GPU 被使用的程度

Compute M.:计算模式,通常是“Default”或“Exclusive”,影响 GPU 的访问控制

MIG M.:如果启用了多实例 GPU(MIG),这里会显示状态

进程信息

这部分列出了当前在 GPU 上运行的所有进程

PID:进程 ID

Type:进程类型,通常是 C(计算)或 G(图形)

Process name:进程名称

GPU Memory Usage:该进程使用的 GPU 内存量

Go 创建 goroutine 的四种方式

· 阅读需 1 分钟
素明诚
Full stack development

直接启动匿名函数

这是创建 goroutine 最常见的方式使用 go 关键字后跟一个匿名函数调用,立即在新的 goroutine 上执行该函数

go func() {
fmt.Println("Running in a goroutine")
}()

启动一个已有函数

如果你已经有一个函数,你可以创建一个 goroutine 来运行这个函数这仍然使用 go 关键字,后面跟随函数名和参数

func printMessage(message string) {
fmt.Println(message)
}

go printMessage("Hello, goroutine!")

启动一个方法

如果你有一个对象的方法需要在 goroutine 中运行,也可以使用 go 关键字直接调用

type Greeter struct {
greeting string
}

func (g Greeter) greet() {
fmt.Println(g.greeting)
}

var greeter = Greeter{"Hello from a goroutine"}
go greeter.greet()

使用闭包调用

如果需要在 goroutine 中使用当前作用域内的变量,可以通过闭包来捕获这些变量

name := "Gopher"
go func(who string) {
fmt.Println("Hello,", who)
}(name)

Go 搭建并使用 goproxy 作为代理服务器

· 阅读需 1 分钟
素明诚
Full stack development

安装 goproxy

仓库地址:https://github.com/goproxyio/goproxy

services:
goproxy:
image: goproxy/goproxy:latest
command: "-listen=0.0.0.0:8081 -cacheDir=/ext"
ports:
- "8081:8081"
restart: always
environment:
- HTTP_PROXY=http://172.22.220.64:7890 # 代理地址
- HTTPS_PROXY=http://172.22.220.64:7890 # 这个得有,否则白玩
volumes:
- ./cacheDir:/ext

配置代理

如果要测试的话先清除缓存

go clean -modcache

设置为自己搭建的代理,我这里的测试环境的 windows。注意使用export是替换该环境变量之前的值,而不是添加新值到现有的列表中

export GOPROXY=http://172.22.220.64:8081

查看配置

go env GOPROXY

下载包

go get -v github.com/sirupsen/logrus

测试

36dd244a94607dce1a9e004e60e89a2e76da0346edcede665a737c847c6473a20cb74ada0bc74a2d10bd4d9941276636

成功~

使用场景

企业内部:企业可以搭建内部的 goproxy 服务器,用来提供企业内部使用的私有模块,同时也可以缓存公共模块,减少对外部网络的依赖。

开源社区:开源项目可以设置使用公共的 goproxy 服务,如 goproxy.cngoproxy.io,这些都是为了提供更快速的模块下载服务而设立的。

个人开发者:个人开发者也可以使用公共的或私有的 goproxy 实例来优化自己的开发流程,尤其是在网络连接不佳的情况下。

embed 包在 Go 使用场景

· 阅读需 1 分钟
素明诚
Full stack development

单页应用(SPA)

单页应用通常由 HTML、CSS 和 JavaScript 构成,这些静态文件可以被嵌入到 Go 服务器中,实现完全的后端前端集成。

import (
"embed"
"net/http"
)

//go:embed dist/*
var staticFiles embed.FS

func main() {
http.Handle("/", http.FileServer(http.FS(staticFiles)))
http.ListenAndServe(":8080", nil)
}

命令行工具的配置文件和资源

对于命令行工具,配置文件、模板或其他资源可以被嵌入到二进制文件中,简化用户的配置过程,用户无需手动设置或修改配置文件。

import (
"embed"
"log"
)

//go:embed config/default.yaml
var defaultConfig embed.FS

func loadConfig() {
data, err := defaultConfig.ReadFile("config/default.yaml")
if err != nil {
log.Fatalf("Error loading config: %v", err)
}
// 解析配置文件
parseConfig(data)
}

桌面应用的资源和多媒体内容

在桌面应用中,如图标、图像、音频和视频文件可以被嵌入到应用中,确保应用运行时所有资源都可用。

import "embed"

//go:embed assets/icons/*
var icons embed.FS

//go:embed assets/sounds/notification.wav
var soundNotification embed.FS

如何编写版本号语义化版本控制规范

· 阅读需 2 分钟
素明诚
Full stack development

版本号的构成

语义化版本号由三部分组成:主版本号、次版本号和补丁版本号,格式为 X.Y.Z。

主版本号(X):当你做出不兼容的 API 更改时递增这个版本号。不兼容的更改指的是,任何现有用户必须修改其代码才能继续运行的更改,例如重大的重构或功能移除。

次版本号(Y):当你添加了向后兼容的新功能时递增这个版本号。向后兼容意味着旧版本的用户可以安全升级,不会影响现有功能。

补丁版本号(Z):当你进行了向后兼容的问题修正时递增这个版本号。这通常包括对 bug 的修复或安全问题的修复,不改变软件的功能和 API。

版本号的递增规则

版本号需要按顺序递增。如果主版本号增加,次版本号和补丁版本号应重置为 0;如果次版本号增加,补丁版本号应重置为 0。

不必每个版本都发布,可以跳过某些数字,例如从 1.0.0 直接升级到 2.0.0,或者从 1.5.0-beta 直接升级到 1.5.0。

版本控制注意事项

正常版本号如v1.1.11.1.1更推荐使用前者

如果主版本号没有为 1,那说这个应用可能还没有发布稳定版本,需要注意

每次发布主版本的时候,一般都会提前发布一个beta版本,等beta版本稳定了再发布新版本

迭代版本的时候最好使用 CI/CD 工具来代替人为的设置,这样有记录而且更清晰

Go 的 GOPROXY 和 GONOPROXY 的配置和使用

· 阅读需 2 分钟
素明诚
Full stack development

GOPROXY 的使用

GOPROXY 环境变量用于指定 Go 模块代理服务器的 URL。Go 模块代理服务器是一种提供 Go 包及其依赖的中间服务器,可以加速包下载和确保包的可用性。您可以配置多个代理,使用逗号分隔。例如,如果第一个代理返回 404 或 410 错误,Go 工具链将自动尝试列表中的下一个代理。这种机制确保了即使某个代理服务不可用,模块获取操作也可以继续进行。

搭建自己的代理服务:https://zhuanlan.zhihu.com/p/706537626

默认的 GOPROXY 设置

默认情况下,GOPROXY 被设置为 https://proxy.golang.org,direct。这里的 direct 关键字告诉 Go 工具链

如果你的 GOPROXY 环境变量包含了 direct 关键词,并且列出的代理服务器(例如 proxy.golang.org)没有找到你需要的模块(如 github.com/sirupsen/logrus),那么 Go 工具链会尝试直接从模块的源地址,即 GitHub 上的 github.com/sirupsen/logrus 仓库,获取这个模块

配置直连模式

通过设置 GOPROXY=direct,开发者可以让所有的 go get 命令绕过代理,直接从源代码托管站点下载模块。这对于在公司内部网络环境中工作,且需要直接访问内部 Git 服务器(如 GitLab)上的私有模块时特别有用。

模块验证和 GONOSUMDB 配置

为了确保下载的模块未被篡改,Go 提供了模块校验和功能。GONOSUMDB 环境变量允许指定哪些模块不应进行校验和检查。例如,设置 GONOSUMDB=gitlab.mycorp.com 表明所有托管在 gitlab.mycorp.com 上的模块都不需要进行校验和验证。

配置 GOPRIVATE 和 GONOPROXY

GOPRIVATEGONOPROXY 环境变量用于定义不通过公共代理或不进行校验和验证的私有模块的模式。这些设置对于管理企业内部或敏感的私有模块非常有用,确保这些模块的使用不会被公开或误用。

Go 使用 Swagger

· 阅读需 2 分钟
素明诚
Full stack development

安装 Swagger

使用 Go 的包管理工具安装 swag 命令行工具,这个工具用于自动生成 Swagger 文档的相关文件。

go get -u github.com/swaggo/swag/cmd/swag

在 bin 目录安装

go install github.com/swaggo/swag/cmd/swag@latest

生成 Swagger 文档

在项目的根目录下运行 swag init 命令。这将会扫描你的 Go 源代码文件(通常是查找特定的注解格式),并在项目中生成一个 docs 文件夹,里面包含 swagger.jsonswagger.yamldocs.go

swag init

安装 Gin 与 Swagger 的集成库

需要安装 swaggo/gin-swaggerswaggo/files 包,用于在 Gin 应用程序中提供 Swagger UI。

go get -u github.com/swaggo/gin-swagger
go get -u github.com/swaggo/files

配置 Gin 路由以提供 Swagger UI

修改你的 Gin 应用程序代码,引入 Swagger 文档生成的包,并设置一个路由来提供 Swagger UI。

package main

import (
"github.com/gin-gonic/gin"
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
_ "your_project/docs" // 替换 your_project 为实际的项目名或路径 必须导入
)

func main() {
r := gin.Default()

// 设置 Swagger 的路由
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

// 运行 Gin
r.Run()
}

注解你的 API

在你的 API 控制器或处理器函数上添加必要的注解,以便 swag 能够识别并生成正确的 API 文档。

// @Summary 概述你的接口
// @Description 详细描述接口功能
// @Tags 使用适当的标签
// @Accept json
// @Produce json
// @Param name query string true "参数描述"
// @Success 200 {object} YourResponseStruct "成功返回的结构体描述"
// @Router /your_route [get]
func YourHandler(c *gin.Context) {
// 实现功能
}

重新生成文档并测试: 每次更新注解后,你需要重新运行 swag init 以更新 Swagger 文档。然后启动你的 Gin 应用程序,访问 Swagger UI 确认 API 文档是否正确。

4bab4dcdcd0c2d2c95b45cbd07d14fbb## 仓库地址
https://github.com/swaggo/swag

Go 语言的 go get 命令时禁用模块的哈希校验功能

· 阅读需 2 分钟
素明诚
Full stack development

GOSUMDB 环境变量

GOSUMDB 环境变量用于指定用于验证模块内容的 Go checksum database 的服务器。Go 模块系统使用这个数据库来确保模块内容的一致性和安全性,防止模块遭到篡改。

禁用哈希校验

设置 GOSUMDB=off,可以关闭对所有外部模块的校验和数据库查询。这意味着当你使用 go get 下载依赖时,Go 工具链不会尝试验证下载的模块是否与校验和数据库中记录的哈希值相匹配。

这种设置通常用于私有网络或者是对安全要求不高且需要提速的开发环境中。

设置方法

在命令行中设置 GOSUMDB=off 可以通过以下命令实现

go env -w GOSUMDB=off

这个命令会在当前用户的 Go 环境中永久设置 GOSUMDB 的值为 off

提示~

禁用模块哈希校验将降低项目安全性,因为你将无法验证模块的内容是否被篡改。只有在你完全信任你的模块来源,或在内部、隔离的开发环境中使用时,才推荐使用这种方法。

使用场景

在内部或私有的网络环境中,无法访问 Go 的官方 checksum database。

开发过程中需要频繁测试或更新依赖,且对安全性的即时验证要求较低。

JWT 签名和验证签名的过程

· 阅读需 3 分钟
素明诚
Full stack development

生成(签名)JWT

确定 Header:Header 通常包含两部分信息:使用的算法(比如 HS256 表示 HMAC SHA-256)和 Token 类型(通常是 JWT)。

{
"alg": "HS256",
"typ": "JWT"
}

构建 Payload:Payload 包含 claims,这些 claims 可以是注册的 claims、公共的 claims 或私有的 claims

{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}

签名:使用 Header 中指定的算法和一个密钥对 Header 和 Payload 进行签名。签名的目的是验证 Token 在传输过程中未被篡改。

例如,如果使用 HMAC SHA-256,签名过程将是

  HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)

组合 JWT:将编码后的 Header、Payload 和签名组合成一个 JWT。格式通常为header.payload.signature

JWT 验证过程

分解 JWT:首先,从 JWT 字符串中分离出 Base64 编码的 Header、Payload 和 Signature。JWT 通常形如header.payload.signature

Base64 解码:将编码的 Header 和 Payload 解码回它们原始的 JSON 格式的字符串。

重新生成签名:使用相同的算法(Header 中指定的,如 HMAC SHA-256)和secret对解码后的 Header 和 Payload 重新生成签名。具体步骤如下:

  1. 将解码后的 Header 和 Payload 重新转换成 Base64 编码的字符串。
  2. 将这两个 Base64 字符串用点.连接起来形成一个新的字符串。
  3. 使用secret作为密钥,对这个字符串进行 HMAC SHA-256 运算,生成新的签名。

比较签名:将重新生成的签名与 JWT 中原来包含的签名进行比较。如果两者相同,则认为 JWT 是有效的,没有被篡改,且是由掌握secret的实体发行的。

Secret 的作用

在这个验证过程中,secret起到的是保证签名真实性和数据未被篡改的关键角色:

  1. 签名的安全性:只有知道secret的实体才能正确生成和验证签名。这意味着即使有人截获了 JWT,但没有secret,他们也无法生成新的有效签名,从而无法伪造有效的 JWT。
  2. 数据的完整性:通过比较重新生成的签名和 JWT 中的签名,可以确认数据在传输过程中未被修改。因为任何对 Header 或 Payload 的改动都会导致新生成的签名与原签名不匹配。

检查 Claims:验证签名之后,还需要检查 Payload 中的 claims,如exp(过期时间)来确定 Token 的有效性。

注意

虽然 JWT 的 Header 和 Payload 是使用 Base64 编码的,这种编码是可逆的,因此任何人都可以看到内容。如果需要保密 Payload 中的数据,应考虑对 Payload 进行加密,这种情况下通常使用 JWE(JSON Web Encryption)。