CI/CD初探 (Drone+Docker)

將使用 docker + docker compose + drone + git 實現(xiàn)項目自動部署

使用docker可以讓drone實現(xiàn)任意語言程序的構建與部署

分工

  • docker: 整潔迅速的部署方案
  • docker-compose: 組網(wǎng)和簡單容器編排
  • drone: go語言寫的基于docker的CI框架

流程預覽

  • 代碼提交到git
  • git 通知drone應用
  • 觸發(fā)drone服務器運行項目下的.drone.yml
    • 如果沒有配置clone步驟, drone會運行默認的clone步驟, 并clone到workspace設置下的path
    • 依次運行pipeline下的步驟, 通常是 test -> build -> publish -> ssh連接到運行服務容器的服務器 并重啟容器, 下面會依次說明pipeline各步驟.

安裝Drone

此文基于Drone0.8版本安裝, 已經(jīng)過時, 請多多參考Drone官方安裝文檔.

官方使用docker-compose安裝, 編寫docker-compose.yml如下

docker-compose.yml

version: '2'

services:
  drone-server:
    image: drone/drone:latest

    ports:
      - 8000
      - 9000
    volumes:
      - /workspace/docker/volumes/drone:/var/lib/drone/
    restart: always
    environment:
      - DRONE_OPEN=true
      - DRONE_HOST=${DRONE_HOST}
      - DRONE_CODING=true
      - DRONE_CODING_CLIENT=${DRONE_CODING_CLIENT}
      - DRONE_CODING_URL=https://coding.net
      - DRONE_CODING_SECRET=${DRONE_CODING_SECRET}
      - DRONE_CODING_GIT_MACHINE=e.coding.net
      - DRONE_CODING_SCOPE=user,project,project:depot
      - DRONE_GITHUB_SKIP_VERIFY=false
      - DRONE_SECRET=${DRONE_SECRET}
      - DRONE_ADMIN=bysir
      - DRONE_CODING_GIT_USERNAME=${DRONE_CODING_GIT_USERNAME}
      - DRONE_CODING_GIT_PASSWORD=${DRONE_CODING_GIT_PASSWORD}

  drone-agent:
    image: drone/agent:latest

    command: agent
    restart: always
    depends_on:
      - drone-server
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - DRONE_SERVER=drone-server:9000
      - DRONE_SECRET=${DRONE_SECRET}
      - DRONE_MAX_PROCS=5

備注

字段 注釋
DRONE_ADMIN 管理員, 名字是你版本控制的賬號名, 添加了管理員的才可以管理用戶
DRONE_OPEN 是否開啟新用戶注冊
DRONE_GITHUB 使用github作為版本控制

在上面你會看到其中有${DRONE_HOST}的變量,這是docker-compose支持的語法, 文檔

我們需要在同級目錄下編寫一個.env文件來寫入這些變量

.env

# drone的安裝服務器, 不需要端口
DRONE_HOST=http://40.90.200.130
# DRONE需要GITHUB作為應用授權, 這里填寫授權賬號密碼, 詳情看[官方文檔](http://docs.drone.io/install-for-github/)
DRONE_GITHUB_CLIENT=xxxx
DRONE_GITHUB_SECRET=xxxx
# 用于drone服務器和agent之間的密鑰, 隨意填寫
DRONE_SECRET=123456

現(xiàn)在運行docker-compose up就能運行drone了, 如果有報錯就按報錯提示來解決.

訪問服務器 8000 端口就能看到drone的web頁面了, 使用GITHUB的賬號登陸即可, 登陸后drone會自動拉取項目目錄, 點擊項目就能開啟對這個項目的監(jiān)管.

編寫項目

需要單獨為每一個項目編寫.drone.yml文件 用來表述在代碼提交后需要執(zhí)行哪些操作.

用一個簡單的go項目說明

.drone.yml

workspace:
  base: /go
  path: src/github.com/bysir-zl/gokit_start

pipeline:
  build:
    image: golang:1.9
    commands:
      - pwd
      - go env
      - go version
      - go build

  publish:
      image: plugins/docker
      registry: https://index.docker.io/v1/ # 倉庫
      repo: bysir/golang_base # docker倉庫地址
      # mirror: https://docker.mirrors.ustc.edu.cn
      # 需要使用drone cli添加secrets: http://docs.drone.io/manage-secrets/
      secrets: [ docker_username, docker_password ]
      tags:
        - latest

  deploy:
      image: appleboy/drone-ssh
      host: 47.94.204.137
      username: root
      port: 22
      secrets: [ ssh_key ]
      script:
        - cd /root/app
        - docker-compose pull bysir/golang_base
        - docker-compose up

workspace

其中workspace指定pipeline的工作目錄, 上例中我們會在buildpwd看到當前目錄是/go/src/github.com/bysir-zl/gokit_start, 為什么我們需要指定到/go目錄下, 因為在golang:1.9的鏡像中, go_path就是/go, 我們要go build當然要在go_path下執(zhí)行.

build

build步驟很簡單只是go build, 你好奇為什么沒有go get, 因為我將vendor目錄也一起提交了, 推薦使用go官方依賴管理工具dep

docker在構建的時候都是以一個空白鏡像golang:1.9作為基礎的, 如果不提交vendor就需要每次構建都go get, 十分耗時. 當然還有辦法就是提交一個已經(jīng)按照好go包的基礎鏡像到registry里, 在build中的image就換成你提交的鏡像. 相比之下更簡單的方法就是提交vendor目錄.

publish

publish步驟就有點復雜了, 使用到了plugins/docker插件, 這個插件是drone寫的, 用于發(fā)布docker鏡像. 它的作用就是構建一個鏡像, 并push到registry.

我們需要配置的值有

  • registry: 倉庫registry, 如hub.docker.com的registry地址是https://index.docker.io/v1/
  • repo: 在docker倉庫下的項目名稱
  • secrets: drone用于傳遞密鑰的實現(xiàn)方式, 下面會詳細介紹

plugins/docker插件中, 構建項目鏡像是通過Dockerfile來的, 所以我們還需要在項目根編寫一個Dockerfile
Dockerfile

FROM alpine:latest

COPY gokit_start /

WORKDIR /

ENTRYPOINT ["./gokit_start"]

其中ENTRYPOINT是容器啟動后的運行入口, "./gokit_start"是示例項目build后的二進制文件

deply

發(fā)布流程就是通過SSH登陸上要部署程序的服務器pull下剛剛publish的鏡像并啟動.

登陸SSH就需要配置ssh_key或者ssh_password, 更多詳情看appleboy/ssh這個插件的文檔, 這里推薦使用ssh_key, 我們需要在drone的secrets添加一項ssh_key值為私鑰, 然后我們將與之匹配的公鑰放在服務器上.ssh/authorized_keys里, 這樣就能使用ssh_key登陸上服務器并執(zhí)行script.

測試

現(xiàn)在你的項目機構應該類似于


項目

現(xiàn)在你可以將你寫的代碼和配置文件一起提交到git, 然后你就能看到這個項目正在構建

你可以點擊查看構建步驟


ps

終于跑起來了


我相信你沒有我這么菜

2018/04/27 更新

最近需要使用coding作為版本控制軟件

文檔說drone-server在0.8版本之后是支持coding的, 但實際不然. 實際運行起來會報錯:version control system not configured

找了很久的原因, 翻了很久源代碼發(fā)現(xiàn)并沒有問題, 直到發(fā)現(xiàn)這個Issue

I encounter this issue too.
When use drone from latest docker image, setting DRONE_CODING=true has no effect, result: "version control system not configured".
When build drone from git source code, It's works.

I found

git clone git@github.com:drone/drone-enterprise.git extras

go build -ldflags '-extldflags "-static" -X github.com/drone/drone/version.VersionDev=build.'${DRONE_BUILD_NUMBER} -o release/drone-server github.com/drone/drone/extras/cmd/drone-server
at .drone.sh,
You use drone-enterprise.git for extras to build the docker image, not the open source code.
Is that the problem?

所以我嘗試使用git上源碼重新編譯一個drone-server使用, 修改倉庫下.drone.sh如下:

#!/bin/sh

# clone the extras project.
set -e
set -x

# 由于要運行在alpine, 所以需要加GOOS=linux GOARCH=arm64 CGO_ENABLED=0
# 由于drone-server使用到了sqlite3, sqlite3使用到了gcc, 所以需要-extldflags "-static"
# -ldflags "-extldflags -static" at the end makes sure C code is statically linked so resulting binary truly has no dependencies even for C code.
go build -ldflags '-extldflags "-static" -X github.com/drone/drone/version.VersionDev=build.'0.01 -o release/drone-server github.com/drone/drone/cmd/drone-server
GOOS=linux GOARCH=amd64 CGO_ENABLED=0         go build -ldflags '-X github.com/drone/drone/version.VersionDev=build.'0.01 -o release/drone-agent             github.com/drone/drone/cmd/drone-agent
GOOS=linux GOARCH=arm64 CGO_ENABLED=0         go build -ldflags '-X github.com/drone/drone/version.VersionDev=build.'0.01 -o release/linux/arm64/drone-agent github.com/drone/drone/cmd/drone-agent
GOOS=linux GOARCH=arm   CGO_ENABLED=0 GOARM=7 go build -ldflags '-X github.com/drone/drone/version.VersionDev=build.'0.01 -o release/linux/arm/drone-agent   github.com/drone/drone/cmd/drone-agent

重新編譯, 打包鏡像.

為了方便, 我將做好的鏡像放在了共有倉庫下:
bysir/drone-server (對于官方0.8.5的版本)

可以這樣使用:

version: '2'

services:
  drone-server:
    image: bysir/drone-server

    ports:
      - 8082:8000
      - 9000
    volumes:
      - /workspace/docker/volumes/drone:/var/lib/drone/
    restart: always
    environment:
      - DRONE_OPEN=true
      - DRONE_HOST=${DRONE_HOST}
      - DRONE_CODING=true
      - DRONE_CODING_CLIENT=${DRONE_CODING_CLIENT}
      - DRONE_CODING_URL=https://zhuzi.coding.net
      - DRONE_CODING_SECRET=${DRONE_CODING_SECRET}
      - DRONE_CODING_GIT_MACHINE=e.coding.net
      - DRONE_CODING_SCOPE=user,project,project:depot
      - DRONE_GITHUB_SKIP_VERIFY=false
      - DRONE_SECRET=${DRONE_SECRET}
      - DRONE_ADMIN=bysir

  drone-agent:
    image: drone/agent

    command: agent
    restart: always
    depends_on:
      - drone-server
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - DRONE_SERVER=drone-server:9000
      - DRONE_SECRET=${DRONE_SECRET}

ps: 真是折騰... 不過終于好了

歡迎看我接下來的折騰:


擴展閱讀: 私鑰登錄原理

為什么要生成一對秘鑰將秘鑰放在drone的ssh_key:
DroneService(A)想要登錄Service(B)并執(zhí)行命令, 在SSH登錄認證的時候需要A用私鑰簽名一段信息發(fā)送到B, B收到請求后會使用.ssh/authorized_keys中的公鑰依次驗簽, 如果驗簽成功則登錄成功.

ps: 私鑰的格式是-----BEGIN RSA PRIVATE KEY-----xxxxxxxxx-----END RSA PRIVATE KEY----- 全部放在web頁面就行了, 如下

添加secrets

publish步驟有secrets選項, 其中docker_username和docker_password是由drone注入的, 所以我們需要在drone右上角添加secrets:


添加之后如下:

secrets實現(xiàn)原理:
drone有一個專門存儲secrets的地方, 當pipeline中step需要secrets的時候, 會得到其值并設置為容器的環(huán)境變量

上例中drone會從數(shù)據(jù)庫拿到docker_usernamedocker_password并賦值給環(huán)境變量DOCKER_USERNAMEDOCKER_PASSWORD, 在plugins/docker中會使用這兩個環(huán)境變量去登陸你設置的registry : docker login -p $DOCKER_PASWORD -u $DOCKER_USERNAME $DOCKER_REGISTRY

擴展閱讀:安裝drone cli

可以使用drone的cli來添加secrets: manage-secrets

安裝方法: CLI Installation

curl -L https://github.com/drone/drone-cli/releases/download/v0.8.3/drone_linux_amd64.tar.gz | tar zx
sudo install -t /usr/local/bin drone

CLI需要通過server的授權: CLI Authentication

export DRONE_SERVER=http://47.94.204.137:8080
export DRONE_TOKEN=eyJh33OiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZXh0IjoiYnlzaXItemwiLCJ0eXBlIjoidXNlciJ9.jLsJvi4PafTi-ffefe5-bYTD2N_xmIi9fg

之后就可以使用cli執(zhí)行命令

添加secrets

drone secret add   -repository bysir-zl/gokit_start   -image plugins/docker   -name docker_username  -value bysir
drone secret add   -repository bysir-zl/gokit_start   -image plugins/docker   -name docker_password  -value 123456

刪除secret

drone secret rm --repository bysir-zl/gokit_start --name docker_username

2020/5/14 更新

Coding.net改了API 導致Drone0.8無法獲取到倉庫的.drone.yml 文件, 相關補丁已發(fā)布到此倉庫中https://github.com/zbysir/drone/tree/0.8.10-coding.

如果需要編譯, 為了方便, 應該在linux上編譯, 因為drone依賴了sqlite3, sqlite3依賴的cgg. 另外drone中的vendor缺失了一些依賴包, 你可以試著運行./drone.sh并且下載所缺失的包, 總之 折騰起來有些麻煩, 耐心.

或者 你可以直接使用我構建好的鏡像來一鍵修復此問題: https://hub.docker.com/repository/docker/bysir/drone-server

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末轿曙,一起剝皮案震驚了整個濱河市碰辅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖平酿,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異盅藻,居然都是意外死亡霍骄,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門扑庞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來譬重,“玉大人,你說我怎么就攤上這事罐氨⊥喂妫” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵栅隐,是天一觀的道長塔嬉。 經(jīng)常有香客問我,道長租悄,這世上最難降的妖魔是什么谨究? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮泣棋,結果婚禮上胶哲,老公的妹妹穿的比我還像新娘。我一直安慰自己潭辈,他們只是感情好鸯屿,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著把敢,像睡著了一般寄摆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上修赞,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天婶恼,我揣著相機與錄音,去河邊找鬼柏副。 笑死熙尉,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的搓扯。 我是一名探鬼主播检痰,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼锨推!你這毒婦竟也來了铅歼?” 一聲冷哼從身側響起公壤,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎椎椰,沒想到半個月后厦幅,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡慨飘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年确憨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瓤的。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡休弃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出圈膏,到底是詐尸還是另有隱情塔猾,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布稽坤,位于F島的核電站丈甸,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏尿褪。R本人自食惡果不足惜睦擂,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望杖玲。 院中可真熱鬧祈匙,春花似錦、人聲如沸天揖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽今膊。三九已至,卻和暖如春伞剑,著一層夾襖步出監(jiān)牢的瞬間斑唬,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工黎泣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留恕刘,地道東北人。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓抒倚,卻偏偏與公主長得像褐着,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子托呕,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容