{"componentChunkName":"component---src-templates-generic-template-js","path":"/lectures/lecture6-devops","webpackCompilationHash":"041090671d318979d692","result":{"data":{"markdownRemark":{"htmlAst":{"type":"root","children":[{"type":"element","tagName":"h2","properties":{"id":"deployment-closing-the-loop"},"children":[{"type":"element","tagName":"a","properties":{"href":"#deployment-closing-the-loop","ariaLabel":"deployment closing the loop permalink","className":["anchor"]},"children":[{"type":"element","tagName":"svg","properties":{"ariaHidden":"true","focusable":"false","height":"16","version":"1.1","viewBox":"0 0 16 16","width":"16"},"children":[{"type":"element","tagName":"path","properties":{"fillRule":"evenodd","d":"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"},"children":[]}]}]},{"type":"text","value":"Deployment: Closing the loop"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Programs that are never deployed (for whatever relevant definition of deployed)\nhave not solved their motivating problem. Thus we need to get to deployment!"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"To do so we must first answer several questions:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Are we ready? Is our application in a working state?\nDo we have the necessary resources, e.g. webservers, databases, etc. to\nactually deploy our application?"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"How do we actually deploy our application to its production setting?"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"We will be at our most efficient when we minimize the \"delta\" between the\ncurrent \"version\" of the application and the next \"version\" of the application.\nWhy? Small integrations (e.g. of a single new feature) into the master branch\nwill be fast and predictable. Bugs will hopefully be identified sooner, in a\nsmaller subset of the codebase (you only changed a small part of the system),\nwhile the changes are still fresh in your mind."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"To do so we will practice "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Continuous Integration"}]},{"type":"text","value":" (CI), that is merging small\nchanges frequently instead of merging a large change at the end of the\ndevelopment cycle."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Similarly we will be most efficient when we can automatically provision the\nnecessary compute resources and automatically deploy our application to those\nresources. To do so we will practice a \"DevOps culture\", that is the tight\nintegration of development and operations, to facilitate easy (and frequent)\ndeployment."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"In both cases the goal is to make what was a rare, and thus a difficult and\nscary process, routine."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{"id":"continuous-integration-with-travis-ci-and-continuous-delivery"},"children":[{"type":"element","tagName":"a","properties":{"href":"#continuous-integration-with-travis-ci-and-continuous-delivery","ariaLabel":"continuous integration with travis ci and continuous delivery permalink","className":["anchor"]},"children":[{"type":"element","tagName":"svg","properties":{"ariaHidden":"true","focusable":"false","height":"16","version":"1.1","viewBox":"0 0 16 16","width":"16"},"children":[{"type":"element","tagName":"path","properties":{"fillRule":"evenodd","d":"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"},"children":[]}]}]},{"type":"text","value":"Continuous Integration (with Travis CI) and Continuous Delivery"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://martinfowler.com/articles/continuousIntegration.html#PracticesOfContinuousIntegration"},"children":[{"type":"text","value":"Key practices of Continuous\nIntegration:"}]},{"type":"text","value":":"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Maintain a single source repository"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Automate the Build (and the Build becomes a proper noun)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Make your build self-testing"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Everyone commits to the mainline every day"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Every commit should build the mainline on an integration machine"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Fix broken builds immediately"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Keep the build fast"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Test in a clone of the production environment"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Make it easy for anyone to get the latest executable"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Everyone can see what's happening"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Automate deployment"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"We will use a combination of convention and tooling to support our CI workflow.\nFirst convention: we will treat the master branch as the deployable branch. We\nwant to then to keep it \"green\", that is make sure all commits build and all\ntests pass. We will develop new features on \"feature branches\" to segregate those changes until they are complete and ready to be integrated into the master branch (i.e. all tests pass, etc.)."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"A quick summary of our workflow:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ol","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Create a feature branch, e.g. "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"git checkout -b my-feature"}]},{"type":"text","value":" (combining branch\ncreation with "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"-b"}]},{"type":"text","value":" and checkout)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Edit, add, commit ... (with tests!)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Make sure all tests pass"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"If you are working alone you can \"integrate\" your new feature back into the master branch with:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ol","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"git checkout master"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"git merge my-feature"}]}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"But we are rarely working alone. On a team we need to make sure we stay in sync\nand create opportunities to get a second pair of eyes on our code (i.e. create\nopportunities for code review). "}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ol","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"git pull origin master"}]},{"type":"text","value":" to fetch changes in upstream master branch and\nmerge them into your feature branch (note that this doesn't update your\nlocal master branch). Resolve any conflicts and make sure tests pass."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"git push origin my-feature"}]},{"type":"text","value":" to make your changes visible to your teammates"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Create a pull request on GitHub with your changes to obtain feedback.\nDepending on the review, revise before merge or withdraw request."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"After a successful code review merge your pull request on GitHub and update your local repository (see the "},{"type":"element","tagName":"a","properties":{"href":"practial-deploy-cra.html"},"children":[{"type":"text","value":"practical"}]},{"type":"text","value":" for more detail):"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"git checkout master\ngit pull --prune\ngit branch -d my-feature"}]}]}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"How do the tools support this workflow? We will use "},{"type":"element","tagName":"a","properties":{"href":"https://travis-ci.com/"},"children":[{"type":"text","value":"Travis\nCI"}]},{"type":"text","value":" to automate the build and testing. We add a YAML\nfile, "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":".travis.yml"}]},{"type":"text","value":", to our repository that specifies how to build and test the\napplication. If all the steps complete without an error, then our build\nsucceeds and is \"green\". If the tests fail there is a problem that needs to be\nfixed before we are ready to integrate the pull request. This file ensure that\nthe application always builds in a consistent environment(s) that is similar to\nthe eventual production environment."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"When we enable a repository in Travis, the service monitors the repository for\ncommits and pull requests. For the latter, Travis will build and test the code\nthat "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"would be"}]},{"type":"text","value":" created by the pull request, ensuring it is \"safe\" to merge.\nTravis will notify the authors and update the pull request with the results of\nthe build so that \"everyone can see what is happening\"."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"There are two related\n"},{"type":"element","tagName":"a","properties":{"href":"https://martinfowler.com/bliki/ContinuousDelivery.html"},"children":[{"type":"text","value":"concepts"}]},{"type":"text","value":":"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Continuous Deployment"}]},{"type":"text","value":": Every change automatically gets put into production,\nand thus there are many production deployments each day."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Continuous Delivery"}]},{"type":"text","value":": An extension of CI in which SW is deployable\nthroughout its lifecycle, the team prioritizes keeping SW deployable, and it\nis possible to automatically deploy SW on demand."}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"We will be aiming for a Continuous Delivery-like workflow in which our\napplications start and stay deployable throughout the development process. As\nwith CI, this reduces the complexity (and risk) of deployment by enabling us to\ndo so in small increments. And Continuous Delivery facilitates getting user\nfeedback by frequently getting working SW in front of real users. Although to\nmitigate risk companies will often first deploy for a small subset of users."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h3","properties":{"id":"devops-with-heroku"},"children":[{"type":"element","tagName":"a","properties":{"href":"#devops-with-heroku","ariaLabel":"devops with heroku permalink","className":["anchor"]},"children":[{"type":"element","tagName":"svg","properties":{"ariaHidden":"true","focusable":"false","height":"16","version":"1.1","viewBox":"0 0 16 16","width":"16"},"children":[{"type":"element","tagName":"path","properties":{"fillRule":"evenodd","d":"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"},"children":[]}]}]},{"type":"text","value":"DevOps (with Heroku)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"What is DevOps? Like Agile, DevOps is not "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"a"}]},{"type":"text","value":" process or approach but instead a\nset of values (or a culture or philosophy). There is no one definition, but\ngenerally its core principles\n"},{"type":"element","tagName":"a","properties":{"href":"https://landing.google.com/sre/book/chapters/introduction.html"},"children":[{"type":"text","value":"are"}]},{"type":"text","value":":"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Involvement of the operations function in each phase of a system’s design and\ndevelopment, "}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Heavy reliance on automation versus human effort, "}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"The application of engineering practices and tools to operations tasks"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"In furtherance of the first principle, in some settings there is a single team\nthat is responsible for the entire application lifecycle from development to\ntesting to deployment. The role of automation is to improve efficiency, reduce\nthe chance for human error and provide always up-to-date documentation of the\nworkflow."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"The cloud has made large-scale HW widely available with minimal barrier to\nentry. Providers like AWS offer Infrastructure-as-a-Service, that is you can\nrent HW and services by the hour, GB, etc; all provisioned via APIs. You are\nstill responsible for connecting (in a virtual sense) and administering those\nresources - a non-trivial task. The ability to programmatically provision\nresources (the corresponding opportunities for automation) has accelerated the\nadoption of DevOps approaches."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"There are several common architectural \"design patterns\" for web applications,\ne.g. the "},{"type":"element","tagName":"a","properties":{"href":"https://en.wikipedia.org/wiki/Multitier_architecture#Three-tier_architecture"},"children":[{"type":"text","value":"\"Three Tier\nArchitecture\""}]},{"type":"text","value":".\nThat commonality can be \"factored out\" to create \"higher level\" platforms for\ndeploying specific kinds of applications, often termed Platform-as-a-Service (PaaS)."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.heroku.com"},"children":[{"type":"text","value":"Heroku"}]},{"type":"text","value":" is one of the best known of these PaaS\nofferings. Heroku makes it easy to allocate resources, e.g. computational\nunits, databases, etc. and then automatically deploy your application with a\npush to a Git repository."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Heroku itself runs on top of Amazon AWS. Initially there was a considerable gap\nbetween the interface Heroku offered and what AWS offered. Increasingly though\nAWS and other IaaS providers are offering more PaaS-like features, bridging\nthat gap."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Heroku offers a very capable free tier that we will use in class for production\ndeployment (alternately you can use "},{"type":"element","tagName":"a","properties":{"href":"http://basin.cs.middlebury.edu"},"children":[{"type":"text","value":"http://basin.cs.middlebury.edu"}]},{"type":"text","value":")."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"You could deploy the CRA color picker to Heroku with (from within your\napplication directory):"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"heroku create --buildpack https://github.com/mars/create-react-app-buildpack.git\ngit push heroku master"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"The first command creates the Heroku app (including defining a "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"heroku"}]},{"type":"text","value":" remote\nin our Git repository. Here we use a specific\n"},{"type":"element","tagName":"a","properties":{"href":"https://devcenter.heroku.com/articles/buildpacks"},"children":[{"type":"text","value":"\"buildpack\""}]},{"type":"text","value":", customized to\ndeploy CRA apps. \"Buildpacks are responsible for transforming deployed code\ninto a slug, which can then be executed on a dyno.\" The "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"push"}]},{"type":"text","value":" actually deploys\nyour application! "}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"In a more complex application, we may allocate additional resources, like a\ndatabase, in between creating the application and deploying it. "}]}],"data":{"quirksMode":false}},"frontmatter":{"path":"/lectures/lecture6-devops","title":"Lecture 6 - DevOps","name":"Lecture 6 - DevOps"},"parent":{"__typename":"File","id":"5e1bcbf4-c102-5040-803e-35398b9fcc4f","name":"lecture6-devops","modifiedTime":"Sep 26 2019 04:22"}}},"pageContext":{"isCreatedByStatefulCreatePages":false}}}