最近朋友有個項目代碼託管用的碼雲,測試服務器(阿里雲ECS)只有一臺,三四我的開發,因而想基於阿里雲的CodePipeline快速打造一套自動化cicd的流程,使用docker來進行多套環境部署。html
阿里雲CodePipeline是兼容Jenkins標準的、提供快速可靠的持續集成與持續交付服務。基於容器技術和阿里雲基礎服務架構,提供穩定和安全的代碼/Docker編譯構建,測試,掃描和部署的工具服務,並提供Pipeline As Code的編碼級配置模式,知足應用程序和基礎設施快速可靠的交付和更新。mysql
上面是阿里雲的官方介紹,兼容jekins的標準,一次無心的點擊出現了下圖的圖標,感受就是jenkins的基礎上作了一次二次開發。
linux
因爲項目使用到了一些國外的lib,固然選擇國內的節點也是能夠的,不過在寫Dockerfile的時候記得加上代理。golang
選擇合適的代碼倉庫,也能夠是私倉,不過須要配上本身的帳號和ssh key相關信息。web
我這裏使用的是阿里雲的私有的鏡像倉庫基於Dockerfile來構建鏡像,注意配置憑證。
[在這裏插入圖片描述]redis
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
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.iosql
這裏選擇一個構建的代碼分支,而後點擊生成,將生成後的url能夠在對應的代碼倉庫配上webhook之類的配置。選擇合適的觸發方式。
docker
阿里雲構建步驟裏面部署到ECS上(不方便)和部署到k8s(收費)都不能知足項目場景需求,不過上面支持shell腳本,因而本身想在朋友的那臺阿里雲ECS上跑個ci的web server,這裏構建完以後就去通知下這個接口,而後去執行一些docker指令的腳本,拉取構建完以後的鏡像而且從新啓動,啓動完以後郵件通知。因而寫了這樣一個很簡單的web server。
mainshell
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.gowindows
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上咱們發現咱們的容器已經啓動成功了。