Upgrade to Pro — share decks privately, control downloads, hide ads and more …

如何設計一套具備 Container 容器化技術的 CI/CD 平台?

Bo-Yi Wu
July 05, 2024

如何設計一套具備 Container 容器化技術的 CI/CD 平台?

我相信大家在團隊內一定都有使用 CI/CD 工具,像是 Jenkins、GitLab CI、Travis CI、Circle CI 等等,這些工具都是非常好用的,但是如果想要在自己的環境中建置一套 CI/CD 平台,你會怎麼做呢?這議程會帶您深入了解 Drone CI/CD 開源工具,並且透過實際的 Demo 來說明如何設計一套具備 Container 容器化技術的 CI/CD 平台。藉由 Drone 原始碼的解析,讓您了解 Drone 的運作原理,並且透過 Drone 的 Plugin 機制,讓您可以自行開發 Drone 的 Plugin,讓 Drone 可以更加符合您的需求。

https://cloudsummit.ithome.com.tw/2024/session-page/2653

Bo-Yi Wu

July 05, 2024
Tweet

More Decks by Bo-Yi Wu

Other Decks in Technology

Transcript

  1. Drone 特性 • 使⽤ Go 語⾔編寫,所有組件都運⾏在 Docker 容器中 • ⽀持多種操作系統和架構(Linux、Windows、Mac)

    • 可擴展架構,具⾃動縮放功能,根據需求管理減少雲成本 • 可選擇安裝在本地或作為具有附加功能的 SaaS 產品使⽤ • 可使⽤任何語⾔編寫插件 • 管道使⽤簡單語法的 YAML 格式定義。 • 開源
  2. poller := &poller.Poller{ Client: cli, Dispatch: runner.Run, Filter: &client.Filter{ Kind:

    resource.Kind, Type: resource.Type, OS: config.Platform.OS, Arch: config.Platform.Arch, Variant: config.Platform.Variant, Kernel: config.Platform.Kernel, Labels: config.Runner.Labels, }, } ࠜᎦෆಉܥ౷㐫ଶ ܾఆࣥߦಛఆ೚຿ ՄҎઃఆ(16 $16ෆಉओػ
  3. func (p *Poller) Poll(ctx context.Context, n int) { var wg

    sync.WaitGroup for i := 0; i < n; i++ { wg.Add(1) go func(i int) { for { select { case <-ctx.Done(): wg.Done() return default: p.poll(ctx, i+1) } } }(i) } wg.Wait() } ։啟ଟݸ1PMMFSฏߦ႔ཧ ։࢝ࣥߦ೚຿
  4. func (p *Poller) Poll(ctx context.Context, n int) { var wg

    sync.WaitGroup for i := 0; i < n; i++ { wg.Add(1) go func(i int) { for { select { case <-ctx.Done(): wg.Done() return default: p.poll(ctx, i+1) } } }(i) } wg.Wait() } ։啟ଟݸ1PMMFSฏߦ႔ཧ ։࢝ࣥߦ೚຿ ໰୊
  5. func (p *Poller) Poll(ctx context.Context, n int) { var wg

    sync.WaitGroup for i := 0; i < n; i++ { wg.Add(1) go func(i int) { for { select { case <-ctx.Done(): wg.Done() return default: p.poll(ctx, i+1) } } }(i) } wg.Wait() } ։啟ଟݸ1PMMFSฏߦ႔ཧ ։࢝ࣥߦ೚຿ ṜᬑՄҎᬋػఀ಴YYYNT
  6. func (p *Poller) Poll(ctx context.Context, n int) { var wg

    sync.WaitGroup for i := 0; i < n; i++ { wg.Add(1) go func(i int) { for { select { case <-ctx.Done(): wg.Done() return default: p.poll(ctx, i+1) } } }(i) } wg.Wait() } ։啟ଟݸ1PMMFSฏߦ႔ཧ ։࢝ࣥߦ೚຿ ໰୊
  7. func (p *Poller) Poll(ctx context.Context, n int) { var wg

    sync.WaitGroup for i := 0; i < n; i++ { wg.Add(1) go func(i int) { for { select { case <-ctx.Done(): wg.Done() return default: p.poll(ctx, i+1) } } }(i) } wg.Wait() } ։啟ଟݸ1PMMFSฏߦ႔ཧ ։࢝ࣥߦ೚຿ ṜᬑՄҎᬋػఀ಴YYඵ
  8. func (p *Poller) Poll(ctx context.Context, n int) { var wg

    sync.WaitGroup for i := 0; i < n; i++ { wg.Add(1) go func(i int) { for { select { case <-ctx.Done(): wg.Done() return default: p.poll(ctx, i+1) } } }(i) } wg.Wait() } ։啟ଟݸ1PMMFSฏߦ႔ཧ ։࢝ࣥߦ೚຿ ṜᬑՄҎᬋػఀ಴YYඵ ࠑղ๏။Ҿᚙॄኄ໰୊ʁ
  9. How to handle Agent request? • 建立 Timeout 為 30

    秒的長連線 (Agent) • 使⽤ Go 語⾔ Map 建立所有 Agent 表列 • 使⽤ Channel 將項⽬分配到 Agent
  10. func (s *Server) handleRequest(w http.ResponseWriter, r *http.Request) { ctx :=

    r.Context() ctx, cancel := context.WithTimeout(ctx, defaultTimeout) defer cancel() in := &requestRequest{} err := json.NewDecoder(r.Body).Decode(in) if err != nil { writeBadRequest(w, err) return } stage, err := s.manager.Request(ctx, in.Request) if err != nil { writeError(w, err) return } json.NewEncoder(w).Encode(stage) }  UJNF4FDPOE ݐཱඵత௕࿈ઢ
  11. q.Lock() q.workers[w] = struct{}{} q.Unlock() select { case q.ready <-

    struct{}{}: default: } select { case <-ctx.Done(): q.Lock() delete(q.workers, w) q.Unlock() return nil, ctx.Err() case b := <-w.channel: return b, nil } ࣥߦҰ࣍查ᨑ%# "HFOUࢿ㘤์౸XPSLFS㚎 ᩇऔ4UBHFࢿ㘤 ௒աඵ௚઀ҠআXPSLFS
  12. q.Lock() count := len(q.workers) pause := q.paused q.Unlock() if pause

    { return nil } if count == 0 { return nil } items, err := q.store.ListIncomplete(ctx) if err != nil { return err } ᩇऔॴ༗ঘະࣥߦత೚຿ Ꭴग़ॴ༗ະࣥߦత೚຿ฒ෼഑౸ಛఆత"HFOU
  13. ctxdone, cancel := context.WithCancel(ctx) defer cancel() timeout := time.Duration(data.Repo.Timeout) *

    time.Minute ctxtimeout, cancel := context.WithTimeout(ctxdone, timeout) defer cancel() ctxcancel, cancel := context.WithCancel(ctxtimeout) defer cancel() go func() { done, _ := s.Client.Watch(ctxdone, data.Build.ID) if done { cancel() log.Debugln("received cancellation") } else { log.Debugln("done listening for cancellations") } }()
  14. ctxdone, cancel := context.WithCancel(ctx) defer cancel() timeout := time.Duration(data.Repo.Timeout) *

    time.Minute ctxtimeout, cancel := context.WithTimeout(ctxdone, timeout) defer cancel() ctxcancel, cancel := context.WithCancel(ctxtimeout) defer cancel() go func() { done, _ := s.Client.Watch(ctxdone, data.Build.ID) if done { cancel() log.Debugln("received cancellation") } else { log.Debugln("done listening for cancellations") } }() 
  15. ctxdone, cancel := context.WithCancel(ctx) defer cancel() timeout := time.Duration(data.Repo.Timeout) *

    time.Minute ctxtimeout, cancel := context.WithTimeout(ctxdone, timeout) defer cancel() ctxcancel, cancel := context.WithCancel(ctxtimeout) defer cancel() go func() { done, _ := s.Client.Watch(ctxdone, data.Build.ID) if done { cancel() log.Debugln("received cancellation") } else { log.Debugln("done listening for cancellations") } }() 
  16. ctxdone, cancel := context.WithCancel(ctx) defer cancel() timeout := time.Duration(data.Repo.Timeout) *

    time.Minute ctxtimeout, cancel := context.WithTimeout(ctxdone, timeout) defer cancel() ctxcancel, cancel := context.WithCancel(ctxtimeout) defer cancel() go func() { done, _ := s.Client.Watch(ctxdone, data.Build.ID) if done { cancel() log.Debugln("received cancellation") } else { log.Debugln("done listening for cancellations") } }() 
  17. ctxdone, cancel := context.WithCancel(ctx) defer cancel() timeout := time.Duration(data.Repo.Timeout) *

    time.Minute ctxtimeout, cancel := context.WithTimeout(ctxdone, timeout) defer cancel() ctxcancel, cancel := context.WithCancel(ctxtimeout) defer cancel() go func() { done, _ := s.Client.Watch(ctxdone, data.Build.ID) if done { cancel() log.Debugln("received cancellation") } else { log.Debugln("done listening for cancellations") } }() 
  18. ctxdone, cancel := context.WithCancel(ctx) defer cancel() timeout := time.Duration(data.Repo.Timeout) *

    time.Minute ctxtimeout, cancel := context.WithTimeout(ctxdone, timeout) defer cancel() ctxcancel, cancel := context.WithCancel(ctxtimeout) defer cancel() go func() { done, _ := s.Client.Watch(ctxdone, data.Build.ID) if done { cancel() log.Debugln("received cancellation") } else { log.Debugln("done listening for cancellations") } }()  3FTQPOTF4UBUVT$PEF  3FTQPOTF4UBUVT$PEF
  19. kind: pipeline type: docker name: default steps: - name: test

    image: golang:1.22 commands: - go build - go test -v - name: notify image: plugins/slack settings: channel: dev webhook: from_secret: endpoint ٬੡ԽჩᏐ */165@
  20. END