PageRenderTime 27ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/README.md

https://gitlab.com/JamesClonk/concourse-tutorial
Markdown | 405 lines | 281 code | 124 blank | 0 comment | 0 complexity | d6a47e3eca8b5d25f462ea0464c6b074 MD5 | raw file
  1. Concourse Tutorial
  2. ==================
  3. Learn to use https://concourse.ci with this linear sequence of tutorials. Learn each concept that builds on the previous concept.
  4. Getting started
  5. ---------------
  6. Install Vagrant/Virtualbox.
  7. Fetch this tutorial and start a server
  8. ```
  9. git clone git@github.com:starkandwayne/concourse-tutorial.git
  10. cd concourse-tutorial
  11. vagrant up
  12. ```
  13. Open http://192.168.100.4:8080/ in your browser:
  14. [![initial](http://cl.ly/image/401b2z2B3w17/no-pipelines.png)](http://192.168.100.4:8080/)
  15. Once the page loads in your browser, click to download the `fly` CLI appropriate for your operating system:
  16. ![cli](http://cl.ly/image/1r462S1m1j1H/fly_cli.png)
  17. Once downloaded, copy the `fly` binary into your path (`$PATH`), such as `/usr/local/bin` or `~/bin`. Don't forget to also make it executable. For example,
  18. ```
  19. sudo mkdir -p /usr/local/bin
  20. sudo mv ~/Downloads/fly /usr/local/bin
  21. sudo chmod 0755 /usr/local/bin/fly
  22. ```
  23. Target Concourse
  24. ----------------
  25. In the spirit of declaring absolutely everything you do to get absolutely the same result every time, the `fly` CLI requires that you specify the target API for every `fly` request.
  26. First, alias it with a name `tutorial` (this name is used by all the tutorial wrapper scripts):
  27. ```
  28. fly --target tutorial login --concourse-url http://192.168.100.4:8080 sync
  29. ```
  30. You can now see this saved target Concourse API in a local file:
  31. ```
  32. cat ~/.flyrc
  33. ```
  34. Shows a simple YAML file with the API, credentials etc:
  35. ```yaml
  36. targets:
  37. tutorial:
  38. api: http://192.168.100.4:8080
  39. username: ""
  40. password: ""
  41. cert: ""
  42. ```
  43. When we use the `fly` command we will target this Concourse API using `fly -t tutorial`.
  44. > @alexsuraci: I promise you'll end up liking it more than having an implicit target state :) Makes reusing commands from shell history much less dangerous (rogue fly configure can be bad)
  45. Tutorials
  46. ---------
  47. ### 01 - Hello World task
  48. ```
  49. cd 01_task_hello_world
  50. fly -t tutorial execute -c task_hello_world.yml
  51. ```
  52. The output starts with
  53. ```
  54. Connecting to 192.168.100.4:8080 (192.168.100.4:8080)
  55. - 100% |*******************************| 10240 0:00:00 ETA
  56. initializing with docker:///busybox
  57. ```
  58. Every task in Concourse runs within a "container" (as best available on the target platform). The `task_hello_world.yml` configuration shows that we are running on a `linux` platform using a container image defined by `docker:///busybox`.
  59. Within this container it will run the command `echo hello world`:
  60. ```yaml
  61. ---
  62. platform: linux
  63. image: docker:///busybox
  64. run:
  65. path: echo
  66. args: [hello world]
  67. ```
  68. At this point in the output above it is downloading a Docker image `busybox`. It will only need to do this once; though will recheck every time that it has the latest `busybox` image.
  69. Eventually it will continue:
  70. ```
  71. running echo hello world
  72. hello world
  73. succeeded
  74. ```
  75. Try changing the `image:` and the `run:` and run a different task:
  76. ```yaml
  77. ---
  78. platform: linux
  79. image: docker:///ubuntu#14.04
  80. run:
  81. path: uname
  82. args: [-a]
  83. ```
  84. This task file is provided for convenience:
  85. ```
  86. $ fly -t tutorial execute -c task_ubuntu_uname.yml
  87. Connecting to 192.168.100.4:8080 (192.168.100.4:8080)
  88. - 100% |*******************************| 10240 0:00:00 ETA
  89. initializing with docker:///ubuntu#14.04
  90. running uname -a
  91. Linux mjgia714efl 3.13.0-49-generic #83-Ubuntu SMP Fri Apr 10 20:11:33 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
  92. succeeded
  93. ```
  94. A common pattern is for Concourse tasks to `run:` wrapper shell scripts, rather than directly invoking commands.
  95. As your tasks and wrapper scripts build up into complex pipelines you will appreciate the following pattern:
  96. - Give your task files and wrapper shell scripts the same base name
  97. In the `01_task_hello_world` folder you can see two files:
  98. - `task_show_uname.yml`
  99. - `task_show_uname.sh`
  100. When you execute a task file directly via `fly`, it will upload the current folder as an input to the task. This means the wrapper shell script is available for execution:
  101. ```
  102. $ fly -t tutorial execute -c task_show_uname.yml
  103. Connecting to 192.168.100.4:8080 (192.168.100.4:8080)
  104. - 100% |*******************************| 10240 0:00:00 ETA
  105. initializing with docker:///busybox
  106. running ./task_show_uname.sh
  107. Linux mjgia714eg3 3.13.0-49-generic #83-Ubuntu SMP Fri Apr 10 20:11:33 UTC 2015 x86_64 GNU/Linux
  108. succeeded
  109. ```
  110. The output above `running ./task_show_uname.sh` shows that the `task_show_uname.yml` task delegated to a wrapper script to perform the task work.
  111. The `task_show_uname.yml` task is:
  112. ```yaml
  113. platform: linux
  114. image: docker:///busybox
  115. inputs:
  116. - name: 01_task_hello_world
  117. path: .
  118. run:
  119. path: ./task_show_uname.sh
  120. ```
  121. The new concept above is `inputs:`.
  122. In order for a task to run a wrapper script, it must be given access to the wrapper script. In order for a task to process data files, it must be given access to those data files.
  123. In Concourse these are `inputs` to a task.
  124. Given that we are running the task directly from the `fly` CLI, and we're running it from our host machine inside the `01_task_hello_world` folder, then the current host machine folder will be uploaded to Concourse and made available as an input called `01_task_hello_world`.
  125. Later when we look at Jobs with inputs, tasks and outputs we'll return to passing `inputs` into tasks within a Job.
  126. Consider the `inputs:` snippet above:
  127. ```yaml
  128. inputs:
  129. - name: 01_task_hello_world
  130. path: .
  131. ```
  132. This is saying:
  133. 1. I want to receive an input folder called `01_task_hello_world`
  134. 2. I want it to be placed in the folder `.` (that is, the root folder of the task when its running)
  135. By default, without `path:` an input will be placed in a folder with the same name as the input itself.
  136. Given the list of `inputs`, we now know that the `task_show_uname.sh` script (which is in the same folder) will be available in the root folder of the running task.
  137. This allows us to invoke it:
  138. ```yaml
  139. run:
  140. path: ./task_show_uname.sh
  141. ```
  142. ### 02 - Hello World job
  143. ```
  144. cd ../02_job_hello_world
  145. fly set-pipeline -t tutorial -c pipeline.yml -p 02helloworld
  146. fly unpause-pipeline -p 02helloworld
  147. ```
  148. It will display the concourse pipeline (or any changes) and request confirmation:
  149. ```yaml
  150. jobs:
  151. job job-hello-world has been added:
  152. name: job-hello-world
  153. public: true
  154. plan:
  155. - task: hello-world
  156. config:
  157. platform: linux
  158. image: docker:///busybox
  159. run:
  160. path: echo
  161. args:
  162. - hello world
  163. ```
  164. You will be prompted to apply any configuration changes each time you run `fly set-pipeline` (or its alias `fly sp`)
  165. ```
  166. apply configuration? (y/n):
  167. ```
  168. Press `y`.
  169. You should see:
  170. ```
  171. pipeline created!
  172. you can view your pipeline here: http://192.168.100.4:8080/pipelines/02helloworld
  173. ```
  174. Go back to your browser and start the job manually. Click on `job-hello-world` and then click on the large `+` in the top right corner. Your job will run.
  175. ![job](http://cl.ly/image/3i2e0k0v3O2l/02-job-hello-world.gif)
  176. Clicking the top-left "Home" icon will show the status of our pipeline.
  177. ### 03 - Tasks extracted into resources
  178. It is easy to iterate on a job's tasks by configuring them in the `pipeline.yml` as above. Eventually you might want to colocate a job task with one of the resources you are already pulling in.
  179. This is a little convoluted example for our "hello world" task, but let's assume the task we want to run is the one from "01 - Hello World task" above. It's stored in a git repo.
  180. In our `pipeline.yml` we add the tutorial's git repo as a resource:
  181. ```yaml
  182. resources:
  183. - name: resource-tutorial
  184. type: git
  185. source:
  186. uri: https://github.com/starkandwayne/concourse-tutorial.git
  187. ```
  188. Now we can consume that resource in our job. Update it to:
  189. ```yaml
  190. jobs:
  191. - name: job-hello-world
  192. public: true
  193. plan:
  194. - get: resource-tutorial
  195. - task: hello-world
  196. file: resource-tutorial/01_task_hello_world/task_hello_world.yml
  197. ```
  198. Our `plan:` specifies that first we need to `get` the resource `resource-tutorial`.
  199. Second we use the `01_task_hello_world/task_hello_world.yml` file from `resource-tutorial` as the task configuration.
  200. Apply the updated pipeline using `fly set-pipeline -t tutorial -c pipeline.yml -p 03_resource_job`. #TODO find out how to do that better
  201. Note: `fly` has shorter aliases for it's commands, `fly sp` is shorthand for `fly set-pipeline`
  202. Or run the pre-created pipeline from the tutorial:
  203. ```
  204. cd ../03_resource_job
  205. fly sp -t tutorial -c pipeline.yml -p 03_resource_job
  206. fly unpause-pipeline -t tutorial -p 03_resource_job
  207. ```
  208. ![resource-job](http://cl.ly/image/271z3T322l25/03-resource-job.gif)
  209. After manually triggering the job via the UI, the output will look like:
  210. ![job-task-from-wrapper](http://cl.ly/image/0Q3m223v2l3M/job-task-from-wrapper.png)
  211. The `job-hello-world` job now has two steps in its build plan.
  212. The first step fetches the git repository for these training materials and tutorials. This is a "resource" called `resource-tutorial`.
  213. This resource can now be an input to any task in the job build plan.
  214. The second step runs a user-defined task. We give the task a name `hello-world` which will be displayed in the UI output. The task itself is not described in the pipeline. Instead it is described in `01_task_hello_world/task_hello_world.yml` from the `resource-tutorial` input.
  215. There is a benefit and a downside to abstracting tasks into YAML files outside of the pipeline.
  216. The benefit is that the behavior of the task can be modified to match the input resource that it is operating upon. For example, if the input resource was a code repository with tests then the task file could be kept in sync with how the code repo needs to have its tests executed.
  217. The downside is that the `pipeline.yml` no longer explains exactly what commands will be invoked. Comprehension is potentially reduced. `pipeline.yml` files can get long and it can be hard to read and comprehend all the YAML.
  218. Consider comprehension of other team members when making these choices. "What does this pipeline actually do?!"
  219. One idea is to consider how you name your task files, and thus how you name the wrapper scripts that they invoke.
  220. Consider using (long) names that describe their purpose/behavior.
  221. Try to make the `pipeline.yml` readable. It will become important orchestration within your team/company/project; and everyone needs to know how it actually works.
  222. ### 04 - Get job output in terminal
  223. The `job-hello-world` had terminal output from its resource fetch of a git repo and of the `hello-world` task running.
  224. You can also view this output from the terminal with `fly`:
  225. ```
  226. fly -t tutorial watch -j 03_resource_job/job-hello-world
  227. ```
  228. The output will be similar to:
  229. ```
  230. Cloning into '/tmp/build/get'...
  231. e8c6632 Added trigger: true to autostart both jobs after update.
  232. initializing with docker:///busybox
  233. running echo hello world
  234. hello world
  235. succeeded
  236. ```
  237. ### 05 - Trigger a Job via the Concourse API
  238. Our concourse in vagrant has an API running at `http://192.168.100.4:8080`. The `fly` CLI targets this endpoint by default.
  239. We can trigger a job to be run using that API. For example, using `curl`:
  240. ```
  241. curl http://192.168.100.4:8080/pipelines/03_resource_job/jobs/job-hello-world/builds -X POST
  242. ```
  243. You can then watch the output in your terminal using `fly watch` from above:
  244. ```
  245. fly -t tutorial watch -j 03_resource_job/job-hello-world
  246. ```
  247. ### 06 - Triggering jobs - the `time` resource
  248. "resources are checked every minute, but there's a shorter (10sec) interval for determining when a build should run; time resource is to just ensure a build runs on some rough periodicity; we use it to e.g. continuously run integration/acceptance tests to weed out flakiness" - alex
  249. The net result is that a timer of `2m` will trigger every 2 to 3 minutes.
  250. ### 20 - Available concourse resources
  251. https://github.com/concourse?query=resource
  252. - [bosh-deployment-resource](https://github.com/concourse/bosh-deployment-resource) - deploy bosh releases as part of your pipeline
  253. - [semver-resource](https://github.com/concourse/semver-resource) - automated semantic version bumping
  254. - [bosh-io-release-resource](https://github.com/concourse/bosh-io-release-resource) - Tracks the versions of a release on bosh.io
  255. - [s3-resource](https://github.com/concourse/s3-resource) - Concourse resource for interacting with AWS S3
  256. - [git-resource](https://github.com/concourse/git-resource) - Tracks the commits in a git repository.
  257. - [bosh-io-stemcell-resource](https://github.com/concourse/bosh-io-stemcell-resource) - Tracks the versions of a stemcell on bosh.io.
  258. - [vagrant-cloud-resource](https://github.com/concourse/vagrant-cloud-resource) - manages boxes in vagrant cloud, by provider
  259. - [docker-image-resource](https://github.com/concourse/docker-image-resource) - a resource for docker images
  260. - [archive-resource](https://github.com/concourse/archive-resource) - downloads and extracts an archive (currently tgz) from a uri
  261. - [github-release-resource](https://github.com/concourse/github-release-resource) - a resource for github releases
  262. - [tracker-resource](https://github.com/concourse/tracker-resource) - pivotal tracker output resource
  263. - [time-resource](https://github.com/concourse/time-resource) - a resource for triggering on an interval
  264. - [cf-resource](https://github.com/concourse/cf-resource) - Concourse resource for interacting with Cloud Foundry
  265. To find out which resources are available on your target Concourse you can ask the API endpoint `/api/v1/workers`:
  266. ```
  267. $ curl -s http://192.168.100.4:8080/api/v1/workers | jq -r ".[0].resource_types[].type" | sort
  268. archive
  269. bosh-deployment
  270. bosh-io-release
  271. bosh-io-stemcell
  272. cf
  273. docker-image
  274. git
  275. github-release
  276. s3
  277. semver
  278. time
  279. tracker
  280. vagrant-cloud
  281. ```