<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Simone Gotti</title>
    <description>The latest articles on Forem by Simone Gotti (@sgotti).</description>
    <link>https://forem.com/sgotti</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F195738%2F60777195-5f74-4b30-a57f-281d330e9524.jpeg</url>
      <title>Forem: Simone Gotti</title>
      <link>https://forem.com/sgotti</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sgotti"/>
    <language>en</language>
    <item>
      <title>Agola Direct Runs: Power to the Developers!</title>
      <dc:creator>Simone Gotti</dc:creator>
      <pubDate>Wed, 21 Aug 2019 09:30:17 +0000</pubDate>
      <link>https://forem.com/sgotti/agola-direct-runs-power-to-the-developers-57b2</link>
      <guid>https://forem.com/sgotti/agola-direct-runs-power-to-the-developers-57b2</guid>
      <description>&lt;p&gt;When we started drafting the big list of Agola wanted features, one of the primary requirements we heard from many developers was the ability to execute the agola &lt;strong&gt;Runs&lt;/strong&gt; (or pipelines/workflows in other CI/CD tool concepts) from their local development directory while they were developing new features at any time (and without the need to commit).&lt;/p&gt;

&lt;p&gt;There are many good reasons to ask for this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They want to be sure that all the pipelines will finish successfully before opening a pull request or pushing to a branch (to avoid a loop of force push and wait for the CI/CD run being successful).&lt;/li&gt;
&lt;li&gt;They want to test conditional &lt;strong&gt;runs&lt;/strong&gt; (a run that have tasks that depends on diffent conditions: if it's a push to a branch, a push of a tag, a pull request etc...) and simulate the different conditions.&lt;/li&gt;
&lt;li&gt;Usually developers are able to only execute a subset of tests locally but when they want to execute the same CI/CD pipeline that is executed by their CI/CD tools they face different problems:

&lt;ul&gt;
&lt;li&gt;Their local environment is not a clean environment like the one where an agola run is executed (since every task is executed inside a container).&lt;/li&gt;
&lt;li&gt;Their laptops/desktops aren't usually powerful enough to execute it.&lt;/li&gt;
&lt;li&gt;A continuous delivery system is not just for tests but for a complete workflow (i.e. building images, deploying to test/staging/production etc...), so they'd like to test everything.&lt;/li&gt;
&lt;li&gt;Usually they end up pushing to a temporary branch (if the CI/CD tool is configured to permit this) as the unique way to test if the pipeline will work.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This looked like a great idea. It'll be great if you'll be able, at any time, with just one command, to test on a powerful system the full CI/CD runs, simulate possible conditions etc...&lt;/p&gt;

&lt;p&gt;So we implemented this feature and called it &lt;strong&gt;direct runs&lt;/strong&gt; and gave users the ability to execute a run from their local directory to the agola servers with just one command (&lt;code&gt;agola directrun start&lt;/code&gt;). I ended up using direct runs many times in a day during the agola development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using direct runs.
&lt;/h2&gt;

&lt;p&gt;Using direct runs is very simple. Once you have an user token for the agola service, at every time you can execute to &lt;code&gt;agola --gateway-url "https://youragola" --toke $USERTOKEN directrun start&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This will push (more on how it works later) the local development repository to the agola server and start the runs defined in the agola config file like you pushed to a remote git repo connected to agola or created a pull request.&lt;br&gt;
By the default it'll also push git untracked files (can be disabled with &lt;code&gt;--untracked=false&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;Without more options the command will act like pushing to a &lt;code&gt;master branch&lt;/code&gt;, but you can control to which ref (and shortcuts for branches and tags) you want to push using the &lt;code&gt;--ref&lt;/code&gt;, &lt;code&gt;--branch&lt;/code&gt; or &lt;code&gt;--tag&lt;/code&gt; options. To simulate a pull request you should push to a special ref using the &lt;code&gt;--ref&lt;/code&gt; option (i.e. to simulate a github pull request you should use something like &lt;code&gt;--ref refs/pull/1/head&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;In this way you can "simulate" the runs and see the effect of them when pushing to a branch, pushing a tag or opening a pull request. Since in the run definition you can define some conditional tasks based on the source branch/tag/ref you can use these options to completely tests how a run will behave.&lt;/p&gt;

&lt;p&gt;So, if, for example, you have defined a run that will do different things when pushing to a branch or when pushing a tag, you can easily test it.&lt;/p&gt;

&lt;p&gt;You can also pass run variables using the &lt;code&gt;--var&lt;/code&gt; or &lt;code&gt;--var-file&lt;/code&gt; options.&lt;/p&gt;

&lt;p&gt;Just a little demo of this in action:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/gZE1FRcgc7U"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  How a direct run works
&lt;/h2&gt;

&lt;p&gt;Direct runs rely on two main components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An agola internal git server&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;agola directrun start&lt;/code&gt; command&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The internal git server is where the &lt;code&gt;agola directrun start&lt;/code&gt; command will push the local development git repository.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;agola directrun start&lt;/code&gt; command will create a temporary git index based on the current index, the related tree object, commit it and store it in a temporary git ref in the local git repository, everything is transparent without impacting the working tree. Then it'll push this ref to the agola git server under a user repository to the required destination ref. Then agola will be instructed to create/start the runs defined in the agola config file.&lt;/p&gt;

&lt;p&gt;Everything is git based so only the required git objects will be pushed making it really fast.&lt;/p&gt;

&lt;p&gt;We developed a library called &lt;code&gt;git-save&lt;/code&gt; to do this work, now it lives &lt;a href="https://github.com/agola-io/agola/blob/v0.1.1/internal/git-save/save.go"&gt;in the agola repository&lt;/a&gt; but we'd like to make it a standalone library since it can have many uses. It's inspired by the great &lt;a href="https://github.com/bartman/git-wip"&gt;git-wip project&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>devops</category>
      <category>git</category>
    </item>
    <item>
      <title>Building and pushing docker/OCI images with Agola and Kaniko</title>
      <dc:creator>Simone Gotti</dc:creator>
      <pubDate>Tue, 23 Jul 2019 08:18:25 +0000</pubDate>
      <link>https://forem.com/sgotti/building-and-pushing-docker-oci-images-with-agola-and-kaniko-1ihk</link>
      <guid>https://forem.com/sgotti/building-and-pushing-docker-oci-images-with-agola-and-kaniko-1ihk</guid>
      <description>&lt;p&gt;Today a common need is to build and push docker/OCI images in your CI/CD system. One of the primary issues users are facing when doing this is how to build images inside a container (Agola by default uses containers to execute run tasks). This usually requires using docker-in-docker and so privileged containers or bind mount the host docker socket. These choices can face some security issues or break the container isolation.&lt;/p&gt;

&lt;p&gt;With Agola you can build and push docker/OCI images without breaking container isolation thanks to tools like &lt;a href="https://github.com/GoogleContainerTools/kaniko"&gt;kaniko&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There's an example repository &lt;a href="https://github.com/agola-io/agola-example-kaniko"&gt;here&lt;/a&gt; that contains a simple go program that will be built and put in a docker/OCI image.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the image
&lt;/h3&gt;

&lt;p&gt;Let's walk through the &lt;a href="https://github.com/agola-io/agola-example-kaniko/blob/master/.agola/config.yml"&gt;first run definition&lt;/a&gt; in this example (the agola configuration format used in this example is the &lt;code&gt;yaml&lt;/code&gt; format. But for more advanced definitions you could use the &lt;a href="https://agola.io/doc/config/reference.html#config-file-formats"&gt;jsonnet&lt;/a&gt; format):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v0&lt;/span&gt;

&lt;span class="na"&gt;runs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build image&lt;/span&gt;
    &lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
        &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;golang:1.12-stretch&lt;/span&gt;
        &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;clone&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build the program&lt;/span&gt;
              &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;go build .&lt;/span&gt;
          &lt;span class="c1"&gt;# Copy the built binary and the Dockerfile to the workspace&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;save_to_workspace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;source_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
                  &lt;span class="na"&gt;dest_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/bin/&lt;/span&gt;
                  &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;agola-example-kaniko&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;source_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
                  &lt;span class="na"&gt;dest_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
                  &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Dockerfile&lt;/span&gt;
                    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.dockerignore&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build docker image&lt;/span&gt;
        &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gcr.io/kaniko-project/executor:debug&lt;/span&gt;
        &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/busybox/sh&lt;/span&gt;
        &lt;span class="na"&gt;working_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/workspace&lt;/span&gt;
        &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;restore_workspace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;dest_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/kaniko/executor --no-push&lt;/span&gt;
        &lt;span class="na"&gt;depends&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This run definition will build the go program and then create an image without pushing it.&lt;/p&gt;

&lt;p&gt;This is a run made of two tasks, the first one will checkout the code and build the go binary. Then it'll copy the binary and the &lt;code&gt;Dockerfile&lt;/code&gt; in the &lt;a href="https://agola.io/doc/concepts/workspaces.html"&gt;run workspace&lt;/a&gt;. The &lt;code&gt;build docker image&lt;/code&gt; task will execute kaniko and build the image.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;build docker image&lt;/code&gt; task uses the official &lt;code&gt;gcr.io/kaniko-project/executor:debug&lt;/code&gt; image. The image with debug tag is used as it provides also a busybox shell (useful for debugging purposes). We have to override the default shell since in this image the busybox binaries are in the &lt;code&gt;/busybox/&lt;/code&gt; directory. Kaniko by default expects the "docker context" inside &lt;code&gt;/workspace&lt;/code&gt;, so we'll use the &lt;code&gt;working_dir&lt;/code&gt; task option to set it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Building and Pushing the image
&lt;/h4&gt;

&lt;p&gt;Usually building the image without pushing it to a registry isn't very useful, so let's see the changes needed to also push the image.&lt;/p&gt;

&lt;p&gt;We just have to add few lines to the &lt;code&gt;build docker image&lt;/code&gt; task.&lt;/p&gt;

&lt;p&gt;Kaniko documents some ways to authenticate to gcr and aws registries and its images already include a credential helper for amazon ecr. For more information refer to the kaniko doc.&lt;/p&gt;

&lt;p&gt;For dockerhub or your own registry you should create a docker &lt;code&gt;config.json&lt;/code&gt; config file (inside &lt;code&gt;/kaniko/.docker/config.json&lt;/code&gt;) with the required auth data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v0&lt;/span&gt;

&lt;span class="na"&gt;runs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build and push image&lt;/span&gt;
    &lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
        &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build docker image&lt;/span&gt;
        &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gcr.io/kaniko-project/executor:debug&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;DOCKERREGISTRY_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://index.docker.io/v1/"&lt;/span&gt;
          &lt;span class="na"&gt;DOCKERAUTH&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;from_variable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dockerauth&lt;/span&gt;
        &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/busybox/sh&lt;/span&gt;
        &lt;span class="na"&gt;working_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/workspace&lt;/span&gt;
        &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;restore_workspace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;dest_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;generate docker config&lt;/span&gt;
              &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
                &lt;span class="s"&gt;cat &amp;lt;&amp;lt; EOF &amp;gt; /kaniko/.docker/config.json&lt;/span&gt;
                &lt;span class="s"&gt;{&lt;/span&gt;
                  &lt;span class="s"&gt;"auths": {&lt;/span&gt;
                    &lt;span class="s"&gt;"$DOCKERREGISTRY_URL": { "auth" : "$DOCKERAUTH" }&lt;/span&gt;
                  &lt;span class="s"&gt;}&lt;/span&gt;
                &lt;span class="s"&gt;}&lt;/span&gt;
                &lt;span class="s"&gt;EOF&lt;/span&gt;
          &lt;span class="c1"&gt;# build and push with kaniko. You can add more than one --destination option.&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/kaniko/executor --destination your/image:tag&lt;/span&gt;
        &lt;span class="na"&gt;depends&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The environment variable &lt;code&gt;DOCKERAUTH&lt;/code&gt; is populated from a variable defined inside the Agola projectgroup/project, while, for this example, the &lt;code&gt;DOCKERREGISTRY_URL&lt;/code&gt; value is defined in the run definition.&lt;/p&gt;

&lt;p&gt;As a note, thanks to the powerful &lt;a href="https://agola.io/doc/concepts/secrets_variables.html"&gt;Agola secrets/variables system&lt;/a&gt;, you are able to map different variables based on different conditions (branch, tag, pull request) so you can reuse the same run definition and use different registries and auths for your development branches, pull request, master branch or tags&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>docker</category>
      <category>devops</category>
    </item>
    <item>
      <title>Introducing Agola: CI/CD redefined</title>
      <dc:creator>Simone Gotti</dc:creator>
      <pubDate>Mon, 15 Jul 2019 16:24:32 +0000</pubDate>
      <link>https://forem.com/sgotti/introducing-agola-ci-cd-redefined-1bl3</link>
      <guid>https://forem.com/sgotti/introducing-agola-ci-cd-redefined-1bl3</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fagola.io%2Fscreenshots%2Fscreenshot_run_01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fagola.io%2Fscreenshots%2Fscreenshot_run_01.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There're many CI/CD tools outside, some of them are available only as SaaS (and many are free for Open Source projects but some of them are closed source), others are open source and you can install them wherever you want. So: why another CI/CD tool?&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://www.sorint.it" rel="noopener noreferrer"&gt;Sorint.lab&lt;/a&gt; we used many different CI/CD tools for years, our Open Source projects usually use free SaaS tools, internally and from our customer we used Open Source tools installed on premise. So, in the years, we got a great deal of knowledge on many CI/CD tools and learned many of their pros and cons. In the end we always struggled to achieve some features that we considered very important for such kind of tools. That's why we created our own tool: Agola.&lt;/p&gt;

&lt;p&gt;What are the requirements we tried to satisfy while designing and writing Agola?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy to install and manage.&lt;/li&gt;
&lt;li&gt;Scalable and High Available: go from a single instance (single process) deployment to a distributed deployment.&lt;/li&gt;
&lt;li&gt;Deploy anywhere: Kubernetes, IaaS, bare metal and execute the "tasks" anywhere (currently containers executors like docker or orchestrators and Kubernetes, but easily extensible to future technologies or VMs instead of containers).&lt;/li&gt;
&lt;li&gt;Support any language, deployment system etc... (just use the right image)&lt;/li&gt;
&lt;li&gt;Integrate with multiple git providers at the same time: you could add repos from github, gitlab, gitea (and more to come) inside the same agola installation.&lt;/li&gt;
&lt;li&gt;Use it to manage the full development lifecycle: from build to deploy.&lt;/li&gt;
&lt;li&gt;Tasks Workflows (that we called &lt;strong&gt;Runs&lt;/strong&gt;) with ability to achieve fan-in, fan-out, matrixes etc..., everything containerized to achieve maximum reproducibility.&lt;/li&gt;
&lt;li&gt;Git based workflow: the run definition is committed inside the git repository (so everything is tracked and reproducible). A run execution is started by a git action (push, pull-request).&lt;/li&gt;
&lt;li&gt;Design it with the ability to achieve at most once runs: during a deployment to production we don't want multiple concurrent execution of the deploy...&lt;/li&gt;
&lt;li&gt;Restartable and reproducible Runs (restart a run from scratch or from failed tasks using the same source commit, variables etc...)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://agola.io/doc/concepts/user_direct_runs.html" rel="noopener noreferrer"&gt;User Direct Runs&lt;/a&gt;: give every user the power to test their software using the same run definition used when pushing to git/opening a pull request inside the Agola installation with just one command like if they were running tests locally (without requiring a super powerful workstation).&lt;/li&gt;
&lt;li&gt;Testable "Runs" (what is a CI/CD environment if you cannot test your changes to the Runs definitions?): use the same run definition but use a powerful &lt;a href="https://agola.io/doc/concepts/secrets_variables.html" rel="noopener noreferrer"&gt;secrets and variables system&lt;/a&gt; to access different resources (environments, docker registries etc...).&lt;/li&gt;
&lt;li&gt;Don't try to extend YAML to be a templating language but use a real templating language (as of now &lt;a href="https://jsonnet.org/" rel="noopener noreferrer"&gt;jsonnet&lt;/a&gt;) to easily generate the run configuration without side effects.&lt;/li&gt;
&lt;li&gt;An advanced permissions system (work in progress).&lt;/li&gt;
&lt;li&gt;Dependency Caching to speed up tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Runs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Runs&lt;/strong&gt; are a workflow. Agola is a continuous Doer deeply integrated in a git based workflow. Agola (or better one of its main services: &lt;strong&gt;Run Service&lt;/strong&gt;) executes "commands" in an containerized and organized way. These commands can be anything, written in any language and do whatever you want. It fits perfectly for a CI/CD system.&lt;/p&gt;

&lt;p&gt;Runs are made of tasks that can depend on other tasks and execute only on some conditions, tasks are containerized executions made of multiple sequential steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Git based workflow
&lt;/h2&gt;

&lt;p&gt;We deeply integrated it in a git based workflow because to achieve the best results and automation we have to track everything. A Git workflow let you track and control everything via git. The runs definition is inside the git repository so it's deeply attached to the code and can be reviewed as everything else.&lt;br&gt;
If you love code review (we do), use pull/merge request to do it and agola will execute the run on the PR and provide the run status before you merge your changes to the "master" branch. If you use features branches Agola will execute the runs at every push and provide run status for that commit.&lt;br&gt;
If you want to deploy to production when pushing to master new commits or tags, agola can do this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agola architecture
&lt;/h3&gt;

&lt;p&gt;Agola is young but a big and ambitious project. In the next weeks we'll create more posts detailing its internals and architectural peculiarities.&lt;/p&gt;

&lt;p&gt;Just as a small taste, Agola is composed of &lt;a href="https://agola.io/doc/architecture/" rel="noopener noreferrer"&gt;multiple services&lt;/a&gt; and it's extensible by writing new service on top of its base services APIs (no old style plugins!). To be fully distributed and high available some if its services use two primary components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/etcd-io/etc" rel="noopener noreferrer"&gt;etcd&lt;/a&gt; to coordinate multiple instances (in many ways)&lt;/li&gt;
&lt;li&gt;An object storage (as of today a shared posix fs like nfs, cephfs or an s3 like compatible storage)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Someone may ask now: "where's the database?". If you mean where's a relational (talking sql language) database that stores all the config, run data etc... the answer is: there isn't.&lt;/p&gt;

&lt;p&gt;A good thing of developing something new is that you can try to do something different. Beside trying to improve the CI/CD experience we also wanted to experiment (and try to innovate) with some new architectural choices.&lt;/p&gt;

&lt;p&gt;Since we want a fully distributed and high available system we wanted to rely only on components that could be fully distributed and high available: etcd and an object storage meet these requirements. So, instead of adding a third component that will increase the project requirements and that is, as of today, difficult to scale and made high available (ok there are some products that can achieve this like &lt;a href="https://www.cockroachlabs.com/" rel="noopener noreferrer"&gt;cockroachdb&lt;/a&gt;) and be free to structure our data as we preferred, we tried to achieve a atomic, consistent, isolated and transactional store using etcd and an object storage.&lt;/p&gt;

&lt;p&gt;In this way everything is managed at the application level without putting part of the logic inside the relational database (constraints, foreign keys etc...) or relying on features that are available only on some products. But this is a big argument (and an experiment that could change or prove it wrong) that we'd like to elaborate in a future post (an hint: we are not ditching relational databases, if you look at the agola code you'll find a package called readdb that uses sqlite: yes we are using a &lt;strong&gt;per instance/local&lt;/strong&gt;, &lt;strong&gt;rebuildable&lt;/strong&gt;, &lt;strong&gt;subject to a lot of schema changes&lt;/strong&gt; relational database as a read only database for queries).&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Just try &lt;a href="https://agola.io/tryit/" rel="noopener noreferrer"&gt;the agola demo&lt;/a&gt; and see how we are using it to &lt;a href="https://github.com/agola-io/agola/blob/master/.agola/config.jsonnet" rel="noopener noreferrer"&gt;build/test agola&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Agola documentation with various examples is in the &lt;a href="https://agola.io" rel="noopener noreferrer"&gt;Agola web site&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Get in touch
&lt;/h3&gt;

&lt;p&gt;Agola is an open source project created by &lt;a href="https://www.sorint.it" rel="noopener noreferrer"&gt;Sorint.lab&lt;/a&gt; but we need a community around it. To get in touch for anything (contributing, help, proposals etc...) join the &lt;a href="https://talk.agola.io" rel="noopener noreferrer"&gt;Agola forums&lt;/a&gt; and our &lt;a href="https://github.com/agola-io" rel="noopener noreferrer"&gt;github organization&lt;/a&gt;. And don't forget to leave a star on the agola main repository (&lt;a href="https://github.com/agola-io/agola" rel="noopener noreferrer"&gt;https://github.com/agola-io/agola&lt;/a&gt;), it costs you nothing!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>continuousdelivery</category>
      <category>distributed</category>
      <category>go</category>
    </item>
  </channel>
</rss>
