Minikube 架构图
Minikube 利用本地虚拟机环境部署 Kubernetes,其基本架构如图。
Reference
https://github.com/kubernetes/minikube
https://minikube.sigs.k8s.io/docs/
Kubernetes 里面与开发者关系最密切的几个概念
Kubernetes 跟 Docker 等很多项目最大的不同,在于它不推荐使用命令行的方式直接运行容器(但也支持:kubectl run),而是用 YAML 文件的方式,即:把容器的定义、参数、配置,统统记录在一个 YAML 文件中,然后用一句指令把它运行起来:
$ kubectl create -f 我的配置文件
apiVersion: apps/v1kind: Deploymentmetadata:name: nginx-deploymentspec:selector:matchLabels:app: nginxreplicas: 2template:metadata:labels:app: nginxspec:containers:- name: nginximage: nginx:1.7.9ports:- containerPort: 80
这样一个 YAML 文件,对应到 Kubernetes 中,就是个 API Object,Kubernetes 负责创建出这些对象所定义但容器或者其它类型的 API 资源。
- Deployment
YAML 文件中 Kind 字段,指定了这个 API 对象的类型(Type),是一个 Deployment。
定义多副本应用(即多个副本 Pod)的对象。Deployment 还负责在 Pod 定义发生变化时,对每个副本进行滚动更新(Rolling Update)。
上面的 YAML 文件中,定义的 Pod 副本个数(spec.replicas)为:2。 - Pod
Pod 模板(spec.template) 描述了要创建的 Pod 的细节。上例中,Pod 里只有一个容器,容器的镜像(spec.containers.image) 是 nginx:1.7.9,容器监听端口(containerPort) 是 80。
Pod 就是 Kubernetes 世界里的“应用”;而一个应用,可以由多个容器组成。
像这样使用一种 API 对象 (Deployment) 管理另一种 API 对象 (Pod) 的方式,在Kubernetes 中叫“控制器”模式(controller pattern)。 - Metadata
API 对象的“标识”,元数据。从 Kubernetes 里找到这个对象的主要依据。其中最主要使用字段是 Labels。 - Labels
一组 key-value 格式的标签。像 Deployment 这样的控制器对象,可以通过 Labels 字段从 Kubernetes 中过滤出它所关心的被控制对象。
如上例:Deployment 会把所有正在运行的、携带“app: niginx”标签的 Pod 识别为被管理对象,并确保这些 Pod 的总数严格等于两个。过滤规则 Label Selector。 - Label Selector
过滤规则的定义,在 Deployment 的“spec.selector.matchLabels”字段。 - Annotations
在 Metadata 中,与 Labels 格式、层级完全相同。专门用来携带 key-value 格式的内部信息。内部信息指的是对这些信息感兴趣的,是 Kubernetes 组件本身,而不是用户。所以大多 Annotations,都是在 Kubernetes 运行过程中,被自动加在这个 API 对象上。
一个 Kubernetes 的 API 对象的定义,大多可分为 Metadata 和 Spec 两部分。Metadata 存放的是对象的元数据,对所有 API 对象来说,这部分的字段和格式基本是一样的;Spec 存放的是属于这个对象独有的定义,用来描述它所要表达的功能。
运行 YAML 文件
kubectl get从 Kubernetes 里 GET 指定的 API 对象。 ```bash $ kubectl create -f nigix-deployment.yaml
$ kubectl get pods -l app=nginx NAME READY STATUS RESTARTS AGE nginx-deployment-67594d6bf6-9gdvr 1/1 Running 0 10m nginx-deployment-67594d6bf6-v6j7w 1/1 Running 0 10m
`-l` 获取所有匹配 app: nginx 标签 的 Pod。在命令中,所有 key-value 格式的参数,都是用“=”而非“:”。<br />从返回看出,两个 Pod 处于 Running 状态,意味着 Deployment 所管理的 Pod 都处于预期的状态。
- `kubectl describe` 查看 API 对象的细节。
```bash
$ kubectl describe pod nginx-deployment-67594d6bf6-9gdvr
Name: nginx-deployment-67594d6bf6-9gdvr
Namespace: default
Priority: 0
PriorityClassName: <none>
Node: node-1/10.168.0.3
Start Time: Thu, 16 Aug 2018 08:48:42 +0000
Labels: app=nginx
pod-template-hash=2315082692
Annotations: <none>
Status: Running
IP: 10.32.0.23
Controlled By: ReplicaSet/nginx-deployment-67594d6bf6
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 1m default-scheduler Successfully assigned default/nginx-deployment-67594d6bf6-9gdvr to node-1
Normal Pulling 25s kubelet, node-1 pulling image "nginx:1.7.9"
Normal Pulled 17s kubelet, node-1 Successfully pulled image "nginx:1.7.9"
Normal Created 17s kubelet, node-1 Created container
Normal Started 17s kubelet, node-1 Started container
其中有一部分值得特别关注, Events(事件) 。
Events
在Kubernetes 执行过程中,对 API 对象对所有重要操作,都会被记录在这个对象对 Events,并显示在 kubectl describe 返回结果中。
如上,对于这个 Pod,它被创建之后,被调度器调度(Successfully assigned) 到 node-1,拉取指定镜像(pulling image) ,启动 Pod 里定义对容器(Started container)。
这部分是进行 Debug 对重要依据。 如果有异常发生,一定要第一时间查看 Events ,往往可以看到非常详细对错误信息。
服务升级
对 Nginx 服务进行升级。修改 Yaml 文件。
...
spec:
containers:
- name: nginx
image: nginx:1.8 #这里被从1.7.9修改为1.8
ports:
- containerPort: 80
kubectl replace完成更新。$ kubectl replace -f niginx-deployment.yamlkubectl apply来统一进行 Kubernetes 对象的创建和更新操作。 ```bash $ kubectl apply -f nginx-deployment.yaml
修改nginx-deployment.yaml的内容
$ kubectl apply -f nginx-deployment.yaml
这种是 Kubernetes “声明式 API” 推荐的使用方法。作为用户,不必关心当前的操作是创建,还是更新,执行的命令始终是 `kubectl apply` ,Kubernetes 会根据 YAML 文件的内容变化,自动进行具体的处理。<br />开发和运维围绕可版本化管理的 YAML 文件进行协作。<br />容器镜像保证应用本身在开发和部署环境里的一致性,YAML 文件保证应用的“部署参数”在开发和部署环境中的一致性。
<a name="MTcog"></a>
#### Volume
Volume 属于 Pod 的一部分,需修改 template.spec 字段。
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.8
ports:
- containerPort: 80
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: nginx-vol
volumes:
- name: nginx-vol
emptyDir: {}
在 Deployment 的 Pod 模板部分添加了 volumes 字段,定义了这个 Pod 声明的所有 Volume。叫 nigin-vol,类型是 emptyDir(等同于 Docker 的隐式 Volume 参数,即:不显式声明宿主机目录的 Volume)。Kubernetes 会在宿主机上创建一个临时目录,将会被绑定挂载到容器所声明的 Volume 目录上。
Kubernetes 的 emptyDir 类型,是把 Kubernetes 创建的临时目录作为 Volume 的宿主机目录,交给了 Docker。这么做是 Kubernetes 不想依赖 Docker 创建的 _data 目录。
Pod 中的容器,使用 volumeMounts 字段声明自己要挂载哪个 Volume,并通过 mountPath 字段来定义容器内的 Volume 目录,如:/usr/share/nginx/html。
Kubernetes 也提供了显式的 Volume 定义,hostPath:
...
volumes:
- name: nginx-vol
hostPath:
path: " /var/data"
这样容器挂载的宿主机目录就为 /var/data。
修改完成后,使用 kubectl apply 更新 Deployment。
可使用 kubectl get 查看两个 Pod 被逐一更新的过程:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-5c678cfb6d-v5dlh 0/1 ContainerCreating 0 4s
nginx-deployment-67594d6bf6-9gdvr 1/1 Running 0 10m
nginx-deployment-67594d6bf6-v6j7w 1/1 Running 0 10m
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-5c678cfb6d-lg9lw 1/1 Running 0 8s
nginx-deployment-5c678cfb6d-v5dlh 1/1 Running 0 19s
可看出,新旧两个 Pod,被交替创建、删除,最后剩下新版本的 Pod。
使用 kubectl describe 查看最新的 Pod,Container 描述部分包含了 Volume 信息。
...
Containers:
nginx:
Container ID: docker://07b4f89248791c2aa47787e3da3cc94b48576cd173018356a6ec8db2b6041343
Image: nginx:1.8
...
Environment: <none>
Mounts:
/usr/share/nginx/html from nginx-vol (rw)
...
Volumes:
nginx-vol:
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
使用 kubectl exec 进入 Pod 中(即容器的 Namesapce 中),查看 Volume 目录。
$ kubectl exec -it nginx-deployment-5c678cfb6d-lg9lw -- /bin/bash
# ls /usr/share/nginx/html
从 Kubernetes 集群中删除这个 Nginx Deployment,执行:
$ kubectl delete -f nginx-deployment.yaml
总结
Kubernetes 推荐使用方式:用一个 YAML 文件描述所要部署的 API 对象。统一使用 kubectl apply 完成对对象对创建和更新操作。
Kubernetes “最小”的 API 对象是 Pod。Pod 可等价为一个应用,所以 Pod 可由多个紧密协作的容器组成。
Kubernetes 经常通过一种 API 对象来管理另一种 API 对象,如 Deployment 和 Pod 。而 Pod 是“最小”的对象,所以往往都是被其他对象控制的。这种组合方式,是 Kubernetes 进行容器编排的重要模式。
这样的 Kubernetes API 对象,往往由 Metadata 和 Spec 两部分组成,其中 Metadata 里的 Labels 字段是 Kubernetes 过滤对象的主要手段。
在这些字段里面,容器想要使用的数据卷,也就是 Volume,是 Pod 的 Spec 字段的一部分。而 Pod 里的每个容器,则需要显式的声明自己要挂载哪个 Volume。
上面这些基于 YAML 文件的容器管理方式,跟 Docker、Mesos 的使用习惯都是不一样的,需从 docker run 这样的命令行操作,向 kubectl apply YAML 文件这样的声明式 API 的转变。
所以,按照下面的流程进行练习 Kubernetes:
- 首先,在本地通过 Docker 测试代码,制作镜像;
- 然后,选择合适的 Kubernetes API 对象,编写对应 YAML 文件(比如,Pod,Deployment);
- 最后,在 Kubernetes 上部署这个 YAML 文件。
在部署到 Kubernetes 之后,接下来的所有操作,要么通过 kubectl 来执行,要么通过修改 YAML 文件来实现,尽量不要再碰 Docker 的命令行了。
