File k3s.spec of Package k3s
#
# spec file for package k3s
#
# Copyright (c) 2025 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
# Please submit bugfixes or comments via https://bugs.opensuse.org/
#
%define directory_name k3s
%define binary_name k3s
%define baseversion 1.33
%define golang_version go1.24
%define hardened_etcd_version build2025
Name: k3s
Version: 1.34.1+k3s1
Release: 0
Summary: Lightweight Kubernetes
License: Apache-2.0
URL: https://github.com/k3s-io/k3s
Source0: k3s-%{version}.tar.xz
Source1: k3s-vendor.tar.zstd
Source2: server.conf
Source3: agent.conf
Source6: containerd-current.tar.xz
Source8: flannel-current.tar.xz
Source9: runc-current.tar.xz
Source10: versions.xslt
Source20: containerd-vendor.tar.zstd
Source22: flannel-vendor.tar.zstd
Source23: runc-vendor.tar.zstd
Source24: plugins-current.tar.xz
Source25: plugins-vendor.tar.zstd
Patch01: install.sh.patch
#Patch02: image-list.patch
BuildRequires: %{golang_version}
BuildRequires: fdupes
BuildRequires: git
BuildRequires: xsltproc
BuildRequires: sqlite3-devel
BuildRequires: golang-org-x-sys
BuildRequires: libseccomp-devel
BuildRequires: k3s-charts
BuildRequires: yq
BuildRequires: traefik
Conflicts: cri-tools
Conflicts: kubectl
Conflicts: containerd-ctr
Conflicts: containerd
Conflicts: kubernetes-client
Conflicts: kubernetes-client-provider
# /var/lib/kubelet is also packaged in kubernetes1.XX-kubelet-common
# this in turn Requires kubernetes-kubelet-common
# by conflicting with kubernetes-kubelet-common we conflict with all
# kubernetes-version packages
Conflicts: kubernetes-kubelet-common
Conflicts: rke2
Requires(post): update-alternatives
Requires(postun):update-alternatives
%{?systemd_requires}
# if iptables is missing, the nginx-controller pod does not start
Requires: iptables
Requires: conntrack-tools
Requires: iptables
Requires: %{golang_version}
Provides: containerd-ctr
Provides: kubectl
%description
k3s is a container orchestration system for automating application
deployment, scaling, and management. It is a Kubernetes-compliant
distribution that differs from the original Kubernetes (colloquially
"k8s") in that:
* Legacy, alpha, or non-default features are removed.
* Most in-tree plugins (cloud providers and storage plugins) were
removed, since they can be replaced with out-of-tree addons.
* sqlite3 is the default storage mechanism.
etcd3 is still available, but not the default.
* There is a new launcher that handles a lot of the complexity of
TLS and options.
%prep
%autosetup -p 1 -a 1 -n %{directory_name}-%{version}
# versions are still in _service, however not in obsinfo anymore.
xsltproc %{SOURCE10} %{_sourcedir}/_service > %{_builddir}/version.out
# write vendor directories for components to "component-vendor"
mkdir -p build/src/github.com/opencontainers/runc
tar -x -C build/src/github.com/opencontainers/runc --strip-components=1 -f %{SOURCE9}
tar -x -C build/src/github.com/opencontainers/runc -f %{SOURCE23}
mkdir -p build/src/github.com/containerd/containerd
tar -x -C build/src/github.com/containerd/containerd --strip-components=1 -f %{SOURCE6}
tar -x -C build/src/github.com/containerd/containerd -f %{SOURCE20}
mkdir -p build/src/github.com/containernetworking/plugins
tar -x -C build/src/github.com/containernetworking/plugins --strip-components=1 -f %{SOURCE24}
tar -x -C build/src/github.com/containernetworking/plugins -f %{SOURCE25}
mkdir -p build/src/github.com/containernetworking/plugins/meta/flannel
tar -x -C build/src/github.com/containernetworking/plugins/meta/flannel --strip-components=1 -f %{SOURCE8}
tar -x -C build/src/github.com/containernetworking/plugins/meta/flannel -f %{SOURCE22}
sed -i 's/package main/package flannel/; s/func main/func Main/' build/src/github.com/containernetworking/plugins/meta/flannel/*.go
mkdir -p build/static/charts
# update manifests/traefik.yaml to latest k3s-chart
API_URL="https://%{KUBERNETES_API}%/static/charts/"
export TRAEFIK_VERSION=$(rpm -q traefik --json | yq -p json '.Version' | sed 's/"//g')
export CHART_FILE="$(ls -1 %{_datadir}/k3s-charts/assets/traefik | sort -n | tail -n 1)"
export CHART_CRD_FILE="$(ls -1 %{_datadir}/k3s-charts/assets/traefik-crd | sort -n | tail -n 1)"
export CHART="${API_URL}${CHART_FILE}"
export CHART_CRD="${API_URL}${CHART_CRD_FILE}"
# copy charts to charts folder
cp -a %{_datadir}/k3s-charts/assets/traefik/${CHART_FILE} build/static/charts
cp -a %{_datadir}/k3s-charts/assets/traefik-crd/${CHART_CRD_FILE} build/static/charts
yq 'select(.metadata.name =="traefik-crd") | .spec.chart = env(CHART_CRD)' manifests/traefik.yaml > manifests/traefik.yaml.update
echo "---" >> manifests/traefik.yaml.update
yq 'select(.metadata.name =="traefik") | .spec.chart = env(CHART)' manifests/traefik.yaml >> manifests/traefik.yaml.update
yq -i eval-all '. |= with(select(.metadata.name == "traefik"); .spec.valuesContent |= (from_yaml | .image.tag = env(TRAEFIK_VERSION) | to_yaml ) )' manifests/traefik.yaml.update
mv manifests/traefik.yaml.update manifests/traefik.yaml
rm -f pkg/deploy/zz_generated_bindata.go
mkdir bin
mkdir dist
mkdir -p build/data build/out build/static
mkdir -p dist/artifacts
mkdir -p ./etc
%build
# instead of hardcoding the various pieces of information,
# run the upstream script
# VERSION_GOLANG tries to download the dependencies.yaml from upstream Kubernetes
# that is being packaged, so we remove that line from the script
bash --version
sed -i '/^VERSION_GOLANG/d' ./scripts/version.sh
sed -i '/VERSION_RUNC=\$/d' ./scripts/version.sh
sed -i '/VERSION_CONTAINERD=\$/d' ./scripts/version.sh
sed -i '/VERSION_FLANNEL=\$/d' ./scripts/version.sh
GOOS=linux CC=gcc CXX=g++ go generate
# instead of getting the golang version from the kubernetes dependencies.yaml,
# we hardcode the goland version that we are using
# As long as the go major version is not different, this should be fine
buildDate=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
VERSION_CONTAINERD=$(set -- $(grep containerd %{_builddir}/version.out); echo $2)
VERSION_FLANNEL=$(set -- $(grep flannel %{_builddir}/version.out); echo $2)
VERSION_RUNC=$(set -- $(grep runc %{_builddir}/version.out); echo $2)
DRONE_COMMIT=%{commit}
source ./scripts/version.sh
COMMIT=$(grep commit %{_sourcedir}/%{name}.obsinfo | awk '{print $2}')
export COMMIT=${COMMIT:0:8}
VERSION=v%{version}
VERSION_GOLANG=$(go version | awk '{print $3}')
PKG="github.com/k3s-io/k3s"
PKG_CONTAINERD="github.com/containerd/containerd/v2"
PKG_CRICTL="sigs.k8s.io/cri-tools/pkg"
PKG_K8S_BASE="k8s.io/component-base"
PKG_K8S_CLIENT="k8s.io/client-go/pkg"
PKG_CNI_PLUGINS="github.com/containernetworking/plugins"
PKG_KUBE_ROUTER="github.com/cloudnativelabs/kube-router/v2"
PKG_CRI_DOCKERD="github.com/Mirantis/cri-dockerd"
PKG_ETCD="go.etcd.io/etcd"
LDFLAGS=" \
-X ${PKG}/pkg/version.Version=${VERSION} \
-X ${PKG}/pkg/version.GitCommit=${COMMIT:0:8} \
-X ${PKG}/pkg/version.UpstreamGolang=${VERSION_GOLANG} \
-X ${PKG_K8S_CLIENT}/version.gitVersion=${VERSION} \
-X ${PKG_K8S_CLIENT}/version.gitCommit=${COMMIT} \
-X ${PKG_K8S_CLIENT}/version.gitTreeState=${TREE_STATE} \
-X ${PKG_K8S_CLIENT}/version.buildDate=${buildDate} \
-X ${PKG_K8S_BASE}/version.gitVersion=${VERSION} \
-X ${PKG_K8S_BASE}/version.gitCommit=${COMMIT} \
-X ${PKG_K8S_BASE}/version.gitTreeState=${TREE_STATE} \
-X ${PKG_K8S_BASE}/version.buildDate=${buildDate} \
-X ${PKG_CRICTL}/version.Version=${VERSION_CRICTL} \
-X ${PKG_CONTAINERD}/version.Version=${VERSION_CONTAINERD} \
-X ${PKG_CONTAINERD}/version.Package=${PKG_CONTAINERD_K3S} \
-X ${PKG_CNI_PLUGINS}/pkg/utils/buildversion.BuildVersion=${VERSION_CNIPLUGINS} \
-X ${PKG_CNI_PLUGINS}/plugins/meta/flannel.Program=flannel \
-X ${PKG_CNI_PLUGINS}/plugins/meta/flannel.Version=${VERSION_FLANNEL_PLUGIN}+${VERSION_FLANNEL} \
-X ${PKG_CNI_PLUGINS}/plugins/meta/flannel.Commit=HEAD \
-X ${PKG_CNI_PLUGINS}/plugins/meta/flannel.buildDate=${buildDate} \
-X ${PKG_KUBE_ROUTER}/pkg/version.Version=${VERSION_KUBE_ROUTER} \
-X ${PKG_KUBE_ROUTER}/pkg/version.BuildDate=${buildDate} \
-X ${PKG_CRI_DOCKERD}/cmd/version.Version=${VERSION_CRI_DOCKERD} \
-X ${PKG_CRI_DOCKERD}/cmd/version.GitCommit=HEAD \
-X ${PKG_CRI_DOCKERD}/cmd/version.BuildTime=${buildDate} \
-X ${PKG_ETCD}/api/v3/version.GitSHA=HEAD \
-w -s "
TAGS="ctrd netcgo osusergo providerless urfave_cli_no_docs sqlite_omit_load_extension apparmor seccomp libsqlite3"
#GO111MODULE=off GOPATH=$TMPDIR CGO_ENABLED=0 "${GO}" build -tags "$TAGS" -gcflags="all=${GCFLAGS}" -ldflags "$VERSIONFLAGS $LDFLAGS $STATIC" -o $INSTALLBIN/cni${BINARY_POSTFIX}
#CGO_ENABLED=1
pushd ./build/src/github.com/containernetworking/plugins
go build -mod=vendor \
-buildmode=pie \
-buildvcs=false \
-tags "${TAGS}" -ldflags=" \
-X ${PKG}/pkg/version.Version=${VERSION} \
-X ${PKG}/pkg/version.GitCommit=${COMMIT:0:8} \
-X ${PKG}/pkg/version.UpstreamGolang=${VERSION_GOLANG} \
-X ${PKG_K8S_CLIENT}/version.gitVersion=${VERSION} \
-X ${PKG_K8S_CLIENT}/version.gitCommit=${COMMIT} \
-X ${PKG_K8S_CLIENT}/version.gitTreeState=${TREE_STATE} \
-X ${PKG_K8S_CLIENT}/version.buildDate=${buildDate} \
-X ${PKG_K8S_BASE}/version.gitVersion=${VERSION} \
-X ${PKG_K8S_BASE}/version.gitCommit=${COMMIT} \
-X ${PKG_K8S_BASE}/version.gitTreeState=${TREE_STATE} \
-X ${PKG_K8S_BASE}/version.buildDate=${buildDate} \
-X ${PKG_CRICTL}/version.Version=${VERSION_CRICTL} \
-X ${PKG_CONTAINERD}/version.Version=${VERSION_CONTAINERD} \
-X ${PKG_CONTAINERD}/version.Package=${PKG_CONTAINERD_K3S} \
-X ${PKG_CNI_PLUGINS}/pkg/utils/buildversion.BuildVersion=${VERSION_CNIPLUGINS} \
-X ${PKG_CNI_PLUGINS}/plugins/meta/flannel.Program=flannel \
-X ${PKG_CNI_PLUGINS}/plugins/meta/flannel.Version=${VERSION_FLANNEL_PLUGIN}+${VERSION_FLANNEL} \
-X ${PKG_CNI_PLUGINS}/plugins/meta/flannel.Commit=HEAD \
-X ${PKG_CNI_PLUGINS}/plugins/meta/flannel.buildDate=${buildDate} \
-X ${PKG_KUBE_ROUTER}/pkg/version.Version=${VERSION_KUBE_ROUTER} \
-X ${PKG_KUBE_ROUTER}/pkg/version.BuildDate=${buildDate} \
-X ${PKG_CRI_DOCKERD}/cmd/version.Version=${VERSION_CRI_DOCKERD} \
-X ${PKG_CRI_DOCKERD}/cmd/version.GitCommit=HEAD \
-X ${PKG_CRI_DOCKERD}/cmd/version.BuildTime=${buildDate} \
-X ${PKG_ETCD}/api/v3/version.GitSHA=HEAD \
-w -s " -o %{_builddir}/%{directory_name}-%{version}/bin/cni
popd
mkdir -p pkg/deploy/embed
mkdir -p pkg/static/embed
mkdir -p pkg/data/embed
cp -av manifests/* pkg/deploy/embed/
cp -av build/static/* pkg/static/embed/
go build \
-mod=vendor \
-buildmode=pie \
-buildvcs=false \
-tags="${TAGS}" \
-ldflags=" \
-X ${PKG}/pkg/version.Version=${VERSION} \
-X ${PKG}/pkg/version.GitCommit=${COMMIT:0:8} \
-X ${PKG}/pkg/version.UpstreamGolang=${VERSION_GOLANG} \
-X ${PKG_K8S_CLIENT}/version.gitVersion=${VERSION} \
-X ${PKG_K8S_CLIENT}/version.gitCommit=${COMMIT} \
-X ${PKG_K8S_CLIENT}/version.gitTreeState=${TREE_STATE} \
-X ${PKG_K8S_CLIENT}/version.buildDate=${buildDate} \
-X ${PKG_K8S_BASE}/version.gitVersion=${VERSION} \
-X ${PKG_K8S_BASE}/version.gitCommit=${COMMIT} \
-X ${PKG_K8S_BASE}/version.gitTreeState=${TREE_STATE} \
-X ${PKG_K8S_BASE}/version.buildDate=${buildDate} \
-X ${PKG_CRICTL}/version.Version=${VERSION_CRICTL} \
-X ${PKG_CONTAINERD}/version.Version=${VERSION_CONTAINERD} \
-X ${PKG_CONTAINERD}/version.Package=${PKG_CONTAINERD_K3S} \
-X ${PKG_CNI_PLUGINS}/pkg/utils/buildversion.BuildVersion=${VERSION_CNIPLUGINS} \
-X ${PKG_CNI_PLUGINS}/plugins/meta/flannel.Program=flannel \
-X ${PKG_CNI_PLUGINS}/plugins/meta/flannel.Version=${VERSION_FLANNEL_PLUGIN}+${VERSION_FLANNEL} \
-X ${PKG_CNI_PLUGINS}/plugins/meta/flannel.Commit=HEAD \
-X ${PKG_CNI_PLUGINS}/plugins/meta/flannel.buildDate=${buildDate} \
-X ${PKG_KUBE_ROUTER}/pkg/version.Version=${VERSION_KUBE_ROUTER} \
-X ${PKG_KUBE_ROUTER}/pkg/version.BuildDate=${buildDate} \
-X ${PKG_CRI_DOCKERD}/cmd/version.Version=${VERSION_CRI_DOCKERD} \
-X ${PKG_CRI_DOCKERD}/cmd/version.GitCommit=HEAD \
-X ${PKG_CRI_DOCKERD}/cmd/version.BuildTime=${buildDate} \
-X ${PKG_ETCD}/api/v3/version.GitSHA=HEAD \
-w -s \
" -o ./bin/%{binary_name} ./cmd/server
## build containerd
TAGS="${TAGS/netcgo/netgo}"
pushd ./build/src/github.com/containerd/containerd
go build \
-mod=vendor \
-tags "${TAGS}" \
-ldflags "${LDFLAGS}" -o bin/containerd-shim-runc-v2 ./cmd/containerd-shim-runc-v2
popd
cp -vf ./build/src/github.com/containerd/containerd/bin/* ./bin/
## build runc
pushd ./build/src/github.com/opencontainers/runc
rm -f runc
make EXTRA_LDFLAGS="${LDFLAGS}"
popd
cp -vf ./build/src/github.com/opencontainers/runc/runc ./bin/
## set k3s binaries
for i in ctr crictl containerd kubectl k3s-agent k3s-server k3s-token k3s-etcd-snapshot k3s-secrets-encrypt k3s-certificate k3s-completion; do
rm -f bin/$i
ln -s k3s bin/$i
done
## set cni binaries
for i in bandwidth bridge firewall flannel host-local loopback portmap; do
rm -f bin/$i
ln -s cni bin/$i
done
cp contrib/util/check-config.sh bin/check-config
mkdir -p build/data build/out build/static
mkdir -p dist/artifacts
mkdir -p ./etc
(
set +x
cd bin
find . -not -path '*/\.*' -type f -exec sha256sum {} \; | sed -e 's| \./| |' | sort -k2 >.sha256sums
(
for f in $(find . -type l); do
echo $f $(readlink $f)
done
) | sed -e 's|^\./||' | sort >.links
set -x
)
tar cvf ./build/out/data.tar ./bin ./etc
zstd --no-progress -T0 -16 -f --long=25 --rm ./build/out/data.tar -o ./build/out/data.tar.zst
HASH=$(sha256sum ./build/out/data.tar.zst | awk '{print $1}')
cp ./build/out/data.tar.zst ./build/data/${HASH}.tar.zst
mkdir -p pkg/deploy/embed
mkdir -p pkg/static/embed
mkdir -p pkg/data/embed
cp -av manifests/* pkg/deploy/embed/
cp -av build/static/* pkg/static/embed/
cp -av build/data/* pkg/data/embed/
GOOS=linux CC=gcc CXX=g++ go generate
LDFLAGS="
-X github.com/k3s-io/k3s/pkg/version.Version=$VERSION
-X github.com/k3s-io/k3s/pkg/version.GitCommit=${COMMIT:0:8}
-w -s
"
TAGS="urfave_cli_no_docs"
STATIC="-extldflags"
CGO_ENABLED=0 go build -tags="$TAGS" -buildvcs=false -ldflags="$LDFLAGS $STATIC" -o %{binary_name} ./cmd/k3s
## Generate service files
export SYSTEMD_TYPE=notify
export BIN_DIR=%{_bindir}
for i in server agent; do
export FILE_K3S_ENV=%{_sysconfdir}/rancher/%{binary_name}/$i.conf
export CMD_K3S_EXEC="$i \${SERVER_OPTS}"
export FILE_K3S_SERVICE="%{binary_name}-$i.service"
./install.sh
done
#%check
#go test -v ./...
%install
# Install the binary.
install -D -m 0755 %{binary_name} %{buildroot}%{_bindir}/%{binary_name}
## set k3s binaries
for i in ctr crictl kubectl; do
ln -s "%{_bindir}/%{binary_name}" "%{buildroot}%{_bindir}/$i"
done
# systemd unit and env files
mkdir -p %{buildroot}%{_unitdir}
install -D -m 0644 k3s-agent.service %{buildroot}%{_unitdir}/k3s-agent.service
install -D -m 0644 k3s-server.service %{buildroot}%{_unitdir}/k3s-server.service
mkdir -p %{buildroot}%{_sysconfdir}/rancher/k3s
install -D -m 644 %{SOURCE2} %{buildroot}%{_sysconfdir}/rancher/%{binary_name}/server.conf
install -D -m 644 %{SOURCE3} %{buildroot}%{_sysconfdir}/rancher/%{binary_name}/agent.conf
mkdir -p %{buildroot}%{_localstatedir}/lib/rancher/k3s
mkdir -p %{buildroot}%{_localstatedir}/lib/rancher/k3s/server/manifests
%fdupes %{buildroot}/%{_unitdir}/
%pre
%service_add_pre k3s-server.service k3s-agent.service
%post
%service_add_post k3s-server.service k3s-agent.service
%preun
%service_del_preun k3s-server.service k3s-agent.service
%postun
%service_del_postun k3s-server.service k3s-agent.service
%files
%doc README.md
%license LICENSE
%dir %{_bindir}
%{_bindir}/k3s
%{_bindir}/kubectl
%{_bindir}/crictl
%{_bindir}/ctr
%{_localstatedir}/lib/rancher
%config %{_sysconfdir}/rancher
%config(noreplace) %{_sysconfdir}/rancher/k3s/agent.conf
%config(noreplace) %{_sysconfdir}/rancher/k3s/server.conf
%{_unitdir}/k3s-agent.service
%{_unitdir}/k3s-server.service
%changelog