k8s nginx
pod部署
- 编写nginx-pod.yml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: nginx-storage
mountPath: /var/log/nginx #容器内部nginx的日志
- name: nginx-conf
mountPath: /usr/share/nginx/html #容器内部nginx的html位置
volumes:
- name: nginx-storage
hostPath:
path: /data/logs/nginx #将宿主机的日志目录挂载到容器中的日志目录
- name: nginx-conf
hostPath:
path: /data/nginx #将宿主机的html目录挂载到容器中的日志目录
- 执行kubectl apply -f nginx-pod.yml创建成功pod
- 通过kubectl get pod nginx -o wide查看pod启动情况
[root@master k8s]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 5m17s 10.0.3.164 cdh2 <none> <none>
- 通过执行kubectl exec -it nginx sh可以进入到容器内部,然后执行curl http://127.0.0.1可以查看内容
- 由于此刻Pod的端口还未对外暴露,因此无法在外部访问,可以采取以下方法:
- hostNetwork
- hostPort
- NodePort
- LoadBalancer
- Ingress
hostNetwork
这是一种直接定义Pod网络的方式。
如果在Pod中使用hostNotwork:true配置的话,在这种pod中运行的应用程序可以直接看到pod启动的主机的网络接口。在主机的所有网络接口上都可以访问到该应用程序。以下是使用主机网络的pod的示例定义:
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
hostNetwork: true
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: nginx-storage
mountPath: /var/log/nginx
- name: nginx-conf
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-storage
hostPath:
path: /data/logs/nginx
- name: nginx-conf
hostPath:
path: /data/nginx
这样就可以访问宿主机的80端口就可以访问nginx的页面了,但是这种方式的弊端就是由于k8s集群中节点很多,无法知道这个nginx的pod部署到哪个节点。
因此一般情况下除非您知道需要某个特定应用占用特定宿主机上的特定端口时才使用hostNetwork: true的方式。
hostPort
hostPort是直接将容器的端口与所调度的节点上的端口路由,这样用户就可以通过宿主机的IP加上来访问Pod了
apiVersion: v1
kind: Pod
metadata:
name: nginx-host-port
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
hostPort: 7878
volumeMounts:
- name: nginx-storage
mountPath: /var/log/nginx
- name: nginx-conf
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-storage
hostPath:
path: /data/logs/nginx
- name: nginx-conf
hostPath:
path: /data/nginx
这样就可以访问宿主机的7878端口就可以访问nginx的页面了,这样做有个缺点,因为Pod重新调度的时候该Pod被调度到的宿主机可能会变动,这样就变化了。问题通hostNetwork一样。
用户必须自己维护一个Pod与所在宿主机的对应关系。
NodePort
NodePort在kubenretes里是一个广泛应用的服务暴露方式。Kubernetes中的service默认情况下都是使用的ClusterIP这种类型,这样的service会产生一个ClusterIP,这个IP只能在集群内部访问,要想让外部能够直接访问service,需要将service type修改为 nodePort。
#声明一个pod,然后定义一个Service去访问pod,通过 selector来选择标签,这里记住,选择的是pod中定义的标签名,这样定义一个Service可以负载均衡到一个标签下的多个pod。
------------------------
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: NodePort #Service声明为NodePort这样将Service的端口映射到宿主机的一个端口
ports:
- port: 80 #Service的端口
targetPort: 80 #Pod容器的端口
nodePort: 30000 #宿主机的端口
selector:
app: nginx-node-1 #选择 标签为nginx-node-1的POD作为后端服务
---
apiVersion: v1
kind: Pod
metadata:
name: nginx-node
labels:
app: nginx-node-1
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: nginx-storage
mountPath: /var/log/nginx
- name: nginx-conf
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-storage
hostPath:
path: /data/logs/nginx
- name: nginx-conf
hostPath:
path: /data/nginx
集群外就可以使用kubernetes任意一个节点的IP加上30000端口访问该服务了。kube-proxy会自动将流量以round-robin的方式转发给该service的每一个pod。
这种服务暴露方式,无法让你指定自己想要的应用常用端口,不过可以在集群上再部署一个反向代理作为流量入口。
LoadBalancer
LoadBalancer 只能在service上定义。这是公有云提供的负载均衡器,如AWS、Azure、CloudStack、GCE等。
kind: Service
apiVersion: v1
metadata:
name: influxdb
spec:
type: LoadBalancer
ports:
- port: 80
selector:
app: nginx-node-1
---
apiVersion: v1
kind: Pod
metadata:
name: nginx-node
labels:
app: nginx-node-1
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: nginx-storage
mountPath: /var/log/nginx
- name: nginx-conf
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-storage
hostPath:
path: /data/logs/nginx
- name: nginx-conf
hostPath:
path: /data/nginx
查看服务
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 192.168.0.1 <none> 443/TCP 22d <none>
nginx-service LoadBalancer 192.168.180.49 <pending> 80:31981/TCP 2m23s app=nginx-node-1
使用EXTERNAL-IP来访问,这是一个VIP,是云供应商提供的负载均衡器IP
由于只能在公有云上建立,因此此方法无法在本机进行测试演示
Ingress
Ingress是自kubernetes1.1版本后引入的资源类型。必须要部署 Ingress controller 才能创建Ingress资源,Ingress controller是以一种插件的形式提供。Ingress controller 是部署在Kubernetes之上的Docker容器。它的Docker镜像包含一个像nginx或HAProxy的负载均衡器和一个控制器守护进程。控制器守护程序从Kubernetes接收所需的Ingress配置。它会生成一个nginx或HAProxy配置文件,并重新启动负载平衡器进程以使更改生效。换句话说,Ingress controller是由Kubernetes管理的负载均衡器。
Kubernetes Ingress提供了负载平衡器的典型特性:HTTP路由,粘性会话,SSL终止,SSL直通,TCP和UDP负载平衡等。目前并不是所有的Ingress controller都实现了这些功能,需要查看具体的Ingress controller文档。
ingress.yml
ingress一定要配合service使用,这样可以使service无需使用NodeType模式,将端口部署到节点
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-test
spec:
rules:
#定义域名
- host: test.ingress.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
nginx-pod.yml
这里无需将type设置为nodeType,直接去掉,无需对外访问
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
ports:
- port: 80
targetPort: 80
selector:
app: nginx-node-1
---
apiVersion: v1
kind: Pod
metadata:
name: nginx-node
labels:
app: nginx-node-1
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: nginx-storage
mountPath: /var/log/nginx
- name: nginx-conf
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-storage
hostPath:
path: /data/logs/nginx
- name: nginx-conf
hostPath:
path: /data/nginx
总结
总的来说Ingress是一个非常灵活和越来越得到厂商支持的服务暴露方式,包括Nginx、HAProxy、Traefik,还有各种Service Mesh,而其它服务暴露方式可以更适用于服务调试、特殊应用的部署。
Deployment
采用pod部署,无法进行很好的扩容操作,主流的都是是用deployment来部署,然后再结合上面的Ingress来进行负载均衡接入service
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx-deployment-pod
template:
metadata:
labels:
app: nginx-deployment-pod
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
volumeMounts:
- name: nginx-storage
mountPath: /var/log/nginx
- name: nginx-html
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-storage
hostPath:
path: /data/logs/nginx
- name: nginx-html
hostPath:
path: /data/nginx
---
apiVersion: v1
kind: Service
metadata:
name: nginx-deploy-service
spec:
ports:
- port: 81
targetPort: 80
selector:
app: nginx-deployment-pod
执行kubectl apply -f nginx-deploy-pod.yml,查看运行情况
[root@master k8s]# kubectl get deployments -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx-deployment 2/2 2 2 69m nginx nginx:1.7.9 app=nginx-deployment-pod
[root@master k8s]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-78dbd4c9f4-9kw84 1/1 Running 0 11m 10.10.1.31 cdh3 <none> <none>
nginx-deployment-78dbd4c9f4-pngnn 1/1 Running 0 11m 10.10.2.25 cdh2 <none> <none>
Deployment + LoadBalancer模式的Service
如果要把ingress部署在公有云,那用这种方式比较合适。用Deployment部署ingress-controller,创建一个type为LoadBalancer的service关联这组pod。大部分公有云,都会为LoadBalancer的service自动创建一个负载均衡器,通常还绑定了公网地址。只要把域名解析指向该地址,就实现了集群服务的对外暴露。
Deployment+NodePort模式的Service
同样用deployment模式部署ingress-controller,并创建对应的Service,但是Service的type为NodePort。这样,ingress就会暴露在集群节点ip的特定端口上。由于nodeport暴露的端口是随机端口,一般会在前面再搭建一套负载均衡器来转发请求。该方式一般用于宿主机是相对固定的环境ip地址不变的场景。
NodePort方式暴露ingress虽然简单方便,但是NodePort多了一层NAT,在请求量级很大时可能对性能会有一定影响。
DaemonSet+HostNetwork+nodeSelector
用DaemonSet结合nodeselector来部署ingress-controller到特定的node上,然后使用HostNetwork直接把该pod与宿主机node的网络打通,直接使用宿主机的80/433端口就能访问服务。这时,ingress-controller所在的node机器就很类似传统架构的边缘节点,比如机房入口的nginx服务器。该方式整个请求链路最简单,性能相对NodePort模式更好。缺点是由于直接利用宿主机节点的网络和端口,一个node只能部署一个ingress-controller pod。比较适合大并发的生产环境使用。
更新deployment
- 升级nginx版本号,将版本号升级到1.16.1
[root@master k8s]# kubectl --record deployment.apps/nginx-deployment set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1
deployment.apps/nginx-deployment image updated
deployment.apps/nginx-deployment image updated
更新后会一个个pod替换重启
- 执行完命令后,要查看更新状况
kubectl rollout status deployment/nginx-deployment
[root@master k8s]# kubectl rollout status deployment/nginx-deployment
deployment "nginx-deployment" successfully rolled out(全部更新完毕)
又或者会提示,即还有1个未更新
Waiting for rollout to finish: 1 out of 2 new replicas have been updated...
回滚
有可能更新版本出错,这个时候可能需要回滚
1.执行回滚语句
kubectl rollout undo deployment.v1.apps/nginx-deployment
2.查看回滚状况,同上述查看更新状况命令一致
自动伸缩
1.指定扩容个数
[root@master k8s]# kubectl scale deployment.v1.apps/nginx-deployment --replicas=3
deployment.apps/nginx-deployment scaled
查看pod已生效
[root@master k8s]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-7fd7589cf4-h4jlz 1/1 Running 0 19s 10.10.2.29 cdh2 <none> <none>
nginx-deployment-7fd7589cf4-hd967 1/1 Running 0 95s 10.10.2.28 cdh2 <none> <none>
nginx-deployment-7fd7589cf4-vnvlg 1/1 Running 0 93s 10.10.1.34 cdh3 <none> <none>
2.动态扩容个数
假设集群中启用了水平Pod自动缩放,则可以为Deployment设置一个自动缩放器,并根据现有Pod的CPU利用率选择要运行的最小和最大Pod数。
使用动态扩容需要为k8s创建metric-server,且为容器配置资源
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx-deployment-pod
template:
metadata:
labels:
app: nginx-deployment-pod
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
resources:
limits: #限制最高资源
cpu: "500m"
requests: #最低保障资源
cpu: "200m"
volumeMounts:
- name: nginx-storage
mountPath: /var/log/nginx
- name: nginx-html
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-storage
hostPath:
path: /data/logs/nginx
- name: nginx-html
hostPath:
path: /data/nginx
---
apiVersion: v1
kind: Service
metadata:
name: nginx-deploy-service
spec:
ports:
- port: 81
targetPort: 80
selector:
app: nginx-deployment-pod
kubectl autoscale deployment.v1.apps/nginx-deployment --min=1 --max=3 --cpu-percent=50
我们可以通过运行以下命令检查自动定标器的当前状态:
[root@master k8s]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
nginx-deployment Deployment/nginx-deployment <unknown>/50% 1 3 3 3m13s
K8S的资源描述:
在K8s的资源:
CPU:
我们知道2核2线程的CPU,可被系统识别为4个逻辑CPU,在K8s中对CPU的分配限制是对逻辑CPU做分片限制的。
也就是说分配给容器一个CPU,实际是分配一个逻辑CPU。
而且1个逻辑CPU还可被单独划分子单位,即 1个逻辑CPU,还可被划分为1000个millicore(毫核), 简单说就是1个逻辑CPU,继续逻辑分割为1000个豪核心。
豪核:可简单理解为将CPU的时间片做逻辑分割,每一段时间片就是一个豪核心。
所以:500m 就是500豪核心,即0.5个逻辑CPU.