使用 Golang 在 GitLab 上拉取代码并将静态资源部署到 Nginx,同时将图库上传至阿里云 OSS
本文章采用几个任务执行
最终想要实现效果,
1、golang做成一个服务占用一个端口,然后监测gitlab仓库webhook
2、前端人员提交代码到gitlab,golang触发去拉取代码,放到本地指定目录
3、go判断目录进行区分,静态资源,跟图库
4、静态资源上传到远程服务器html目录下
5、图库资源上传到阿里云OSS里面
6、刷新一下CDN缓存
目前没有服务化,尝试监听gitlab的webhook,但是推送代码,golang没有触发,目前还在解决中。。。。。
以下是源代码
任务一拉取代码
代码如下
//这个是需要手动执行,没有做成服务
package main
import (
"fmt"
"os"
"os/exec"
"strings"
)
func main() {
// 判断当前环境是否有 Git
//if _, err := exec.LookPath("git"); err != nil {
// fmt.Println("当前没有Git环境,建议你安装一下Git环境")
// return
//}
// 执行 git clone 命令克隆代码仓库,并输入账户密码
fmt.Println("开始执行 git clone 命令...")
cmd1 := exec.Command("git", "clone", "-b", "oss", "xxxxx", "D:/impromptu")
cmd1.Stdin = os.Stdin
cmd1.Stdout = os.Stdout
cmd1.Stderr = os.Stderr
cmd1.Env = append(cmd1.Env, "GIT_TERMINAL_PROMPT=1")
cmd1.Env = append(cmd1.Env, "GIT_ASKPASS=")
cmd1.Run()
fmt.Println("oss代码已经拉取下来,存放在本地:D:/impromptu")
//执行上传文件到linux静态资源文件
fmt.Println("开始上传文件到 Linux服务器...")
cmd := exec.Command("E:/go/goproject/src/go_code/project01/upload.exe")
out1, err := cmd.Output()
if err != nil {
fmt.Println(err)
return
}
if strings.Contains(string(out1), "successfully") {
fmt.Println("上传文到服务器 执行成功,请到浏览器刷新查看是否更新")
} else {
fmt.Println("你的文件上传到服务器失败,请查看问题!")
}
//执行 上传文件到oss Go 文件
fmt.Println("开始上传文件到 OSS...")
cmd2 := exec.Command("E:/go/goproject/src/go_code/golang01/oss.exe")
out, err := cmd2.Output()
if err != nil {
fmt.Println(err)
return
}
if strings.Contains(string(out), "successfully") {
fmt.Println("上传oss文件执行成功,请到oss查看文件是否存在")
} else {
fmt.Println("你的oss上传文件失败,请查看问题!")
}
// 执行刷新cdn缓存 Go 文件
fmt.Println("执行刷新cdn缓存 Go 文件...")
cmd3 := exec.Command("E:/go/goproject/src/go_code/golang02/cdn.exe")
out2, err := cmd3.Output()
if err != nil {
fmt.Println(err)
return
}
if strings.Contains(string(out2), "successfully") {
fmt.Println("刷新cdn缓存文件执行成功,请到CDN查看操作记录")
} else {
fmt.Println("你的刷新cdn缓存失败,请查看问题!")
}
}
执行结果
查看有没有拉取代码下来
任务二上传静态文件到服务器
package main
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
)
func main() {
// 获取远程服务器地址和 port
host := "xxx"
port := "xxxx"
// 获取远程服务器用户名和登录密码
user := "root"
password := "xxxx"
// 获取本地文件路径和文件名
localPath := "D:\\impromptu\\web" // 本地文件夹路径
// 获取远程服务器目标路径
remotePath := "/front/nginx/html/test/web" // 远程目录路径
// 建立 SSH 连接
config := &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{
ssh.Password(password),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
conn, err := ssh.Dial("tcp", host+":"+port, config)
if err != nil {
fmt.Printf("无法连接到远程服务器:%s\n", err.Error())
os.Exit(1)
}
defer conn.Close()
// 建立 SFTP 客户端
client, err := sftp.NewClient(conn)
if err != nil {
fmt.Printf("创建 SFTP 客户端失败:%s\n", err.Error())
os.Exit(1)
}
defer client.Close()
// 遍历本地目录中的文件,并上传到远程服务器
err = filepath.Walk(localPath, func(filePath string, info os.FileInfo, err error) error {
if err != nil {
fmt.Printf("遍历本地目录失败:%s\n", err.Error())
return err
}
// 判断是否是目录,如果是则创建远程目录
if info.IsDir() {
// 获取相对路径,并拼接到远程目录路径上
relativePath := strings.TrimPrefix(filePath, localPath)
remoteDir := filepath.ToSlash(filepath.Join(remotePath, relativePath))
err = client.MkdirAll(remoteDir)
if err != nil {
fmt.Printf("创建远程目录失败:%s\n", err.Error())
return err
}
fmt.Printf("已在远程服务器上创建目录:%s\n", remoteDir)
} else {
// 读取文件内容并上传到远程服务器
fileBytes, err := ioutil.ReadFile(filePath)
if err != nil {
fmt.Printf("读取本地文件失败:%s\n", err.Error())
return err
}
// 获取文件名,并拼接到远程目录路径上
fileName := info.Name()
remoteFile := filepath.ToSlash(filepath.Join(remotePath, fileName))
remoteWriter, err := client.Create(remoteFile)
if err != nil {
fmt.Printf("在远程服务器上创建文件失败:%s\n", err.Error())
return err
}
_, err = remoteWriter.Write(fileBytes)
if err != nil {
fmt.Printf("向远程服务器写入文件内容失败:%s\n", err.Error())
return err
}
fmt.Printf("已将本地文件 %s 上传到远程服务器:%s\n", filePath, remoteFile)
}
return nil
})
if err != nil {
fmt.Printf("上传文件失败:%s\n", err.Error())
os.Exit(1)
}
fmt.Println("文件上传完成!successfully.")
}
执行结果
查看服务器上面有没有资源
任务三上-图库到阿里云OSS
// 这个是分资源上传到oss
package main
import (
"fmt"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"io/ioutil"
"os"
"path/filepath"
"strings"
)
func main() {
// 阿里云OSS相关配置信息
endpoint := "xxxxx"
accessKeyId := "xxxx"
accessKeySecret := "xxxx"
bucketName := "oss-cicd"
// 创建阿里云OSS客户端
client, err := oss.New(endpoint, accessKeyId, accessKeySecret)
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 获取要操作的Bucket
bucket, err := client.Bucket(bucketName)
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 定义本地目录和OSS目录
localDir := "D:/impromptu/oss/"
ossDir := "oss/"
// 递归遍历本地目录下所有文件和子目录
err = filepath.Walk(localDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// 如果是子目录,则在OSS上创建同名目录
if info.IsDir() {
dirName := strings.TrimPrefix(strings.ReplaceAll(path, "\\", "/"), localDir)
if dirName == "" {
return nil
}
ossPath := filepath.ToSlash(filepath.Join(ossDir, dirName)) + "/"
fmt.Printf("Creating OSS directory %s\n", ossPath)
err = bucket.PutObject(ossPath, strings.NewReader(""))
if err != nil {
return err
}
} else {
// 如果是文件,则上传到OSS中对应的目录
fileName := strings.TrimPrefix(strings.ReplaceAll(path, "\\", "/"), localDir)
ossPath := filepath.ToSlash(filepath.Join(ossDir, fileName))
fmt.Printf("Uploading file %s to OSS path %s\n", path, ossPath)
// 读取本地文件内容
content, err := ioutil.ReadFile(path)
if err != nil {
return err
}
// 上传文件到OSS
err = bucket.PutObject(ossPath, strings.NewReader(string(content)))
if err != nil {
return err
}
}
return nil
})
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
fmt.Println("All objects uploaded successfully.")
}
执行结果
查看阿里云OSS
任务四-刷新阿里云CDN
这一步如果你们没有CDN可以忽略,我们有配置cdn内容分发网络,每次更新都需要刷新一下缓存
// This file is auto-generated, don't edit it. Thanks.
package main
import (
"fmt"
cdn "github.com/alibabacloud-go/cdn-20180510/v2/client"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
util "github.com/alibabacloud-go/tea-utils/v2/service"
"github.com/alibabacloud-go/tea/tea"
)
/**
* 使用AK&SK初始化账号Client
* @param accessKeyId
* @param accessKeySecret
* @return Client
* @throws Exception
*/
func CreateClient(accessKeyId *string, accessKeySecret *string) (_result *cdn.Client, _err error) {
config := &openapi.Config{
// 必填,您的 AccessKey ID
AccessKeyId: accessKeyId,
// 必填,您的 AccessKey Secret
AccessKeySecret: accessKeySecret,
}
// 访问的域名
config.Endpoint = tea.String("cdn.aliyuncs.com")
_result = &cdn.Client{}
_result, _err = cdn.NewClient(config)
return _result, _err
}
func _main() (_err error) {
// 请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID 和 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
// 工程代码泄露可能会导致 AccessKey 泄露,并威胁账号下所有资源的安全性。以下代码示例使用环境变量获取 AccessKey 的方式进行调用,仅供参考,建议使用更安全的 STS 方式,更多鉴权访问方式请参见:https://help.aliyun.com/document_detail/378661.html
client, _err := CreateClient(tea.String("xxxx"), tea.String("xxxx"))
if _err != nil {
return _err
}
refreshObjectCachesRequest := &cdn.RefreshObjectCachesRequest{
ObjectPath: tea.String("https://xxxx.com/"),
ObjectType: tea.String("Directory"),
}
runtime := &util.RuntimeOptions{}
tryErr := func() (_e error) {
defer func() {
if r := tea.Recover(recover()); r != nil {
_e = r
}
}()
// 复制代码运行请自行打印 API 的返回值
_, _err = client.RefreshObjectCachesWithOptions(refreshObjectCachesRequest, runtime)
if _err != nil {
return _err
}
return nil
}()
if tryErr != nil {
var error = &tea.SDKError{}
if _t, ok := tryErr.(*tea.SDKError); ok {
error = _t
} else {
error.Message = tea.String(tryErr.Error())
}
// 如有需要,请打印 error
_, _err = util.AssertAsString(error.Message)
fmt.Println(_err)
if _err != nil {
return _err
}
}
return _err
}
func main() {
err := _main()
if err != nil {
panic(err)
}
fmt.Println("完成刷新CDN缓存 successfully.")
}
ea.SDKError{}
if _t, ok := tryErr.(*tea.SDKError); ok {
error = _t
} else {
error.Message = tea.String(tryErr.Error())
}
// 如有需要,请打印 error
_, _err = util.AssertAsString(error.Message)
fmt.Println(_err)
if _err != nil {
return _err
}
}
return _err
}
func main() {
err := _main()
if err != nil {
panic(err)
}
fmt.Println(“完成刷新CDN缓存 successfully.”)
}