{"id":3630,"date":"2018-04-11T05:57:06","date_gmt":"2018-04-11T11:57:06","guid":{"rendered":"http:\/\/benincosa.com\/?p=3630"},"modified":"2018-04-11T05:57:06","modified_gmt":"2018-04-11T11:57:06","slug":"cicd-continued-drone","status":"publish","type":"post","link":"https:\/\/benincosa.com\/?p=3630","title":{"rendered":"CI\/CD continued: Drone"},"content":{"rendered":"<p>In <a href=\"https:\/\/benincosa.com\/?p=3624\">my previous post<\/a> I showed how we setup a CI\/CD server.\u00a0 In this post we&#8217;ll go into more detail in explaining how drone works.\u00a0 I&#8217;ve previous written about how <a href=\"http:\/\/benincosa.com\/?p=3584\">drone does secrets<\/a>.\u00a0 Well that has changed a bit, so in this update with drone 0.8.5 we&#8217;ll show how it works.\u00a0 This time, we&#8217;re working on a python application.<\/p>\n<h2>Mac Command Line<\/h2>\n<p>Before we begin we need to get the drone command line tool. The easiest way to do this is to get it with <a href=\"https:\/\/brew.sh\/\">homebrew<\/a><\/p>\n<pre class=\"lang:sh decode:true \">brew install drone<\/pre>\n<p>From here we need to add some environment variables to our ~\/.bash_profile so that we can communicate with our drone server.\u00a0 Essentially, we add:<\/p>\n<pre class=\"lang:sh decode:true \">export DRONE_SERVER=http:\/\/1db27123.ngrok.io\r\nexport DRONE_TOKEN=eyJhbGciOiJIUzI1...<\/pre>\n<p>The drone token you can get by logging into drone (<a href=\"https:\/\/benincosa.com\/?p=3624\">see previous post<\/a>) and account token in the upper left of the web interface.<\/p>\n<p>Sourcing this file, we can now run something like<\/p>\n<pre class=\"lang:sh decode:true \">drone info<\/pre>\n<p>If this command shows your github credentials you are good to go!<\/p>\n<h2>Drone vs. Jenkins Level set<\/h2>\n<p>Drone differs from Jenkins in a few ways.\u00a0 First off, the configuration file for the job is not stored in the &#8220;Jenkins Master&#8221;.\u00a0 Instead, the job&#8217;s configuration file is stored in the repository with the actual code.\u00a0 I love this because it makes sense that the developer own the workflow.\u00a0 It&#8217;s just a paradigm shift and in my opinion much better.\u00a0 It also means I could take this workflow to any drone CI\/CD process and it should work fine.<\/p>\n<p>The second difference is how the workflows are created.\u00a0 With Jenkins you download &#8220;Plugins&#8221; and different tools and store them on the Jenkins server.\u00a0 With Drone, every module is just a container.\u00a0 That way they&#8217;re all the same.\u00a0 I&#8217;ve written a couple as well and I really like the way its laid out.<\/p>\n<p>That said, Jenkins is crusty, tried, and true and Drone is still evolving and changing.<\/p>\n<h2>Drone Workflow Config File<\/h2>\n<p>Inside the repo of the code to be tested and released we create a .drone.yml file.\u00a0 Our final file (which will undergo several changes) is <a href=\"https:\/\/github.com\/CiscoUcs\/KUBaM\/blob\/v2.0\/.drone.yml\">located here<\/a>.<\/p>\n<p>Let&#8217;s go over how this works.<\/p>\n<p>First we specify the pipeline.\u00a0 Each entry in this pipeline is an arbitrary name that helps me remember what is going on.<\/p>\n<h3>Notify<\/h3>\n<p>The first one notifies that a build is happening.\u00a0 This first one looks as follows:<\/p>\n<pre class=\"lang:sh decode:true\"> notify:\r\n    image: vallard\/drone-spark\r\n    room: \"KUBAM Feedback\"\r\n    template: \"Starting build {{ build.number }} for {{ repo.owner }}\/{{ repo.name }} for {{ build.author }}.\"\r\n    environment:\r\n      - https_proxy=proxy.esl.cisco.com:80\r\n      - http_proxy=proxy.esl.cisco.com:80\r\n    secrets: [ SPARK_TOKEN ]<\/pre>\n<p>Since we are good Cisco employees we use Spark for notifications.\u00a0 You might use slack or something you might find cooler, but we like Spark.\u00a0 Notice we have a SPARK_TOKEN secret.\u00a0 This secret needs to be added via the command line as we don&#8217;t want to check secrets into repositories.\u00a0 That is a no-no.<\/p>\n<pre class=\"lang:sh decode:true\">drone secret add -repository CiscoUcs\/KUBaM -image vallard\/drone-spark -name SPARK_TOKEN -value YmI1NjJlNWQtZmVmNi0....\r\n<\/pre>\n<h3>Test<\/h3>\n<p>Next up, we want to test the python flask image using our test cases.\u00a0 To do so, we created a test docker image that has all the necessary dependencies in it called <a href=\"https:\/\/hub.docker.com\/r\/kubam\/python-test\/\">kubam\/python-test<\/a>.\u00a0 This way the container loads quick and doesn&#8217;t have to install dependencies.\u00a0 The <a href=\"https:\/\/github.com\/CiscoUcs\/KUBaM\/blob\/v2.0\/test\/Dockerfile\">Dockerfile<\/a> is in the same repo.\u00a0 This step looks as follows:<\/p>\n<pre class=\"lang:sh decode:true \">unittests:\r\n    image: kubam\/python-test\r\n    environment:\r\n      - https_proxy=proxy.esl.cisco.com:80\r\n      - http_proxy=proxy.esl.cisco.com:80\r\n    commands:\r\n      - echo \"Building..\"\r\n      - cd kubam\/app; python -m unittest test.test_db.DBUnitTests\r\n      - cd ..\/..\/<\/pre>\n<p>You&#8217;ll notice that in each step we add the proxy environment variables.\u00a0 The reason for this is that you have to remember we are behind a firewall!\u00a0 So for the container to get out, it has to use the proxy configuration.<\/p>\n<h3>Docker<\/h3>\n<p>Next we want to build and publish the &#8216;artifact&#8217;.\u00a0 In this case the artifact is a docker image.\u00a0 This is done with the default drone docker plugin.<\/p>\n<pre class=\"lang:sh decode:true \"> docker:\r\n    image: plugins\/docker\r\n    repo: kubam\/kubam\r\n    tags: v2\r\n    user: kubam\r\n    secrets: [docker_username, docker_password]\r\n    environment:\r\n      - https_proxy=proxy.esl.cisco.com:80\r\n      - http_proxy=proxy.esl.cisco.com:80\r\n    when:\r\n      branch: v2.0<\/pre>\n<p>Since we are working on a branch that we want to create new images for we use the v2.0 tag to make sure we get the one we want.<\/p>\n<p>Notice there are secrets here so we have to add these.\u00a0 So we do:<\/p>\n<pre class=\"lang:sh decode:true \">drone secret add -repository CiscoUcs\/KUBaM -image plugins\/docker -name docker_username -value kubam\r\ndrone secret add -repository CiscoUcs\/KUBaM -image plugins\/docker -name docker_password -value secretpassword<\/pre>\n<h2>Let it run<\/h2>\n<p>Now we have a great system!\u00a0 Let&#8217;s let it go.\u00a0 Launching it and we have it doing these three steps and publishing the docker container.\u00a0 Now anytime someone pushes we&#8217;ll test it and if they all pass put it into production.\u00a0 This is safe as long as we have sufficient test cases.\u00a0 This is how we can go fast and make less work for everyone and be more productive.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In my previous post I showed how we setup a CI\/CD server.\u00a0 In this post we&#8217;ll go into more detail in explaining how drone works.\u00a0 I&#8217;ve previous written about how drone does secrets.\u00a0 Well that has changed a bit, so in this update with drone 0.8.5 we&#8217;ll show how it works.\u00a0 This time, we&#8217;re working&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts\/3630"}],"collection":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3630"}],"version-history":[{"count":1,"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts\/3630\/revisions"}],"predecessor-version":[{"id":3631,"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts\/3630\/revisions\/3631"}],"wp:attachment":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3630"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3630"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3630"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}