{"__v":11,"_id":"56ccf3498c4a331d002c1e1e","category":{"__v":2,"_id":"56ccf29a431ada1f00e85aae","pages":["56ccf3498c4a331d002c1e1e","56ccf35a8c4a331d002c1e21"],"project":"55c6bec1b9aa4e0d0016c2c3","version":"55c6bec1b9aa4e0d0016c2c6","sync":{"url":"","isSync":false},"reference":false,"createdAt":"2016-02-24T00:00:26.717Z","from_sync":false,"order":4,"slug":"code-labs","title":"Code Labs"},"parentDoc":null,"project":"55c6bec1b9aa4e0d0016c2c3","user":"55c8f42fb79cb30d005b3e48","version":{"__v":8,"_id":"55c6bec1b9aa4e0d0016c2c6","project":"55c6bec1b9aa4e0d0016c2c3","createdAt":"2015-08-09T02:45:21.683Z","releaseDate":"2015-08-09T02:45:21.683Z","categories":["55c6bec2b9aa4e0d0016c2c7","56c14bc5826df10d00e82230","56cceed8723ad71d00cae46c","56ccf29a431ada1f00e85aae","56ccf3c28fa8b01b00b82018","56ce1e6ee538330b0021ac5d","56f97e9a4c612020008f2eaf","5734fafd146eb82000597261"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"1.0.0","version":"1.0"},"updates":["56f59be28884db19007d390b","5714e5ccff0cce190056ed80","57311c5da825f30e00b5180d","579902af7700d30e00ad2526","57c46c7087a1060e00e36d04","57c713e580cbfa0e0070651f","57c88a649e6bca0e007eded3"],"next":{"pages":[],"description":""},"createdAt":"2016-02-24T00:03:21.426Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":1,"body":"#An Introduction to Spinnaker: Hello Deployment\n\nThis guide will run through the workflow of setting up an example application deployment with [Spinnaker](http://spinnaker.io/). It assumes you already have Spinnaker up and running on AWS or GCE. A guide for installation can be found [Installing and Running Spinnaker](doc:installing-and-running-spinnaker) .\n\nBelow is a diagram of the workflow we will setup.\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/06CDzZS2RhmmJ0PaMFgy_flow.png\",\n        \"flow.png\",\n        \"616\",\n        \"600\",\n        \"#c63b3c\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n##Setup Jenkins\n\nJenkins is a powerful continuous integration server that allows us to do several important things:\n\n* Poll our Github repository for changes so Spinnaker knows when to run a pipeline.\n* Compile and build our example application into a .deb package so Spinnaker can bake it on an image. Spinnaker expects all applications to be deployed as deb packages.\n\n###Installing Jenkins\n\nIf you already have a Jenkins server, you can skip this step. However be sure that port 9999 on the server is open to the internet if you plan to host your deb repository there. Also be sure that your Jenkins port is accessible by your Spinnaker instance.\n\nSSH into your instance and run the following:\n\n~~~\n$ sudo apt-get update\n$ sudo apt-get upgrade\n$ sudo apt-get install openjdk-7-jdk\n$ wget -q -O - https://jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -\n$ sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list'\n$ sudo apt-get update\n$ sudo apt-get install jenkins git\n$ sudo service jenkins start\n~~~\n\nVisit port :8080 on your instance and you should see Jenkins startup and present the dashboard.\n\n###Enable Jenkins API\n\nSpinnaker communicates with Jenkins by using its REST API. However the API is not enabled by default. To enable it we first must enable global security (which is a good idea anyway). Click \"Manage Jenkins\" then \"Configure Global Security\". Under Access Control check \"Jenkins own database\" and \"allow users to sign up\". Under authorization check \"Logged-in users can do anything\" and save.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/AP5tbGUOQb6jKbdpEEvw_jenkins1.png\",\n        \"jenkins1.png\",\n        \"727\",\n        \"824\",\n        \"#5291b1\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nYou will now be presented with a login screen. Click the \"Create an account\" link to register. Take note of your username and password, Spinnaker will need them later. Now you can turn off allowing users to register as you can add them manually from the control panel. The Jenkins API is now enabled.\n\n###Setup deb repo\n\nThere are several options you can use to setup your private deb repo. This involves leveraging a tool to create the file structure and format for your .deb packages. You will also need to serve them publicly on the internet so they can be installed.\n\n#####deb-s3\n\n[deb-s3](https://github.com/krobertson/deb-s3) is a ruby gem that allows you to create a publish your packages directly to an s3 bucket. The nice part about this is that you do not have to concern yourself with setting up ports or configuring a web server. S3 handles everything for us.\n\nFirst create a new s3 bucket to hold your packages, take note of the name and region.\n\nNext edit the properties of your bucket and turn on static website hosting.\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/dzK4KjTrTmScMZINAHDi_s3.png\",\n        \"s3.png\",\n        \"1686\",\n        \"756\",\n        \"#549ff0\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\nWe will now install deb-s3 on our Jenkins server.\n\nLog in to your Jenkins user (you may need to add it to your sudoers file) and install Ruby and bundler:\n\n~~~\n$ sudo apt-get install software-properties-common\n$ sudo apt-add-repository ppa:brightbox/ruby-ng\n$ sudo apt-get update\n$ sudo apt-get install build-essential ruby2.2 ruby2.2-dev zlib1g-dev liblzma-dev\n$ sudo gem install bundler\n~~~\nnow install the deb-s3 gem globally\n~~~\n$ sudo gem install deb-s3\n~~~\nThe address of your repo will now be `http://BUCKET-NAME.s3-website-REGION-NAME.amazonaws.com trusty main`\n\n\n####Aptly\n\n[Aptly](http://www.aptly.info/) is a tool that easily allows us to manage and publish the packages to the local filesystem. After we install and configure the tool, nginx will host the repository on our jenkins server so it can be consumed during the bake process. Since nginx will run on port 9999 it is important that this port on your Jenkins server will be accessible from the internet.\n\nThe following will install aptly to the jenkins user home directory so our jobs can easily use it. We will also create our repo so the jobs can easily add packages.\n\n~~~\n$ sudo su - jenkins\n$ cd ~\n$ wget https://dl.bintray.com/smira/aptly/0.9.5/debian-squeeze-x64/aptly\n$ chmod +x aptly\n~~~\n\nCreate our repo named \"hello\"\n\n~~~\n$ ./aptly repo create hello\n~~~\n\nWe will now publish our (currently empty) repo and setup nginx to host it on port 9999.\n\n~~~\n$ ./aptly publish repo -architectures=\"amd64\" -component=main -distribution=trusty -skip-signing=true hello\n~~~\n###Setup Nginx to serve aptly deb repo\nInstall and configure nginx\n\n~~~\n$ sudo apt-get install nginx\n$ sudo vim /etc/nginx/sites-enabled/default\n~~~\n\nContents of /etc/nginx/sites-enabled/default:\n\n~~~\nserver {\n        listen 9999 default_server;\n        listen [::]:9999 default_server ipv6only=on;\n        root /var/lib/jenkins/.aptly/public;\n        index index.html index.htm;\n        server_name localhost;\n        location / {\n                try_files $uri $uri/ =404;\n        }\n}\n~~~\n\nStart nginx `sudo service nginx start`\n\nthe address of the repo will be `http://JENKINS-SERVER:9999 trusty main`\n\n###Fork example application\n\nWe have set up an example application with a gradle.build ready to package your app for spinnaker deployment. Fork [https://github.com/kenzanlabs/hello-karyon-rxnetty](https://github.com/kenzanlabs/hello-karyon-rxnetty) via the github UI so you can make changes and see them flow through the Spinnaker pipeline.\n\n###Create Jenkins Jobs\n\nWe will now setup our jenkins jobs for spinnaker to use.\n\n1. Polling Job\n\nThe first is a simple job that polls our git repo for changes. Spinnaker has no knowledge of our repo location, so it needs a way to trigger a pipeline automatically when code is pushed. (A pipeline is a set of actions that handle the application delivery) Spinnaker will poll our polling job and kick off a pipeline when it detects a fresh run.\n\n* Ensure the Jenkins git plugin is enabled and create a new freesyle Project named \"Hello Poll\".\n* Add your app fork git address.\n* Under build triggers check \"Poll SCM\" and enter `* * * * *` for Jenkins to poll once a minute. You can now save the job.\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/T3V7FvrURoiMxTWuHJyI_jenkins2.png\",\n        \"jenkins2.png\",\n        \"1478\",\n        \"1736\",\n        \"#5cacfa\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n2. Build and Publish Job\n\nThis job will be responsible for building and publishing our package, along with passing the package and version name to Spinnaker.\n\n* Create a new freestyle job named \"HelloBuild\".\n* Add the git url for your application fork\n* Add a build step for \"execute shell\"\n* In the textbox, cleanup prior builds and execute the packDeb task `./gradlew clean packDeb`\n* If you used deb-s3 for your repo, add the following: \n  * `deb-s3 upload --bucket BUCKETNAME --arch amd64 --codename trusty --preserve-versions true build/distributions/*.deb`\n* If you used aptly for your repo, add the following: \n > `~/aptly repo add -force-replace hello build/distributions/*.deb\n > ~/aptly publish update -force-overwrite -architectures=\"amd64\" -skip-signing=true trusty`\n* Add a post-build action: \"Archive the artifacts\" with `build/distributions/*.deb` as the directory. This allows our deb package name to be passed to spinnaker.\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/IlYtgmKXRVCm46jNJE8d_build.png\",\n        \"build.png\",\n        \"759\",\n        \"1144\",\n        \"#4f6784\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n\n##Configure Spinnaker\n\nSSH to your Spinnaker instance by tunneling the needed ports. Tunneling ensures that Spinnaker is not accessible from the internet outside of your ssh connection. This is **very important** because anyone who has access to Spinnaker can do anything your cloud account can do.\n\nThe ports needed:\n\n* 9000: html/js UI (Deck)\n* 8084: API entrypoint (Gate)\n* 8087: Image bakery (Rosco)\n\n~~~\nssh -i yourkey.pem -L 9000:127.0.0.1:9000 -L 8084:127.0.0.1:8084 -L 8087:127.0.0.1:8087 ubuntu:::at:::instanceip\n~~~\n\nSpinnaker will be accessible on [http://localhost:9000](http://localhost:9000).\n\n###Jenkins Integration\n\nBefore we can begin setting up our workflow, we need to edit the Spinnaker configuration to allow it to communicate with our Jenkins server.\n\nBegin by shutting down Spinnaker. Spinnaker configuration is stored in memory so we need to reload it every time we make a change. You can now edit the master configuration file:\n\n~~~\n# stop spinnaker\n# vim /opt/spinnaker/config/spinnaker-local.yml\n~~~\n\nScroll down to jenkins section and add your url, username and password from above\n\n~~~\n  jenkins:\n    defaultMaster:\n      name: Jenkins # The display name for this server\n      baseUrl: http://jenkins-server:8080\n      username: jenkinsuser\n      password: jenkinspassword\n~~~\n\nYou also need to enable igor, the service that communicates with the jenkins api.\n\n~~~\nigor:\n    enabled: true\n~~~\n\n###Deb Repository\n\nThe last configuration step is to add our deb repository address to the Rosco config. When Spinnaker is baking the application image, it will add this address to the sources list so it can `apt-get install` the deb package. For this reason it is important that port 9000 is open on our Jenkins server which hosts the repo.\n\n~~~\n# vim /opt/rosco/config/rosco.yml\n~~~\nAdd your repo address from above. For example if we used deb-s3:\n\n~~~\ndebianRepository: http://BUCKET-NAME.s3-website-REGION-NAME.amazonaws.com trusty main\n~~~\nWe can now start Spinnaker and start configuring our workflow. `# start spinnaker`\n\n##Create Spinnaker application and resources\n\nThe concept of an application allows us to group our resources and pipelines in a logical way. This makes it easy to manage our app in a single place instead of searching for items buried in menus.\n\n* Visit http://localhost:9000 and click the actions button -> create application.\n* Fill out the information, naming it \"hello\" and click save. We are now ready to add resources to our app.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/0i135ajLTTybra8MxFCq_create.png\",\n        \"create.png\",\n        \"1038\",\n        \"846\",\n        \"#596e82\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n\n###Create security group\n\nNow we will create a security group to allow access to our application. Spinnaker only allows you to attach ingress sources based on another security group, so we first must create a base security group via the aws console to allow traffic on port 8080.\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/vCrPy5AURDWrwUZxTDhW_group1.png\",\n        \"group1.png\",\n        \"1003\",\n        \"544\",\n        \"#405e81\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n\nNow we can use this group as an inbound rule for our application security group. Click the security groups tab and add a new group.\n\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/hXeKfK4SSGAER0NuFBRM_group2.png\",\n        \"group2.png\",\n        \"1110\",\n        \"850\",\n        \"#597187\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n\nSelect our group as ingress source\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/6sPtJxDQ6OoiD6bPiP4R_group3.png\",\n        \"group3.png\",\n        \"1110\",\n        \"850\",\n        \"#597187\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n\n###Create load balancer\n\nThe load balancer will be the entry-point to our application scaling group. Click the load balancers tab and add it.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/ZtHWZISV6bgLxwYJDGQ0_group4.png\",\n        \"group4.png\",\n        \"1126\",\n        \"950\",\n        \"#243e48\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n##Setup Spinnaker Pipeline\n\nWe now have the necessary resources to begin pipeline creation. A pipeline is a group of actions that handle the complete lifecycle of our deployment. It is also a great centralized place to monitor the status of each stage instead of hopping between jenkins or the aws console.\n\nOur pipeline is triggered by polling our Jenkins server to see if our code has updated. We then create two stages.\n\nClick the pipelines tab and add a new pipeline.\n\n###Pipeline trigger\n\nAdd a trigger and select \"jenkins job\" then we can select our jenkins server and choose the \"hello poll\" job. Spinnaker will poll jenkins for a successful run of this job. We know that if it ran then there is new code to deploy from github\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/jhi31gsGSXWF3qY2Hnqp_pipe1.png\",\n        \"pipe1.png\",\n        \"1117\",\n        \"921\",\n        \"#4c657e\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n\n###Build and package stage\n\nThe first stage in our pipeline will be to build and package our app. This also published our deb to our repository for baking. Choose Jenkins for type and select our \"hellobuild\" job.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/ZboJ8cQKyNeE9AurMVcA_pipe2.png\",\n        \"pipe2.png\",\n        \"1131\",\n        \"1137\",\n        \"#4a6780\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n\n###Bake stage\n\nThe next stage will bake our application. \"Baking\" refers to booting up an instance, installing our application package, and saving the os image for launching. All of this is handled by [packer](http://packer.io). Because our build stage returns the name of our deb artifact and knows our repo address, we simply need to select the region(s) and add our application package name. We can also take advantage of the async features of spinnaker and do a multi-region bake.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/sz1rlPC4RcawcQbC8x3O_bake.png\",\n        \"bake.png\",\n        \"1131\",\n        \"1137\",\n        \"#4d6882\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n\n###Deploy stage\n\nSpinnaker will automatically pass our baked image id to the deploy stage. This is where we set up our server group to be deployed to a cluster.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/Wa2w0ElbRasgRfAtVQPw_pipe4.png\",\n        \"pipe4.png\",\n        \"1314\",\n        \"1137\",\n        \"#4b667f\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\nClick \"add server group\" and configure the server group.\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/yGILeBAxQjeHeb6f1ZPc_pipe5.png\",\n        \"pipe5.png\",\n        \"1187\",\n        \"870\",\n        \"#596f83\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\nOur app is fairly lightweight so t2.micro will be fine for instance type.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/j9qCCROjTBO6PigsAD0w_pipe6.png\",\n        \"pipe6.png\",\n        \"1187\",\n        \"870\",\n        \"#596f83\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\nChoose two instances so we can be sure they our load balanced correctly. Our application will display the instance id so we can easily confirm this.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/iKq06UxsTmGALVuYmeJI_pipe7.png\",\n        \"pipe7.png\",\n        \"1187\",\n        \"870\",\n        \"#597186\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n##Triggering the pipeline\n\nWe can trigger our pipeline several ways. The first way is to simply push to our github repo. Jenkins will detect this and run our polling job, which Spinnaker will detect and kick off our pipeline.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/XNIDn9s0SRiXY0DPkKAq_pipe8.png\",\n        \"pipe8.png\",\n        \"2334\",\n        \"1406\",\n        \"#385a6f\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\nWe then can see our pipeline progress to the bake stage.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/XTtxTWEPTgyOtKBgqi7r_pipe9.png\",\n        \"pipe9.png\",\n        \"2254\",\n        \"1330\",\n        \"#395b6c\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\nFinally we reach our deploy stage where our server group is created.\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/e3w0ZpDT8GxHieNL7rY8_pipe10.png\",\n        \"pipe10.png\",\n        \"2772\",\n        \"1526\",\n        \"#3c596e\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\nWe can also manually trigger the pipeline by clicking the \"start manual execution\" button. Then we can select a specific build of our app from Jenkins for Spinnaker to use.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/ftbR6GLrQMm09JGCkIRD_pipe11.png\",\n        \"pipe11.png\",\n        \"1134\",\n        \"706\",\n        \"#613129\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]","excerpt":"","slug":"hello-spinnaker","type":"basic","title":"Hello Deployment"}
#An Introduction to Spinnaker: Hello Deployment This guide will run through the workflow of setting up an example application deployment with [Spinnaker](http://spinnaker.io/). It assumes you already have Spinnaker up and running on AWS or GCE. A guide for installation can be found [Installing and Running Spinnaker](doc:installing-and-running-spinnaker) . Below is a diagram of the workflow we will setup. [block:image] { "images": [ { "image": [ "https://files.readme.io/06CDzZS2RhmmJ0PaMFgy_flow.png", "flow.png", "616", "600", "#c63b3c", "" ] } ] } [/block] ##Setup Jenkins Jenkins is a powerful continuous integration server that allows us to do several important things: * Poll our Github repository for changes so Spinnaker knows when to run a pipeline. * Compile and build our example application into a .deb package so Spinnaker can bake it on an image. Spinnaker expects all applications to be deployed as deb packages. ###Installing Jenkins If you already have a Jenkins server, you can skip this step. However be sure that port 9999 on the server is open to the internet if you plan to host your deb repository there. Also be sure that your Jenkins port is accessible by your Spinnaker instance. SSH into your instance and run the following: ~~~ $ sudo apt-get update $ sudo apt-get upgrade $ sudo apt-get install openjdk-7-jdk $ wget -q -O - https://jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add - $ sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list' $ sudo apt-get update $ sudo apt-get install jenkins git $ sudo service jenkins start ~~~ Visit port :8080 on your instance and you should see Jenkins startup and present the dashboard. ###Enable Jenkins API Spinnaker communicates with Jenkins by using its REST API. However the API is not enabled by default. To enable it we first must enable global security (which is a good idea anyway). Click "Manage Jenkins" then "Configure Global Security". Under Access Control check "Jenkins own database" and "allow users to sign up". Under authorization check "Logged-in users can do anything" and save. [block:image] { "images": [ { "image": [ "https://files.readme.io/AP5tbGUOQb6jKbdpEEvw_jenkins1.png", "jenkins1.png", "727", "824", "#5291b1", "" ] } ] } [/block] You will now be presented with a login screen. Click the "Create an account" link to register. Take note of your username and password, Spinnaker will need them later. Now you can turn off allowing users to register as you can add them manually from the control panel. The Jenkins API is now enabled. ###Setup deb repo There are several options you can use to setup your private deb repo. This involves leveraging a tool to create the file structure and format for your .deb packages. You will also need to serve them publicly on the internet so they can be installed. #####deb-s3 [deb-s3](https://github.com/krobertson/deb-s3) is a ruby gem that allows you to create a publish your packages directly to an s3 bucket. The nice part about this is that you do not have to concern yourself with setting up ports or configuring a web server. S3 handles everything for us. First create a new s3 bucket to hold your packages, take note of the name and region. Next edit the properties of your bucket and turn on static website hosting. [block:image] { "images": [ { "image": [ "https://files.readme.io/dzK4KjTrTmScMZINAHDi_s3.png", "s3.png", "1686", "756", "#549ff0", "" ] } ] } [/block] We will now install deb-s3 on our Jenkins server. Log in to your Jenkins user (you may need to add it to your sudoers file) and install Ruby and bundler: ~~~ $ sudo apt-get install software-properties-common $ sudo apt-add-repository ppa:brightbox/ruby-ng $ sudo apt-get update $ sudo apt-get install build-essential ruby2.2 ruby2.2-dev zlib1g-dev liblzma-dev $ sudo gem install bundler ~~~ now install the deb-s3 gem globally ~~~ $ sudo gem install deb-s3 ~~~ The address of your repo will now be `http://BUCKET-NAME.s3-website-REGION-NAME.amazonaws.com trusty main` ####Aptly [Aptly](http://www.aptly.info/) is a tool that easily allows us to manage and publish the packages to the local filesystem. After we install and configure the tool, nginx will host the repository on our jenkins server so it can be consumed during the bake process. Since nginx will run on port 9999 it is important that this port on your Jenkins server will be accessible from the internet. The following will install aptly to the jenkins user home directory so our jobs can easily use it. We will also create our repo so the jobs can easily add packages. ~~~ $ sudo su - jenkins $ cd ~ $ wget https://dl.bintray.com/smira/aptly/0.9.5/debian-squeeze-x64/aptly $ chmod +x aptly ~~~ Create our repo named "hello" ~~~ $ ./aptly repo create hello ~~~ We will now publish our (currently empty) repo and setup nginx to host it on port 9999. ~~~ $ ./aptly publish repo -architectures="amd64" -component=main -distribution=trusty -skip-signing=true hello ~~~ ###Setup Nginx to serve aptly deb repo Install and configure nginx ~~~ $ sudo apt-get install nginx $ sudo vim /etc/nginx/sites-enabled/default ~~~ Contents of /etc/nginx/sites-enabled/default: ~~~ server { listen 9999 default_server; listen [::]:9999 default_server ipv6only=on; root /var/lib/jenkins/.aptly/public; index index.html index.htm; server_name localhost; location / { try_files $uri $uri/ =404; } } ~~~ Start nginx `sudo service nginx start` the address of the repo will be `http://JENKINS-SERVER:9999 trusty main` ###Fork example application We have set up an example application with a gradle.build ready to package your app for spinnaker deployment. Fork [https://github.com/kenzanlabs/hello-karyon-rxnetty](https://github.com/kenzanlabs/hello-karyon-rxnetty) via the github UI so you can make changes and see them flow through the Spinnaker pipeline. ###Create Jenkins Jobs We will now setup our jenkins jobs for spinnaker to use. 1. Polling Job The first is a simple job that polls our git repo for changes. Spinnaker has no knowledge of our repo location, so it needs a way to trigger a pipeline automatically when code is pushed. (A pipeline is a set of actions that handle the application delivery) Spinnaker will poll our polling job and kick off a pipeline when it detects a fresh run. * Ensure the Jenkins git plugin is enabled and create a new freesyle Project named "Hello Poll". * Add your app fork git address. * Under build triggers check "Poll SCM" and enter `* * * * *` for Jenkins to poll once a minute. You can now save the job. [block:image] { "images": [ { "image": [ "https://files.readme.io/T3V7FvrURoiMxTWuHJyI_jenkins2.png", "jenkins2.png", "1478", "1736", "#5cacfa", "" ] } ] } [/block] 2. Build and Publish Job This job will be responsible for building and publishing our package, along with passing the package and version name to Spinnaker. * Create a new freestyle job named "HelloBuild". * Add the git url for your application fork * Add a build step for "execute shell" * In the textbox, cleanup prior builds and execute the packDeb task `./gradlew clean packDeb` * If you used deb-s3 for your repo, add the following: * `deb-s3 upload --bucket BUCKETNAME --arch amd64 --codename trusty --preserve-versions true build/distributions/*.deb` * If you used aptly for your repo, add the following: > `~/aptly repo add -force-replace hello build/distributions/*.deb > ~/aptly publish update -force-overwrite -architectures="amd64" -skip-signing=true trusty` * Add a post-build action: "Archive the artifacts" with `build/distributions/*.deb` as the directory. This allows our deb package name to be passed to spinnaker. [block:image] { "images": [ { "image": [ "https://files.readme.io/IlYtgmKXRVCm46jNJE8d_build.png", "build.png", "759", "1144", "#4f6784", "" ] } ] } [/block] ##Configure Spinnaker SSH to your Spinnaker instance by tunneling the needed ports. Tunneling ensures that Spinnaker is not accessible from the internet outside of your ssh connection. This is **very important** because anyone who has access to Spinnaker can do anything your cloud account can do. The ports needed: * 9000: html/js UI (Deck) * 8084: API entrypoint (Gate) * 8087: Image bakery (Rosco) ~~~ ssh -i yourkey.pem -L 9000:127.0.0.1:9000 -L 8084:127.0.0.1:8084 -L 8087:127.0.0.1:8087 ubuntu@instanceip ~~~ Spinnaker will be accessible on [http://localhost:9000](http://localhost:9000). ###Jenkins Integration Before we can begin setting up our workflow, we need to edit the Spinnaker configuration to allow it to communicate with our Jenkins server. Begin by shutting down Spinnaker. Spinnaker configuration is stored in memory so we need to reload it every time we make a change. You can now edit the master configuration file: ~~~ # stop spinnaker # vim /opt/spinnaker/config/spinnaker-local.yml ~~~ Scroll down to jenkins section and add your url, username and password from above ~~~ jenkins: defaultMaster: name: Jenkins # The display name for this server baseUrl: http://jenkins-server:8080 username: jenkinsuser password: jenkinspassword ~~~ You also need to enable igor, the service that communicates with the jenkins api. ~~~ igor: enabled: true ~~~ ###Deb Repository The last configuration step is to add our deb repository address to the Rosco config. When Spinnaker is baking the application image, it will add this address to the sources list so it can `apt-get install` the deb package. For this reason it is important that port 9000 is open on our Jenkins server which hosts the repo. ~~~ # vim /opt/rosco/config/rosco.yml ~~~ Add your repo address from above. For example if we used deb-s3: ~~~ debianRepository: http://BUCKET-NAME.s3-website-REGION-NAME.amazonaws.com trusty main ~~~ We can now start Spinnaker and start configuring our workflow. `# start spinnaker` ##Create Spinnaker application and resources The concept of an application allows us to group our resources and pipelines in a logical way. This makes it easy to manage our app in a single place instead of searching for items buried in menus. * Visit http://localhost:9000 and click the actions button -> create application. * Fill out the information, naming it "hello" and click save. We are now ready to add resources to our app. [block:image] { "images": [ { "image": [ "https://files.readme.io/0i135ajLTTybra8MxFCq_create.png", "create.png", "1038", "846", "#596e82", "" ] } ] } [/block] ###Create security group Now we will create a security group to allow access to our application. Spinnaker only allows you to attach ingress sources based on another security group, so we first must create a base security group via the aws console to allow traffic on port 8080. [block:image] { "images": [ { "image": [ "https://files.readme.io/vCrPy5AURDWrwUZxTDhW_group1.png", "group1.png", "1003", "544", "#405e81", "" ] } ] } [/block] Now we can use this group as an inbound rule for our application security group. Click the security groups tab and add a new group. [block:image] { "images": [ { "image": [ "https://files.readme.io/hXeKfK4SSGAER0NuFBRM_group2.png", "group2.png", "1110", "850", "#597187", "" ] } ] } [/block] Select our group as ingress source [block:image] { "images": [ { "image": [ "https://files.readme.io/6sPtJxDQ6OoiD6bPiP4R_group3.png", "group3.png", "1110", "850", "#597187", "" ] } ] } [/block] ###Create load balancer The load balancer will be the entry-point to our application scaling group. Click the load balancers tab and add it. [block:image] { "images": [ { "image": [ "https://files.readme.io/ZtHWZISV6bgLxwYJDGQ0_group4.png", "group4.png", "1126", "950", "#243e48", "" ] } ] } [/block] ##Setup Spinnaker Pipeline We now have the necessary resources to begin pipeline creation. A pipeline is a group of actions that handle the complete lifecycle of our deployment. It is also a great centralized place to monitor the status of each stage instead of hopping between jenkins or the aws console. Our pipeline is triggered by polling our Jenkins server to see if our code has updated. We then create two stages. Click the pipelines tab and add a new pipeline. ###Pipeline trigger Add a trigger and select "jenkins job" then we can select our jenkins server and choose the "hello poll" job. Spinnaker will poll jenkins for a successful run of this job. We know that if it ran then there is new code to deploy from github [block:image] { "images": [ { "image": [ "https://files.readme.io/jhi31gsGSXWF3qY2Hnqp_pipe1.png", "pipe1.png", "1117", "921", "#4c657e", "" ] } ] } [/block] ###Build and package stage The first stage in our pipeline will be to build and package our app. This also published our deb to our repository for baking. Choose Jenkins for type and select our "hellobuild" job. [block:image] { "images": [ { "image": [ "https://files.readme.io/ZboJ8cQKyNeE9AurMVcA_pipe2.png", "pipe2.png", "1131", "1137", "#4a6780", "" ] } ] } [/block] ###Bake stage The next stage will bake our application. "Baking" refers to booting up an instance, installing our application package, and saving the os image for launching. All of this is handled by [packer](http://packer.io). Because our build stage returns the name of our deb artifact and knows our repo address, we simply need to select the region(s) and add our application package name. We can also take advantage of the async features of spinnaker and do a multi-region bake. [block:image] { "images": [ { "image": [ "https://files.readme.io/sz1rlPC4RcawcQbC8x3O_bake.png", "bake.png", "1131", "1137", "#4d6882", "" ] } ] } [/block] ###Deploy stage Spinnaker will automatically pass our baked image id to the deploy stage. This is where we set up our server group to be deployed to a cluster. [block:image] { "images": [ { "image": [ "https://files.readme.io/Wa2w0ElbRasgRfAtVQPw_pipe4.png", "pipe4.png", "1314", "1137", "#4b667f", "" ] } ] } [/block] Click "add server group" and configure the server group. [block:image] { "images": [ { "image": [ "https://files.readme.io/yGILeBAxQjeHeb6f1ZPc_pipe5.png", "pipe5.png", "1187", "870", "#596f83", "" ] } ] } [/block] Our app is fairly lightweight so t2.micro will be fine for instance type. [block:image] { "images": [ { "image": [ "https://files.readme.io/j9qCCROjTBO6PigsAD0w_pipe6.png", "pipe6.png", "1187", "870", "#596f83", "" ] } ] } [/block] Choose two instances so we can be sure they our load balanced correctly. Our application will display the instance id so we can easily confirm this. [block:image] { "images": [ { "image": [ "https://files.readme.io/iKq06UxsTmGALVuYmeJI_pipe7.png", "pipe7.png", "1187", "870", "#597186", "" ] } ] } [/block] ##Triggering the pipeline We can trigger our pipeline several ways. The first way is to simply push to our github repo. Jenkins will detect this and run our polling job, which Spinnaker will detect and kick off our pipeline. [block:image] { "images": [ { "image": [ "https://files.readme.io/XNIDn9s0SRiXY0DPkKAq_pipe8.png", "pipe8.png", "2334", "1406", "#385a6f", "" ] } ] } [/block] We then can see our pipeline progress to the bake stage. [block:image] { "images": [ { "image": [ "https://files.readme.io/XTtxTWEPTgyOtKBgqi7r_pipe9.png", "pipe9.png", "2254", "1330", "#395b6c", "" ] } ] } [/block] Finally we reach our deploy stage where our server group is created. [block:image] { "images": [ { "image": [ "https://files.readme.io/e3w0ZpDT8GxHieNL7rY8_pipe10.png", "pipe10.png", "2772", "1526", "#3c596e", "" ] } ] } [/block] We can also manually trigger the pipeline by clicking the "start manual execution" button. Then we can select a specific build of our app from Jenkins for Spinnaker to use. [block:image] { "images": [ { "image": [ "https://files.readme.io/ftbR6GLrQMm09JGCkIRD_pipe11.png", "pipe11.png", "1134", "706", "#613129", "" ] } ] } [/block]