Skip to content

Commit

Permalink
Merge pull request #114737 from johanot/kubernetes-1.20-with-containerd
Browse files Browse the repository at this point in the history
kubernetes: 1.19.5 -> 1.20.4 (dockerd -> containerd)
  • Loading branch information
zowoq committed Mar 7, 2021
2 parents 38f0072 + 7b5c38e commit 05f5a98
Show file tree
Hide file tree
Showing 15 changed files with 217 additions and 197 deletions.
9 changes: 9 additions & 0 deletions nixos/doc/manual/release-notes/rl-2105.xml
Expand Up @@ -788,6 +788,15 @@ self: super:
and use Maturin as their build tool.
</para>
</listitem>
<listitem>
<para>
Kubernetes has <link xlink:href="https://kubernetes.io/blog/2020/12/02/dont-panic-kubernetes-and-docker/">deprecated docker</link> as container runtime.
As a consequence, the Kubernetes module now has support for configuration of custom remote container runtimes and enables containerd by default.
Note that containerd is more strict regarding container image OCI-compliance.
As an example, images with CMD or ENTRYPOINT defined as strings (not lists) will fail on containerd, while working fine on docker.
Please test your setup and container images with containerd prior to upgrading.
</para>
</listitem>
</itemizedlist>
</section>
</section>
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Expand Up @@ -1053,6 +1053,7 @@
./testing/service-runner.nix
./virtualisation/anbox.nix
./virtualisation/container-config.nix
./virtualisation/containerd.nix
./virtualisation/containers.nix
./virtualisation/nixos-containers.nix
./virtualisation/oci-containers.nix
Expand Down
7 changes: 3 additions & 4 deletions nixos/modules/services/cluster/kubernetes/addons/dns.nix
Expand Up @@ -3,7 +3,7 @@
with lib;

let
version = "1.6.4";
version = "1.7.1";
cfg = config.services.kubernetes.addons.dns;
ports = {
dns = 10053;
Expand Down Expand Up @@ -55,9 +55,9 @@ in {
type = types.attrs;
default = {
imageName = "coredns/coredns";
imageDigest = "sha256:493ee88e1a92abebac67cbd4b5658b4730e0f33512461442d8d9214ea6734a9b";
imageDigest = "sha256:4a6e0769130686518325b21b0c1d0688b54e7c79244d48e1b15634e98e40c6ef";
finalImageTag = version;
sha256 = "0fm9zdjavpf5hni8g7fkdd3csjbhd7n7py7llxjc66sbii087028";
sha256 = "02r440xcdsgi137k5lmmvp0z5w5fmk8g9mysq5pnysq1wl8sj6mw";
};
};
};
Expand Down Expand Up @@ -156,7 +156,6 @@ in {
health :${toString ports.health}
kubernetes ${cfg.clusterDomain} in-addr.arpa ip6.arpa {
pods insecure
upstream
fallthrough in-addr.arpa ip6.arpa
}
prometheus :${toString ports.metrics}
Expand Down
42 changes: 35 additions & 7 deletions nixos/modules/services/cluster/kubernetes/apiserver.nix
Expand Up @@ -238,14 +238,40 @@ in
type = int;
};

apiAudiences = mkOption {
description = ''
Kubernetes apiserver ServiceAccount issuer.
'';
default = "api,https://kubernetes.default.svc";
type = str;
};

serviceAccountIssuer = mkOption {
description = ''
Kubernetes apiserver ServiceAccount issuer.
'';
default = "https://kubernetes.default.svc";
type = str;
};

serviceAccountSigningKeyFile = mkOption {
description = ''
Path to the file that contains the current private key of the service
account token issuer. The issuer will sign issued ID tokens with this
private key.
'';
type = path;
};

serviceAccountKeyFile = mkOption {
description = ''
Kubernetes apiserver PEM-encoded x509 RSA private or public key file,
used to verify ServiceAccount tokens. By default tls private key file
is used.
File containing PEM-encoded x509 RSA or ECDSA private or public keys,
used to verify ServiceAccount tokens. The specified file can contain
multiple keys, and the flag can be specified multiple times with
different files. If unspecified, --tls-private-key-file is used.
Must be specified when --service-account-signing-key is provided
'';
default = null;
type = nullOr path;
type = path;
};

serviceClusterIpRange = mkOption {
Expand Down Expand Up @@ -357,8 +383,10 @@ in
${optionalString (cfg.runtimeConfig != "")
"--runtime-config=${cfg.runtimeConfig}"} \
--secure-port=${toString cfg.securePort} \
${optionalString (cfg.serviceAccountKeyFile!=null)
"--service-account-key-file=${cfg.serviceAccountKeyFile}"} \
--api-audiences=${toString cfg.apiAudiences} \
--service-account-issuer=${toString cfg.serviceAccountIssuer} \
--service-account-signing-key-file=${cfg.serviceAccountSigningKeyFile} \
--service-account-key-file=${cfg.serviceAccountKeyFile} \
--service-cluster-ip-range=${cfg.serviceClusterIpRange} \
--storage-backend=${cfg.storageBackend} \
${optionalString (cfg.tlsCertFile != null)
Expand Down
33 changes: 25 additions & 8 deletions nixos/modules/services/cluster/kubernetes/default.nix
Expand Up @@ -5,6 +5,29 @@ with lib;
let
cfg = config.services.kubernetes;

defaultContainerdConfigFile = pkgs.writeText "containerd.toml" ''
version = 2
root = "/var/lib/containerd/daemon"
state = "/var/run/containerd/daemon"
oom_score = 0
[grpc]
address = "/var/run/containerd/containerd.sock"
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image = "pause:latest"
[plugins."io.containerd.grpc.v1.cri".cni]
bin_dir = "/opt/cni/bin"
max_conf_num = 0
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes."io.containerd.runc.v2".options]
SystemdCgroup = true
'';

mkKubeConfig = name: conf: pkgs.writeText "${name}-kubeconfig" (builtins.toJSON {
apiVersion = "v1";
kind = "Config";
Expand Down Expand Up @@ -222,14 +245,9 @@ in {
})

(mkIf cfg.kubelet.enable {
virtualisation.docker = {
virtualisation.containerd = {
enable = mkDefault true;

# kubernetes needs access to logs
logDriver = mkDefault "json-file";

# iptables must be disabled for kubernetes
extraOptions = "--iptables=false --ip-masq=false";
configFile = mkDefault defaultContainerdConfigFile;
};
})

Expand Down Expand Up @@ -269,7 +287,6 @@ in {
users.users.kubernetes = {
uid = config.ids.uids.kubernetes;
description = "Kubernetes user";
extraGroups = [ "docker" ];
group = "kubernetes";
home = cfg.dataDir;
createHome = true;
Expand Down
40 changes: 2 additions & 38 deletions nixos/modules/services/cluster/kubernetes/flannel.nix
Expand Up @@ -8,16 +8,6 @@ let

# we want flannel to use kubernetes itself as configuration backend, not direct etcd
storageBackend = "kubernetes";

# needed for flannel to pass options to docker
mkDockerOpts = pkgs.runCommand "mk-docker-opts" {
buildInputs = [ pkgs.makeWrapper ];
} ''
mkdir -p $out
# bashInteractive needed for `compgen`
makeWrapper ${pkgs.bashInteractive}/bin/bash $out/mk-docker-opts --add-flags "${pkgs.kubernetes}/bin/mk-docker-opts.sh"
'';
in
{
###### interface
Expand All @@ -43,43 +33,17 @@ in
cniVersion = "0.3.1";
delegate = {
isDefaultGateway = true;
bridge = "docker0";
bridge = "mynet";
};
}];
};

systemd.services.mk-docker-opts = {
description = "Pre-Docker Actions";
path = with pkgs; [ gawk gnugrep ];
script = ''
${mkDockerOpts}/mk-docker-opts -d /run/flannel/docker
systemctl restart docker
'';
serviceConfig.Type = "oneshot";
};

systemd.paths.flannel-subnet-env = {
wantedBy = [ "flannel.service" ];
pathConfig = {
PathModified = "/run/flannel/subnet.env";
Unit = "mk-docker-opts.service";
};
};

systemd.services.docker = {
environment.DOCKER_OPTS = "-b none";
serviceConfig.EnvironmentFile = "-/run/flannel/docker";
};

# read environment variables generated by mk-docker-opts
virtualisation.docker.extraOptions = "$DOCKER_OPTS";

networking = {
firewall.allowedUDPPorts = [
8285 # flannel udp
8472 # flannel vxlan
];
dhcpcd.denyInterfaces = [ "docker*" "flannel*" ];
dhcpcd.denyInterfaces = [ "mynet*" "flannel*" ];
};

services.kubernetes.pki.certs = {
Expand Down
39 changes: 33 additions & 6 deletions nixos/modules/services/cluster/kubernetes/kubelet.nix
Expand Up @@ -23,7 +23,7 @@ let
name = "pause";
tag = "latest";
contents = top.package.pause;
config.Cmd = "/bin/pause";
config.Cmd = ["/bin/pause"];
};

kubeconfig = top.lib.mkKubeConfig "kubelet" cfg.kubeconfig;
Expand Down Expand Up @@ -125,6 +125,18 @@ in
};
};

containerRuntime = mkOption {
description = "Which container runtime type to use";
type = enum ["docker" "remote"];
default = "remote";
};

containerRuntimeEndpoint = mkOption {
description = "Endpoint at which to find the container runtime api interface/socket";
type = str;
default = "unix:///var/run/containerd/containerd.sock";
};

enable = mkEnableOption "Kubernetes kubelet.";

extraOpts = mkOption {
Expand Down Expand Up @@ -235,16 +247,24 @@ in
###### implementation
config = mkMerge [
(mkIf cfg.enable {

environment.etc."cni/net.d".source = cniConfig;

services.kubernetes.kubelet.seedDockerImages = [infraContainer];

boot.kernel.sysctl = {
"net.bridge.bridge-nf-call-iptables" = 1;
"net.ipv4.ip_forward" = 1;
"net.bridge.bridge-nf-call-ip6tables" = 1;
};

systemd.services.kubelet = {
description = "Kubernetes Kubelet Service";
wantedBy = [ "kubernetes.target" ];
after = [ "network.target" "docker.service" "kube-apiserver.service" ];
after = [ "containerd.service" "network.target" "kube-apiserver.service" ];
path = with pkgs; [
gitMinimal
openssh
docker
util-linux
iproute
ethtool
Expand All @@ -254,8 +274,12 @@ in
] ++ lib.optional config.boot.zfs.enabled config.boot.zfs.package ++ top.path;
preStart = ''
${concatMapStrings (img: ''
echo "Seeding docker image: ${img}"
docker load <${img}
echo "Seeding container image: ${img}"
${if (lib.hasSuffix "gz" img) then
''${pkgs.gzip}/bin/zcat "${img}" | ${pkgs.containerd}/bin/ctr -n k8s.io image import -''
else
''${pkgs.coreutils}/bin/cat "${img}" | ${pkgs.containerd}/bin/ctr -n k8s.io image import -''
}
'') cfg.seedDockerImages}
rm /opt/cni/bin/* || true
Expand Down Expand Up @@ -306,6 +330,9 @@ in
${optionalString (cfg.tlsKeyFile != null)
"--tls-private-key-file=${cfg.tlsKeyFile}"} \
${optionalString (cfg.verbosity != null) "--v=${toString cfg.verbosity}"} \
--container-runtime=${cfg.containerRuntime} \
--container-runtime-endpoint=${cfg.containerRuntimeEndpoint} \
--cgroup-driver=systemd \
${cfg.extraOpts}
'';
WorkingDirectory = top.dataDir;
Expand All @@ -315,7 +342,7 @@ in
# Allways include cni plugins
services.kubernetes.kubelet.cni.packages = [pkgs.cni-plugins];

boot.kernelModules = ["br_netfilter"];
boot.kernelModules = ["br_netfilter" "overlay"];

services.kubernetes.kubelet.hostname = with config.networking;
mkDefault (hostName + optionalString (domain != null) ".${domain}");
Expand Down
1 change: 1 addition & 0 deletions nixos/modules/services/cluster/kubernetes/pki.nix
Expand Up @@ -361,6 +361,7 @@ in
tlsCertFile = mkDefault cert;
tlsKeyFile = mkDefault key;
serviceAccountKeyFile = mkDefault cfg.certs.serviceAccount.cert;
serviceAccountSigningKeyFile = mkDefault cfg.certs.serviceAccount.key;
kubeletClientCaFile = mkDefault caCert;
kubeletClientCertFile = mkDefault cfg.certs.apiserverKubeletClient.cert;
kubeletClientKeyFile = mkDefault cfg.certs.apiserverKubeletClient.key;
Expand Down
6 changes: 2 additions & 4 deletions nixos/modules/services/networking/flannel.nix
Expand Up @@ -162,10 +162,7 @@ in {
NODE_NAME = cfg.nodeName;
};
path = [ pkgs.iptables ];
preStart = ''
mkdir -p /run/flannel
touch /run/flannel/docker
'' + optionalString (cfg.storageBackend == "etcd") ''
preStart = optionalString (cfg.storageBackend == "etcd") ''
echo "setting network configuration"
until ${pkgs.etcdctl}/bin/etcdctl set /coreos.com/network/config '${builtins.toJSON networkConfig}'
do
Expand All @@ -177,6 +174,7 @@ in {
ExecStart = "${cfg.package}/bin/flannel";
Restart = "always";
RestartSec = "10s";
RuntimeDirectory = "flannel";
};
};

Expand Down

0 comments on commit 05f5a98

Please sign in to comment.