Docker部署git-commit项目
上次说了本地如何运行gitCommit这个项目,现在我们准备将其使用部署到服务器上,部署方法为Docker容器部署。
对于docker,相当于是一个新的开发环境,所以你进行git操作一定要避免代码冲突,这里提出的一种解决方式是先add和commit自己本地的代码,然后再push远程分支到本地的另外一个分支,然后接着切换分支,然后进行ticker里面的循环操作
main文件修改
- 将项目路径修改为了 /app,即 projectPath = "/app" ,/app是Docker容器里面的的工作目录
移动到工作目录:/app
dockerfile
WORKDIR /app
- 在go代码里面获取了容器里面设置的环境变量,即GITHUB_PAT
go
githubPAT := os.Getenv("GITHUB_PAT")
mian.go
go
package main
import (
"fmt"
"log"
"math/rand"
"os"
"os/exec"
"path/filepath"
"time"
)
const (
projectPath = "/app" //把项目目录设置为容器的工作目录
fileName = "fish.txt"
message = "我没摸鱼"
prefix = "今天又摸鱼了鸭"
maxCommitsPerDay = 5 // 每天最大提交次数
startHour = 9 // 允许操作的开始小时(24小时制)
endHour = 24 // 允许操作的结束小时(24小时制)
)
func main() {
//首先得到正确的文件路径 用这个函数的好处是不用管操作系统的分隔符 管它是/还是\ go语言直接帮你解决
path := filepath.Join(projectPath, fileName)
//检测该文件是否存在
if ifExist := checkFileExist(path); ifExist == false {
if err := createFile(path); err != nil {
log.Printf("createFile(path) failed,err%v", err)
return
}
log.Println("createFile(path) success")
}
// 定时逻辑
var commitTimes = 0
now := getChineseTime()
today := now.Day()
//格式化时间
interval := getRandomInterval()
ticker := time.NewTicker(interval)
defer ticker.Stop()
//初始化仓库
if err := initAndRemoteAdd(projectPath); err != nil {
log.Printf("initAndRemoteAdd(projectPath) failed,err:%v", err)
return
}
//第一次获取最大push次数
maxCommitsPerDay := getRandomPushTimes()
//根据条件来判断 对文件的操作
for range ticker.C {
log.Printf("%d chances today", maxCommitsPerDay)
if err := modifyFile(path); err != nil {
log.Printf("modifyFile(fileName) failed,err:%v", err)
return
}
log.Println("modifyFile(fileName) success")
now = getChineseTime()
currentHour := now.Hour()
currentDay := now.Day()
// 如果跨越了一天,重置计数器和日期
if today != currentDay {
commitTimes = 0
today = currentDay
maxCommitsPerDay = getRandomPushTimes()
}
// 检查是否在允许的时间段内
if currentHour >= startHour && currentHour < endHour && commitTimes < maxCommitsPerDay {
//提交git 代码待补充
if err := commitChanges(projectPath, message, commitTimes); err != nil {
log.Printf("commitChanges(path,message) failed,err:%v", err)
return
}
// 提交后增加计数器
commitTimes++
}
// 更新间隔
interval = getRandomInterval()
ticker.Reset(interval)
}
}
// 检测文件是否存在
func checkFileExist(path string) bool {
_, err := os.Stat(path)
return !os.IsNotExist(err)
}
// 创建文件
func createFile(path string) error {
//先创建文件 没有文件会默认创建一个
fPointer, err := os.OpenFile(path, os.O_CREATE, 0644)
if err != nil {
log.Printf("create file failed,err:%v", err)
return err
}
defer fPointer.Close()
return err
}
// 修改文件
func modifyFile(path string) error {
content := fmt.Sprintf("%s %d", prefix, time.Now().UnixNano())
fPointer, err := os.OpenFile(path, os.O_TRUNC|os.O_WRONLY, 0666) // os.O_WRONLY 仅写权限 |os.O_TRUNC 清空
defer fPointer.Close()
if err != nil {
return err
}
_, err = fPointer.Write([]byte(content))
return err
}
// 初始化仓库
func initAndRemoteAdd(projectPath string) error {
//init
if err := gitCommand(projectPath, "init"); err != nil {
return err
}
//git add . --> 因为后续要切换分支 所以当前的分支必须add
if err := gitCommand(projectPath, "add", "."); err != nil {
return err
}
//git commit . --> 因为后续要切换分支 所以当前的分支必须commit
if err := gitCommand(projectPath, "commit", "-m", "commit本地分支"); err != nil {
return err
}
//remote add
githubPAT := os.Getenv("GITHUB_PAT") //这里是因为要使用docker 所以设置了这个
//拼接URL
remoteURL := fmt.Sprintf("https://%s@github.com/username/Script.git", githubPAT)
//这里可以不进行错误处理,一般报错就是已经有了这个远程仓库,但还是建议第一次写一下,后续改回来
_ = gitCommand(projectPath, "remote", "add", "origin", remoteURL)
//强行pull分支
_ = gitCommand(projectPath, "pull", "--force", "origin", "main:main")
//切换到main分支
_ = gitCommand(projectPath, "checkout", "main")
return nil
}
// push代码
func commitChanges(projectPath, message string, times int) error {
//add
if err := gitCommand(projectPath, "add", "."); err != nil {
return err
}
//commit
if err := gitCommand(projectPath, "commit", "-m", message); err != nil {
return err
}
//push
if err := gitCommand(projectPath, "push", "-u", "origin", "main:main"); err != nil {
return err
}
log.Println(fmt.Sprintf("push %d times today", times+1))
return nil
}
// 指令代码
func gitCommand(dir string, command ...string) (err error) {
cmd := exec.Command("git", command...)
cmd.Dir = dir
var commandSql string
for _, v := range command {
commandSql += v + " "
}
output, err := cmd.CombinedOutput()
if err != nil {
log.Println(commandSql + "failed")
log.Println("Command output:", string(output))
return err
}
log.Println(commandSql + "success")
return err
}
// 设置为中国时区
func getChineseTime() time.Time {
loc, _ := time.LoadLocation("Asia/Shanghai")
now := time.Now().In(loc)
return now
}
// 生成种子
func newSeed() *rand.Rand {
// 创建一个新的随机数生成器实例,为其设置种子
src := rand.NewSource(time.Now().UnixNano())
return rand.New(src)
}
// 得到随机时间间隔
func getRandomInterval() time.Duration {
// 将分钟数转换为字符串,格式为"Xm"
return time.Duration(newSeed().Intn(30)+150) * time.Minute
}
// 得到随机每天的push次数
func getRandomPushTimes() int {
return newSeed().Intn(maxCommitsPerDay + 1)
}
docker部分
值得关注的点
- 设置了环境变量
dockerfile
GITHUB_PAT=你自己的GitHub生成的token \
- 合并Run指令,以此来减少镜像构建层数
dockerfile
FROM golang:alpine AS builder
# 为我们的镜像设置必要的环境变量,并进行其他设置
ENV GO111MODULE=on \
CGO_ENABLED=0 \
GOOS=linux \
GOARCH=amd64 \
GITHUB_PAT=你自己的GitHub生成的token \
GOPROXY=https://goproxy.cn,direct
# 使用单个RUN命令执行多个命令以减少镜像层数
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && \
apk update && apk add --no-cache git && \
git config --global user.name "lzh" && \
git config --global user.email "2115883273@qq.com" && \
go env -w GO111MODULE=on && \
go env -w GOPROXY=https://goproxy.cn,direct
# 移动到工作目录:/app
WORKDIR /app
# 将代码复制到容器中
COPY . .
RUN go mod download
# 将我们的代码编译成二进制可执行文件 也可以在这里合并RUN指令,但是考虑到可读性和构建缓存的有效利用,通常保持这个步骤单独是有益的
RUN go build -o git_commit .
# 声明服务端口
EXPOSE 8080
# 需要运行的命令
ENTRYPOINT ["/app/git_commit"]
如何生成自己的GitHub token
右边选择Tokens(classic),简单起见就全部勾选选项。
然后生成就可以了。
然后会出现一个token,务必保存,因为只可以看见一次。
然后把Dockerfile里面的 GITHUB_PAT 替换成你的token就可以了
然后在项目目录下打开终端,依次运行
sh
docker build -t git_commit .
docker run -p 8888:8888 -d --name git_commit git_commit
# 容器的端口映射可以自行设置
这样项目就成功在本地用Docker部署了
如果要在服务器上部署,只需要在服务器上安装Docker即可,然后把本地文件传输过去,然后运行以上的两行命令,即可完成服务器的部署。
注意
上传文件时应当删除本地的.git文件(隐藏文件,要自行设置文件可见)
评论区
登录后才可以评论