<?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>DEV Community: Jérémie Drouet</title>
    <description>The latest articles on DEV Community by Jérémie Drouet (@jdrouet).</description>
    <link>https://dev.to/jdrouet</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%2F49524%2F0b34c006-74c2-4b50-bea4-4ac601205289.png</url>
      <title>DEV Community: Jérémie Drouet</title>
      <link>https://dev.to/jdrouet</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jdrouet"/>
    <language>en</language>
    <item>
      <title>Build metrics and budgets with git-metrics</title>
      <dc:creator>Jérémie Drouet</dc:creator>
      <pubDate>Wed, 07 Aug 2024 16:30:14 +0000</pubDate>
      <link>https://dev.to/jdrouet/build-metrics-and-budgets-with-git-metrics-4pb4</link>
      <guid>https://dev.to/jdrouet/build-metrics-and-budgets-with-git-metrics-4pb4</guid>
      <description>&lt;h1&gt;
  
  
  Build metrics and budgets with git-metrics
&lt;/h1&gt;

&lt;p&gt;Monitoring metrics for a project can be challenging. Deciding what to track, determining the cardinality of each tag, naming the metrics, and choosing what should be split into a tag or kept as a metric are all complex tasks that require experience.&lt;/p&gt;

&lt;p&gt;But monitoring the run of your project is not the only thing we need to monitor; the development phase is also important. Code coverage is a good example of how we monitor the build of a project. Many projects implement rules to prevent code coverage from decreasing. In the frontend world, there is a growing trend to track metrics such as page size and load time. This kind of monitoring might seem less complicated, but determining where and how to store the metrics is more challenging.&lt;/p&gt;

&lt;p&gt;In recent years, I've been working on several projects where I wanted to put in place such boundaries. When looking at how to implement that, I always ended up using multiple external services or deploying applications to store those metrics that I would have to keep running all the time. This didn't match my requirements. I wanted to keep that cheap in terms of resource usage and low in terms of maintenance. I don't want to have a VPS running 24/7 just to push some metrics.&lt;/p&gt;

&lt;p&gt;With global warming already well established, and human activity being the principal reason for it, we should rethink the way we build software. We cannot keep increasing exponentially the resource usage of our systems. Therefore, we need to put in place boundaries on the projects we build.&lt;/p&gt;

&lt;h2&gt;
  
  
  State of the Art
&lt;/h2&gt;

&lt;p&gt;For open-source projects, many SaaS platforms offer free tiers for monitoring. For tracking code coverage, you can use &lt;a href="https://codecov.io" rel="noopener noreferrer"&gt;Codecov&lt;/a&gt; or &lt;a href="https://coveralls.io" rel="noopener noreferrer"&gt;Coveralls&lt;/a&gt;. For tracking complexity, &lt;a href="https://codeclimate.com" rel="noopener noreferrer"&gt;CodeClimate&lt;/a&gt; is a good option. These platforms integrate well with GitHub repositories.&lt;/p&gt;

&lt;p&gt;For closed-source projects, these SaaS platforms offer paid subscriptions, which may require budget considerations. Alternatively, if your DevOps team has the bandwidth, you can set up tools like &lt;a href="https://www.sonarsource.com/products/sonarqube/" rel="noopener noreferrer"&gt;SonarQube&lt;/a&gt; for in-house monitoring.&lt;/p&gt;

&lt;p&gt;However, be prepared for potential vendor lock-in, which can make switching services or losing historical data problematic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternative Approach
&lt;/h2&gt;

&lt;p&gt;Shouldn’t the metrics related to the code be attached to the code itself?&lt;/p&gt;

&lt;p&gt;Some projects, such as &lt;a href="https://github.com/actions/typescript-action" rel="noopener noreferrer"&gt;typescript-action&lt;/a&gt;, version code coverage alongside the code. This approach isn't perfect, as it requires developers to update the metrics for each commit, or you need a CI job to keep them in sync. However, keeping metrics directly in Git is appealing as it provides easy access and avoids reliance on external services. Switching from GitHub to GitLab, for instance, would be as simple as pushing the repository.&lt;/p&gt;

&lt;p&gt;To address synchronization issues, instead of writing these metrics with the code, they can be kept next to it. Git offers a feature called &lt;a href="https://git-scm.com/docs/git-notes" rel="noopener noreferrer"&gt;&lt;code&gt;notes&lt;/code&gt;&lt;/a&gt;, which allows attaching textual data to a commit reference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution Implementation
&lt;/h2&gt;

&lt;p&gt;This is where &lt;a href="https://github.com/jdrouet/git-metrics" rel="noopener noreferrer"&gt;&lt;code&gt;git-metrics&lt;/code&gt;&lt;/a&gt; comes into play.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Usage
&lt;/h3&gt;

&lt;p&gt;With &lt;code&gt;git-metrics&lt;/code&gt;, you can attach, replace, or remove metrics for a given commit with a simple command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git-metrics add my-metric-name &lt;span class="nt"&gt;--tag&lt;/span&gt; &lt;span class="s2"&gt;"foo: bar"&lt;/span&gt; 1024.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To show the metrics attached to a given commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git metrics show &amp;lt;commit-sha&amp;gt;
my-metric-name&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"bar"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt; 1024.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To display a list of all commits, or within a commit range:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git metrics diff HEAD~2..HEAD
- my-metric-name&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"bar"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt; 512.0
+ my-metric-name&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"bar"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt; 1024.0 &lt;span class="o"&gt;(&lt;/span&gt;+200.00 %&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These commands provide a solid foundation, but there are additional features worth exploring.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extra features
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Budget management
&lt;/h4&gt;

&lt;p&gt;Tracking metrics is useful, but the goal is to improve the codebase or project. One way to ensure this is by blocking commits that don’t meet certain metric criteria, a feature already used by many external services.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;git-metrics&lt;/code&gt;, you can configure rules by adding a &lt;code&gt;.git-metrics.toml&lt;/code&gt; file to your repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# fails when increase size is above 10%&lt;/span&gt;
&lt;span class="nn"&gt;[[metrics.binary-size.rules]]&lt;/span&gt;
&lt;span class="py"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"max-increase"&lt;/span&gt;
&lt;span class="py"&gt;ratio&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;

&lt;span class="c"&gt;# fails when the size increases by more that 1MB&lt;/span&gt;
&lt;span class="nn"&gt;[[metrics.binary-size.rules]]&lt;/span&gt;
&lt;span class="py"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"max-increase"&lt;/span&gt;
&lt;span class="py"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1048576.0&lt;/span&gt;

&lt;span class="c"&gt;# fails when binary size is more than 10MB&lt;/span&gt;
&lt;span class="nn"&gt;[[metrics.binary-size.rules]]&lt;/span&gt;
&lt;span class="py"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"max"&lt;/span&gt;
&lt;span class="py"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;10485760.0&lt;/span&gt;

&lt;span class="c"&gt;# fails when the code coverage goes below 80%&lt;/span&gt;
&lt;span class="nn"&gt;[[metrics."coverage.lines.percentage".rules]]&lt;/span&gt;
&lt;span class="py"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"min"&lt;/span&gt;
&lt;span class="py"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;

&lt;span class="c"&gt;# fails when the code coverage decreases of more than 5%&lt;/span&gt;
&lt;span class="nn"&gt;[[metrics."coverage.lines.percentage".rules]]&lt;/span&gt;
&lt;span class="py"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"max-decrease"&lt;/span&gt;
&lt;span class="py"&gt;ratio&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.05&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running &lt;code&gt;git-metrics check&lt;/code&gt; from your CI after adding your metrics will inform you if your changes meet the specified budget.&lt;/p&gt;

&lt;h4&gt;
  
  
  Importing from other file formats
&lt;/h4&gt;

&lt;p&gt;Manually adding metrics with the &lt;code&gt;add&lt;/code&gt; command can be cumbersome, especially for derived metrics. For instance, after computing code coverage, you might end up with an &lt;code&gt;lcov&lt;/code&gt; file, which needs to be processed to extract useful metrics. &lt;code&gt;git-metrics&lt;/code&gt; can handle this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git-metrics import lcov ./lcov.info
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command adds summary metrics such as &lt;code&gt;coverage.lines.count&lt;/code&gt;, &lt;code&gt;coverage.functions.hit&lt;/code&gt;, or &lt;code&gt;coverage.branches.percentage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Currently, &lt;code&gt;git-metrics&lt;/code&gt; supports only &lt;code&gt;lcov&lt;/code&gt; files, but more formats will be supported as the tool evolves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;git-metrics&lt;/code&gt; is in its early stages but already provides essential commands for tracking metrics, creating budgets, and blocking contributions that don’t meet the budget criteria, all within your git repository.&lt;/p&gt;

&lt;p&gt;Similar to the mentioned SaaS solutions, git-metrics offers &lt;a href="https://github.com/jdrouet/action-git-metrics" rel="noopener noreferrer"&gt;GitHub actions&lt;/a&gt; for installation, tracking, and checking metrics. GitLab support is expected soon.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Article also available &lt;a href="https://github.com/jdrouet/jdrouet/blob/master/articles/202408041030-git-metrics.md" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>rust</category>
      <category>metrics</category>
      <category>budgets</category>
    </item>
    <item>
      <title>Mailer sender microservice</title>
      <dc:creator>Jérémie Drouet</dc:creator>
      <pubDate>Mon, 26 Oct 2020 15:51:06 +0000</pubDate>
      <link>https://dev.to/jdrouet/mailer-sender-microservice-4pd1</link>
      <guid>https://dev.to/jdrouet/mailer-sender-microservice-4pd1</guid>
      <description>&lt;p&gt;I've been working for many companies until now, banks, service companies, small startups or big startups, and sending emails was always a challenge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;First there is the problem of output. It's pretty hard to have a mail that renders on mobile as well as in Outlook.&lt;/p&gt;

&lt;p&gt;Then comes the implementation where the language that is used is not always the same, the architecture is different between projects or the developers don't have time to spend on the mailing feature.&lt;/p&gt;

&lt;p&gt;It's quite easy to create a fully featured implementation in a big monolith, but the email service doesn't usually need to be scaled as much as the rest. So separating it as a microservice seems to be the right way to do it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the solutions?
&lt;/h2&gt;

&lt;p&gt;As well as one doesn't reimplement a database (or more an ORM) each time it's needed, using a microservice to build, interpolate and send emails seems like the smart move.&lt;/p&gt;

&lt;p&gt;Of course, you could go for a SaaS, pay some money to get access to lots of features that you probably don't need and be tied to their solution.&lt;/p&gt;

&lt;p&gt;Or you could go for a fully open source solution, providing everything you need, it's probably not worth the time to reimplement everything. And that's where &lt;a href="https://github.com/jdrouet/catapulte" rel="noopener noreferrer"&gt;Catapulte&lt;/a&gt; comes into play.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Catapulte?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/jdrouet/catapulte" rel="noopener noreferrer"&gt;Catapulte&lt;/a&gt; is a micro-service, implemented in Rust, and built on top of &lt;a href="https://github.com/jdrouet/mrml" rel="noopener noreferrer"&gt;MRML&lt;/a&gt;, the Rust implementation of the nice &lt;a href="https://mjml.io/" rel="noopener noreferrer"&gt;MJML&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;It comes with the possibility of declaring templates, using variables and interpolating them before sending the email.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should you use Catapulte?
&lt;/h2&gt;

&lt;p&gt;Mainly because it makes it easier to build an email template, bundle it and push it to production. And if it's not easy enough, it's possible to couple it with &lt;a href="https://github.com/jdrouet/jolimail" rel="noopener noreferrer"&gt;Jolimail&lt;/a&gt; to allow anyone to edit your email templates from their browser and have a dynamic preview.&lt;/p&gt;

&lt;p&gt;The Second advantage is that it doesn't use much RAM (3Mo on the &lt;a href="https://jolimail.io" rel="noopener noreferrer"&gt;demo instance&lt;/a&gt;) and is really low in CPU consumption. It's mainly distributed through a lightweight &lt;a href="https://hub.docker.com/r/jdrouet/catapulte" rel="noopener noreferrer"&gt;docker image&lt;/a&gt; that allows you to run it almost everywhere (a laptop, an old computer, a server, a Raspberry PI, in the cloud, ...). And because it's a layer of abstraction in front of the SMTP server, it offers the possibility to start multiple instances with different SMTP server and load balance between them.&lt;/p&gt;

&lt;p&gt;To finish up, it's open source, you don't have to maintain it (although &lt;a href="https://github.com/jdrouet/catapulte" rel="noopener noreferrer"&gt;you're welcome to contribute&lt;/a&gt;), so it costs almost nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can you use Catapulte?
&lt;/h2&gt;

&lt;p&gt;If you want to try it, there is an &lt;a href="https://jolimail.io/demo" rel="noopener noreferrer"&gt;demo instance of the Jolimail suite&lt;/a&gt; available.&lt;/p&gt;

&lt;p&gt;In order to use it locally, it's also pretty straightforward, your will need to have Docker installed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; catapulte &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;SMTP_HOSTNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;localhost &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;SMTP_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;25 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;SMTP_USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;optional &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;SMTP_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;optional &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;TEMPLATE_PROVIDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;TEMPLATE_ROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/templates &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; /path/to/your/templates:/templates:ro &lt;span class="se"&gt;\&lt;/span&gt;
  jdrouet/catapulte:canary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And voila, it's ready to send emails using curl.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{"from":"alice@example.com","to":"bob@example.com","params":{"some":"data"}}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  http://localhost:3000/templates/the-name-of-your-template
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Sending emails properly is more time consuming than complicated to implement. It's now your choice if you want to reinvent the wheel or to use an open source solution that comes with many advantages. Spending time on your business features is probably more important.&lt;/p&gt;

</description>
      <category>mail</category>
      <category>microservices</category>
      <category>rust</category>
    </item>
    <item>
      <title>Hacktoberfest, the good kick</title>
      <dc:creator>Jérémie Drouet</dc:creator>
      <pubDate>Sun, 18 Oct 2020 14:56:03 +0000</pubDate>
      <link>https://dev.to/jdrouet/hacktoberfest-the-good-kick-2kkh</link>
      <guid>https://dev.to/jdrouet/hacktoberfest-the-good-kick-2kkh</guid>
      <description>&lt;h2&gt;
  
  
  Jolimail Overview
&lt;/h2&gt;

&lt;p&gt;Before joining Docker and then Datadog, I used to build applications for clients. Each application had to have a way to send transactional emails and the available solutions for that were never awesome, nor installable on premise.&lt;/p&gt;

&lt;p&gt;Last year I decided to make a big move from the JS environment to Rust and decided to implement the nice &lt;a href="https://mjml.io/" rel="noopener noreferrer"&gt;MJML Framework&lt;/a&gt; in &lt;a href="https://crates.io/crates/mrml" rel="noopener noreferrer"&gt;Rust&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;From that, came &lt;a href="https://github.com/jdrouet/catapulte" rel="noopener noreferrer"&gt;Catapulte&lt;/a&gt; which is a microservice that &lt;strong&gt;only&lt;/strong&gt; generate emails, interpolates variables and sends the email.&lt;/p&gt;

&lt;p&gt;But the solution given by &lt;a href="https://github.com/jdrouet/catapulte" rel="noopener noreferrer"&gt;Catapulte&lt;/a&gt; was not what I expected: you still had to develop the template by hand and put it in the &lt;a href="https://github.com/jdrouet/catapulte" rel="noopener noreferrer"&gt;Catapulte&lt;/a&gt; container you run in production.&lt;/p&gt;

&lt;p&gt;From that, was born &lt;a href="https://jolimail.io" rel="noopener noreferrer"&gt;Jolimail&lt;/a&gt; which allows you to edit the Mjml template in the browser and have a direct preview. And the big advantage of the &lt;a href="https://crates.io/crates/mrml" rel="noopener noreferrer"&gt;Rust&lt;/a&gt; implementation is that everything is running in the browser. As opposed to MJML that cannot run in the browser and has to make a backend call each time you have to render your template.&lt;/p&gt;

&lt;p&gt;The other advantage is, although we don't have a WYSIWYG editor yet, that anybody can edit a template in &lt;a href="https://github.com/jdrouet/jolimail" rel="noopener noreferrer"&gt;Jolimail&lt;/a&gt;, make several different versions, but only publish the one they want when they're ready.&lt;/p&gt;




&lt;h2&gt;
  
  
  My Hacktoberfest Experience
&lt;/h2&gt;

&lt;p&gt;As of today, the whole suite is working, you can host a &lt;a href="https://github.com/jdrouet/jolimail" rel="noopener noreferrer"&gt;Jolimail&lt;/a&gt; instance and a &lt;a href="https://github.com/jdrouet/catapulte" rel="noopener noreferrer"&gt;Catapulte&lt;/a&gt; instance, and send emails.&lt;/p&gt;

&lt;p&gt;The main features to come will be to implement a WYSIWYG editor and another microservice to have the confirmation of reception for the emails.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned From Hacktoberfest
&lt;/h2&gt;

&lt;p&gt;You've to make a checklist and stick to it. When you work on your own project, you can be easily distracted. You don't have a constraint (maybe time) on what you've to do, so you easily digress. So, to be sure you don't go out of the way, make a checklist and go!&lt;/p&gt;

</description>
      <category>hacktoberfest</category>
      <category>opensource</category>
      <category>contributorswanted</category>
    </item>
    <item>
      <title>Building multi arch Docker images without using qemu</title>
      <dc:creator>Jérémie Drouet</dc:creator>
      <pubDate>Wed, 23 Sep 2020 12:09:01 +0000</pubDate>
      <link>https://dev.to/jdrouet/building-multi-arch-docker-images-without-using-qemu-322c</link>
      <guid>https://dev.to/jdrouet/building-multi-arch-docker-images-without-using-qemu-322c</guid>
      <description>&lt;p&gt;Lately I've been doing lots of Rust with &lt;a href="https://github.com/jdrouet/mrml" rel="noopener noreferrer"&gt;MRML&lt;/a&gt;, &lt;a href="https://github.com/jdrouet/catapulte" rel="noopener noreferrer"&gt;Catapulte&lt;/a&gt; and &lt;a href="https://github.com/jdrouet/jolimail" rel="noopener noreferrer"&gt;Jolimail&lt;/a&gt;, and one of the pain points of Rust is that the compiling process is pretty slow. When, on top of that, you want to build it for amd64, i386, arm64 and arm32v7 because your application is open source and supposed to work everywhere, it becomes a bit tricky to make it build.&lt;/p&gt;

&lt;p&gt;Candidly, I initially tried to build it using docker and Qemu for multiple architectures but I finished &lt;a href="https://github.com/jdrouet/docker-bug-value-too-long" rel="noopener noreferrer"&gt;with some weird errors&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After a bit of chatting with my previous colleagues from Docker, I was encouraged to try to cross compile. Cross compiling is really great when you don't have a lib dependency on the system. But &lt;a href="https://github.com/jdrouet/catapulte" rel="noopener noreferrer"&gt;Catapulte&lt;/a&gt; and &lt;a href="https://github.com/jdrouet/jolimail" rel="noopener noreferrer"&gt;Jolimail&lt;/a&gt; are based on &lt;a href="https://crates.io/crates/actix" rel="noopener noreferrer"&gt;actix&lt;/a&gt; which depends on OpenSSL, which is supposed to be compiled for the architecture. In short, to cross compile your rust code you first have to cross compile OpenSSL. If you have other libraries, well, cross compile them.&lt;/p&gt;

&lt;p&gt;So I did it for &lt;a href="https://github.com/jdrouet/jolimail/blob/master/crosscompile.Dockerfile" rel="noopener noreferrer"&gt;Jolimail&lt;/a&gt;, it cross compiles, but deep down, I don't like this approach for several reason. First, I've to handle the build of OpenSSL. If there is a new version, I've to update everything and not only rebuild my image. Then, it adds an unwanted complexity to my Dockerfile. So I decided to find another way to do this.&lt;/p&gt;

&lt;p&gt;After a bit of digging and a good hint from a nice user on the docker slack community (Billy), I finally did my first use of &lt;code&gt;docker buildx create --append&lt;/code&gt;. If you're not familiar with &lt;code&gt;docker buildx&lt;/code&gt; and multi arch images, I encourage you to take a look at &lt;a href="https://www.docker.com/blog/multi-arch-build-and-images-the-simple-way/" rel="noopener noreferrer"&gt;the article I wrote&lt;/a&gt;, back when I was at Docker.&lt;/p&gt;

&lt;p&gt;When you are on an amd64 machine and you want to make a multi arch image, the initial &lt;code&gt;buildx&lt;/code&gt; solution is to use Qemu to emulate the target environment. But you can also, when you create a &lt;code&gt;buildx&lt;/code&gt; context, specify a context target for a specific platform.&lt;/p&gt;

&lt;p&gt;Like lots of my peers, I bought every version of the raspberry pi, I even have several of each version, but I don't really have time to properly use them. So I started one (3b+ I guess) and installed &lt;a href="https://blog.hypriot.com/" rel="noopener noreferrer"&gt;HypriotOS&lt;/a&gt; on it (take a look, install it, test it, it's great). I then created a &lt;a href="https://docs.docker.com/engine/context/working-with-contexts/" rel="noopener noreferrer"&gt;context&lt;/a&gt; to be able to build on the raspberry pi from my local machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker context create rpi &lt;span class="nt"&gt;--docker&lt;/span&gt; &lt;span class="s2"&gt;"host=ssh://pirate@black-pearl"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When this is done, I am able to target the raspberry pi by doing &lt;code&gt;DOCKER_CONTEXT=rpi docker pull jdrouet/kaamelott-quote&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then the trick is to tell &lt;code&gt;buildx&lt;/code&gt; that, when it needs to build the image for &lt;code&gt;arm32v7&lt;/code&gt;, it should use the context &lt;code&gt;rpi&lt;/code&gt;.&lt;br&gt;
First, I use &lt;code&gt;docker buildx ls&lt;/code&gt; to get the name of the current builder. Then, I append the context to this builder with the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker buildx create &lt;span class="nt"&gt;--append&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; you-builder-name &lt;span class="nt"&gt;--platform&lt;/span&gt; linux/arm/v7 rpi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it! I can now build your multi arch image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker buildx build &lt;span class="nt"&gt;--tag&lt;/span&gt; jdrouet/catapulte:some-tag &lt;span class="nt"&gt;--platform&lt;/span&gt; linux/amd64,linux/i386,linux/arm/v7 &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>docker</category>
      <category>buildx</category>
      <category>raspberrypi</category>
    </item>
    <item>
      <title>Multi arch images with docker</title>
      <dc:creator>Jérémie Drouet</dc:creator>
      <pubDate>Wed, 27 Nov 2019 10:40:06 +0000</pubDate>
      <link>https://dev.to/jdrouet/multi-arch-images-with-docker-152f</link>
      <guid>https://dev.to/jdrouet/multi-arch-images-with-docker-152f</guid>
      <description>&lt;p&gt;Most of the time, when I start a project, I like to try to install it everywhere to test it. Since I have a cluster of Raspberry PIs, I love to install my projects on it and see how they evolve, where they could break and fix the issues.&lt;/p&gt;

&lt;p&gt;To do so, I try to get as close a possible to my production configuration. So I usually put in place a CI/CD that test, build and deploy my projects. But when it comes to build my Docker Images for ARMv7 on a regular CI, it tends to become a bit complicated. You need to have Qemu available on the CI to emulate the target platform.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# depending on the CI&lt;/span&gt;
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--privileged&lt;/span&gt; hypriot/qemu-register
&lt;span class="c"&gt;# or&lt;/span&gt;
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--privileged&lt;/span&gt; multiarch/qemu-user-static:register &lt;span class="nt"&gt;--reset&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When this is done, I also want to try the image on my laptop. So, on the CI, we have to build for different architectures with the same Dockerfile.&lt;/p&gt;

&lt;p&gt;One way to do it would be to have and argument in our Dockerfile to specify the platform.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; BASE_ARCH=amd64&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ${BASE_ARCH}/alpine&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once this is done, I "just" have to build several times on my favorite CI, create a &lt;a href="https://docs.docker.com/engine/reference/commandline/manifest/" rel="noopener noreferrer"&gt;manifest&lt;/a&gt; and annotate each image in a final stage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;BASE_ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;amd64 &lt;span class="nt"&gt;-t&lt;/span&gt; my_image:amd64-latest &lt;span class="nb"&gt;.&lt;/span&gt;
docker build &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;BASE_ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm32v7 &lt;span class="nt"&gt;-t&lt;/span&gt; my_image:arm32v7-latest &lt;span class="nb"&gt;.&lt;/span&gt;
docker manifest create my_image:latest my_image:amd64-latest my_image:arm32v7-latest
docker manifest annotate &lt;span class="nt"&gt;--arch&lt;/span&gt; amd64 my_image:latest my_image:amd64-latest
docker manifest annotate &lt;span class="nt"&gt;--arch&lt;/span&gt; armv7 my_image:latest my_image:arm32v7-latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok, you can say it, it's pretty verbose.&lt;/p&gt;

&lt;p&gt;Luckily, the Docker Team (relatively) recently released &lt;a href="https://github.com/docker/buildx" rel="noopener noreferrer"&gt;buildx&lt;/a&gt; in Tech Preview. What this does is that it will build all the images, do the manifest and annotate everything in only 1 command.&lt;/p&gt;

&lt;p&gt;First we have to remove the argument from our dockerfile because it became useless. If we create an image from a multiarch image, buildx will manage the rest.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker buildx build &lt;span class="nt"&gt;--platform&lt;/span&gt; linux/arm/v7,linux/amd64 &lt;span class="nt"&gt;-t&lt;/span&gt; my_image:latest &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, I can use the image on any of the 2 platforms without having to use different images.&lt;/p&gt;

&lt;p&gt;Ok, now this is nice but buildx is only available in experimental and requires Docker Engine 18.09+. And depending on the CI that is going to be used, the installation will more or less differ. So I prepared &lt;a href="https://github.com/jdrouet/docker-on-ci/" rel="noopener noreferrer"&gt;a repository&lt;/a&gt; containing an example of multi arch build with &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;Github Actions&lt;/a&gt;, &lt;a href="https://circleci.com/" rel="noopener noreferrer"&gt;Circle CI&lt;/a&gt;, &lt;a href="https://travis-ci.org/" rel="noopener noreferrer"&gt;Travis CI&lt;/a&gt; and &lt;a href="https://about.gitlab.com/product/continuous-integration/" rel="noopener noreferrer"&gt;Gitlab CI&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>multiarch</category>
      <category>ci</category>
      <category>raspberrypi</category>
    </item>
  </channel>
</rss>
