自建 Kubernetes 上运行容器
编写配置文件
Kubernetes 跟 Docker 等很多项目最大的不同,就在于它不推荐你使用命令行的方式直接运行容器(虽然 Kubernetes 项目也支持这种方式,比如:kubectl run),而是希望你用 YAML 文件的方式,即:把容器的定义、参数、配置,统统记录在一个 YAML 文件中,然后用这样一句指令把它运行起来:
$ kubectl create -f 我的配置文件
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.7.9
ports:
- containerPort: 80
- 像这样的一个 YAML 文件,对应到 Kubernetes 中,就是一个 API Object(API 对象)。当你为这个对象的各个字段填好值并提交给 Kubernetes 之后,Kubernetes 就会负责创建出这些对象所定义的容器或者其他类型的 API 资源。
- 这个 YAML 文件中的 Kind 字段,指定了这个 API 对象的类型(Type),是一个 Deployment。Deployment,是一个定义多副本应用(即多个副本 Pod)的对象
- 这个 YAML 文件中,定义的 Pod 副本个数 (spec.replicas) 是:2。
- Pod 模版(spec.template),这个模版描述了创建的 Pod 的细节。在上面的例子这个 Pod 里只有一个容器,这个容器的镜像(spec.containers.image)是 nginx:1.7.9,这个容器监听端口(containerPort)是 80。
- 这样使用一种 API 对象(Deployment)管理另一种 API 对象(Pod)的方法,在 Kubernetes 中,叫作“控制器”模式(controller pattern)
- 一个 Kubernetes 的 API 对象的定义,大多可以分为 Metadata 和 Spec 两个部分。前者存放的是这个对象的元数据,对所有 API 对象来说,这一部分的字段和格式基本上是一样的;而后者存放的,则是属于这个对象独有的定义,用来描述它所要表达的功能。
[root@k8s ~]# kubectl apply -f nginx-deployment.yaml --namespace=kube-system
deployment.apps/nginx-deployment created
[root@k8s ~]# kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
nginx-deployment-54f57cf6bf-jpgq4 0/1 Pending 0 86m
nginx-deployment-54f57cf6bf-rrmbq 0/1 Pending 0 86m
或者
[root@k8s ~]# kubectl get pods -n kube-system
解决 pending 状态:
检查:
[root@k8s ~]# kubectl -n kube-system describe pod nginx-deployment-54f57cf6bf-rg8td
……
……
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 5s (x17 over 22m) default-scheduler 0/1 nodes are available: 1 node(s) had taints that the pod didn't tolerate.
查看节点的 Taints(kubectl describe node <node_name>)
Taints: node-role.kubernetes.io/master:NoSchedule
解决方案:
- 在 Pod 的.yaml 文件中的 spec 部分,加入 tolerations 字段即可
- 或者
kubectl taint nodes --all node-role.kubernetes.io/master-
在“node-role.kubernetes.io/master”这个键后面加上了一个短横线“-”,这个格式就意味着移除所有以“node-role.kubernetes.io/master”为键的 Taint。
[root@k8s ~]# kubectl taint nodes --all node-role.kubernetes.io/master-
node/instance-010oj085 untainted
再次查看状态(在命令行中,所有 key-value 格式的参数,都使用“=”而非“:”表示)
[root@k8s ~]# kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
nginx-deployment-54f57cf6bf-jpgq4 1/1 Running 0 148m
nginx-deployment-54f57cf6bf-rrmbq 1/1 Running 0 148m
查看 describe 的 Event 事件:
……
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 10m (x39 over 65m) default-scheduler 0/1 nodes are available: 1 node(s) had taints that the pod didn't tolerate.
Normal Pulling 5m41s kubelet, instance-010oj085 Pulling image "nginx:1.7.9"
Normal Pulled 4m37s kubelet, instance-010oj085 Successfully pulled image "nginx:1.7.9"
Normal Created 4m37s kubelet, instance-010oj085 Created container nginx
Normal Started 4m37s kubelet, instance-010oj085 Started container nginx
镜像服务升级
1. 修改 YAML 文件
2. 执行命令
# 修改nginx-deployment.yaml的内容
kubectl apply -f nginx-deployment.yaml
当应用本身发生变化时,开发人员和运维人员可以依靠容器镜像来进行同步;当应用部署参数发生变化时,这些 YAML 文件就是他们相互沟通和信任的媒介。
删除 Nginx Deployment
$ kubectl delete -f nginx-deployment.yaml
总结
- Kubernetes 里“最小”的 API 对象是 Pod。Pod 可以等价为一个应用,所以,Pod 可以由多个紧密协作的容器组成。
- 在 Kubernetes 中,我们经常会看到它通过一种 API 对象来管理另一种 API 对象,比如 Deployment 和 Pod 之间的关系;而由于 Pod 是“最小”的对象,所以它往往都是被其他对象控制的。这种组合方式,正是 Kubernetes 进行容器编排的重要模式。
- 像这样的 Kubernetes API 对象,往往由 Metadata 和 Spec 两部分组成,其中 Metadata 里的 Labels 字段是 Kubernetes 过滤对象的主要手段。
- 在这些字段里面,容器想要使用的数据卷,也就是 Volume,正是 Pod 的 Spec 字段的一部分。而 Pod 里的每个容器,则需要显式的声明自己要挂载哪个 Volume。