<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Fotoallerlei</title>
	<atom:link href="https://fotoallerlei.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://fotoallerlei.com</link>
	<description>Tech, photography, notes and random stuff.</description>
	<lastBuildDate>Sun, 22 Oct 2023 15:53:39 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.5.3</generator>

<image>
	<url>https://fotoallerlei.com/wp-content/uploads/2023/10/logo-150x150.png</url>
	<title>Fotoallerlei</title>
	<link>https://fotoallerlei.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Suspend All Kubernetes Cronjobs</title>
		<link>https://fotoallerlei.com/blog/2022/suspend-all-kubernetes-cronjobs/</link>
		
		<dc:creator><![CDATA[Max]]></dc:creator>
		<pubDate>Thu, 23 Jun 2022 15:13:00 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[kubernetes]]></category>
		<guid isPermaLink="false">https://fotoallerlei.com/?p=16</guid>

					<description><![CDATA[Recently, I had the need to suspend all Kubernetes cronjobs in a cluster. Looking around for an existing one-liner I came across this helpful gist. It loops over all namespaces, gets all cronjobs in each and patches them to spec.suspend: true. And to enable them again, we can patch them to spec.suspend: false. Keep in [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Recently, I had the need to suspend all Kubernetes cronjobs in a cluster. Looking around for an existing one-liner I came across <a href="https://gist.github.com/mousavian/1541a6a38c2a8db0e9a95f5944946270" target="_blank" rel="noreferrer noopener">this helpful gist</a>. It loops over all namespaces, gets all cronjobs in each and patches them to <code>spec.suspend: true</code>.</p>



<pre class="wp-block-code"><code>for ns in $(kubectl get ns -o jsonpath="{.items&#91;*].metadata.name}"); do
  for cj in $(kubectl get cronjobs -n "$ns" -o name); do
    kubectl patch "$cj" -n "$ns" -p '{"spec" : {"suspend" : true }}';
  done
done</code></pre>



<p>And to enable them again, we can patch them to <code>spec.suspend: false</code>.</p>



<pre class="wp-block-code"><code>for ns in $(kubectl get ns -o jsonpath="{.items&#91;*].metadata.name}"); do
  for cj in $(kubectl get cronjobs -n "$ns" -o name); do
    kubectl patch "$cj" -n "$ns" -p '{"spec" : {"suspend" : false }}';
  done
done</code></pre>



<p>Keep in mind that resuming overdue cronjobs immediately schedules new jobs, so depending on your jobs this might cause some additional load.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Whoami or Who Is My DNS Resolver?</title>
		<link>https://fotoallerlei.com/blog/2021/whoami-or-who-is-my-dns-resolver/</link>
		
		<dc:creator><![CDATA[Max]]></dc:creator>
		<pubDate>Mon, 31 May 2021 22:59:00 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[DNS]]></category>
		<guid isPermaLink="false">https://fotoallerlei.com/?p=9</guid>

					<description><![CDATA[There are thousands of memes that DNS is the cause of (almost) all computer issues, so debugging DNS issues is necessary more often than anyone would like. One question that comes up often when debugging DNS is: Which server is my actual DNS resolver? An easy way I found to answer this question is the [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>There are thousands of memes that DNS is the cause of (almost) all computer issues, so debugging DNS issues is necessary more often than anyone would like. One question that comes up often when debugging DNS is: Which server is my actual DNS resolver? An easy way I found to answer this question is the whoami tool of Akamai. whoami.ds.akahelp.net will always respond with the IP address of the requesting server.</p>



<pre class="wp-block-code"><code>$ dig +short TXT whoami.ds.akahelp.net
"ns" "203.0.113.1"</code></pre>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Figuring out the Network Interface of an IP Address in Ansible</title>
		<link>https://fotoallerlei.com/blog/2021/figuring-out-the-network-interface-of-an-ip-address-in-ansible/</link>
		
		<dc:creator><![CDATA[Max]]></dc:creator>
		<pubDate>Fri, 02 Apr 2021 15:18:00 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[ansible]]></category>
		<guid isPermaLink="false">https://fotoallerlei.com/?p=20</guid>

					<description><![CDATA[Recently I had an odd problem with Ansible. I had a bunch of servers and knew that all of them had an IP address from a specific subnet but I couldn&#8217;t be sure which network interface this IP would be (automatically, outside of my control) assigned to. Well, Ansible discovers all network interfaces and IP [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Recently I had an odd problem with <a href="https://docs.ansible.com/">Ansible</a>. I had a bunch of servers and knew that all of them had an IP address from a specific subnet but I couldn&#8217;t be sure which network interface this IP would be (automatically, outside of my control) assigned to. Well, Ansible discovers all network interfaces and IP addresses of our hosts, so that should be easy, right? Let&#8217;s take a look at those Ansible facts:</p>



<pre class="wp-block-code"><code>$ ansible localhost -m setup
localhost | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": &#91;
            "10.24.94.195",
            "172.17.0.1"
        ],
        ...
        "ansible_interfaces": &#91;
            "enp0s31f6",
            "lo",
            "docker0"
        ],
        ...
        "ansible_docker0": {
            "device": "docker0",
            "ipv4": {
                "address": "172.17.0.1",
                "broadcast": "172.17.255.255",
                "netmask": "255.255.0.0",
                "network": "172.17.0.0"
            },
            ...
        },
        ...
        "ansible_enp0s31f6": {
            "device": "enp0s31f6",
            "ipv4": {
                "address": "10.24.94.195",
                "broadcast": "10.24.94.255",
                "netmask": "255.255.255.0",
                "network": "10.24.94.0"
            },
            ...
        },
        ...
        "ansible_lo": {
            "device": "lo",
            "ipv4": {
                "address": "127.0.0.1",
                "broadcast": "",
                "netmask": "255.0.0.0",
                "network": "127.0.0.0"
            },
            ...
        },
        ...
    }
}</code></pre>



<p>In theory we have all the facts right there and for the human eye it is quite easy to spot which IP belongs to which interface. But (as far as I know) there is no obvious way in Ansible to query the interface based on an IP. We could use the <a href="https://docs.ansible.com/ansible/latest/collections/ansible/builtin/shell_module.html" target="_blank" rel="noreferrer noopener">shell</a> module and call some <code>ip a | sed | foo</code> command to figure out the network interface but after searching the web for a while I finally figured out a way solve this directly in Ansible:</p>



<pre class="wp-block-code"><code># debug.yml
- name: Debug
  hosts: localhost
  tasks:
    - name: set_fact | figure out network device of private network
      set_fact:
        private_interface: "{{ hostvars&#91;inventory_hostname]&#91;'ansible_' + item]&#91;'device'] }}"
      when:
        - hostvars&#91;inventory_hostname]&#91;'ansible_' + item].ipv4 is defined
        - hostvars&#91;inventory_hostname]&#91;'ansible_' + item]&#91;'ipv4']&#91;'address'] | ipaddr('10.24.94.0/24')
      with_items: "{{ ansible_interfaces }}"
    - name: debug | print network interface
      debug:
        msg: Interface {{ private_interface | default("not") }} found</code></pre>



<p>Wait, what? Yep.</p>



<pre class="wp-block-code"><code>$ ansible-playbook debug.yml

PLAY &#91;Debug]

TASK &#91;Gathering Facts]
ok: &#91;localhost]

TASK &#91;set_fact | figure out network device of private network]
ok: &#91;localhost] => (item=enp0s31f6)
skipping: &#91;localhost] => (item=lo)
skipping: &#91;localhost] => (item=docker0)

TASK &#91;debug | print network interface]
ok: &#91;localhost] => {
    "msg": "Interface enp0s31f6 found"
}

PLAY RECAP
localhost                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0</code></pre>



<p>We use the <code>ansible_interfaces</code> fact to get a list of all interfaces, then we loop through all interfaces and use the fact that the interface specific Ansible facts are called <code>ansible_$interface</code>. For each interface we use the <code>when</code> conditions to check if the interface has an IP in the desired subnet. In that case the fact <code>private_interface</code> is set to the current interface, otherwise the task is skipped. This way we can now use the new fact in other tasks or templates. In the <code>when</code> conditions we could also use other filters, for example if we want to match a specific IP instead of a subnet, etc.</p>



<p>Is this a bit hacky? Hell yeah! Does it work? Yes. Will it break in some situations? Probably, for example with several interfaces in the subnet. But depending on the situation it can be a feasible solution.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>16. &#038; 17. #everyonecancontribute Cafe: Building a K3s Cluster on Hetzner Cloud &#8211; Part 3 and 4</title>
		<link>https://fotoallerlei.com/blog/2021/16-17-everyonecancontribute-cafe-building-a-k3s-cluster-on-hetzner-cloud-part-3-and-4/</link>
		
		<dc:creator><![CDATA[Max]]></dc:creator>
		<pubDate>Wed, 31 Mar 2021 15:30:00 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[everyonecancontribute]]></category>
		<category><![CDATA[hetzner]]></category>
		<category><![CDATA[kubernetes]]></category>
		<guid isPermaLink="false">https://fotoallerlei.com/?p=25</guid>

					<description><![CDATA[In January and February we started our ongoing journey to build a k3s Kubernetes cluster on Hetzner cloud in part 1 and part 2. We continued this in February with part 3 and 4 where we deployed the hcloud cloud controller manager, cert-manager and nginx ingress controller to get traffic into our cluster.]]></description>
										<content:encoded><![CDATA[
<p>In January and February we started our ongoing journey to build a k3s Kubernetes cluster on Hetzner cloud in <a href="https://fotoallerlei.com/blog/14-everyonecancontribute-cafe-building-a-k3s-cluster-on-hetzner-cloud-part-1-27/" data-type="post" data-id="27">part 1</a> and <a href="https://fotoallerlei.com/blog/15-everyonecancontribute-cafe-building-a-k3s-cluster-on-hetzner-cloud-part-2-29/" data-type="post" data-id="29">part 2</a>. We continued this in February with part 3 and 4 where we deployed the <a rel="noreferrer noopener" href="https://github.com/hetznercloud/hcloud-cloud-controller-manager" target="_blank">hcloud cloud controller manager</a>, <a rel="noreferrer noopener" href="https://cert-manager.io" target="_blank">cert-manager</a> and <a rel="noreferrer noopener" href="https://github.com/kubernetes/ingress-nginx/" target="_blank">nginx ingress controller</a> to get traffic into our cluster.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="16. #everyonecancontribute cafe: Kubernetes deployments to Hetzner Cloud, step 3" width="500" height="281" src="https://www.youtube.com/embed/fHyRrV0eUaU?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="17. #everyonecancontribute cafe: Kubernetes deployments to Hetzner cloud, step 4" width="500" height="281" src="https://www.youtube.com/embed/WkKnfdRa99U?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Joining the Hetzner Cloud Team</title>
		<link>https://fotoallerlei.com/blog/2021/joining-the-hetzner-cloud-team/</link>
		
		<dc:creator><![CDATA[Max]]></dc:creator>
		<pubDate>Wed, 31 Mar 2021 15:27:00 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[hetzner]]></category>
		<category><![CDATA[job]]></category>
		<guid isPermaLink="false">https://fotoallerlei.com/?p=23</guid>

					<description><![CDATA[A week ago I shared on Twitter that I quit my job at SysEleven after half a decade. Those years have been an incredible ride from &#8220;part time in support&#8221; to &#8220;senior kubernetes architect&#8221; while learning a ton of things, not only as an engineer but also as a human. If our paths crossed during [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>A week ago I <a href="https://twitter.com/ekeih/status/1374336650684346371" target="_blank" rel="noreferrer noopener">shared on Twitter</a> that I quit my job at SysEleven after half a decade. Those years have been an incredible ride from &#8220;part time in support&#8221; to &#8220;senior kubernetes architect&#8221; while learning a ton of things, not only as an engineer but also as a human. If our paths crossed during this time as coworkers or in some other capacity I want to thank you! I am also very happy that some of those work relationships evolved into friendships that will hopefully outlast any job changes.</p>



<p>In December 2011 I <del>bought</del> rented my first server from <a href="https://www.hetzner.com/" target="_blank" rel="noreferrer noopener">Hetzner Online</a>, since then there hasn&#8217;t been a month without an invoice from them&#8230; accumulating to a surprising amount of money. In November 2018 I booted the first four instances on the new <a href="https://www.hetzner.com/cloud" target="_blank" rel="noreferrer noopener">Hetzner Cloud</a> which was released earlier in the year&#8230; one of those instances is still running smoothly along. I can&#8217;t really put a number on it, but it is safe to say that a major part of my engineering knowledge is based on the stuff I have built and broken on this infrastructure over the years.</p>



<p>So, after almost a decade as a very happy customer I am beyond delighted to join the <a href="https://hetzner-cloud.de" target="_blank" rel="noreferrer noopener">Hetzner Cloud team</a> on the 1st of April. I can&#8217;t wait to see how this new chapter turns out.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Unknown Subcommand sh in Gitlab CI with Tanka</title>
		<link>https://fotoallerlei.com/blog/2021/unknown-subcommand-sh-in-gitlab-ci-with-tanka/</link>
		
		<dc:creator><![CDATA[Max]]></dc:creator>
		<pubDate>Sat, 06 Feb 2021 16:41:00 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[gitlab]]></category>
		<category><![CDATA[tanka]]></category>
		<guid isPermaLink="false">https://fotoallerlei.com/?p=31</guid>

					<description><![CDATA[I am using Tanka to template and deploy namespaces and network policies to Kubernetes. To do this in GitLab CI I am using the official Tanka image on Docker Hub, my .gitlab-ci.yml for it looked like this: Until recently it worked fine like this, but suddenly it stopped working and started to produce the following [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>I am using <a href="https://tanka.dev" target="_blank" rel="noreferrer noopener">Tanka</a> to template and deploy namespaces and network policies to Kubernetes. To do this in GitLab CI I am using the official <a href="https://hub.docker.com/r/grafana/tanka" target="_blank" rel="noreferrer noopener">Tanka image on Docker Hub</a>, my <code>.gitlab-ci.yml</code> for it looked like this:</p>



<pre class="wp-block-code"><code>.tanka:
  image: grafana/tanka:0.13.0
  before_script:
    - cd tanka
    - tk env set --server-from-context='centralserver-k3s' environments/default/

Tanka Diff:
  extends: .tanka
  stage: tanka-diff
  script:
    - tk diff environments/default || if &#91; $? -eq 16 ]; then echo 0; else echo $?; fi
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event" || ($CI_PIPELINE_SOURCE == "push" &amp;&amp; $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH)
      changes:
        - tanka/**/*
    - if: $CI_PIPELINE_SOURCE == "web"

Tanka Apply:
  extends: .tanka
  stage: tanka
  script:
    - tk apply --dangerous-auto-approve environments/default
  rules:
    - if: $CI_PIPELINE_SOURCE == "push" &amp;&amp; $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
      changes:
        - tanka/**/*
      when: manual
    - if: $CI_PIPELINE_SOURCE == "web"</code></pre>



<p>Until recently it worked fine like this, but suddenly it stopped working and started to produce the following error:</p>



<pre class="wp-block-code"><code>Executing "step_script" stage of the job script
Error: unknown subcommand `sh`
Usage:
  tk &#91;command]
Available Commands:
&#91;...]
Cleaning up file based variables
ERROR: Job failed: exit code 1</code></pre>



<p>So, this is rather weird&#8230; it sounds like GitLab CI tries to run something like <code>tk sh ...</code>, why would it do that? There is no <code>tk sh</code> command in my <code>.gitlab-ci.yml</code>, it doesn&#8217;t seem to make any sense. After searching a bit I found this helpful explanation: <a rel="noreferrer noopener" href="https://gitlab.com/gitlab-org/gitlab-foss/-/issues/65110#note_198073241" target="_blank">https://gitlab.com/gitlab-org/gitlab-foss/-/issues/65110#note_198073241</a>. Looking at the <a rel="noreferrer noopener" href="https://github.com/grafana/tanka/blob/v0.13.0/Dockerfile#L36" target="_blank">Dockerfile of Tanka</a> confirms that it calls <code>tk</code> in the entrypoint. As explained in the linked issue the combination of the entrypoint and the way the Docker executor starts the container leads to a start command like <code>tk sh -c [rest of shell detection...]</code>. With this knowledge it is even reproducible locally:</p>



<pre class="wp-block-code"><code>$ docker run --rm -it grafana/tanka:0.13.0 sh -c 'echo Hello World'
Error: unknown subcommand `sh`

Usage:
  tk &#91;command]

Available Commands:
&#91;...]</code></pre>



<p>Overriding the entrypoint with an empty string, as described in the issue, fixes the problem:</p>



<pre class="wp-block-code"><code>$ docker run --rm -it --entrypoint "" grafana/tanka:0.13.0 sh -c 'echo Hello World'
Hello World</code></pre>



<p>The same fix works in the <code>.gitlab-ci.yml</code> file:</p>



<pre class="wp-block-code"><code>.tanka:
  image:
    name: grafana/tanka:0.13.0
    entrypoint: &#91;""]
  before_script:
    - cd tanka
    - tk env set --server-from-context='centralserver-k3s' environments/default/</code></pre>



<p>This leaves me with one question: Why did it work before? I think when it worked the job was running with the Kubernetes executor and then it broke when I switched it to the Docker executor. So, my guess is that the Kubernetes executor already overrides the entrypoint by default.</p>



<p>Even though the initial error message was rather confusing the technical explanation makes a lot sense and the fix works fine. Also it is worth mentioning that this is not really a Tanka issue! This will happen with every Docker image with an <code>ENTRYPOINT</code> in the Dockerfile, the fix should also work for all of them.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>15. #everyonecancontribute Cafe: Building a K3s Cluster on Hetzner Cloud &#8211; Part 2</title>
		<link>https://fotoallerlei.com/blog/2021/15-everyonecancontribute-cafe-building-a-k3s-cluster-on-hetzner-cloud-part-2/</link>
		
		<dc:creator><![CDATA[Max]]></dc:creator>
		<pubDate>Wed, 03 Feb 2021 16:38:00 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[everyonecancontribute]]></category>
		<category><![CDATA[hetzner]]></category>
		<category><![CDATA[kubernetes]]></category>
		<guid isPermaLink="false">https://fotoallerlei.com/?p=29</guid>

					<description><![CDATA[Today we continued where we left off last week. With our existing Terraform code we created a new cluster and then we built a few Ansible roles to deploy our k3s cluster. After an hour we reached the goal of the evening: kubectl get nodes showed us our three running nodes in Ready state. Next [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Today we continued where we left off <a href="https://fotoallerlei.com/blog/14-everyonecancontribute-cafe-building-a-k3s-cluster-on-hetzner-cloud-part-1-27/" data-type="post" data-id="27">last week</a>. With our existing Terraform code we created a new cluster and then we built a few Ansible roles to deploy our k3s cluster. After an hour we reached the goal of the evening: <code>kubectl get nodes</code> showed us our three running nodes in <code>Ready</code> state. Next week we will deploy the cloud controller manager and the CSI driver to make the networking and persistent storage work. If you want to try it yourself you can find the current state of our experiments at <a href="https://gitlab.com/ekeih/k3s-demo" target="_blank" rel="noreferrer noopener">GitLab</a>.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="15. #everyonecancontribute cafe: Kubernetes deployments to Hetzner Cloud, step 2" width="500" height="281" src="https://www.youtube.com/embed/oGI06xr2PYk?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>14. #everyonecancontribute Cafe: Building a K3s Cluster on Hetzner Cloud &#8211; Part 1</title>
		<link>https://fotoallerlei.com/blog/2021/14-everyonecancontribute-cafe-building-a-k3s-cluster-on-hetzner-cloud-part-1/</link>
		
		<dc:creator><![CDATA[Max]]></dc:creator>
		<pubDate>Tue, 02 Feb 2021 16:33:00 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[everyonecancontribute]]></category>
		<category><![CDATA[hetzner]]></category>
		<category><![CDATA[kubernetes]]></category>
		<guid isPermaLink="false">https://fotoallerlei.com/?p=27</guid>

					<description><![CDATA[Last week during our weekly #everyonecancontribute call we started to build a k3s cluster on Hetzner Cloud. Based on my existing personal k3s cluster I gave an introduction to Terraform, Ansible and the related hcloud libraries, like the hcloud Terraform provider and the hcloud Ansible collection. In the next part we will actually start to [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Last week during our <a href="https://everyonecancontribute.com/page/about/" target="_blank" rel="noreferrer noopener">weekly #everyonecancontribute call</a> we started to build a <a href="https://k3s.io/" target="_blank" rel="noreferrer noopener">k3s</a> cluster on Hetzner Cloud. Based on my existing personal k3s cluster I gave an introduction to Terraform, Ansible and the related hcloud libraries, like the <a href="https://registry.terraform.io/providers/hetznercloud/hcloud/latest/docs" target="_blank" rel="noreferrer noopener">hcloud Terraform provider</a> and the <a href="https://docs.ansible.com/ansible/latest/collections/hetzner/hcloud/hcloud_inventory.html" target="_blank" rel="noreferrer noopener">hcloud Ansible collection</a>. In the next part we will actually start to use Ansible to deploy k3s on our virtual machines and deploy our first containers in the cluster. If you want to try it yourself you can find the current state of our experiments at <a href="https://gitlab.com/ekeih/k3s-demo" target="_blank" rel="noreferrer noopener">GitLab</a>.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="14. #everyonecancontribute cafe: Kubernetes deployments to Hetzner Cloud with Max Rosin" width="500" height="281" src="https://www.youtube.com/embed/LvFvQmqce5o?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Organize Python Imports on save in VS Code</title>
		<link>https://fotoallerlei.com/blog/2021/organize-python-imports-on-save-in-vs-code/</link>
		
		<dc:creator><![CDATA[Max]]></dc:creator>
		<pubDate>Sun, 24 Jan 2021 16:49:00 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[vscode]]></category>
		<guid isPermaLink="false">https://fotoallerlei.com/?p=34</guid>

					<description><![CDATA[The &#8220;PEP 8 &#8211; Style Guide for Python Code&#8221; defines the following order for Python imports: Taking care of that manually is just tedious work! This is something the editor or IDE should take care of instead. VS Code has a feature called Organize Imports to do exactly that, but unfortunately by default we have [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>The &#8220;<a rel="noreferrer noopener" href="https://www.python.org/dev/peps/pep-0008/#imports" target="_blank">PEP 8 &#8211; Style Guide for Python Code</a>&#8221; defines the following order for Python imports:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Imports should be grouped in the following order:</p>



<ul>
<li>Standard library imports.</li>



<li>Related third party imports.</li>



<li>Local application/library specific imports.</li>
</ul>



<p>You should put a blank line between each group of imports.</p>
</blockquote>



<p>Taking care of that manually is just tedious work! This is something the editor or IDE should take care of instead. VS Code has a feature called <code>Organize Imports</code> to do exactly that, but unfortunately by default we have to run it manually. Instead, it would be much nicer if it was triggered each time we save a file. We can achieve that by adding the following to VS Codes <code>settings.json</code>:</p>



<pre class="wp-block-code"><code>{
  ...
  "editor.codeActionsOnSave": {
    "source.organizeImports": true
  }
  ...
}</code></pre>



<p>And just like that we get sorted and grouped imports each time we save a file.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>13. #everyonecancontribute Cafe: Autoscaling Gitlab Runners on Hetzner Cloud</title>
		<link>https://fotoallerlei.com/blog/2021/13-everyonecancontribute-cafe-autoscaling-gitlab-runners-on-hetzner-cloud/</link>
		
		<dc:creator><![CDATA[Max]]></dc:creator>
		<pubDate>Thu, 21 Jan 2021 16:52:00 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[everyonecancontribute]]></category>
		<category><![CDATA[gitlab]]></category>
		<category><![CDATA[hetzner]]></category>
		<guid isPermaLink="false">https://fotoallerlei.com/?p=36</guid>

					<description><![CDATA[A while ago Michael invited me to join the weekly #everyonecancontribute coffee chats. It took me a while until I actually managed to join, but yesterday I attended the call for the second time and was promptly surprised when the agenda turned out to be a hands-on demo of an earlier blogpost of mine: Autoscaling [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>A while ago <a href="https://twitter.com/dnsmichi" target="_blank" rel="noreferrer noopener">Michael</a> invited me to join the <a href="https://everyonecancontribute.com/page/about/" target="_blank" rel="noreferrer noopener">weekly #everyonecancontribute coffee chats</a>. It took me a while until I actually managed to join, but yesterday I attended the call for the second time and was promptly surprised when the agenda turned out to be a hands-on demo of an earlier blogpost of mine: <a href="https://blog-awe.pages.dev/blog/post/2021/2020/autoscaling-gitlab-runners-on-hetzner-cloud/post">Autoscaling GitLab Runners on Hetzner Cloud</a>. Thanks to <a href="https://twitter.com/solidnerd" target="_blank" rel="noreferrer noopener">Niclas</a> for the demo, it was quite nice seeing someone else implementing something based on the words I wrote. <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="13. #everyonecancontribute cafe: Auto-scaling GitLab runners in Hetzner Cloud" width="500" height="281" src="https://www.youtube.com/embed/isKaBJ4VT24?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
