2024-08-17



# 使用官方 Golang 镜像作为基础镜像
FROM golang:1.16-alpine
 
# 设置工作目录
WORKDIR /go/src/app
 
# 复制 go.mod 和 go.sum 文件,并下载依赖
COPY go.mod go.sum ./
RUN go mod download
 
# 复制项目源码
COPY . .
 
# 构建应用程序
RUN go build -o /usr/local/bin/myapp
 
# 容器运行时监听的端口
EXPOSE 8080
 
# 容器启动时运行应用程序
CMD ["/usr/local/bin/myapp"]

这个Dockerfile为创建Golang开发环境提供了一个基本的模板。它使用官方的Golang镜像,设置了工作目录,并且包含了从构建到运行应用程序所需的指令。这为开发者提供了一个简洁且可靠的起点,使他们能够快速开始开发并部署他们的Golang应用程序。

2024-08-17

限流算法有很多种,常见的有漏桶算法、令牌桶算法。以下是用Go实现的简单的令牌桶算法示例:




package main
 
import (
    "fmt"
    "sync"
    "time"
)
 
type TokenBucketLimiter struct {
    capacity int64 // 桶的容量
    rate     int64 // 填充速率
    tokens   int64 // 当前令牌数
    lastTime time.Time
    mu sync.Mutex
}
 
func NewTokenBucketLimiter(capacity int64, rate int64) *TokenBucketLimiter {
    return &TokenBucketLimiter{
        capacity: capacity,
        rate:     rate,
        tokens:   capacity,
        lastTime: time.Now(),
    }
}
 
func (l *TokenBucketLimiter) reserve() bool {
    l.mu.Lock()
    defer l.mu.Unlock()
 
    now := time.Now()
    l.tokens = min(l.capacity, l.tokens+l.rate*(now.Sub(l.lastTime).Seconds()))
    l.lastTime = now
 
    if l.tokens < 1 {
        return false
    }
 
    l.tokens--
    return true
}
 
func min(a, b int64) int64 {
    if a < b {
        return a
    }
    return b
}
 
func main() {
    limiter := NewTokenBucketLimiter(10, 1) // 桶容量为10,填充速率为每秒1个令牌
 
    for i := 0; i < 20; i++ {
        if limiter.reserve() {
            fmt.Println("Request allowed")
        } else {
            fmt.Println("Request rejected")
        }
        time.Sleep(500 * time.Millisecond)
    }
}

这段代码实现了一个简单的令牌桶限流器,其中NewTokenBucketLimiter函数创建了一个新的限流器,reserve方法用于尝试获取令牌以执行操作。如果没有足够的令牌,则返回false,表示请求被拒绝。实际应用中,需要考虑并发安全和性能优化。

2024-08-17



package main
 
import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
 
    "github.com/dgrijalva/jwt-go"
)
 
var jwtKey = []byte("your-256-bit-secret")
 
// UserClaims 定义了 JWT 的 payload
type UserClaims struct {
    Username string `json:"username"`
    jwt.StandardClaims
}
 
// loginHandler 处理登录请求
func loginHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodPost {
        http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
        return
    }
 
    // 假设这里从请求中获取用户名和密码进行验证,验证通过后生成 token
    username := "exampleUser"
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserClaims{
        Username: username,
        StandardClaims: jwt.StandardClaims{
            ExpiresAt: 15000, // 设置过期时间
        },
    })
 
    // 使用密钥签名 token
    tokenString, err := token.SignedString(jwtKey)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
 
    // 返回 token 给客户端
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(map[string]string{
        "token": tokenString,
    })
}
 
func main() {
    http.HandleFunc("/login", loginHandler)
 
    log.Println("服务器运行于: http://localhost:8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

这段代码实现了一个简单的登录接口,在用户登录成功后,生成了一个包含用户信息的 token,并返回给客户端。在实际应用中,你需要替换 jwtKey 的值,并且实现用户验证的逻辑。

2024-08-17



package main
 
import (
    "context"
    "fmt"
    "k8s.io/apimachinery/pkg/runtime"
    "k8s.io/client-go/kubernetes/scheme"
    "k8s.io/client-go/rest"
    "k8s.io/client-go/tools/remotecommand"
    "os"
    "path/filepath"
 
    // 导入客户端go相关的包
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
)
 
// 初始化k8s客户端
func initKubeClient() *kubernetes.Clientset {
    config, err := rest.InClusterConfig()
    if err != nil {
        panic(err.Error())
    }
    clientset := kubernetes.NewForConfigOrDie(config)
    return clientset
}
 
// 执行kubectl exec命令
func execCommand(client *kubernetes.Clientset, podName, containerName, namespace, command string) error {
    req := client.CoreV1().RESTClient().Post().
        Resource("pods").
        Name(podName).
        Namespace(namespace).
        SubResource("exec").
        Param("container", containerName)
    req.VersionedParams(&corev1.PodExecOptions{
        Command: []string{"sh", "-c", command},
        Stdin:   true,
        Stdout:  true,
        Stderr:  true,
        TTY:     true,
    }, scheme.ParameterCodec)
 
    exec, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL())
    if err != nil {
        return err
    }
    err = exec.Stream(remotecommand.StreamOptions{
        Stdin:  os.Stdin,
        Stdout: os.Stdout,
        Stderr: os.Stderr,
        Tty:    true,
    })
    return err
}
 
func main() {
    // 获取Pod名称
    podName := "my-pod"
    // 获取容器名称
    containerName := "my-container"
    // 获取命名空间
    namespace := "default"
    // 获取要执行的命令
    command := "ls -l"
 
    client := initKubeClient()
    err := execCommand(client, podName, containerName, namespace, command)
    if err != nil {
        panic(err.Error())
    }
}

这段代码展示了如何使用client-go包在Go语言中初始化Kubernetes客户端,并执行一个简单的kubectl exec命令。这对于理解如何在Go语言中与Kubernetes集群交互是非常有用的。

2024-08-17



package main
 
import (
    "fmt"
    "github.com/go-redis/redis/v8"
    "context"
)
 
var ctx = context.Background()
 
func main() {
    // 创建Redis客户端实例,指定连接选项
    rdb := redis.NewClient(&redis.Options{
        Addr:     "localhost:6379", // Redis服务器的地址
        Password: "",               // 密码,没有则留空
        DB:       0,                // 使用默认DB
    })
 
    // 使用客户端执行Redis命令
    val, err := rdb.Get(ctx, "key").Result()
    if err == redis.Nil {
        fmt.Println("key does not exist")
    } else if err != nil {
        panic(err)
    } else {
        fmt.Println("key", val)
    }
 
    // 关闭客户端连接,释放资源
    if err := rdb.Close(); err != nil {
        panic(err)
    }
}

这段代码展示了如何在Go语言中使用go-redis库创建Redis客户端实例,并执行基本的GET命令。同时,它还演示了如何正确地关闭客户端连接,以防止资源泄露。这是一个典型的Redis客户端使用场景,对开发者有很好的教育意义。

2024-08-17



package main
 
import (
    "context"
    "fmt"
    "github.com/go-redsync/redsync"
    "github.com/go-redsync/redsync/redis/goredis"
    "github.com/go-redsync/redsync/strategy"
    "github.com/gomodule/redigo/redis"
    "time"
)
 
// 初始化Redisson分布式锁客户端
func NewRedissonClient(addr string) *redsync.Mutex {
    pool := &redis.Pool{
        MaxIdle:     3,
        MaxActive:   10,
        IdleTimeout: 240 * time.Second,
        Dial: func() (redis.Conn, error) {
            return redis.Dial("tcp", addr, redis.DialDatabase(0), redis.DialPassword(""))
        },
    }
    go func() {
        for {
            conn := pool.Get()
            _, err := conn.Do("PING")
            if err != nil {
                fmt.Println("Redis连接失败:", err)
            }
            conn.Close()
            time.Sleep(10 * time.Second)
        }
    }()
 
    return redsync.New(goredis.NewPool(pool))
}
 
func main() {
    // 假设Redis服务器地址
    redisServerAddr := "127.0.0.1:6379"
    // 创建Redisson客户端
    redisson := NewRedissonClient(redisServerAddr)
    // 锁的键值
    lockKey := "my_lock"
    // 锁的超时时间
    expiration := 10 * time.Second
    // 等待锁的最长时间
    waitTime := 30 * time.Second
    // 尝试获取锁
    ctx, _ := context.WithTimeout(context.Background(), waitTime)
    lock, err := redisson.Lock(lockKey, strategy.WithExpiration(expiration))
    if err != nil {
        fmt.Println("获取锁失败:", err)
        return
    }
    // 使用defer语句确保释放锁
    defer func() {
        if err := lock.Unlock(ctx); err != nil {
            fmt.Println("释放锁失败:", err)
        }
    }()
 
    // 在获取锁之后执行的业务逻辑代码
    fmt.Println("已获取锁,执行业务逻辑...")
    // ... 业务逻辑代码 ...
}

这段代码展示了如何使用Go语言和Redisson库来实现分布式锁。首先,它创建了一个连接到Redis服务器的Redisson客户端。然后,它定义了一个获取锁并在使用完毕后释放锁的过程,确保了即使在发生错误的情况下锁也能被释放。这是一个分布式系统中避免竞争条件和数据不一致的有效方法。

2024-08-17

在ARM架构的CentOS系统上部署Golang、Prometheus的步骤如下:

  1. 安装Go环境:



wget https://go.dev/dl/go1.18.1.linux-arm64.tar.gz
sudo tar -C /usr/local -xzf go1.18.1.linux-arm64.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
source ~/.bashrc
  1. 创建Prometheus用户:



sudo adduser prometheus
  1. 安装Prometheus:



sudo prometheus --version

如果Prometheus已经提供了预编译的二进制包,可以直接下载使用。如果没有,你需要从源码编译Prometheus。

  1. 编译Prometheus(如果需要):



go get github.com/prometheus/prometheus
cd $GOPATH/src/github.com/prometheus/prometheus
make build
sudo cp prometheus /usr/local/bin/
  1. 配置Prometheus服务:

    创建Prometheus配置文件prometheus.yml,并根据需要进行配置。

  2. 运行Prometheus服务:



prometheus --config.file=/path/to/your/prometheus.yml
  1. 配置系统服务(可选):

    创建一个systemd服务文件/etc/systemd/system/prometheus.service,内容如下:




[Unit]
Description=Prometheus Monitoring System
Documentation=https://prometheus.io/docs/introduction/overview/
After=network.target
 
[Service]
User=prometheus
Type=simple
ExecStart=/usr/local/bin/prometheus \
    --config.file=/path/to/your/prometheus.yml \
    --web.listen-address=:9090
 
[Install]
WantedBy=multi-user.target

启动并使Prometheus服务随系统启动:




sudo systemctl daemon-reload
sudo systemctl enable prometheus
sudo systemctl start prometheus

以上步骤提供了一个基本的指南来在ARM架构的CentOS上部署Golang和Prometheus。具体细节(如Go版本、Prometheus配置和systemd服务文件路径)可能需要根据实际情况进行调整。

2024-08-17



package main
 
import (
    "bytes"
    "encoding/gob"
    "fmt"
    "log"
)
 
// 定义一个示例数据结构
type ExampleData struct {
    IntVal int
    StrVal string
}
 
func main() {
    // 创建一个编码器和解码器对象
    var network bytes.Buffer // 用于序列化和反序列化的缓冲区
    enc := gob.NewEncoder(&network) // 创建编码器
    dec := gob.NewDecoder(&network) // 创建解码器
 
    // 创建一个ExampleData实例
    example := ExampleData{IntVal: 10, StrVal: "示例字符串"}
 
    // 使用编码器将数据序列化到缓冲区
    if err := enc.Encode(example); err != nil {
        log.Fatal(err)
    }
 
    // 清空缓冲区中的数据以准备反序列化
    network.Reset()
 
    // 使用解码器从缓冲区中反序列化数据
    var decoded ExampleData
    if err := dec.Decode(&decoded); err != nil {
        log.Fatal(err)
    }
 
    // 输出反序列化后的数据
    fmt.Printf("反序列化后的数据: %+v\n", decoded)
}

这段代码首先定义了一个名为ExampleData的数据结构,然后创建了一个bytes.Buffer实例来作为序列化和反序列化的缓冲区。接着,使用gob.NewEncodergob.NewDecoder函数创建了编码器和解码器。最后,使用编码器将ExampleData实例序列化,并使用解码器将其反序列化,并打印出反序列化后的数据。这个过程展示了encoding/gob包的基本用法,并且是学习Go语言数据序列化的一个很好的起点。

2024-08-17



package main
 
import (
    "fmt"
    "github.com/Telmate/proxmox-api-go/proxmox"
    "log"
)
 
func main() {
    // 创建Proxmox API客户端实例
    client := proxmox.New("https://your.proxmox-server.com", "username@pam", "password")
 
    // 获取Proxmox节点列表
    nodes, err := client.Nodes.Get()
    if err != nil {
        log.Fatalf("获取节点列表失败: %s", err)
    }
 
    // 打印每个节点的名称
    for _, node := range nodes {
        fmt.Printf("节点名称: %s\n", node.Node)
    }
}

这段代码演示了如何使用proxmox-api-go包创建Proxmox API客户端,并获取Proxmox服务器上的节点列表。代码简洁,并在注释中包含了必要的解释。

2024-08-17

JWT(JSON Web Tokens)是一种用于双方之间传递安全信息的简洁的、URL安全的表示方法。它可以在网络应用环境中进行信息交换,并且可以进行签名,为所交换信息提供一种校验方式。

在Go中实现JWT,你可以使用github.com/dgrijalva/jwt-go包。以下是一个创建和验证JWT的简单例子:

首先,通过运行以下命令来安装jwt-go包:




go get github.com/dgrijalva/jwt-go

然后,你可以使用以下代码创建和验证JWT:




package main
 
import (
    "fmt"
    "time"
 
    jwt "github.com/dgrijalva/jwt-go"
)
 
var jwtKey = []byte("your_secret_key")
 
// 创建JWT
func createJWT(username string, expireTime time.Duration) (string, error) {
    token := jwt.New(jwt.SigningMethodHS256)
 
    claims := token.Claims.(jwt.MapClaims)
    claims["username"] = username
    claims["iss"] = "issuer"
    claims["exp"] = time.Now().Add(expireTime).Unix()
 
    tokenString, err := token.SignedString(jwtKey)
    if err != nil {
        return "", err
    }
 
    return tokenString, nil
}
 
// 验证JWT
func validateJWT(tokenString string) (*jwt.Token, error) {
    return jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
        // 确保token使用的算法是我们认为安全的
        if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
            return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
        }
        return jwtKey, nil
    })
}
 
func main() {
    // 创建JWT
    tokenString, err := createJWT("user1", time.Hour)
    if err != nil {
        fmt.Printf("Error creating JWT: %v\n", err)
        return
    }
    fmt.Printf("JWT: %s\n", tokenString)
 
    // 验证JWT
    token, err := validateJWT(tokenString)
    if err != nil {
        fmt.Printf("Error validating JWT: %v\n", err)
        return
    }
 
    claims, ok := token.Claims.(jwt.MapClaims)
    if ok && token.Valid {
        fmt.Printf("JWT is valid. Claims: %+v\n", claims)
    } else {
        fmt.Println("JWT is invalid.")
    }
}

在这个例子中,createJWT函数创建了一个新的JWT,并且设置了用户名和过期时间。validateJWT函数验证了JWT的签名和过期时间。在实际应用中,你需要根据自己的需求来定制这些功能。