美文网首页
go程序基于阿里云CodePipeline的一次devops实践

go程序基于阿里云CodePipeline的一次devops实践

作者: 朗月清风hyj | 来源:发表于2019-05-30 01:51 被阅读0次

    背景

    最近朋友有个项目代码托管用的码云,测试服务器(阿里云ECS)只有一台,三四个人开发,于是想基于阿里云的CodePipeline快速打造一套自动化cicd的流程,使用docker来进行多套环境部署。

    CodePipeline 介绍

    阿里云CodePipeline是兼容Jenkins标准的、提供快速可靠的持续集成与持续交付服务。基于容器技术和阿里云基础服务架构,提供稳定和安全的代码/Docker编译构建,测试,扫描和部署的工具服务,并提供Pipeline As Code的编码级配置模式,满足应用程序和基础设施快速可靠的交付和更新。

    在这里插入图片描述

    上面是阿里云的官方介绍,兼容jekins的标准,一次无意的点击出现了下图的图标,感觉就是jenkins的基础上做了一次二次开发。


    在这里插入图片描述

    新建构建项目

    在这里插入图片描述

    构建项目基本配置

    基本信息配置

    在这里插入图片描述

    由于项目使用到了一些国外的lib,当然选择国内的节点也是可以的,不过在写Dockerfile的时候记得加上代理。

    源码管理配置

    在这里插入图片描述

    选择合适的代码仓库,也可以是私仓,不过需要配上自己的账号和ssh key相关信息。

    构建配置

    在这里插入图片描述

    我这里使用的是阿里云的私有的镜像仓库基于Dockerfile来构建镜像,注意配置凭证。


    在这里插入图片描述
    项目目录
    gin_demo
    ├── app
    │   └── app.go
    ├── conf
    │   └── app.ini
    ├── Dockerfile
    ├── docs
    │   └── sql
    │       └── mjs.sql
    ├── go.mod
    ├── go.sum
    ├── main.go
    ├── middleware
    │   ├── jwt
    │   │   └── jwt.go
    │   └── logging
    │       └── logger.go
    ├── mjs.exe
    ├── models
    │   ├── mongo
    │   │   └── db.go
    │   └── mysql
    │       ├── db.go
    │       ├── teacher.go
    │       └── user.go
    ├── pkg
    │   ├── app
    │   │   ├── form.go
    │   │   ├── request.go
    │   │   └── response.go
    │   ├── def
    │   │   └── def.go
    │   ├── e
    │   │   ├── code.go
    │   │   ├── def.go
    │   │   └── msg.go
    │   ├── file
    │   │   └── file.go
    │   ├── gredis
    │   │   └── redis.go
    │   ├── logging
    │   │   ├── file.go
    │   │   └── log.go
    │   ├── setting
    │   │   └── setting.go
    │   ├── upload
    │   │   └── image.go
    │   └── util
    │       ├── jwt.go
    │       ├── md5.go
    │       ├── pagination.go
    │       └── util.go
    ├── README.en.md
    ├── README.md
    ├── routers
    │   ├── api
    │   │   └── v1
    │   └── router.go
    ├── runtime
    │   └── logs
    │       ├── log20190528.log
    │       └── log20190529.log
    └── service
        ├── teacher_service
        │   └── teacher.go
        └── user_service
            └── user.go
    
    
    Dockerfile
    FROM golang:1.12.4 as build
    
    #ENV GOPROXY https://goproxy.io 
    
    WORKDIR /go/cache
    
    ADD go.mod .
    ADD go.sum .
    RUN go mod download
    
    WORKDIR /go/release
    
    ADD . .
    
    RUN GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -installsuffix cgo -o gin_demo main.go
    
    FROM scratch as prod
    
    COPY --from=build /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    COPY --from=build /go/release/gin_demo /
    COPY --from=build /go/release/conf ./conf
    CMD ["/gin_demo"]
    

    注:如果选择国内节点构建必须配上代理 ENV GOPROXY https://goproxy.io

    配置触发器

    在这里插入图片描述

    这里选择一个构建的代码分支,然后点击生成,将生成后的url可以在对应的代码仓库配上webhook之类的配置。选择合适的触发方式。


    在这里插入图片描述

    配置部署

    在这里插入图片描述

    阿里云构建步骤里面部署到ECS上(不方便)和部署到k8s(收费)都不能满足项目场景需求,不过上面支持shell脚本,于是自己想在朋友的那台阿里云ECS上跑个ci的web server,这里构建完之后就去通知下这个接口,然后去执行一些docker指令的脚本,拉取构建完之后的镜像并且重新启动,启动完之后邮件通知。于是写了这样一个很简单的web server。
    main

    package main
    
    import (
        "fmt"
        "log"
        "net/http"
        "os/exec"
        "path"
    )
    
    /*
    * @Author:hanyajun
    * @Date:2019/5/28 16:44
    * @Name:ci_tools
    * @Function: ci 工具
     */
    
    //
    func HandleCi(w http.ResponseWriter, req *http.Request) {
        user := path.Base(req.URL.Path)
        //针对不同开发人员的push拉取不同的镜像和映射不同的端口
        var port string
        switch user {
        case "zhangsan":
            port = "8088"
        case "lisi":
            port = "8087"
        case "wangmazi":
            port = "8086"
        case "dev":
            port = "8085"
        case "master":
            port = "8084"
    
        }
        println(user)
        result := Run(user,port)
        client:=NewMailClient("smtp.qq.com",465,"******@qq.com","*********")//注意使用465 ssl发送,25端口阿里云ecs禁止了。
        s:=&SendObject{
            ToMails:[]string{"******@qq.com","******@qq.com","******@qq.com"},
            CcMails:[]string{"******@qq.com"},
            Object:"cicd流程结果通知",
            ContentType:"text/html",
            Content:user+" has push something to the branch: "+user+"\n"+"result: "+string(result),
        }
        err:=client.SendMail(s)
        if err!=nil{
            println("send mail fail",err)
        }
        _, _ = w.Write(result)
    }
    func main() {
        http.HandleFunc("/ci/", HandleCi)
        err := http.ListenAndServe(":8080", nil)
        if err != nil {
            log.Fatal("ListenAndServe: ", err)
        }
    }
    
    func Run(user string,port string) []byte {
    
        shellPath := "/root/ci/ci.sh"
        command := exec.Command(shellPath, user,port) 
        err := command.Start()                   
        if nil != err {
            fmt.Println(err)
            return []byte(err.Error())
        }
        fmt.Println("Process PID:", command.Process.Pid)
        err = command.Wait() //等待执行完成
        if nil != err {
            fmt.Println(err)
            return []byte(err.Error())
        }
        fmt.Println("ProcessState PID:", command.ProcessState.Pid())
        return []byte("success")
    }
    
    

    mail.go

    package main
    
    import (
        "fmt"
        "gopkg.in/gomail.v2"
    )
    
    /*
    * @Author:15815
    * @Date:2019/5/8 17:47
    * @Name:mail
    * @Function:邮件发送
     */
    
    type Client struct {
        Host     string
        Port     int
        Mail     string
        Password string
    }
    
    type SendObject struct {
        ToMails     []string
        CcMails     []string
        Object      string
        ContentType string
        Content     string
    }
    
    func NewMailClient(host string, port int, sendMail, password string) *Client {
        return &Client{
            Host:     host,
            Port:     port,
            Mail:     sendMail,
            Password: password,
        }
    }
    func (m *Client) SendMail(s *SendObject) error {
        mgs := gomail.NewMessage()
        mgs.SetHeader("From", m.Mail)
        mgs.SetHeader("To", s.ToMails...)
        mgs.SetHeader("Cc", s.CcMails...)
        mgs.SetHeader("Subject", s.Object)
        mgs.SetBody(s.ContentType, s.Content)
        d := gomail.NewDialer(m.Host, m.Port, m.Mail, m.Password)
        if err := d.DialAndSend(mgs); err != nil {
            fmt.Printf("send mail err:%v", err)
            return err
        }
        return nil
    }
    
    

    ci.sh

    #!/bin/bash
    funCiTools()
    {
        docker pull registry.cn-shanghai.aliyuncs.com/***/***:$1
        docker rm -f $1
        docker run -d -p $2:8000 --name $1 registry.cn-shanghai.aliyuncs.com/***/***:$1
    }
    funCiTools $1 $2
    

    第一个参数是对应开发人员启动容器的名字以及构建镜像的tag和上面构建的配置一致,第二个参数是映射的端口。
    构建ci_web_server

    自己的电脑是windows的,朋友的阿里云ecs上又没有go环境,想构建基于linux的二进制程序,于是直接利用docker image 来构建了镜像,一个指令解决问题。
    build.sh

    docker run --rm -i -v `pwd`:/go/src/ci -w /go/src/ci  golang:1.11.5   go build -o ci  ci
    

    使用nohup直接将ci server放置后台运行。

    nohup ./ci  >output 2>&1 &
    

    效果测试

    直接修改点东西提交代码后就等邮件通知了,是不是感觉很爽。


    在这里插入图片描述

    提交完代码后就开始触发构建了。


    在这里插入图片描述
    最后构建完完成后触发ci server 进行deploy,完成邮件通知。
    在这里插入图片描述

    登录到阿里云Ecs上我们发现我们的容器已经启动成功了。


    在这里插入图片描述

    相关文章

      网友评论

          本文标题:go程序基于阿里云CodePipeline的一次devops实践

          本文链接:https://www.haomeiwen.com/subject/yfuptctx.html