原文内容:https://gitee.com/dev-99cloud/training-kubernetes ,在此基础上有新增。
Lesson 02:Kubernetes Concepts
2.1 什么是 K8S?
-
什么是 Kubernetes?容器编排工具。为什么叫 K8S?
-
K8S 和 Docker 有什么关系?参考:Container runtimes
-
Orchestration API -> Container API (cri-runtime) -> Kernel API(oci-runtime)
-
OCI:runC / Kata( 及其前身 runV 和 Clear Containers ),gVisor,Rust railcar
- 容器镜像的制作标准,即 ImageSpec。大致规定:容器镜像这个压缩了的文件夹里以 xxx 结构放 xxx 文件
- 容器要需要能接收哪些指令,以及这些指令的行为,即 RuntimeSpec。这里面的大致内容就是“容器”要能够执行 “create”,“start”,“stop”,“delete” 这些命令,并且行为要规范。
- Docker 则把 libcontainer 封装了一下,变成 runC 捐献出来作为 OCI 的参考实现。
-
CRI:Docker( 借助 dockershim ),containerd( 借助 CRI-containerd ),CRI-O,Frakti。是一组 gRPC 接口,cri-api/pkg/apis/services.go:
- 一套针对容器操作的接口,包括创建,启停容器等等
- 一套针对镜像操作的接口,包括拉取镜像删除镜像等
- 一套针对 PodSandbox(容器沙箱环境)的操作接口
-
正常的 K8S 调用 Docker 流程
-
containerd-1.0,对 CRI 的适配通过一个单独的进程 CRI-containerd 来完成
-
containerd-1.1,把适配逻辑作为插件放进了 containerd 主进程中
-
CRI-O,更为专注的 cri-runtime,非常纯粹,兼容 CRI 和 OCI,做一个 Kubernetes 专用的运行时
-
-
CRI-O 的架构:
-
K8S 和 Borg 有何关系?Start from Borg, however completely different!
2.2 K8S 是为了解决什么问题?
- K8S 有什么优势?适用于哪些场景?自动化编排:自愈,快速缩放,一键部署和升降级,备份恢复
- 如何查文档?K8S,OpenShift Origin
- 其它资料:slack、cncf、quay.io
2.3 K8S 不解决什么问题?
- 用户管理
- 限流熔断:istio
- 监控审计:prometheus / grafana / alertmanager / elasticsearch / fluent / kibana
- 用户界面
- 中间件
- 底层云平台支持
2.4 K8S 的模块架构是怎样的?
-
K8S 有哪些组件?api-server、kube-scheduler、kube-controller、etcd、coredns、kubelete、kubeproxy
-
整体结构图
2.5 K8S 有哪些竞争产品?
-
-
和 K8S 相比,OpenShift( 红帽最有价值的产品 )有哪些优势?
-
-
VMware
-
KubeSphere
-
Rancher
2.6 怎么部署出一个 K8S 群集?
- kubeadm
- Ansible
2.7 实验:K8S 的部署
2.7.1 在 centos 7 上部署 k8s
# 1. 关闭防火墙(在阿里云的 centos-7.9 镜像默认就是关闭的,不用做)
systemctl stop firewalld.service
systemctl disable firewalld.service
# 2. 关闭 selinx (在阿里云的 centos-7.9 镜像默认就是关闭的,不用做)
# 将 SELINUX=enforcing 改为 SELINUX=disabled
vi /etc/selinux/config
# 立刻停止 selinux
setenforce=0
# 3. 关闭 swap(在阿里云的 centos-7.9 镜像默认就是关闭的,不用做)
# 注释掉 swapoff xxx ,避免重启后 swap 重新启用
vi /etc/fstab
# 立刻停止 swap
swapoff -a
# 4.开启内核参数
# 持久化激活内核模块 br_netfilter
echo br_netfilter | tee -a /etc/modules
modprobe br_netfilter
# 开启 ipv4 forward
cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
# 启动内核参数配置
sysctl -p
sysctl --system
# 5. 配置 kubernetes repo 源, 这里我们使用阿里云的 repo
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
# 6. [可选] 移除之前安装的 docker(可能有老版本的)
yum remove -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 7. 安装新版本的 docker
yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin -y
# 开机启动 containerd 和 docker
systemctl enable containerd --now
systemctl enable docker --now
# 初始化 containerd 配置
containerd config default > /etc/containerd/config.toml
vi /etc/containerd/config.toml
# 更新 sandbox 镜像
# sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.6" 用国内的镜像仓库
# 更新 SystemdCgroup,false 改成 true
# SystemdCgroup = true
vi /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"]
}
# 重新启动 containerd 和 docker
systemctl restart containerd
systemctl restart docker
# 8. 安装 kubernetes 1.23.3
export k8s_version="1.23.3"
# 安装 1.23.3 的repo包
yum install -y kubelet-${k8s_version}-0 kubeadm-${k8s_version}-0 kubectl-${k8s_version}-0 --disableexcludes=kubernetes
# 启动 kubelet
systemctl restart kubelet
systemctl enable kubelet
# 提前拉取镜像
kubeadm config images pull --kubernetes-version ${k8s_version} --image-repository registry.aliyuncs.com/google_containers
# 安装 master
kubeadm init --image-repository registry.aliyuncs.com/google_containers --kubernetes-version=v${k8s_version} --pod-network-cidr=10.244.0.0/16
# 配置 kubectl 的配置文件
mkdir $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 安装 calico
kubectl apply -f https://gitee.com/dev-99cloud/lab-openstack/raw/master/src/ansible-cloudlab-centos/playbooks/roles/init04-prek8s/files/calico-${k8s_version}.yml
上述部署可以让 K8S 对接 Docker,如果想直接对接 containerd,那么 kubeadm int 命令需要改成:kubeadm init --cri-socket unix:///run/containerd/containerd.sock --image-repository registry.aliyuncs.com/google_containers --kubernetes-version=v${k8s_version} --pod-network-cidr=10.244.0.0/16
,参考 Github 或 Gitee
如果要重新安装,可以 kubeadm reset -f
-
检查集群状态
# 检查节点状态 $ kubectl get nodes NAME STATUS ROLES AGE VERSION cka-node1 Ready control-plane,master,worker 30s v1.23.3
-
集群安装/加入 GPU 节点(仅当 cri 为 docker 时才行)
# 1. 节点安装显卡驱动 # 可以参考 https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#abstract # 2. 安装 docker # 见上文 # 3. 安装 nvidia-docker distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \ && curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.repo | sudo tee /etc/yum.repos.d/nvidia-docker.repo yum install -y nvidia-docker2 # ubuntu 等其他系统安装参考文档 https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#installing-on-centos-7-8 # 4. 更改默认容器运行时 # 编辑 `/etc/docker/daemon.json`, 添加如下字段: { "default-runtime": "nvidia", "runtimes": { "nvidia": { "path": "nvidia-container-runtime", "runtimeArgs": [] } } } systemctl daemon-reload && systemctl restart docker # 5. 安装 k8s 集群或将集群加入节点即可 # 6. 安装 vgpu 插件 # * Nvidia 官方的插件只能在 k8s 上整卡调度,调度力度太大,在我们的场景中没有太大实际意义 # * 阿里云 gpushare 是阿里云公有云使用的 cgpu 的部分开源项目,能对 gpu 进行显存划分,多容器调度,但是没有实现显存隔离 # * 第四范式 vgpu 是第四范式开源的 vgpu 上层实现,底层核心逻辑是 libvgpu.so提供的,没有开源,可以实现对物理 gpu 的切分,实现了显存隔离。 # 安装第四范式 vgpu 参考 `https://github.com/4paradigm/k8s-device-plugin/blob/master/README_cn.md#Kubernetes%E5%BC%80%E5%90%AFvGPU%E6%94%AF%E6%8C%81`
2.7.2 在 Ubuntu 18.04 / 20.04 上部署 k8s
-
# iptables 看到 bridged 流量 cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF sudo sysctl --system # Install kubeadm apt-get update && apt-get install -y apt-transport-https curl curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list deb https://apt.kubernetes.io/ kubernetes-xenial main EOF apt-get update -y && apt-get install -y kubelet kubeadm kubectl # 重启 kubelet systemctl daemon-reload systemctl restart kubelet # 检查 kubelet 状态,在加入 k8s 集群之前,kubelet 状态会一直处于 activating 状态 systemctl status kubelet
-
# 拉起 k8s 群集 kubeadm init --pod-network-cidr 192.168.1.90/16 # 配置 kubectl 客户端 mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
-
此时可以观察到 node 并未 ready,导致 coredns 无法调度。接下来需要:安装网络插件,插件列表,这里我们用 Calico。
# 添加网络插件 # Install the Tigera Calico operator and custom resource definitions kubectl create -f https://docs.projectcalico.org/manifests/tigera-operator.yaml # Install Calico by creating the necessary custom resource kubectl create -f https://docs.projectcalico.org/manifests/custom-resources.yaml # 查看 pods 和 nodes 状态 kubectl get pods --all-namespaces kubectl get nodes
2.8 什么是 Pod?
-
Pod 和容器的关系是什么?
# pod 里的 pause 容器和业务容器共享 ipc / net / user namespaces [root@cloud025 ~]# ll /proc/10982/ns/ total 0 lrwxrwxrwx 1 root root 0 Aug 10 16:14 ipc -> ipc:[4026532513] lrwxrwxrwx 1 root root 0 Aug 10 15:33 mnt -> mnt:[4026532592] lrwxrwxrwx 1 root root 0 Aug 10 15:33 net -> net:[4026532516] lrwxrwxrwx 1 root root 0 Aug 10 15:33 pid -> pid:[4026532594] lrwxrwxrwx 1 root root 0 Aug 10 16:14 user -> user:[4026531837] lrwxrwxrwx 1 root root 0 Aug 10 16:14 uts -> uts:[4026532593] [root@cloud025 ~]# ll /proc/10893/ns/ total 0 lrwxrwxrwx 1 root root 0 Aug 10 15:33 ipc -> ipc:[4026532513] lrwxrwxrwx 1 root root 0 Aug 10 15:33 mnt -> mnt:[4026532511] lrwxrwxrwx 1 root root 0 Aug 10 15:33 net -> net:[4026532516] lrwxrwxrwx 1 root root 0 Aug 10 16:15 pid -> pid:[4026532514] lrwxrwxrwx 1 root root 0 Aug 10 16:15 user -> user:[4026531837] lrwxrwxrwx 1 root root 0 Aug 10 16:15 uts -> uts:[4026532512]
-
为什么调度的基本单位是 pod 不是容器?
2.9 启动一个 pod
-
apiVersion: v1 kind: Pod metadata: name: nginx labels: env: test spec: containers: - name: nginx image: nginx
-
启动一个 Pod
# 起 nginx pod kubectl apply -f nginx.yaml # 可以看到 pod 无法被调度,进行诊断 kubectl describe pod nginx # 去污点、允许 pod 调度到 master kubectl taint nodes $(hostname) node-role.kubernetes.io/master:NoSchedule- # 查看 pods kubectl get pods # 查看容器 docker ps | grep nginx
-
在容器平台上发布 Python 应用
-
我们将要做什么?
- 下载应用代码,并且在本地跑起来
- 为应用构建一个 Docker 镜像,然后启动一个 Docker 容器来运行此应用
- 创建一个 Deployment 对象,将应用运行在 K8S 平台上
- 参考:https://kubernetes.io/blog/2019/07/23/get-started-with-kubernetes-using-python/
- 对应的原始代码在:https://github.com/JasonHaley/hello-python
-
预置条件有哪些?
- 本地具备 Python 3.6+ 的运行环境
- 安装了 Git(非必须)
- 安装了 Docker
- 一个 Kubernetes 平台
-
-
其中
requirements.txt
里只有一行:flask,是依赖包列表文件 -
另一个文件是
main.py
,是应用的逻辑代码from flask import Flask import os import socket app = Flask(__name__) @app.route("/") def hello(): html = "<h3>Hello {name}!</h3>" \ "<b>Hostname:</b> {hostname}<br/>" return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname()) if __name__ == "__main__": app.run(host='0.0.0.0')
-
-
下载代码
mkdir ~/test-hello-world cd ~/test-hello-world/ wget https://gitee.com/dev-99cloud/training-kubernetes/raw/master/src/hello-python/main.py wget https://gitee.com/dev-99cloud/training-kubernetes/raw/master/src/hello-python/requirements.txt wget https://gitee.com/dev-99cloud/training-kubernetes/raw/master/src/hello-python/Dockerfile wget https://gitee.com/dev-99cloud/training-kubernetes/raw/master/src/hello-python/deployment.yaml
-
本地运行:
- 安装依赖:
pip3 install -r requirements.txt
- 本地运行:
python3 main.py
,会在本地启动一个用于开发的 web 服务器。 - 你可以打开浏览器,访问
http://<IP>:5000
端口
- 安装依赖:
-
Docker 镜像构建文件,目录下有一个 Dockerfile 文件
FROM python:3.7 RUN mkdir /app WORKDIR /app ADD . /app/ RUN pip install -r requirements.txt EXPOSE 5000 CMD ["python", "/app/main.py"]
-
构建 Docker 镜像并运行
- 运行命令构建镜像:
docker build -f Dockerfile -t hello-python:latest .
- 构建完成后,可以通过
docker image ls
看到刚才构建的镜像 - 然后运行此镜像:
docker run -p 5001:5000 hello-python
- 然后访问
http://<IP>:5001
,同样可以看到Hello form Python!
字符串
- 运行命令构建镜像:
-
确定 Kubernetes 和 kubectl 运行正常
- 运行命令:
kubectl version
,如果该命令不报错,就说明 kubectl 安装完成。 - 运行命令:
kubectl get nodes
,如果返回节点信息,说明 K8S 运行正常,kubectl 配置正常。
- 运行命令:
-
K8S deployment YAML 文件:
apiVersion: v1 kind: Service metadata: name: hello-python-service spec: type: NodePort selector: app: hello-python ports: - protocol: "TCP" port: 6000 targetPort: 5000 nodePort: 31000 --- apiVersion: apps/v1 kind: Deployment metadata: name: hello-python spec: selector: matchLabels: app: hello-python replicas: 4 template: metadata: labels: app: hello-python spec: containers: - name: hello-python image: hello-python:latest imagePullPolicy: Never ports: - containerPort: 5000
-
将 Deployment 部署到 K8S 平台
- 运行命令:
kubectl apply -f deployment.yaml
- 运行命令:
kubectl get pods,检查 pods
- 然后可以打开浏览器,在
http://<IP>:31000
看到Hello form Python!
信息
- 运行命令:
-
实验
# 观察 service / deployment 和 pod 的关系,通过 label 关联 kubectl get pods -l app=hello-python kubectl get deploy kubectl get deployment kubectl get svc kubectl get service kubectl get pods -l app=hello-python -o wide # 访问应用 curl http://<pod-ip>:5000 curl http://<cluster-ip>:6000 curl http://<host-ip>:31000
-
评论