···5, iptables
6, iproute2
7, bridge-utils
08, conntrack-tools
9-, buildGoPackage
10, runc
011, kmod
12, libseccomp
13, pkg-config
···18, fetchzip
19, fetchgit
20, zstd
021, nixosTests
22}:
23···43# Those pieces of software we entirely ignore upstream's handling of, and just
44# make sure they're in the path if desired.
45let
46- k3sVersion = "1.22.3+k3s1"; # k3s git tag
47- k3sCommit = "61a2aab25eeb97c26fa3f2b177e4355a7654c991"; # k3s git commit at the above version
48- k3sRepoSha256 = "0lz5hr3c86gxm9w5jy3g26n6a26m8k0y559hv6220rsi709j7ma9";
4950- traefikChartVersion = "10.3.0"; # taken from ./manifests/traefik.yaml at spec.version
51- traefikChartSha256 = "0y6wr64xp7bgx24kqil0x6myr3pnfrg8rw0d1h5zd2n5a8nfd73f";
005253- k3sRootVersion = "0.9.1"; # taken from ./scripts/download at ROOT_VERSION
054 k3sRootSha256 = "0r2cj4l50cxkrvszpzxfk36lvbjf9vcmp6d5lvxg8qsah8lki3x8";
5556- k3sCNIVersion = "0.9.1-k3s1"; # taken from ./scripts/version.sh at VERSION_CNIPLUGINS
057 k3sCNISha256 = "1327vmfph7b8i14q05c2xdfzk60caflg1zhycx0mrf3d59f4zsz5";
580000000059 baseMeta = {
60 description = "A lightweight Kubernetes distribution";
61 license = licenses.asl20;
62 homepage = "https://k3s.io";
63- maintainers = with maintainers; [ euank ];
64 platforms = platforms.linux;
65 };
66000000000000000000067 # bundled into the k3s binary
68 traefikChart = fetchurl {
69 url = "https://helm.traefik.io/traefik/traefik-${traefikChartVersion}.tgz";
···84 sha256 = k3sRootSha256;
85 stripRoot = false;
86 };
87- k3sPlugins = buildGoPackage rec {
88- name = "k3s-cni-plugins";
89 version = k3sCNIVersion;
09091- goPackagePath = "github.com/containernetworking/plugins";
92 subPackages = [ "." ];
9394 src = fetchFromGitHub {
···98 sha256 = k3sCNISha256;
99 };
1000000101 meta = baseMeta // {
102 description = "CNI plugins, as patched by rancher for k3s";
103 };
···124 # Then, we bundle those binaries into our thick k3s binary and use that as
125 # the final single output.
126 # This approach was chosen because it ensures the bundled binaries all are
127- # correctly built to run with nix (we can lean on the existing buildGoPackage
128 # stuff), and we can again lean on that tooling for the final k3s binary too.
129 # Other alternatives would be to manually run the
130 # strip/patchelf/remove-references step ourselves in the installPhase of the
131 # derivation when we've built all the binaries, but haven't bundled them in
132 # with generated bindata yet.
133- k3sBuildStage1 = buildGoPackage rec {
134- name = "k3s-build-1";
135 version = k3sVersion;
136137- goPackagePath = "github.com/rancher/k3s";
138-139 src = k3sRepo;
140-141- # Patch build scripts so that we can use them.
142- # This makes things more dynamically linked (because nix can deal with
143- # dynamically linked dependencies just fine), removes the upload at the
144- # end, and skips building runc + cni, since we have our own derivations for
145- # those.
146- patches = [ ./patches/0002-Add-nixpkgs-patches.patch ];
147148 nativeBuildInputs = [ pkg-config ];
149 buildInputs = [ libseccomp ];
150151- # Versioning info for build script
152- DRONE_TAG = "v${version}";
153- DRONE_COMMIT = k3sCommit;
154-155- buildPhase = ''
156- pushd go/src/${goPackagePath}
157-158- patchShebangs ./scripts/build ./scripts/version.sh
159- mkdir -p bin
160- ./scripts/build
161-162- popd
163- '';
164-165- installPhase = ''
166- pushd go/src/${goPackagePath}
167-168- mkdir -p "$out/bin"
169- install -m 0755 -t "$out/bin" ./bin/*
1700000000000000171 popd
172 '';
173···175 description = "The various binaries that get packaged into the final k3s binary";
176 };
177 };
178- k3sBin = buildGoPackage rec {
179- name = "k3s-bin";
180 version = k3sVersion;
181-182- goPackagePath = "github.com/rancher/k3s";
183-184- src = k3sRepo;
185-186- # See the above comment in k3sBuildStage1
187- patches = [ ./patches/0002-Add-nixpkgs-patches.patch ];
188-189- nativeBuildInputs = [ pkg-config zstd ];
190- # These dependencies are embedded as compressed files in k3s at runtime.
191- # Propagate them to avoid broken runtime references to libraries.
192- propagatedBuildInputs = [ k3sPlugins k3sBuildStage1 runc ];
193-194- # k3s appends a suffix to the final distribution binary for some arches
195- archSuffix =
196- if stdenv.hostPlatform.system == "x86_64-linux" then ""
197- else if stdenv.hostPlatform.system == "aarch64-linux" then "-arm64"
198- else throw "k3s isn't being built for ${stdenv.hostPlatform.system} yet.";
199-200- DRONE_TAG = "v${version}";
201- DRONE_COMMIT = k3sCommit;
202-203- # In order to build the thick k3s binary (which is what
204- # ./scripts/package-cli does), we need to get all the binaries that script
205- # expects in place.
206- buildPhase = ''
207- pushd go/src/${goPackagePath}
208-209- patchShebangs ./scripts/build ./scripts/version.sh ./scripts/package-cli
210-211- mkdir -p bin
212-213- install -m 0755 -t ./bin ${k3sBuildStage1}/bin/*
214- install -m 0755 -T "${k3sPlugins}/bin/plugins" ./bin/cni
215- # Note: use the already-nixpkgs-bundled k3s rather than the one bundled
216- # in k3s because the k3s one is completely unmodified from upstream
217- # (unlike containerd, cni, etc)
218- install -m 0755 -T "${runc}/bin/runc" ./bin/runc
219- cp -R "${k3sRoot}/etc" ./etc
220- mkdir -p "build/static/charts"
221- cp "${traefikChart}" "build/static/charts/traefik-${traefikChartVersion}.tgz"
222-223- ./scripts/package-cli
224-225- popd
226- '';
227-228- installPhase = ''
229- pushd go/src/${goPackagePath}
230-231- mkdir -p "$out/bin"
232- install -m 0755 -T ./dist/artifacts/k3s${archSuffix} "$out/bin/k3s"
233-234- popd
235- '';
236-237- meta = baseMeta // {
238- description = "The k3s go binary which is used by the final wrapped output below";
239 };
0000240 };
241in
242-stdenv.mkDerivation rec {
243 pname = "k3s";
244 version = k3sVersion;
245246- # `src` here is a workaround for the updateScript bot. It couldn't be empty.
247- src = builtins.filterSource (path: type: false) ./.;
000000248249 # Important utilities used by the kubelet, see
250 # https://github.com/kubernetes/kubernetes/issues/26093#issuecomment-237202494
···260 conntrack-tools
261 ];
262263- buildInputs = [
264- k3sBin
265- ] ++ k3sRuntimeDeps;
00000000000000000000000000000000000266267- nativeBuildInputs = [ makeWrapper ];
000268269- unpackPhase = "true";
00270271- # And, one final derivation (you thought the last one was it, right?)
272- # We got the binary we wanted above, but it doesn't have all the runtime
273- # dependencies k8s wants, including mount utilities for kubelet, networking
274- # tools for cni/kubelet stuff, etc
275- # Use a wrapper script to reference all the binaries that k3s tries to
276- # execute, but that we didn't bundle with it.
277 installPhase = ''
278- runHook preInstall
279- mkdir -p "$out/bin"
280- makeWrapper ${k3sBin}/bin/k3s "$out/bin/k3s" \
281 --prefix PATH : ${lib.makeBinPath k3sRuntimeDeps} \
282 --prefix PATH : "$out/bin"
283- runHook postInstall
284 '';
285286 doInstallCheck = true;
287 installCheckPhase = ''
288- $out/bin/k3s --version | grep v${k3sVersion} > /dev/null
289 '';
290291 passthru.updateScript = ./update.sh;
···5, iptables
6, iproute2
7, bridge-utils
8+, btrfs-progs
9, conntrack-tools
10+, buildGoModule
11, runc
12+, rsync
13, kmod
14, libseccomp
15, pkg-config
···20, fetchzip
21, fetchgit
22, zstd
23+, yq-go
24, nixosTests
25}:
26···46# Those pieces of software we entirely ignore upstream's handling of, and just
47# make sure they're in the path if desired.
48let
49+ k3sVersion = "1.23.3+k3s1"; # k3s git tag
50+ k3sCommit = "6f4217a3405d16a1a51bbb40872d7dcb87207bb9"; # k3s git commit at the above version
51+ k3sRepoSha256 = "sha256-0dRusG1vL+1KbmViIUNCZK1b+FEgV6otcVUyFonHmm4=";
5253+ # taken from ./manifests/traefik.yaml, extracted from '.spec.chart' https://github.com/k3s-io/k3s/blob/v1.23.3%2Bk3s1/scripts/download#L9
54+ # The 'patch' and 'minor' versions are currently hardcoded as single digits only, so ignore the trailing two digits. Weird, I know.
55+ traefikChartVersion = "10.9.1";
56+ traefikChartSha256 = "sha256-XM1DLofU1zEEFeB5bNQ7cgv102gXsToPP7SFh87QuGQ=";
5758+ # taken from ./scripts/version.sh VERSION_ROOT https://github.com/k3s-io/k3s/blob/v1.23.3%2Bk3s1/scripts/version.sh#L47
59+ k3sRootVersion = "0.9.1";
60 k3sRootSha256 = "0r2cj4l50cxkrvszpzxfk36lvbjf9vcmp6d5lvxg8qsah8lki3x8";
6162+ # taken from ./scripts/version.sh VERSION_CNIPLUGINS https://github.com/k3s-io/k3s/blob/v1.23.3%2Bk3s1/scripts/version.sh#L45
63+ k3sCNIVersion = "0.9.1-k3s1";
64 k3sCNISha256 = "1327vmfph7b8i14q05c2xdfzk60caflg1zhycx0mrf3d59f4zsz5";
6566+ # taken from go.mod, the 'github.com/containerd/containerd' line
67+ # run `grep github.com/containerd/containerd go.mod | head -n1 | awk '{print $4}'`
68+ containerdVersion = "v1.5.9-k3s1";
69+ containerdSha256 = "sha256-7xlhBA6KuwFlw+jyThygv4Ow9F3xjjIUtS6x8YHwjic=";
70+71+ # run `grep github.com/kubernetes-sigs/cri-tools go.mod | head -n1 | awk '{print $4}'` in the k3s repo at the tag
72+ criCtlVersion = "v1.22.0-k3s1";
73+74 baseMeta = {
75 description = "A lightweight Kubernetes distribution";
76 license = licenses.asl20;
77 homepage = "https://k3s.io";
78+ maintainers = with maintainers; [ euank mic92 ];
79 platforms = platforms.linux;
80 };
8182+ # https://github.com/k3s-io/k3s/blob/5fb370e53e0014dc96183b8ecb2c25a61e891e76/scripts/build#L19-L40
83+ versionldflags = [
84+ "-X github.com/rancher/k3s/pkg/version.Version=v${k3sVersion}"
85+ "-X github.com/rancher/k3s/pkg/version.GitCommit=${lib.substring 0 8 k3sCommit}"
86+ "-X k8s.io/client-go/pkg/version.gitVersion=v${k3sVersion}"
87+ "-X k8s.io/client-go/pkg/version.gitCommit=${k3sCommit}"
88+ "-X k8s.io/client-go/pkg/version.gitTreeState=clean"
89+ "-X k8s.io/client-go/pkg/version.buildDate=1970-01-01T01:01:01Z"
90+ "-X k8s.io/component-base/version.gitVersion=v${k3sVersion}"
91+ "-X k8s.io/component-base/version.gitCommit=${k3sCommit}"
92+ "-X k8s.io/component-base/version.gitTreeState=clean"
93+ "-X k8s.io/component-base/version.buildDate=1970-01-01T01:01:01Z"
94+ "-X github.com/kubernetes-sigs/cri-tools/pkg/version.Version=${criCtlVersion}"
95+ "-X github.com/containerd/containerd/version.Version=${containerdVersion}"
96+ "-X github.com/containerd/containerd/version.Package=github.com/k3s-io/containerd"
97+ "-X github.com/containerd/containerd/version.Version=${containerdVersion}"
98+ "-X github.com/containerd/containerd/version.Package=github.com/k3s-io/containerd"
99+ ];
100+101 # bundled into the k3s binary
102 traefikChart = fetchurl {
103 url = "https://helm.traefik.io/traefik/traefik-${traefikChartVersion}.tgz";
···118 sha256 = k3sRootSha256;
119 stripRoot = false;
120 };
121+ k3sCNIPlugins = buildGoModule rec {
122+ pname = "k3s-cni-plugins";
123 version = k3sCNIVersion;
124+ vendorSha256 = null;
1250126 subPackages = [ "." ];
127128 src = fetchFromGitHub {
···132 sha256 = k3sCNISha256;
133 };
134135+ postInstall = ''
136+ mv $out/bin/plugins $out/bin/cni
137+ '';
138+139 meta = baseMeta // {
140 description = "CNI plugins, as patched by rancher for k3s";
141 };
···162 # Then, we bundle those binaries into our thick k3s binary and use that as
163 # the final single output.
164 # This approach was chosen because it ensures the bundled binaries all are
165+ # correctly built to run with nix (we can lean on the existing buildGoModule
166 # stuff), and we can again lean on that tooling for the final k3s binary too.
167 # Other alternatives would be to manually run the
168 # strip/patchelf/remove-references step ourselves in the installPhase of the
169 # derivation when we've built all the binaries, but haven't bundled them in
170 # with generated bindata yet.
171+ k3sServer = buildGoModule rec {
172+ pname = "k3s-server";
173 version = k3sVersion;
17400175 src = k3sRepo;
176+ vendorSha256 = "sha256-9+2k/ipAOhc8JJU+L2dwaM01Dkw+0xyrF5kt6mL19G0=";
000000177178 nativeBuildInputs = [ pkg-config ];
179 buildInputs = [ libseccomp ];
180181+ subPackages = [ "cmd/server" ];
182+ ldflags = versionldflags;
00000000000000000183184+ # create the multicall symlinks for k3s
185+ postInstall = ''
186+ mv $out/bin/server $out/bin/k3s
187+ pushd $out
188+ # taken verbatim from https://github.com/k3s-io/k3s/blob/v1.23.3%2Bk3s1/scripts/build#L105-L113
189+ ln -s k3s ./bin/k3s-agent
190+ ln -s k3s ./bin/k3s-server
191+ ln -s k3s ./bin/k3s-etcd-snapshot
192+ ln -s k3s ./bin/k3s-secrets-encrypt
193+ ln -s k3s ./bin/k3s-certificate
194+ ln -s k3s ./bin/kubectl
195+ ln -s k3s ./bin/crictl
196+ ln -s k3s ./bin/ctr
197 popd
198 '';
199···201 description = "The various binaries that get packaged into the final k3s binary";
202 };
203 };
204+ k3sContainerd = buildGoModule {
205+ pname = "k3s-containerd";
206 version = k3sVersion;
207+ src = fetchFromGitHub {
208+ owner = "k3s-io";
209+ repo = "containerd";
210+ rev = containerdVersion;
211+ sha256 = containerdSha256;
00000000000000000000000000000000000000000000000000000212 };
213+ vendorSha256 = null;
214+ buildInputs = [ btrfs-progs ];
215+ subPackages = [ "cmd/containerd" "cmd/containerd-shim-runc-v2" ];
216+ ldflags = versionldflags;
217 };
218in
219+buildGoModule rec {
220 pname = "k3s";
221 version = k3sVersion;
222223+ src = k3sRepo;
224+ proxyVendor = true;
225+ vendorSha256 = "sha256-8Yp9csyRNSYi9wo8E8mF8cu92wG1t3l18wJ8Y4L7HEA=";
226+227+ patches = [
228+ ./patches/0001-scrips-download-strip-downloading-just-package-CRD.patch
229+ ./patches/0002-Don-t-build-a-static-binary-in-package-cli.patch
230+ ];
231232 # Important utilities used by the kubelet, see
233 # https://github.com/kubernetes/kubernetes/issues/26093#issuecomment-237202494
···243 conntrack-tools
244 ];
245246+ buildInputs = k3sRuntimeDeps;
247+248+ nativeBuildInputs = [
249+ makeWrapper
250+ rsync
251+ yq-go
252+ zstd
253+ ];
254+255+ # embedded in the final k3s cli
256+ propagatedBuildInputs = [
257+ k3sCNIPlugins
258+ k3sContainerd
259+ k3sServer
260+ runc
261+ ];
262+263+ # We override most of buildPhase due to peculiarities in k3s's build.
264+ # Specifically, it has a 'go generate' which runs part of the package. See
265+ # this comment:
266+ # https://github.com/NixOS/nixpkgs/pull/158089#discussion_r799965694
267+ # So, why do we use buildGoModule at all? For the `vendorSha256` / `go mod download` stuff primarily.
268+ buildPhase = ''
269+ patchShebangs ./scripts/package-cli ./scripts/download ./scripts/build-upload
270+271+ # copy needed 'go generate' inputs into place
272+ mkdir -p ./bin/aux
273+ rsync -a --no-perms ${k3sServer}/bin/ ./bin/
274+ ln -vsf ${runc}/bin/runc ./bin/runc
275+ ln -vsf ${k3sCNIPlugins}/bin/cni ./bin/cni
276+ ln -vsf ${k3sContainerd}/bin/* ./bin/
277+ rsync -a --no-perms --chmod u=rwX ${k3sRoot}/etc/ ./etc/
278+ mkdir -p ./build/static/charts
279+ # Note, upstream's chart has a 00 suffix. This seems to not matter though, so we're ignoring that naming detail.
280+ export TRAEFIK_CHART_FILE=${traefikChart}
281+ # place the traefik chart using their code since it's complicated
282+ # We trim the actual download, see patches
283+ ./scripts/download
284285+ export ARCH=$GOARCH
286+ export DRONE_TAG="v${k3sVersion}"
287+ export DRONE_COMMIT="${k3sCommit}"
288+ # use ./scripts/package-cli to run 'go generate' + 'go build'
289290+ ./scripts/package-cli
291+ mkdir -p $out/bin
292+ '';
293294+ # Otherwise it depends on 'getGoDirs', which is normally set in buildPhase
295+ doCheck = false;
296+000297 installPhase = ''
298+ # wildcard to match the arm64 build too
299+ install -m 0755 dist/artifacts/k3s* -D $out/bin/k3s
300+ wrapProgram $out/bin/k3s \
301 --prefix PATH : ${lib.makeBinPath k3sRuntimeDeps} \
302 --prefix PATH : "$out/bin"
0303 '';
304305 doInstallCheck = true;
306 installCheckPhase = ''
307+ $out/bin/k3s --version | grep -F "v${k3sVersion}" >/dev/null
308 '';
309310 passthru.updateScript = ./update.sh;