使用 Golang 在 GitLab 上拉取代码并将静态资源部署到 Nginx,同时将图库上传至阿里云 OSS

news2024/11/15 19:29:17

使用 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缓存失败,请查看问题!")
	}
}

执行结果

image-20230608143534636

查看有没有拉取代码下来

image-20230608143617585

任务二上传静态文件到服务器

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.")
}

执行结果

image-20230608143805708

查看服务器上面有没有资源

image-20230608143841662

任务三上-图库到阿里云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.")
}

执行结果

image-20230608144043405

查看阿里云OSS
image-20230608144119259

任务四-刷新阿里云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.”)
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/623815.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5.3图的综合应用算法

一.最小生成树算法 1.概念(Minimum-Spanning-Tree)MST 生成树:针对于连通图,包含全部顶点,去掉一条边后不连通,加一条边形成环 最小生成树:带权连通无向图,边的权值之和最小的生成树(MST) 2.…

insightface 人脸检测与识别

参考:https://huaweicloud.csdn.net/638088d7dacf622b8df89c0c.html insightface模型下载可能需要连接外网,模型自动下载保存再models\buffalo_l下,人脸注册自动保存再face_db目录下 1、具体人脸录入 python face_label.py --picture 刘亦…

GD32E230F4使用硬件IIC+DMA读写24C04

前言 在很久很久以前,我就写过GD32E230替换STM32F031的帖子,主要介绍了USART和SPI的外设移植开发,当时IIC使用的是软件i2c,没有介绍的价值。在使用IIC时,大多数我们都是采用软件的方式,因为软件的方式及其…

护网是什么?怎么参加

一、什么是护网行动? 护网行动是以公安部牵头的,用以评估企事业单位的网络安全的活动。 具体实践中。公安部会组织攻防两方,进攻方会在一个月内对防守方发动网络攻击,检测出防守方(企事业单位)存在的安全…

对象进阶、原型-原型链

工厂方法创建对象 我们之前已经学习了如何创建一个对象,那我们要是想要创建多个对象又该怎么办?聪明的同学可能会说,直接在写几个对象不就好了吗?比如下边的代码: var person1 {name: "孙悟空",age: 18,s…

2核2G3M轻量服务器腾讯云和阿里云怎么选择?

2核2G3M轻量应用服务器选阿里云还是腾讯云?腾讯云2核2G3M轻量应用服务器95元一年,阿里云2核2G3M配置优惠价108元一年,如何选择?阿腾云详细对比阿里云和腾讯云轻量应用服务器2核2G3M配置CPU性能及选择方法: 目录 轻量…

基于STM32F103+思岚A1激光雷达的扫描仪

前言 一个朋友在做服务机器人项目,用到思岚的激光雷达,于是便把淘汰的A1M8雷达送我一个,本着拿到啥就玩啥的态度,必须整一波。其实激光雷达还是搭配ROS才能发挥最大的作用,奈何资源有限,实力不足&#xff…

STM32 USB CDC VPC

STM32 USB CDC VPC 关键字 STM32,STM32CubeMX,HAL库,USB,虚拟串口,串口不定长接收 1.简介 通过使用stm32cubemx,实现USB CDC虚拟串口,并与硬件串口进行数据传输,实现了硬件串口数据的不定长接收,以及USB虚拟串口超过64字节的数…

钉钉H5微应用基础学习

钉钉开发文档 一、使用调试工具——IDE: 1、先下载调试工具,并且新建一个企业内部应用。 如果需要管理员权限,可以自己创建一个企业。 (tips:一定要屏蔽自己创建的企业的消息,不然消息很多) 2…

Burpsuite超详细安装教程

概述 Burp Suite 是用于攻击web 应用程序的集成平台,包含了许多工具。Burp Suite为这些工具设计了许多接口,以加快攻击应用程序的过程。所有工具都共享一个请求,并能处理对应的HTTP 消息、持久性、认证、代理、日志、警报。 接下来我来给大…

Linux4.8Nginx Rewrite

文章目录 计算机系统5G云计算第六章 LINUX Nginx Rewrite一、Nginx Rewrite 概述1.常用的Nginx 正则表达式2.rewrite和location3.location4.实际网站使用中,至少有三个匹配规则定义5.rewrite6.rewrite 示例 计算机系统 5G云计算 第六章 LINUX Nginx Rewrite 一、…

看完一位毕业的拼多多“P9”级别员工以及他的四页半简历,我悟了

前几天在脉脉上看到一个热帖,是刚从PDD毕业的P9级别员工吴可发的,同时附上了他的简历,这个简历很有意思,基本上和国内互联网这十多年来的发展步骤重叠,能够反映出,在这样一个跌宕起伏的时代里,个…

一次有关 DNS 解析导致 APP 慢的问题探究

一、业务背景 HTTTPDNS AWS Router53 APP 使用 HTTPDNS, 为解决 DNS 解析生效慢, DNS 劫持等问题。 我们 IOS 和安卓都是使用了 HTTPDNS。 域名托管在 AWS Router53。 域名有多个解析(基于延迟),为了解决就近接入。 示例配置 ai.baidu.c…

网易Java后端面经(一面)

这是网易的Java一面,问的都很基础。 1.session过期怎么处理? session过期通常指用户在一段时间内没有进行任何操作而导致session失效。针对这种情况,可以采取以下措施: 1. 前端提示用户session即将过期,提醒其重新登录…

JavaScript对象的增强知识

Object.defineProperty ◼ 在前面我们的属性都是直接定义在对象内部,或者直接添加到对象内部的:  但是这样来做的时候我们就不能对这个属性进行一些限制:比如这个属性是否是可以通过delete删除的?这个属性是否在for-in遍历的时候…

微信能取代对讲机吗?区别在哪?

对讲机和微信的区别在哪?为什么大家在通讯方面选择对讲机而不是微信? 微信作为社交软件在多个领域都有着广泛的应用,不过在对讲机行业也在讨论一个话题:微信能否取代对讲机?下面河南宝蓝小编就和大家聊聊这个话题。 …

基于redis实现秒杀并防止超卖

基于redis实现秒杀并防止超卖 为什么基于redis针对秒杀商品库存为一个的情况setnx代码实现测试 针对有多个库存的商品实现测试 为什么基于redis 因为所有redis的操作(这里指的是key的操作,像备份落盘之类的另算)都是单线程的,所以…

一文读懂:LoRA实现大模型LLM微调

LoRA大模型LLM微调 为什么要进行微调?LoRA思路提高权重更新效率选择低的秩 实现LoRALoRA在LLaMA实现 为什么要进行微调? 在快速发展的人工智能领域中,以高效和有效的方式使用大型语言模型变得越来越重要。 预训练的大型语言模型通常被称为优…

02-启动 Vue 项目

一. 学习目标 掌握 Vue 项目的启动 二. 学习内容 掌握 Vue 项目的启动 三. 学习过程 项目的启动也有两种方式,一种是通过图形界面启动,另一种是通过命令行启动。 1.图形界面 打开vscode编辑器,点击 1.文件 ——>打开文件夹&#xff0c…