<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: José Castillo Lema</title>
    <description>The latest articles on DEV Community by José Castillo Lema (@josecastillolema).</description>
    <link>https://dev.to/josecastillolema</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F843800%2F0120592b-fb49-47dd-8462-36dd04b93d0f.png</url>
      <title>DEV Community: José Castillo Lema</title>
      <link>https://dev.to/josecastillolema</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/josecastillolema"/>
    <language>en</language>
    <item>
      <title>Development workflows on inmutable distros: rootless setup</title>
      <dc:creator>José Castillo Lema</dc:creator>
      <pubDate>Sat, 21 Oct 2023 05:00:00 +0000</pubDate>
      <link>https://dev.to/josecastillolema/development-workflows-on-inmutable-distros-rootless-setup-2f1e</link>
      <guid>https://dev.to/josecastillolema/development-workflows-on-inmutable-distros-rootless-setup-2f1e</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Continuation of &lt;a href="https://samsai.eu/"&gt;Samsai&lt;/a&gt; notes on &lt;a href="https://samsai.eu/post/toolbox-based-emacs-flatpak-workflow/"&gt;Toolbox-based Emacs Flatpak workflow&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have been using inmutable OS distributions for a while (Fedora Silverblue and Sericea, see my &lt;a href="https://josecastillolema.github.io/dotfiles/"&gt;dotfiles&lt;/a&gt;). They have the following characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;System root (baseOS) is mostly immutable&lt;/li&gt;
&lt;li&gt;System software installation/updates are handled as images and applied on reboot&lt;/li&gt;
&lt;li&gt;For installing desktop applications, &lt;a href="https://flatpak.org/"&gt;Flatpak&lt;/a&gt; is the recommended default route&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://containertoolbx.org/"&gt;Toolbx&lt;/a&gt; can be used to set up containerized Linux environments for developer tools, these containers will mount your home directory and certain important files for GUI programs to work as well&lt;/li&gt;
&lt;li&gt;Local user (rootless) installations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I personally follow these guidelines when installing new applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If it is a desktop application, prefer Flatpak (and some terminal ones too, i.e.: &lt;a href="https://flathub.org/apps/io.neovim.nvim"&gt;Neovim&lt;/a&gt; and &lt;a href="https://flathub.org/apps/org.gnu.emacs"&gt;Emacs&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;For terminal applications, consider Toolbx or local installations&lt;/li&gt;
&lt;li&gt;Do not install desktop applications into Toolbx&lt;/li&gt;
&lt;li&gt;Avoid duplication (i.e.: installing the same editors or development environments in several places)&lt;/li&gt;
&lt;li&gt;Try to avoid &lt;code&gt;rpm-ostree&lt;/code&gt; layering on baseOS as much as possible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The development workflow story on inmutable distros hasn’t really been standardized yet, as these distros are quite new. Let’s take a look at several approaches and &lt;strong&gt;finally discuss the local (rootless) installation method&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layering with rpm-ostree (not a good idea)
&lt;/h2&gt;

&lt;p&gt;You can also install development tools directly on the inmutable distros install using package layering with &lt;code&gt;rpm-ostree&lt;/code&gt;. So, if you want to, you can install your editor, compilers, build tools and linters straight on the Silverblue install.&lt;/p&gt;

&lt;p&gt;However, this isn’t really how most people view you should use Silverblue. The application installation process is a bit more annoying, although experimental support for installing software without rebooting does exist nowadays. It also makes your system install kind of messy due to large numbers of overlayed packages.&lt;/p&gt;

&lt;p&gt;I wouldn’t take this route because while you aren’t strictly speaking losing all of the benefits of inmutable distros, you are making life quite difficult for yourself compared to just using regular Fedora Workstation for instance. You also don’t get the benefits of separating your system from your application environments and expose yourself to more potential breakages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Toolbx approaches
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Single toolbx container for all dev activities
&lt;/h3&gt;

&lt;p&gt;The easiest way to have everything working in a predictable and simple manner is to create a single Toolbox container, which has all of the development tools for every single project installed within it. This means that the container contains your text editor of choice, compilers, linters, build tools and all of their dependencies.&lt;/p&gt;

&lt;p&gt;The benefit of this approach is that it is extremely close to how you’d work on any other Linux distribution.&lt;/p&gt;

&lt;p&gt;This approach has several drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All software pilled into one environment&lt;/li&gt;
&lt;li&gt;Keeping the text editor inside the Toolbox still results in somewhat poor integration with the host system&lt;/li&gt;
&lt;li&gt;Install desktop applications into toolbx containers instead of Flatpak applications&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A toolbx container per language / project
&lt;/h3&gt;

&lt;p&gt;Another (better IMO) possibility is to separately set up a Toolbox container for each project you work on. This means that all of your project environments are fully separated from each other and all of them only carry tools and dependencies relevant to the project in question.&lt;/p&gt;

&lt;p&gt;Loss of a Toolbox container limits the damage to a particular project and per-project Toolboxes are fairly simple to recreate.&lt;/p&gt;

&lt;p&gt;Drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Certain parts of your development workflow need to be duplicated. You potentially need to install your text editor and all of its required dependencies and tools in each environment.&lt;/li&gt;
&lt;li&gt;Keeping the text editor inside the Toolbox still results in somewhat poor integration with the host system.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Flatpak approach
&lt;/h2&gt;

&lt;p&gt;You can install Flatpak SDKs such as the Rust build tools like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ flatpak install org.freedesktop.Sdk.Extension.rust-stable

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then load them into a Flatpak editor using an SDK extension flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ FLATPAK_ENABLE_SDK_EXT=rust-stable flatpak run com.visualstudio.code

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or just load every SDK available in your local setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ FLATPAK_ENABLE_SDK_EXT=* flatpak run com.visualstudio.code

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This causes the tools and libraries from that SDK to be made visible to the Flatpak application. There are Flatpak SDKs for a few languages like Java, Rust, Haskell, PHP and Node, but obviously support for all use-cases does not exist. But if you only plan to develop in languages that already have an SDK ready or are willing to learn how to package more SDKs, then this approach is definitely viable for things like Neovim, Emacs and VSCode Flatpaks.&lt;/p&gt;

&lt;p&gt;Drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some languages do not have an SDK available&lt;/li&gt;
&lt;li&gt;Limited to the language runtime versions available in the SDKs&lt;/li&gt;
&lt;li&gt;Duplication of the language runtime (plus you will need to install all the library dependencies on the Flatpak to have proper code support from your editor)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Combined approach
&lt;/h2&gt;

&lt;p&gt;You can also mix approaches such that part of the development activity happens outside Toolbox and part of it inside the Toolbox. The simplest case would be installing your text editor via Flatpak for example and then connecting from that text editor to a Toolbox for project-specific tools like compilers.&lt;/p&gt;

&lt;p&gt;The benefit here is that you can install tools where they make most sense and where they integrate the best. So, you will get your nice app launchers and the ability to keep project environments separate.&lt;/p&gt;

&lt;p&gt;Tools available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For VSCode 

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers"&gt;Dev Containers extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/owtaylor/toolbox-vscode"&gt;toolbox-vscode&lt;/a&gt;: a script that configures the current toolbox container to work with the Remote Containers Visual Studio Code extension&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;For Emacs 

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/fejfighter/toolbox-tramp"&gt;toolbox-tramp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;For Neovim 

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;nvim --remote&lt;/code&gt; ?&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jamestthompson3/nvim-remote-containers"&gt;nvim-remote-containers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  User (rootless) installations
&lt;/h2&gt;

&lt;p&gt;I have not seen much information about this method anywhere and for me as of today it is the prefered approach. Flatpak applications (i.e.: editors) cannot access the root filesystem (i.e.: the preinstalled python package on &lt;code&gt;/usr/bin/python&lt;/code&gt;). However they have full access to the home directory (same as Toolbx containers).&lt;/p&gt;

&lt;p&gt;So installing the development runtimes and tools locally (and then configuring your Flatpak editor to use them) provides an excelent out of the box developer experience without the need of Flatpak SDKs nor plugins to enable your editor to access the Toolbx containers.&lt;/p&gt;

&lt;p&gt;Drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It can be more time consuming to set up than normal &lt;code&gt;rpm&lt;/code&gt; installs in some scenarios&lt;/li&gt;
&lt;li&gt;No automatic updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s take a look at local installs for several platforms.&lt;/p&gt;

&lt;h3&gt;
  
  
  OCaml
&lt;/h3&gt;

&lt;p&gt;We will leverage the &lt;a href="https://opam.ocaml.org/"&gt;OCaml Package Manager (opam)&lt;/a&gt; to install the platform (or several versions) and local switches to each project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl https://github.com/ocaml/opam/releases/download/2.1.5/opam-2.1.5-i686-linux -Lo ~/bin/opam &amp;amp;&amp;amp; chmod +x ~/bin/opam

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From a toolbx container with proper development tools, i.e.: &lt;a href="https://github.com/josecastillolema/toolbox-images/blob/main/fedora-toolbox-38/Containerfile"&gt;this one&lt;/a&gt; incialize the opam environment and install the &lt;a href="https://ocaml.org/docs/platform"&gt;platform tools&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⬢ $ opam init
⬢ $ opam install dune ocaml-lsp-server odoc ocamlformat utop

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optionally, install some extras for Emacs, Vim and Neovim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⬢ $ opam install ocp-indent ocp-index merlin tuareg

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to add the opam path (&lt;code&gt;~/bin&lt;/code&gt;) to our editor of choice (i.e.: VSCode) path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo flatpak override --env=PATH='/app/bin:/usr/bin:/home/$USER/bin:/home/$USER/.opam/default/bin' com.visualstudio.code

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, open the project in VSCode and choose the corresponding opam switch.&lt;/p&gt;

&lt;h4&gt;
  
  
  Using local switches
&lt;/h4&gt;

&lt;p&gt;It is possible to define a switch within the source of a project to be used specifically in that project. If a &lt;strong&gt;local switch&lt;/strong&gt; is detected in the current directory or a parent, opam will select it automatically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⬢ $ opam switch create .

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, open the project in VSCode and choose the corresponding recommended opam switch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Golang
&lt;/h3&gt;

&lt;p&gt;Download latest version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdr ~/go
$ curl https://go.dev/dl/go1.21.3.linux-amd64.tar.gz -Lo ~/go.tar.gz
$ tar xf ~/go/go.tar.gz
$ mv ~/go/go ~/go/go-1.21.3

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following environment variables to your environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export GOROOT=$HOME/go/go-1.21.3
export GOPATH=$HOME/go
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ go version
go version go1.21.3 linux/amd64

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, open VSCode (it should automatically detect the local Golang installation), install the &lt;a href="https://marketplace.visualstudio.com/items?itemName=golang.Go"&gt;Go VSCode extension&lt;/a&gt; and click on &lt;code&gt;⚠ Analysis Tools Missing&lt;/code&gt; to install those.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9Ff1iGA4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://josecastillolema.github.io/assets/images/posts/2023-10-21-dev-inmutable-distros/go.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9Ff1iGA4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://josecastillolema.github.io/assets/images/posts/2023-10-21-dev-inmutable-distros/go.png" alt="" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Local install
&lt;/h4&gt;

&lt;p&gt;Install both &lt;code&gt;python&lt;/code&gt; and &lt;code&gt;pip&lt;/code&gt; in the local user environment.&lt;/p&gt;

&lt;p&gt;From a toolbx container with proper development tools, i.e.: &lt;a href="https://github.com/josecastillolema/toolbox-images/blob/main/fedora-toolbox-38/Containerfile"&gt;this one&lt;/a&gt; download and compile Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⬢ $ wget https://www.python.org/ftp/python/3.12.0/Python-3.12.0.tgz
⬢ $ tar -xf Python-3.?.?.tar.xz
⬢ $ cd Python-3.?.?.tar.xz
⬢ $ ./configure --prefix=$HOME
⬢ $ make install
⬢ $ ln -s ~/bin/python3 ~/bin/python
⬢ $ pip install readline

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can just pip install any dependencies, open the project in VSCode and choose the corresponding Python environment &lt;code&gt;~/bin/python&lt;/code&gt;. I do not tend to pip install the requirements of the projects thought (only the indispensable ones, like i.e.: ansible), instead prefer the virtual environments approach that will be described next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q6cyokFV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://josecastillolema.github.io/assets/images/posts/2023-10-21-dev-inmutable-distros/python.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q6cyokFV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://josecastillolema.github.io/assets/images/posts/2023-10-21-dev-inmutable-distros/python.png" alt="" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Using python virtual environments
&lt;/h4&gt;

&lt;p&gt;Before opening the project in VSCode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ flatpak run --command=sh com.visualstudio.code
[📦] python -m venv .
[📦] source bin/activate
()[📦] pip install -r requirements.txt

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open the project in VSCode and choose the local virtual environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ansible
&lt;/h3&gt;

&lt;p&gt;Python local install is a pre-requisite.&lt;/p&gt;

&lt;p&gt;Local ansible installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python -m pip install --user ansible ansible-lint

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ansible will be installed on ~/.local/bin, so we need to add this path to our editor of choice (i.e.: VSCode):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ which ansible
~/.local/bin/ansible
$ sudo flatpak override --env=PATH='/app/bin:/usr/bin:/home/$USER/.local/bin' com.visualstudio.code

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Installed the Ansible extension by Red Hat in VSCode and &lt;a href="https://developers.redhat.com/articles/2023/08/22/enhance-ansible-development-experience-lightspeed"&gt;enabled Lightspeed&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When opening VSCode it should automatically detect the local Ansible installation.&lt;/p&gt;

</description>
      <category>en</category>
      <category>redhat</category>
    </item>
    <item>
      <title>Kubemark on OpenShift</title>
      <dc:creator>José Castillo Lema</dc:creator>
      <pubDate>Tue, 19 Sep 2023 05:00:00 +0000</pubDate>
      <link>https://dev.to/josecastillolema/kubemark-on-openshift-1j7h</link>
      <guid>https://dev.to/josecastillolema/kubemark-on-openshift-1j7h</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/kubernetes/kubernetes/tree/master/cmd/kubemark"&gt;Kubemark&lt;/a&gt; is a performance testing tool which allows users to run experiments on simulated clusters, by creating “hollow” Kubernetes nodes. What this means is that the nodes do not actually run containers or attach storage, but they do behave like they did, with updates to etcd and all the trimmings. At the same time, &lt;strong&gt;hollow nodes are extremely light (&amp;lt;30 MiB)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The primary use case of Kubemark is scalability testing, as simulated clusters can be much bigger than the real ones. The objective is to expose problems with the master components (API server, controller manager or scheduler) that appear only on bigger clusters (e.g. small memory leaks).&lt;/p&gt;

&lt;h2&gt;
  
  
  Hands to work
&lt;/h2&gt;

&lt;p&gt;We won’t be using the &lt;a href="https://github.com/kubernetes-sigs/cluster-api-provider-kubemark/"&gt;Cluster API Kubemark Provider&lt;/a&gt; for this demo, and instead we will be using directly Kubemark itself.&lt;/p&gt;

&lt;p&gt;Let’s assume we have a &lt;strong&gt;working OpenShift cluster&lt;/strong&gt; available. We will be leveraging a &lt;a href="https://developers.redhat.com/products/openshift-local/overview"&gt;Red Hat OpenShift Local instance&lt;/a&gt; (formerly Red Hat CodeReady Containers) for this demo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯ oc version
Client Version: 4.13.6
Kustomize Version: v4.5.7
Server Version: 4.13.6
Kubernetes Version: v1.26.6+73ac561

❯ oc get node
NAME STATUS ROLES AGE VERSION
crc-2zx29-master-0 Ready control-plane,master,worker 54d v1.26.6+73ac561

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s create a new &lt;strong&gt;project&lt;/strong&gt; , &lt;strong&gt;secret&lt;/strong&gt; and corresponding &lt;strong&gt;permissions&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯ oc new-project kubemark
Now using project "kubemark" on server "https://api.crc.testing:6443".

❯ oc create secret generic kubeconfig --from-file=kubeconfig=$KUBECONFIG
secret/kubeconfig created

❯ oc adm policy add-scc-to-user privileged -z default
clusterrole.rbac.authorization.k8s.io/system:openshift:scc:privileged added: "default"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s create the &lt;strong&gt;Kubemark pod&lt;/strong&gt; (which in turn will automatically instantiate a new node):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;❯ cat &amp;lt;&amp;lt;EOF | oc apply -f -&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hollow-node&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kubemark-node&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kubemark&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--v=3&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--morph=kubelet&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--name=kubemark-node&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--extended-resources=cpu=1,memory=4G&lt;/span&gt;
      &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/kubemark&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;quay.io/cluster-api-provider-kubemark/kubemark:v1.26.7&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hollow-node&lt;/span&gt;
      &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;privileged&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/kubeconfig&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kubeconfig&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/run/containerd/containerd.sock&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;containerd-sock&lt;/span&gt;
  &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kubeconfig&lt;/span&gt;
      &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;defaultMode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;420&lt;/span&gt;
        &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kubeconfig&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;hostPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/run/crio/crio.sock&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Socket&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;containerd-sock&lt;/span&gt;
&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;span class="s"&gt;pod/kubemark-node created&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s check the if new node was properly registered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯ oc get po
NAME READY STATUS RESTARTS AGE
kubemark-node 1/1 Running 0 5s

❯ oc get node
NAME STATUS ROLES AGE VERSION
crc-2zx29-master-0 Ready control-plane,master,worker 54d v1.26.6+73ac561
kubemark-node Ready &amp;lt;none&amp;gt; 4s v1.26.7

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cluster should be healthy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯ oc get co
NAME VERSION AVAILABLE PROGRESSING DEGRADED SINCE MESSAGE
authentication 4.13.6 True False False 12d
cluster-api 4.13.6 True False False 13d
config-operator 4.13.6 True False False 54d
console 4.13.6 True False False 12d
control-plane-machine-set 4.13.6 True False False 54d
dns 4.13.6 True False False 12d
etcd 4.13.6 True False False 54d
image-registry 4.13.6 True False False 12d
ingress 4.13.6 True False False 54d
kube-apiserver 4.13.6 True False False 54d
kube-controller-manager 4.13.6 True False False 54d
kube-scheduler 4.13.6 True False False 54d
kube-storage-version-migrator 4.13.6 True False False 12d
machine-api 4.13.6 True False False 54d
machine-approver 4.13.6 True False False 54d
machine-config 4.13.6 True False False 54d
marketplace 4.13.6 True False False 54d
network 4.13.6 True False False 54d
openshift-apiserver 4.13.6 True False False 12d
openshift-controller-manager 4.13.6 True False False 12d
openshift-samples 4.13.6 True False False 54d
operator-lifecycle-manager 4.13.6 True False False 54d
operator-lifecycle-manager-catalog 4.13.6 True False False 54d
operator-lifecycle-manager-packageserver 4.13.6 True False False 119m
platform-operators-aggregated 4.13.6 True False False 119m
service-ca 4.13.6 True False False 54d

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there should a few pods already “running” in the new hollow node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯ oc get pods -A --field-selector spec.nodeName=kubemark-node
NAMESPACE NAME READY STATUS RESTARTS AGE
hostpath-provisioner csi-hostpathplugin-8p9j5 4/4 Running 0 17m
openshift-dns dns-default-lt7g8 2/2 Running 0 17m
openshift-dns node-resolver-9plz7 1/1 Running 0 17m
openshift-image-registry node-ca-x7hq7 1/1 Running 0 17m
openshift-ingress-canary ingress-canary-l2mlx 1/1 Running 0 17m
openshift-machine-config-operator machine-config-daemon-smq5z 2/2 Running 0 17m
openshift-multus multus-7xp8p 1/1 Running 0 17m
openshift-multus multus-additional-cni-plugins-rv6j7 0/1 Init:0/6 0 17m
openshift-multus network-metrics-daemon-zh2vz 2/2 Running 0 17m
openshift-network-diagnostics network-check-target-l85xq 1/1 Running 0 17m
openshift-sdn sdn-rv9mb 2/2 Running 0 17m

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s try to create some pods on the new hollow node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯ oc run test --image nginx --overrides='{"spec": { "nodeSelector": {"kubernetes.io/hostname": "kubemark-node"}}}'
pod/test created

❯ oc get po -o wide test
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test 1/1 Running 0 36s 192.168.192.168 kubemark-node &amp;lt;none&amp;gt; &amp;lt;none&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, bear in mind that in order to create new hollow nodes you will have to change two fields in the pod definition:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The pod name: &lt;code&gt;metadata.name&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The name of the hollow node: &lt;code&gt;spec.containers.args.--name&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>en</category>
      <category>networks</category>
      <category>openshift</category>
      <category>redhat</category>
    </item>
    <item>
      <title>DevConf.CZ 2023 - Writing a K8s Operator for Knative Functions</title>
      <dc:creator>José Castillo Lema</dc:creator>
      <pubDate>Tue, 23 May 2023 05:00:00 +0000</pubDate>
      <link>https://dev.to/josecastillolema/devconfcz-2023-writing-a-k8s-operator-for-knative-functions-4cb8</link>
      <guid>https://dev.to/josecastillolema/devconfcz-2023-writing-a-k8s-operator-for-knative-functions-4cb8</guid>
      <description>&lt;p&gt;&lt;a href="https://www.devconf.info/cz/"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Iss1qrkR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://josecastillolema.github.io/assets/images/posts/2023-05-23-devconf23/1.png" alt="" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.devconf.info/cz/"&gt;DevConf.CZ&lt;/a&gt; is an annual, free, Red Hat sponsored community conference for developers, admins, DevOps engineers, testers, documentation writers and other contributors to open source technologies. At DevConf.CZ, FLOSS communities sync, share, and hack on upstream projects together.&lt;/p&gt;

&lt;p&gt;DevConf.cz Mini is a bi-annual, highly focused, local, in-person version of DevConf.cz. It offers an opportunity to return to our conference themes in a smaller setting and establishes a platform for the Czech Republic and EMEA based community to sync, share and hack on upstream projects together.&lt;/p&gt;

&lt;p&gt;There is no admission or ticket charge for DevConf.CZ events. However, you are required to complete a free registration. Watch this site for updates about registration.&lt;/p&gt;

&lt;p&gt;We are committed to fostering an open and welcoming environment at our conference. We set expectations for inclusive behavior through our code of conduct and media policies, and are prepared to enforce these.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://devconfcz2023.sched.com/"&gt;Schedule&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://devconfcz2023.sched.com/event/1MYpJ/writing-a-k8s-operator-for-knative-functions"&gt;&lt;strong&gt;Writing a K8s Operator for Knative Functions&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://research.redhat.com/blog/2023/06/09/red-hat-research-engineers-will-lead-the-workshop-on-k8s-operator-for-faas-at-devconf-cz-2023/"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nv2tte9D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://josecastillolema.github.io/assets/images/posts/2023-05-23-devconf23/2.png" alt="" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Serverless and Function as a Service (FaaS) are getting more and more attention from customers and developers as a way to develop, run and manage applications functionality without the burden of infrastructure related knowledge. All big cloud providers offer them already, e.g., AWS Lambda, Google Cloud Functions or Microsoft Azure Functions. One of the most relevant upstream projects for serverless is Knative, which recently added support for functions (create, build, and deploy) on top of K8s clusters.&lt;/p&gt;

&lt;p&gt;This workshop will introduce you to the the &lt;a href="https://dev.to/physics"&gt;PHYSICS European project&lt;/a&gt; and its FaaS model, as well as to building Kubernetes operators. You will implement a K8s Operator, using the operatorsdk framework, to provide the functionality of the Knative CLI. This will allow easier creation, build and deployment of functions with Knative just by creating Kubernetes (CR) objects, and will help you learn the internals about how K8s Operators work in a real life example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Friday June 16, 2023 • 2:15pm - 3:35pm CEST&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tw4NCs15--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://josecastillolema.github.io/assets/images/posts/2023-05-23-devconf23/3.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tw4NCs15--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://josecastillolema.github.io/assets/images/posts/2023-05-23-devconf23/3.jpeg" alt="" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Speakers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://devconfcz2023.sched.com/speaker/ltomasbo"&gt;Luis Tomas Bolivar&lt;/a&gt; - Software Engineer at &lt;strong&gt;Red Hat&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devconfcz2023.sched.com/speaker/jlema"&gt;Jose Castillo Lema&lt;/a&gt; - Software Engineer at &lt;strong&gt;Red Hat&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devconfcz2023.sched.com/event/1MYpJ/writing-a-k8s-operator-for-knative-functions"&gt;DevConf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://research.redhat.com/blog/2023/06/09/red-hat-research-engineers-will-lead-the-workshop-on-k8s-operator-for-faas-at-devconf-cz-2023/"&gt;Red Hat Research (RHR) blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://physics-faas.eu/event/future-tech-and-open-research-hackathon/"&gt;Physics blog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Workshop
&lt;/h2&gt;

&lt;h1&gt;
  
  
  physics-devconf
&lt;/h1&gt;

&lt;p&gt;This repository provides an easy way to deploy a &lt;a href="https://kind.sigs.k8s.io/"&gt;KinD&lt;/a&gt; cluster with &lt;a href="https://knative.dev/"&gt;Knative&lt;/a&gt; (using &lt;a href="https://github.com/knative/func/blob/main/hack/allocate.sh"&gt;this script&lt;/a&gt;) on top of a Fedora 37 VM.&lt;/p&gt;

&lt;p&gt;It also provides a couple of sample scripts to deploy a Knative service and a function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
physics-devconf

&lt;ul&gt;
&lt;li&gt;Index&lt;/li&gt;
&lt;li&gt;Goals&lt;/li&gt;
&lt;li&gt;Deploy the environment (VM)&lt;/li&gt;
&lt;li&gt;Access the environment&lt;/li&gt;
&lt;li&gt;Create a new (python) function and invoke it&lt;/li&gt;
&lt;li&gt;Fork the base operator github repository and deploy locally&lt;/li&gt;
&lt;li&gt;Solution&lt;/li&gt;
&lt;li&gt;Links&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Goals
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Get familiar on how to create/test Knative functions&lt;/li&gt;
&lt;li&gt;Get familiar with the operator SDK&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deploy the environment (VM)
&lt;/h2&gt;

&lt;p&gt;The VM requires 4 vCPUs and 6GB of memory. It takes approximately 10 minutes to come up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ vagrant up
Bringing machine 'default' up with 'libvirt' provider...
==&amp;gt; default: Checking if box 'fedora/37-cloud-base' version '37.20221105.0' is up to date...
==&amp;gt; default: Creating image (snapshot of base box volume).
==&amp;gt; default: Creating domain with the following settings...
...
    default: configmap/config-br-defaults configured
    default: ⑦ Dapr
    default: ./allocate.sh: line 251: dapr: command not found
    default: popd
    default: ~/go/src/github.com/knative/func
    default:
    default: cat &amp;lt;&amp;lt;EOF | sudo tee /etc/docker/daemon.json
    default: {"insecure-registries": ["localhost:50000"]}
    default: EOF
    default: {"insecure-registries": ["localhost:50000"]}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The provision script installs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Golang&lt;/li&gt;
&lt;li&gt;Pip&lt;/li&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;li&gt;Curl&lt;/li&gt;
&lt;li&gt;Wget&lt;/li&gt;
&lt;li&gt;Cosign&lt;/li&gt;
&lt;li&gt;Kubectl&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://knative.dev/docs/client/install-kn/"&gt;Kn&lt;/a&gt; - the Knative client&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://knative.dev/docs/functions/install-func/"&gt;Func&lt;/a&gt; - Knative functions&lt;/li&gt;
&lt;li&gt;Kind&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sdk.operatorframework.io/docs/installation/"&gt;Operator-sdk&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Access the environment
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Login into the virtual machine just created:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; $ vagrant ssh

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Check if all the pods are running:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; $ kubectl get pods -A
 NAMESPACE NAME READY STATUS RESTARTS AGE
 contour-external contour-56cfd44877-gmzdd 1/1 Running 0 2m30s
 contour-external contour-56cfd44877-wj844 1/1 Running 0 2m30s
 contour-external contour-certgen-v1.22.0-qbbx6 0/1 Completed 0 2m30s
 contour-external envoy-4j2vr 2/2 Running 0 2m30s
 contour-internal contour-865fdc98f9-48vv9 1/1 Running 0 2m29s
 contour-internal contour-865fdc98f9-l22kw 1/1 Running 0 2m29s
 contour-internal contour-certgen-v1.22.0-5t52p 0/1 Completed 0 2m30s
 contour-internal envoy-vlxrb 2/2 Running 0 2m29s
 knative-eventing eventing-controller-64b4b79c45-bxk6f 1/1 Running 0 4m5s
 knative-eventing eventing-webhook-86f7dd95db-phc9x 1/1 Running 0 4m5s
 knative-eventing imc-controller-769d8b7f66-hx2lj 1/1 Running 0 3m33s
 knative-eventing imc-dispatcher-55979cf74b-8n2w9 1/1 Running 0 3m33s
 knative-eventing mt-broker-controller-f97f8747-r7nnr 1/1 Running 0 3m21s
 knative-eventing mt-broker-filter-77c75d69fb-j4972 1/1 Running 0 3m21s
 knative-eventing mt-broker-ingress-d96f6d8b5-g4ng6 1/1 Running 0 3m21s
 knative-serving activator-75777fd57c-hwsth 1/1 Running 0 4m49s
 knative-serving autoscaler-57d647d6ff-cs2bx 1/1 Running 0 4m49s
 knative-serving controller-677995dc7b-9tbmj 1/1 Running 0 4m48s
 knative-serving domain-mapping-5676fb7bcf-92xmf 1/1 Running 0 4m48s
 knative-serving domainmapping-webhook-fcbd7dff4-5v26r 1/1 Running 0 4m48s
 knative-serving net-contour-controller-847758c4bf-kltdx 1/1 Running 0 2m
 knative-serving webhook-544b958c69-h7vmz 1/1 Running 0 4m48s
 kube-system coredns-6d4b75cb6d-btqsp 1/1 Running 0 5m16s
 kube-system coredns-6d4b75cb6d-shbkf 1/1 Running 0 5m16s
 kube-system etcd-func-control-plane 1/1 Running 0 5m35s
 kube-system kindnet-mr2xx 1/1 Running 0 5m16s
 kube-system kube-apiserver-func-control-plane 1/1 Running 0 5m30s
 kube-system kube-controller-manager-func-control-plane 1/1 Running 0 5m30s
 kube-system kube-proxy-vpb8z 1/1 Running 0 5m16s
 kube-system kube-scheduler-func-control-plane 1/1 Running 0 5m32s
 local-path-storage local-path-provisioner-6b84c5c67f-575j5 1/1 Running 0 5m16s
 metallb-system controller-6c58495cbb-j52ls 1/1 Running 0 3m3s
 metallb-system speaker-v5hd2 1/1 Running 0 3m3s

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Check if the local registry is running:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; $ docker ps
 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
 59be051ba43c registry:2 "/entrypoint.sh /etc…" 2 minutes ago Up 2 minutes 127.0.0.1:50000-&amp;gt;5000/tcp func-registry
 caf78811a6a9 kindest/node:v1.24.6 "/usr/local/bin/entr…" 4 minutes ago Up 4 minutes 127.0.0.1:39609-&amp;gt;6443/tcp, 127.0.0.1:80-&amp;gt;30080/tcp, 127.0.0.1:443-&amp;gt;30443/tcp func-control-plane

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create a new (python) function and invoke it
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create the Knative function:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; $ func create -l python test-hw
 Created python function in /home/vagrant/test-hw

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Take a look around and change the &lt;code&gt;func.py&lt;/code&gt; code as follows:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; $ cd test-hw

 $ ls
 app.sh func.py func.yaml Procfile README.md requirements.txt test_func.py

 $ cat func.py


 from parliament import Context
 from flask import Request
 import json

 # parse request body, json data or URL query parameters
 def payload_print(req: Request) -&amp;gt; str:
     if req.method == "GET":
         return "DevConf.cz 2023!"

 def main(context: Context):
     """
     Function template
     The context parameter contains the Flask request object and any
     CloudEvent received with the request.
     """

     # Add your business logic here
     print("Received request")

     if 'request' in context.keys():
         return payload_print(context.request), 200
     else:
         print("Empty request", flush=True)
         return "{}", 200

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Build (and push) the function to the internal registry:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; $ export FUNC_REGISTRY=localhost:50000/kn-user
 $ func build --push
 🙌 Function image built: localhost:50000/kn-user/test-hw:latest
 🕕 Pushing function image to the registry "localhost:50000" using the "" user credentials

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Check that the image has been correctly pushed into the internal registry:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; $ curl localhost:50000/v2/_catalog
 {"repositories":["kn-user/test-hw"]}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Deploy the function to the kind cluster:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; $ func deploy --build=false --push=false
 ✅ Function deployed in namespace "default" and exposed at URL:
      http://test-hw.default.127.0.0.1.sslip.io

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Check that the function has been correctly deployed. A new &lt;strong&gt;Knative service (ksvc)&lt;/strong&gt; object is created, which triggers the Knative controllers to create the other k8s objects (deployment and route). After approximately one minute minute the deployment is scaled down to 0 replicas if not used to spare resources:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; $ kubectl get ksvc
 NAME URL LATESTCREATED LATESTREADY READY REASON
 test-hw http://test-hw.default.127.0.0.1.sslip.io test-hw-00001 test-hw-00001 True

 $ kubectl get deploy
 NAME READY UP-TO-DATE AVAILABLE AGE
 test-hw-00001-deployment 0/0 0 0 104s

 $ kubectl get route
 NAME URL READY REASON
 test-hw http://test-hw.default.127.0.0.1.sslip.io True

 $ kubectl get pods
 (empty if more than a minute has passed)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Invoke the function:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl http://test-hw.default.127.0.0.1.sslip.io
DevConf.cz 2023!

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Check that the deployment has been scaled up:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
test-hw-00001-deployment 1/1 1 1 3s

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fork the base operator github repository and deploy locally
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Fork &lt;a href="https://github.com/luis5tb/devconf-knative-operator"&gt;this github repository&lt;/a&gt; into your github account: &lt;code&gt;https://github.com/luis5tb/devconf-knative-operator&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Clone your fork locally inside the VM (change &lt;strong&gt;YOUR_USER&lt;/strong&gt; by yours):&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git clone https://github.com/YOUR_USER/devconf-knative-operator.git

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In case you want to start an operator from scratch do the next instead (change &lt;strong&gt;YOUR_USER&lt;/strong&gt; by yours):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir devconf-knative-operator
$ cd devconf-knative-operator

# Create base operator
$ operator-sdk init --domain example.com --repo github.com/YOUR_USER/devconf-knative-operator

# Add API
$ operator-sdk create api --group knf --version v1alpha1 --kind KnativeFunction --resource --controller

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;There are three important files to consider: 

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;controllers/knativefunction_controller.go&lt;/strong&gt; : implements the operator reconcile loop&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;api/v1alpha1/knativefunction_types.go&lt;/strong&gt; : the KnativeFunction CRD definition&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;config/samples/knf_v1alpha1_knativefunction.yaml&lt;/strong&gt; : an example KnativeFunction CRD&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Let’s take a look at &lt;strong&gt;api/v1alpha1/knativefunction_types.go&lt;/strong&gt; , as you can see it defines an example &lt;code&gt;Foo&lt;/code&gt; field:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
type KnativeFunctionSpec struct {
    // Foo is an example field of KnativeFunction. Edit knativefunction_types.go to remove/update
    Foo string `json:"foo,omitempty"`
}
...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Let’s modify the operator reconcyle loop in &lt;strong&gt;controllers/knativefunction_controller.go&lt;/strong&gt; :&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Test your code by deploying it. You will need two terminals, &lt;strong&gt;T1&lt;/strong&gt; and &lt;strong&gt;T2&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;[&lt;strong&gt;T2&lt;/strong&gt;] In a &lt;strong&gt;second terminal&lt;/strong&gt; create a sample CRD:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cat &amp;lt;&amp;lt;EOF | kubectl apply -f -
---
apiVersion: knf.example.com/v1alpha1
kind: KnativeFunction
metadata:
labels:
    app.kubernetes.io/name: knativefunction
    app.kubernetes.io/instance: knativefunction-sample
    app.kubernetes.io/part-of: devconf-knative-operator
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/created-by: devconf-knative-operator
name: knativefunction-sample
spec:
   foo: test
EOF

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;[&lt;strong&gt;T1&lt;/strong&gt;] In the &lt;strong&gt;first terminal&lt;/strong&gt; you should see something like:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2023-06-16T08:12:54Z    INFO    Received a request to create a new knativefunction  {"controller": "knativefunction", "controllerGroup": "knf.example.com", "controllerKind": "KnativeFunction", "KnativeFunction": {"name":"knativefunction-sample","namespace":"default"}, "namespace": "default", "name": "knativefunction-sample", "reconcileID": "9be34733-bca6-4134-bf6d-8f0ed69106bd", "Foo =": "test"}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;[&lt;strong&gt;Challenge&lt;/strong&gt;] The goal now is to extend the operator to deploy the existing Knative function (from step 6). Once this is accomplished, extend the operator to build, push and deploy any function located on a given github repository.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Deploy a CR to force the controller to reconcile and get the function deployed. First you need to edit the &lt;code&gt;config/samples/knf_v1alpha1_knativefunction.yaml&lt;/code&gt; with the desired options:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To check the operator did its job, beside seeing the &lt;code&gt;make install run&lt;/code&gt; logs, you can check as before:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://knative.dev/docs/"&gt;Knative documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pkg.go.dev/knative.dev/client"&gt;Knative.dev/client Golang API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/operator-framework/operator-sdk/tree/master/testdata/go/v3/memcached-operator"&gt;Example memcached operator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sdk.operatorframework.io/docs/building-operators/golang/tutorial/"&gt;Operator SDK - Go Operator tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://courses.course-dev.skills.network/courses/course-v1:IBMSkillsNetwork+CO0201EN+2021T1/course/"&gt;Intermediate Kubernetes Operators on IBM Developer Skills Network&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>en</category>
      <category>events</category>
      <category>openshift</category>
      <category>redhat</category>
    </item>
  </channel>
</rss>
