多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
## Drone 基于 `Docker` 的 `CI/CD` 工具 `Drone` 所有编译、测试的流程都在 `Docker` 容器中进行。 开发者只需在项目中包含 `.drone.yml` 文件,将代码推送到 git 仓库,`Drone` 就能够自动化的进行编译、测试、发布。 本小节以 `GitHub` + `Drone` 来演示 `Drone` 的工作流程。当然在实际开发过程中,你的代码也许不在 GitHub 托管,那么你可以尝试使用 `Gogs` + `Drone` 来进行 `CI/CD`。 ### 要求 - 拥有公网 IP、域名 (如果你不满足要求,可以尝试在本地使用 Gogs + Drone) - 域名 SSL 证书 (目前国内有很多云服务商提供免费证书) - 熟悉 `Docker` 以及 `Docker Compose` - 熟悉 `Git` 基本命令 - 对 `CI/CD` 有一定了解 ### 新建 GitHub 应用 登录 GitHub,在 <https://github.com/settings/applications/new> 新建一个应用。 ![](https://img.kancloud.cn/1d/cb/1dcbae3f2458a312d1a5da327ee58099.png) 接下来查看这个应用的详情,记录 `Client ID` 和 `Client Secret`,之后配置 Drone 会用到。 ### 配置 Drone 我们通过使用 `Docker Compose` 来启动 `Drone`,编写 `docker-compose.yml` 文件。 ``` <pre class="prettyprint"><ol class="linenums"><li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln">version</span><span class="pun">:</span><span class="pln"> </span><span class="str">'3'</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln">services</span><span class="pun">:</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> drone</span><span class="pun">-</span><span class="pln">server</span><span class="pun">:</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> image</span><span class="pun">:</span><span class="pln"> drone</span><span class="pun">/</span><span class="pln">drone</span><span class="pun">:</span><span class="lit">0.8</span><span class="pun">-</span><span class="pln">alpine</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> ports</span><span class="pun">:</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">443</span><span class="pun">:</span><span class="lit">443</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="com"># - "${PRO_PUBLIC_IP}:8000:8000"</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> volumes</span><span class="pun">:</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> drone</span><span class="pun">-</span><span class="pln">data</span><span class="pun">:</span><span class="str">/var/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">drone</span><span class="pun">/:</span><span class="pln">rw</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">SSL_PATH</span><span class="pun">}:</span><span class="str">/etc/</span><span class="pln">certs</span><span class="pun">:</span><span class="pln">rw</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> restart</span><span class="pun">:</span><span class="pln"> always</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> environment</span><span class="pun">:</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> DRONE_SECRET</span><span class="pun">=</span><span class="pln">drone</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> DRONE_OPEN</span><span class="pun">=</span><span class="kwd">false</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> DRONE_ADMIN</span><span class="pun">=</span><span class="pln">$</span><span class="pun">{</span><span class="pln">GITHUB_SERNAME</span><span class="pun">}</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> DRONE_HOST</span><span class="pun">=</span><span class="pln">$</span><span class="pun">{</span><span class="pln">DRONE_HOST</span><span class="pun">}</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> DRONE_GITHUB</span><span class="pun">=</span><span class="kwd">true</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> DRONE_GITHUB_CLIENT</span><span class="pun">=</span><span class="pln">$</span><span class="pun">{</span><span class="pln">DRONE_GITHUB_CLIENT</span><span class="pun">}</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> DRONE_GITHUB_SECRET</span><span class="pun">=</span><span class="pln">$</span><span class="pun">{</span><span class="pln">DRONE_GITHUB_SECRET</span><span class="pun">}</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> DRONE_SERVER_CERT</span><span class="pun">=</span><span class="str">/etc/</span><span class="pln">certs</span><span class="pun">/</span><span class="pln">drone</span><span class="pun">.</span><span class="pln">domain</span><span class="pun">.</span><span class="pln">com</span><span class="pun">.</span><span class="pln">crt</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> DRONE_SERVER_KEY</span><span class="pun">=</span><span class="str">/etc/</span><span class="pln">certs</span><span class="pun">/</span><span class="pln">drone</span><span class="pun">.</span><span class="pln">domain</span><span class="pun">.</span><span class="pln">com</span><span class="pun">.</span><span class="pln">key</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> drone</span><span class="pun">-</span><span class="pln">agent</span><span class="pun">:</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> image</span><span class="pun">:</span><span class="pln"> drone</span><span class="pun">/</span><span class="pln">agent</span><span class="pun">:</span><span class="lit">0.8</span><span class="pun">-</span><span class="pln">alpine</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> restart</span><span class="pun">:</span><span class="pln"> always</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> depends_on</span><span class="pun">:</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> drone</span><span class="pun">-</span><span class="pln">server</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> volumes</span><span class="pun">:</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="str">/var/</span><span class="pln">run</span><span class="pun">/</span><span class="pln">docker</span><span class="pun">.</span><span class="pln">sock</span><span class="pun">:</span><span class="str">/var/</span><span class="pln">run</span><span class="pun">/</span><span class="pln">docker</span><span class="pun">.</span><span class="pln">sock</span><span class="pun">:</span><span class="pln">rw</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> environment</span><span class="pun">:</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> DRONE_SECRET</span><span class="pun">=</span><span class="pln">drone</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> DRONE_SERVER</span><span class="pun">=</span><span class="pln">drone</span><span class="pun">-</span><span class="pln">server</span><span class="pun">:</span><span class="lit">9000</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> dns</span><span class="pun">:</span><span class="pln"> </span><span class="lit">114.114</span><span class="pun">.</span><span class="lit">114.114</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln">volumes</span><span class="pun">:</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> drone</span><span class="pun">-</span><span class="pln">data</span><span class="pun">:</span></code></li> </ol> ``` 替换 `${SSL_PATH}` 为你网站的 SSL 证书路径。 替换 `${GITHUB_SERNAME}` 为你 GitHub 的用户名,该用户将成为 Drone 的管理员。 替换 `${DRONE_HOST}` 为你部署 Drone 的域名。 替换 `${DRONE_GITHUB_CLIENT}` 为你 GitHub 应用的 `Client ID` 替换 `${DRONE_GITHUB_SECRET}` 为你 GitHub 应用的 `Client Secret` *注意:* 如果你的服务器占用了 `443` 端口,请配置 Nginx 代理,这里不再赘述。 #### 启动 Drone ``` <pre class="prettyprint"><ol class="linenums"><li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln">$ docker</span><span class="pun">-</span><span class="pln">compose up </span><span class="pun">-</span><span class="pln">d</span></code></li></ol> ``` ### Drone 关联项目 在 Github 新建一个名为 `drone-demo` 的仓库。 打开我们已经部署好的 Drone 网站,使用 GitHub 账号登录,在界面中关联刚刚新建的 `drone-demo` 仓库。 ### 编写项目源代码 在本机初始化一个 git 仓库 ``` <pre class="prettyprint"><ol class="linenums"><li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln">$ mkdir drone</span><span class="pun">-</span><span class="pln">demo</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln">$ cd drone</span><span class="pun">-</span><span class="pln">demo</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln">$ git init</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln">$ git remote add origin git@github</span><span class="pun">.</span><span class="pln">com</span><span class="pun">:</span><span class="pln">username</span><span class="pun">/</span><span class="pln">drone</span><span class="pun">-</span><span class="pln">demo</span><span class="pun">.</span><span class="pln">git</span></code></li> </ol> ``` 这里以一个简单的 `Go` 程序为例,该程序输出 `Hello World!` 编写 `app.go` 文件 ``` <pre class="prettyprint"><ol class="linenums"><li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="kwd">package</span><span class="pln"> main</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln">func main</span><span class="pun">(){</span><span class="pln"> </span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"Hello World!"</span><span class="pun">);</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pun">}</span></code></li> </ol> ``` 编写 `.drone.yml` 文件 ``` <pre class="prettyprint"><ol class="linenums"><li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln">workspace</span><span class="pun">:</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="kwd">base</span><span class="pun">:</span><span class="pln"> </span><span class="str">/srv/</span><span class="pln">drone</span><span class="pun">-</span><span class="pln">demo</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> path</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln">pipeline</span><span class="pun">:</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> build</span><span class="pun">:</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> image</span><span class="pun">:</span><span class="pln"> golang</span><span class="pun">:</span><span class="pln">alpine</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="com"># pull: true</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> environment</span><span class="pun">:</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> KEY</span><span class="pun">=</span><span class="pln">VALUE</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> secrets</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">key1</span><span class="pun">,</span><span class="pln"> key2</span><span class="pun">]</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> commands</span><span class="pun">:</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> echo $$KEY</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> pwd</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> ls</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> CGO_ENABLED</span><span class="pun">=</span><span class="lit">0</span><span class="pln"> GOOS</span><span class="pun">=</span><span class="pln">linux go build </span><span class="pun">-</span><span class="pln">a </span><span class="pun">-</span><span class="pln">installsuffix cgo </span><span class="pun">-</span><span class="pln">o app </span><span class="pun">.</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="pun">./</span><span class="pln">app</span></code></li> </ol> ``` `workspace` 指明 git 源代码克隆的目标路径,本例中 git 源代码将被克隆到 golang 容器中的 `/srv/drone-demo` 目录中。 `pipeline` 指明构建所需的 Docker 镜像,环境变量,编译指令等。 现在目录结构如下 ``` <pre class="prettyprint"><ol class="linenums"><li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pun">.</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pun">├──</span><span class="pln"> </span><span class="pun">.</span><span class="pln">drone</span><span class="pun">.</span><span class="pln">yml</span></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pun">└──</span><span class="pln"> app</span><span class="pun">.</span><span class="pln">go</span></code></li> </ol> ``` ### 推送项目源代码到 GitHub ``` <pre class="prettyprint"><ol class="linenums"><li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln">$ git add </span><span class="pun">.</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln">$ git commit </span><span class="pun">-</span><span class="pln">m </span><span class="str">"test drone ci"</span></code></li> <li class="l1"><code class="pcalibre10 pcalibre11 pcalibre9"></code></li> <li class="l"><code class="pcalibre10 pcalibre11 pcalibre9"><span class="pln">$ git push origin master</span></code></li> </ol> ``` ### 查看项目构建过程及结果 打开我们部署好的 `Drone` 网站,即可看到构建结果。 ![](https://img.kancloud.cn/06/58/0658109d193575eeb6c1c54c541cdc60.png) 当然我们也可以把构建结果上传到 GitHub,Docker Registry,云服务商提供的对象存储,或者生产环境中。 本书 GitBook 也使用 Drone 进行 CI/CD,具体配置信息请查看本书根目录 [`.drone.yml`](https://github.com/yeasy/docker_practice/blob/master/.drone.yml) 文件。 ## 参考链接 - [Drone Github](https://github.com/drone/drone) - [Drone 文档](http://docs.drone.io/)