为什么使用 LXD
首先,我们搭建的是一个 Kubernetes 集群,所以需要多台计算机,这对于一个普通初学者来说是承担不起的,由于是实践环境(学习环境),我们可以使用虚拟来虚拟出多台计算机,但这会浪费计算机大量的内存与磁盘资源,下面是虚拟机与 LXD 的对比:
- 共享内核,且不需要预分配内存,使用多少就是多少
- 由于共享内核,需要的内核功能只要在主机操作一遍即可
- 因为容器的体量小,创建、删除的速度极快,出现误操作可以直接删除重来
注意
-
本文章仅在 ArchLinux 环境下有效,在 Ubuntu 等环境可能会出现 cgroups 功能缺失,内核模块加载失败等错误,若仍要参考此文章请自行在网络上搜索问题的解决方案。
-
很不幸,Kubernetes 暂不支持在使用 Btrfs 文件格式的主机的容器中部署,当然,如果要坚持使用 LXD 创建 Kubernetes 集群,可以参考以下解决方案:
- 将空闲分区格式化为 ext4 文件格式并挂载。
- 创建虚拟磁盘(img 文件)格式化为 ext4 文件格式并挂载。
- 创建虚拟机。
-
本文章使用了大量的国内镜像源,如果您在境外或可以直接访问 Docker、Kubernetes 等网站建议使用官方软件源与镜像
创建存储池
下面指令将使用 /mnt/vol/lxd
目录创建一个名为 k8s
的存储池,如有特殊需求请自行更改位置。
因下文配置含有存储池相关,不建议更改名称。
lxc storage create k8s dir source=/mnt/vol/lxd
创建容器配置模板
下面指令将创建一个名为 k8s
的配置模板:
lxc profile create k8s && echo 'name: k8s
config:
boot.autostart: "true"
linux.kernel_modules: ip_tables,ip6_tables,netlink_diag,nf_nat,overlay,br_netfilter
limits.memory.swap: "false"
raw.lxc: |
lxc.apparmor.profile=unconfined
lxc.mount.auto=proc:rw sys:rw cgroup:rw
lxc.cgroup.devices.allow=a
lxc.cap.drop=
security.nesting: "true"
security.privileged: "true"
description: "K8s on LXD"
devices:
eth0:
name: eth0
nictype: bridged
parent: lxdbr0
type: nic
root:
path: /
pool: k8s
type: disk' | lxc profile edit k8s
验证配置是否创建:
lxc profile show k8s
创建容器
使用配置 k8s
创建一个名为 k-master
的 Debian 11 容器
创建非 Ubuntu 容器需要设置镜像,请参考:ArchLinux 安装 LXD#添加国内镜像
lxc launch -p k8s mirrors:debian/11 k-master
你可以选择在配置完 master 控制平面节点后一个个创建 node 节点容器,也可以使用下面指令一次性创建三个 node 容器:
for N in 1 2 3 ; do lxc launch -p k8s mirrors:debian/11 k-node$N ; done
查看容器列表:
lxc list
注意:以下内容直到 拉取部署 K8s 所需的 Images
章节前的内容,需要在所有容器中操作一遍。
登录容器并更新系统
请自行将下文的 <容器名>
关键词替换为你环境中的容器名
lxc exec <容器名> -- /bin/bash
解决 kubelet 无法读取 kmsg 的问题:(原理创建/dev/kmsg 到/dev/null 的链接,需要重启生效)
echo 'L /dev/kmsg - - - - /dev/null' > /etc/tmpfiles.d/kmsg.conf
设置 apt 镜像并完全更新系统
echo 'deb http://mirrors.aliyun.com/debian/ bullseye main contrib non-free
deb http://mirrors.aliyun.com/debian/ bullseye-updates main contrib non-free
deb http://mirrors.aliyun.com/debian/ bullseye-backports main contrib non-free
deb http://mirrors.aliyun.com/debian-security/ bullseye-security main contrib non-free' | \
tee /etc/apt/sources.list > /dev/null
apt update && apt full-upgrade
注: 以下步骤与物理机安装无区别。除无需再次设置内核流量转发外,其余部分均可参考:使用 kubeadm 引导集群
安装 Docker
添加 Docker 软件源并安装 Docker
# 安装 apt-https 和 gpg 密钥支持
apt install apt-transport-https ca-certificates curl gnupg -y
# 下载并存储密钥
curl -fsL http://mirrors.aliyun.com/docker-ce/linux/debian/gpg | \
gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 添加软件源
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] http://mirrors.aliyun.com/docker-ce/linux/debian bullseye stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装
apt update && apt install docker-ce docker-ce-cli containerd.io -y
创建 Docker 配置并设置镜像源与 cgroupdriver
echo \
'{
"registry-mirrors": ["https://dockerhub.azk8s.cn"],
"exec-opts": ["native.cgroupdriver=systemd"],
"storage-driver": "overlay2",
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
}
}' | tee /etc/docker/daemon.json > /dev/null
重启 Docker 使配置生效:(Docker 安装后会默认启动并设置开机自启动,无需再次手动设置)
systemctl restart docker
systemctl status docker # 查看状态
安装 kubeadm 等工具
# 下载并存储密钥
curl -fsL http://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | \
gpg --dearmor -o /usr/share/keyrings/kubernetes-archive-keyring.gpg
# 添加软件源
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] http://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main" | \
tee /etc/apt/sources.list.d/kubernetes.list > /dev/null
# 安装
apt update && apt install -y kubelet kubeadm kubectl
拉取部署 K8s 所需的 Images
更简单的方法:参考 使用 kubeadm 初始化控制平面节点 的 (当前不可用,原因:coredns)注4
,但 coredns 仍需要使用下列步骤拉取,但是要在修改 tag 时将 k8s.gcr.io 改为你参数指定的值
由于网络原因,我们无法直接使用 kubeadm 部署,但是我们可以通过提前从镜像源拉取并打 tag 的方式来解决。
使用 kubeadm config images list
指令获取当前版本的镜像列表,比如在我写这篇文章的时候版本如下:
k8s.gcr.io/kube-apiserver:v1.22.1
k8s.gcr.io/kube-controller-manager:v1.22.1
k8s.gcr.io/kube-scheduler:v1.22.1
k8s.gcr.io/kube-proxy:v1.22.1
k8s.gcr.io/pause:3.5
k8s.gcr.io/etcd:3.5.0-0
k8s.gcr.io/coredns/coredns:v1.8.4
将其中的 k8s.gcr.io
修改为 registry.aliyuncs.com/google_containers
就可从阿里的镜像中拉取,但 coredns 除外,coredns 位于 Docker 官方仓库,我们只需直接拉取就行了,但是要注意:k8s.gcr.io 中的 coredns 的版本有 v
,Docker 官方的没有
拉取镜像:
docker pull registry.aliyuncs.com/google_containers/kube-apiserver:v1.22.1
docker pull registry.aliyuncs.com/google_containers/kube-controller-manager:v1.22.1
docker pull registry.aliyuncs.com/google_containers/kube-scheduler:v1.22.1
docker pull registry.aliyuncs.com/google_containers/kube-proxy:v1.22.1
docker pull registry.aliyuncs.com/google_containers/pause:3.5
docker pull registry.aliyuncs.com/google_containers/etcd:3.5.0-0
docker pull coredns/coredns:1.8.4 # 去掉 v
拉取完之后只需要按照 docker tag <修改后名称> <修改前名称>
的格式打上 tag 便可让 kubeadm 检测到并使用
docker tag registry.aliyuncs.com/google_containers/kube-apiserver:v1.22.1 k8s.gcr.io/kube-apiserver:v1.22.1
docker tag registry.aliyuncs.com/google_containers/kube-controller-manager:v1.22.1 k8s.gcr.io/kube-controller-manager:v1.22.1
docker tag registry.aliyuncs.com/google_containers/kube-scheduler:v1.22.1 k8s.gcr.io/kube-scheduler:v1.22.1
docker tag registry.aliyuncs.com/google_containers/kube-proxy:v1.22.1 k8s.gcr.io/kube-proxy:v1.22.1
docker tag registry.aliyuncs.com/google_containers/pause:3.5 k8s.gcr.io/pause:3.5
docker tag registry.aliyuncs.com/google_containers/etcd:3.5.0-0 k8s.gcr.io/etcd:3.5.0-0
docker tag coredns/coredns:1.8.4 k8s.gcr.io/coredns/coredns:v1.8.4
使用 kubeadm 初始化控制平面节点
注:
- 在此操作之前强烈建议使用
kubelet --cgroup-driver=systemd
检测 kubelet 是否能正常运行 - 若要重新初始化请先使用
kubeadm reset
删除之前初始化产生的配置 - 更多 kubeadm 参数请参考:初始化控制平面节点
可设置--image-repository
参数选择用于拉取控制平面镜像的容器仓库,以达到加速的目的,例如:--image-repository registry.aliyuncs.com/google_containers
或--image-repository k8s-gcr-io.mirrors.sjtug.sjtu.edu.cn
(对 coredns 并不生效),当然使用kubeadm init
的时候也需要加上。- 在
kubeadm init
之前运行kubeadm config images pull
,以验证与容器镜像仓库的连通性,并提前拉取镜像。 - 命令行参数
--kubernetes-version
会影响到镜像的版本。
kubeadm init \
--pod-network-cidr=10.244.0.0/16 \
--control-plane-endpoint=10.161.141.34 \
--apiserver-advertise-address=10.161.141.34 # 填你的eth0 IP
等待几分钟即可
要使非 root 用户可以运行 kubectl,请运行以下命令, 它们也是 kubeadm init 输出的一部分:
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
或者,如果你是 root 用户,则可以运行:
export KUBECONFIG=/etc/kubernetes/admin.conf
加入节点
节点容器也需要拉取 k8s.gcr.io/pause
这个 Image
在 node 容器中运行(其中的参数来自 kubeadm init
,请注意查看)
kubeadm join --token <token> <control-plane-host>:<control-plane-port> --discovery-token-ca-cert-hash sha256:<hash>
安装 Flannel Pod 网络插件
docker pull quay.mirrors.ustc.edu.cn/coreos/flannel:v0.14.0
docker tag quay.mirrors.ustc.edu.cn/coreos/flannel:v0.14.0 quay.io/coreos/flannel:v0.14.0
kubectl apply -f https://raw.fastgit.org/coreos/flannel/v0.14.0/Documentation/kube-flannel.yml
由于 LXC 容器的限制,容器无法直接修改内核配置,会导致 kube-proxy
和 kube-flannel
无法正常启动。临时解决办法:使用 kubectl logs kube-proxy-<填写自己的pod名> --namespace kube-system
查看日志,并在主机中将参数手动写入 /sys/module/nf_conntrack/parameters/hashsize
和 /proc/sys/net/netfilter/nf_conntrack_max
(具有风险,谨慎操作)
kubectl get nodes
kubectl get pods --namespace kube-system
若 STATUS
为 Ready
、Running
则表明部署成功
(可选) 部署 Dashboard UI
默认情况下不会部署 Dashboard。可以通过以下命令部署:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yaml
上面是官方网的文档,我们可以用FastGit来加速一下
kubectl apply -f https://raw.fastgit.org/kubernetes/dashboard/v2.3.1/aio/deploy/recommended.yaml
kubectl proxy
问题
coredns 停滞在 Pending 状态
这一行为是预期之中的,因为系统就是这么设计的。 kubeadm 的网络供应商是中立的,因此管理员应该选择 安装 pod 的网络插件。 你必须完成 Pod 的网络配置,然后才能完全部署 CoreDNS。 在网络被配置好之前,DNS 组件会一直处于 Pending
状态。
查看 Pods 运行状态
# 查看所有 pods
kubectl get pods --all-namespaces
kubectl get pods --namespace kube-system
# 查看单个 pod 日志
kubectl logs <name>