<?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 Vibhav Bobade on Medium]]></title>
        <description><![CDATA[Stories by Vibhav Bobade on Medium]]></description>
        <link>https://medium.com/@waveywaves?source=rss-107cf468a271------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/2*4xCkGN9qrk1MpLesOTOxqw.jpeg</url>
            <title>Stories by Vibhav Bobade on Medium</title>
            <link>https://medium.com/@waveywaves?source=rss-107cf468a271------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 06:17:06 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@waveywaves/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[Scheduling simulations and ghosts in the cluster ]]></title>
            <link>https://waveywaves.medium.com/scheduling-simulations-and-ghosts-in-the-cluster-700fead1b5a1?source=rss-107cf468a271------2</link>
            <guid isPermaLink="false">https://medium.com/p/700fead1b5a1</guid>
            <dc:creator><![CDATA[Vibhav Bobade]]></dc:creator>
            <pubDate>Fri, 01 Nov 2024 16:31:55 GMT</pubDate>
            <atom:updated>2024-11-01T16:31:55.256Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*NVsQ4oQv0gl9Rstc.png" /></figure><p><em>A series of diary entries where I hack away at the Virtual Kubelets, what they stand for and what they don’t stand for and whether they can stand in the first place considering they are ghosts (you’ll figure out what I mean by that soon).</em></p><h3>Scheduling Simulations</h3><p>17th October 2024</p><p>I had a very interesting discussion with <a href="https://substack.com/@anjulsahu">Anjul Sahu</a> yesterday about the state of Cloud Computing and Kubernetes generally and he was gracious enough to catch me up on what the current state of GPU computing in India looks like.</p><p>Thanks for reading Vibhav’s Tech Diary! Subscribe for free to receive new posts and support my work.</p><p>After being a little out of touch with the Kubernetes ecosystem, it was nice to get this little crash course back into the system because of it. Today, after that discussion I have decided to learn more about Virtual Kubelets and try them out. I also plan on continue on hacking on something else later today, so I am going to keep it short.</p><p>The latest KubeCon video I could find on Virtual Kubelets is the one below.</p><h3>Notes on SimKube</h3><h4>Why Simulation ?</h4><p>Simulating `workload scheduling` locally gives us a peek into how the workloads might perform on actual clusters or help us debug through replaying simulations without having to run the workloads on real clusters.</p><p>We also talk about simulating the control plane components of the cluster here (not the applications).</p><h4>SimKube Architecture</h4><p><a href="https://github.com/acrlabs/simkube">SimKube</a> is the project that is being demoed in this talk and below is the high level architecture diagram for SimKube. The components marked in yellow are the 6 components discussed in this talk. SimKube is also written in Rust which is kind of amazing. Would definitely be nice to see more controllers being written in Rust ;)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/605/0*FDWEnQG_qMrSmncx.png" /></figure><p>User Interface to SimKube</p><ul><li><strong>skctl (CLI)</strong> — Helps talk to your production cluster for exporting data to persistent storage, and also helps replay that same data on the simulated cluster.</li></ul><p>SimKube Components in the <strong><em>Production Cluster</em></strong> (eg: Azure, AWS EKS, GKE etc.)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/794/0*I2wpvMmWGOZ_SJPd.png" /></figure><ul><li><strong>sk-tracer (tracing service)</strong> — Runs in the production cluster. Collects data which is later stored in persistent storage.</li><li>When we want to use the data being collected by the tracer we can call `skctl export`, which stores the data in some persistent storage from where we it can be used. This data would be used for creating simulations using `skctl run`. `skctl run` creates a <a href="https://github.com/acrlabs/simkube/blob/master/k8s/raw/simkube.io_simulations.yml"><em>Simulation</em></a> <a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/">CustomResource</a>.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/605/0*3Y0eSR4DXKBLA6ku.png" /></figure><p>SimKube Components in <em>Simulated Cluster</em> (eg: kind, minikube etc.)SimKube Simulation Control Plane</p><ul><li><strong>sk-ctrl (kubernetes controller)</strong> — listens for the <a href="https://github.com/acrlabs/simkube/blob/master/k8s/raw/simkube.io_simulations.yml"><em>Simulation</em></a> <a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/">CustomResource</a>.</li><li>To use the collected data from the production cluster in the simulated cluster, we will have to run `skctl run` which will <a href="https://github.com/acrlabs/simkube/blob/master/k8s/raw/simkube.io_simulations.yml"><em>Simulation</em></a> <a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/">CustomResource</a>.</li><li><strong>sk-driver (part of </strong><a href="https://github.com/acrlabs/simkube/blob/master/k8s/raw/simkube.io_simulations.yml"><em>Simulation</em></a><strong>) </strong>— created by <strong>sk-ctrl</strong> when a <a href="https://github.com/acrlabs/simkube/blob/master/k8s/raw/simkube.io_simulations.yml"><em>Simulation</em></a> <a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/">CustomResource</a> is created on the cluster.</li><li>installs a <a href="https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/">Mutating Admission Webhook</a> and intercepts all the pods and moves them to the target <strong>sk-vnode</strong>.</li></ul><p>SimKube Core Components (the heart of SimKube)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/794/0*POUALvH7FvdkLqZT.png" /></figure><ul><li><strong>sk-vnode (Virtual Kubelet based Virtual/Fake Node) — </strong>acts as a Kubernetes node and listens for workloads being created but doesn’t actually create it. <strong>sk-vnode</strong> is that it, only supposed to simulate/mock behavior of resources in the nodes.</li><li><strong>sk-cloudprov (Cloud Provider for Cluster Autoscaler) — </strong>the <a href="https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler/cloudprovider">Cluster Autoscaler interfaces will all different cloud providers</a> and sk-cloudprov is a cloud provider here in SimKube. sk-cloudprov scaled the nodes up and down if necessary for it’s simulations. <a href="https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/#pod-deletion-cost">Pod Deletion Cost</a> is used to select nodes to terminate.</li></ul><p>I was lucky enough to find <a href="https://open.substack.com/users/155618049-drmorr?utm_source=mentions">drmorr</a> aka David Morrison and his company’s blog here on Substack. if you like this tool and are intrigued by it and would like to hear more about the work Applied Computing Research Labs is doing, go ahead and subscribe to their blog below if you haven’t already.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/518/0*R3c61SeCuWkheqF5.png" /></figure><p><a href="https://blog.appliedcomputing.io/?utm_source=substack&amp;utm_campaign=publication_embed&amp;utm_medium=web">Applied Computing Research Labs</a></p><p><a href="https://blog.appliedcomputing.io/?utm_source=substack&amp;utm_campaign=publication_embed&amp;utm_medium=web">Open-source research and development in distributed systems</a></p><p><a href="https://blog.appliedcomputing.io/?utm_source=substack&amp;utm_campaign=publication_embed&amp;utm_medium=web">By drmorr</a></p><p>At the end of the talk, David also spoke about possible future plans for the project, one of them stood out to me which was “intergrating with <a href="https://github.com/kubernetes-sigs/kwok">KWOK</a>”. KWOK is Kubernetes WithOut Kubelet, and the point of the project is to be able to simulate nodes and clusters which falls inline with what SimKube is trying to do.</p><p>21st October 2024 (morning)</p><h3>Ghosts of the Node <a href="https://emojipedia.org/ghost">👻</a></h3><p>It’s spooky how Virtual Kubelets work. If a kubelet is the soul of a node then a virtual kubelet is a kubelet without a node (or a real node). Let’s first look at a normal kubelet in an actual node to understand what they are.</p><h4>Let’s check out a (real) Kubelet (for now)</h4><p>Kubelet is a cute name. It sounds like it’s a “mini-me” version of a Kube(ernetes). But that’s definitely not the case. It’s a crucial part(s) of a Kubernetes cluster that manages the lifecycle of workloads on Nodes.</p><p>Let’s take a look at what the kubelet looks like. I am running Docker Desktop on my Mac and just going to create a kind cluster with the following command and peek into the container created for that cluster to see if I can find the kubelet service running.</p><pre>kind create cluster</pre><p>Let’s list the container running for the kind cluster.</p><pre>docker container list</pre><pre>CONTAINER ID   IMAGE                  COMMAND                  CREATED         STATUS         PORTS                       NAMES<br>a035b26721b6   kindest/node:v1.29.2   &quot;/usr/local/bin/entr…&quot;   5 minutes ago   Up 5 minutes   127.0.0.1:51437-&gt;6443/tcp   kind-control-plane</pre><p>Let’s get into the container with the following command</p><pre>docker exec -it a035b26721b6 bash</pre><pre>root@kind-control-plane:/#</pre><p>And let’s see if we can find the kubelet service running here.</p><pre>systemctl status kubelet</pre><pre>● kubelet.service - kubelet: The Kubernetes Node Agent<br>     Loaded: loaded (/etc/systemd/system/kubelet.service; enabled; preset: enabled)<br>    Drop-In: /etc/systemd/system/kubelet.service.d<br>             └─10-kubeadm.conf, 11-kind.conf<br>     Active: active (running) since Mon 2024-10-21 00:32:04 UTC; 14min ago<br>       Docs: <a href="http://kubernetes.io/docs/">http://kubernetes.io/docs/</a><br>    Process: 701 ExecStartPre=/bin/sh -euc if [ -f /sys/fs/cgroup/cgroup.controllers ]; then /kind/bin/create-kubelet-cgroup-v2.sh; fi (code=exited, status=0/SUCCESS)<br>    Process: 709 ExecStartPre=/bin/sh -euc if [ ! -f /sys/fs/cgroup/cgroup.controllers ] &amp;&amp; [ ! -d /sys/fs/cgroup/systemd/kubelet ]; then mkdir -p /sys/fs/cgroup/systemd/kubelet; fi (code=exited, status=0/SUCCESS)<br>   Main PID: 710 (kubelet)<br>      Tasks: 20 (limit: 9310)<br>     Memory: 36.8M<br>        CPU: 21.179s<br>     CGroup: /kubelet.slice/kubelet.service<br>             └─710 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime-endpoint=unix:///run/containerd/containerd.sock --node-ip=172.18.0.2 --node-labels= --pod-infra-container-image=registry.k8s.io/pause:3.9 --provider-id=kind://docker/kind/kind-control-plane --runtime-cgroups=/system.slice/containerd.service</pre><p>and yes we do. Under the above output there are logs of the kubelet which I haven’t pasted here. But the logs pertain to any of the pods and volumes which are being managed by the kubelet here. Let’s look more into the kubelet logs.</p><pre>journalctl -u kubelet | more</pre><p>Just going through the logs here, noting down anything that stands out.</p><ul><li>Container Manager is created based on Node Config.</li><li>There is a topology manager here.</li><li>Node is synced with API Server.</li><li>Relevant Kubernetes objects are queried from the API server.</li><li>kubelet initialized iptables rules (I am saying this based on the log below, there seems to be contention online whether if the kubelet even has anything to do with the iptables, and some sources say it doesn’t but the logs might say one thing but <a href="https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/kubelet_network_linux.go#L50">the code</a> says another.</li></ul><pre>kubelet_network_linux.go:50] &quot;Initialized iptables rules.&quot; protocol=&quot;IPv4&quot;</pre><ul><li>After the resource management is setup, we move onto access control related setup with certificate setup and stuff where the node is being registered.</li><li>from here on out the Topology Admit Handler shows up quite a bit along with other things which seem to be part of the reconciliation loop.</li></ul><p>As we take a break here having understood that there is a lot which goes into resource allocation and workload creation by the kubelet including communication and syncing with the API Server.</p><h4>Virtual Kubelets: The ghastly equivalent of a Kubelet</h4><p>(Here, ghastly is being used to refer to virtual kubelets as being ghost like)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/220/0*nkCm3eToSrN0pSsf.gif" /></figure><p>Now that we have some idea of what a kubelet is, let’s focus on what happens when a kubelet doesn’t have a node to live in exactly. It won’t have the resources to handle but it will still contain the interfaces without any endpoints. These interfaces can abstract node capabilities through Container Runtime Interface (CRI), Container Storage Interface (CSI) and Container Network Interface (CNI) without being tied to actual hardware.</p><blockquote><a href="https://github.com/virtual-kubelet/virtual-kubelet?tab=readme-ov-file#usage"><em>Virtual Kubelet</em></a><em> is focused on providing a library that you can consume in your project to build a custom Kubernetes node agent.</em></blockquote><h4>Using Virtual Kubelets to use VMs as a Provider</h4><p>Now, I want to be able to use virtual Kubelets to connect a virtual machine to a kind cluster without having to deal with Kubernetes federation. This can be great for use cases where I don’t need to</p><p>21st October 2024 (afternoon)</p><p>For the use case I have for the virtual kubelet, seems like <a href="https://github.com/intertwin-eu/interlink">Interlink</a> is the perfect tool for it and the <a href="https://intertwin-eu.github.io/interLink/docs/intro#target-providers">Target Providers</a> does include “Remote/on-demand virtual machines with any container runtime”. So let’s try this out.</p><h3>(this discussion is continued in the next batch of diary entries/post …)</h3><p>Thanks for reading Vibhav’s Tech Diary! Subscribe for free to receive new posts and support my work.</p><p><em>Originally published at </em><a href="https://vibhavstechdiary.substack.com/p/scheduling-simulations-and-ghosts"><em>https://vibhavstechdiary.substack.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=700fead1b5a1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[In search of a Nextcloud Operator ➡️⛅]]></title>
            <link>https://waveywaves.medium.com/in-search-of-a-nextcloud-operator-%EF%B8%8F-bdf14bb85f89?source=rss-107cf468a271------2</link>
            <guid isPermaLink="false">https://medium.com/p/bdf14bb85f89</guid>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[nextcloud]]></category>
            <dc:creator><![CDATA[Vibhav Bobade]]></dc:creator>
            <pubDate>Wed, 30 Oct 2024 04:31:53 GMT</pubDate>
            <atom:updated>2024-10-30T04:31:53.362Z</atom:updated>
            <content:encoded><![CDATA[<h4>only to find a AGPL 3.0 dilemma, an empty repository and hacking together a new operator.</h4><p>TLDR; I started hacking on <a href="https://github.com/waveywaves/nextcloud-operator">a Nextcloud Operator</a>.</p><p><em>14th October 2024 (daytime)</em></p><p>So, I started hacking with the GlassKube Operator as I wanted an easy way to create and manage Nextcloud instances on Kubernetes and while searching for this an operator I found GlassKube. There isn’t a lot of documentation on how to run it with Mac. It’s either that or I didn’t search hard enough. Anyways, here’s how you can get start developing with it.</p><h3>Prerequisites for GlassKube Operator</h3><pre>brew install openjdk gradle</pre><p>After installing the developer dependencies and making sure you have things like kubectl etc. installed, which you will usually require to work with Kubernetes based tools, let’s go ahead and run the operator in development mode.</p><p>This operator is written in Java/Kotlin which gives me the heebie jeebies from back in the Jenkins days when I worked on the openshift-sync-plugin and the openshift-client-plugin for Jenkins, because this operator uses the <a href="https://github.com/fabric8io/kubernetes-client">fabric8io kubernetes client</a>. It was fun working with it then but now it’s nice to see it again, being used in this format.</p><p>The preferred distro for development with glasskube is minikube so let’s start the minikube cluster</p><pre>minikube start</pre><p>Let’s clone the repo and understand how the build for GlassKube works and how we can get started working on this operator ASAP.</p><pre>git clone https://github.com/glasskube/operator<br>cd operator</pre><pre># Build<br>gradle<br>gradle check<br>gradle operator:installCrd</pre><p>After this you can start the operator directly with the following command…</p><pre>gradle operator:bootRun</pre><p>but you will get cascading failures related the operator’s dependencies.</p><p>Let’s take a hacky approach and install the operator helm chart, scale the deployment of the operator to 0 and then run the above command again so that we can ensure the availability of runtime dependencies without having to iterating through these dependencies and installing all of them one by one which would take much more time.</p><pre># install via helm<br>helm repo add glasskube https://charts.glasskube.eu/<br>helm repo update</pre><pre>kubectl delete crds --all # run this because we installed all the crds in the last command and helm won&#39;t work if it cannot install the crds again</pre><pre># install glasskube operator<br>helm install go glasskube/glasskube-operator</pre><p>This above installs the glasskube-operator successfully. Let’s build an image and then push it to minikube using the following command.</p><pre>gradle operator:loadImage</pre><p>The above command will ensure that minikube has access to a newly built image from the source code. After running this command, I get the “docker.io/glasskube/operator:0.13.14-SNAPSHOT” image in the list of images accessible to my minikube.</p><pre>minikube image ls</pre><p>With the above command you can list these images for yourself.</p><h3>Deploying Nextcloud using the Glasskube Operator</h3><p>Let’s use the YAML below to create a Nextcloud instance.</p><pre>apiVersion: glasskube.eu/v1alpha1<br>kind: Nextcloud<br>metadata:<br>  name: nextcloud<br>spec:<br>  host: nextcloud.mycompany.eu<br>  defaultPhoneRegion: DE<br>  apps:<br>    office:<br>      host: office.nextcloud.mycompany.eu</pre><p>Create a yaml file with the above contents and call it nextcloud.yaml.</p><pre>kubectl create -f nextcloud.yaml</pre><p>I ran this and Nextcloud didn’t work as expected. Had a lot of errors in the operator logs. Gonna get onto debugging this tomorrow now.</p><p>Thanks for reading Vibhav’s Tech Diary! Subscribe for free to receive new posts and support my work.</p><p><em>15th October 2024 (extremely early morning, carry over from the last day)</em></p><p>The maintainer and author let me know that this operator is in maintenance mode as you can see below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/0*XKtSJ26-ltdga5Un.png" /></figure><h3>The AGPL 3.0 Dilemma</h3><p>I decided to install GlassKube and see if there is a package which they provide in the current version of the package manager, but seems like they don’t support Nextcloud yet. It might be because of Nextcloud’s AGPL 3.0 license which doesn’t allow people to use Nextcloud as part of a service offering over the network. <a href="https://github.com/glasskube/glasskube">The newer Glasskube repo</a> on the other hand has moved to Apache 2.0 license and don’t think they would want to support Nextcloud because of that. The <a href="https://github.com/glasskube/operator">Glasskube operator</a> on the other hand is LGPL 3.0 License. AGPL has a stronger copyleft so the LGPL operator will be subject to it probably.</p><blockquote><strong><em>Stronger copyleft</em></strong><em> refers to a type of licensing that imposes strict requirements on derivative works based on the original licensed software.</em></blockquote><p>Here, the strict requirements are given by AGPL.</p><p>I will do more justice to GlassKube in a future post, for now, I need a Nextcloud Operator.</p><h3>nextcloud/operator</h3><p>All of us have this one project idea (in my case, many) where you create a placeholder repository on Github to ensure that one day you might just finish that project you always wanted to start. <a href="https://github.com/nextcloud/operator">This repository</a> seems like a project like that, created 4 years, ago and waiting to get started.</p><h3>nextcloud/helm</h3><p><a href="https://github.com/nextcloud/helm">The Nextcloud Helm Chart</a> seems to be in active maintenance.</p><h3>A new Nextcloud Operator</h3><p>If something already has a Helm chart which works extremely well, I would rather create an operator that wraps around that Helm chart and then at that point the Helm chart can be managed by the <a href="https://github.com/fluxcd/helm-controller">FluxCD Helm Controller</a>. I have used this method before to create an operator where the target application that needed to be managed had a very comprehensive helm chart and it made sense to write an operator to manage the creation of these Helm charts. The operator here will be an abstraction layer over the creation and management of these charts. Any of the dependencies regarding storage, networking, CI/CD, backups etc. which nextcloud might have, will be managed by the operator itself.</p><h3>Hacking together an operator</h3><p><em>15th October 2024 (daytime)</em></p><p>Let’s start hacking on this. Committing everything to the repository below.</p><pre>https://github.com/waveywaves/nextcloud-operator.git</pre><p>Initialize the operator with <a href="https://sdk.operatorframework.io/">Operator SDK</a> after installation.</p><pre>brew install operator-sdk</pre><pre>operator-sdk init --domain waveywaves.com --repo github.com/waveywaves/nextcloud-operator .</pre><p>This will populate the project with the operator-sdk boilerplate.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*K-4Z0m2eM96vVXLa.png" /></figure><p>Now, let’s add a NextCloud CustomResourceDefinition.</p><pre>operator-sdk create api --group nc --version v1beta1 --kind Nextcloud</pre><p>After running the above you should have a scaffold operator and a basic CRD created. Say yes to all options when</p><pre>make install &amp;&amp; make run</pre><p>The above will run the operator and start listening for resources of kind Nextcloud.</p><pre>kubectl create -f config/samples/nc_v1beta1_nextcloud.yaml<br>kubectl get nextcloud</pre><pre>NAME               AGE<br>nextcloud-sample   7s</pre><h3>Creating a Nextcloud instance through the FluxCD Helm Controller</h3><p>We need the FluxCD source and helm controllers so that we can have it manage the Helm chart for us. We can later on figure out a way to make sure these are installed along side the operator in a helm chart.</p><pre>flux install --namespace=flux-system --components=&quot;source-controller,helm-controller&quot;</pre><p>The above will install the necessary CRDs and controllers to which our NextCloud operator will delegate to. To be able to manage these CRDs through our operator let’s add these schemes to to the operator schemes. First add the dependencies below in the cmd/main.go.</p><pre>fluxhelmv2beta1 &quot;github.com/fluxcd/helm-controller/api/v2beta1&quot;<br>fluxsourcev1beta2 &quot;github.com/fluxcd/source-controller/api/v1beta2&quot;</pre><p>And add the code below in the init() function.</p><pre>utilruntime.Must(fluxhelmv2beta1.AddToScheme(scheme))<br>utilruntime.Must(fluxsourcev1beta2.AddToScheme(scheme))</pre><p>Once the above code is added, we can be sure of this operator being able to work well with FluxCD Custom Resource which we need. I am taking a break here as moving forward, we only have a basic integration job to ensure that the Helm Chart for Nextcloud is deployed for the operator once the user creates an instance of the Nextcloud Custom Resouce.</p><p>Thanks for reading Vibhav’s Tech Diary! This post is public so feel free to share it. <a href="https://vibhavstechdiary.substack.com/p/in-search-of-a-nextcloud-operator?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&amp;token=eyJ1c2VyX2lkIjoxMTkwNjEyMywicG9zdF9pZCI6MTUwMjA3NTA2LCJpYXQiOjE3Mjk5NDQ5MDksImV4cCI6MTczMjUzNjkwOSwiaXNzIjoicHViLTI2OTE0ODQiLCJzdWIiOiJwb3N0LXJlYWN0aW9uIn0.3UAUA7qxJ35boDZSCbeB5bZvv2sEScqCWlgQGWNbF0Y">Share</a></p><h3>Nextcloud CRD → Nextcloud Helm chart creation</h3><p><em>16th October 2024 (daytime)</em></p><p>It has been a nice morning and I need to prep for an interview so we are gonna try and get through this as quickly as possible.</p><p>Let’s listen to some <a href="https://open.spotify.com/album/2WBrAkDpKDtCn7Ueyeg6m8?si=KQK1stGHRj-RbNLeuxDeHg">Cory Wong</a> while we get through this.</p><p>Whenever a Nextcloud Custom Resource is created we would like to create an adjacent HelmRelease which would create a (surprise surprise) a Helm release for Nextcloud. I have gone through a lot of programming blogs in the heyday of blogging so I know for a fact how hard it can be to read through some of these, so I am going to put the whole code below and in the comments you can read what I have done, and why I have done what I have had to do.</p><p>Let’s install a <a href="https://artifacthub.io/packages/helm/nextcloud/nextcloud">helm chart for Nextcloud</a> locally just to be sure.</p><pre>helm repo add nextcloud https://nextcloud.github.io/helm/<br>helm install nc nextcloud/nextcloud</pre><p>I get an output from the above command and reduce it to the commands below to make this testing easier.</p><pre>export APP_HOST=127.0.0.1<br>export APP_PASSWORD=$(kubectl get secret --namespace default nc-nextcloud -o jsonpath=&quot;{.data.nextcloud-password}&quot; | base64 --decode)</pre><pre>helm upgrade nc nextcloud/nextcloud --set nextcloud.password=$APP_PASSWORD,nextcloud.host=$APP_HOST,service.type=ClusterIP,mariadb.enabled=false</pre><p>Run the command below and go to <a href="https://127.0.0.1:8080/">https://127.0.0.1:8080</a> to login into your Nextcloud instance.</p><pre>kubectl port-forward service/nc-nextcloud 8080:8080</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*qu5RsUlk2CSnptDN.png" /></figure><pre>username: admin<br>password: changeme</pre><p>Use the username and password above to login.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*LFoI24Z4wUpSa1FN.png" /></figure><p>We get the above page after logging in, this is where we are going to stop. We are going to use the same helm values we used in the last step to intialize Nextcloud.</p><pre>helm list </pre><pre>NAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION<br>nc      default         2               2024-10-16 12:41:42.116235 +0530 IST    deployed        nextcloud-6.1.0 30.0.0</pre><p>We need to deploy the v6.1.0 chart through the operator.</p><p>Now, let’s make the following changes to the code. First, add a Status field. This will be in a nextcloud_types.go</p><pre>// NextcloudStatus defines the observed state of Nextcloud<br>type NextcloudStatus struct {<br>	HelmReleaseName string `json:&quot;helmReleaseName&quot;`<br>}</pre><p>Next, update the controller reconcile loop as I have done in <a href="https://github.com/waveywaves/nextcloud-operator/commit/b68f04e3c2153672e857bdfd1b0d54b9584e9b0d">this commit</a>. I will be refactoring everything in a commit later. Not a big fan of editing while writing.</p><p>In one terminal instance run …</p><pre>make run</pre><p>In another one run …</p><pre>kubectl create -f config/samples/nc_v1beta1_nextcloud.yaml</pre><p>Find the Nextcloud Operator code <a href="https://github.com/waveywaves/nextcloud-operator">here</a>.</p><p>We are also going to set the LICENSE to AGPL 3.0 because Nextcloud is AGPL 3.0 and that extends to us as well.</p><h3>Next Steps</h3><h4>Lifecycle</h4><p>We need to make sure that the correct Conditions are set on creation of the Nextcloud instance.</p><h4>Networking</h4><p>I need to first make sure that the Nextcloud instance is easily accessible over a Network. Right now we are using ClusterIP, but ideally we should be able to assign a host to the Nextcloud instance and access it like a normal human being instead of port forwarding it.</p><p>There is a lot more we can do, but for next time we will focus only on the above two steps. Let me know in the comments if there are some specific next steps you would like to see.</p><p>Thanks for reading Vibhav’s Tech Diary! Subscribe for free to receive new posts and support my work. <a href="https://vibhavstechdiary.substack.com/p/in-search-of-a-nextcloud-operator"><em>https://vibhavstechdiary.substack.com</em></a></p><p><em>Originally published at </em><a href="https://vibhavstechdiary.substack.com/p/in-search-of-a-nextcloud-operator"><em>https://vibhavstechdiary.substack.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bdf14bb85f89" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Necessities of an Air-Gapped Environment ]]></title>
            <link>https://waveywaves.medium.com/necessities-of-an-air-gapped-environment-3bb7f6f8e579?source=rss-107cf468a271------2</link>
            <guid isPermaLink="false">https://medium.com/p/3bb7f6f8e579</guid>
            <category><![CDATA[airgapped]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[zarf]]></category>
            <dc:creator><![CDATA[Vibhav Bobade]]></dc:creator>
            <pubDate>Sun, 27 Oct 2024 04:32:12 GMT</pubDate>
            <atom:updated>2024-10-27T04:32:12.088Z</atom:updated>
            <content:encoded><![CDATA[<h4>Important components required to transport and run mission critical Kubernetes software in secure networked environments</h4><h3>Introduction</h3><h4>What is an air-gapped environment ?</h4><p>It’s possible you haven’t heard of air-gapped environments if you haven’t worked in enterprise software. Enterprises like running their workloads in controlled environments where the supply chain is monitored very closely to avoid any unnecessary side effects and vulnerabilites being introduced into the system due to unsecure network exposure.</p><p>Air-gapped systems are necessary security pre-requisite in enterprises but what are the tools we need which make a modern air-gapped system ? Getting data in and out of an air-gapped environment is already hard considering you have to transport the data to a server which has access to the system and then inject the data from there. This becomes even harder when we have to manage a complex distributed system like Kubernetes in an air-gapped environment.</p><p>Thanks for reading Vibhav’s Tech Diary! Subscribe for free to receive new posts and support my work. <a href="https://vibhavstechdiary.substack.com/p/necessities-of-an-air-gapped-environment"><em>https://vibhavstechdiary.substack.com</em></a><em>.</em></p><h4>Air-gapping Kubernetes clusters from the get-go</h4><p>In the context of Kubernetes, you will usually need access to a registry which will have all the necessary images you need to run your mission critical software.</p><ul><li>What if we didn’t want the Kubernetes cluster to have any access to a unsecure network or an external network in it’s lifetime ?</li><li>What if we wanted the Kubernetes cluster to be self sufficient in an air-gapped environment from the get go ?</li></ul><h4>A swiss-knife for air-gapped software delivery</h4><p>This is where <a href="https://zarf.dev/">Zarf</a> comes in.</p><p><a href="https://zarf.dev/">Zarf</a> is a package manager for Kubernetes which specializes in software delivery to air-gapped environments.</p><h4>Necessities of a air-gapped Kubernetes cluster</h4><p>Here, we are going to look at critical components required to make an air-gapped environment self-sufficient. When we say self-sufficient, we mean that the environment should have a local artifact registry and a git server which will ensure that the said system is GitOps enabled as well.</p><p>We are going to also look at this environment in the context of Kubernetes and what it takes to have a Kubernetes clusters initialize and successfully work and be self-sufficient to a particular extent in an air-gapped environment.</p><h3>Prerequisites</h3><h4>Necessary Background Knowledge</h4><p>The reader will need to have an understanding of the following ideas/concepts/tools to be able to get through this article with minimal effort.</p><ul><li>Kubernetes (basic working knowledge)</li><li>- ConfigMaps</li><li>- Pods</li><li>- Mutating Admission Webhooks</li><li>Helm</li><li>- Charts vs. Releases</li><li>Basic working of an HTTP Server</li><li>Container image internals</li><li>Git Server</li></ul><h4>Setting up a test air-gapped Kubernetes cluster</h4><p>Tools Used</p><ul><li>minikube / kind / k3d etc.</li><li>zarf</li></ul><p>Let’s go !</p><p>We first need a Kubernetes cluster which we can “air-gap” i.e. disconnect it from the internet (the most air-gapping we need right now to learn about software delivery on air-gapped Kubernetes clusters).</p><p>I am using a Mac so I am going to use Docker Desktop + minikube.</p><pre>minikube start</pre><pre>😄  minikube v1.31.2 on Darwin 14.2.1 (arm64)<br>🎉  minikube 1.34.0 is available! Download it: <a href="https://github.com/kubernetes/minikube/releases/tag/v1.34.0">https://github.com/kubernetes/minikube/releases/tag/v1.34.0</a><br>💡  To disable this notice, run: &#39;minikube config set WantUpdateNotification false&#39;</pre><pre>✨  Using the docker driver based on existing profile</pre><pre>💣  Exiting due to PROVIDER_DOCKER_NOT_RUNNING: &quot;docker version --format &lt;no value&gt;-&lt;no value&gt;:&lt;no value&gt;&quot; exit status 1: Cannot connect to the Docker daemon at unix:///Users/vibhavbobade/.docker/run/docker.sock. Is the docker daemon running?<br>💡  Suggestion: Start the Docker service<br>📘  Documentation: <a href="https://minikube.sigs.k8s.io/docs/drivers/docker/">https://minikube.sigs.k8s.io/docs/drivers/docker/</a></pre><p>And now minikube runs happily on my system.</p><p>Next we need to <a href="https://docs.zarf.dev/getting-started/install/">install Zarf</a>.</p><pre>brew tap defenseunicorns/tap &amp;&amp; brew install zarf</pre><p>Once installed, contemplate on the nature of security in this world and then remember that you have another train of thought to complete and then create a folder which will be a safe space for this technical exploration.</p><pre>mkdir zarf-test/explore-init</pre><p>Contemplate for a bit whether you are a ‘-’ person or a `_` person and move on. Abandon minikube and start using kind.</p><pre>minikube delete<br>kind delete cluster &amp;&amp; kind create cluster</pre><pre>Deleting cluster &quot;kind&quot; ...<br>ERROR: failed to delete cluster &quot;kind&quot;: error listing nodes: failed to list nodes: command &quot;docker ps -a --filter label=io.x-k8s.kind.cluster=kind --format &#39;{{.Names}}&#39;&quot; failed with error: exit status 1<br>Command Output: Cannot connect to the Docker daemon at unix:///Users/vibhavbobade/.docker/run/docker.sock. Is the docker daemon running?</pre><p>Realize you haven’t started Docker Desktop, restart it and rerun the kind cluster creation commands.</p><pre>kind delete cluster &amp;&amp; kind create cluster</pre><pre>Deleting cluster &quot;kind&quot; ...<br>Creating cluster &quot;kind&quot; ...<br> ✓ Ensuring node image (kindest/node:v1.29.2) 🖼<br> ✓ Preparing nodes 📦  <br> ✓ Writing configuration 📜 <br> ✓ Starting control-plane 🕹️  <br> ✓ Installing CNI 🔌<br> ✓ Installing StorageClass 💾 <br>Set kubectl context to &quot;kind-kind&quot;<br>You can now use your cluster with:</pre><pre>kubectl cluster-info --context kind-kind</pre><pre>Not sure what to do next? 😅  Check out <a href="https://kind.sigs.k8s.io/docs/user/quick-start/">https://kind.sigs.k8s.io/docs/user/quick-start/</a></pre><p>Let’s initialize the air-gapped environment for usage. Before that we are going to check our zarf version.</p><pre>zarf version</pre><pre>v0.41.0</pre><p>Awesome.</p><h3>Components required for an air-gapped environment</h3><p>Learning about air-gapped environments through Zarf</p><p>Zarf makes it easy for us to dig deeper into deploying an air-gapped Kubernetes cluster and understanding</p><h4>Initialization</h4><p>Installing the Init Package</p><p>Now that we have Zarf installed, let’s initialize our kind cluster so that it will be a self reliant Kubernetes cluster who does not need help from the outside world when it comes to mission critical services.</p><pre>zarf init</pre><pre>NOTE  Saving log file to<br>       /var/folders/v7/yqyq_d6x2996hfnnwvgs5f080000gn/T/zarf-2024-10-11-00-44-29-2167645169.log</pre><pre>It seems the init package could not be found locally, but can be pulled from<br>oci://ghcr.io/zarf-dev/packages/init:v0.41.0</pre><pre> NOTE  Note: This will require an internet connection.<br>? Do you want to pull this init package? (y/N)</pre><p>zarf is trying to pull a particular init package from oci://ghcr.io/zarf-dev/packages/init:v0.41.0. Let’s have zarf pull it by pressing `y` and enter and try to see what this init package is. You should see a progress bar like the one below as you go ahead with this.</p><pre>? Do you want to pull this init package? Yes<br>    Pulling (63.19 MBs of 325.30 MBs) ███████████████████████████████████████████████████  19% | 12s</pre><p>Once the package is pulled we will see the below output. For this specifically we needed the init package to be pulled but in an air-gapped environment, we can have this init package be pulled before hand so that it can be used without requiring the user to have an internet connection.</p><pre>NOTE  Note: This will require an internet connection.                                                                                                                                                                <br>? Do you want to pull this init package? Yes                                                                                                                                                                          <br>  ✔  Pulling &quot;oci://ghcr.io/zarf-dev/packages/init:v0.41.0&quot; (325.30 MBs)                                                                                                                                              <br>  ✔  Validating full package checksums                                                                                                                                                                                <br>  ✔  Loading package from &quot;/Users/vibhavbobade/.zarf-cache/zarf-init-arm64-v0.41.0.tar.zst&quot;                                                                                                                           <br>  ✔  Loading package from &quot;/Users/vibhavbobade/.zarf-cache/zarf-init-arm64-v0.41.0.tar.zst&quot;</pre><h4>Understanding the Init Package</h4><p>In the output we also have a Package Definition which we can go through.</p><pre>📦 PACKAGE DEFINITION                                                                                                                                                                                               <br>                                                                                                                                                                                                             <br>kind: ZarfInitConfig                                                                                                                                                                                                  <br>                                                                                                                                                                                                                      <br>━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━                                                                                                            <br>metadata:  information about this package                                                                                                                                                                             <br>                                                                                                                                                                                                                      <br>  name: init                                                                                                                                                                                                          <br>  description: Used to establish a new Zarf cluster                                                                                                                                                                   <br>  version: v0.41.0                                                                                                                                                                                                    <br>  architecture: arm64                                                                                                                                                                                                 <br>  aggregateChecksum: a1e37c97567a64c8067e1c3886914bc040f5179c9b6703ce793272eddd80b360                                                                                                                                 <br>                                                                                                                                                                                                                      <br>━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━                                                                                                              <br>build:  info about the machine, zarf version, and user that created this package                                                                                                                                      <br>                                                                                                                                                                                                                      <br>  terminal: fv-az1501-989                                                                                                                                                                                             <br>  user: runner                                                                                                                                                                                                        <br>  architecture: arm64                                                                                                                                                                                                 <br>  timestamp: Thu, 03 Oct 2024 18:40:17 +0000                                                                                                                                                                          <br>  version: v0.41.0                                                                                                                                                                                                    <br>  migrations:                                                                                                                                                                                                         <br>  - scripts-to-actions                                                                                                                                                                                                <br>  - pluralize-set-variable<br>  lastNonBreakingVersion: v0.27.0</pre><p>The first two sections of the Package Definition as we can see about are the metadata of the package and the build section which contains information about the build of this package. The package definition also contains different components that are present in the init package which would be installed. Let’s go component by component.</p><pre>━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━                                                                                                00:47:51 [293/710]<br>components:  components selected for this operation                                                                                                                                                                   </pre><pre>- name: k3s<br>  description: &quot;*** REQUIRES ROOT (not sudo) *** Install K3s, a certified Kubernetes distribution built for IoT &amp; Edge computing. K3s provides the cluster need for Zarf running in Appliance Mode as well as can host<br> a low-resource Gitops Service if not using an existing Kubernetes platform.&quot;<br>  only:<br>    localOS: linux<br>  files:<br>  - source: packages/distros/k3s/common/zarf-clean-k3s.sh<br>    target: /opt/zarf/zarf-clean-k3s.sh<br>    executable: true<br>  - source: packages/distros/k3s/common/k3s.service<br>    target: /etc/systemd/system/k3s.service<br>    symlinks:<br>    - /etc/systemd/system/multi-user.target.wants/k3s.service<br>  - source: <a href="https://github.com/k3s-io/k3s/releases/download/v1.28.4+k3s2/k3s-arm64">https://github.com/k3s-io/k3s/releases/download/v1.28.4+k3s2/k3s-arm64</a><br>    shasum: 1ae72ca06d3302f3e86ef92e6e8f84e14a084da69564e87d6e2e75f62e72388d<br>    target: /usr/sbin/k3s<br>    executable: true<br>    symlinks:<br>    - /usr/sbin/kubectl<br>    - /usr/sbin/ctr<br>    - /usr/sbin/crictl<br>  - source: <a href="https://github.com/k3s-io/k3s/releases/download/v1.28.4+k3s2/k3s-airgap-images-arm64.tar.zst">https://github.com/k3s-io/k3s/releases/download/v1.28.4+k3s2/k3s-airgap-images-arm64.tar.zst</a><br>    shasum: 50621ae1391aec7fc66ca66a46a0e9fd48ce373a58073000efdc278233adc64b<br>    target: /var/lib/rancher/k3s/agent/images/k3s.tar.zst<br>  actions:<br>    onDeploy:<br>      before:<br>      - maxRetries: 0<br>        cmd: ./zarf internal is-valid-hostname<br>        description: Check if the current system has a, RFC1123 compliant hostname<br>      - cmd: &quot;[ -e /etc/redhat-release ] &amp;&amp; systemctl disable firewalld --now || echo &#39;&#39;&quot;<br>        description: If running a RHEL variant, disable &#39;firewalld&#39; per k3s docs<br>      - maxRetries: 0<br>        cmd: if [ &quot;$(uname -m)&quot; != &quot;aarch64&quot; ] &amp;&amp; [ &quot;$(uname -m)&quot; != &quot;arm64&quot; ]; then echo &quot;this package architecture is arm64, but the target system has a different architecture. These architectures must be the sam<br>e&quot; &amp;&amp; exit 1; fi<br>        description: Check that the host architecture matches the package architecture<br>      after:<br>      - cmd: systemctl daemon-reload<br>        description: Reload the system services<br>      - cmd: systemctl enable k3s<br>        description: Enable &#39;k3s&#39; to run at system boot<br>      - cmd: systemctl restart k3s<br>        description: Start the &#39;k3s&#39; system service<br>    onRemove:<br>      before:<br>      - cmd: /opt/zarf/zarf-clean-k3s.sh<br>        description: Remove &#39;k3s&#39; from the system<br>      - cmd: rm /opt/zarf/zarf-clean-k3s.sh<br>        description: Remove the cleanup script</pre><p>As we see above, the first component is actually <a href="https://k3s.io/">K3s</a>. From the description above, we understand that <a href="https://k3s.io/">K3s</a> provides the cluster need for Zarf running in Appliance Mode as well as can host a low-resource Gitops Service if not using an existing Kubernetes platform.</p><p>To understand Appliance Mode I had to go to<a href="https://github.com/zarf-dev/zarf/issues/174"> this github issue</a> where Jeff McCoy has described Appliance Mode perfectly.</p><blockquote><em>Zarf deploys a </em><a href="https://k3s.io/"><em>K3s</em></a><em> cluster with some pre-configured technologies in a simple, low-resource, declarative way we have been calling </em><strong><em>Appliance Mode</em></strong><em>.</em></blockquote><p>This means that we didn’t have to run our own kind cluster and could have just run zarf in Applicance Mode for the purpose of this, but is that even true.</p><p>I searched the Zarf docs for Appliance Mode and got 2 hits. Both of them mention using this mode during CLI E2E tests. This is a good way to make development easy for zarf by building in the required components for testing, making it a developer friendly application as well.</p><h4>Components required to initialize an air-gapped environment</h4><p>Let’s move on to the next three components. There are a total of five.</p><pre>- name: zarf-injector                                                                                                                                                                                                 <br>  description: |                                                                                                                                                                                                      <br>    Bootstraps a Kubernetes cluster by cloning a running pod in the cluster and hosting the registry image.                                                                                                           <br>    Removed and destroyed after the Zarf Registry is self-hosting the registry image.                                                                                                                                 <br>  required: true                                                                                                                                                                                                      <br>  files:                                                                                                                                                                                                              <br>  - source: https://zarf-init.s3.us-east-2.amazonaws.com/injector/2024-07-22/zarf-injector-arm64                                                                                                                      <br>    shasum: b905e647e0d7876cfd5b665632cfc43ad919dc60408f7236c5b541c53277b503                                                                                                                                          <br>    target: &quot;###ZARF_TEMP###/zarf-injector&quot;                                                                                                                                                                           <br>    executable: true</pre><pre>- name: zarf-seed-registry<br>  description: |<br>    Deploys the Zarf Registry using the registry image provided by the Zarf Injector.<br>  required: true<br>  charts:<br>  - name: docker-registry<br>    version: 1.0.0<br>    localPath: packages/zarf-registry/chart<br>    namespace: zarf<br>    releaseName: zarf-docker-registry<br>    valuesFiles:<br>    - packages/zarf-registry/registry-values.yaml<br>    - packages/zarf-registry/registry-values-seed.yaml<br>  images:<br>  - library/registry:2.8.3</pre><pre>- name: zarf-registry                                                                                                                                                                                                 <br>  description: |                                                                                                                                                                                                      <br>    Updates the Zarf Registry to use the self-hosted registry image.                                                                                                                                                  <br>    Serves as the primary docker registry for the cluster.                                                                                                                                                            <br>  required: true                                                                                                                                                                                                      <br>  manifests:                                                                                                                                                                                                          <br>  - name: registry-connect                                                                                                                                                                                            <br>    namespace: zarf                                                                                                                                                                                                   <br>    files:                                                                                                                                                                                                            <br>    - packages/zarf-registry/connect.yaml                                                                                                                                                                             <br>  - name: kep-1755-registry-annotation                                                                                                                                                                                <br>    namespace: zarf                                                                                                                                                                                                   <br>    files:                                                                                                                                                                                                            <br>    - packages/zarf-registry/configmap.yaml                                                                                                                                                                           <br>  charts:                                                                                                                                                                                                             <br>  - name: docker-registry                                                                                                                                                                                             <br>    version: 1.0.0                                                                                                                                                                                                    <br>    localPath: packages/zarf-registry/chart                                                                                                                                                                           <br>    namespace: zarf                                                                                                                                                                                                   <br>    releaseName: zarf-docker-registry                                                                                                                                                                                 <br>    valuesFiles:                                                                                                                                                                                                      <br>    - packages/zarf-registry/registry-values.yaml                                                                                                                                                                     <br>  images:                                                                                                                                                                                                             <br>  - library/registry:2.8.3                                                                                                                                                                                            <br>  actions:                                                                                                                                                                                                            <br>    onDeploy:                                                                                                                                                                                                         <br>      after:                                                                                                                                                                                                          <br>      - wait:                                                                                                                                                                                                         <br>          cluster:                                                                                                                                                                                                    <br>            kind: deployment                                                                                                                                                                                          <br>            name: app=docker-registry                                                                                                                                                                                 <br>            namespace: zarf                                                                                                                                                                                           <br>            condition: Available</pre><p>You can read the <a href="https://docs.zarf.dev/ref/init-package/#core-components">Core Components documentation</a>, but we are trying to read the docs and trying to read these package manifests to understand this more intuitively. So, hang on.</p><h4>Zarf Injector, Seed Registry and Main Registry : Injecting a Container Registry and the brilliance of a Seed Registry with Zarf</h4><p>In a Kubernetes cluster you cannot just inject an image into the cluster. First, the cluster needs to have a registry and if you want to run a registry in a Kubernetes cluster you are going to need to have an image already available in a nearby registry to be able to do that.</p><p>The Chicken and Egg Problem: I need a registry in the cluster, but I can’t create a registry in the cluster because the cluster doesn’t have a registry which contains an image for the registry.</p><p>In our scenario where we have no access to the internet and the Kubernetes cluster is airgapped, you cannot get access to the internet and pull the registry image with docker and then run the image in a Pod on the cluster. Here we have two problems :-</p><ul><li>No registry running in the cluster</li><li>No image available to be be pulled from a registry</li></ul><p>A classic chicken and egg problem. But what if the image for the registry didn’t have to be an image.</p><p>All images are datablobs and can be represented as tarballs and can be moved around as we please. All kubernetes clusters also have ConfigMap support regardless of whether they are EKS, AKS, K3S or Vanila Kubernetes. We could divide this registry image up between multiple configmaps and install it into the cluster. But once installed these configmaps need to be reassembled. This is where the <a href="https://github.com/zarf-dev/zarf/blob/main/src/injector/README.md">zarf-injector</a> comes into the picture.</p><p><em>The below is from the documentation itself :-</em></p><p>The zarf-injector binary serves 2 purposes during &#39;init&#39;.</p><ol><li>It re-assembles a multi-part tarball that was split into multiple ConfigMap entries (located at ./zarf-payload-*) back into payload.tar.gz, then extracts it to the /zarf-seed directory. It also checks that the SHA256 hash of the re-assembled tarball matches the first (and only) argument provided to the binary.</li><li>It runs a pull-only, insecure, HTTP OCI compliant registry server on port 5000 that serves the contents of the /zarf-seed directory (which is of the OCI layout format).</li></ol><p>The zarf-injector binary’s job is to re assemble the registry’s image basically. But, once the zarf-injector and the registry’s images as ConfigMaps are already present in the cluster what happens now ? We have a total of 11 relevant ConfigMaps here now. 10 for each MB of the registry image and 1 for the zarf-injector binary.</p><p>The zarf-injector component unlike the other components is just an executable file and nothing more. It is hence of type <a href="https://docs.zarf.dev/ref/components/#files">Files</a> and is copied from source to target where the source is a AWS S3 bucket and target is ###ZARF_TEMP###/zarf-injector. From <a href="https://github.com/zarf-dev/zarf/issues/1413#issuecomment-1467152447">this comment</a> we understand that</p><blockquote><em>###ZARF_TEMP### is also a special internal variable that can only be used with </em><em>file </em><em>targets and nothing else...</em></blockquote><p>Zarf <a href="https://github.com/zarf-dev/zarf/blob/main/src/pkg/cluster/injector.go#L264">searches for an image</a> which is already running onto the cluster and uses it as a base from where it can run the zarf-injector binary.</p><p><a href="https://github.com/zarf-dev/zarf/blob/main/src/pkg/cluster/injector.go#L112">This</a> is where the injection Pod build executes, and this is what the build looks like. As you can see, this piece of code which is run by the CLI generates a Pod manifest which is then created onto the cluster. The zarf-injector binary here is running in an unknown environment and this is what it was created for. The injection here is complete. The injector binary also executes the assembled registry image as you can see <a href="https://github.com/zarf-dev/zarf/blob/main/src/injector/src/main.rs#L104">here</a>. Cool.</p><p>We basically have fragmented binaries which were brought into a Kubernetes Cluster via ConfigMaps. A Pod created to run one of the ConfigMaps as a binary which assembled the other ConfigMaps into a tarball and then <a href="https://github.com/zarf-dev/zarf/blob/main/src/injector/src/main.rs#L64">unpacked</a> again to get the files that were part of the tarball, and then we start the Axum http server which serves the a docker registry containing the registry image we just assembled.</p><p>If you notice the seed-registry and the registry components above, you can see that the only difference in the value files is the seed-registry having an extra values file provided.</p><pre>image:<br>  repository: &quot;###ZARF_SEED_REGISTRY###/###ZARF_CONST_REGISTRY_IMAGE###&quot;<br>  tag: &quot;###ZARF_CONST_REGISTRY_IMAGE_TAG###&quot;</pre><p>###ZARF_SEED_REGISTRY### is temporarily set to the location of the injector which is serving the seed image in this release. This is then overriden when the zrf-registry component executes and the value is set to ###ZARF_REGISTRY### as you can see here. Once this component runs and executes it’s marked as completed, after making changes to the newly deployed registry chart. At this point the cluster would be using this registry as the default registry and with that the cluster has been initialized with a docker-registry.</p><h4>Ensuring automatic resource aliasing to avoid operational overhead</h4><p>Now that the cluster has been initialized with it’s own docker-registry we can run services inside the cluster which are necessary for us to run our GitOps applications and that brings us onto our next component. The Zarf Agent.</p><pre>- name: zarf-agent                                                                                                                                                                                                    <br>  description: |                                                                                                                                                                                                      <br>    A Kubernetes mutating webhook to enable automated URL rewriting for container                                                                                                                                     <br>    images and git repository references in Kubernetes manifests. This prevents                                                                                                                                       <br>    the need to manually update URLs from their original sources to the Zarf-managed                                                                                                                                  <br>    docker registry and git server.                                                                                                                                                                                   <br>  required: true                                                                                                                                                                                                      <br>  manifests:                                                                                                                                                                                                          <br>  - name: zarf-agent                                                                                                                                                                                                  <br>    namespace: zarf                                                                                                                                                                                                   <br>    files:                                                                                                                                                                                                            <br>    - packages/zarf-agent/manifests/service.yaml                                                                                                                                                                      <br>    - packages/zarf-agent/manifests/secret.yaml                                                                                                                                                                       <br>    - packages/zarf-agent/manifests/deployment.yaml                                                                                                                                                                   <br>    - packages/zarf-agent/manifests/webhook.yaml                                                                                                                                                                      <br>    - packages/zarf-agent/manifests/role.yaml                                                                                                                                                                         <br>    - packages/zarf-agent/manifests/rolebinding.yaml                                                                                                                                                                  <br>    - packages/zarf-agent/manifests/clusterrole.yaml                                                                                                                                                                  <br>    - packages/zarf-agent/manifests/clusterrolebinding.yaml                                                                                                                                                           <br>    - packages/zarf-agent/manifests/serviceaccount.yaml                                                                                                                                                               <br>  images:                                                                                                                                                                                                             <br>  - ghcr.io/zarf-dev/zarf/agent:v0.41.0                                                                                                                                                                               <br>  actions:                                                                                                                                                                                                            <br>    onCreate:                                                                                                                                                                                                         <br>      before:                                                                                                                                                                                                         <br>      - dir: .                                                                                                                                                                                                        <br>        cmd: test &quot;v0.41.0&quot; != &quot;local&quot; || make build-local-agent-image AGENT_IMAGE_TAG=&quot;v0.41.0&quot; ARCH=&quot;arm64&quot;                                                                                                         <br>        shell:                                                                                                                                                                                                        <br>          windows: pwsh                                                                                                                                                                                               <br>        description: Build the local agent image (if &#39;AGENT_IMAGE_TAG&#39; was specified as &#39;local&#39;)                                                                                                                      <br>    onDeploy:                                                                                                                                                                                                         <br>      after:                                                                                                                                                                                                          <br>      - wait:                                                                                                                                                                                                         <br>          cluster:                                                                                                                                                                                                    <br>            kind: pod                                                                                                                                                                                                 <br>            name: app=agent-hook                                                                                                                                                                                      <br>            namespace: zarf                                                                                                                                                                                           <br>            condition: Ready</pre><p>This component is a Mutating Admission Webhook and it’s job is to intercept any workload creation request to see if the images which are being requested have an alternate image in the internal registry. This way the user doesn’t have to update the name of the image everytime they are deploying an application on Zarf.</p><p>The zarf-agent does the same internal renaming of git servers as it does for images. With that let’s move onto the final component which is the git-server.</p><h4>A reliable Git server for all the GitOps needs</h4><pre>- name: git-server                                                                                                                                                                                                    <br>  description: |                                                                                                                                                                                                      <br>    Deploys Gitea to provide git repositories for Kubernetes configurations.                                                                                                                                          <br>    Required for GitOps deployments if no other git server is available.                                                                                                                                              <br>  manifests:<br>  - name: git-connect<br>    namespace: zarf<br>    files:<br>    - packages/gitea/connect.yaml<br>  charts:<br>  - name: gitea<br>    version: 10.1.1<br>    url: https://dl.gitea.io/charts<br>    namespace: zarf<br>    releaseName: zarf-gitea<br>    valuesFiles:<br>    - packages/gitea/gitea-values.yaml<br>  images:<br>  - gitea/gitea:1.21.5-rootless<br>  actions:<br>    onDeploy:<br>      before:<br>      - mute: true<br>        cmd: ./zarf internal update-gitea-pvc --no-progress<br>        setVariables:<br>        - name: GIT_SERVER_CREATE_PVC<br>      after:<br>      - wait:<br>          cluster:<br>            kind: pod<br>            name: app=gitea<br>            namespace: zarf<br>            condition: Ready<br>      - maxTotalSeconds: 60<br>        maxRetries: 3<br>        cmd: ./zarf internal create-read-only-gitea-user --no-progress<br>        description: Create the read-only Gitea user<br>      - maxTotalSeconds: 60<br>        maxRetries: 3<br>        cmd: ./zarf internal create-artifact-registry-token --no-progress<br>        description: Create an artifact registry token<br>      onFailure:<br>      - cmd: ./zarf internal update-gitea-pvc --rollback --no-progress</pre><p>Here, zarf installs a git server backed by Gitea which brings GitOps capabilities to this air-gapped Kubernetes clusters. Users can now use GitOps enabled tools like ArgoCD on an air-gapped cluster like this out of the box.</p><p>Now that we have understood what each of these components are, let’s move past the constants and variables for now and initialize our Zarf enabled Air-Gapped Kubernetes Cluster.</p><pre>...<br>━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━<br> Software Bill of Materials   an inventory of all software contained in this package</pre><pre> NOTE  This package has 5 artifacts to be reviewed. These are available in a temporary<br>       &#39;zarf-sbom&#39; folder in this directory and will be removed upon deployment.</pre><pre>- View SBOMs now by navigating to the &#39;zarf-sbom&#39; folder or copying this link into a browser:<br>/Users/vibhavbobade/go/src/github.com/waveywaves/zarf-test/zarf-sbom/sbom-viewer-docker.io_gitea_gitea_1.21.5-rootless.html</pre><pre>- View SBOMs after deployment with this command:<br>$ zarf package inspect /Users/vibhavbobade/.zarf-cache/zarf-init-arm64-v0.41.0.tar.zst</pre><pre>━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━</pre><pre>? Deploy this Zarf package? (y/N)¸</pre><p>I was asked if I want to install the git server compoent after saying yes above. I obliged and said yes please.</p><pre>✔  Zarf deployment complete</pre><pre>     Application          | Username           | Password                                 | Connect               | Get-Creds Key<br>     Registry             | zarf-push          | P3TgKAGniPUajPzMzcEJ58Jt                 | zarf connect registry | registry<br>     Registry (read-only) | zarf-pull          | sz4qG~Pe-9eGxDGwJcnySzjD                 | zarf connect registry | registry-readonly<br>     Git                  | zarf-git-user      | EhtJClcvRzq2jggrlw~dEsgA                 | zarf connect git      | git<br>     Git (read-only)      | zarf-git-read-user | 0j7Y8zE1S8svuV7ZTpkBV7pr                 | zarf connect git      | git-readonly<br>     Artifact Token       | zarf-git-user      | ea148bb0776c14424d578703018720805e156c34 | zarf connect git      | artifact</pre><p>This is the final part of the output after running zarf init and smashing the “y” button over and over again.</p><p>Now to test some of these fun connect commands</p><pre>zarf connect registry</pre><pre> NOTE  Using config file /Users/vibhavbobade/go/src/github.com/defenseunicorns/zarf/zarf-config.toml</pre><pre> NOTE  Saving log file to<br>       /var/folders/v7/yqyq_d6x2996hfnnwvgs5f080000gn/T/zarf-2024-10-11-03-45-17-208292671.log<br>  ⠹  Tunnel established at <a href="http://127.0.0.1:51632/v2/_catalog,">http://127.0.0.1:51632/v2/_catalog,</a> opening your default web browser (ctrl-c to end)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1018/0*6BFMO3dT23teHFBc.png" /></figure><p>Cool.</p><p>The agent, and the gitea images were pushed into the registry after deployed registry from the injector hosted seed-registry.</p><p>And these are the components required to run Kubernetes in an air-gapped environment and also have it be GitOps enabled.</p><p><em>Originally published at </em><a href="https://vibhavstechdiary.substack.com/p/necessities-of-an-air-gapped-environment"><em>https://vibhavstechdiary.substack.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3bb7f6f8e579" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Getting acquainted with XDG(freedesktop) on Linux]]></title>
            <link>https://waveywaves.medium.com/getting-acquainted-with-xdg-freedesktop-on-linux-18e63b5ed120?source=rss-107cf468a271------2</link>
            <guid isPermaLink="false">https://medium.com/p/18e63b5ed120</guid>
            <category><![CDATA[linux]]></category>
            <category><![CDATA[xdg]]></category>
            <category><![CDATA[freedesktop]]></category>
            <dc:creator><![CDATA[Vibhav Bobade]]></dc:creator>
            <pubDate>Fri, 25 Dec 2020 23:26:55 GMT</pubDate>
            <atom:updated>2021-01-05T19:05:21.541Z</atom:updated>
            <content:encoded><![CDATA[<h4>Understanding XDG Specifications and their importance</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*6aLpsyYdx_lTLQj2" /><figcaption>Photo by <a href="https://unsplash.com/@umby?utm_source=medium&amp;utm_medium=referral">Umberto</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>I stumbled upon XDG while working on an issue for a CLI tool in the past. It required a background on what XDG is and it’s specification. With a little bit of “googling” I was able to find the specification but I was still a bit confused as to what the hell XDG is and was frustrated that there is no concise article for it.</p><p>Somewhere, someone had said, <em>“If there is something that you want to read and it doesn’t exist, write it yourself.” </em>So here goes.</p><h4>What is XDG ?</h4><p>Quoting from the <a href="https://en.wikipedia.org/wiki/Freedesktop.org">freedesktop.org wikipedia page</a>,</p><blockquote>freedesktop.org was formerly known as the X Desktop Group, and the abbreviation “XDG” remains common in their work.</blockquote><p>Now we know that XDG is just another name for the freedesktop.org. But what is freedesktop.org ?</p><blockquote>freedesktop.org hosts the development of free and open source software, focused on interoperability and shared technology for open-source graphical and desktop systems. We do not ourselves produce a desktop, but we aim to help others to do so.</blockquote><blockquote>— <a href="https://www.freedesktop.org/wiki/">https://www.freedesktop.org/wiki/</a></blockquote><p>So, it is a collaboration zone for “interoperability and shared technology for open-source graphical and desktop systems”. Some of the more popular projects hosted by XDG are <a href="https://wayland.freedesktop.org/">Wayland</a>, <a href="https://www.freedesktop.org/wiki/Software/PulseAudio/">PulseAudio</a> and <a href="https://www.freedesktop.org/wiki/Software/systemd/">systemd</a>.</p><h4>The Portland Project</h4><p>Apart from sounding like a great name for a highschool garage band, The Portland Project was an initiative aimed at portable application software between desktop environments and kernels and hence strengthen the appeal of Linux as a Desktop Environment and not just for basement dwellers like some of us who refuse to deal with the capitalist technocrat folks of the Operating Systems world.</p><p><a href="https://www.freedesktop.org/wiki/Software/xdg-utils/"><strong><em>xdg-utils</em></strong></a> is the more well known name for the project and it is basically</p><blockquote>a set of tools that allows applications to easily integrate with the desktop environment of the user, regardless of the specific desktop environment that the user runs.</blockquote><h3>Relevant Specifications by XDG</h3><p>These specifications are important as they form the base for tools in <strong><em>xdg-utils </em></strong>and are a staple of Linux distributions today.</p><p>Some specifications one can start with are the<em> Base Directory</em> and the D<em>esktop Entry Specifications</em>. We are only covering the <strong><em>Base Directory Specification</em></strong> as it helps a ton to understand it while creating consistent applications across Linux Environments (great to know while building Command Line Interfaces for Linux).</p><h4>XDG Base Directory Specification</h4><p>Defines the Configuration for Base Directories and the <em>defaulted location of files based on their usage</em> so that not everything is stored in the same place by default.</p><blockquote>This specification outlines that the user-specific data, the configuration files and cache files for a particular application need to be segregated and each of their locations need to be defined by an environment variable.</blockquote><blockquote>User Specific Data should be in <strong><em>$XDG_DATA_HOME</em></strong><em> (default to </em><em>$HOME/.local/share)</em></blockquote><blockquote>Configuration files should be in<strong> </strong><strong><em>$XDG_CONFIG_HOME</em></strong><em> (default to </em><em>$HOME/.config)</em></blockquote><blockquote>Cache files in <strong><em>$XDG_CACHE_HOME </em></strong><em>(default </em><em>$HOME/.cache)</em></blockquote><p>Then there are other environment variables which are more of aggregators which help for searching the locations in different places.</p><blockquote>Multiple locations for Configuration files given in <strong><em>$XDG_CONFIG_DIRS (</em></strong><em>includes </em><em>$XDG_CONFIG_HOME)</em></blockquote><blockquote>Multiple locations for Data files <strong><em>$XDG_DATA_DIRS </em></strong><em>(includes </em><em>$XDG_DATA_HOME)</em></blockquote><h3>References</h3><p>Base Directory Specification <a href="https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html">https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html</a></p><p><a href="https://wiki.archlinux.org/index.php/XDG_Base_Directory">https://wiki.archlinux.org/index.php/XDG_Base_Directory</a></p><p><a href="https://askubuntu.com/tags/xdg-open/info">https://askubuntu.com/tags/xdg-open/info</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=18e63b5ed120" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Jenkins Operator 0.7.0 on Openshift 4]]></title>
            <link>https://waveywaves.medium.com/managing-jenkins-with-the-jenkins-operator-0-7-0-on-openshift-4-1c6fe4434667?source=rss-107cf468a271------2</link>
            <guid isPermaLink="false">https://medium.com/p/1c6fe4434667</guid>
            <category><![CDATA[jenkins]]></category>
            <category><![CDATA[openshift]]></category>
            <category><![CDATA[operators]]></category>
            <dc:creator><![CDATA[Vibhav Bobade]]></dc:creator>
            <pubDate>Fri, 18 Dec 2020 08:21:46 GMT</pubDate>
            <atom:updated>2021-01-05T19:27:58.331Z</atom:updated>
            <content:encoded><![CDATA[<h3>The Jenkins Operator v0.7.0 on Openshift 4</h3><h4>Operator managed Jenkins on Kubernetes</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*HutQSHYwazbGODd9" /><figcaption>Photo by <a href="https://unsplash.com/@realaxer?utm_source=medium&amp;utm_medium=referral">tian kuan</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>Introduction</h3><p>Jenkins has been <strong>the</strong> CI/CD tool used by most companies out there big and small. Before there was DevOps, there was Jenkins and Jenkins ushered the DevOps revolution by helping abstract and automate processes which were too cumbersome to be done manually all the time.</p><p>Administration of Jenkins has thus become a real responsibility and with the increasing infrastructure needs of individuals, managing Jenkins can become tough and at times frustrating. While we understand this, Jenkins itself has tried to keep up with the times by being extensible with a massive plugin support and increasing improvements in performance especially with the onset of increased need for containerization. With that in mind, The Jenkins Operator was created to help better manage and automate the Jenkins lifecycle in Kubernetes.</p><h3>We’ve come a long way</h3><p>Since the last blog post on Jenkins Operator 0.4.0, we have been working on the Operator <a href="https://github.com/redhat-developer/jenkins-operator">here</a> with having a better code quality, architecture and user experience in mind. We have moved the Jenkins Operator from its previously monolith design to a more distributed design, which allows for increased performance and better code readability which makes it easier for contributors in the open source community to contribute.</p><h3>Working with the Jenkins Operator on Openshift</h3><p>The Jenkins Operator has been released as a Tech preview on Openshift now which can be consumed by users. In the following examples we will look at how to use the Jenkins Operator on Openshift.</p><h3>Deploying the Jenkins Operator</h3><p>Login to the Openshift Console and create a new project.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/274/0*LlvnJn7tVNZJHzhT" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/603/0*nDCuQU1CFdSiI5bi" /></figure><p>Install the Operator in the newly created project</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/865/0*f6Ute2_ppsDjCOvT" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/659/0*nwXkU0b7T4h3fm-L" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/639/0*BSivbtpNwG3om3Fi" /></figure><p>Once the Operator has successfully installed please follow the documentation <a href="https://github.com/redhat-developer/jenkins-operator/tree/master/docs">here</a> to perform any of the following tasks.</p><h3>Building a custom Jenkins Image</h3><p>The Jenkins Operator provides the ability for the users to create their own Jenkins images which can be used in a reproducible way without having to install their plugins at runtime. This sees to it that the user has a definitive workflow and a good idea of what plugins they need to use and keep documented to have their Jenkins run in a stable manner in Kubernetes.</p><p>To be able to use <em>ConfigurationAsCode</em> for Jenkins you would also have to include the <a href="https://plugins.jenkins.io/configuration-as-code/">plugin</a> in the Jenkins Image you are using.</p><p>You can follow the <a href="https://github.com/redhat-developer/jenkins-operator/blob/master/docs/jenkinsimage.adoc">documentation</a> provided here to create your Jenkins Image via the Operator and push it to your repository.</p><h3>Configuring the Jenkins instance</h3><p>As you have your Jenkins image ready , you would need to deploy it with the right configuration which fits your needs. You can follow the <a href="https://github.com/redhat-developer/jenkins-operator/blob/master/docs/configurationascode.adoc">documentation</a> to understand how to enable configuration as code for your jenkins instance and follow the steps to move your CasC configs from your legacy Jenkins instances to Kubernetes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/321/1*Iwj283YQsyX3ZNHbaD_xrQ.png" /></figure><p>If you would like to use Backup and Restore for your Jenkins instances you would also need to enable it as given <a href="https://github.com/redhat-developer/jenkins-operator/blob/master/docs/backupandrestore.adoc#enable-backup-for-your-jenkins-instance">here</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/373/1*ptjiMrl6PPyA1lFx_PqcMQ.png" /></figure><h3>Deploying Jenkins</h3><p>Once you have completed the configuration you can deploy the Jenkins by creating an instance of the Jenkins Custom Resource which has been configured above.</p><p>After creating the Jenkins instance with Backup enabled you can see that the default BackupConfig as well as the example Jenkins is up.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/934/1*JWE_lgFIZqUnfAceSqQu3w.png" /></figure><h3>Backup and Restore for our Jenkins instance</h3><p>As we now have enabled Backup for this Jenkins instance, we can now use Backup and Restore operations using the respective Custom Resources to secure important data you don’t want to lose.</p><p>You can follow the documentation given <a href="https://github.com/redhat-developer/jenkins-operator/blob/master/docs/backupandrestore.adoc">here</a> to understand how to configure and use the Backup and Restore operations.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/934/1*JWE_lgFIZqUnfAceSqQu3w.png" /><figcaption>Jenkins “example” was created with backupEnabled set to True and “default” BackupConfig was created for “example”.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/326/1*Ik7E4pryTDxs47NGvbknRw.png" /><figcaption>Click on Create Instance to trigger Backup.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/958/1*MqqS3Tfgwv-wb69E83JXPw.png" /><figcaption>The BackupConfig points to the Jenkins instance so provide the reference in the Config Ref.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/951/1*tmjwiV1pkeAX2Ga1s9iCeg.png" /><figcaption>After Backup is completed the Condition is updated in Backup.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/327/1*4bUNKRtxdAqGL7Yinzb_0Q.png" /><figcaption>Click on Create Instance to trigger Restore.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/943/1*HLbsrttqhtLtRhZvClco6g.png" /><figcaption>Mention which Backup needs to be restored.</figcaption></figure><h3>Running the Jenkins Operator locally</h3><p>You can run the Jenkins Operator locally for development purposes. The <a href="https://github.com/redhat-developer/jenkins-operator/blob/master/docs/install.adoc">documentation</a> for the same is provided.</p><p>This would be very good for running locally and testing the Operator before deployment.</p><h3>What’s Next ?</h3><p>With the current update we have added features and updated the architecture and as we move forward we would be working on improving it further. Our focus currently is for the user to be able to automate their Jenkins lifecycle. So we would be working on fixes and features to make the Operator more robust and have a better automation lifecycle.</p><p>We would be focusing on the following:</p><ul><li>BackupSchedule for scheduling backups at regular intervals</li><li>Persistence Support for Jenkins and Backups</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1c6fe4434667" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Get Started w/ the Jenkins Operator v0.4.0 on Openshift 4.]]></title>
            <link>https://waveywaves.medium.com/get-started-w-the-jenkins-operator-v0-4-0-on-openshift-4-e11d7c5c2625?source=rss-107cf468a271------2</link>
            <guid isPermaLink="false">https://medium.com/p/e11d7c5c2625</guid>
            <category><![CDATA[openshift]]></category>
            <category><![CDATA[jenkins]]></category>
            <category><![CDATA[continuous-delivery]]></category>
            <category><![CDATA[continuous-integration]]></category>
            <category><![CDATA[kubernetes]]></category>
            <dc:creator><![CDATA[Vibhav Bobade]]></dc:creator>
            <pubDate>Mon, 27 Apr 2020 07:24:59 GMT</pubDate>
            <atom:updated>2020-12-28T05:27:44.461Z</atom:updated>
            <content:encoded><![CDATA[<h3>Get Started w/ the Jenkins Operator v0.4.0 on Openshift 4</h3><figure><img alt="Mostly accurate representation of what a Jenkins Pipeline looks like in everyone’s mind." src="https://cdn-images-1.medium.com/max/1024/0*BD7ewzmSyz7uINct" /><figcaption>Photo by <a href="https://unsplash.com/@jjying?utm_source=medium&amp;utm_medium=referral">JJ Ying</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Jenkins in the past has been provided as a first class Build option alongside Dockerfile build and s2i build in Openshift. Currently, Jenkins is well integrated in the Openshift ecosystem and with the movement of everything towards Operators, it is only natural that Jenkins make the move as well.</p><p>We will go through the current Jenkins Operator specification and how you can migrate from your earlier workflow for Jenkins on Openshift to the Jenkins Operator with minimal changes to your current infrastructure.</p><h3>What is the Jenkins Operator ?</h3><p>The <a href="https://github.com/jenkinsci/kubernetes-operator">Jenkins Operator</a> is a <a href="https://coreos.com/operators/">Kubernetes Operator </a>which aims to carry out Day 2 operational tasks with minimal or no intervention allowing for automation of operational tasks which can be repetetive at times. Operations like SeedJobs creation and Backup management are aimed at being automated in this case.</p><p>The Jenkins Operator has initially been developed by <a href="https://virtuslab.com/">VirtusLab</a> and is now being adopted by us folks working at <a href="https://www.redhat.com/en">Red Hat</a> on <a href="https://www.openshift.com/">Openshift</a>. With it’s strong backing from the community as well as it being a part of the <a href="https://github.com/jenkinsci">JenkinsCI</a> organization on Github, there lies a lot of potential to make this the defacto Jenkins Operator for people who cannot move to other CI/CD systems.</p><h3>Your Traditional Jenkins Workflow on Openshift</h3><p>If you already have Jenkins running in your Openshift Cluster, this is what your workflow might resemble from deploying to kickstarting a Jenkins Job.</p><ul><li>Deploy Jenkins via an Openshift Template</li><li>Create a Jenkins Job from a BuildConfig</li><li>Create Builds as instances of Runs for the Jenkins Job</li></ul><p>As we move forward we will carry out the same with a Jenkins instance deployed via a Jenkins Operator and also look at how to install the Operator itself.</p><h3>Deploying the Operator via Operator Lifecycle Manager</h3><h4>Installation</h4><ul><li>Login to your Openshift Cluster.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EQsiobDIKo-oTGFfv0Zj5g.png" /><figcaption>Openshift Login Page</figcaption></figure><ul><li>Go to Operators sub-menu in the burger menu and select OperatorHub and search for Jenkins Operator.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*z2Rs5GG1-PkLDK1NUGSm1A.png" /><figcaption>OperatorHub Menu</figcaption></figure><ul><li>Select Jenkins Operator and press theInstall button and in the next page for the Subscription, click on the Subscribe button for the Operator.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2gs5sxG97XHHE6cIi0AHwQ.png" /><figcaption>Operator Installation Page</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*POQv4eRNhWq48nsbYDluLw.png" /><figcaption>Operator Subscription Page</figcaption></figure><ul><li>Wait for the Operator to get installed and show up under your Installed Operators</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2kYkYVbDgSWBcMT8yRX64g.png" /><figcaption>Installed Operators in the current namespace</figcaption></figure><h4>Create Jenkins</h4><ul><li>To create a Jenkins instance, click on the Jenkins Operator as shown above and you would be presented with the menu below and then press on the + Create Instance in the Jenkins resource shown below, Provided APIs.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WuB0KNI8CLWEUdFtd01_LQ.png" /></figure><ul><li>You would be presented with the following option to make changes to the example. You can configure the size of the Jenkins as well as make other changes to the Instance via the YAML config. Press on Create once you are happy with the settings. Do remove the securityContext under the spec to avoid any problems regarding the same. We are working on getting this removed from example.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/883/1*X_DebPjzPJW1kBWjRl5H6g.png" /></figure><ul><li>If everything goes well, a Jenkins Instance would be created and be shown here.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/876/1*dK5UegoSjhtdpwsJrw-WWQ.png" /></figure><ul><li>Let’s login and check from the terminal.</li></ul><pre>$ oc login -u kubeadmin -p password<br>$ oc get pods -n jenkins-operator-test<br>NAME                                READY   STATUS    RESTARTS   AGE<br>jenkins-example                     1/1     Running   0          6m18s<br>jenkins-operator-5d7bf9c657-8g96b   1/1     Running   0          16m</pre><h4>Configuring additional necessary resources</h4><p>Considering that the Jenkins instance is up and running let’s set it up to work with the right configuration necessary to run with Openshift.</p><ul><li>Add ClusterRole edit to the ServiceAccount used by the Jenkins instance created by the Operator.</li></ul><pre>$ oc adm policy add-cluster-role-to-user edit -z jenkins-operator-example -n jenkins-operator-test</pre><ul><li>Expose the Service pointing to the Jenkins instance to be used as a Route so we can access the Jenkins instance from outside the Cluster Network.</li></ul><blockquote>Get the service which points to the Jenkins instance</blockquote><pre>$ oc get svc | grep jenkins-operator-http</pre><pre>jenkins-operator-http-example    ClusterIP   172.30.54.123    &lt;none&gt;        8080/TCP            11m</pre><blockquote>Expose the Http Service pointing to the Jenkins instance via a Route</blockquote><pre>$ oc expose svc jenkins-operator-http-example</pre><blockquote>Update the Route to use TLS Edge Temination and set the HA Proxy timout</blockquote><pre># TLS Edge Termination<br>$  oc patch route jenkins-operator-http-example -p &#39;{&quot;spec&quot;:{&quot;tls&quot;:{&quot;insecureEdgeTerminationPolicy&quot;:&quot;Redirect&quot;,&quot;termination&quot;:&quot;edge&quot;}}}&#39;</pre><pre># HA Proxy Timeout<br>$  oc annotate route jenkins-operator-http-example &quot;haproxy.router.openshift.io/timeout&quot;=&quot;4m&quot;</pre><ul><li>Configure Jenkins instance ServiceAccount to be used for the Redirection.</li></ul><pre>$ oc annotate sa jenkins-operator-example &quot;serviceaccounts.openshift.io/oauth-redirectreference.jenkins&quot;=&quot;{\&quot;kind\&quot;:\&quot;OAuthRedirectReference\&quot;,\&quot;apiVersion\&quot;:\&quot;v1\&quot;,\&quot;reference\&quot;:{\&quot;kind\&quot;:\&quot;Route\&quot;,\&quot;name\&quot;:\&quot;jenkins-operator-http-example\&quot;}}&quot;</pre><p>With the above you should be able to have a Jenkins working that will comply with Openshift Builds with which the jobs can be triggered as well.</p><h4>Triggering Jenkins Jobs using the Openshift Builds</h4><p>Simple example to create a BuildConfig with a Jenkinsfile Strategy would be to have a git repo with a Jenkinsfile at the root of the repo as it is given here</p><pre>$ oc new-app <a href="https://github.com/waveywaves/nodejs-ex">https://github.com/waveywaves/nodejs-ex</a> --context-dir openshift/pipelines</pre><p>Upon doing the above, a BuildConfig would be created based on the Jenkinsfile strategy.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/963/1*iJGDKDvULNCiToL6wJEK0w.png" /><figcaption>List of BuildConfigs in the namespace as seen in the Openshift Console</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/967/1*L1t46GZdzpsCllQXu28VFw.png" /><figcaption>List of Builds in the namespace as seen in the Openshift Console</figcaption></figure><p>Above we can see the BuildConfig nodejs-ex has been created by the oc new-app command given above and the Build nodejs-ex-1 has also succeeded which is an instance of the same. This Build is responsible for deploying a NodeJS application including the creation of the BuildConfig, Deployment, Services and Route of the same which are prefixed with nodejs-example in their names.</p><p>Let’s check the Build from Jenkins itself and see what exactly happened. We have the Route from before from when we exposed the Service which we are going to use to access the the Jenkins.</p><pre>$ oc get route | grep jenkins-operator-http</pre><p>After going to the Route and logging in via our Openshift Credentials, we should be able to see the Jenkins User Interface. Click on the folder with the name of the Namespace.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DSNnIisONlUj-gVcuQhz-w.png" /><figcaption>Folder with all Jobs in the particular namespace</figcaption></figure><p>You should now be able to see the Jenkins Job that resembles the <em>&lt;namespace&gt;/&lt;build-config&gt;</em> name pattern pointing to our BuildConfig.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zz-0hX8Lc7lZcfJ8i5fBsA.png" /><figcaption>Jenkins Job resembling the BuildConfig</figcaption></figure><p>Once you click on the same you can see the Build and the different stages it has gone through. Click on the Build and then click on the Console Output option given in the left column of the screen.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/911/1*mVsZWryEMYxwr2qoQiAYBQ.png" /><figcaption>Builds/Runs for the Jenkins Job</figcaption></figure><p>After doing that you can see the output of your Job Run and in times of failure you can check here, if the Build succeeded or not.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/941/1*KOjdgiBUK8QrfG2jbTq4AQ.png" /><figcaption>Start of the Build Log</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/935/1*4a3gzMXM-uT3rd4pAEpE4w.png" /><figcaption>End of the Build Log</figcaption></figure><h3>Conclusion</h3><p>As of now the Operator provides basic functionality and few extra features like creation of SeedJobs and Backing Up Jenkins instances etc. But wouldn’t be considered production ready for Openshift.</p><p>The current state of support for the Operator in Openshift is Developer Preview only and is not completely supported yet. A lot of the features and improvements are still Work In Progress. We will keep updating the progress on this and let the world know the story of the Jenkins Operator ;)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e11d7c5c2625" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>