<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Ben Hearsum (Posts about taskcluster)</title><link>https://hearsum.ca/</link><description></description><atom:link href="https://hearsum.ca/categories/taskcluster.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2025 &lt;a href="mailto:ben@hearsum.ca"&gt;Ben Hearsum&lt;/a&gt; </copyright><lastBuildDate>Thu, 30 Jan 2025 16:13:56 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Building and Pushing Docker Images with Taskcluster-Github</title><link>https://hearsum.ca/posts/building-and-pushing-docker-images-with-taskcluster-github/</link><dc:creator>Ben Hearsum</dc:creator><description>&lt;p&gt;Earlier this year I spent some time modernizing and improving Balrog's toolchain. One of my goals in doing so was to switch from Travis CI to &lt;a href="https://docs.taskcluster.net/"&gt;Taskcluster&lt;/a&gt; both to give us more flexibility in our CI configuration, as well as help dogfood &lt;a href="https://docs.taskcluster.net/manual/vcs/github"&gt;Taskcluster-Github&lt;/a&gt;. One of the most challenging aspects of this was how to build and push our Docker image, and I'm hoping this post will make it easier for other folks who want to do the same in the future.&lt;/p&gt;
&lt;h2&gt;The Task Definition&lt;/h2&gt;
&lt;p&gt;Let's start by breaking down &lt;a href="https://github.com/mozilla/balrog/blob/b0404ab22649c650def7e4c9c90ce2576e28d8a9/.taskcluster.yml#L31"&gt;Task definition&lt;/a&gt; from &lt;a href="https://github.com/mozilla/balrog/blob/b0404ab22649c650def7e4c9c90ce2576e28d8a9/.taskcluster.yml"&gt;Balrog's .taskcluster.yml&lt;/a&gt;. Like other Taskcluster-Github jobs, we use the standard &lt;em&gt;taskcluster.docker&lt;/em&gt; provisioner and worker.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;  - provisionerId: "{{ taskcluster.docker.provisionerId }}"
    workerType: "{{ taskcluster.docker.workerType }}"
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, we have something a little different. This section grants the Task access to a secret (managed by the &lt;a href="https://docs.taskcluster.net/reference/core/secrets"&gt;Secrets Service&lt;/a&gt;). More on this later.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;    scopes:
      - secrets:get:repo:github.com/mozilla/balrog:dockerhub
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;em&gt;payload&lt;/em&gt; has a few things of note. Because we're going to be building Docker images it makes sense to use Taskcluster's image_builder Docker image as well as enabling the docker-in-docker feature. The taskclusterProxy feature is needed to access the Secrets Service.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;    payload:
      maxRunTime: 3600
      image: "taskcluster/image_builder:0.1.3"
      features:
        dind: true
        taskclusterProxy: true
      command:
        - "/bin/bash"
        - "-c"
        - "git clone $GITHUB_HEAD_REPO_URL &amp;amp;&amp;amp; cd balrog &amp;amp;&amp;amp; git checkout $GITHUB_HEAD_BRANCH &amp;amp;&amp;amp; scripts/push-dockerimage.sh"
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;em&gt;extra&lt;/em&gt; section has some metadata for Taskcluster-Github. Unlike CI tasks, we limit this to only running on pushes (not pull requests) to the master branch of the repository. Because only a few people can push to this branch, it means that only these can trigger Docker builds.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;    extra:
      github:
        env: true
        events:
          - push
        branches:
          - master
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Finally, we have the metadata, which is just standard Taskcluster stuff.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;    metadata:
      name: Balrog Docker Image Creation
      description: Balrog Docker Image Creation
      owner: "{{ event.head.user.email }}"
      source: "{{ event.head.repo.url }}"
&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Secrets&lt;/h2&gt;
&lt;p&gt;I mentioned the "Secrets Service" earlier, and it's the key piece that enables us to &lt;strong&gt;securely&lt;/strong&gt; push Docker images. Putting our Dockerhub password in it means access is limited to those who have the right scopes. We store it in a secret with the key "repo:github.com/mozilla/balrog:dockerhub", which means that anything with the "secrets:get:repo:github.com/mozilla/balrog:dockerhub" scope is granted access to it. My own personal Taskcluster account has it, which lets me set or change the password:&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://hearsum.ca/blog/dockerhub-secret.png" title="Screenshot of Taskcluster Secrets Manager"&gt;&lt;/p&gt;
&lt;p&gt;We also have a Role called "repo:github.com/mozilla/balrog:branch:master" which has that scope:&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://hearsum.ca/blog/balrog-role.png" title="Screenshot of Taskcluster Role Manager"&gt;&lt;/p&gt;
&lt;p&gt;You can see from its name that this Role is associated with the Balrog repository's master branch. Because of this, any Tasks created for as a result of pushes to that branch in that repository and branch may assign the scopes that Role has - like we did above in the "scopes" section of the Task.&lt;/p&gt;
&lt;h2&gt;Building and Pushing&lt;/h2&gt;
&lt;p&gt;The last piece of the puzzle here is &lt;a href="https://github.com/mozilla/balrog/blob/b0404ab22649c650def7e4c9c90ce2576e28d8a9/scripts/push-dockerimage.sh"&gt;the actual script that does the building and pushing&lt;/a&gt;. Let's look at a few specific parts of it.&lt;/p&gt;
&lt;p&gt;To start with, we deal with retrieving the Dockerhub password from the Secrets Service. Because we enabled the &lt;em&gt;taskclusterProxy&lt;/em&gt; earlier, "taskcluster" resolves to the hosted Taskcluster services. Had we forgotten to grant the Task the necessary scope, this would return a 403 error.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;password_url="taskcluster/secrets/v1/secret/repo:github.com/mozilla/balrog:dockerhub"
dockerhub_password=$(curl ${password_url} | python -c 'import json, sys; a = json.load(sys.stdin); print a["secret"]["dockerhub_password"]')
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We build, tag, and push the image, which is very similar to building it locally. If we'd forgotten to enable the &lt;em&gt;dind&lt;/em&gt; feature, this would throw errors about not being able to run Docker.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;docker build -t mozilla/balrog:${branch_tag} .
docker tag mozilla/balrog:${branch_tag} "mozilla/balrog:${date_tag}"
docker login -e $dockerhub_email -u $dockerhub_username -p $dockerhub_password
docker push mozilla/balrog:${branch_tag}
docker push mozilla/balrog:${date_tag}
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Finally, we attach an artifact to our Task containing the sha256 of the Docker images. This allows consumers of the Docker image to verify that they're getting exactly what we built, and not something that may have been tampered on Dockerhub or in transit.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;sha256=$(docker images --no-trunc mozilla/balrog | grep "${date_tag}" | awk '/^mozilla/ {print $3}')
put_url=$(curl --retry 5 --retry-delay 5 --data "{\"storageType\": \"s3\", \"contentType\": \"text/plain\", \"expires\": \"${artifact_expiry}\"}" ${artifact_url} | python -c 'import json; import sys; print json.load(sys.stdin)["putUrl"]')
curl --retry 5 --retry-delay 5 -X PUT -H "Content-Type: text/plain" --data "${sha256}" "${put_url}"
&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;The Result&lt;/h2&gt;
&lt;p&gt;Now that you've seen how it's put together, let's have a look at the end result. &lt;a href="https://tools.taskcluster.net/task-graph-inspector/#CLnMzzpSQ3Wysl9EpkG0rQ/MYD_j8yKTgy7lZFYkt6Bzg/"&gt;This is the most recent Balrog Docker build Task&lt;/a&gt;. You can see the sha256 artifact created on it:&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://hearsum.ca/blog/balrog-dockerbuild.png"&gt;&lt;/p&gt;
&lt;p&gt;And of course, the newly built image has shown up &lt;a href="https://hub.docker.com/r/mozilla/balrog/tags/"&gt;on the Balrog Dockerhub repo&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://hearsum.ca/blog/balrog-dockerhub.png"&gt;&lt;/p&gt;</description><category>aus</category><category>balrog</category><category>planet-mozilla</category><category>releng</category><category>taskcluster</category><guid>https://hearsum.ca/posts/building-and-pushing-docker-images-with-taskcluster-github/</guid><pubDate>Thu, 30 Jun 2016 19:29:00 GMT</pubDate></item><item><title>Buildbot &amp;lt;-&amp;gt; Taskcluster Bridge Now in Production</title><link>https://hearsum.ca/posts/buildbot-taskcluster-bridge-now-in-production/</link><dc:creator>Ben Hearsum</dc:creator><description>&lt;p&gt;A few weeks ago I gave &lt;a href="http://hearsum.ca/blog/buildbot-taskcluster-bridge-an-overview.html"&gt;a brief overview of the Buildbot &amp;lt;-&amp;gt;Taskcluster Bridge&lt;/a&gt; that we've been developing, and Selena &lt;a href="http://www.chesnok.com/daily/2015/06/03/taskcluster-migration-about-the-buildbot-bridge/"&gt;provided some additional details&lt;/a&gt; about it yesterday. Today I'm happy to announce that it is ready to take on production work. As &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1118394"&gt;more&lt;/a&gt; &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1119546"&gt;and&lt;/a&gt; &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1135206"&gt;more&lt;/a&gt; &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1149142"&gt;jobs&lt;/a&gt; from our CI infrastructure move to Taskcluster, the Bridge will coordinate between them and jobs that must remain in Buildbot for the time being.&lt;/p&gt;

&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;The Bridge itself is feature complete until our &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1156305"&gt;requirements change&lt;/a&gt; (though there's a couple of &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1164819"&gt;minor&lt;/a&gt; &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1168099"&gt;bugs&lt;/a&gt; that would be nice to fix), but most of the Buildbot Schedulers still need to be replaced with Task Graphs. Some of this work will be done at the same time as porting specific build or test jobs to run natively in Taskcluster, but it doesn't have to be. I made a proof of concept on &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1157242"&gt;how to integrate selected Buildbot builds into the existing "taskcluster-graph" command&lt;/a&gt; and &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1157310"&gt;disable the Buildbot schedulers that it replaces&lt;/a&gt;. With a bit more work this could be extended to schedule all of the Buildbot builds for a branch, which would make porting specific jobs simpler. If you'd like to help out with this, let me know!&lt;/p&gt;</description><category>buildbot</category><category>planet-mozilla</category><category>taskcluster</category><guid>https://hearsum.ca/posts/buildbot-taskcluster-bridge-now-in-production/</guid><pubDate>Thu, 04 Jun 2015 15:11:34 GMT</pubDate></item><item><title>Buildbot &lt;-&gt; Taskcluster Bridge - An Overview</title><link>https://hearsum.ca/posts/buildbot-taskcluster-bridge-an-overview/</link><dc:creator>Ben Hearsum</dc:creator><description>&lt;p&gt;Mozilla has been using &lt;a href="http://buildbot.net"&gt;Buildbot&lt;/a&gt; as its continuous integration system for Firefox and Fennec for many years now. It enabled us to switch from a machine-per-build model to a pool-of-slaves model, and greatly aided us in getting to our current scale. But it's not perfect - and we've known for a few years that we'll need to do an overhaul. Lucky for us, the FirefoxOS Automation team has built up a fantastic piece of infrastructure known as &lt;a href="http://docs.taskcluster.net/"&gt;Taskcluster&lt;/a&gt; that we're eager to start moving to.&lt;/p&gt;

&lt;p&gt;It's not going to be a small task though - it will take a lot more work than taking our existing build scripts and running them in Taskcluster. One reason for this is that many of our jobs trigger other jobs, and Buildbot manages those relationships. This means that if we have a build job that triggers a test job, we can't move one without moving the other. We don't want to be forced into moving entire job chains at once, so we need something to help us transition more slowly. Our solution to this is to make it possible to schedule jobs in Taskcluster while still implementing them in Buildbot. Once the scheduling is in Taskcluster it's possible to move individual jobs to Taskcluster one at a time. The software that makes this possible is the Buildbot Bridge.&lt;/p&gt;

&lt;p&gt;The Bridge is responsible for synchronizing job state between Taskcluster and Buildbot. Jobs that are requested through Taskcluster will be created in Buildbot by the Bridge. When those jobs complete, the Bridge will update Taskcluster with their status. Let's look at a simple example to see see how the state changes in both systems over the course of a job being submitted and run:&lt;/p&gt;
&lt;table style="border: solid 1px black; border-collapse: collapse;"&gt;
&lt;tr style="border: solid 1px black;"&gt;
&lt;th style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Event&lt;/th&gt;
&lt;th style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Taskcluster state&lt;/th&gt;
&lt;th style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Buildbot state&lt;/th&gt;
&lt;/tr&gt;
&lt;tr style="border: solid 1px black;"&gt;
&lt;td style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Task is created&lt;/td&gt;
&lt;td style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Task is pending&lt;/td&gt;
&lt;td style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;--&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border: solid 1px black;"&gt;
&lt;td style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Bridge receives "task-pending" event, creates BuildRequest&lt;/td&gt;
&lt;td style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Task is pending&lt;/td&gt;
&lt;td style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Build is pending&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border: solid 1px black;"&gt;
&lt;td style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Build starts in Buildbot&lt;/td&gt;
&lt;td style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Task is pending&lt;/td&gt;
&lt;td style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Build is running&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border: solid 1px black;"&gt;
&lt;td style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Bridge receives "build started" event, claims the Task&lt;/td&gt;
&lt;td style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Task is running&lt;/td&gt;
&lt;td style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Build is running&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border: solid 1px black;"&gt;
&lt;td style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Build completes successfully&lt;/td&gt;
&lt;td style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Task is running&lt;/td&gt;
&lt;td style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Build is completed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border: solid 1px black;"&gt;
&lt;td style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Bridge receives "build finished" event, reports success to Taskcluster&lt;/td&gt;
&lt;td style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Task is resolved&lt;/td&gt;
&lt;td style="border: solid 1px black; padding: 2px 5px 2px 5px"&gt;Build is completed&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;br&gt;
&lt;p&gt;The details of how this work are a bit more complicated - if you'd like to learn more about that I recommend watching &lt;a href="https://vreplay.mozilla.com/replay/showRecordDetails.html?recId=1879"&gt;the presentation I did about the Bridge architecture&lt;/a&gt;, or just have a read through &lt;a href="http://hearsum.ca/slides/buildbot-bridge-overview/#/"&gt;my slides&lt;/a&gt;&lt;/p&gt;</description><category>buildbot</category><category>planet-mozilla</category><category>taskcluster</category><guid>https://hearsum.ca/posts/buildbot-taskcluster-bridge-an-overview/</guid><pubDate>Fri, 08 May 2015 16:37:02 GMT</pubDate></item></channel></rss>