上篇我们已经安装好k8s1.23集群,现在我们开始使用k8s部署我们的项目
PodPod 是一组容器集合,是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。这些容器共享存储、网络。
准备Demo我们要实现多容器Pod所以准备两个WebAPI项目
新建一个webapi,命名为oneapi,里面新增TestController,新增两个api,一个是返回当前pod的ip,另一个是模拟高cpu操作
[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内容器共享存储、网络)
[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,下面所有的镜像都使用我们刚刚推送到阿里云里的镜像
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
多容器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
kubectl describe pod chesterapi
通过以下调用twoapi的接口验证pod是否部署成功
curl podip:5001/test/calloneapi
验证完成,通过以下命令删除pod
kubectl delete -f pod.yaml探针
探针用于检测pod的健康状态,探针有三种,
-
ExecAction
(借助容器运行时执行) -
TCPSocketAction
(由 kubelet 直接检测) -
HTTPGetAction
(由 kubelet 直接检测)
我们通过http探针,来检测pod的健康状态,修改pod.yaml文件,并直接kubectl apply -f 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 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: 5001Pod状态 Pod重启策略
restartPolicy的选择值
-
Always:当容器失效时,由kubelet自动重启该容器。
-
OnFailure:当容器终止运行且退出码不为0时,由kubelet自动 重启该容器。
-
Never:不论容器运行状态如何,kubelet都不会重启该容器。
我们通过pod.yaml的探针接口地址为一个不存在的地址,并将restartPolicy设置为Never,让其即使健康检查失败,Pod也永不重启
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
通过以下命令部署,并验证
kubectl apply -f pod.yamlkubectl describe pod -n chesterapiDeployemnt
说完了pod,我们来看看deployment。生产环境中基本不存在直接定义pod的方式来部署项目,更多的是通过Deployment来部署。
用途-
方便管理、部署Pod
-
横扩应对高负载
-
快速程序更新与回滚
首先我们创建一个文件ns.yaml来定义一个namespace
apiVersion: v1
kind: Namespace
metadata:
name: chesterns
我们通过定义以下一个deployment,实现部署三个pod,模拟负载
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
通过以下命令部署并调用接口
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也为我们提供了应对异常回滚的方法,下面就开始模拟
更新镜像
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通过 kubectl scale即可快速实现pod的横向扩展
kubectl scale deployment/chesterdeployment -n chesterns --replicas=10