DevOps

Kubernetes (以下简称 K8S) 是 Docker 推出之后最热门的容器编排技术,然而想在本地将 K8S 跑起来,并不像我们想象的那么容易。存在以下几点「问题」:

  • 网络:K8S 里面的一些镜像在国内很难将其 pull 下来,当然这可以通过代理、镜像站等方式解决。
  • 资源:在内存资源不这么充裕的本地开发环境,去部署一个 K8S 集群,这无疑不是一个明智的选择。

那么有没有什么方案可以更优雅更轻量更快速搭建一个 K8S 集群呢?答案就是 K3D

目前主流的本地 k8s 运行方式有很多

  • minikube 仅支持单节点,但是我们期望可以跑一个集群的方式,方便我们去 Mock 节点宕机之后 K8S 自动调度的 case ✖️
  • microk8s 是 Ubuntu 生态里提供的一个可以单机运行的 k8s 版本,配合 Ubuntu 生态的 multipass,可以模拟多节点,但是在本就资源紧张的本地环境,通过虚拟机的方式模拟多节点,显然并不是我想要的 ✖️
  • kind 是一个基于 Docker 构建 Kubernetes 集群的工具,Kubernetes in Docker ✔️
  • k3d 是一个可以让 k3s 运行在 Docker 中的工具,相比于 kind ,启动速度更快,占用资源更小,也是本文采取的方案 ✅
关于 k3d 以及 kind 的对比,可以参考 K3d vs Kind 谁更适合本地研发

1. 什么是 K3D

k3s 是 Rancher 公司推出非常快速且轻量级的完全兼容的 Kubernetes 发行版(CNCF 认证)
k3d 是一个可以让 k3s 运行在 Docker 中的工具,它提供了一个简单的 CLI 来创建、运行和删除具有 1 到 N 个节点的 Kubernetes 集群
  • 最大程度减轻了外部依赖性,仅需要 kernel 和 cgroup 挂载。
  • 占用资源比完整版的 K8S 少了不少
  • 内置了很多组件,开箱即用,而且每一个组件都是可替换的
详情参考官方文档 什么是 K3s?

2. 通过 docker-machine 启动 Docker 服务

官方提供的 Docker Desktop 是基于 WSL2 实现的,需要开启 Hyper-V 功能。 这样会使整个 Windows 都跑在虚拟机中,导致某些虚拟化相关的应用不正常 (比如某些模拟器),而且内存占用也不太可控。
本文采用了基于 boot2docker 的方式运行 Docker 服务,定制性更灵活一些。

2.1 安装必备工

这里强烈推荐使用 Git for Windows 自带的 MinGW 命令行SHELL,使开发体验更加贴近与 Linux。以下操作均在 Git Bash 中进行

首先需要安装虚拟机软件 VirtualBox
然后需要下载如下命令工具并添加到环境变量 PATH

本文中上面这些工具下载到了 D:\Docker\bin,并将 D:\Docker\bin 添加到环境变量中
同时也配置了如下环境变量,将虚拟机文件的储存位置修改为 D 盘,避免占用系统空间
  • MACHINE_STORAGE_PATH=D:\Docker

~/.profile 文件添加如下内容配置命令行自动补全

source <(kubectl completion bash)
source <(k3d completion bash)

2.2 使用 boot2docker 启动 Docker 引擎

下面创建了一个磁盘大小为 60000 MB,CPU 使用 4 个核心的虚拟机

docker-machine create --virtualbox-cpu-count 4 --virtualbox-disk-size 60000 --virtualbox-memory 4096 --virtualbox-no-share default
# 每次使用 docker 时都需要执行如下命令
eval $(docker-machine env --shell bash default)

稍等片刻,当出现以下日志时,说明 Docker 服务已启动完成

docker.png

第一次创建 Docker 实例会下载 boot2docker.iso 作为启动镜像,国内用户可以通过添加参数 --virtualbox-boot2docker-url https://cdn.dragonfly.fun/iso/boot2docker.iso 加速镜像下载

3 使用 k3d 启动 k3s 集群

3.1 创建 k3s 节点

首先我们尝试创建包含主节点和容器仓库的集群

eval $(docker-machine env --shell bash)
k3d cluster create --api-port 6443 \
  -p 0.0.0.0:80:80@loadbalancer \
  --k3s-arg "--disable=traefik@server:0" \
  --registry-create registry:0.0.0.0:5000

当出现下面的日志时,k3s 集群就创建成功了

k3d.png

此时,我们按照日志提示,运行 kubectl cluster-info 查看下当前集群的信息

运行 kubectl get pod -o wide -A 命令,当所有 Pod 的状态都是 Running 或者 Done 的时候,集群就初始化完毕了

  • 如果遇到 cgroups: cannot find cgroup mount destination: unknown. 的错误提示,请执行如下命令
cat << EOF | docker-machine ssh default sudo sh -
mkdir /sys/fs/cgroup/systemd
mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd
EOF

3.2 安装 K3S 组件

  • Helm 是 Kubernetes 的首选包管理工具

而 K3s 不需要任何特殊的配置就可以使用 Helm 命令行工具,如下命令使用 Helm CRD 部署 traefik 服务

cat << EOF | kubectl apply -f -
apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
  name: traefik
  namespace: kube-system
spec:
  chart: traefik
  repo: https://helm.traefik.io/traefik
EOF

下面的例子是使用 Traefik CRD 开启内置的仪表盘

cat << EOF | kubectl apply -f -
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: traefik-dashboard
  namespace: kube-system
spec:
  entryPoints:
  - web
  routes:
  - match: Host(\`traefik.domain.com\`)
    kind: Rule
    services:
    - name: api@internal
      kind: TraefikService
EOF
更多配置参考 https://docs.rancher.cn/docs/k3s/helm/_index

4. 使用 KinD 启动 k8s 集群

KinD 顾名思义 Kubernetes in Docker,是一个使用 Docker 容器在本地运行 Kubernetes 集群的工具。相比 k3d,Kind 更贴近原生 Kubernetes,适合用于开发测试 Kubernetes 原生组件。

4.1 安装 KinD 命令行工具

首先下载最新版本的 KinD https://kind.sigs.k8s.io/dl/latest/kind-windows-amd64

cat << EOF | kind create cluster --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
  apiServerAddress: "$(docker-machine ip)"
  apiServerPort: 6443
nodes:
- image: kindest/node:v1.20.7
  extraPortMappings:
  - containerPort: 32080
    hostPort: 80
  - containerPort: 32443
    hostPort: 443
EOF
参数描述参考 https://kind.sigs.k8s.io/docs/user/quick-start#configuring-your-kind-cluster

4.2 使用 Helm 部署 Ingress

https://docs.nginx.com/nginx-ingress-controller/
# 生成测试用 SSL 证书
openssl req -x509 -nodes -newkey rsa:4096 -keyout tls.key -out tls.crt -days 3650 -subj "/CN=kube"
kubectl create secret tls ingress-wildcard-tls -n kube-system --cert=tls.crt --key=tls.key

# 安装控制器
cat << EOF | helm install nginx -n kube-system --repo https://helm.nginx.com/stable nginx-ingress --values -
controller:
  image:
    tag: "alpine"
  service:
    type: NodePort
    httpPort:
      nodePort: 32080
    httpsPort:
      nodePort: 32443
  wildcardTLS:
    secret: "kube-system/ingress-wildcard-tls"
  setAsDefaultIngress: true
EOF
cat << EOF | helm install traefik -n kube-system --repo https://helm.traefik.io/traefik traefik --values -
persistence:
  enabled: true
service:
  type: NodePort
ports:
  web:
    nodePort: 32080
  websecure:
    nodePort: 32443
    tls:
      enabled: true
ingressClass:
  enabled: true
  isDefaultClass: true
EOF

4.3 部署 K8S 控制台

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/alternative.yaml
# 添加 ingress 路由 
kubectl create ing -n kubernetes-dashboard dashboard --rule="domain.com/*=kubernetes-dashboard:80,tls"
# 添加用户权限
kubectl create serviceaccount admin-user -n kubernetes-dashboard 
kubectl create clusterrolebinding admin-user --serviceaccount=kubernetes-dashboard:admin-user --clusterrole=cluster-admin
# 获取 Token
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')

参考文档:

Comment

This is just a placeholder img.