k8s

resource

资源 组织 类型
devops-exercises bregman-arie 基础

k8s

什么是 k8s

  • 开源的容器编排工具

  • 由 google 开发

  • 帮助在不同的部署环境中管理容器应用

k8s 解决的问题

  • 将传统铁板一块的应用转为微服务管理

  • 增加容器的使用便利

  • 高效管理成千上百的容器的能力

k8s 提供的编排功能

  • 高可用且无关机时延

  • 可扩展性或高性能

  • 容灾,备份和还原

links:

安装

docker runtime 安装 k8s

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# 安装docker

# centos
yum install -y yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# ubuntu
apt-get update
apt-get install ca-certificates curl gnupg
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update && apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# debian
apt-get update
apt-get install ca-certificates curl gnupg
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update && apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 配置docker

cat >/etc/docker/daemon.json<<EOF
{
"default-runtime": "nvidia",
"exec-opts": [
"native.cgroupdriver=systemd"
],
"runtimes": {
"nvidia": {
"args": [],
"path": "nvidia-container-runtime"
}
},
"builder": {
"gc": {
"defaultKeepStorage": "20GB",
"enabled": true
}
},
"experimental": true,
"features": {
"buildkit": true
},
"insecure-registries": [
"harbor.baijiayun.com",
"docker.huaguisystems.com"
],
"registry-mirrors": [
"https://docker.mirrors.sjtug.sjtu.edu.cn",
"https://reg-mirror.qiniu.com"
]
}
EOF

systemctl restart docker

# 安装 k8s 软件工具

# Update sysctl settings for Kubernetes networking
cat >>/etc/sysctl.d/kubernetes.conf<<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system

# 配置k8s源并安装

# centos
cat <<EOF | tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF
yum updatee && yum install -y kubelet kubeadm kubectl
# debian/ubuntu
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list
# 国内
curl -s https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main" | tee /etc/apt/sources.list.d/kubernetes.list

apt update && apt install -y kubelet kubeadm kubectl

# 可选:为kubelet 关闭交换优化性能

swapoff -a

# centos用于临时关闭 SELinux 安全策略

setenforce 0

# 可选:为了实现 docker 使用的 cgroup-driver 和 kubelet 使用的 cgroup 一致,根据具体情况修改kubelet 配置

echo 'KUBELET_EXTRA_ARGS="--cgroup-driver=systemd"' | tee -a /etc/default/kubelet

systemctl restart kubelet

配置 k8s 集群

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 查看配置需要的k8s镜像
kubeadm config images list
kubeadm config images list | xargs docker pull

kubeadm init \
--image-repository registry.aliyuncs.com/google_containers \
# 根据网络配置api及service
# --pod-network-cidr=10.244.0.0/16 \
# --apiserver-advertise-address=10.16.8.135 \
# --service-cidr=10.96.0.0/16

# 使用阿里云镜像源
kubeadm config images pull \
--image-repository registry.aliyuncs.com/google_containers

# 更换时区到国内
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
#安装ntpdate工具
apt-get install ntpdate
#设置系统时间与网络时间同步
ntpdate cn.pool.ntp.org
#然后将时间更新到硬件上:
hwclock --systohc

containerd 安装 k8s

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 配置containerd

# 为kubelet 关闭交换优化性能

swapoff -a

# Update sysctl settings for Kubernetes networking
cat >>/etc/sysctl.d/kubernetes.conf<<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system

curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list

apt update && apt install -y kubelet kubeadm kubectl

containerd config default | tee /etc/containerd/config.toml
systemctl restart containerd
systemctl status containerd
# https://www.youtube.com/watch?v=k3iexxiYPI8

参考:

QA

kubelet.service failed
1
2
3
4
5
6
7
8
9
10
11
12
kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)
Active: activating (auto-restart) (Result: exit-code) since Wed 2023-07-19 11:44:14 CST; 7s ago
Docs: https://kubernetes.io/docs/
Process: 2856971 ExecStart=/usr/bin/kubelet (code=exited, status=1/FAILURE)
Main PID: 2856971 (code=exited, status=1/FAILURE)
Tasks: 0
Memory: 0B
CGroup: /system.slice/kubelet.service

Jul 19 11:44:14 localhost.localdomain systemd[1]: Unit kubelet.service entered failed state.
Jul 19 11:44:14 localhost.localdomain systemd[1]: kubelet.service failed.

kubelet 启动失败
kubelet 服务启动失败。可以通过查看 kubelet 的日志来获取更多信息,使用以下命令:

1
2
journalctl -fu kubelet
journalctl -xe
validate service connection: CRI v1 runtime API is not implemented

错误日志:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@localhost ~]# containerd --version
containerd containerd.io 1.6.21 3dce8eb055cbb6872793272b4f20ed16117344f8
[root@localhost ~]# docker info |grep Cgroup
Cgroup Driver: cgroupfs
WARNING: bridge-nf-call-ip6tables is disabled
Cgroup Version: 1
[root@localhost ~]# cat /var/lib/kubelet/kubeadm-flags.env
--container-runtime=docker
[root@localhost ~]# kubeadm init --pod-network-cidr=10.244.0.0/16
[init] Using Kubernetes version: v1.27.3
[preflight] Running pre-flight checks
[WARNING Swap]: swap is enabled; production deployments should disable swap unless testing the NodeSwap feature gate of the kubelet
error execution phase preflight: [preflight] Some fatal errors occurred:
[ERROR CRI]: container runtime is not running: output: time="2023-07-19T15:29:19+08:00" level=fatal msg="validate service connection: CRI v1 runtime API is not implemented for endpoint \"unix:///var/run/containerd/containerd.sock\": rpc error: code = Unimplemented desc = unknown service runtime.v1.RuntimeService"
, error: exit status 1

解决 1: 将 containerd 配置文件 /etc/containerd/config.toml 的 containerd.toml中disabled_plugins = ["cri"]注释

[!TIP]
cri 是 Container Runtime Interface 的缩写,这是 Kubernetes 用来与容器运行时进行交互的接口。如果在 containerd.toml 文件中禁用了 cri,那么 containerd 将无法作为 Kubernetes 的容器运行时使用.

解决 2: 使用 Docker 作为其容器运行时。可以通过编辑 /etc/default/kubelet 文件来完成这个操作。在这个文件中,需要添加或修改以下行:

1
KUBELET_EXTRA_ARGS=--container-runtime=docker

然后,重新启动 kubelet 服务:

1
systemctl restart kubelet
如何确定 k8s 运行时
1
kubectl describe nodes | grep 'Container Runtime Version'

基于 docker 为: Container Runtime Version: docker://24.0.4
基于 containerd 为: Container Runtime Version: containerd://1.7.1-k3s1

架构

  • 整体架构图
    k8s arch.

  • 控制面架构图
    image.

  • 多控制面及多节点架构
    image.

k8s 主要组件

Node & Pod

容器的抽象

  • pod 是 k8s 最小单元

  • pod 是基于容器的抽象

  • 通常一个 pod 只包含一个应用

  • 每个 pod 都有 ip, 当 pod 挂掉时,重启的 pod 会生成新的 ip.

image.

Service & Ingress

容器间通信

  • service 持有不变的 ip.

  • service 声明周期和 Pod 不是唯一绑定关系.

image.

  • ingress 为服务提供了统一的访问方式

  • ingress 屏蔽了 ip 及 port 的传统方式

image.

ConfigMap & Secret

容器运行外部配置

  • ConfigMap 提供了容器外部配置管理方式

  • Secert 提供加密数据的配置,可在 Deployment/Pod 中引用
    image.

Volume

数据持久化

  • 用于提供数据持久化配置

  • 本地机器,远程或集群外部位置
    image.

Deploment & StatefulSet

提供容器副本部署,deployment 下所有配置都由 k8s 处理

  • Deploment 提供了多次多节点部署的能力 (replica)

  • Deploment 节点间由 svc 提供统一访问 ip

  • Deploment 多节点间提供了负载均衡能力

  • StatefulSet 用于部署状态应用,如 MySQL,MonogDB,ES

  • StatefulSet 部署 DB 并不容易,通常部署于 k8s 集群外
    image.

k8s 配置

  • kubctl k8s cli

  • yaml 配置声明模板

  • etcd 保存了所有的 k8s 组件当前状态

  • 每个配置由 3 个部分组成 metadata, specification, status

  • status 由 k8s 从 控制面的 etcd 拉取结果 和 metadata/specification 对比生成

1
2
3
4
5
6
7
8
9
# 1)metadata of configuration
apiVersion: xxx
kind: xxx
metadata:
...
# 2)specification of the kind
spec:
...
# 3)status generated and added by k8s

k8s yaml 完整配置

流量请求路径

browser -> (webapp external service) -> webapp(pod) -> (mongodb internal service) -> mongodb(pod)

配置文件:

1
2
3
4
5
6
7
8
9
10
# 1.configmap: mongo-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
# config map name
name: mongo-config
# key-value format
data:
# mongo service and endpoint
mongo-url: mongo-service
1
2
3
4
5
6
7
8
9
# 2.secret: mongo-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: mongo-secret
type: Opaque # base64-encoded
data:
mongo-user: bW9uZ291c2Vy # echo -n mongouser | base64
mongo-password: bW9uZ29wYXNzd29yZA== # echo -n mongopassword | base64
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# 3.mongo deployment: mongo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mongo-deployment
# 1.can naming any k8s component a label
# 2.label are key/value pairs
# 3.identifier to a collection
# 4.key app is used to matched in selector to connection between deployments and pods(connecting pods to deploments)
# 5.connecting services to deployments
labels:
app: mongo
spec:
replicas: 1
selector:
matchLabels:
app: mongo
# 1.blueprint for pods
# 2.apply to pod
# 3.has its own "metadata" and "spec" section and configure for pod
template:
metadata:
labels:
app: mongo
spec:
containers:
- name: mongodb
image: mongo:5.0 # which image
ports:
- containerPort: 27017
# image init environment
env:
- name: MONGO_INITDB_ROOT_USERTNAME
valueFrom:
secretKeyRef:
# same as mongo-secret of memtadata in mongo-secret.yaml
name: mongo-secret
# same as mongo-user of data in mongo-secret.yaml
key: mongo-user
- name: MONGO_INITDB_ROOT_PASSWORD
valueFrom:
secretKeyRef:
# same as mongo-secret of memtadata in mongo-secret.yaml
name: mongo-secret
# same as mongo-password of data in mongo-secret.yaml
key: mongo-password
---
# 4.mongo service: mongo.yaml
apiVersion: v1
kind: Service
metadata:
# same as mongo-url in configmap to define the service url to mongo
name: mongo-service
spec:
# select pods to forwaord the request to service(connecting services to deployments)
selector:
# same as app in template connecting service to Pods
app: mongo
ports:
# request-> (port:27017)mongo service -> (targetPort:27017)pod(contianerPort:27017)
- protocol: TCP
# service port
port: 27017
# contianerPort of Deployment
targetPort: 27017 # same as contianerPort in template
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# 3.webapp deployment: webapp.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp-deployment
# 1.can naming any k8s component a label
# 2.label are key/value pairs
# 3.identifier to a collection
# 4.key app is used to matched in selector to connection between deployments and pods
labels:
app: webapp
spec:
replicas: 1
selector:
matchLabels:
app: webapp
# main port: blueprint for pods
template: # has its own "metadata" and "spec" section and configure for pod
metadata:
labels:
app: webapp
spec:
containers:
- name: webapp
# which image
image: nanajanashia/k8s-demo-app:v1.0
ports:
- containerPort: 3000
env:
- name: USER_NAME
valueFrom:
name: mongo-secret
key: mongo-user
- name: USER_PWD
valueFrom:
name: mongo-secret
key: mongo-password
- name: DB_URL
valueFrom:
configMapKeyRef:
name: mongo-config
key: mongo-url
---
# 4.webapp service: webapp.yaml
apiVersion: v1
kind: Service
metadata:
# same as mongo-url in configmap
name: webapp-service
spec:
# Default = ClusterIp (an internal service)
# NodePort here,NodePort Service is accessible on each worker node's ip address
type: NodePort
# select pods to forwaord the request to service
selector:
# same as app in template connecting service to Pods
app: webapp
ports:
# request-> (port:3000)webapp service -> (targetPort:3000)pod(contianerPort:3000)
- protocol: TCP
# service port
port: 3000
# contianerPort of Deployment
targetPort: 3000 # same as contianerPort in template
# expose the service on each node's ip at a static port <NodeIP>:<NodePort>(here 3000:30100)
nodePort: 30100 # 30000-32768
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
kubectl apply -f mongo-config.yaml
kubectl apply -f mongo-secret.yaml
kubectl apply -f mongo.yaml
kubectl apply -f webapp.yaml
# interacting with k8s clusuter
kubectl get all
kubectl get configmap
kubectl get secret
kubectl get pod
kubectl get --help
kubectl describe service webapp-service
kubectl describe pod < pod name >
kubectl logs < pod name > -f
kubectl get svc
kubectl get node
kubectl get node -o wide # It can be accessed in a browser at address internal-ip:30100

Namespace

  • 提供以名字空间的方式管理资源

  • 每个名字空间需要定义自己的 configmap,不同空间通过 service 访问

  • default 默认提供的名字空间,默认创建的资源都位于该空间下。

  • kube-system 不要改动或创建该空间,提供了系统处理,master, kubectl 处理

  • kube-public 提供了包含集群信息的 configMap 信息

  • kube-node-lease 提供了感知节点心跳、节点可用

通过 kubectl 创建

1
2
# create namespace [namespace name]:创建名字空间
kubectl create namespaec my-ns

通过配置文件创建

1
2
3
4
5
6
7
apiVersioni: v1
kind: ConfigMap
metadata:
name: mysql-configmap
namespace: my-ns
data:
db_url: mysql-service.database

为什么用 Namespace

  • 结构化管理组件

  • 团队间避免冲突

  • 共享服务

  • 命名空间限制访问及资源

在空间中创建组件

  • 当未指定空间时在默认空间创建

1
2
3
4
kubectl apply -f mysql-configmap.yaml
kubectl get configmap
# 获取默认空间中的 configmap
kubectl get configmap -n default

Ingress

避免 service ip 及 port 暴露

image.

External Service:通过分配 external IP 给服务 (nodePort of ports in Service),使用 ip:port 外部访问

Ingress: 通过分配 routing 规则推动请求到内部服务 (internal service),这里 http 只代表推动请求
image.
Host: 需为合理的域名地址,映射域名地址到节点 IP 为入口点
image.

配置 Ingress

  • 匹配所有映射规则,可配置单个 domain 映射多服务 (多个 path) 或多 domain 映射规则

  • 管理所有重定向

  • 集群入口控制

  • 大多是由第三方实现,云服务商提供 Ingress 访问(自有虚拟负载均衡)

  • K8s Nginx Ingress Controller(不需要自己实现)

image.
image.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# dasahboard-ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: dashboard-ingress
namespacce: kubernetes-dashboard
spec:
rules:
- host: dashboard.com
http:
paths:
- backend:
serviceNamme: kubernetes-dashboard
servicePort: 80
1
2
3
4
5
6
kubectl apply -f dashboard-ingress.yaml
# 查看 ingress ip
kubectl get ingress -n kubernetes-dashboard --watch
vim /etc/hosts # add 'ip dashboard.com' domain map
# 查看 ingress 默认 backend
kubectl describe ingress dashboard-ingress -n kubernetes-dashboard

Ingress 常用配置方法

  • 单个 domain 配置多个映射路径
    image.

  • 多个 host 配置
    image.

  • https 配置
    image.

HPA、KPA

  • HPA(Horizontal Pod Autoscaler):HPA 是一种 Kubernetes 控制器,用于根据 CPU 利用率或自定义指标自动调整 Pod 的副本数。当 Pod 的 CPU 利用率或自定义指标超过或低于一定阈值时,HPA 会自动增加或减少 Pod 的副本数,以确保应用程序的可用性和性能。要使用 HPA,需要在 Kubernetes 集群中启用 Metrics Server。

  • KPA(Kubernetes Pod Autoscaler):KPA 是一种 Kubernetes 控制器,用于根据内存使用率自动调整 Pod 的容器资源限制。当 Pod 的内存使用率超过一定阈值时,KPA 会自动增加 Pod 的容器资源限制,以确保应用程序的可用性和性能。与 HPA 不同,KPA 不会增加或减少 Pod 的副本数,而是仅调整 Pod 的容器资源限制。

持久化 in k8s

调度节点

scheduling

要将另一台机器加入到当前 Kubernetes 集群中,需要执行以下步骤:

  • 在要加入集群的机器上安装 Kubernetes 组件,包括 kubelet、kubeadm 和 kubectl 等。

  • 在当前集群中的任意一台机器上运行以下命令,生成加入集群所需的 token:

    1
    kubeadm token create --print-join-command
  • 将第 2 步生成的加入集群的命令复制到要加入集群的机器上执行。例如:

    1
    kubeadm join <ip_address>:<port> --token <token> --discovery-token-ca-cert-hash sha256:<hash>

    其中,ip_address 和 port 是当前 Kubernetes 集群中某一台机器的地址和端口号,token 和 hash 是第 2 步生成的。

  • 等待几分钟,新的节点就会加入到集群中,并自动同步集群中的配置信息。

  • 可以使用 kubectl 命令查看新节点是否已经加入到集群中:

    1
    kubectl get nodes

    如果新节点已经加入到集群中,那么可以看到它的状态为 Ready。

GPU

1
2
# 当部署单机k8s支持 GPU时,需要将control panel untaint,让master node 能调度
kubectl taint nodes --all node-role.kubernetes.io/master-

links:

reference

minikube

minikube 是一个轻量级的 Kubernetes 实现,用于在本地机器上运行单节点 Kubernetes 集群。它支持多个驱动程序(Docker、containerd、cri-o、Podman 等),可以在 Linux、macOS 和 Windows 上运行。

安装

  • Linux 上

1
2
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube

[!TIP] 常见错误

memory-swap is not allowed

若在 docker 中使用 minikube,则需要为 docker 容器开启 privileged 权限。

  • macOS 上

1
brew install minikube
  • Windows 上

1
choco install minikube

基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 初始化/启动 minikube 环境
minikube start --driver=docker [--memory=2g] [--kubernetes-version=1.22.1]

# 停止 minikube 环境
minikube stop

# 删除 minikube 环境
minikube delete

# 在 minikube 中查看 api version
minikube kubectl -- api-versions
kubectl api-versions

# 查看 minikube 状态
minikube status

# 查看 minikube IP
minikube ip

# 查看 minikube 版本
minikube version

# 查看 minikube dashboard
minikube addons enable metrics-server
minikube dashboard

# 启动 Kubernetes 代理
kubectl proxy

# 访问 Kubernetes 代理
http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/

运行应用

1
2
3
4
5
6
7
8
9
10
11
# 创建一个 deployment
kubectl create deployment hello-minikube --image=k8s.gcr.io/echoserver:1.4

# 暴露 deployment 服务
kubectl expose deployment hello-minikube --type=NodePort --port=8080

# 查看服务
kubectl get services

# 访问服务
minikube service hello-minikube

本地多集群模拟

在 minikube 中,如果需要创建多个本地集群,可以使用以下步骤:

使用不同的文件夹或文件名安装多个 minikube 实例。例如,可以使用以下命令安装两个 minikube 实例:

  • 安装多个 minikube 实例,创建两个名为 cluster-1cluster-2 的本地集群。

1
2
3
4
minikube start -p cluster-1
minikube start -p cluster-2
# 列出找到的集群
minikube profile list
  • 设置当前使用的 minikube 实例

在使用多个 minikube 实例时,需要使用 minikube profile 命令来设置当前使用的 minikube 实例。例如,要使用 cluster-1 实例,可以使用以下命令:

1
minikube profile cluster-1

然后,可以使用 kubectl 命令与该实例进行交互。

  • 删除 minikube 实例

如果不再需要某个 minikube 实例,可以使用以下命令删除它:

1
minikube delete -p cluster-1

这将删除名为 cluster-1 的 minikube 实例。

kind

使用 kind 创建本地 cluster。

安装完成后,可以使用 kind 来管理 Kubernetes 集群。一些常用的命令包括:

  • kind create cluster: 创建一个新的 Kubernetes 集群

  • kind delete cluster: 删除当前的 Kubernetes 集群

  • kind get clusters: 获取当前存在的 Kubernetes 集群

  • kind load docker-image: 将本地的 Docker 镜像加载到 kind 集群中

  • kind export kubeconfig: 将 kind 集群的 kubeconfig 导出到本地文件中

  • kind get nodes: 获取 kind 集群中的节点

gpu support

links:

kubectl

kubectl 是 Kubernetes 的命令行工具,用于管理 Kubernetes 集群,C/S 架构。

安装

  • Linux 上

1
2
3
4
5
6
7
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/

# 查看 kubectl 版本信息
kubectl version --client
kubectl version --client --output=yaml
  • macOS 上

1
brew install kubectl
  • Windows 上

1
choco install kubernetes-cli

基本使用

k8s cli 工具 kubectl,提供了操作基本组件及交互能力。

  • create/edit/delete deployment: 基于 deployment 的 CRUD 操作

  • get nodes/pod/service/replicaset/deployment: 查看 k8s 不同组件状态

  • logs [pod name]: 调试 pod

  • exec -it [pod name] – bash: 获取交互式终端

  • describe pod [pod name]: 获取 pod 详情

  • apply -f [file name]: 应用配置

  • delete -f [file name]: 删除配置

  • deployment 管理 replicaset

  • replicaset 管理 pod

  • pod 是容器的抽象

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 查看 API Version
kubectl api-version

# 查看 Kubernetes 集群信息
kubectl cluster-info

# subcommand
# - pod
# - service
# - deployment
# - replicaset
# - configmap
# - secret
# - ingress
# - pv
# - pvc
# - storageclass
# - envet
# - namespaces
# - componentstatuses
# - nodes

# 查看 Kubernetes 节点信息
kubectl get [subcommand]

# 查看 Kubernetes 详细信息
kubectl describe pod [name]

# 应用 Kubernetes 资源
kubectl apply -f [file]

# 删除 Kubernetes Pod
kubectl delete pod [pod-name]
kubectl delete pods -l <label> -n <namespace>

持久化存储

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 创建一个 PVC
kubectl apply -f https://k8s.io/examples/pods/storage/pv-claim.yaml

# 创建一个 Pod
kubectl apply -f https://k8s.io/examples/pods/storage/pv-pod.yaml

# 查看 Pod
kubectl get pod task-pv-pod

# 访问 Pod
kubectl exec -it task-pv-pod -- /bin/bash

# 在 Pod 中创建文件
echo "Hello World" > /usr/share/nginx/html/index.html

# 退出 Pod
exit

# 删除 Pod
kubectl delete pod task-pv-pod

# 创建一个新的 Pod
kubectl apply -f https://k8s.io/examples/pods/storage/pv-pod.yaml

# 查看 Pod
kubectl get pod task-pv-pod

# 访问 Pod
kubectl exec -it task-pv-pod -- /bin/bash

# 查看文件,输出 "Hello World",说明 index.html 是被持久化在 PV 中的
cat /usr/share/nginx/html/index.html

# 退出 Pod
exit

# 删除 PVC
kubectl delete pvc task-pv-claim

pod 调试

查看及调试 pod 详情,k8s 官方 POD 调试参考

1
2
3
4
5
6
7
8
9
# 创建 deployment: kubectl create deployment [pod name] --images=xxxx
kubectl create deployment nginx-depl --image=nginx
# 编辑 deployment nginx-depl: kubectl edit deployment [pod name]
# 查看 pod 信息发现自动创建一个新 deployment(running),旧的 deployment(terminating)。
kubectl edit deployment nginx-depl
# 删除 deployment :kubectl delete deployment [pod name]
kubectl delete deployment nginx-depl
# 查看 部署更新状态
kubectl rollout status [pod-name]
1
2
3
4
5
6
7
8
9
# 创建 mongo depl
kubectl create deployment mongo-depl --image=mongo
# 查看详情,状态为:mongo-depl(containerCreating)
kubectl get pod
kubectl describe pod mongo-depl-xxxx
# 查看 debug pod name: kubectl logs [pod name]
kubectl logs mongo-depl-xxxx
# 进入容器查看 kubectl exec -it [pod name] -- /bin/bash
kubectl exec -it mongo-depl-xxxx -- bash

k3d

gpu workload

links:

kustomize

kustomize 是一个用于 Kubernetes 部署的工具,它允许通过声明性配置来管理应用程序的部署。使用 Kustomize,可以轻松地管理多个环境(如开发、测试和生产)之间的差异,而无需为每个环境创建单独的部署文件。

Kustomize 使用 Kubernetes 的原生 API 来管理部署,因此它与 Kubernetes 的其他工具(如 kubectl)非常兼容。此外,Kustomize 还支持使用变量和模板来生成部署文件,使得管理大型应用程序变得更加容易。详情文档参考

安装

  • Linux

1
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"  | bash
  • Windows

1
choco install kustomize

helm

概念

helm 是 k8s 包管理 yaml 工具。

helm charts

  • 一堆 yaml 文件

  • 使用 helm 创建自己的 charts

  • 推送 chars 到 helm 仓库

  • 使用现有的 helm chars

  • 使用模板引擎配置 yaml

helm char 结构
image.

links:

安装

1
2
3
4
5
6
7
8
9
10
# 二进制下载安装
wget -o helm.tar.gz https://storage.googleapis.com/kubernetes-helm/helm-v2.13.1-linux-amd64.tar.gz
tar -zxvf helm.tar.gz
# 直接使用脚本安装
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# 国内安装 https://mirrors.huaweicloud.com/helm/
wget -o helm.tar.gz https://mirrors.huaweicloud.com/helm/v3.12.2/helm-v3.12.2-linux-amd64.tar.gz
tar -zxvf helm.tar.gz
cp linux-amd64/helm /usr/local/bin/

links:

基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# helm repo add [NAME] [URL] [flags]
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add brigade https://brigadecore.github.io/charts
helm repo update

# helm install [NAME] [CHART] [flags]
# 使用 my-values.yaml 值覆盖模板值安装
helm install --values=my-values.yaml <charname>
# 直接指定值覆盖安装,多个值用逗号隔开
helm install --set version=v2.0.0

# helm upgrade [RELEASE] [CHART] [flags]
helm upgrade -i nvdp nvdp/nvidia-device-plugin \
--namespace nvdp \
--create-namespace \
--set=runtimeClassName=nvidia \
--set=image.repository=registry.gitlab.com/nvidia/kubernetes/device-plugin/staging/k8s-device-plugin \
--set=image.tag=8b416016

# helm uninstall <release_name>
helm uninstall nvdp

image.

打包

  • helm create --generated-from-existing

helm create --generate-from-existing` 是 Helm 命令行工具中的一个命令,用于从现有的 Kubernetes 资源中生成 Helm 包的模板。

它的语法是:

1
helm create <chart-name> --generate-from-existing <existing-resource>

其中,<chart-name> 是 Helm 包的名称,<existing-resource> 是现有的 Kubernetes 资源名称。

该命令将会从现有的 Kubernetes 资源中生成 Helm 包的模板,包括 Chart.yamlvalues.yamltemplates 目录等文件。在生成的 Helm 包模板中,所有的 Kubernetes 资源将会被转换为 Helm 模板语法。

例如,假设我们有一个名为 my-app 的 Kubernetes 资源,我们可以使用以下命令生成一个 Helm 包模板:

1
helm create my-chart --generate-from-existing my-app

这将会在当前目录下生成一个名为 my-chart 的 Helm 包模板,其中包括 Chart.yamlvalues.yamltemplates 目录等文件,所有的 Kubernetes 资源都会被转换为 Helm 模板语法。

需要注意的是,该命令只能生成基本的 Helm 包模板,仍然需要手动编辑以适应特定的需求。此外,该命令仅适用于 Kubernetes 资源,不适用于其他类型的资源。

rancher

rancher 是一个 全栈式 的 Kubernetes 容器管理平台,为提供在任何地方都能成功运行 Kubernetes 的工具。

links:

安装

单节点通过容器安装,并访问浏览器访问 ip:443,设置 admin 密码,右下角可设置显示语言为简体中文。

1
2
3
4
5
docker run -d --restart=unless-stopped \
--name rancher \
-p 80:80 -p 443:443 \
--privileged \
rancher/rancher:v2.5.9

参考:

App

gpu

rke

Rancher Kubernetes Engine,简称 RKE,是一个经过 CNCF 认证的 Kubernetes 安装程序。

links:

k3s

K3s 是一个轻量级的 Kubernetes 发行版,它针对边缘计算、物联网等场景进行了高度优化。

links:

安装

Quickstart

使用脚本部署快速部署

1
2
3
4
5
curl -sfL https://get.k3s.io | sh -
# 国内加速
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh -
# 卸载时使用安装时的脚本卸载
k3s-uninstall.sh

运行此安装后,详情参考

  • K3s 服务将被配置为在节点重启后或进程崩溃或被杀死时自动重启.

  • 将安装其他实用程序,包括 kubectl, crictl, ctr, k3s-killall.shk3s-uninstall.sh

  • 将 kubeconfig 文件写入到 /etc/rancher/k3s/k3s.yaml,由 K3s 安装的 kubectl 将自动使用该文件.

1
2
3
# 查看安装的k3s服务
systemctl status k3s
journalctl -u k3s

Run with autok3s

AutoK3s 是用于简化 K3s 集群管理的轻量级工具,可以使用 AutoK3s 在任何地方运行 K3s 服务。

1
2
3
4
docker run -itd  --name autok3s \
--restart=unless-stopped \
-p 8080:8080 \
cnrancher/autok3s:v0.6.0

Run k3s in docker

在容器中运行 k3s 集群,镜像由 rancher 社区提供

1
2
3
4
5
6
7
docker run \
--privileged \
--name k3s-server-1 \
--hostname k3s-server-1 \
-p 6443:6443 \
-d rancher/k3s:v1.24.10-k3s1 \
server

运行起来后,通过 kubeconfig 进行访问

1
docker cp k3s-server-1:/etc/rancher/k3s/k3s.yaml ~/.kube/config

[!TIP]
如果需要 gpu 支持的 k3s 运行在容器中时,需要安装 cuda 及做相关配置

links:

Run k3s Based on docker

k3s 默认使用自己维护的 /var/lib/rancher/rke2/bin/containerd 作为运行时。以 docker 作为运行时需要指定参数: -s - --docker.

1
2
3
curl -sfL https://get.k3s.io | sh -s - --docker
# 国内
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_RKE2_MIRROR=cn sh -s - --docker

[!TIP]
可以将 k3s 配置到使用 docker 的运行时,方便资源管理

links:

Run k3s Based on containerd

k3s 默认使用自己维护的 /var/lib/rancher/rke2/bin/containerd 作为运行时,如果需要用自定义的 containerd 时,需指定参数 -s - --container-runtime-endpoint /run/containerd/containerd.sock

1
2
3
4
5
6
# 使用默认的containerd
curl -sfL https://get.k3s.io | sh -
# 使用自定义的containerd
curl -sfL https://get.k3s.io | sh -s - --container-runtime-endpoint /run/containerd/containerd.sock
# 国内
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_RKE2_MIRROR=cn sh -s - --container-runtime-endpoint /run/containerd/containerd.sock

[!TIP]
同时也可以将 docker 配置为使用自定义的 containerd, 方便资源管理

编辑 Docker 的 daemon.json 文件(通常位于 /etc/docker/daemon.json),添加以下内容,然后重启 docker 服务 systemctl restart docker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
// Set the execution options with native.cgroupdriver as systemd
"exec-opts": ["native.cgroupdriver=systemd"],

// Set the log driver as json-file
"log-driver": "json-file",

// Set the log options with a maximum size of 100m
"log-opts": {
"max-size": "100m"
},

// Set the storage driver as overlay2
"storage-driver": "overlay2",

// Set the containerd socket path
"containerd": "/run/containerd/containerd.sock"
}

这样,k3s 和 Docker 就会使用同一个 containerd 实例作为其容器运行时,在不考虑 docker 时优先使用 containerd。

QA

  • /var/lib/kubelet目录报Device or resource busy

1
2
# 先卸载,再删除
umount $(df -HT | grep '/var/lib/kubelet' | awk '{print $7}')

访问集群

存储在 /etc/rancher/k3s/k3s.yaml 的是部署的 k3 集群的 kubeconfig 文件,用于对 Kubernetes 集群的访问

1
2
3
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
kubectl get pods --all-namespaces
helm ls --all-namespaces

直接指定 kubeconfig

1
2
kubectl --kubeconfig /etc/rancher/k3s/k3s.yaml get pods --all-namespaces
helm --kubeconfig /etc/rancher/k3s/k3s.yaml ls --all-namespaces

links:

gpu on k3s

Step 1, 准备节点 (驱动等)
Step 2, 安装 k8s nvidia plugins
Step 3, benchmark 测试

links:

Based on docker

根据 k3s 文档 , 注册 RuntimeClass 及 nvidia 设备发现及调度插件.

1
2
3
4
5
6
7
8
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: nvidia
handler: docker # change to `docker` for dockerd
---
# the following is same as k3s based on containerd
# ...

links:

Based on containerd

根据 k3s 文档 , 注册 RuntimeClass 及 nvidia 设备发现及调度插件.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: nvidia
handler: nvidia
---
# From https://github.com/NVIDIA/gpu-feature-discovery/blob/main/deployments/static/nfd.yaml
# Modified to set `runtimeClassName: nvidia`, as k3s does not replace the default container runtime
apiVersion: v1
kind: Namespace
metadata:
name: node-feature-discovery
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfd-master
namespace: node-feature-discovery
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: nfd-master
rules:
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- patch
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: nfd-master
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: nfd-master
subjects:
- kind: ServiceAccount
name: nfd-master
namespace: node-feature-discovery
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
app: nfd
name: nfd
namespace: node-feature-discovery
spec:
selector:
matchLabels:
app: nfd
template:
metadata:
labels:
app: nfd
spec:
serviceAccount: nfd-master
runtimeClassName: nvidia
containers:
- env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
image: quay.io/kubernetes_incubator/node-feature-discovery:v0.6.0
name: nfd-master
command:
- "nfd-master"
args:
- "--extra-label-ns=nvidia.com"
- env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
image: quay.io/kubernetes_incubator/node-feature-discovery:v0.6.0
name: nfd-worker
command:
- "nfd-worker"
args:
- "--sleep-interval=60s"
- "--options={\"sources\": {\"pci\": { \"deviceLabelFields\": [\"vendor\"] }}}"
volumeMounts:
- name: host-boot
mountPath: "/host-boot"
readOnly: true
- name: host-os-release
mountPath: "/host-etc/os-release"
readOnly: true
- name: host-sys
mountPath: "/host-sys"
- name: source-d
mountPath: "/etc/kubernetes/node-feature-discovery/source.d/"
- name: features-d
mountPath: "/etc/kubernetes/node-feature-discovery/features.d/"
volumes:
- name: host-boot
hostPath:
path: "/boot"
- name: host-os-release
hostPath:
path: "/etc/os-release"
- name: host-sys
hostPath:
path: "/sys"
- name: source-d
hostPath:
path: "/etc/kubernetes/node-feature-discovery/source.d/"
- name: features-d
hostPath:
path: "/etc/kubernetes/node-feature-discovery/features.d/"
---
# From https://github.com/NVIDIA/gpu-feature-discovery/blob/main/deployments/static/gpu-feature-discovery-daemonset.yaml
# Modified to set `runtimeClassName: nvidia`, as k3s does not replace the default container runtime
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: gpu-feature-discovery
namespace: node-feature-discovery
labels:
app.kubernetes.io/name: gpu-feature-discovery
app.kubernetes.io/version: 0.6.1
app.kubernetes.io/part-of: nvidia-gpu
spec:
selector:
matchLabels:
app.kubernetes.io/name: gpu-feature-discovery
app.kubernetes.io/part-of: nvidia-gpu
template:
metadata:
labels:
app.kubernetes.io/name: gpu-feature-discovery
app.kubernetes.io/version: 0.6.1
app.kubernetes.io/part-of: nvidia-gpu
spec:
runtimeClassName: nvidia
containers:
- image: nvcr.io/nvidia/gpu-feature-discovery:v0.6.1
name: gpu-feature-discovery
volumeMounts:
- name: output-dir
mountPath: "/etc/kubernetes/node-feature-discovery/features.d"
- name: dmi-product-name
mountPath: "/sys/class/dmi/id/product_name"
securityContext:
privileged: true
env:
- name: MIG_STRATEGY
value: none
nodeSelector:
feature.node.kubernetes.io/pci-10de.present: "true" # NVIDIA vendor ID
volumes:
- name: output-dir
hostPath:
path: "/etc/kubernetes/node-feature-discovery/features.d"
- name: dmi-product-name
hostPath:
path: "/sys/class/dmi/id/product_name"
---
# From https://github.com/NVIDIA/k8s-device-plugin/blob/master/nvidia-device-plugin.yml
# Modified to set `runtimeClassName: nvidia`, as k3s does not replace the default container runtime
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nvidia-device-plugin-daemonset
namespace: kube-system
spec:
selector:
matchLabels:
name: nvidia-device-plugin-ds
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
name: nvidia-device-plugin-ds
spec:
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
# Mark this pod as a critical add-on; when enabled, the critical add-on
# scheduler reserves resources for critical add-on pods so that they can
# be rescheduled after a failure.
# See https://kubernetes.io/docs/tasks/administer-cluster/guaranteed-scheduling-critical-addon-pods/
priorityClassName: "system-node-critical"
runtimeClassName: "nvidia"
containers:
# The below image from gitlab works on the wsl2 from 2023/7/26, see
# - https://github.com/NVIDIA/k8s-device-plugin/issues/332#issuecomment-1650894074
# - https://gitlab.com/nvidia/kubernetes/device-plugin/container_registry
# - image: registry.gitlab.com/nvidia/kubernetes/device-plugin/staging/k8s-device-plugin:8b416016
- image: nvcr.io/nvidia/k8s-device-plugin:v0.14.1
name: nvidia-device-plugin-ctr
env:
- name: FAIL_ON_INIT_ERROR
value: "false"
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
volumeMounts:
- name: device-plugin
mountPath: /var/lib/kubelet/device-plugins
volumes:
- name: device-plugin
hostPath:
path: /var/lib/kubelet/device-plugins
---
# https://catalog.ngc.nvidia.com/orgs/nvidia/teams/k8s/containers/cuda-sample
apiVersion: v1
kind: Pod
metadata:
name: cuda-sample-vectoradd
namespace: default
spec:
restartPolicy: OnFailure
runtimeClassName: nvidia
containers:
- name: cuda-container
image: nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda10.2
resources:
limits:
nvidia.com/gpu: 1
env:
- name: NVIDIA_VISIBLE_DEVICES
value: all
- name: NVIDIA_DRIVER_CAPABILITIES
value: all

Enable with helm

根据上面两种方式,需设置 runtimeClassName, 在使用 helm 安装 k8s-device-plugin 步骤如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
cat <<EOF | kubectl apply -f -
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: nvidia
handler: nvidia # 创建基于 containerd 的RuntimeClass, 使用dockerd时改为docker
EOF

helm repo add nvdp https://nvidia.github.io/k8s-device-plugin
# 参考镜像:https://gitlab.com/nvidia/kubernetes/device-plugin/container_registry
helm upgrade -i nvdp nvdp/nvidia-device-plugin \
--namespace nvdp \
--create-namespace \
--set=runtimeClassName=nvidia \
--set=image.repository=registry.gitlab.com/nvidia/kubernetes/device-plugin/staging/k8s-device-plugin \
--set=image.tag=8b416016

helm upgrade -i nvdp nvdp/nvidia-device-plugin \
--namespace nvdp \
--create-namespace \
--version v0.14.1 \
--set=runtimeClassName=nvidia \
--set=image.repository=nvcr.io/nvidia/k8s-device-plugin

links:

Test

测试 cuda sample.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# https://github.com/NVIDIA/k8s-device-plugin/tree/master#running-gpu-jobs
# Add runtimeClassName to request gpu scheduled.
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
spec:
restartPolicy: Never
runtimeClassName: nvidia
containers:
- name: cuda-container
image: nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda10.2
resources:
limits:
nvidia.com/gpu: 1 # requesting 1 GPU
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
EOF

links:

k3s registry mirror

如果从国内环境安装 K3s 可能会遇到安装速度特别缓慢或者 time out 的情况,从以上的安装过程可以分析出主要由以下几个原因导致:

  • K3s 的安装脚本 https://get.k3s.io 存储在国外的服务器,从国内环境访问可能出现无法访问的情况

  • K3s 默认安装 stable 版本,stable 对应的具体 K3s 版本是通过 https://update.k3s.io/v1-release/channels 解析来的,而这个地址也是运行在一个国外的服务器上

  • 当通过 channel 解析出对应 K3s 的版本为:v1.25.3+k3s1,此时需要到 github 上拉取对应的 K3s 二进制文件。虽然这个二进制文件才几十兆,但国内环境访问 github 经常会出现无法访问的情况。

配置国内镜像

1
2
3
4
5
6
7
8
9
10
cat <<EOF > /etc/rancher/k3s/registries.yaml
mirrors:
"docker.io":
endpoint:
- "https://docker.mirrors.ustc.edu.cn" # 可根据需求替换 mirror 站点
- "https://registry-1.docker.io"
EOF
systemctl restart k3s
# 核查registry字段验证是否生效
crictl info

经过以上配置后,通过 K3s 拉取的镜像如果在配置的 mirror 站点中存在,那么将会从该站点拉取镜像。如果不存在,将会从默认的 docker.io 中拉取镜像。

links:

traefik

默认情况下,K3s 1.21 及更高版本默认安装 Traefik v2。出于安全考虑,默认不公开 Traefik Dashboard。参考

links:

crictl

crictl 是一个用于与 Kubernetes 中的容器运行时接口 (CRI) 进行交互的命令行工具。它允许在 Kubernetes 集群中管理容器和 Pod。它提供了创建、列出、启动、停止和删除容器等功能。

基本使用

1
2
3
4
5
6
# 显示容器运行时信息
crictl info
# 查看镜像
crictl images
# 查看pods
crictl pods

–runtime-endpoint

1
2
3
4
5
6
7
8
# 通过环境变量指定运行时终端
export CONTAINER_RUNTIME_ENDPOINT=unix:///run/containerd/containerd.sock

# 通过配置文件指定
echo 'runtime-endpoint: unix:///run/containerd/containerd.sock' >> /etc/crictl.yaml

# 命令参数指定
crictl --runtime-endpoint unix:///run/containerd/containerd.sock info

rke2

rke2,也被称为 RKE Government,是 Rancher 的下一代 Kubernetes 发行版

links:

安装

1
2
3
curl -sfL https://get.rke2.io | sh -
# 国内加速
curl -sfL https://rancher-mirror.rancher.cn/rke2/install.sh | INSTALL_RKE2_MIRROR=cn sh -

links:

istio

解析微服务实践中网络稳定的痛点,实践中通常使用服务网格 Service Mesh

Service Mesh 演化

  • 代码逻辑处理网络可靠,难维护

  • 公共库,解决耦合

  • 代理,功能简陋

  • Sidecar

  • Service Mesh

  • Service Mesh V2(加了控制平面)

Service Mesh

[!NOTE]
A service mesh is a dedicated infrastructure layer for handling service-to-service communication. It’s responsible for the reliable delivery of requests through the complex topology of services that comprise a modern,cloud native application. In practice,the service mesh is typically implemented as an array of lightweight network proxies that are deployed alongside application code,without the application needing to be aware.

服务网格是用于处理服务到服务通信的专用基础设施层。它负责通过组成现代云原生应用程序的复杂服务拓扑可靠地交付请求。在实践中,服务网格通常被实现为一组轻量级网络代理,它们与应用程序代码一起部署,而不需要应用程序察觉。即,应用中服务会有额外的 Sidecar 服务代理请求并可靠的提供通信的网络拓扑。

  • 流量控制

    • 路由
    • 超时重试
    • 故障处理
  • 策略

    • 流量限制
    • 黑白名单
  • 网络安全

    • 授权
    • 身份验证
  • 可观察性

    • 指标搜集展示
    • 日志收集
    • 分布式跟踪

Service Mesh 标准:

  • UDPA,同一的数据平面 API,为不同数据平面提供 API 接入。

  • SMI,为用户提供统一的控制平面。

istio

istio 定义

  • 服务网格产品

  • 对应用层透平

  • 为微服务架构设计

  • 可连接、保护、控制遥测系统

istio 核心资源 CRD

  • 虚拟服务(Virtual Service)

    • 将流量路由给定目标规则
    • 请求地址和真实工作负载解耦
    • 包含一组路由规则
    • 丰富的路由匹配规则

虚拟服务

  • 目标规则(Destination Rule)

    • 定义虚拟服务路由到目标真实地址,即子集
    • 负载均衡,随机、权重、最小请求数

目标规则

  • 网关(Gateway)

    • 管理进出网格的流量
    • 处在网格边界

网关

  • 服务入口(Service Entry)

    • 把外部服务注册到网格中
      • 为外部目标转发请求
      • 添加超时重试等策略
      • 扩展网络

服务入口

  • Sidecar

    • 调整 Envoy 代理接管的端口和协议
    • 限制 Envoy 代理可访问的服务

Sidecar

可观测性

  • 可观察性!= 监控

  • 组成:指标、日志、追踪

指标(Metrics)

  • 以聚合方式监控和理解系统行为

  • istio 中指标的分类

    • 代理级别指标(Proxy-level)
    • 服务级别指标(Service-level)
    • 控制平面指标(Control plane)

日志(Logging)

  • 系统产生事件了解系统

  • 包含完整的元数据信息(目标、源)

  • 生成位置可选(本地、远端,如 filebeat)

  • 日志内容

    • 应用日志
    • Envoy 日志 kubectl logs -l app=demo -c istio-proxy

追踪(Tracing)

  • 通过追踪请求,了解服务调用关系

  • 常用于调用链的问题排查、性能分析等

  • 支持多种追踪系统(Jeager、Zipkin、Datadog)

安全架构

认证

  • 对等认证(Peer authentication)

    • 服务间身份认证
    • Mutual TLS(mTLS)
  • 请求认证(Request authentication)

    • 终端用户身份认证
    • JSON Web Token(JWT)

授权

  • 授权级别

  • 策略分发

  • 授权引擎

  • 无需显示启用

安装

配置安装 istio

[!NOTE]
istio 需要匹配 k8s 环境。

curl -L https://istio.io/downloadIstio | sh -

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
istioctl version

# 需要测试环境demo的话可将 profile 从 default 到 demo
# default for production
istioctl manifest apply
# demo mode for learning
istioctl manifest apply --set profile=demo
# custom 增加 default + grafana
istioctl manifest apply --set addonComponents.grafana.enable=true

# 查看 istio pod
kubectl get ns
kubectl get pod -n istio-system

# 查看 istio crd/api
kubectl get crd | grep istio
kubectl api-resources | grep istio

# 验证安装
istioctl dashboard kiali

# 添加一个名称空间标签,以指示 istio 在以后部署应用程序时自动注入特使边车代理
kubectl label namespace default istio-injection=enabled

[!TIP]
可以部署 Bookinfo 应用,验证 istio。

示例部署 Bookinfo,并使用默认的 gateway 配置 ingressgateway,然后导出 8099 给外部访问。

1
2
3
4
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
kubectl port-forward svc/istio-ingressgateway 8099:80 -n istio-system
curl localhost:8099/productpage

Virtucal Service 和 Destination Rule

可实现的功能:

  • 按服务版本路由

    • 将流量都路由到 v1,samples/bookinfo/networking/virtual-service-all-v1.yaml
  • 按比例流量区分

  • 根据匹配规则进行路由

    • 根据请求 url 前缀匹配,samples/bookinfo/networking/bookinfo-gateway.yaml
  • 定义各种策略(负载均衡、连接池等)

knative

[!NOTE]
knative is an Open-Source Enterprise-level solution to build Serverless and Event Driven Applications.

Knative 是一个企业级的开源软件构建无服务器和事件驱动应用程序的解决方案。

knative 文档

要了解如何在 Kubernetes 上使用 Knative,需要重点关注以下文档:

Knative 官方文档中的以下章节对于了解 Knative 也非常重要:

traefik

Traefik 是一种流行的反向代理和负载均衡器,可用于将流量路由到不同的后端服务。它支持多种后端服务,例如 Docker,Kubernetes 和 Consul 等。Traefik 还提供了许多有用的功能,例如自动发现和自动配置。

参考:

traefik 示例

docker-compose 示例

如果正在使用 Docker,则可以使用 Traefik 作为反向代理和负载均衡器。Traefik 可以自动发现 Docker 容器,并将流量路由到正确的容器。以下是一个示例 docker-compose 文件,其中包含 Traefik 和一个 Web 服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
version: '3'

services:
traefik:
image: traefik:v2.4
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
ports:
- "80:80"
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"

web:
image: nginx:alpine
labels:
- "traefik.enable=true"
- "traefik.http.routers.web.rule=Host(`web.example.com`)"
- "traefik.http.services.web.loadbalancer.server.port=80"

# Add the lines to hosts and open example.com in browser
# 127.0.0.1 web.example.com

在此示例中,Traefik 将监听端口 80,并将流量路由到 Web 服务。Web 服务使用 Traefik 标签来指示 Traefik 应该将其作为后端服务使用。Traefik 还使用标签来指定路由规则。

k8s 示例

在 Kubernetes 中,Traefik 可以使用 Kubernetes Ingress 对象来路由流量。

要在 Kubernetes 中使用 Traefik,请按照以下步骤操作:

安装 Traefik Operator,Traefik Operator 是一个 Kubernetes 控制器,用于管理 Traefik 实例。可以使用 Helm Chart 安装 Traefik Operator。以下是安装 Traefik Operator 的命令:

1
2
3
helm repo add traefik https://helm.traefik.io/traefik
helm repo update
helm install traefik-operator traefik/traefik-operator

创建 Traefik 实例,要在 Kubernetes 中使用 Traefik,需要创建一个 Traefik 实例。可以使用 Traefik CRD(Custom Resource Definition)来定义 Traefik 实例。以下是一个示例 Traefik CRD:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: traefik.containo.us/v1alpha1
kind: TraefikService
metadata:
name: traefik
spec:
ports:
- name: http
port: 80
- name: admin
port: 8080
api:
dashboard: true
entryPoints:
- name: http
address: ":80"
- name: https
address: ":443"

在此示例中,Traefik 将监听端口 80 和 8080,并将流量路由到正确的后端服务。Traefik 还将启用 Traefik Dashboard,并监听端口 8080。

要创建 Traefik 实例,请使用以下命令:

1
kubectl apply -f traefik-crd.yaml

创建网关,网关可以使用 k8s 网关或 traefik IngressRoute。

  • 创建 Ingress 对象

要在 Kubernetes 中使用 Traefik 路由流量,需要创建一个 Ingress 对象。以下是一个示例 Ingress 对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: http
traefik.ingress.kubernetes.io/router.rule: "Host(`example.com`)"
spec:
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
name: http

在此示例中,Ingress 对象将流量路由到名为 “web” 的 Kubernetes Service。Traefik 将使用标签 “traefik.ingress.kubernetes.io/router.rule” 来指定路由规则。

要创建 Ingress 对象,请使用以下命令:

1
kubectl apply -f ingress.yaml
  • 创建 Traefik IngressRoute

在 Kubernetes 上使用 Traefik 的信息,并且想要了解如何使用 Traefik IngressRoute。Traefik IngressRoute 是 Traefik 的一种扩展,它提供了更多的路由选项和更好的可读性。要在 Kubernetes 中使用 Traefik IngressRoute 路由流量,需要创建一个 IngressRoute 对象。以下是一个示例 IngressRoute 对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: web
spec:
entryPoints:
- web
routes:
- match: Host(`example.com`) && PathPrefix(`/web`)
kind: Rule
services:
- name: web
port: 80

在此示例中,IngressRoute 对象将流量路由到名为 “web” 的 Kubernetes Service。Traefik 将使用标签 “match” 来指定路由规则。

要创建 IngressRoute 对象,请使用以下命令:

1
kubectl apply -f ingressroute.yaml

[!NOTE]
Traefik 和 Istio 是两个不同的工具,它们都可以用于在 Kubernetes 中管理流量路由和负载均衡,但它们的设计目标和功能略有不同。

Traefik 是一个轻量级的反向代理和负载均衡器,它专注于将流量路由到正确的后端服务。Traefik 提供了许多路由选项和可插拔的中间件,例如 TLS 证书管理和 HTTP 重定向。Traefik 还提供了一个易于使用的 Web UI,用于监视和管理流量路由。

相比之下,Istio 是一个更全面的服务网格解决方案,它提供了更多的功能,例如流量管理、安全性和可观察性。Istio 使用 Envoy 作为其数据平面,Envoy 是一个高性能的代理,它可以在应用程序和服务之间进行流量路由和负载均衡。Istio 还提供了一些高级功能,例如流量控制、故障注入和跟踪。

因此,如果只需要一个简单的反向代理和负载均衡器,Traefik 可能是更好的选择。但是,如果需要更全面的服务网格功能,例如流量管理和安全性,那么 Istio 可能更适合需求。

opentelemetry

opentelemetry 是一个 api、sdk 和工具的集合。使用它来检测、生成、收集和导出遥测数据 (度量、日志和跟踪),以帮助分析软件的性能和行为。