Skip to content

Commit

Permalink
add
Browse files Browse the repository at this point in the history
  • Loading branch information
yangpeng committed Apr 15, 2020
1 parent b758df3 commit 993e22c
Show file tree
Hide file tree
Showing 2 changed files with 314 additions and 0 deletions.
121 changes: 121 additions & 0 deletions kubernetes/Kubernetes-Pod钩子.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
> - 作者:jasonminghao
> - 链接:https://www.cnblogs.com/jasonminghao/p/12681352.html?utm_source=tuicool&utm_medium=referral
## 目录导航

- 1、Pod容器钩子最终目的
- 2、何为Pod容器钩子
- 3、基于PostStart演示
- 4、基于PreStop演示
- 5、优雅停止Java应用

## 1、Pod容器钩子最终目的

之前在生产环境中使用`dubbo框架`,由于服务更新的过程中,容器直接被停止了,部分请求仍会被分发到终止的容器,导致有用户会访问服务出现`500错误`,这部分错误请求数据占用的比较少,因为Pod是滚动一对一更新。由于这个问题出现了,考虑使用优雅的终止方式,将错误请求将至到最低,直至滚动更新完全不会影响到用户。

### 简单分析一下 `优雅的停止Pod`

微服务中,网关会把流量分配给每个Pod节点,如:我们线上更新Pod的时候

1、如果我们直接把Pod给杀死,那这部分流量就无法得到正确的处理,会影响到部分用户访问,一般来说网关或者注册中心会将我们的服务保持一个心跳,过了心跳超时后就会自动摘除我们的服务,但是有一个问题就是超时时间可能是10s、30s、甚至是60s,虽然不会大规模的影响我们业务系统,但是一定会对用户产生轻微的抖动。

2、如果我们在停止服务前执行一条命令,通知网关或注册中心摘掉这台Pod,即服务进行下线,那么注册中心就会标记这个Pod服务已经下线,不进行流量转发,用户也就不会有任何的影响,这就是优雅停止,将滚动更新的影响最小化。

## 2、何为Pod容器钩子

Kubernetes 最小调度单位为 `Pod`,它为Pod中的容器提供了生命周期钩子,钩子能够使得容器感知其生命周期内的所有事件,并且当相应的生命周期的钩子被调用时运行执行的代码,而Pod 钩子是由Kubelet发起的。

容器钩子两类触发点:

- `PostStart`:容器创建后
- `PreStop`:容器终止前

### PostStart

这个钩子在容器创建后立即执行。但是,并不能保证钩子将在容器 `ENTRYPOINT` 之前运行。没有参数传递给处理程序。

容器 `ENTRYPOINT``钩子` 执行是`异步操作`。如果钩子花费太长时间以至于容器不能运行或者挂起,容器将不能达到running状态。

### PreStop

这个钩子在容器终止之前立即被调用。它是`阻塞的`,意味着它是同步的,所以它必须在删除容器调用发出之前完成。

如果钩子在执行期间挂起,Pod阶段将停留在running状态并且永不会达到failed状态。

如果 `PostStart` 或者 `PreStop` 钩子失败,容器将会被 `kill`

用户应该使它们的钩子处理程序尽可能的`轻量`

## 3、基于PostStart演示

如果 `PostStart` 或者 `PreStop` 钩子失败,它会杀死容器。所以我们应该让钩子函数尽可能的轻量。当然有些情况下,长时间运行命令是合理的,比如在停止容器之前预先保留状态。

1、我们echo一段话追加到/tmp/message,在Pod启动前操作

```bash
$ cat >>hook_test.yaml<<EOF
apiVersion: v1
kind: Pod
metadata:
name: hook-demo1
spec:
containers:
- name: hook-demo1
image: nginx
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo 1 > /tmp/message"]
EOF
```

2、应用 hook_test.yaml

```bash
$ kubectl apply -f hook_test.yaml
```

3、可以通过下面查看结果

```bash
$ kubectl get pods | grep hook-demo1

hook-demo1 1/1 Running 0 49s

$ kubectl exec -it hook-demo1 /bin/bash
root@hook-demo1:/# cat /tmp/message

1
```

## 4、基于PreStop演示

下面示例中,定义一个Nginx Pod,设置了PreStop钩子函数,即在容器退出之前,优雅的关闭Nginx。

```bash
$ cat >>hook_test.yaml<<EOF
apiVersion: v1
kind: Pod
metadata:
name: hook-demo2
spec:
containers:
- name: hook-demo2
image: nginx
lifecycle:
preStop:
exec:
command: ["/usr/sbin/nginx","-s","quit"]
EOF
```

## 5、优雅停止Java应用

我们都知道java应用的启动和停止都需要时间,为了更加优雅的停止,可以通过 `pidof` 获取到java进程ID,循环通过kill命令往PID发送 `SIGTERM` 信号。

```yaml
lifecycle:
preStop:
exec:
command: ["/bin/bash","-c","PID=`pidof java` && kill -SIGTERM $PID && while ps -p $PID > /dev/null;do sleep 1; done;"]
```
193 changes: 193 additions & 0 deletions kubernetes/使用k8s集群调度GPU.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
## 背景

最近接到任务,要使k8s集群支持调度`GPU`,我对硬件资源不是很懂,大概看了看官方,简单梳理了一下思路,便开始了踩坑之路(本片文章是无坑文档,请放心使用/参考)

## 前提条件:

对于实验学习而言,在k8s集群中,至少保证1台node节点是有显卡的(本文是`NVIDIA`),其他品牌显卡请出门右转自行Google

## 集群环境说明:

> 本文是学习实验环境,所以只有 `ai-gpu-flask2.novalocal` 支持 `GPU`,其余的节点都是虚拟机。最终验证也是在 `ai-gpu-flask2.novalocal` 上进行。
|系统|名称|角色|k8s版本|
|:--:|:--:|:--:|:--:|
|centos7.6|ai-gpu-flask2.novalocal|worker|kubeadm v1.16.8|
|centos7.6|master|etcd,master|kubeadm v1.16.8|
|centos7.6|node1|worker|kubeadm v1.16.8|
|centos7.6|node2|worker|kubeadm v1.16.8|

## 预安装

- 本步骤在支持`GPU`节点上执行
- 参考链接:https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#introduction

要验证您的 `GPU` 是否具有 `CUDA` 功能,请转至与您的发行版等效的“系统属性”,或者在命令行中输入:

```bash
$ lspci | grep -i nvidia

00:06.0 3D controller: NVIDIA Corporation TU104GL [Tesla T4] (rev a1)
```

要确定您正在运行的发行版和发行版号,请在命令行中键入以下内容:
```bash
$ uname -m && cat /etc/*release
```

要验证系统上安装的`gcc`版本,请在命令行中键入以下内容:
```bash
$ gcc --version
```

可以通过运行以下命令找到系统正在运行的内核版本:
```bash
$ uname -r
```

当前运行的内核的内核头文件和开发包可以通过以下方式安装:
```bash
$ sudo yum install kernel-devel-$(uname -r) kernel-headers-$(uname -r)
```

选择您正在使用的平台并下载 `NVIDIA CUDA Toolkit`

> 下载链接:http://developer.nvidia.com/cuda-downloads
```
$ wget http://developer.download.nvidia.com/compute/cuda/10.2/Prod/local_installers/cuda-repo-rhel7-10-2-local-10.2.89-440.33.01-1.0-1.x86_64.rpm
$ sudo rpm -i cuda-repo-rhel7-10-2-local-10.2.89-440.33.01-1.0-1.x86_64.rpm
$ sudo yum clean all
$ sudo yum -y install nvidia-driver-latest-dkms cuda
$ sudo yum -y install cuda-drivers
```

要安装显示驱动程序,必须首先禁用 `Nouveau` 驱动程序:
在以下位置创建文件
```bash
$ vim /etc/modprobe.d/blacklist-nouveau.conf

# 具有以下内容:
$ blacklist nouveau
$ options nouveau modeset=0
```

重新生成内核initramfs:
```bash
$ sudo dracut --force
```

## 验证

```bash
# 正常来说会输出已经安装过的程序
$ rpm -qa | grep nvidia

# 正常来说会输出已经安装过的程序
$ rpm -qa | grep cuda
```
## 满足先决条件

- 阅读文档:https://github.com/NVIDIA/k8s-device-plugin#prerequisites
- 说明:该文章中描述了安装`k8s-device-plugin`的先决条件
- 条件一 NVIDIA drivers ~= 384.81 已经满足
- 条件四 Kubernetes version >= 1.10 已经满足

## 先决条件准备

- 满足`条件二` nvidia-docker version > 2.0
- 参考链接:https://github.com/NVIDIA/nvidia-docker#centos-7-docker-ce-rhel-7475-docker-ce-amazon-linux-12

```bash
$ 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

$ sudo yum install -y nvidia-container-toolkit
$ sudo systemctl restart docker
```
- 满足`条件三` docker configured with nvidia as the default runtime.
- 参考链接:https://github.com/NVIDIA/k8s-device-plugin#preparing-your-gpu-nodes

```bash
$ vim /etc/docker/daemon.json
```

```json
{
"default-runtime": "nvidia",
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
}
}
```

## 验证

> 参考链接:https://github.com/NVIDIA/nvidia-docker#usage
```bash
$ docker run --gpus all nvidia/cuda:10.0-base nvidia-smi

# 报错如下:
docker: Error response from daemon: OCI runtime create failed: unable to retrieve OCI runtime error (open /run/containerd/io.containerd.runtime.v1.linux/moby/36cd5b1383a3ca5d2196d05e3655122ea4703af69bdfedfdfc6657f/log.json: no such file or directory): fork/exec /usr/bin/nvidia-container-runtime: no such file or directory: unknown.
ERRO[0000] error waiting for container: context canceled
```
- 解决办法

```bash
$ yum search nvidia-container-runtime
$ yum -y install nvidia-container-runtime.x86_64 nvidia-container-runtime-hook.x86_64
```

## 再次验证

```bash
$ docker run --gpus all nvidia/cuda:10.0-base nvidia-smi
```
![](/img/fc46531a-b6fa-408f-8577-9521c97f5fda.png)

### 至此,docker环境下使用`GPU`已经完成,接下来部署`k8s-device-plugin`使k8s也支持`GPU`

> 参考链接:https://github.com/NVIDIA/k8s-device-plugin#enabling-gpu-support-in-kubernetes
```bash
$ kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/1.0.0-beta5/nvidia-device-plugin.yml
```

### 验证

通过命令`kubectl describe node ai-gpu-flask2.novalocal`可以看到node节点有`ncidia.com/gpu`就正常了

![](/img/b5fc1888-c27a-4732-9df4-84805641c62a.png)

### 运行一个pod

- 参考链接:https://github.com/NVIDIA/k8s-device-plugin#running-gpu-jobs

```yaml
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
spec:
containers:
- name: cuda-container
image: nvidia/cuda:9.0-devel
resources:
limits:
nvidia.com/gpu: 2 # requesting 2 GPUs
- name: digits-container
image: nvidia/digits:6.0
resources:
limits:
nvidia.com/gpu: 2 # requesting 2 GPUs
```
## 结束语
经过两天踩坑到填坑的魔鬼历程,才有了这篇无坑文章,大家且用且珍惜。
GPU的学习成本较高,普通的虚拟机是不可能完成这个实验操作的,如果你看到了这篇文档,不妨先收藏一下,日后如果有需求,可以第一时间拿出来参考。

0 comments on commit 993e22c

Please sign in to comment.