Compare commits

...

No commits in common. "docs" and "main" have entirely different histories.
docs ... main

36 changed files with 1015 additions and 312 deletions

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
# ---> Ansible
*.retry
plugins
library
# ---> Python
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

7
.markdownlint.yml Normal file
View File

@ -0,0 +1,7 @@
---
default: True
MD013: False
MD041: False
MD024: False
MD004:
style: dash

1
.prettierignore Normal file
View File

@ -0,0 +1 @@
LICENSE

47
.woodpecker/docs.yaml Normal file
View File

@ -0,0 +1,47 @@
---
when:
- event: [pull_request]
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
steps:
- name: generate
image: quay.io/thegeeklab/ansible-doctor
environment:
ANSIBLE_DOCTOR_EXCLUDE_FILES: "['molecule/']"
ANSIBLE_DOCTOR_RENDERER__FORCE_OVERWRITE: "true"
ANSIBLE_DOCTOR_LOGGING__LEVEL: info
ANSIBLE_DOCTOR_ROLE__NAME: ${CI_REPO_NAME}
ANSIBLE_DOCTOR_TEMPLATE__NAME: readme
- name: format
image: quay.io/thegeeklab/alpine-tools
commands:
- prettier -w README.md
- name: diff
image: quay.io/thegeeklab/alpine-tools
commands:
- git diff --color=always README.md
- name: publish
image: quay.io/thegeeklab/wp-git-action
settings:
action:
- commit
- push
author_email: ci-bot@rknet.org
author_name: ci-bot
branch: main
message: "[skip ci] automated docs update"
netrc_machine: gitea.rknet.org
netrc_password:
from_secret: gitea_token
when:
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
depends_on:
- test

30
.woodpecker/lint.yaml Normal file
View File

@ -0,0 +1,30 @@
---
when:
- event: [pull_request, tag]
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
steps:
- name: ansible-lint
image: quay.io/thegeeklab/ansible-dev-tools:1
commands:
- ansible-lint
environment:
FORCE_COLOR: "1"
- name: python-format
image: docker.io/python:3.12
commands:
- pip install -qq ruff
- ruff format --check --diff .
environment:
PY_COLORS: "1"
- name: python-lint
image: docker.io/python:3.12
commands:
- pip install -qq ruff
- ruff check .
environment:
PY_COLORS: "1"

26
.woodpecker/notify.yml Normal file
View File

@ -0,0 +1,26 @@
---
when:
- event: [tag]
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
runs_on: [success, failure]
steps:
- name: matrix
image: quay.io/thegeeklab/wp-matrix
settings:
homeserver:
from_secret: matrix_homeserver
room_id:
from_secret: matrix_room_id
user_id:
from_secret: matrix_user_id
access_token:
from_secret: matrix_access_token
when:
- status: [failure]
depends_on:
- docs

25
.woodpecker/test.yaml Normal file
View File

@ -0,0 +1,25 @@
---
when:
- event: [pull_request, tag]
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
variables:
- &molecule_image quay.io/thegeeklab/ansible-dev-tools:1
- &molecule_base
depends_on: []
environment:
PY_COLORS: "1"
HCLOUD_TOKEN:
from_secret: molecule_hcloud_token
steps:
- name: molecule-default
image: *molecule_image
<<: *molecule_base
commands:
- molecule test -s default
depends_on:
- lint

20
.yamllint Normal file
View File

@ -0,0 +1,20 @@
---
extends: default
rules:
truthy:
allowed-values: ["True", "False"]
comments:
min-spaces-from-content: 1
comments-indentation: False
line-length: disable
braces:
min-spaces-inside: 0
max-spaces-inside: 1
brackets:
min-spaces-inside: 0
max-spaces-inside: 0
indentation: enable
octal-values:
forbid-implicit-octal: True
forbid-explicit-octal: True

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Robert Kaussow <mail@thegeeklab.de>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,18 +1,16 @@
---
title: k3s
type: docs
---
# xoxys.k3s
[![Source Code](https://img.shields.io/badge/gitea-source%20code-blue?logo=gitea&logoColor=white)](https://gitea.rknet.org/ansible/xoxys.k3s)
[![Build Status](https://img.shields.io/drone/build/ansible/xoxys.k3s?logo=drone&server=https%3A%2F%2Fdrone.rknet.org)](https://drone.rknet.org/ansible/xoxys.k3s)
[![Build Status](https://ci.rknet.org/api/badges/ansible/xoxys.k3s/status.svg)](https://ci.rknet.org/repos/ansible/xoxys.k3s)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?label=license)](https://gitea.rknet.org/ansible/xoxys.k3s/src/branch/main/LICENSE)
Setup K3s cluster nodes.
<!--more-->
## Table of content
- [Requirements](#requirements)
- [Default Variables](#default-variables)
- [k3s_flannel_external_ip](#k3s_flannel_external_ip)
- [k3s_flannel_ipv6_masq_enabled](#k3s_flannel_ipv6_masq_enabled)
- [k3s_init_log_enabled](#k3s_init_log_enabled)
- [k3s_iscsi_enabled](#k3s_iscsi_enabled)
- [k3s_node_ip](#k3s_node_ip)
@ -46,17 +44,34 @@ Setup K3s cluster nodes.
- [k3s_server_workload_enabled](#k3s_server_workload_enabled)
- [k3s_token](#k3s_token)
- [k3s_version](#k3s_version)
- [Discovered Tags](#discovered-tags)
- [Dependencies](#dependencies)
- [License](#license)
- [Author](#author)
---
## Requirements
- Minimum Ansible version: `2.1`
- Minimum Ansible version: `2.10`
## Default Variables
### k3s_flannel_external_ip
#### Default value
```YAML
k3s_flannel_external_ip: _unset_
```
### k3s_flannel_ipv6_masq_enabled
#### Default value
```YAML
k3s_flannel_ipv6_masq_enabled: false
```
### k3s_init_log_enabled
#### Default value
@ -78,7 +93,8 @@ k3s_iscsi_enabled: false
#### Default value
```YAML
k3s_node_ip: '{{ ansible_default_ipv4.address }}'
k3s_node_ip:
- '{{ ansible_default_ipv4.address }}'
```
### k3s_node_labels
@ -202,7 +218,8 @@ k3s_server_cloud_controller_enabled: true
#### Default value
```YAML
k3s_server_cluster_cidr: 10.42.0.0/16
k3s_server_cluster_cidr:
- 10.42.0.0/16
```
### k3s_server_cluster_dns
@ -308,7 +325,8 @@ k3s_server_resource_patches: []
#### Default value
```YAML
k3s_server_service_cidr: 10.43.0.0/16
k3s_server_service_cidr:
- 10.43.0.0/16
```
### k3s_server_service_node_port_range
@ -340,15 +358,17 @@ k3s_token: secure-token
#### Default value
```YAML
k3s_version: 1.27.5+k3s1
k3s_version: 1.28.6+k3s2
```
## Discovered Tags
skip_ansible_later
: &nbsp;
## Dependencies
None.
## License
MIT
## Author
[Robert Kaussow](https://gitea.rknet.org/xoxys)

72
defaults/main.yml Normal file
View File

@ -0,0 +1,72 @@
---
k3s_version: 1.28.6+k3s2
k3s_packages:
- epel-release
- python3-kubernetes
- container-selinux
- selinux-policy-base
k3s_packages_extra: []
k3s_reset: False
k3s_token: "secure-token"
k3s_node_name: "{{ ansible_hostname }}"
k3s_node_ip:
- "{{ ansible_default_ipv4.address }}"
k3s_init_log_enabled: False
k3s_selinux_enabled: False
k3s_protect_kernel_defaults: False
k3s_server: True
k3s_server_bind_ip: "0.0.0.0"
k3s_server_cluster_domain: "cluster.local"
k3s_server_cluster_cidr:
- "10.42.0.0/16"
k3s_server_service_cidr:
- "10.43.0.0/16"
k3s_server_service_node_port_range: "30000-32767"
k3s_server_cluster_dns: "10.43.0.10"
k3s_server_nodes:
- "{{ ansible_hostname }}"
k3s_server_flannel_backend_enabled: True
k3s_flannel_ipv6_masq_enabled: False
# @var k3s_flannel_external_ip:value: $ "_unset_"
k3s_server_network_policy_enabled: True
k3s_server_cloud_controller_enabled: True
k3s_server_kube_proxy_enabled: True
k3s_server_workload_enabled: True
k3s_server_feature_gates: []
k3s_server_components_disabled:
- traefik
k3s_server_manifests_templates: []
k3s_server_manifests_urls: []
k3s_server_admission_plugins:
- NodeRestriction
- EventRateLimit
- ServiceAccount
- NamespaceLifecycle
k3s_server_admission_configuration:
- name: EventRateLimit
configuration:
kind: Configuration
apiVersion: eventratelimit.admission.k8s.io/v1alpha1
limits:
- type: Namespace
qps: 50
burst: 100
cacheSize: 2000
- type: User
qps: 10
burst: 50
k3s_server_resource_creations: []
k3s_server_resource_patches: []
k3s_node_labels: {}
k3s_iscsi_enabled: False

16
handlers/main.yml Normal file
View File

@ -0,0 +1,16 @@
---
- name: Restart K3s service
ansible.builtin.service:
name: k3s
state: restarted
daemon_reload: True
enabled: True
listen: __k3s_restart
- name: Restart iscsid service
ansible.builtin.service:
name: iscsid
state: restarted
daemon_reload: True
enabled: True
listen: __iscsid_restart

293
index.md
View File

@ -1,293 +0,0 @@
---
title: k3s
type: docs
---
[![Source Code](https://img.shields.io/badge/gitea-source%20code-blue?logo=gitea&amp;logoColor=white)](https://gitea.rknet.org/ansible/xoxys.k3s) [![Build Status](https://img.shields.io/drone/build/ansible/xoxys.k3s?logo=drone&amp;server=https%3A%2F%2Fdrone.rknet.org)](https://drone.rknet.org/ansible/xoxys.k3s) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?label=license)](https://gitea.rknet.org/ansible/xoxys.k3s/src/branch/main/LICENSE)
Setup K3s cluster nodes.
<!--more-->
- [Default Variables](#default-variables)
- [k3s_init_log_enabled](#k3s_init_log_enabled)
- [k3s_iscsi_enabled](#k3s_iscsi_enabled)
- [k3s_node_ip](#k3s_node_ip)
- [k3s_node_labels](#k3s_node_labels)
- [k3s_node_name](#k3s_node_name)
- [k3s_packages](#k3s_packages)
- [k3s_packages_extra](#k3s_packages_extra)
- [k3s_protect_kernel_defaults](#k3s_protect_kernel_defaults)
- [k3s_reset](#k3s_reset)
- [k3s_selinux_enabled](#k3s_selinux_enabled)
- [k3s_server](#k3s_server)
- [k3s_server_admission_configuration](#k3s_server_admission_configuration)
- [k3s_server_admission_plugins](#k3s_server_admission_plugins)
- [k3s_server_bind_ip](#k3s_server_bind_ip)
- [k3s_server_cloud_controller_enabled](#k3s_server_cloud_controller_enabled)
- [k3s_server_components_disabled](#k3s_server_components_disabled)
- [k3s_server_feature_gates](#k3s_server_feature_gates)
- [k3s_server_flannel_backend_enabled](#k3s_server_flannel_backend_enabled)
- [k3s_server_manifests_templates](#k3s_server_manifests_templates)
- [k3s_server_manifests_urls](#k3s_server_manifests_urls)
- [k3s_server_network_policy_enabled](#k3s_server_network_policy_enabled)
- [k3s_server_nodes](#k3s_server_nodes)
- [k3s_server_resource_creations](#k3s_server_resource_creations)
- [k3s_server_resource_patches](#k3s_server_resource_patches)
- [k3s_server_workload_enabled](#k3s_server_workload_enabled)
- [k3s_token](#k3s_token)
- [k3s_version](#k3s_version)
- [Discovered Tags](#discovered-tags)
- [Dependencies](#dependencies)
---
## Default Variables
### k3s_init_log_enabled
#### Default value
```YAML
k3s_init_log_enabled: false
```
### k3s_iscsi_enabled
#### Default value
```YAML
k3s_iscsi_enabled: false
```
### k3s_node_ip
#### Default value
```YAML
k3s_node_ip: '{{ ansible_default_ipv4.address }}'
```
### k3s_node_labels
#### Default value
```YAML
k3s_node_labels: {}
```
### k3s_node_name
#### Default value
```YAML
k3s_node_name: '{{ ansible_hostname }}'
```
### k3s_packages
#### Default value
```YAML
k3s_packages:
- epel-release
- python3-kubernetes
- container-selinux
- selinux-policy-base
```
### k3s_packages_extra
#### Default value
```YAML
k3s_packages_extra: []
```
### k3s_protect_kernel_defaults
#### Default value
```YAML
k3s_protect_kernel_defaults: false
```
### k3s_reset
#### Default value
```YAML
k3s_reset: false
```
### k3s_selinux_enabled
#### Default value
```YAML
k3s_selinux_enabled: false
```
### k3s_server
#### Default value
```YAML
k3s_server: true
```
### k3s_server_admission_configuration
#### Default value
```YAML
k3s_server_admission_configuration:
- name: EventRateLimit
configuration:
kind: Configuration
apiVersion: eventratelimit.admission.k8s.io/v1alpha1
limits:
- type: Namespace
qps: 50
burst: 100
cacheSize: 2000
- type: User
qps: 10
burst: 50
```
### k3s_server_admission_plugins
#### Default value
```YAML
k3s_server_admission_plugins:
- NodeRestriction
- EventRateLimit
- ServiceAccount
- NamespaceLifecycle
```
### k3s_server_bind_ip
#### Default value
```YAML
k3s_server_bind_ip: 0.0.0.0
```
### k3s_server_cloud_controller_enabled
#### Default value
```YAML
k3s_server_cloud_controller_enabled: true
```
### k3s_server_components_disabled
#### Default value
```YAML
k3s_server_components_disabled:
- traefik
```
### k3s_server_feature_gates
#### Default value
```YAML
k3s_server_feature_gates: []
```
### k3s_server_flannel_backend_enabled
#### Default value
```YAML
k3s_server_flannel_backend_enabled: true
```
### k3s_server_manifests_templates
#### Default value
```YAML
k3s_server_manifests_templates: []
```
### k3s_server_manifests_urls
#### Default value
```YAML
k3s_server_manifests_urls: []
```
### k3s_server_network_policy_enabled
#### Default value
```YAML
k3s_server_network_policy_enabled: true
```
### k3s_server_nodes
#### Default value
```YAML
k3s_server_nodes:
- '{{ ansible_hostname }}'
```
### k3s_server_resource_creations
#### Default value
```YAML
k3s_server_resource_creations: []
```
### k3s_server_resource_patches
#### Default value
```YAML
k3s_server_resource_patches: []
```
### k3s_server_workload_enabled
#### Default value
```YAML
k3s_server_workload_enabled: true
```
### k3s_token
#### Default value
```YAML
k3s_token: secure-token
```
### k3s_version
#### Default value
```YAML
k3s_version: 1.25.3+k3s1
```
## Discovered Tags
skip_ansible_later
: &nbsp;
## Dependencies
None.

21
meta/main.yml Normal file
View File

@ -0,0 +1,21 @@
---
galaxy_info:
# @meta author:value: [Robert Kaussow](https://gitea.rknet.org/xoxys)
author: "Robert Kaussow <mail@thegeeklab.de>"
namespace: xoxys
role_name: k3s
# @meta description: >
# [![Build Status](https://ci.rknet.org/api/badges/ansible/xoxys.k3s/status.svg)](https://ci.rknet.org/repos/ansible/xoxys.k3s)
# [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?label=license)](https://gitea.rknet.org/ansible/xoxys.k3s/src/branch/main/LICENSE)
#
# Setup K3s cluster nodes.
# @end
description: Setup K3s cluster nodes
license: MIT
min_ansible_version: "2.10"
platforms:
- name: EL
versions:
- "9"
galaxy_tags: []
dependencies: []

View File

@ -0,0 +1,57 @@
---
- name: Converge
hosts: all
vars:
kernel_custom_config:
- file: 90-kubelet
content:
- name: vm.panic_on_oom
value: 0
- name: vm.overcommit_memory
value: 1
- name: kernel.panic
value: 10
- name: kernel.panic_on_oops
value: 1
- name: kernel.keys.root_maxbytes
value: 25000000
k3s_reset: False
k3s_packages_extra:
- https://github.com/k3s-io/k3s-selinux/releases/download/v1.5.stable.1/k3s-selinux-1.5-1.el9.noarch.rpm
k3s_server_nodes:
- "rocky9-k3s"
k3s_server_flannel_backend_enabled: False
k3s_server_network_policy_enabled: False
k3s_server_cloud_controller_enabled: True
k3s_server_workload_enabled: True
k3s_server_manifests_templates:
- "calico-installation.yaml.j2"
k3s_server_manifests_urls:
- url: https://raw.githubusercontent.com/projectcalico/calico/v3.27.2/manifests/tigera-operator.yaml
dest: tigera-operator.yaml
# - url: https://github.com/hetznercloud/hcloud-cloud-controller-manager/releases/latest/download/ccm.yaml
# dest: hcloud-ccm.yaml
k3s_init_log_enabled: True
k3s_selinux_enabled: True
k3s_protect_kernel_defaults: True
# k3s_server_resource_creations:
# - kind: Secret
# name: hcloud
# definition:
# metadata:
# namespace: kube-system
# apiVersion: v1
# type: Opaque
# data:
# token: "{{ hcloud_token | b64encode }}"
k3s_node_labels:
node.kubernetes.io/exclude-from-external-load-balancers: "true"
k3s_iscsi_enabled: True
pre_tasks:
- name: Override host variables
ansible.builtin.set_fact:
k3s_node_ip:
- "{{ ansible_default_ipv4.address }}"
roles:
- role: xoxys.kernel
- role: xoxys.k3s

View File

@ -0,0 +1,17 @@
---
driver:
name: molecule_hetznercloud
dependency:
name: galaxy
options:
role-file: requirements.yml
requirements-file: requirements.yml
platforms:
- name: "rocky9-k3s"
server_type: "cx22"
image: "rocky-9"
provisioner:
name: ansible
log: False
verifier:
name: testinfra

View File

@ -0,0 +1,11 @@
---
- name: Prepare
hosts: all
gather_facts: False
tasks:
- name: Bootstrap Python for Ansible
ansible.builtin.raw: |
command -v python3 python ||
((test -e /usr/bin/apt && (apt -y update && apt install -y python-minimal)) ||
echo "Warning: Python not boostrapped due to unknown platform.")
changed_when: False

View File

@ -0,0 +1,21 @@
---
apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
name: default
spec:
calicoNetwork:
ipPools:
- blockSize: 26
cidr: "10.42.0.0/16"
encapsulation: "VXLANCrossSubnet"
natOutgoing: Enabled
nodeSelector: all()
nodeMetricsPort: 9091
typhaMetricsPort: 9093
---
apiVersion: operator.tigera.io/v1
kind: APIServer
metadata:
name: default
spec: {}

View File

@ -0,0 +1,46 @@
import json
import os
import testinfra.utils.ansible_runner
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
os.environ["MOLECULE_INVENTORY_FILE"]
).get_hosts("all")
def test_k3s_running_and_enabled(host):
k3s = host.service("k3s")
assert k3s.is_running
assert k3s.is_enabled
def test_iscsid_running_and_enabled(host):
k3s = host.service("iscsid")
assert k3s.is_running
assert k3s.is_enabled
def test_k3s_node_ready(host):
jsonpth = '{range .items[*]}{@.metadata.name}:{range @.status.conditions[?(@.type=="Ready")]}{@.type}={@.status};{end}{end}' # noqa
nodes = host.run(f"k3s kubectl get nodes -o jsonpath='{jsonpth}'").stdout
assert "rocky9-k3s:Ready=True;" in nodes
def test_k3s_node_labels(host):
jsonpth = "{.items[0].metadata.labels}" # noqa
nodes = host.run(f"k3s kubectl get nodes -o jsonpath='{jsonpth}'").stdout
assert '"node.kubernetes.io/exclude-from-external-load-balancers":"true"' in nodes
def test_k3s_cluster_ready(host):
cluster = host.run("k3s kubectl get --raw='/readyz'").stdout
assert cluster == "ok"
def test_k3s_cni(host):
cni = json.loads(host.file("/etc/cni/net.d/10-calico.conflist").content_string)
assert cni["plugins"][0]["type"] == "calico"

17
pyproject.toml Normal file
View File

@ -0,0 +1,17 @@
[tool.ruff]
exclude = [".git", "__pycache__"]
line-length = 99
indent-width = 4
[tool.ruff.lint]
ignore = ["W191", "E111", "E114", "E117", "S101", "S105"]
select = ["F", "E", "I", "W", "S"]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
line-ending = "lf"
[tool.pytest.ini_options]
filterwarnings = ["ignore::FutureWarning", "ignore::DeprecationWarning"]

9
requirements.yml Normal file
View File

@ -0,0 +1,9 @@
---
collections:
- name: ansible.posix
- name: kubernetes.core
roles:
- src: https://gitea.rknet.org/ansible/xoxys.kernel
scm: git
version: main

54
tasks/init.yml Normal file
View File

@ -0,0 +1,54 @@
---
- name: Ensure k3s-init service is stopped
ansible.builtin.service:
name: k3s-init
state: stopped
failed_when: False
- name: Clean previous runs of k3s-init
ansible.builtin.command: systemctl reset-failed k3s-init # noqa command-instead-of-module
failed_when: False
changed_when: False
- name: Init cluster inside the transient k3s-init service
ansible.builtin.command:
cmd: >-
systemd-run
-p RestartSec=2
-p Restart=on-failure
--unit=k3s-init
{{ __k3s_binary }} server {{ __k3s_server_init_args }}
creates: "{{ __k3s_service_file }}"
register: __k3s_init
- name: Wait for k3s-init to finish
when: __k3s_init.changed | bool # noqa no-handler
block:
- name: Verify that all nodes actually joined
ansible.builtin.command: >-
{{ __k3s_binary }} kubectl get nodes
-l "node-role.kubernetes.io/control-plane=true"
-o=jsonpath="{.items[*].metadata.name}"
register: __k3s_init_nodes
until: __k3s_init_nodes.rc == 0 and (__k3s_init_nodes.stdout.split() | length) == (k3s_server_nodes | length)
retries: 30
delay: 10
changed_when: False
always:
- name: Fetch k3s-init logs
ansible.builtin.command: journalctl --all --unit=k3s-init.service
changed_when: False
register: __k3s_init_log
- name: Save k3s-init logs
ansible.builtin.copy:
content: "{{ __k3s_init_log.stdout }}"
dest: "{{ __k3s_log_dir }}/k3s-init.log"
mode: "0640"
when: k3s_init_log_enabled | bool
- name: Kill the temporary service used for initialization
ansible.builtin.service:
name: k3s-init
state: stopped
failed_when: False

23
tasks/iscsi.yml Normal file
View File

@ -0,0 +1,23 @@
---
- name: Ensure iscsi is installed
ansible.builtin.package:
name: "{{ item }}"
state: present
loop:
- iscsi-initiator-utils
- name: Configure iscsi-initiator
ansible.builtin.copy:
content: "InitiatorName=$(/sbin/iscsi-iname)"
dest: /etc/iscsi/initiatorname.iscsi
owner: root
group: root
mode: "0644"
notify: __iscsid_restart
- name: Ensure iscsid service is up and running
ansible.builtin.service:
name: iscsid
daemon_reload: True
enabled: True
state: started

14
tasks/main.yml Normal file
View File

@ -0,0 +1,14 @@
---
- name: Reset k3s
ansible.builtin.include_tasks: reset.yml
when: k3s_reset | bool
- name: Prepare k3s
ansible.builtin.include_tasks: prepare.yml
- name: Initialize cluster
ansible.builtin.include_tasks: init.yml
when: k3s_server | bool
- name: Setup k3s
ansible.builtin.include_tasks: setup.yml
- name: Setup iscsi
ansible.builtin.include_tasks: iscsi.yml
when: k3s_iscsi_enabled | bool

96
tasks/prepare.yml Normal file
View File

@ -0,0 +1,96 @@
---
- name: Import Rancher public key
ansible.builtin.rpm_key:
state: present
key: https://rpm.rancher.io/public.key
- name: Ensure dependencies are installed
ansible.builtin.package:
name: "{{ item }}"
state: present
loop: "{{ k3s_packages + k3s_packages_extra }}"
- name: Check if cluster is installed
ansible.builtin.stat:
path: "{{ __k3s_config_dir }}/k3s.yaml"
register: __k3s_installed
- name: Prepare directory structure
ansible.builtin.file:
path: "{{ item }}"
owner: root
group: root
mode: "0700"
state: directory
loop:
- "{{ __k3s_config_dir }}"
- "{{ __k3s_config_dir }}/server"
- "{{ __k3s_data_dir }}"
- "{{ __k3s_manifests_dir }}"
- "{{ __k3s_log_dir }}"
- name: Download K3s binary
ansible.builtin.get_url:
url: https://github.com/k3s-io/k3s/releases/download/v{{ k3s_version }}/k3s
checksum: sha256:https://github.com/k3s-io/k3s/releases/download/v{{ k3s_version }}/sha256sum-amd64.txt
dest: /usr/local/bin/k3s
timeout: 30
owner: root
group: root
mode: "0755"
notify: __k3s_restart
- name: Copy K3s config file
ansible.builtin.template:
src: "etc/rancher/k3s/config.yaml.j2"
dest: "{{ __k3s_config_dir }}/config.yaml"
owner: root
group: root
mode: "0600"
notify: __k3s_restart
- name: Copy K3s kubelet config file
ansible.builtin.template:
src: "etc/rancher/k3s/kubelet.yaml.j2"
dest: "{{ __k3s_config_dir }}/kubelet.yaml"
owner: root
group: root
mode: "0600"
notify: __k3s_restart
- name: Copy K3s server config files
ansible.builtin.template:
src: "etc/rancher/k3s/server/{{ item }}.j2"
dest: "{{ __k3s_config_dir }}/server/{{ item }}"
owner: root
group: root
mode: "0600"
loop:
- admission-config.yaml
when: k3s_server | bool
notify: __k3s_restart
- name: Copy auto-deploying manifests to the server
ansible.builtin.template:
src: "{{ item }}"
dest: "{{ __k3s_manifests_dir }}/{{ item | basename | replace('.j2', '') }}"
mode: "0644"
loop: "{{ k3s_server_manifests_templates }}"
loop_control:
label: "{{ __k3s_manifests_dir }}/{{ item | basename | replace('.j2', '') }}"
when:
- ansible_hostname == hostvars[k3s_server_nodes[0]]['ansible_hostname']
- not __k3s_installed.stat.exists
- name: Download auto-deploying manifests to the server
ansible.builtin.get_url:
url: "{{ item.url }}"
dest: "{{ __k3s_manifests_dir }}/{{ item.dest | default(item.url | basename) }}"
timeout: 30
mode: "0644"
loop: "{{ k3s_server_manifests_urls }}"
loop_control:
label: "{{ __k3s_manifests_dir }}/{{ item.dest | default(item.url | basename) }}"
when:
- ansible_hostname == hostvars[k3s_server_nodes[0]]['ansible_hostname']
- not __k3s_installed.stat.exists

60
tasks/reset.yml Normal file
View File

@ -0,0 +1,60 @@
---
- name: Disable services
ansible.builtin.service:
name: "{{ item }}"
state: stopped
enabled: False
failed_when: False
loop:
- k3s
- k3s-init
- kubepods
- name: Kill containerd-shim-runc
register: __k3s_pkill_containerd_shim_runc
ansible.builtin.command: pkill -9 -f "k3s/data/[^/]+/bin/containerd-shim-runc"
changed_when: __k3s_pkill_containerd_shim_runc.rc == 0
failed_when: False
- name: Get the list of mounted filesystems
ansible.builtin.shell: set -o pipefail && cat /proc/mounts | awk '{ print $2}' | grep -E "^{{ item }}"
loop:
- /run/k3s
- /var/lib/kubelet
- /run/netns
- /var/lib/kubelet/pods
- /var/lib/kubelet/plugins
- /run/netns/cni-
- "{{ __k3s_data_dir }}"
register: __k3s_mounted_fs
args:
executable: /bin/bash
failed_when: False
changed_when: False
- name: Umount filesystem
ansible.posix.mount:
path: "{{ item }}"
state: unmounted
loop: "{{ __k3s_mounted_fs.results | map(attribute='stdout_lines') | list | flatten | reverse }}"
- name: Remove service files, binaries and data
ansible.builtin.file:
name: "{{ item }}"
state: absent
loop:
- /usr/local/bin/k3s
- "{{ __k3s_service_file }}"
- "{{ __k3s_config_dir }}"
- "{{ __k3s_data_dir }}"
- "{{ __k3s_log_dir }}"
- /etc/cni
- /run/k3s
- /run/flannel
- /var/lib/kubelet
- /var/lib/cni
- /var/run/netns
- name: Reload systemd daemon
ansible.builtin.service:
daemon_reload: True

92
tasks/setup.yml Normal file
View File

@ -0,0 +1,92 @@
---
- name: Copy K3s service file
ansible.builtin.template:
src: "etc/systemd/system/k3s.service.j2"
dest: "{{ __k3s_service_file }}"
owner: root
group: root
mode: "0644"
notify: __k3s_restart
- name: Force restart
ansible.builtin.meta: flush_handlers
- name: Ensure K3s service is up and running
ansible.builtin.service:
name: k3s
daemon_reload: True
enabled: True
state: started
- name: Wait for Kubernetes API
ansible.builtin.command: >-
{{ __k3s_binary }} kubectl get --raw='/readyz'
register: __k3s_api_readyz
until: __k3s_api_readyz.rc == 0 and __k3s_api_readyz.stdout == "ok"
retries: 30
delay: 10
changed_when: False
when: k3s_server | bool
- name: Set server address
ansible.builtin.command: >-
{{ __k3s_binary }} kubectl config set-cluster default
--server=https://{{ __k3s_server_ip }}:6443
--kubeconfig {{ __k3s_config_dir }}/k3s.yaml
changed_when: False
- name: Create setup resources
kubernetes.core.k8s:
kind: "{{ item.kind }}"
name: "{{ item.name }}"
kubeconfig: "{{ __k3s_config_dir }}/k3s.yaml"
state: present
definition: "{{ item.definition }}"
loop: "{{ k3s_server_resource_creations }}"
loop_control:
label: "{{ item.kind | lower }}/{{ item.name | lower }}"
when: k3s_server | bool
- name: Wait for initial setup
ansible.builtin.command: >-
{{ __k3s_binary }} kubectl get deployment coredns
-n kube-system
-o go-template={% raw %}'{{ .status.availableReplicas }}'{% endraw %}
register: __k3s_init_setup
until: __k3s_init_setup.rc == 0 and __k3s_init_setup.stdout == "1"
retries: 30
delay: 10
changed_when: False
when: k3s_server | bool
- name: Add node role label
kubernetes.core.k8s:
kind: "Node"
name: "{{ k3s_node_name }}"
kubeconfig: "{{ __k3s_config_dir }}/k3s.yaml"
state: patched
definition:
metadata:
labels: "{{ (__k3s_node_lables['control'] if k3s_server | bool else __k3s_node_lables['worker']) | combine(__k3s_node_lables['general'], k3s_node_labels) }}"
delegate_to: "{{ hostvars[k3s_server_nodes[0]]['inventory_hostname'] }}"
- name: Patch existing resources
kubernetes.core.k8s:
kind: "{{ item.kind }}"
name: "{{ item.name }}"
kubeconfig: "{{ __k3s_config_dir }}/k3s.yaml"
state: patched
definition: "{{ item.definition }}"
loop: "{{ k3s_server_resource_patches }}"
loop_control:
label: "{{ item.kind | lower }}/{{ item.name | lower }}"
when: k3s_server | bool
- name: Remove auto-deploying manifests
ansible.builtin.file:
path: "{{ __k3s_manifests_dir }}/{{ item.dest | default(item.url) | default(item) | basename | replace('.j2', '') }}"
state: absent
loop: "{{ k3s_server_manifests_urls + k3s_server_manifests_templates }}"
loop_control:
label: "{{ __k3s_manifests_dir }}/{{ item.dest | default(item.url) | default(item) | basename | replace('.j2', '') }}"
when: ansible_hostname == hostvars[k3s_server_nodes[0]]['ansible_hostname']

View File

@ -0,0 +1,14 @@
#jinja2: lstrip_blocks: True
- anonymous-auth=false
- authorization-mode=Node,RBAC
- profiling=0
- service-account-lookup=true
- request-timeout=300s
- tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- admission-control-config-file={{ __k3s_config_dir }}/server/admission-config.yaml
{% if k3s_server_admission_plugins | length > 0 %}
- enable-admission-plugins={{ k3s_server_admission_plugins | join(',') }}
{% endif %}
{% if k3s_server_feature_gates | length > 0 %}
- feature-gates={{ k3s_server_feature_gates | join(',') }}
{%- endif %}

View File

@ -0,0 +1,2 @@
- terminated-pod-gc-threshold=10
- use-service-account-credentials=true

View File

@ -0,0 +1,5 @@
#jinja2: lstrip_blocks: True
- config={{ __k3s_config_dir }}/kubelet.yaml
{% if not k3s_server_cloud_controller_enabled | bool %}
- cloud-provider=external
{% endif %}

View File

@ -0,0 +1,6 @@
#jinja2: lstrip_blocks: True
{% if k3s_server | bool %}
{% if not k3s_server_workload_enabled | bool %}
- CriticalAddonsOnly=true:NoExecute
{% endif %}
{% endif %}

View File

@ -0,0 +1,65 @@
#jinja2: lstrip_blocks: True
---
{% set __k3s_kube_apiserver_arg = lookup("template", "_internal/apiserver-arg.yaml.j2") | from_yaml %}
{% set __k3s_kube_controller_manager_arg = lookup("template", "_internal/kube-controller-manager-arg.yaml.j2") | from_yaml %}
{% set __k3s_kubelet_arg = lookup("template", "_internal/kubelet-arg.yaml.j2") | from_yaml %}
{% set __k3s_node_taint = lookup("template", "_internal/node-taint.yaml.j2") | from_yaml %}
token: "{{ k3s_token }}"
node-name: "{{ k3s_node_name }}"
node-ip: "{{ k3s_node_ip | join(',') }}"
{% if __k3s_node_taint is iterable %}
node-taint:
{{ __k3s_node_taint | to_nice_yaml(indent=2) | indent(2, False) }}
{% endif %}
{% if __k3s_kubelet_arg is iterable %}
kubelet-arg:
{{ __k3s_kubelet_arg | to_nice_yaml(indent=2) | indent(2, False) }}
{% endif %}
selinux: {{ k3s_selinux_enabled | bool | lower }}
protect-kernel-defaults: {{ k3s_protect_kernel_defaults | bool | lower }}
{% if k3s_server | bool %}
bind-address: "{{ k3s_server_bind_ip }}"
cluster-domain: "{{ k3s_server_cluster_domain }}"
cluster-cidr: "{{ k3s_server_cluster_cidr | join(',') }}"
cluster-dns: "{{ k3s_server_cluster_dns }}"
service-cidr: "{{ k3s_server_service_cidr | join(',') }}"
service-node-port-range: "{{ k3s_server_service_node_port_range }}"
secrets-encryption: True
write-kubeconfig: "{{ __k3s_config_dir }}/k3s.yaml"
write-kubeconfig-mode: "0600"
tls-san-security: True
{% if k3s_server_components_disabled | length > 0 %}
disable:
{{ k3s_server_components_disabled | to_nice_yaml(indent=2) | indent(2, False) }}
{% endif %}
{% if __k3s_kube_apiserver_arg is iterable %}
kube-apiserver-arg:
{{ __k3s_kube_apiserver_arg | to_nice_yaml(indent=2) | indent(2, False) }}
{% endif %}
{% if __k3s_kube_controller_manager_arg is iterable %}
kube-controller-manager-arg:
{{ __k3s_kube_controller_manager_arg | to_nice_yaml(indent=2) | indent(2, False) }}
{% endif %}
{% if not k3s_server_flannel_backend_enabled | bool %}
flannel-backend: "none"
{% else %}
{% if k3s_flannel_ipv6_masq_enabled | bool %}
flannel-ipv6-masq: True
{% endif %}
{% if k3s_flannel_external_ip is defined %}
flannel-external-ip: "{{ k3s_flannel_external_ip }}"
{% endif %}
{% endif %}
{% if not k3s_server_cloud_controller_enabled | bool %}
disable-cloud-controller: True
{% endif %}
{% if not k3s_server_network_policy_enabled | bool %}
disable-network-policy: True
{% endif %}
{% if not k3s_server_kube_proxy_enabled | bool %}
disable-kube-proxy: True
{% endif %}
{% else %}
server: "https://{{ __k3s_server_ip }}:6443"
{% endif %}

View File

@ -0,0 +1,8 @@
#jinja2: lstrip_blocks: True
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
shutdownGracePeriod: 30s
shutdownGracePeriodCriticalPods: 10s
streamingConnectionIdleTimeout: 5m
makeIPTablesUtilChains: True

View File

@ -0,0 +1,10 @@
#jinja2: lstrip_blocks: True
---
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
{% if k3s_server_admission_configuration | length > 0 %}
plugins:
{{ k3s_server_admission_configuration | to_nice_yaml(indent=2) | indent(2, False) }}
{% else %}
plugins: []
{% endif %}

View File

@ -0,0 +1,24 @@
#jinja2: lstrip_blocks: True
{{ ansible_managed | comment }}
[Unit]
Description=K3s Kubernetes
Documentation=https://k3s.io
After=network-online.target
[Service]
Type=notify
ExecStartPre=-/sbin/modprobe br_netfilter
ExecStartPre=-/sbin/modprobe overlay
ExecStart={{ __k3s_binary }} {{ "server" if k3s_server | bool else "agent" }} --config {{ __k3s_config_dir }}/config.yaml
KillMode=process
Delegate=yes
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
TimeoutStartSec=0
Restart=always
RestartSec=5s
[Install]
WantedBy=multi-user.target

28
vars/main.yml Normal file
View File

@ -0,0 +1,28 @@
---
__k3s_binary: /usr/local/bin/k3s
__k3s_server_ip: "{{ hostvars[k3s_server_nodes[0]].k3s_node_ip | first }}"
__k3s_server_init_args: >-
{% if k3s_server_nodes | length > 1 %}
{% if ansible_hostname == hostvars[k3s_server_nodes[0]]['ansible_hostname'] %}
--cluster-init
{% else %}
--server https://{{ __k3s_server_ip }}:6443
{% endif %}
{% endif %}
--config {{ __k3s_config_dir }}/config.yaml
__k3s_service_file: /etc/systemd/system/k3s.service
__k3s_config_dir: /etc/rancher/k3s
__k3s_data_dir: /var/lib/rancher/k3s
__k3s_manifests_dir: "{{ __k3s_data_dir }}/server/manifests"
__k3s_log_dir: /var/log/rancher/k3s
__k3s_node_lables:
general:
node-role.kubernetes.io/k3s-node: "true"
control:
node-role.kubernetes.io/control-plane: "true"
worker:
node-role.kubernetes.io/worker: "true"