ansible-role-k3s installs K3s as a server or a cluster
Ansible role for installing k3s as either a standalone server or HA cluster.
At a glance
- What is it?
- The PyratLabs Ansible role installs K3s on Linux hosts, either as a single standalone server or as a clustered control plane with agents, configuring it through the K3s configuration file rather than command line arguments. It is BSD-3-Clause licensed, tested against a dozen distributions, and its author is looking for a new maintainer.
- Who is it for?
- ansible-role-k3s suits a team that installs K3s from a control machine with Ansible already in place, since the role handles the standalone and clustered cases through the same variables and writes K3s configuration the way current K3s expects it. It is the wrong tool if you want a Kubernetes distribution you can install without Ansible, and it is the wrong tool if you need K3s older than v1.19, because the v3 releases of the role dropped support for that.
- Can I use it commercially?
- Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 159 days ago.
- What is it written in?
- Mainly Jinja, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the role does and who maintains it
ansible-role-k3s is an Ansible role for installing K3S, described in the README as Lightweight Kubernetes, as either a standalone server or cluster. The primary language of the repository is recorded as Jinja, which is what you would expect for a role whose work is largely templating.
The role is versioned separately from K3s itself, and the current line is v3.x, matching the README title. The release tags are v3.6.2 from 2025-11-16, v3.6.1 from 2025-09-27 and v3.6.0 from 2025-09-21.
There is a section at the top of the README headed Help Wanted, and it is worth reading because it bears on how you should treat the project. The author, xanmanning, is looking for a new maintainer to work on this Ansible role, because of a lack of free time and because Ansible is no longer part of their day job. That is an honest statement rather than a red flag, but it does mean the maintenance burden is currently on one person who has said they are stepping back.
The last push to the repository was on 2026-05-17 and the repository is not archived. So the code is not frozen, but the release cadence has already slowed: the most recent tag is from November 2025, roughly six months before that last commit.
For a role that installs a Kubernetes distribution, that matters more than it would for a library, because the thing being installed moves underneath it. The CHANGELOG.md and the releases page are linked from the README for exactly this reason, and the README asks you to consult the CHANGELOG before upgrading for notifications of breaking changes.
Configuration through config.yaml, not a populated systemd unit
The most consequential design decision in the role is stated in the Role Variables section, and it is a change of mechanism rather than of interface.
Since K3s v1.19.1+k3s1 you can configure K3s using a configuration file rather than environment variables or command line arguments, and the v2 release of this role moved to the configuration file method rather than populating a systemd unit file with command-line arguments. There may be exceptions defined in the Global/Cluster Variables, but you will mostly be configuring K3s by configuration files using the k3s_server and k3s_agent variables.
That is a better shape, because a populated systemd unit is hard to review and hard to diff, while a YAML file can be templated, checked and kept in version control. The role's own structure follows the same logic, with a defaults/ directory, a templates/ directory, tasks/, handlers/, vars/, meta/ and a documentation/ directory.
There is also a variable that lets you add your own files into that configuration. k3s_server_config_yaml_d_files is a flat list of templates to supplement the k3s_server configuration, and there is a matching k3s_agent_config_yaml_d_files for the agent side. Both default to an empty list. This is the extension point most teams will use, and it is worth knowing it exists before you try to express something in a variable that was not designed for it.
The default path for the configuration file itself is k3s_config_file, set to /etc/rancher/k3s/config.yaml, and the install directory is /usr/local/bin.
The variables that decide the topology
The global and cluster variables are described as being set against all of the play hosts for environment consistency, and they are generally cluster-level configuration. Several of them change what the role actually does rather than how it configures K3s.
The first is k3s_state, whose values are installed, started, stopped, downloaded, uninstalled and validated, with installed as the default. That single variable gives the role a lifecycle interface, which is what makes it usable in a larger playbook where the cluster comes up in stages.
The second is k3s_build_cluster, defaulting to true, which is described as: when multiple play hosts are available, attempt to cluster. So the same role installs a single node or joins a cluster depending on how many hosts are in the play, and the flag is there when you need to force one or the other.
The third group is about the cluster datastore and the features you are willing to run. k3s_etcd_datastore enables the embedded etcd datastore and defaults to false, which is the classic K3s decision: the default is a SQLite-backed single server store, and a highly available control plane needs etcd. k3s_use_experimental allows experimental features in K3s, and k3s_use_unsupported_config allows unsupported configurations, both defaulting to false. The defaults are conservative, which is the right posture for a role that runs on machines you will not be watching.
Then there is the airgap switch. k3s_airgap is a boolean to enable air-gapped installations, defaulting to false, and it works together with k3s_github_url, the GitHub URL to install K3s from, defaulting to https://github.com/k3s-io/k3s, and k3s_api_url, the URL for the K3s updates API, defaulting to https://update.k3s.io. In an air-gapped environment you point those at your own mirror, and the role can install a specific release with k3s_release_version, where specifying false means stable.
Manifests, pod manifests and the rest of the surface
Four variables handle the add-ons that usually turn into a pile of ad hoc commands, and they come in pairs: one for URLs and one for templates, for both server manifests and static pod manifests.
k3s_server_manifests_urls is a list of URLs to deploy on the primary control plane, with a matching k3s_server_manifests_templates for templates, and k3s_server_pod_manifests_urls is a list of URLs for installing static pod manifests on the control plane, with k3s_server_pod_manifests_templates for templates. All four default to empty lists, and the server manifest variables carry a read notes below pointer in the table.
The split between URLs and templates is the useful part. A URL is fetched at deploy time, which is how you consume an upstream chart or a released manifest, and a template is rendered on the control machine and written out, which is how you deploy something that is specific to your environment. Having both means you are not forced to choose between pinning a version and templating values.
Note that the server side has these and the agent side does not, which matches how K3s itself works: the server is where the add-ons and the static pods live, and the agent is a worker that joins.
The remaining variables cover smaller decisions. k3s_registration_address is a fixed registration address for nodes, as an IP or an FQDN, and it defaults to NULL, which is how a cluster forms: the first server creates the registration secret and the others join against it. k3s_install_hard_links installs using hard links rather than symbolic links, defaulting to false. k3s_debug enables debug logging on the K3s service. And k3s_registries holds the registries configuration file content, defaulting to a structure with empty mirrors and configs.
Requirements, tested distributions and the k3s version floor
The requirements section is short and worth reading in full, because one of the entries is easy to miss.
The host you run Ansible from requires Python 3.6.0 or later, ansible 2.9.16 or later or ansible-base 2.10.4 or later, and netaddr 1.3.0 or later, which is required for dual-stack IP address handling. The dependencies can be installed from the requirements.txt file in the repository:
pip3 install -r requirements.txtThat file pins ansible>=11.7.0 and netaddr>=1.3.0. Note the gap between the README's stated floor of ansible 2.9.16 and what requirements.txt asks for, which is a modern Ansible.
The dual-stack note is the reason netaddr is a hard dependency rather than an optional one. A role that supports both IPv4 and IPv6 addressing has to parse and manipulate address families in the control code, and netaddr is the library that does that cleanly. If you have a role dependency conflict on netaddr, this is why.
The tested distribution list is longer than most role READMEs give: Alpine Linux, Archlinux, CentOS 8, Debian 11, Debian 12, Fedora 41, Fedora 42, openSUSE Leap 15, RockyLinux 9, RockyLinux 10, Ubuntu 22.04 LTS and Ubuntu 24.04 LTS. That spread tells you the role is not tied to one package manager's way of installing K3s.
The version floor is stated as a warning. The v3 releases of this role only support k3s >= v1.19, and for k3s < v1.19 you should consider updating or use the v1.x releases of the role. So the role lines and the K3s versions are coupled, and you have to check which pairing you are on before an upgrade.
Testing, tooling and what the repository contains
The repository has the shape of a role that is worked on properly rather than a script that got published once.
There is a molecule/ directory, which is the usual home for Ansible role testing with Molecule, and a CI workflow badge in the README pointing at the GitHub Actions CI runs on push. There is an .ansible-lint configuration, a .yamllint configuration, a .mise.toml for tool version management, a .devcontainer/ directory for a development container, a CONTRIBUTING.md, and a CHANGELOG.md.
The templates/ directory holds the templated files, defaults/ holds the default variable values, tasks/ the task files, handlers/ the handlers, vars/ the internal variables, meta/ the role metadata, and documentation/ the generated or hand-written role documentation. There is also a vars/ entry point and a separate documentation/ directory, which is where you would look for the per-variable reference beyond the README's tables.
The licence is BSD-3-Clause, and the LICENSE.txt file is at the repository root, which is a permissive licence with no obligations on the organisations using the role beyond attribution.
The topics list the role with ansible, ansible-role, k3s, k3s-cluster, k8s, k8s-cluster, kubernetes, kubernetes-cluster, playbook and standalone-server. That last one is worth noticing, because the standalone-server tag is a signal that the single node case is a first class use and not just a degenerate cluster.
Editorial conclusion
ansible-role-k3s suits a team that installs K3s from a control machine with Ansible already in place, since the role handles the standalone and clustered cases through the same variables and writes K3s configuration the way current K3s expects it. It is the wrong tool if you want a Kubernetes distribution you can install without Ansible, and it is the wrong tool if you need K3s older than v1.19, because the v3 releases of the role dropped support for that. Before adopting it, read the CHANGELOG for breaking changes, decide whether you need the embedded etcd datastore rather than the default, and note that the role's author is asking for a new maintainer, so upstream responsiveness is a factor in your own maintenance plan.
Frequently asked questions
How do I install the ansible-role-k3s dependencies?
The host running Ansible needs Python 3.6.0 or later, ansible 2.9.16 or later or ansible-base 2.10.4 or later, and netaddr 1.3.0 or later for dual-stack IP address handling. The README says to install them with pip3 install -r requirements.txt, and the requirements file pins ansible>=11.7.0 and netaddr>=1.3.0.
Does ansible-role-k3s install a single server or a cluster?
Both, from the same role. The k3s_build_cluster variable defaults to true and is described as: when multiple play hosts are available, attempt to cluster, so the role joins hosts into a cluster when the play contains more than one host.
How does the role configure K3s?
Through a configuration file rather than command line arguments. Since K3s v1.19.1+k3s1 the role writes the K3s configuration file, by default at /etc/rancher/k3s/config.yaml, using the k3s_server and k3s_agent variables, and the v2 release moved away from populating a systemd unit file with command line arguments.
Which K3s versions does the v3 line of the role support?
The README warns that the v3 releases of the role only support k3s >= v1.19, and that for k3s < v1.19 you should update or use the v1.x releases of the role. The CHANGELOG is where breaking changes between role versions are notified.
Is the embedded etcd datastore enabled by default?
No. The k3s_etcd_datastore variable enables the embedded etcd datastore and defaults to false, so the default installation uses the standard K3s single-server store. The role also exposes k3s_use_experimental and k3s_use_unsupported_config, both defaulting to false.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/pyratlabs-ansible-role-k3s)Was this useful?