Developer Relations (DevRel) must be a strategic business priority to any organization with a sizeable contingent of developers. As organizations scale, ensuring software developers are aligned with business objectives is critical. Yet explicit functions intended to span the boundaries between leadership and development teams either don’t exist or lack standardization.
Internal DevRel is, relative to its external cousin, a rarer species, poorly defined. Without clear positioning, the function is often left to the mercy of changing business priorities, when what it really needs is a clear definition of its business value.
The value of a strategic DevRel function
Large organizations naturally face challenges in scale and alignment, such as:
Business units disconnected from developer roadmaps, sometimes unintentionally impeding innovation.
A loss of developer trust in organizational priorities.
Software policies produced without developer input, leading to direct loss of productivity, workarounds, and quiet non-compliance from developers who just want to get work done.
A well-positioned DevRel function directly addresses these systemic issues by rebuilding broken trust lines between leadership and developers, baking 2-way input loops into policies that affect developer ways of working, and functioning as liasons between business units.
To remain strategically valuable, DevRel must also stop engaging in low-impact activities. A well-rounded DevRel team is a high-leverage function, and its resources should be directed toward initiatives that maximize business and developer outcomes.
What internal DevRel is not
DevRel is not developer marketing or community management
Marketing and community engagement are best handled by dedicated teams. While DevRel may contribute to developer engagement strategies, it does so from the perspective of advocacy, not promotion.
DevRel is not Developer Experience (DevEx)
GitLab defines a developer advocate as “a liaison between developers and the DevEx team, gathering feedback and advocating for developer needs.” While this definition is partially correct, it is too narrow. DevRel is not just a bridge to DevEx—it represents the interests of developers across the entire organization.
Developer advocates in the enterprise have a broader organizational remit. They maintain deep knowledge of both business strategy and developer pain points, making them the ideal translation layer between leadership and developers. Their role extends beyond tooling and workflows, influencing cultural, procedural, and policy-level decisions that impact the entire developer ecosystem.
DevRel from first principles
The word “advocate” originates from the Latin advocatus, meaning “to call to one’s aid.” In Middle English, it evolved to mean “one who intercedes for another” or “protector, champion, patron.” This is the foundation of our industry standard. DevRel exists to serve and protect developers, ensuring their needs are represented at all levels of the organization.
DevRel has a monopoly on developer trust
Developer trust is the foundational element of DevRel. If DevRel breaks this trust—such as by becoming a one-way conduit for top-down messaging that disregards developer interests—it ceases to be valuable. Effective DevRel operates bidirectionally, gathering insights from developers and ensuring leadership decisions are informed by ground-level realities. When developers are included in decision-making, organizations benefit from policies that align with technical realities and minimize disruption to productivity.
The value of DevRel (at length)
A holistic DevRel practice
A well-functioning DevRel practice recognizes that developer productivity is shaped by more than just tooling. Developers operate within sociotechnicalSociotechnical systems and boundary spanning roles were introduced to me by Dr. Jabe Bloom, a genius in organization theory. You should drop everything you’re doing to watch his talk, Whole Work: Sociotechnicity and DevOps and then come back to this article after. systems—interdependent networks of people, technology, and organizational structures.
A strategic DevRel function considers:
The cultural and organizational factors affecting developer effectiveness.
The policies and processes that impact how developers work.
The psychological and cognitive aspects of developer experience.
An effective internal DevRel function looks for root causes of dysfunction at the level of the entire system and applies treatment. Such a function can only be effective if empowered by the very top of any given enterprise, because of its systems-level actions.
An example: a new acquisition involving a hundred-plus developers naive to the organization necessitates cultural and technical onboarding. Do the new developers feel psychologically safe enough to contribute to a codebase? Do they have the developer tools required to contribute? How do they gain access to cloud resources? What best practices must they know before contributing?
All of these questions are best solved by a function both technically proficient and organizationally savvy. That’s DevRel.
DevRel as boundary spanners
“Boundary spanners facilitate the sharing of expertise by linking two or more groups of people separated by hierarchy, location, or function.“—Tamara Keszey
DevRel acts as a critical boundary-spanning function within an organization. Consider security and compliance. When new software policies are created by parts of an organization without developer input, those policies can freeze developer productivity in place and shatter trust.
Boundary spanners do the messy work of bridging two worlds, often speaking two different languages. In the example of software policy, these teams often do not possess their own developers and may make assumptions about impact and architecture unmoored from technical consequence. DevRel, external or internal, has always done this sort of bridging, and is uniquely suited to this diplomatic task.
DevRel is “user 0”, and the ideal go-between to facilitate collaboration between security teams and developers. A DevRel function might run a limited test of new software policies internally and provide feedback or run empathy sessions with other developers.
Translation layer between leadership and developers
A core function of internal DevRel is translating between developers and leadership. Developer advocates are in touch with more developers, more often than anyone in your business. The fact they know more about how each developer team is contributing to your business outcomes than anyone else makes them the ideal translation layer between leadership and developers.
If enterprise leaders are put in charge of initiatives with the power to make sweeping impact to how developers deliver software, DevRel is an essential consultant to those leaders.
Conclusion
Internal DevRel is a strategic function that, when positioned effectively, can bridge the gap between developers and business leadership. Organizations that invest in DevRel as a core function—rather than an auxiliary role, or worse an enterprise mirror of external DevRel activities—harvest developer trust, create and sustain high-performing and empowered delivery teams, and align business priorities to technical realities.
This inaugural blogpost of Goose and Quill is intended as a storehouse of my own learning on PodmanPodman was developed by Daniel Walsh and his team at Red Hat in 2017. Walsh writes in Podman in Action, 2023, of his aim to, “create a tool that ran the same containerized applications in the same manner but with more security and requiring fewer privileges.”, especially centered in its operation on Guix System, a futuristic flavor of Linux with user freedom at its heart. It should be of use to you. By the time you’ve reached the end you will have set up Podman rootlessly, created a local Kubernetes cluster using Podman Desktop and deployed a simple web service to the cluster without any assumed knowledge of the internals of Kubernetes.
Why Podman?
Podman is enormously useful. Rejected by many as a Docker clone, Podman possesses a toolset broader than its cousin.Fun fact: Guix System, like Podman, began as a reaction. Guix is a portmanteau of “Guile” and “Nix”.
Podman is a portmanteau for “POD MANager“. The unit of abstraction Podman operates on is the pod, a collection of software containers that work together to perform their function. In Docker, the fundamental unit is the container. Because Podman works at the level of the pod, just like its bigger cousin, Kubernetes, it’s able to serve as an ad-hoc container orchestrator.
This level of shared abstraction enables powerful workflows that start at the level of a container specification, the Containerfile or Dockerfile, and end with a generated manifest that runs on any enterprise Kubernetes cluster. You could use just Podman and your favorite programming language and be well-equipped to deploy (almost) everywhere, anywhere.
Why rootless?
Running containers rootlessly is both practically powerful and secure. It’s practically powerful because of the way containers achieve file and network separation from their host, using namespaces, a Linux kernel feature. When a namespace is created without elevated privileges, the user’s user ID (UID) and group ID (GUID) are mapped inside the container. Any files shared across this boundary maintain consistent permissions. The result is an entire class of annoying container problems that just don’t apply—Docker Compose veterans understand the pain of setting the right UID and GID when using bind mounts.
If you’re sharing a workstation with others (more commonly, a server), users can run their own rootless containers isolated from others’. Podman has even introduced “Podmansh” in Podman 4.6, which extends this to its logical conclusion: every user logs in to their own rootless container.
Rootless containers are also secure from container escapes and file mount mishaps that allow a determined attacker to mount your entire drive and toast it.
How-to set up Podman for rootless mode on Guix System
Because Docker, by default, runs root, it can do anything it wants, which makes its perceived ease of use very high. Rootless Podman is going to take some vim and vigor. After installing Podman with guix install podman, there’s just two pre-requisites to bootstrap Podman and they’re copy-paste jobs.
Reserve user and group IDs for Podman to map into a namespace
User namespaces isolate security-related identifiers and attributes, in particular, user IDs and group IDs, the root directory, keys, and capabilities. A process’s user and group IDs can be different inside and outside a user namespace. In particular, a process can have a normal unprivileged user ID outside a user namespace while at the same time having a user ID of 0 inside the namespace; in other words, the process has full privileges for operations inside the user namespace, but is unprivileged for operations outside the namespace.
We “trick” our containers into believing they have all the privileges of a rootful environment by assigning a range of user and group IDs our rootless container will map inside their boundary. In the code sample below, which you’ll need to copy into your own Guix System configuration (here system.scm), we map 65,536 subuidsSubuids or subordinate UIDs authorize a user to delegate user IDs into child namespaces. to our user. Rootless containers will map, from host to container: 100000 to 1, 100001 to 2, and so on. 1000 to 0 is a special default mapping we don’t need to define.
Change the username string, “worldofgeese” to your own user.
One more nicety before we write, build and run our first image: setting a fast storage driver. Podman on Guix uses vfs by default and you should absolutely not subject yourself to it because it is dog slow. You can check for yourself if you’re using vfs with podman info | grep graphDriverName, which should return graphDriverName: vfs. I won’t go into virtual filesystems here.Docker has a good intro to storage drivers as well as a page on each if you’re curious.overlayfs has been in the kernel since 5.11 so that’s what we’ll be using here. Below where you put your container image trust policy add the following:
Activate your changes to system.scm. I keep mine in ~/.config/guix/system.scm so I activate a new Guix generationA Guix generation is a collection of symbolic links that points to a specific Guix configuration in time. This gives Guix its power to roll back non-destructively to previous sytem versions without fuss. Try that with your Windows system! with my changes by invoking sudo -E guix system reconfigure ~/.config/guix/system.scm.
If you’ve used Podman before, you’ll need to run {podman system reset} after to enable your new storage driver. Check again with podman info | grep graphDriverName. It should now read graphDriverName: overlay.
If Guile isn’t already installed, install it with guix install guile. In the example above where we’ve saved the code to my-hello-http.scm, you can run it directly with guile my-hello-http.scm, open a web browser and visit http://localhost:8080 where you’ll see, printed, “Hello, World!”.
This code isn’t yet portable: it’s still a script that requires a user to know to install Guile first, download the code and run it in a file ending in .scm. And it won’t run in Podman, which expects a container, not a script. In the next section, we’ll write a self-contained Guix package definition that generates a container image using Guix. This is a break from what you may be used to, which is using Podman or Docker to build an image from a Containerfile or Dockerfile.
Create a container image with Guix and run it with Podman
To package our “Hello, World!“ example, we’re going to need to write more Guile. This time, in Guix’s own extension language to Guile.Teaching Guix’s Guile syntax is out of scope of this post. For an intro, visit the Guix website for a three-part tutorial. It’s Guile-ception!
The following code package definition puts the HTTP server code we ran earlier into a function generate-server-code, then uses Guix’s special “G-expressions”G-expressions use special notation (#~, #$) to evaluate Guix package expressions inside the build environment. in the build step. Finally, we generate a manifest that tells Guix the contents of our package. Replace the code in my-hello-http.scm with the following:
Now we need to tell Guix where to find our package. We do that by adding the package path to the GUIX_PACKAGE_PATH environment variable. On your command line, enter export GUIX_PACKAGE_PATH=$GUIX_PACKAGE_PATH:~/path/to/package. As an example, if my-hello-http.scm file is in the /home/worldofgeese/testing folder, I’d enter export GUIX_PACKAGE_PATH=$GUIX_PACKAGE_PATH:~/testing.
To test that Guix can find your package, run guix show my-hello-http, which should print:
name: my-hello-http
version: 0.1
outputs:
+ out: everything
systems: x86_64-linux i686-linux
dependencies: guile@3.0.9
location: my-hello-http.scm:10:2
homepage: http://example.com
license: GPL 3+
synopsis: My Hello HTTP server
description: This package contains a simple HTTP server.
Now, from /home/$USER enter guix pack -f docker -m testing/my-hello-http.scm.
Voilà! A container image is produced in the Guix store. We can load this image directly into Podman like so:
> podman load < /gnu/store/235f92alcfr7hfjbs8a0snnnrxz3ill1-my-hello-http-docker-pack.tar.gz
WARN[0000] "/" is not a shared mount, this could cause issues or missing mounts with rootless containers
Getting image source signatures
Copying blob 304960ad3eb5 done
Copying config b1a55ba007 done
Writing manifest to image destination
Storing signatures
Loaded image: localhost/my-hello-http:latest
Then run it with podman run localhost/my-hello-http.