<?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: Stéphane Brunner</title>
    <description>The latest articles on DEV Community by Stéphane Brunner (@sbrunner).</description>
    <link>https://dev.to/sbrunner</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%2F376790%2F2a750749-384f-4e0c-a104-a0b79f0d0936.jpeg</url>
      <title>DEV Community: Stéphane Brunner</title>
      <link>https://dev.to/sbrunner</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sbrunner"/>
    <language>en</language>
    <item>
      <title>HELM application chart on 2025</title>
      <dc:creator>Stéphane Brunner</dc:creator>
      <pubDate>Wed, 19 Feb 2025 11:17:37 +0000</pubDate>
      <link>https://dev.to/camptocamp-geo/helm-application-chart-on-2025-4gpp</link>
      <guid>https://dev.to/camptocamp-geo/helm-application-chart-on-2025-4gpp</guid>
      <description>&lt;h1&gt;
  
  
  Application Helm Chart
&lt;/h1&gt;

&lt;p&gt;A universal Helm chart for streamlined Kubernetes deployments with simplified configuration.&lt;br&gt;
Creates standard resources like Deployments, Ingress, PodMonitors (Prometheus), and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Writing a Helm chart for even a small application can get really tedious, as it involves a lot of repetitive tasks and templating is not very user-friendly. However, with the Helm application, you can make the task much easier and fun to use!&lt;/p&gt;

&lt;p&gt;We developed this unified chart because our applications share common deployment patterns. Managing multiple similar charts became time-consuming and maintenance-heavy.&lt;/p&gt;

&lt;p&gt;This chart manages extended standard Kubernetes objects to simplify application deployment using only YAML configuration. While staying close to native Kubernetes syntax, it allows all settings to be overridden in sub-values YAML files using dictionaries with meaningful keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Support for multiple workloads (Deployment, CronJob, Job, or StatefulSet)&lt;/li&gt;
&lt;li&gt;Internal resource linking (Secret, ConfigMap, and ExternalSecret to env and volume, ...)&lt;/li&gt;
&lt;li&gt;Environment variable management from various sources (values, ConfigMap, Secret, ExternalSecret)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Kubernetes Adaptations
&lt;/h2&gt;

&lt;p&gt;While staying close to standard Kubernetes manifests, this chart implements these enhancements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Converts lists to dictionaries for easier value overrides&lt;/li&gt;
&lt;li&gt;Provides flexible environment variable definitions&lt;/li&gt;
&lt;li&gt;Implements image configuration with hash pinning and metadata storage&lt;/li&gt;
&lt;li&gt;Adds standard Kubernetes labels to all components:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;app.kubernetes.io/name&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;app.kubernetes.io/instance&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;app.kubernetes.io/component&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;helm.sh/chart&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;app.kubernetes.io/version&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;app.kubernetes.io/managed-by&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Links components using standard labels:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;app.kubernetes.io/name&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;app.kubernetes.io/instance&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;app.kubernetes.io/component&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Supports special selectors (&lt;code&gt;self&lt;/code&gt;, &lt;code&gt;self-metadata&lt;/code&gt;, &lt;code&gt;self-external&lt;/code&gt;) for internal resources&lt;/li&gt;

&lt;li&gt;Handles Docker registry secret configuration automatically&lt;/li&gt;

&lt;li&gt;Supports metadata ConfigMap generation&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Supported Resources
&lt;/h2&gt;

&lt;p&gt;Kubernetes standard objects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/" rel="noopener noreferrer"&gt;Deployments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/" rel="noopener noreferrer"&gt;CronJob&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/job/" rel="noopener noreferrer"&gt;Job&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/" rel="noopener noreferrer"&gt;StatefulSet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/disruptions/#pod-disruption-budgets" rel="noopener noreferrer"&gt;PodDisruptionBudget&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/concepts/configuration/configmap/" rel="noopener noreferrer"&gt;ConfigMap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/concepts/configuration/secret/" rel="noopener noreferrer"&gt;Secret&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/" rel="noopener noreferrer"&gt;HorizontalPodAutoscaler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/" rel="noopener noreferrer"&gt;Service&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/concepts/services-networking/ingress/" rel="noopener noreferrer"&gt;Ingress&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/concepts/security/service-accounts/" rel="noopener noreferrer"&gt;ServiceAccount&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Common third-party objects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://external-secrets.io/" rel="noopener noreferrer"&gt;ExternalSecrets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://prometheus-operator.dev/docs/getting-started/design/#podmonitor" rel="noopener noreferrer"&gt;PodMonitor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Planned additions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/concepts/workloads/autoscaling/#scaling-workloads-vertically" rel="noopener noreferrer"&gt;VerticalPodAutoscaler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/concepts/services-networking/network-policies/" rel="noopener noreferrer"&gt;NetworkPolicy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Examples
&lt;/h2&gt;

&lt;p&gt;An example showing how to deploy a Deployment with an ExternalSecret and Docker registry configuration. &lt;/p&gt;

&lt;p&gt;The example below demonstrates how to set up a simple deployment that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses an external Docker registry (GitHub Container Registry)&lt;/li&gt;
&lt;li&gt;Configures an ExternalSecret to manage sensitive data&lt;/li&gt;
&lt;li&gt;Creates a basic deployment with service and ingress
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;application&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;dockerregistry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ghcr_io&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;externalEmail&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr-email&lt;/span&gt;
        &lt;span class="na"&gt;externalUsername&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr-username&lt;/span&gt;
        &lt;span class="na"&gt;externalPassword&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr-password&lt;/span&gt;
        &lt;span class="na"&gt;externalUrl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr-url&lt;/span&gt;

  &lt;span class="na"&gt;externalSecrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;refreshInterval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1h&lt;/span&gt;
      &lt;span class="na"&gt;secretStoreRef&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;my-secret-store&lt;/span&gt;
        &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SecretStore&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;my-secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;remoteRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-secret&lt;/span&gt;

  &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;my-deployment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

      &lt;span class="na"&gt;pdb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

      &lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;

      &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterIP&lt;/span&gt;
        &lt;span class="na"&gt;servicePort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
        &lt;span class="na"&gt;ports&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;http&lt;/span&gt;
            &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
            &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
            &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;

      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;my-container&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="na"&gt;repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;camptocamp/my-image&lt;/span&gt;
            &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;latest&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;sleep&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3600'&lt;/span&gt;

          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;SECRET&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secret&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;self-external-secret-app&lt;/span&gt;
              &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-secret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/camptocamp/helm-application" rel="noopener noreferrer"&gt;Main Project Repository&lt;/a&gt; - Source code, issues, and releases&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/camptocamp/helm-application/wiki" rel="noopener noreferrer"&gt;Documentation Wiki&lt;/a&gt; - Detailed guides and configuration examples&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This chart is not perfect, but it can be used for major simple cases and some big applications.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
    </item>
    <item>
      <title>Prospector on Visual Studio Code</title>
      <dc:creator>Stéphane Brunner</dc:creator>
      <pubDate>Wed, 29 Jan 2025 16:15:06 +0000</pubDate>
      <link>https://dev.to/camptocamp-geo/prospector-on-visual-studio-code-3790</link>
      <guid>https://dev.to/camptocamp-geo/prospector-on-visual-studio-code-3790</guid>
      <description>&lt;h2&gt;
  
  
  Visual Studio Code plugin for Prospector
&lt;/h2&gt;

&lt;p&gt;As part of my efforts to improve Prospector's integration with popular IDEs, I created a Visual Studio Code &lt;a href="https://github.com/sbrunner/vscode-linter-prospector/" rel="noopener noreferrer"&gt;plugin&lt;/a&gt; based on the &lt;a href="https://marketplace.visualstudio.com/items?itemName=fnando.linter" rel="noopener noreferrer"&gt;Linter&lt;/a&gt; plugin. While this plugin is not actively maintained, it was a valuable tool for quickly building a new plugin that integrates Prospector with VS Code.&lt;/p&gt;

&lt;p&gt;The plugin provides a seamless experience for users to run Prospector directly from within VS Code and see linting results instantly in the editor.&lt;/p&gt;

&lt;p&gt;Result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fptyfa90o5t4l32u6243l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fptyfa90o5t4l32u6243l.png" alt="Screenshot" width="800" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=sbrunner.linter-prospector&amp;amp;ssr=false#overview" rel="noopener noreferrer"&gt;Available&lt;/a&gt; in the Visual Studio Code Marketplace.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Prospector
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://prospector.landscape.io/" rel="noopener noreferrer"&gt;Prospector&lt;/a&gt; is a powerful bundler of various linting tools for Python, designed to improve code quality by running multiple linters and static analysis tools in a single pass. It integrates a collection of popular tools, which can be easily configured and customized to fit your project’s needs. You can explore the full list of &lt;a href="https://prospector.landscape.io/en/master/supported_tools.html" rel="noopener noreferrer"&gt;Supported Tools&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Over the past few years at Camptocamp, we have contributed several improvements to Prospector, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;   &lt;strong&gt;Python 3.12 compatibility&lt;/strong&gt;: Ensuring Prospector works seamlessly with the latest version of Python.&lt;/li&gt;
&lt;li&gt;   &lt;strong&gt;Adding Ruff support&lt;/strong&gt;: Integrating Ruff, a fast linter for Python, to improve linting performance.&lt;/li&gt;
&lt;li&gt;   &lt;strong&gt;Improved Bandit and Mypy integration&lt;/strong&gt;: Enhancing the integration of Bandit (security-focused static analysis) and Mypy (static type checking).&lt;/li&gt;
&lt;li&gt;   &lt;strong&gt;Support for profiles in PyPI packages&lt;/strong&gt;: Allowing users to publish Prospector profiles as PyPI packages.&lt;/li&gt;
&lt;li&gt;   &lt;strong&gt;Bug fixes&lt;/strong&gt;: Addressing various issues to make the tool more reliable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Latest Prospector version
&lt;/h2&gt;

&lt;p&gt;In the most recent release of Prospector, I focused on improving the integration with IDEs, particularly by enhancing the JSON output generated by Prospector. These improvements allow for better interaction with code editors and IDEs like Visual Studio Code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;   &lt;strong&gt;Line and character end information&lt;/strong&gt;: This change allows the IDE to highlight the entire element (e.g., a function or variable) that has an issue, rather than just the first character. This provides a more intuitive user experience when reviewing linting errors.&lt;/li&gt;
&lt;li&gt;   &lt;strong&gt;Documentation URL&lt;/strong&gt;: A new addition that provides a direct link to the relevant documentation for each linting rule. This allows developers to quickly understand and resolve issues without having to search for the documentation manually.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Useful related packages I maintain
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://pypi.org/project/prospector-profile-utils/" rel="noopener noreferrer"&gt;Base Prospector profiles&lt;/a&gt;&lt;/strong&gt; A set of basic profiles to help configure Prospector for your project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://pypi.org/project/prospector-profile-duplicated/" rel="noopener noreferrer"&gt;Prospector profiles used to avoid duplicated messages&lt;/a&gt;&lt;/strong&gt; A collection of profiles designed to prevent duplicate linting messages, making the output more concise and easier to understand.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>vscode</category>
    </item>
  </channel>
</rss>
