{"action":"created","comment":{"url":"https://api.github.com/repos/codurance/site/pulls/comments/54522831","id":54522831,"diff_hunk":"@@ -0,0 +1,179 @@\n+---\n+layout: post\n+name: docker-meets-continuous-deployment\n+title: Docker meets Continuous Deployment\n+date: 2016-03-01 00:00:00 +00:00\n+author: Robert Firek\n+image:\n+    src: /assets/img/custom/blog/2016-03-01-docker-meets-continuous-deployment.png\n+    attribution:\n+        text: Track icon by Freepik (CC 3.0 BY)\n+        href: http://www.freepik.com\n+tags:\n+- Continuous Deployment\n+- Docker\n+- TeamCity\n+--- \n+\n+About one year ago I had a first contact with Docker. This new kind on the block promised to relieve our poor computers \n+of installation of all tools, languages, dependencies and operating systems. Isolated run environments emerged on developers computers.\n+\n+A conservative approach of my ops teammates didn't change my joy of using Docker. Despite many people described Docker\n+as tool writen by developers for development our industry found new ways of using images and containers. Images of our \n+applications and services became units of deployment for tool like  Kubernetes, Docker Swarm or Marathon.\n+\n+But... How this images appear in these tools?\n+\n+## Set The Scene\n+\n+From developers perspective any application is manifested by a code. There is long way before we finally find some place on a production environment.\n+To show this process we need small application. Our application is going to expose some HTTP API which we are going to use after the deployment. \n+Let's assume that will are going to use **Gradle** to build the application and **TeamCity** as build automation tool.\n+\n+On each **TeamCity** build agent we should have installed **Docker**. We will also use this machine to deploy our application.\n+In the real project probably you don't want to do that, but the deployment phase can be changed to fit better to your environment.\n+ \n+## Build Application\n+\n+We need to build something before we will be able to create any docker image. To do that we need to create the first step in our Continuous Deployment (CD) pipeline. \n+In this step we will download our source code, perform all **test** which can be done on the source code level and produce **artifact** which \n+contains all elements required to start and run our application.\n+\n+This build configuration is not much different then usual step in a common Continuous Deployment pipeline.\n+Alongside common parameters we have to define **artifacts** which will be generated after each execution. We are going to use them as base for next steps in the pipeline \n+\n+In **TeamCity** we define **artifacts** by defining paths to files from working directory (which is created for each run of a configuration).\n+Working directory is combination of files downloaded from a version control system and files generated during execution of build steps.\n+We will define later elements of this directory. \n+\n+We need two artifacts. The first one is `Dockerfile`. We already prepared this file in our source code and it will be stored in `docker` directory.\n+The next file is ***tar*** file which will be generated by our **Gradle** build. It contains script which allows to execute our code and all required libraries. \n+\n+<img src=\"/assets/img/custom/blog/2016-03-01-docker-meets-continuous-deployment/build_config.png\" alt=\"Build Configuration\" title=\"Build Configuration\" class=\"img img-responsive style-screengrab\">\n+\n+Now we are ready to instruct our build configuration how to download our source code. We use github as our code repository.\n+We just have to choose type as *Git* and provide url to our application.\n+\n+<img src=\"/assets/img/custom/blog/2016-03-01-docker-meets-continuous-deployment/build_vcs.png\" alt=\"Version Control Configuration\" title=\"Version Control Configuration\" class=\"img img-responsive style-screengrab\">\n+\n+We have the source code, so we can describe what to do with this code. As I mention before we will **test** our application and generate an **artifact** with executable content.   \n+\n+**TeamCity** have predefined runners for different build tools. In this case we are going to use **Gradle** runner to **test** and **build**. \n+\n+<img src=\"/assets/img/custom/blog/2016-03-01-docker-meets-continuous-deployment/build_step.png\" alt=\"Gradle Step\" title=\"Gradle Step\" class=\"img img-responsive style-screengrab\">\n+\n+Now we can run our build. As result of we should see our **artifacts** in *\"Artifact\"* tab. \n+ \n+<img src=\"/assets/img/custom/blog/2016-03-01-docker-meets-continuous-deployment/build_result.png\" alt=\"Build Result\" title=\"Build Result\" class=\"img img-responsive style-screengrab\">\n+\n+## Release Image\n+\n+Our code is no longer needed. We have all we need to build the docker image. Now we have create our image and **release** with the right version. To simplify our example we are going to use current build number to define an image version.\n+Next we will generate file with this version. This file give us possibility to pass information about version to the next steps.  \n+\n+First, let's take a closer look at `Dockerfile`. We copy to the image all libraries and scripts from `simple_application.tar`. This ***tar*** file already contains all required content, so all we have to do is to use `ADD`. It will automatically *untar* all files in the image. Next we expose port of our HTTP API and we define how we launch our application by adding `ENTRYPOINT` command.  \n+\n+For example our `Dockerfile` can look like as follows: \n+\n+```\n+FROM java:8\n+\n+ADD simple_application.tar .\n+\n+EXPOSE 4567\n+\n+ENTRYPOINT [\"/simple_application/bin/simple_application\"]\n+```\n+\n+Definition of the build configuration is very simple. In the general settings we just define new artifact: `image.version`. We will generate this file in a build step and it will contain an docker image version.\n+\n+<img src=\"/assets/img/custom/blog/2016-03-01-docker-meets-continuous-deployment/release_config.png\" alt=\"Release Configuration\" title=\"Release Configuration\" class=\"img img-responsive style-screengrab\">\n+\n+Without **artifact** we won't be able to build any image. We have to tell our build how to find **artifacts** from **Build** phase. We can do that by defining **Artifact Dependency** in **TeamCity**. We just have to choose build configuration and define files which we want to use in this build.\n+\n+<img src=\"/assets/img/custom/blog/2016-03-01-docker-meets-continuous-deployment/release_artifacts.png\" alt=\"Release Artifact Dependency\" title=\"Release Artifact Dependency\" class=\"img img-responsive style-screengrab\">\n+\n+And finally we have to trigger this build automatically when we pass all **tests** in the previous step. By introducing **Finish Build Trigger** we can start this build just after **TeamCity** successfully finish building the application.  \n+\n+<img src=\"/assets/img/custom/blog/2016-03-01-docker-meets-continuous-deployment/release_trigger.png\" alt=\"Release Trigger\" title=\"Release Trigger\" class=\"img img-responsive style-screengrab\">\n+\n+Now we are ready for release. Three build steps must be introduced: **Build Image**, **Push Image to Repository** and **Save version**. \n+This time we will use different runner type: **Command Line**. We can execute shell script on a build agent. Because we already installed **Docker** on our build agent we can use `docker` command in our shell script.\n+ \n+### Build Image \n+\n+To build image we need to execute the following command: \n+\n+```bash\n+docker build --tag registry.private/simple_application:%build.number% .\n+```\n+Docker's build command will take our `Dockerfile` and build the image tagged as `registry.private/simple_application` and version `%build.number%`. \n+Variable `%build.number%` is build-in **TeamCity** variable which contains current build number.\n+\n+<img src=\"/assets/img/custom/blog/2016-03-01-docker-meets-continuous-deployment/release_step_1.png\" alt=\"Release Build Image Step\" title=\"Release Build Image Step\" class=\"img img-responsive style-screengrab\">\n+\n+### Push Image to Repository\n+\n+The image created in the previous step exists only on the agent machine. To make the image available to others we need to store it in a repository. We can use **Docker Hub**, but in our example we use private repository available under address `repository.private`. We can execute the following command to push the image to the repository.","path":"_posts/2016-03-01-Docker-meets-Continuous-Deployment.md","position":117,"original_position":117,"commit_id":"aff43a4f6b46e27d7f506c4bed9aa682bf394bbb","original_commit_id":"aff43a4f6b46e27d7f506c4bed9aa682bf394bbb","user":{"login":"franziskas","id":5154737,"avatar_url":"https://avatars.githubusercontent.com/u/5154737?v=3","gravatar_id":"","url":"https://api.github.com/users/franziskas","html_url":"https://github.com/franziskas","followers_url":"https://api.github.com/users/franziskas/followers","following_url":"https://api.github.com/users/franziskas/following{/other_user}","gists_url":"https://api.github.com/users/franziskas/gists{/gist_id}","starred_url":"https://api.github.com/users/franziskas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/franziskas/subscriptions","organizations_url":"https://api.github.com/users/franziskas/orgs","repos_url":"https://api.github.com/users/franziskas/repos","events_url":"https://api.github.com/users/franziskas/events{/privacy}","received_events_url":"https://api.github.com/users/franziskas/received_events","type":"User","site_admin":false},"body":"we use a private repository available under the address `repository.private`. We can execute the following command to push the image to the repository:","created_at":"2016-03-01T04:51:32Z","updated_at":"2016-03-01T04:51:32Z","html_url":"https://github.com/codurance/site/pull/138#discussion_r54522831","pull_request_url":"https://api.github.com/repos/codurance/site/pulls/138","_links":{"self":{"href":"https://api.github.com/repos/codurance/site/pulls/comments/54522831"},"html":{"href":"https://github.com/codurance/site/pull/138#discussion_r54522831"},"pull_request":{"href":"https://api.github.com/repos/codurance/site/pulls/138"}}},"pull_request":{"url":"https://api.github.com/repos/codurance/site/pulls/138","id":61178402,"html_url":"https://github.com/codurance/site/pull/138","diff_url":"https://github.com/codurance/site/pull/138.diff","patch_url":"https://github.com/codurance/site/pull/138.patch","issue_url":"https://api.github.com/repos/codurance/site/issues/138","number":138,"state":"open","locked":false,"title":"Docker meets Continuous Deployment blog","user":{"login":"robertfirek","id":3847372,"avatar_url":"https://avatars.githubusercontent.com/u/3847372?v=3","gravatar_id":"","url":"https://api.github.com/users/robertfirek","html_url":"https://github.com/robertfirek","followers_url":"https://api.github.com/users/robertfirek/followers","following_url":"https://api.github.com/users/robertfirek/following{/other_user}","gists_url":"https://api.github.com/users/robertfirek/gists{/gist_id}","starred_url":"https://api.github.com/users/robertfirek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/robertfirek/subscriptions","organizations_url":"https://api.github.com/users/robertfirek/orgs","repos_url":"https://api.github.com/users/robertfirek/repos","events_url":"https://api.github.com/users/robertfirek/events{/privacy}","received_events_url":"https://api.github.com/users/robertfirek/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-03-01T01:39:04Z","updated_at":"2016-03-01T04:51:32Z","closed_at":null,"merged_at":null,"merge_commit_sha":"89e92dfdd15a2359f2f34346b7e71b63298ccc9b","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/codurance/site/pulls/138/commits","review_comments_url":"https://api.github.com/repos/codurance/site/pulls/138/comments","review_comment_url":"https://api.github.com/repos/codurance/site/pulls/comments{/number}","comments_url":"https://api.github.com/repos/codurance/site/issues/138/comments","statuses_url":"https://api.github.com/repos/codurance/site/statuses/aff43a4f6b46e27d7f506c4bed9aa682bf394bbb","head":{"label":"codurance:docker_in_cd_blog","ref":"docker_in_cd_blog","sha":"aff43a4f6b46e27d7f506c4bed9aa682bf394bbb","user":{"login":"codurance","id":5751452,"avatar_url":"https://avatars.githubusercontent.com/u/5751452?v=3","gravatar_id":"","url":"https://api.github.com/users/codurance","html_url":"https://github.com/codurance","followers_url":"https://api.github.com/users/codurance/followers","following_url":"https://api.github.com/users/codurance/following{/other_user}","gists_url":"https://api.github.com/users/codurance/gists{/gist_id}","starred_url":"https://api.github.com/users/codurance/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/codurance/subscriptions","organizations_url":"https://api.github.com/users/codurance/orgs","repos_url":"https://api.github.com/users/codurance/repos","events_url":"https://api.github.com/users/codurance/events{/privacy}","received_events_url":"https://api.github.com/users/codurance/received_events","type":"Organization","site_admin":false},"repo":{"id":38424930,"name":"site","full_name":"codurance/site","owner":{"login":"codurance","id":5751452,"avatar_url":"https://avatars.githubusercontent.com/u/5751452?v=3","gravatar_id":"","url":"https://api.github.com/users/codurance","html_url":"https://github.com/codurance","followers_url":"https://api.github.com/users/codurance/followers","following_url":"https://api.github.com/users/codurance/following{/other_user}","gists_url":"https://api.github.com/users/codurance/gists{/gist_id}","starred_url":"https://api.github.com/users/codurance/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/codurance/subscriptions","organizations_url":"https://api.github.com/users/codurance/orgs","repos_url":"https://api.github.com/users/codurance/repos","events_url":"https://api.github.com/users/codurance/events{/privacy}","received_events_url":"https://api.github.com/users/codurance/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/codurance/site","description":"","fork":false,"url":"https://api.github.com/repos/codurance/site","forks_url":"https://api.github.com/repos/codurance/site/forks","keys_url":"https://api.github.com/repos/codurance/site/keys{/key_id}","collaborators_url":"https://api.github.com/repos/codurance/site/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/codurance/site/teams","hooks_url":"https://api.github.com/repos/codurance/site/hooks","issue_events_url":"https://api.github.com/repos/codurance/site/issues/events{/number}","events_url":"https://api.github.com/repos/codurance/site/events","assignees_url":"https://api.github.com/repos/codurance/site/assignees{/user}","branches_url":"https://api.github.com/repos/codurance/site/branches{/branch}","tags_url":"https://api.github.com/repos/codurance/site/tags","blobs_url":"https://api.github.com/repos/codurance/site/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/codurance/site/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/codurance/site/git/refs{/sha}","trees_url":"https://api.github.com/repos/codurance/site/git/trees{/sha}","statuses_url":"https://api.github.com/repos/codurance/site/statuses/{sha}","languages_url":"https://api.github.com/repos/codurance/site/languages","stargazers_url":"https://api.github.com/repos/codurance/site/stargazers","contributors_url":"https://api.github.com/repos/codurance/site/contributors","subscribers_url":"https://api.github.com/repos/codurance/site/subscribers","subscription_url":"https://api.github.com/repos/codurance/site/subscription","commits_url":"https://api.github.com/repos/codurance/site/commits{/sha}","git_commits_url":"https://api.github.com/repos/codurance/site/git/commits{/sha}","comments_url":"https://api.github.com/repos/codurance/site/comments{/number}","issue_comment_url":"https://api.github.com/repos/codurance/site/issues/comments{/number}","contents_url":"https://api.github.com/repos/codurance/site/contents/{+path}","compare_url":"https://api.github.com/repos/codurance/site/compare/{base}...{head}","merges_url":"https://api.github.com/repos/codurance/site/merges","archive_url":"https://api.github.com/repos/codurance/site/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/codurance/site/downloads","issues_url":"https://api.github.com/repos/codurance/site/issues{/number}","pulls_url":"https://api.github.com/repos/codurance/site/pulls{/number}","milestones_url":"https://api.github.com/repos/codurance/site/milestones{/number}","notifications_url":"https://api.github.com/repos/codurance/site/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/codurance/site/labels{/name}","releases_url":"https://api.github.com/repos/codurance/site/releases{/id}","deployments_url":"https://api.github.com/repos/codurance/site/deployments","created_at":"2015-07-02T09:54:02Z","updated_at":"2016-01-11T15:53:57Z","pushed_at":"2016-03-01T01:39:04Z","git_url":"git://github.com/codurance/site.git","ssh_url":"git@github.com:codurance/site.git","clone_url":"https://github.com/codurance/site.git","svn_url":"https://github.com/codurance/site","homepage":null,"size":151328,"stargazers_count":0,"watchers_count":0,"language":"CSS","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":2,"mirror_url":null,"open_issues_count":1,"forks":2,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"codurance:master","ref":"master","sha":"30557740e7df57ad9bdc9e7568d955ffe9974e45","user":{"login":"codurance","id":5751452,"avatar_url":"https://avatars.githubusercontent.com/u/5751452?v=3","gravatar_id":"","url":"https://api.github.com/users/codurance","html_url":"https://github.com/codurance","followers_url":"https://api.github.com/users/codurance/followers","following_url":"https://api.github.com/users/codurance/following{/other_user}","gists_url":"https://api.github.com/users/codurance/gists{/gist_id}","starred_url":"https://api.github.com/users/codurance/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/codurance/subscriptions","organizations_url":"https://api.github.com/users/codurance/orgs","repos_url":"https://api.github.com/users/codurance/repos","events_url":"https://api.github.com/users/codurance/events{/privacy}","received_events_url":"https://api.github.com/users/codurance/received_events","type":"Organization","site_admin":false},"repo":{"id":38424930,"name":"site","full_name":"codurance/site","owner":{"login":"codurance","id":5751452,"avatar_url":"https://avatars.githubusercontent.com/u/5751452?v=3","gravatar_id":"","url":"https://api.github.com/users/codurance","html_url":"https://github.com/codurance","followers_url":"https://api.github.com/users/codurance/followers","following_url":"https://api.github.com/users/codurance/following{/other_user}","gists_url":"https://api.github.com/users/codurance/gists{/gist_id}","starred_url":"https://api.github.com/users/codurance/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/codurance/subscriptions","organizations_url":"https://api.github.com/users/codurance/orgs","repos_url":"https://api.github.com/users/codurance/repos","events_url":"https://api.github.com/users/codurance/events{/privacy}","received_events_url":"https://api.github.com/users/codurance/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/codurance/site","description":"","fork":false,"url":"https://api.github.com/repos/codurance/site","forks_url":"https://api.github.com/repos/codurance/site/forks","keys_url":"https://api.github.com/repos/codurance/site/keys{/key_id}","collaborators_url":"https://api.github.com/repos/codurance/site/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/codurance/site/teams","hooks_url":"https://api.github.com/repos/codurance/site/hooks","issue_events_url":"https://api.github.com/repos/codurance/site/issues/events{/number}","events_url":"https://api.github.com/repos/codurance/site/events","assignees_url":"https://api.github.com/repos/codurance/site/assignees{/user}","branches_url":"https://api.github.com/repos/codurance/site/branches{/branch}","tags_url":"https://api.github.com/repos/codurance/site/tags","blobs_url":"https://api.github.com/repos/codurance/site/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/codurance/site/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/codurance/site/git/refs{/sha}","trees_url":"https://api.github.com/repos/codurance/site/git/trees{/sha}","statuses_url":"https://api.github.com/repos/codurance/site/statuses/{sha}","languages_url":"https://api.github.com/repos/codurance/site/languages","stargazers_url":"https://api.github.com/repos/codurance/site/stargazers","contributors_url":"https://api.github.com/repos/codurance/site/contributors","subscribers_url":"https://api.github.com/repos/codurance/site/subscribers","subscription_url":"https://api.github.com/repos/codurance/site/subscription","commits_url":"https://api.github.com/repos/codurance/site/commits{/sha}","git_commits_url":"https://api.github.com/repos/codurance/site/git/commits{/sha}","comments_url":"https://api.github.com/repos/codurance/site/comments{/number}","issue_comment_url":"https://api.github.com/repos/codurance/site/issues/comments{/number}","contents_url":"https://api.github.com/repos/codurance/site/contents/{+path}","compare_url":"https://api.github.com/repos/codurance/site/compare/{base}...{head}","merges_url":"https://api.github.com/repos/codurance/site/merges","archive_url":"https://api.github.com/repos/codurance/site/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/codurance/site/downloads","issues_url":"https://api.github.com/repos/codurance/site/issues{/number}","pulls_url":"https://api.github.com/repos/codurance/site/pulls{/number}","milestones_url":"https://api.github.com/repos/codurance/site/milestones{/number}","notifications_url":"https://api.github.com/repos/codurance/site/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/codurance/site/labels{/name}","releases_url":"https://api.github.com/repos/codurance/site/releases{/id}","deployments_url":"https://api.github.com/repos/codurance/site/deployments","created_at":"2015-07-02T09:54:02Z","updated_at":"2016-01-11T15:53:57Z","pushed_at":"2016-03-01T01:39:04Z","git_url":"git://github.com/codurance/site.git","ssh_url":"git@github.com:codurance/site.git","clone_url":"https://github.com/codurance/site.git","svn_url":"https://github.com/codurance/site","homepage":null,"size":151328,"stargazers_count":0,"watchers_count":0,"language":"CSS","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":2,"mirror_url":null,"open_issues_count":1,"forks":2,"open_issues":1,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/codurance/site/pulls/138"},"html":{"href":"https://github.com/codurance/site/pull/138"},"issue":{"href":"https://api.github.com/repos/codurance/site/issues/138"},"comments":{"href":"https://api.github.com/repos/codurance/site/issues/138/comments"},"review_comments":{"href":"https://api.github.com/repos/codurance/site/pulls/138/comments"},"review_comment":{"href":"https://api.github.com/repos/codurance/site/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/codurance/site/pulls/138/commits"},"statuses":{"href":"https://api.github.com/repos/codurance/site/statuses/aff43a4f6b46e27d7f506c4bed9aa682bf394bbb"}}}}