上篇我们已经安装好k8s1.23集群,现在我们开始使用k8s部署我们的项目
Pod
Pod 是一组容器集合,是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。这些容器共享存储、网络。
准备Demo
我们要实现多容器Pod所以准备两个WebAPI项目
新建一个webapi,命名为oneapi,里面新增TestController,新增两个api,一个是返回当前pod的ip,另一个是模拟高cpu操作
代码语言:javascript复制[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
private readonly ILogger<TestController> _logger;
public TestController(ILogger<TestController> logger)
{
_logger = logger;
}
[HttpGet]
public string Get()
{
var ip = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces().Select(p => p.GetIPProperties()).SelectMany(p => p.UnicastAddresses)
.Where(p => p.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork && !System.Net.IPAddress.IsLoopback(p.Address))
.FirstOrDefault()?.Address.ToString();
return "ip is " ip;
}
[HttpGet("highcpu")]
public string HighCpu(int minutes)
{
var now = DateTime.Now;
while (DateTime.Now - now <= TimeSpan.FromMinutes(minutes))
{
_logger.LogInformation(DateTime.Now.ToString());
}
return "ok";
}
}
新建第二个webapi,命名为twoapi,里面同样新增TestController,实现一个接口,通过localhost调用oneapi的ip接口(pod内容器共享存储、网络)
代码语言:javascript复制[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
private readonly ILogger<TestController> _logger;
private readonly HttpClient _httpclient;
public TestController(ILogger<TestController> logger, HttpClient httpclient)
{
_logger = logger;
_httpclient = httpclient;
}
[HttpGet("calloneapi")]
public async Task<string> CallOneApiAsync()
{
var content = await (await _httpclient.GetAsync("http://localhost:5000/test")).Content.ReadAsStringAsync();
return "one api response is " content;
}
}
将这两个api打成镜像,推进阿里云镜像库
单容器Pod
我们通过以下命令即可快速地部署一个pod
代码语言:javascript复制kubectl run oneapi --image=registry.cn-beijing.aliyuncs.com/chester-k8s/oneapi:latest
可通过以下命令查看pod的状态
kubectl describe pod oneapi
查看到pod的私有ip,调用oneapi的ip接口,验证是否部署成功
curl 10.244.36.66:5000/test
多容器Pod
代码语言:javascript复制多容器pod共享存储、网络,我们通过yaml文件来部署一个多容器的pod。
新建pod.yaml文件
apiVersion: v1
kind: Pod
metadata:
name: chesterapi
spec:
containers:
- name: oneapi
image: registry.cn-beijing.aliyuncs.com/chester-k8s/oneapi:latest
ports:
- containerPort: 5000
- name: twoapi
image: registry.cn-beijing.aliyuncs.com/chester-k8s/twoapi:latest
ports:
- containerPort: 5001
通过以下命令部署容器
kubectl apply -f pod.yaml
通过以下命令查看pod
代码语言:javascript复制kubectl describe pod chesterapi
通过以下调用twoapi的接口验证pod是否部署成功
curl podip:5001/test/calloneapi
验证完成,通过以下命令删除pod
代码语言:javascript复制kubectl delete -f pod.yaml
探针
探针用于检测pod的健康状态,探针有三种,
ExecAction
(借助容器运行时执行)TCPSocketAction
(由 kubelet 直接检测)HTTPGetAction
(由 kubelet 直接检测)
我们通过http探针,来检测pod的健康状态,修改pod.yaml文件,并直接kubectl apply -f pod.yaml即可验证
代码语言:javascript复制apiVersion: v1
kind: Pod
metadata:
name: chesterapi
spec:
containers:
- name: oneapi
image: registry.cn-beijing.aliyuncs.com/chester-k8s/oneapi:latest
ports:
- containerPort: 5000
livenessProbe:
httpGet:
path: /test
port: 5000
- name: twoapi
image: registry.cn-beijing.aliyuncs.com/chester-k8s/twoapi:latest
ports:
- containerPort: 5001
livenessProbe:
httpGet:
path: /test/calloneapi
port: 5001
Pod状态
Pod重启策略
restartPolicy的选择值
- Always:当容器失效时,由kubelet自动重启该容器。
- OnFailure:当容器终止运行且退出码不为0时,由kubelet自动 重启该容器。
- Never:不论容器运行状态如何,kubelet都不会重启该容器。
我们通过pod.yaml的探针接口地址为一个不存在的地址,并将restartPolicy设置为Never,让其即使健康检查失败,Pod也永不重启
代码语言:javascript复制apiVersion: v1
kind: Pod
metadata:
name: chesterapi
spec:
restartPolicy: Never
containers:
- name: oneapi
image: registry.cn-beijing.aliyuncs.com/chester-k8s/oneapi:latest
ports:
- containerPort: 5000
livenessProbe:
httpGet:
path: /test1
port: 5000
- name: twoapi
image: registry.cn-beijing.aliyuncs.com/chester-k8s/twoapi:latest
ports:
- containerPort: 5001
livenessProbe:
httpGet:
path: /test/calloneapi1
port: 5001
代码语言:javascript复制通过以下命令部署,并验证
kubectl apply -f pod.yaml
kubectl describe pod -n chesterapi
Deployemnt
说完了pod,我们来看看deployment。生产环境中基本不存在直接定义pod的方式来部署项目,更多的是通过Deployment来部署。
用途
- 方便管理、部署Pod
- 横扩应对高负载
- 快速程序更新与回滚
创建
首先我们创建一个文件ns.yaml来定义一个namespace
代码语言:javascript复制apiVersion: v1
kind: Namespace
metadata:
name: chesterns
代码语言:javascript复制kubectl apply -f ns.yaml
我们通过定义以下一个deployment,实现部署三个pod,模拟负载
代码语言:javascript复制apiVersion: apps/v1
kind: Deployment
metadata:
name: chesterdeployment
namespace: chesterns
labels:
app: chesterapi
spec:
replicas: 3
selector:
matchLabels:
app: chesterapi
template:
metadata:
labels:
app: chesterapi
spec:
containers:
- name: oneapi
image: registry.cn-beijing.aliyuncs.com/chester-k8s/oneapi:latest
ports:
- containerPort: 5000
livenessProbe:
httpGet:
path: /test
port: 5000
- name: twoapi
image: registry.cn-beijing.aliyuncs.com/chester-k8s/twoapi:latest
ports:
- containerPort: 5001
livenessProbe:
httpGet:
path: /test/calloneapi
port: 5001
代码语言:javascript复制通过以下命令部署并调用接口
kubectl apply -f deployment.yaml # 部署
kubectl get deployment -n chesterns # 获取deployment
kubectl describe pod -n chesterns # 查看pod
拿到pod的虚拟ip,开始测试
curl 10.244.36.75:5000/test
curl 10.244.36.75:5001/test/calloneapi
滚动更新(RollingUpdate)与回滚
我们可以借助k8s的滚动更新实现服务的不停机更新,k8s也为我们提供了应对异常回滚的方法,下面就开始模拟
更新镜像
代码语言:javascript复制kubectl set image deployment/chesterdeployment twoapi=registry.cn-beijing.aliyuncs.com/chester-k8s/oneapi:latest -n chesterns --record
查看更新状态
kubectl rollout status deployment/chesterdeployment -n chesterns
查看更新历史
kubectl rollout history deployment/chesterdeployment -n chesterns
回滚
kubectl rollout undo deployment/chesterdeployment -n chesterns
kubectl rollout undo deployment/chesterdeployment -n chesterns --to-revision=1
滚动更新机制
- 启动一个新的RS与新pod
- 等待新的 pod 进入 Ready 状态
- 建立 Endpoint,将新的 pod 归入负载均衡运维
- 移除与老 pod 相关的 Endpoint,而且将老 pod 状态设置为 Terminating,此时将不会有新的请求到达老 pod
- 给老 pod 发送 SIGTERM 信号,而且等待 terminationGracePeriodSeconds 这么长的时间。(默认为 30 秒)
- 超过 terminationGracePeriodSeconds 等待时间直接强制 kill 进程并关闭旧的 pod
除了滚动更新,还有一种更新Recreate,这种模式会先杀掉所有正在运行的Pod,然后创建新的Pod
k8s的横向扩展
k8s通过 kubectl scale即可快速实现pod的横向扩展
代码语言:javascript复制kubectl scale deployment/chesterdeployment -n chesterns --replicas=10