Kubernetes 是什么
不久前,我使用Kubernetes部署了一个特定的服务。 Kubernetes具有很多功能,虽然我只尝试了其中一小部分作为最低必要的功能,但我在阅读官方文档时进行了一些实验,现在将其发表出来。
Kubernetes 的架构
Kubernetes是由Master和Node这两种节点组成的集群系统。
管理员可以在Master上运行kubectl命令,将”资源”部署到Node上。
在本文中,我们使用了KVM来构建集群环境。Master的主机名是kubemaster,Node的主机名是kuberworker。Kubernetes的版本是v1.11。
Kubernetes 资源
公式对以下资源进行了描述。
这篇文章的内容是关于 Workloads 资源和 Services 资源的一部分。
工作量 资源
豆荚 jiá)
Node节点上部署的单位是被称为Pod的单位,Kubernetes不直接管理容器,而是管理这些Pod。通常情况下,一个Pod只有一个容器,但也可以肯定地说,存在一个Pod中启动多个容器的部署方式,例如扮演代理角色的容器或用于SSL终止的容器。辅助主要容器的角色被称为Sidecar的子容器。同时,属于同一个Pod的容器之间共享IP地址和端口,就像是在同一台服务器上启动的进程一样。因此,在容器内部运行的服务可以使用”localhost:<端口号>”的格式进行相互通信。Pod名被共享为主机名。
我们将在同一个 Pod 内启动 NGINX 容器和客户端容器,并验证容器之间的访问。我们已经创建了以下的 YAML 文件。客户端容器是从 CentOS 7.5 镜像启动的。
---
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
- name: centos
image: centos:7.5.1804
command: ["/sbin/init"]
使用kubectl apply命令部署Pod。
[homulilly@kubemaster ~]$ kubectl apply -f nginx-pod.yml
pod/nginx-pod created
[homulilly@kubemaster ~]$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-pod 2/2 Running 0 7s
我会登录到nginx-pod内的centos容器,并使用curl命令访问localhost:80。
[homulilly@kubemaster ~]$ kubectl exec -ti nginx-pod -c centos bash
[root@nginx-pod /]# curl http://localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
我们成功了。官方提供了密切协作的容器示例,不仅共享网络还共享存储空间。
复制集合
ReplicaSet 负责管理 Pod 的副本数量。虽然 ReplicaSet 可以单独启动,但一般情况下会先启动管理 ReplicaSet 的 Deployment。另外,通过 label selector,可以使用为 Kubernetes 对象分配的标签进行对象间的操作。在 ReplicaSet 中,支持通过 =/==/!= 来选择标签的基于等式的方式,以及通过 in/notin/exists 来选择标签的基于集合的方式。
生成ReplicaSet以管理包含NGINX容器的Pod。我已经创建了以下YAML文件。
---
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: nginx-rs
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
使用kubectl apply命令部署Replicaset。
[homulilly@kubemaster ~]$ kubectl apply -f nginx-replicaset.yml
[homulilly@kubemaster ~]$ kubectl get replicaset -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
nginx-rs 2 2 2 17s nginx nginx:latest app=nginx
[homulilly@kubemaster ~]$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-rs-qpxmh 1/1 Running 0 14m 10.44.0.3 kubeworker
nginx-rs-t7frx 1/1 Running 0 14m 10.44.0.4 kubeworker
已生成了2个Pod。
通过Replicaset来管理Pod的副本数量,确保即使Pod被删除,也会立即重新生成。
[homulilly@kubemaster ~]$ kubectl delete pod/nginx-rs-t7frx
pod "nginx-rs-t7frx" deleted
[homulilly@kubemaster ~]$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-rs-qpxmh 1/1 Running 0 54m 10.44.0.3 kubeworker
nginx-rs-rs6z5 1/1 Running 0 8s 10.44.0.4 kubeworker
删除 nginx-rs-t7frx 后,新增了 nginx-rs-rs6z5 的启动。
接下来我们要进行扩容操作,将 nginx-rs 的副本数量设置为 5。
[homulilly@kubemaster ~]$ kubectl scale rs nginx-rs --replicas 5
replicaset.extensions/nginx-rs scaled
[homulilly@kubemaster ~]$ kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
nginx-rs 5 5 5 1h nginx nginx:latest app=nginx
[homulilly@kubemaster ~]$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-rs-2tl74 1/1 Running 0 37s 10.44.0.6 kubeworker
nginx-rs-qdktp 1/1 Running 0 37s 10.44.0.8 kubeworker
nginx-rs-qpxmh 1/1 Running 0 1h 10.44.0.3 kubeworker
nginx-rs-rs6z5 1/1 Running 0 10m 10.44.0.4 kubeworker
nginx-rs-v6dbd 1/1 Running 0 37s 10.44.0.7 kubeworker
数量增加了。我使用kubectl命令直接进行了扩展,但在编辑了YAML文件中的副本数后,再次使用kubectl apply也是同样的结果。
部署
部署(Deployment)通过管理 ReplicaSet 来进行 Pod 的滚动更新和回滚。工作原理非常简单,
-
- 创建一个新的 ReplicaSet
-
- 逐渐增加新 ReplicaSet 上的副本数(Pod 数)
-
- 逐渐减少旧 ReplicaSet 上的副本数(Pod 数)
-
- 4.(重复步骤2和3)
- 保持旧 ReplicaSet 的副本数为0
采取这种流程。在这种情况下,似乎可以调整从旧的 ReplicaSet 到新的 ReplicaSet 的迁移速度,包括一次性迁移或一次迁移一个Pod。
生成一个Deployment,用于管理包含NGINX容器的Pod,并管理Replicaset。已创建以下YAML文件。
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
使用 kubectl apply 命令部署 Deployment。
[homulilly@kubemaster ~]$ kubectl apply -f nginx-deployment.yml
deployment.apps/nginx-deployment created
[homulilly@kubemaster ~]$ kubectl get deployment -o wide
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx-deployment 2 2 2 2 39s nginx nginx:1.7.9 app=nginx
[homulilly@kubemaster ~]$ kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
nginx-deployment-5ff86cd6fb 2 2 2 2m nginx nginx:1.7.9 app=nginx,pod-template-hash=1994278296
[homulilly@kubemaster ~]$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-deployment-5ff86cd6fb-fb8fr 1/1 Running 0 2m 10.44.0.9 kubeworker
nginx-deployment-5ff86cd6fb-l6shs 1/1 Running 0 2m 10.44.0.11 kubeworker
将NGINX版本从1.7.9更新至1.9.1。
[homulilly@kubemaster ~]$ kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
deployment.extensions/nginx-deployment image updated
[homulilly@kubemaster ~]$ kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
nginx-deployment-5ff86cd6fb 0 0 0 1h nginx nginx:1.7.9 app=nginx,pod-template-hash=1994278296
nginx-deployment-6947d8b574 2 2 2 26s nginx nginx:1.9.1 app=nginx,pod-template-hash=2503846130
没有Pod来管理包含NGINX1.7.9的容器的ReplicaSet。
包含NGINX1.9.1的容器的Pod被管理的ReplicaSet中有两个副本正在运行。
将NGINX的版本从1.9.1降级到1.7.9。
[homulilly@kubemaster ~]$ kubectl edit deployment/nginx-deployment
deployment.extensions/nginx-deployment edited
可以用vi编辑器编辑元数据。已更改NGINX版本信息。
[homulilly@kubemaster ~]$ kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
nginx-deployment-5ff86cd6fb 2 2 1 1h nginx nginx:1.7.9 app=nginx,pod-template-hash=1994278296
nginx-deployment-6947d8b574 1 1 1 5m nginx nginx:1.9.1 app=nginx,pod-template-hash=2503846130
[homulilly@kubemaster ~]$ kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
nginx-deployment-5ff86cd6fb 2 2 2 1h nginx nginx:1.7.9 app=nginx,pod-template-hash=1994278296
nginx-deployment-6947d8b574 0 0 0 5m nginx nginx:1.9.1 app=nginx,pod-template-hash=2503846130
我已确认NGINX的版本已逐渐切换。接下来,我们将通过回滚来将NGINX的版本恢复为1.9.1。
[homulilly@kubemaster ~]$ kubectl rollout undo deployment nginx-deployment
deployment.extensions/nginx-deployment
[homulilly@kubemaster ~]$ kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
nginx-deployment-5ff86cd6fb 0 0 0 5h nginx nginx:1.7.9 app=nginx,pod-template-hash=1994278296
nginx-deployment-6947d8b574 2 2 2 3h nginx nginx:1.9.1 app=nginx,pod-template-hash=2503846130
服务资源
服务资源用于将容器连接到外部网络以及用于发现与标签匹配的容器。除了用于执行L4负载均衡的服务资源外,还有用于执行L7负载均衡的入口资源。
将NGINX容器连接到外部网络。我已经创建了以下的YAML文件。我已经指定了类型为NodePort。这种方式似乎是在节点(kubeworker)的固定端口上将容器公开到外部。还有其他一些类型,如使用云服务提供商的负载均衡器。
[homulilly@kubemaster ~]$ cat nginx-service.yml
---
apiVersion: v1
kind: Service
metadata:
name: nginx-nodeport
spec:
type: NodePort
ports:
- port: 80
selector:
app: nginx
使用kubectl apply命令部署Service。
[homulilly@kubemaster ~]$ kubectl apply -f nginx-service.yml
service/nginx-nodeport created
[homulilly@kubemaster ~]$ kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 23d <none>
nginx-nodeport NodePort 10.96.197.250 <none> 80:30773/TCP 22h app=nginx
看起来,NGINX容器的80号端口与kubeworker的30773号端口绑定在一起。因此,在运行kubeworker的主机操作系统上,我们向Firewalld添加了kubeworker:30773的端口转发规则,这样在浏览器中就可以访问NGINX容器了。
[homulilly@kubemaster ~]$ kubectl describe service nginx
Name: nginx-nodeport
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"nginx-nodeport","namespace":"default"},"spec":{"ports":[{"port":80}],"selector...
Selector: app=nginx
Type: NodePort
IP: 10.96.197.250
Port: <unset> 80/TCP
TargetPort: 80/TCP
NodePort: <unset> 30773/TCP
Endpoints: 10.44.0.3:80,10.44.0.4:80
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
在nginx-nodeport的Endpoints中,注册了两个副本的IP地址。
总结
如果我们创建了包含部署服务的Docker镜像,那么只需要启动容器并将其公开到外部即可。只需要创建用于部署和服务的YAML文件来进行公开。