nix-csi, easykubenix, dinix 세 프로젝트를 통해 Kubernetes를 Nix 방식으로 구성·배포·실행하는 아이디어와 현황, 그리고 관련 논의를 소개한다.
저는 Kubernetes를 Nixify하기 위해 함께 맞물리도록 의도된 몇 가지 프로젝트를 한동안 작업해 왔고, 이를 공유하고 싶습니다. 아직 실전에서 검증된 것은 아니고, 문서는 빈약하며 예제도 다소 거칩니다.
easykubenix는 kubenix에서 매우 강하게 영감을 받았습니다. 둘 다 NixOS 모듈 시스템을 사용해 매니페스트를 렌더링합니다. 가장 큰 차이는, Kubernetes API 전체 표면을 Nix로 재현하기 위해 코드젠을 쓰는 대신 저는 (pkgs.formats.json {}).type를 사용해 가능한 모든 리소스를 포괄하고, API 검증을 위해 임시 etcd+kube-apiserver를 띄운 뒤 매니페스트를 적용하는 스크립트를 생성한다는 점입니다.
kluctl을 사용한 배포 스크립트도 함께 번들합니다. kluctl은 CLI에서 작업할 수 있고 GitOps에만 의존하지 않아도 되는 배포 도구를 좋아한다면 정말 훌륭한 도구입니다(그리고 시크릿을 처리해주므로 스토어에 시크릿을 쓰지 않게 됩니다).
Helm 차트 렌더링을 지원하고, YAML 파일 임포트도 지원합니다. 또한 렌더링 단계에서 attrset을 “네임드 리스트(named list)”로 변환하기 위해 attrset에 _namedlist를 설정하는 것도 지원하여, 컨테이너를 리스트가 아니라 attrset으로 참조할 수 있습니다.
easykubenix 모듈 예시:
{
config.kubernetes.resources.namespace.Secret.name.stringData.secret = "nix is awesome";
}
상태: 사용 가능
TL;DR: /nix를 파드에 마운트하고, 스토리지를 공유하며, 노드가 NixOS일 필요가 없고, /nix/store 뷰는 파드별로 생성되므로 전역이 아닙니다.
niX-snapshotter를 “재구현”한 것이지만 CRI 레이어가 아니라 CSI “레이어”에서 동작합니다. 즉 CSI 드라이버만 배포하면 어떤 Kubernetes에서도 실행할 수 있고, 노드 OS가 NixOS일 필요가 없습니다. 내부적으로는 하드링크를 사용해 공유 Nix 스토어의 “뷰”를 만듭니다. 볼륨이 RO면 하드링크 폴더를 파드에 바인드 마운트하고, 볼륨이 RW면 파드에 overlayfs로 마운트합니다(그래서 파드 안에서 nix 명령을 실행할 수 있습니다). nix-snapshotter와 마찬가지로, RO 모드에서는 inode를 끝까지 공유하고 따라서 페이지 캐시도 공유하게 되어, 이 방식의 배포는 컨테이너 이미지보다 RAM 효율이 더 좋습니다.
루트 derivation을 /nix/var/result로 링크해 쉽게 바이너리를 실행할 수 있게 하고, Nix 데이터베이스도 초기화합니다.
또한 선택적으로 클러스터 로컬 바이너리 캐시를 구현했는데, dinix로 openssh와 nix-serve-ng를 실행합니다(추가 작업 필요).
상태: 동작함. 배포 문서는 아직 없고, 이미지는 quay에 있습니다. 현재는 Lix 쪽으로 성향이 좀 강한데, 제가 Lix를 쓰기 때문이며 곧 설정 가능해질 것입니다soon.
dinix는 NixOS 모듈 시스템을 사용해 dinit 설정 + 시작 스크립트를 렌더링합니다. dinit은 컨테이너에서 PID1로 실행할 수도 있고, 터미널에서 일반 사용자 공간(supervisor)으로 실행할 수도 있으며, 시스템이나 다른 어떤 방식으로든 프로세스를 실행할 수 있는 훌륭한 프로세스 슈퍼바이저입니다. 어떤 면에서는 NixNG와 비슷하지만, dinit 하나에만 초점을 극도로 맞췄습니다.
dinix 모듈 예시:
config = {
services.boot = {
type = "internal";
depends-on = [ "nginx" ];
};
services.nginx = {
type = "process";
command =
pkgs.writeExeclineBin "nginx-launcher" # execline
''
${lib.getExe pkgs.nginx} -c ${nginxConfig} -e /dev/stderr
'';
restart = true;
options = [
"shares-console"
"pass-cs-fd"
];
};
};
상태: 동작함. 제 테스트에서는 모든 dinit 옵션을 올바르게 렌더링합니다.
아직 이 워크플로를 문서로 쓰진 않았지만, 동작하는 건 알고 있습니다: nix build로 easykubenix 매니페스트를 빌드하면서 nix-csi 볼륨 안의 dinix 시작 스크립트를 참조하게 만들 수 있고, 그 매니페스트 derivation을 빌드 캐시에 푸시한 다음 easykubenix/kluctl 배포 스크립트로 매니페스트를 적용하면 전체 컨테이너 라이프사이클을 Nix를 통해 관리할 수 있습니다. 즉 완전히 빈 컨테이너 이미지를 실행할 수도 있습니다(Kubernetes 때문에 이미지는 여전히 필요하지만), 그러면서도 Nix의 힘을 사용할 수 있습니다.
물론, 사용 사례에 따라 easykubenix만, nix-csi만, dinix만 따로 사용해도 됩니다.
안정 릴리스 없이 소프트웨어를 발표하는 게 다소 이르다는 걸 알지만, 이 프로젝트들은 한동안 띄엄띄엄 작업해 왔고 커뮤니티의 의견을 정말로 듣고 싶습니다.
제가 하고 싶은 다른 것들: terragrunt용 terranix 같은 것. 모듈 시스템 만세!
궁금하다면 레포지토리를 클론하고 각 레포에서 nix repl --file .을 실행해 탐색해 보세요. 물지 않습니다!
그러니 질문도 하고, 피드백도 주세요… 좋아요와 구독, 알림 설정, 멤버십 가입, Patreon도(/s). 진행되면서 질문에 답이 달리면 이 글을 계속 업데이트해 보겠습니다 
Matrix에서 인사해요: Nix: Cloud Native
읽기 12분
이런 것들에 대한 개요 튜토리얼을 해주시면 좋겠습니다. 도입/채택에 큰 도움이 될 거예요. 영상이든 자세한 블로그든요. 완벽함을 추구하지 마세요.
그리고 아래 주제에 대한 튜토리얼도 추천하고 요청드립니다:
k0s 같은 현대적이고 쉬운 바이너리 배포판으로 “nix 방식으로 Kubernetes를 배우기”를 어떻게 시작하는지. 아니면 설치 부분은 빼고, 사용하는 방법에 대해서라도요. 저처럼 k8s 초보가 더 잘 이해하는 데 도움이 될 것 같습니다.
매주 1~2주마다 새로운 Kubernetes 도구가 많이 나오지만, 저는 nix 생태계 기반 도구들을 신뢰합니다.
감사합니다
문서를 개선하려는 의도는 분명히 있습니다. 다만 아직은 이 프로젝트들의 “기능성” 파트에 있습니다(easykubenix는 일주일도 안 됐고, 셋 중 가장 어린 프로젝트이며, kubenix의 API나 코드젠에 완전히 만족하지 못해 만들게 됐습니다).
글에서 NixOS용 Kubeadm 모듈을 썼다고 언급했는데, 이제는 다른 사람도 쓸 수 있도록 프로젝트화할 때가 된 것 같습니다!
K3s도 NixOS에서 사용 가능하긴 한데, 저는 K3s에서 항상 높은 유휴 CPU를 겪고도 원인을 못 찾겠더라고요. 반면 Kubeadm은 유휴 상태가 너무 조용해서 게임할 때도 끄지 않습니다! 
(+containerd 74MB res)
Kubeadm을 실행하기 위한 모듈과 함께, Nix가 설치된 어떤 Linux 배포판에서도 Kubelet + CRI의 라이프사이클을 관리하는 KNs라는 dinix 모듈을 작성할 계획입니다
이제 Kubernetes 커뮤니티가 Kubeadm을 받아들일 때입니다. 업스트림 Kubernetes가 정답입니다! 
(저는 Kubernetes용 NixOS 모듈을 좋아한 적이 없어요. Kubeadm이 이미 하는 일을 너무 많이 복제하는 것 같습니다.)
피드백 감사합니다! 곧 업데이트 드릴게요 
정말 반갑네요. 저는 nix-snapshotter를 더 해보고 싶었는데, 당신 구현은 그게 가졌을 핵심 제약 중 하나를 없애주네요. 계속 지켜보겠습니다!
좋은 말씀 감사합니다! 네, CSI 레이어로 가면 어떤 Kubernetes 배포판에서도 쓸 수 있게 됩니다. OpenShift 같은 CRI-O 기반도 포함해서요. GKE, EKS, AKE… 뭐든요!
privileged 컨테이너를 실행할 수 있는 곳이라면 다 됩니다 
이번 주에 quay에 이미지를 올리기 위해 좀 노력했으니 곧
배포 가이드가 나와서 직접 테스트할 수 있을 거예요. 또한 상태가 깨졌을 때 정리할 수 있도록 언배포 코드도 작성할 예정입니다. 아직 ingress-nginx 수준의 견고함은 아닙니다
아직 가비지 컬렉션 구현도 해야 하고(이미 gcroots는 설정합니다), 여기저기 작은 개선도 몇 가지 남아 있습니다.
이건 nix와 k8s로 가능한 범위를 밀어붙이는 엄청난 작업이라고 생각하고, 저는 이게 실제로 어떻게 동작하는지 거의 이해하지 못합니다. 그게 답답하면서도 동시에 흥미롭습니다. 특히 nix-csi 부분이요.
제가 고민인 건 엔드투엔드로 어떻게 쓸지입니다. 예를 들어 일상적인 nix/OS 사용을 어떻게 해서 nix-csi로 가져가느냐는 건데, 예시 두 가지가 있습니다: (a) home-manager가 있는 flake 기반 nixOS 설정이 있는데, 사용자에게 나눠줄 수 있는 미리 빌드된 dev nixOS 컨테이너를 nix-csi로 돌리고 싶습니다. 그리고 사용자는 home-manager 부분만 지정하면 되게요 (b) 빌드와 CI용 flake가 있는 rust 프로젝트가 있는데, 그 프로젝트의 dev 버전이나 CI 잡을 nix-csi로 실행하고 싶습니다.
안부 인사
Kubernetes 안에서 완전한 NixOS를 실행할 수는 있지만, systemd 같은 것들 때문에 컨테이너가 privileged여야 합니다. 이런 워크로드에는 dinix나 NixNG가 더 적합합니다. home-manager도 NixOS 모듈로서 동작할 수 있습니다(그래서 HM activation script가 시작 시 실행되겠죠(?)). 약간의 노력을 들이면 dinix에서 HM activation script를 실행해 완전한 사용자 환경을 구성할 수도 있을 겁니다 
nix-csi는 storePath 또는 Nix 표현식을 받아 루트 derivation을 컨테이너 내 /nix/var/result 아래에서 사용 가능하게 만듭니다(그래서 podspec에서 /nix/var/result/bin/hello를 실행할 수 있습니다). storePath를 쓰면 바이너리 캐시에서 가져오고, 표현식을 쓰면 파드가 스케줄된 노드에서 빌드합니다(이건 결국 바뀔 예정인데, 빌드를 Kubernetes 잡 안에서 실행하도록 해서 별도 노드에 빌드를 스케줄할 수 있게 할 계획입니다).
가비지 컬렉션과 관련해 아직 해결해야 할 자잘한 문제들이 있습니다. DaemonSet의 초기 이미지에 있는 nix 데이터베이스가 한 번만 복사되는 이슈가 있는데(그게 맞긴 합니다), 그 뒤 이미지가 바뀌면 /nix/var/result를 덮어쓰고 데이터베이스에 제대로 등록하지 않은 새 패키지를 가져오게 됩니다. 그러면 gcroot가 무효가 되어 CSI가 자기 자신을 가비지 컬렉션해버립니다. 보시다시피 문제는 이미 꽤 잘 이해되고 있고, 머지않아 해결될 겁니다 
(선택 사항인) 클러스터 내 캐시에는 nix-serve-ng를 사용하고 있습니다. 현재는 GC 프로세스 없이 그냥 막 집어넣고 있어요. 의도는 derivation이 캐시에 복사될 때 등록 시간을 다시 써서 “첫 빌드”가 아니라 “마지막 빌드”를 반영하게 만드는 것입니다. 그 다음 regtime 기준으로 정렬해 가장 오래된 엔트리를 제거하려는 대체 GC를 실행할 겁니다. 이에 대한 기능하는 POC는 있지만 아직 할 일이 남아 있습니다.
솔직히 말하면, gRPC를 받아서 몇 가지 명령으로 바꾸는 Python으로 만든 ‘과장된 스크립트 러너’입니다:
gRPC(NodePublishVolume) → nix build → nix path-info --recursive → rsync --one-file-system --archive --hard-links → nix-store --dump-db $pathinforesult | NIX_STATE_DIR=$nixvarforcontainer nix-store --load-db → ln → mount
중간에 mkdir 같은 것들이 좀 섞여 있지만, 파고들어 보면 놀랄 만큼 단순합니다 
질문 감사합니다. 다른 궁금한 것이 있으면 더 설명해 드릴게요!
GC 업데이트: (제가 겪었던 마지막 ‘진짜 블로커급’ 버그였는데) 게스트용 Nix 데이터베이스를 임포트/익스포트하는 스크립트를 재사용했고, 잘 되는 것 같습니다. 다만 급하게 처리하느라 엄격한 테스트를 하진 못했습니다.
여전히 gcroot가 없는 경로에 대해 시간 기반 GC를 하고 싶습니다. 유용할지 여부를 판단하는 꽤 좋은 지표라고 생각합니다 
훌륭한 작업 감사합니다! 정말 흥미로워 보이네요.
혹시 못 보셨을까 해서요. 정말 잘 발표된 것 같았습니다. 이 글을 보고 있다면 luxzeitlos에게도 감사 인사를.
다음에 대한 생각이 궁금합니다: k8nix.nixosModules.kubernetesMultiYamlAddons ?

공유해줘서 감사합니다! Kubernetes 컴포넌트에 대한 좋은 토크예요. Kubernetes가 “진짜로 어떻게 동작하는지” 모르면 확실히 좋은 입문입니다.
다만 Kubernetes 모듈을 사용하는 그의 접근은 “잘못됐다”고 생각합니다. Kubeadm은 검증된 경로이고 “사용되어야 합니다”.
다음은 Kubeadm을 NixOS로 다시 구현하려 하기보다, NixOS에서 Kubeadm을 시작하는 데 도움이 되는 NixOS 모듈입니다.
# Minimal configuration for ClusterAPI
{
config,
pkgs,
lib,
inputs,
...
}:
{
config = {
environment.systemPackages = with pkgs; [
kubernetes
cri-tools
];
# Configure containerd CRI
virtualisation.containerd = {
enable = true;
settings = {
# Use systemd cgroups, this will tell Kubernetes to do the same
plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options.SystemdCgroup = true;
# Force /opt/cni/bin as CNI folder (all CNI's expect this and put their binaries here)
plugins."io.containerd.grpc.v1.cri".cni.bin_dir = lib.mkForce "/opt/cni/bin";
};
};
# Install default CNI plugins
system.activationScripts.cni-install = {
text = # bash
''
${lib.getExe pkgs.rsync} --recursive --mkpath ${pkgs.cni-plugins}/bin/ /opt/cni/bin/
'';
};
# Kubelet systemd unit
# See https://github.com/kubernetes/release/blob/50887114b4fe77d28cc62776eaf03187d7f35120/cmd/krel/templates/latest/kubeadm/10-kubeadm.conf
systemd.services.kubelet = {
description = "kubelet: The Kubernetes Node Agent";
wantedBy = [ "multi-user.target" ];
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
requires = [ "containerd.service" ];
unitConfig = {
# This is our own custom thing, better than imperatively enabling the service
ConditionPathExists = "/var/lib/kubelet/config.yaml";
};
# Kubelet needs "mount" binary.
path = with pkgs; [
util-linuxMinimal
];
serviceConfig = {
EnvironmentFile = [
"-/var/lib/kubelet/kubeadm-flags.env"
"-/etc/sysconfig/kubelet"
];
ExecStart = "${lib.getExe' pkgs.kubernetes "kubelet"} $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS";
Restart = "always";
RestartSec = 1;
RestartMaxDelaySec = 60;
RestartSteps = 10;
};
environment = {
KUBELET_KUBECONFIG_ARGS = "--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf";
KUBELET_CONFIG_ARGS = "--config=/var/lib/kubelet/config.yaml";
};
};
### Code from below is taken from clusterctl default templating stuff
boot.kernelModules = [
"overlay"
"br_netfilter"
"nf_conntrack"
];
boot.kernel.sysctl = {
# Recommended for Kubernetes
"net.bridge.bridge-nf-call-iptables" = 1;
"net.bridge.bridge-nf-call-ip6tables" = 1;
"net.ipv4.ip_forward" = 1;
};
};
}
또한 Kubernetes 특화 YAML은 YAML을 거치기보다 Kubernetes 스타일 API를 사용해서 JSON을 생성하는 편이 더 낫다고 생각합니다. 멀티 도큐먼트 JSON은 이렇게 합니다:
pkgs.writeTextFile "multidoc.yaml" (builtins.toJSON {
apiVersion = "v1";
kind = "List";
items = [ { apiVersion = ""; kind = ""; .... } ];
};)
이건 --output=json을 사용할 때 Kubernetes가 여러 리소스를 반환하는 방식입니다.
전반적으로 Kubernetes 컴포넌트를 배우기엔 좋은 토크지만, 그는 잘못된 방향으로 가고 있다고 생각합니다. 위의 모듈이 NixOS를 Kubeadm 및 ClusterAPI 호환으로 만드는 데 필요한 전부이고, 이런 도구들은 사용되도록 만들어졌습니다 
질문 감사합니다. 약간 무시하는 듯 보일 수 있다는 건 알지만 그게 제 의도는 아닙니다. 저는 그냥 “올바른 일을 하고” 싶습니다 
그 예시는 멋지지만, nix/OS 관련 k8s 글들은 실제로 노드를 어떻게 조인하는지 생략하는 경우가 많습니다. 제 이해로는 그 예시가 “그냥” 노드를 시작하는 건가요? 댓글에 링크된 YAML들도 확인해 봐야겠네요.
토크 관련해서는, 제 기억이 맞다면 인증서 부분에 아주 집중했는데 저는 그게 k8s 배포의 핵심이라고 생각한 적이 없고, 그리고 그 토크는 제가 다른 토크와 혼동한 게 아니라면 사실상 Nix로 Kubernetes를 다룬다기보다 Kubernetes 컴포넌트 설명에 더 가까웠던 것 같습니다.
저건 노드를 시작하는 것도 아닙니다. 그저 NixOS가 kubeadm과 함께 동작할 수 있도록 설정할 뿐이에요 with kubeadm
저는 오늘도 ClusterAPI(내부적으로 kubeadm 사용)로 노드를 배포할 때 이 모듈을 사용합니다!
노드 조인은 제가 직접 설명하기보다 kubeadm token과 kubeadm join을 참고하는 게 가장 좋다고 생각합니다. 컨트롤 플레인 초기화에는 kubeadm init이 필요합니다.
kubeadm을 설정하는 NixOS 모듈도 만들기 시작했는데, 공유하기엔 아직 준비가 안 됐습니다. YAML과 systemd 디펜던시를 렌더링하기 위한 복잡한 로직 덩어리라 난장판이에요 
저는 k8s를 많이 다뤄서 그게 문제가 아닙니다. nix 밖에서 무엇을 써야 하는지는 알지만, k8s의 많은 부분이 결국 일관성(eventually consistent)이라 nix로 이를 어떻게 다룰지에 대한 결론을 아직 못 내렸습니다.
그리고 추가로 “사전 추론 비용”이 있습니다. 예를 들어 k8s를 준비한 VM 전체를 프로비저닝해야 하나? 그러면 머신 IP가 필요해서 apiserver addr을 kubeadm init에 넘겨야 하죠. 그런데 그 IP는 그 머신 로컬 값이라, 제가 평소 노드 배포에 쓰는 nix 파일에 마법처럼 나타나진 않습니다. 아마 답은 ‘이건 nix로 해결할 문제가 아니다’일 수도 있고, 어떤 레지스트리/DNS/서비스 디스커버리 레지스트리에 IP를 퍼블리시하고 노드는 활성화 스크립트에서 소비하게 하는 편이 낫다는 것일 수도 있습니다.
이런 것들을 탐색해 보려고 합니다. 다만 저는 아직 제 “일반적인” 데스크톱 설정 전체를 nix/OS로 마이그레이션하는 중이라, 가끔씩만 nix+k8s를 훑어보고 있습니다.
Nix로 joinConfigurations를 작성하고 colemna, deploy-rs, nixops 같은 배포 도구로 노드에 배포할 수도 있습니다. kubelet보다 먼저 실행되는 kubeadm용 systemd 유닛을 만들어야 할 거예요. 이에 대해 여기에서 조금 작업했지만, 지금 형태로 누가 쓰는 건 원치 않습니다. 기껏해야 해킹 수준이에요(저는 CAPI 전용으로 Hetzner에 단일 노드 클러스터를 올릴 때 씁니다).
하지만 솔직히 저는 이걸 위해 Nix가 적절한 도구라고 생각하진 않습니다. 대신 ClusterAPI가 이미 대부분의 일을 해줍니다.
{ ... }:
{
config = {
services.cloud-init = {
enable = true;
btrfs.enable = false;
settings = {
cloud_init_modules = lib.mkForce [
"write-files"
"update_hostname"
]; # Some issue with some module crashing with default config
};
extraPackages = with pkgs; [
nixos-rebuild-ng
kubernetes
];
};
};
}
이건 제가 ClusterAPI와 앞서 올린 “kubelet 모듈”과 함께 쓰는 cloud-init 모듈입니다. ClusterAPI의 “preKubeadmCommands”에서 cloud-init이 설정한 호스트네임을 반영하기 위해 NixOS rebuild를 수행합니다. Hetzner가 DHCP를 제공해서 아직 IP 주소 같은 걸 다룰 필요는 없었고, IPv6는 더 조사해야 합니다.
ClusterAPI와 노드 관리 관련 작업도 더 공개하려고 합니다. 현재는 클라이언트 작업용 비공개 레포에 있는데, 다행히 코드 소유권은 제가 갖고 있어서 “OSS 표준”에 맞게 정리만 하면 됩니다 
업데이트: 이제 nix-csi에서 가비지 컬렉션이 동작합니다. 아주 기본적이고 CSI 노드 시작 시에만 가비지를 수거합니다. 시간 기반 GC는 언젠가 구현할 예정입니다 
편집: Python에 능숙한 분이 있다면 코드 리뷰를 정말 받고 싶습니다. 저는 평균 정도예요 
0.1.3 “릴리스”.
CNI 플러그인을 왜 /opt로 rsync하나요?
containerd가 nix store에서 찾도록 그냥 경로만 지정해도 되지 않나요?
그건 CNI들이 스스로 설치하는 “잘 알려진” 경로입니다. Cilium, Calico, Flannel 등은 그 디렉터리를 hostPath로 DaemonSet에 마운트하고, CRI를 위해 CNI 바이너리를 거기에 복사합니다. 이는 Nix로 CNI를 빌드해 설치할 수 없거나 하고 싶지 않을 때를 위한 겁니다(일반 Kubernetes 운영자에게 그걸 기대하긴 어렵죠).
Cilium은 템플릿이고, Calico는 비템플릿이며, flannel은 템플릿입니다 
참고: 실제로는 “진짜 CNI들”이 스스로 설치를 하므로 굳이 복사할 필요는 없습니다. 이건 그냥 범용적인 “충분히 괜찮은” 해결책이에요. 저는 단일 노드 설정에서는 bridge CNI를, 다중 노드 설정에서는 Cilium을 씁니다. 이렇게 하면 어떤 경우든 잘 동작합니다. 다중 노드에서는 복사된 CNI들이 사용되지 않습니다.
편집: activation에서 /var/lib/etcd를 만들고, 가능하면 chattr +C를 시도하는 것도 추가할 만합니다. CoW 데이터베이스는 좋지 않고 etcd는 그걸 전적으로 운영자에게 맡깁니다 
임포트된 YAML(Helm 또는 importyaml) 안의 리스트를 attrset으로 변환하는 기능을 추가했습니다. 모든 요소가 name 속성을 가진 리스트는 name으로 인덱싱되고, 그 외 리스트는 strinteger로 인덱싱됩니다.
# Rendered by Helm in a fixed output derivation (thanks kubenix)
# Notice spec.containers.hcloud-cloud-controller-manager :)
nix-repl> eval.config.kubernetes.resources.kube-system.Deployment.hcloud-cloud-controller-manager.spec.template.spec.containers.hcloud-cloud-controller-manager.args
{
"0" = "--allow-untagged-cloud";
"1" = "--cloud-provider=hcloud";
"2" = "--feature-gates=CloudControllerManagerWatchBasedRoutesReconciliation=false";
"3" = "--route-reconciliation-period=30s";
"4" = "--webhook-secure-port=0";
"5" = "--leader-elect=false";
_numberedlist = true;
}
즉 임포트된 매니페스트의 어떤 단일 값이든 아주 쉽게 오버라이드할 수 있습니다! 
initContainers는 리스트 순서가 실행 순서를 제어하기 때문에, 네임드가 아니라 숫자 인덱스 attrset으로 변환하는 특별 케이스가 있습니다.
@ElvishJerricco modprobe 설정에서 attrset을 선호하자는 말이 맞았던 것 같네요… 
nix-csi에 volumeAttribute $system(보통 x86_64-linux)을 storepath로 설정하는 지원을 구현했습니다. 그러면 nix-csi는 빌드를 하지 않고, 설정된 캐시에서 해당 경로를 가져오기만 합니다.
easykubenix에는 생성된 매니페스트를 바이너리 캐시에 푸시하는 지원을 구현했습니다. 다음을 설정하면
volumeAttributes.${pkgs.system} = pkgs.hello;
매니페스트가 pkgs.hello에 의존하게 되고, pkgs.hello도 캐시에 함께 푸시됩니다. 즉 nix-csi가 가져올 수 있게 됩니다 
@claes 이제 원격 Kubernetes 클러스터에서 로컬 애플리케이션을 빠르고 쉽게 개발하는 좋은 예시가 생겼네요!
최종 사용자 관점에서 시작해 보겠습니다. 저는 파드에서 pkgs.hello를 실행하고 싶습니다. 당신 도구로 그걸 어떻게 하나요?