<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by YNAP Tech on Medium]]></title>
        <description><![CDATA[Stories by YNAP Tech on Medium]]></description>
        <link>https://medium.com/@ynap_tech?source=rss-f5b60ea8336b------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*e4MBP_p8NcSahKLLMzX3GA.png</url>
            <title>Stories by YNAP Tech on Medium</title>
            <link>https://medium.com/@ynap_tech?source=rss-f5b60ea8336b------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 02:30:55 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@ynap_tech/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Introducing Zeitgeist: dependency management for DevOps]]></title>
            <link>https://medium.com/@ynap_tech/introducing-zeitgeist-dependency-management-for-devops-2078596ed236?source=rss-f5b60ea8336b------2</link>
            <guid isPermaLink="false">https://medium.com/p/2078596ed236</guid>
            <category><![CDATA[infrastructure]]></category>
            <category><![CDATA[package-management]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[helm]]></category>
            <category><![CDATA[kubernetes]]></category>
            <dc:creator><![CDATA[YNAP Tech]]></dc:creator>
            <pubDate>Fri, 07 Feb 2020 16:12:16 GMT</pubDate>
            <atom:updated>2020-02-07T17:00:51.299Z</atom:updated>
            <content:encoded><![CDATA[<p><em>This post originally appeared on Florent Delannoy’s personal blog. Read the original </em><a href="https://blog.florentdelannoy.com/blog/2020/introducing-zeitgeist/"><em>here</em></a><em>.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*MWPr2dSwgyhOEx9L" /><figcaption>Photo by <a href="https://unsplash.com/@mbenna?utm_source=medium&amp;utm_medium=referral">Mike Benna</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Developers are spoiled.</p><p>Every single package management system these days will allow a developer to define their project’s dependencies in a simple format, whether that’s a <a href="https://doc.rust-lang.org/cargo/reference/manifest.html">cargo.toml</a> in Rust, <a href="https://bundler.io/gemfile.html">Gemfile</a> for Ruby apps, a <a href="https://maven.apache.org/pom.html">pom.xml</a> for Maven-based projects, <a href="https://docs.npmjs.com/files/package.json">package.json</a> for NodeJS, <a href="https://getcomposer.org/doc/01-basic-usage.md">composer.json</a> in PHP…</p><p>Declaring your dependencies and their desired version in a standard, easily-parseable language allows you to track outdated dependencies, make sure you keep up to date with security updates, ensures other developers working on the same project use the same version of dependencies, lets you set up reproducible builds… The benefits are immense, and it’s universally acknowledged as a best practice in modern software development.</p><p>But when it comes to the subfield of software engineering known as Infrastructure-as-Code (also variously referred to as DevOps, or SRE, but I’ll use infrastructure-as-code through this post) though, the alternatives become rare.</p><p>It is possible, as most sysadmins are used to, to follow individual projects through mailing lists, or periodically check projects’ websites for new releases and updates. But this doesn’t scale well as you add extra dependencies, and is at its core a very manual process.</p><p><a href="https://www.chef.io/">Chef</a> probably has the most full-featured dependency management system that I’ve encountered so far, the <a href="https://supermarket.chef.io/">Chef Supermarket</a>. But it only ensures Chef cookbooks are up-to-date, and only covers the subset of the infrastructure-as-code that Chef will support. What about your cloud orchestration software? What about Chef itself?</p><p>Part of the problem is that a modern infrastructure-as-code pipeline will rely on several separate, distinct, pieces of software, depending on which part of the infrastructure is being set up: <a href="https://www.terraform.io/">Terraform</a>, <a href="https://aws.amazon.com/cloudformation/">CloudFormation</a>, <a href="https://www.chef.io/">Chef</a>/<a href="https://www.ansible.com/">Ansible</a>/<a href="https://puppet.com/">Puppet</a>, <a href="https://helm.sh/">Helm</a>… These incompatible systems are written in different languages and follow different versioning schemes, so an overarching dependency management system isn’t easy to come by.</p><p>But dependency management is a worthy goal, so let’s take a crack at it!</p><p>Based on the findings above and lessons from the <a href="https://groups.google.com/forum/?pli=1#!topic/kubernetes-dev/cTaYyb1a18I">Kubernetes project’s handling of dependencies</a>, I’d like to introduce my attempt at solving this issue: <a href="https://github.com/Pluies/zeitgeist">Zeitgeist</a>.</p><h3>Introducing <a href="https://github.com/Pluies/zeitgeist">Zeitgeist</a></h3><p>Zeitgeist is a language-agnostic dependency checker.</p><p>Zeitgeist will let you define your dependencies in a YAML file, dependencies.yaml, and help you ensure:</p><ul><li>These dependencies versions are consistent within your project</li><li>These dependencies are up-to-date</li></ul><p>The key concept that allows Zeitgeist to be language-independent is that dependencies are declared with <em>a reference to another plain-text file where that dependency is defined for the underlying tool</em>, so any infrastructure-as-code tool that lets you define your dependencies in plain-text will be supported.</p><p>For example, let’s say you build your infrastructure via Terraform, and use a pinned version of Terraform to create a Docker container that applies your infrastructure in a reproducible fashion. Your Dockerfile may look something like:</p><pre><strong>FROM</strong> alpine:3.10</pre><pre><strong>ENV</strong> TERRAFORM_VERSION=&quot;0.12.12&quot;</pre><pre><strong>RUN</strong> curl -LO <a href="https://releases.hashicorp.com/terraform/$%7BTERRAFORM_VERSION%7D/terraform_$%7BTERRAFORM_VERSION%7D_linux_amd64.zip">https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip</a> \  <br>&amp;&amp; unzip terraform_${TERRAFORM_VERSION}_linux_amd64.zip \  <br>&amp;&amp; mv terraform /bin</pre><pre><em># Install more tools, etc</em></pre><p>You can define this version of Terraform as a dependency:</p><pre>- name: terraform   <br>  version: 0.12.12<br>  upstream:<br>    flavour: github<br>    url: hashicorp/terraform   <br>  refPaths:   <br>  - path: Dockerfile<br>    match: TERRAFORM_VERSION</pre><p>The important information for dependency checking here is the refPaths: path refers to a file, and match is a string that will be searched in this file.</p><p>Zeitgeist will read the file at path, searching for a line matching match, and when found, confirm that the version declared on this line is identical to the version declared in your dependencies.yaml.</p><p>The upstream block is used to check if your local version is up-to-date with the project it references. Here, Zeitgeist will check the local version against <a href="https://github.com/hashicorp/terraform/releases">Terraform Releases on Github</a>, and let you know when an update is available.</p><p>You may then define an <a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html">AMI image</a> for an AutoScaling group <a href="https://www.terraform.io/docs/providers/aws/r/autoscaling_group.html#with-latest-version-of-launch-template">in a Terraform source file</a> that we’ll call my-asg.tf as:</p><pre><strong>resource</strong> &quot;aws_launch_template&quot; &quot;foobar&quot; {   <br>  name_prefix   = &quot;foobar&quot;   <br>  image_id      = &quot;ami-1a2b3c&quot;   <br>  instance_type = &quot;t2.micro&quot; <br>}</pre><pre><strong>resource</strong> &quot;aws_autoscaling_group&quot; &quot;bar&quot; {<br>  availability_zones = [&quot;us-east-1a&quot;]<br>  desired_capacity   = 1   <br>  max_size           = 1   <br>  min_size           = 1</pre><pre><strong>launch_template</strong> {     <br>    id      = &quot;${aws_launch_template.foobar.id}&quot;     <br>    version = &quot;$Latest&quot;   <br>  } <br>}</pre><p>Now, how do you ensure this AMI stays up to date? What if a new version gets released?</p><p>Zeitgeist can also take care of that for you! Define the dependency as:</p><pre>- name: my-example-ami   <br>  version: ami-1a2b3c   <br>  scheme: random   <br>  upstream:     <br>    flavour: ami<br>    owner: somebody     <br>    name: &quot;terraform-example-*&quot;   <br>  refPaths:   <br>  - path: my-asg.tf     <br>    match: image_id</pre><p>And Zeitgeist will let you know when a new version of the AMI is available, based on the owner and a regexp.</p><p>Another common issue is when a dependency is used in two different contexts, and these need to be kept in sync. This was the Kubernetes project’s most important requirement when implementing their solution, and I’ve followed the same yaml structure when designing Zeitgeist.</p><p>For example, <a href="https://helm.sh/">Helm</a> (up to version 3) needs two components:</p><ul><li>tiller, the server-side component of Helm, deployed on your Kubernetes cluster</li><li>The helm CLI, used locally to interact with tiller</li></ul><p>But using different versions of helm and tiller <a href="https://stackoverflow.com/questions/50701224/helm-incompatible-versions-between-client-and-server">will often result in errors</a>, so it&#39;s better to keep them in sync.</p><p>This can be expressed as a dependency with two refPaths:</p><pre>- name: helm   <br>  version: 2.12.2   <br>  upstream:     <br>    flavour: github     <br>    url: helm/helm     <br>    constraints: &lt;3.0.0   <br>  refPaths:   <br>  - path: bootstrap/tiller.yaml     <br>    match: gcr.io/kubernetes-helm/tiller   <br>  - path: helper-image/Dockerfile     <br>    match: HELM_LATEST_VERSION</pre><p>And Zeitgeist will ensure these stay in sync with each other, as well as check the upstream for updates.</p><h3>Working with Zeitgeist</h3><p>We have introduced Zeitgeist in our infrastructure-as-code pipeline late last year to check dependencies on deployment and give us a nightly dependency report of available updates.</p><p>Since then, Zeitgeist has been fulfilling its stated aim of helping us keep our infrastructure up-to-date, but its major benefit in my opinion has been the peace of mind gained by knowing that pinned versions of dependencies <em>are managed</em>, and we don’t have to worry about them silently falling behind.</p><p>Zeitgeist supports Github, AMIs, and Helm as upstreams for version checking, with more in the pipeline!</p><h3>How do I use it in my own projects?</h3><p>To use Zeitgeist in your own project, create a dependencies.yaml and run the zeitgeist command-line tool. Pre-build binaries are <a href="https://github.com/Pluies/zeitgeist/releases">available on Github</a>.</p><p><a href="https://github.com/Pluies/zeitgeist">Zeitgeist</a> is written in Go and hosted on Github under the Apache 2.0 license. Contributions, bug reports, and feature suggestions are very welcome!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2078596ed236" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Envoy, Ambassador and Istio: a gzip adventure]]></title>
            <link>https://medium.com/@ynap_tech/envoy-ambassador-and-istio-a-gzip-adventure-1fdc79bfd87b?source=rss-f5b60ea8336b------2</link>
            <guid isPermaLink="false">https://medium.com/p/1fdc79bfd87b</guid>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[performance]]></category>
            <category><![CDATA[compression]]></category>
            <category><![CDATA[infrastructure]]></category>
            <dc:creator><![CDATA[YNAP Tech]]></dc:creator>
            <pubDate>Mon, 25 Nov 2019 10:55:15 GMT</pubDate>
            <atom:updated>2019-11-25T11:02:51.989Z</atom:updated>
            <content:encoded><![CDATA[<p><em>This post originally appeared on Florent Delannoy’s personal blog. Read the original </em><a href="https://blog.florentdelannoy.com/blog/2019/envoy-ambassador-istio-gzip/"><em>here</em></a><em>.</em></p><p><a href="https://en.wikipedia.org/wiki/HTTP_compression">HTTP compression</a> is ubiquitous across the modern web as a way to trade a small amount of computing power in exchange for vastly reduced bandwidth. It is usually achieved with the gzip algorithm, so I’ll refer to HTTP compression and gzip compression interchangeably in this post.</p><p>YOOX NET-A-PORTER GROUP uses compression across the board to load pages faster, which makes users happier, and reduce bandwidth costs, which also makes the finance department happier.</p><p>When we set up a new Kubernetes-based infrastructure for public-facing websites, we started using <a href="https://www.getambassador.io/">Ambassador</a> as a reverse-proxy for all inbound HTTP calls, and <a href="https://istio.io/">Istio</a> as a service mesh. Under the hood, both of these projects use the open-source <a href="https://www.envoyproxy.io/">Envoy</a> reverse-proxy, originally developed at Lyft.</p><p>This setup has proved to be extremely flexible and performant, and after ironing out a few kinks we’ve been really happy with it.</p><p>However, after moving a few markets over, monitoring showed that our average page size and outbound traffic had grown a sizeable bit, which couldn’t be explained by the application payload: it had to be infrastructure-related. After investigating, we found out that gzip compression was much worse on the new stack than it was on the older stack.</p><p>… And that was despite the older stack not having gzip compression enabled at all!</p><h3>Enter Akamai</h3><p>We use <a href="https://www.akamai.com/">Akamai</a> as a Content Delivery Network. All calls to our infrastructure first go through Akamai, which ensures faster delivery thanks to having PoPs much closer to clients than our servers could be, and adds extra features like protection against DDOS attacks, caching, etc.</p><p>Akamai’s coverage is… Extensive:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*nkxTlTtqJKYFTjqj.png" /><figcaption><em>Do you have servers </em><a href="https://www.akamai.com/uk/en/solutions/intelligent-platform/visualizing-akamai/media-delivery-map.jsp"><em>in Antarctica?</em></a></figcaption></figure><p>And, crucially… When a client supports compression and the response that Akamai receives from our origin servers is not compressed, it will go ahead and compress it before returning it to the client. However, if the response from the origin server is <em>already</em> compressed, Akamai will send it to the client as-is: compression twice is useless, and decompressing + recompressing every request is wasteful.</p><p>So, counter-intuitively, enabling gzip compression on our origin backends made compression worse for the clients, as Akamai had better compression performance. We could have just deactivated gzip compression altogether on our origin servers and relied on Akamai to do it, but we also wanted to reduce bandwidth between origin servers and Akamai.</p><p>So we decided to investigate: what is wrong with our own gzip compression?</p><h3>Gzip measurements &amp; parameter tuning</h3><p>We wrote a small benchmark to examine the compression ratio of various reverse-proxies to see:</p><ul><li>If the issue we were facing was specific to Ambassador/Envoy</li><li>Which compression options had an impact</li><li>How the competitors stacked up</li></ul><p>The benchmark’s source and instructions to reproduce can be found on Github: <a href="https://github.com/Pluies/gzip-comparison">https://github.com/Pluies/gzip-comparison</a></p><p>And here is a representative sample:</p><pre>~/projects/gzip-comparison λ ./compare.sh assets/youtube.com.html<br>Comparing compression performance for file: assets/youtube.com.html (all sizes in bytes)<br>origin, uncompressed      247602<br>nginx, base               45826<br>nginx, optimised          38924<br>ambassador, base          55904<br>ambassador, optimised     55804<br>envoy, base               55907<br>envoy, optimised          43763<br>apache, base              38831<br>apache, optimised         38972<br>local gzip, base          39126<br>local gzip, optimised     38941</pre><p>Or as a graph:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*CRuHjucRFcEicemB.png" /></figure><p>The two main takeaways from this test:</p><ul><li>Most servers compress gzip at very similar ratios, similar to the stand-alone gzip utility</li><li>Ambassador produced files <em>40% larger</em> than most servers, even “optimised”!</li></ul><p>Using Envoy directly, we were able to reduce the size by setting the <a href="https://www.envoyproxy.io/docs/envoy/latest/api-v2/config/filter/http/gzip/v2/gzip.proto.html">window_bits parameter</a> to 15, which produced compressed files about 10% larger than other servers. Still not ideal, but a sizeable improvement.</p><p>We also started using this configuration in our Istio mesh to enable compression as widely as possible.</p><p>Ambassador did not expose this setting, but it is open-source! We opened <a href="https://github.com/datawire/ambassador/pull/1890">pull request #1890</a> which got merged within a few days. 🎉</p><h3>Envoy and gzip</h3><p>Even after tuning all available parameters, we are still left with a ~10 to 12% performance degradation by using Envoy, compared to virtually all other options tested.</p><p>We’ve opened <a href="https://github.com/envoyproxy/envoy/issues/8448">Envoy issue #8448</a> to report back our findings, with benchmark results. This is treated as a bug, and hopefully will be fixed in the future 🤞</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1fdc79bfd87b" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>